1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2009 Red Hat, Inc.
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.
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.
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.
20 * Author: Alexander Larsson <alexl@redhat.com>
27 #include "gconverterinputstream.h"
28 #include "gpollableinputstream.h"
29 #include "gsimpleasyncresult.h"
30 #include "gcancellable.h"
31 #include "gioenumtypes.h"
37 * SECTION:gconverterinputstream
38 * @short_description: Converter Input Stream
40 * @see_also: #GInputStream, #GConverter
42 * Converter input stream implements #GInputStream and allows
43 * conversion of data of various types during reading.
45 * As of GLib 2.34, #GConverterInputStream implements
46 * #GPollableInputStream.
49 #define INITIAL_BUFFER_SIZE 4096
58 struct _GConverterInputStreamPrivate
{
59 gboolean at_input_end
;
62 GConverter
*converter
;
64 Buffer converted_buffer
;
72 static void g_converter_input_stream_set_property (GObject
*object
,
76 static void g_converter_input_stream_get_property (GObject
*object
,
80 static void g_converter_input_stream_finalize (GObject
*object
);
81 static gssize
g_converter_input_stream_read (GInputStream
*stream
,
84 GCancellable
*cancellable
,
87 static gboolean
g_converter_input_stream_can_poll (GPollableInputStream
*stream
);
88 static gboolean
g_converter_input_stream_is_readable (GPollableInputStream
*stream
);
89 static gssize
g_converter_input_stream_read_nonblocking (GPollableInputStream
*stream
,
94 static GSource
*g_converter_input_stream_create_source (GPollableInputStream
*stream
,
95 GCancellable
*cancellable
);
97 static void g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface
*iface
);
99 G_DEFINE_TYPE_WITH_CODE (GConverterInputStream
,
100 g_converter_input_stream
,
101 G_TYPE_FILTER_INPUT_STREAM
,
102 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM
,
103 g_converter_input_stream_pollable_iface_init
);
107 g_converter_input_stream_class_init (GConverterInputStreamClass
*klass
)
109 GObjectClass
*object_class
;
110 GInputStreamClass
*istream_class
;
112 g_type_class_add_private (klass
, sizeof (GConverterInputStreamPrivate
));
114 object_class
= G_OBJECT_CLASS (klass
);
115 object_class
->get_property
= g_converter_input_stream_get_property
;
116 object_class
->set_property
= g_converter_input_stream_set_property
;
117 object_class
->finalize
= g_converter_input_stream_finalize
;
119 istream_class
= G_INPUT_STREAM_CLASS (klass
);
120 istream_class
->read_fn
= g_converter_input_stream_read
;
122 g_object_class_install_property (object_class
,
124 g_param_spec_object ("converter",
126 P_("The converter object"),
129 G_PARAM_CONSTRUCT_ONLY
|
130 G_PARAM_STATIC_STRINGS
));
135 g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface
*iface
)
137 iface
->can_poll
= g_converter_input_stream_can_poll
;
138 iface
->is_readable
= g_converter_input_stream_is_readable
;
139 iface
->read_nonblocking
= g_converter_input_stream_read_nonblocking
;
140 iface
->create_source
= g_converter_input_stream_create_source
;
144 g_converter_input_stream_finalize (GObject
*object
)
146 GConverterInputStreamPrivate
*priv
;
147 GConverterInputStream
*stream
;
149 stream
= G_CONVERTER_INPUT_STREAM (object
);
152 g_free (priv
->input_buffer
.data
);
153 g_free (priv
->converted_buffer
.data
);
155 g_object_unref (priv
->converter
);
157 G_OBJECT_CLASS (g_converter_input_stream_parent_class
)->finalize (object
);
161 g_converter_input_stream_set_property (GObject
*object
,
166 GConverterInputStream
*cstream
;
168 cstream
= G_CONVERTER_INPUT_STREAM (object
);
173 cstream
->priv
->converter
= g_value_dup_object (value
);
177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
184 g_converter_input_stream_get_property (GObject
*object
,
189 GConverterInputStreamPrivate
*priv
;
190 GConverterInputStream
*cstream
;
192 cstream
= G_CONVERTER_INPUT_STREAM (object
);
193 priv
= cstream
->priv
;
198 g_value_set_object (value
, priv
->converter
);
202 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
208 g_converter_input_stream_init (GConverterInputStream
*stream
)
210 stream
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (stream
,
211 G_TYPE_CONVERTER_INPUT_STREAM
,
212 GConverterInputStreamPrivate
);
216 * g_converter_input_stream_new:
217 * @base_stream: a #GInputStream
218 * @converter: a #GConverter
220 * Creates a new converter input stream for the @base_stream.
222 * Returns: a new #GInputStream.
225 g_converter_input_stream_new (GInputStream
*base_stream
,
226 GConverter
*converter
)
228 GInputStream
*stream
;
230 g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream
), NULL
);
232 stream
= g_object_new (G_TYPE_CONVERTER_INPUT_STREAM
,
233 "base-stream", base_stream
,
234 "converter", converter
,
241 buffer_data_size (Buffer
*buffer
)
243 return buffer
->end
- buffer
->start
;
247 buffer_tailspace (Buffer
*buffer
)
249 return buffer
->size
- buffer
->end
;
253 buffer_data (Buffer
*buffer
)
255 return buffer
->data
+ buffer
->start
;
259 buffer_consumed (Buffer
*buffer
,
262 buffer
->start
+= count
;
263 if (buffer
->start
== buffer
->end
)
264 buffer
->start
= buffer
->end
= 0;
268 buffer_read (Buffer
*buffer
,
272 memcpy (dest
, buffer
->data
+ buffer
->start
, count
);
273 buffer_consumed (buffer
, count
);
277 compact_buffer (Buffer
*buffer
)
281 in_buffer
= buffer_data_size (buffer
);
282 memmove (buffer
->data
,
283 buffer
->data
+ buffer
->start
,
285 buffer
->end
-= buffer
->start
;
290 grow_buffer (Buffer
*buffer
)
293 gsize size
, in_buffer
;
295 if (buffer
->size
== 0)
296 size
= INITIAL_BUFFER_SIZE
;
298 size
= buffer
->size
* 2;
300 data
= g_malloc (size
);
301 in_buffer
= buffer_data_size (buffer
);
304 buffer
->data
+ buffer
->start
,
306 g_free (buffer
->data
);
308 buffer
->end
-= buffer
->start
;
313 /* Ensures that the buffer can fit at_least_size bytes,
314 * *including* the current in-buffer data */
316 buffer_ensure_space (Buffer
*buffer
,
319 gsize in_buffer
, left_to_fill
;
321 in_buffer
= buffer_data_size (buffer
);
323 if (in_buffer
>= at_least_size
)
326 left_to_fill
= buffer_tailspace (buffer
);
328 if (in_buffer
+ left_to_fill
>= at_least_size
)
330 /* We fit in remaining space at end */
331 /* If the copy is small, compact now anyway so we can fill more */
333 compact_buffer (buffer
);
335 else if (buffer
->size
>= at_least_size
)
337 /* We fit, but only if we compact */
338 compact_buffer (buffer
);
342 /* Need to grow buffer */
343 while (buffer
->size
< at_least_size
)
344 grow_buffer (buffer
);
349 fill_input_buffer (GConverterInputStream
*stream
,
352 GCancellable
*cancellable
,
355 GConverterInputStreamPrivate
*priv
;
356 GInputStream
*base_stream
;
361 buffer_ensure_space (&priv
->input_buffer
, at_least_size
);
363 base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
364 nread
= g_pollable_stream_read (base_stream
,
365 priv
->input_buffer
.data
+ priv
->input_buffer
.end
,
366 buffer_tailspace (&priv
->input_buffer
),
373 priv
->input_buffer
.end
+= nread
;
374 priv
->need_input
= FALSE
;
382 read_internal (GInputStream
*stream
,
386 GCancellable
*cancellable
,
389 GConverterInputStream
*cstream
;
390 GConverterInputStreamPrivate
*priv
;
391 gsize available
, total_bytes_read
;
393 GConverterResult res
;
399 cstream
= G_CONVERTER_INPUT_STREAM (stream
);
400 priv
= cstream
->priv
;
402 available
= buffer_data_size (&priv
->converted_buffer
);
407 /* Converted data available, return that */
408 buffer_read (&priv
->converted_buffer
, buffer
, count
);
412 /* Full request not available, read all currently available and request
413 refill/conversion for more */
415 buffer_read (&priv
->converted_buffer
, buffer
, available
);
417 total_bytes_read
= available
;
418 buffer
= (char *) buffer
+ available
;
421 /* If there is no data to convert, and no pre-converted data,
422 do some i/o for more input */
423 if (buffer_data_size (&priv
->input_buffer
) == 0 &&
424 total_bytes_read
== 0 &&
427 nread
= fill_input_buffer (cstream
, count
, blocking
, cancellable
, error
);
431 priv
->at_input_end
= TRUE
;
434 /* First try to convert any available data (or state) directly to the user buffer: */
438 res
= g_converter_convert (priv
->converter
,
439 buffer_data (&priv
->input_buffer
),
440 buffer_data_size (&priv
->input_buffer
),
442 priv
->at_input_end
? G_CONVERTER_INPUT_AT_END
: 0,
446 if (res
!= G_CONVERTER_ERROR
)
448 total_bytes_read
+= bytes_written
;
449 buffer_consumed (&priv
->input_buffer
, bytes_read
);
450 if (res
== G_CONVERTER_FINISHED
)
451 priv
->finished
= TRUE
; /* We're done converting */
453 else if (total_bytes_read
== 0 &&
454 !g_error_matches (my_error
,
456 G_IO_ERROR_PARTIAL_INPUT
) &&
457 !g_error_matches (my_error
,
459 G_IO_ERROR_NO_SPACE
))
461 /* No previously read data and no "special" error, return error */
462 g_propagate_error (error
, my_error
);
466 g_error_free (my_error
);
469 /* We had some pre-converted data and/or we converted directly to the
471 if (total_bytes_read
> 0)
472 return total_bytes_read
;
474 /* If there is no more to convert, return EOF */
477 g_assert (buffer_data_size (&priv
->converted_buffer
) == 0);
481 /* There was "complexity" in the straight-to-buffer conversion,
482 * convert to our own buffer and write from that.
483 * At this point we didn't produce any data into @buffer.
486 /* Ensure we have *some* initial target space */
487 buffer_ensure_space (&priv
->converted_buffer
, count
);
491 g_assert (!priv
->finished
);
493 /* Try to convert to our buffer */
495 res
= g_converter_convert (priv
->converter
,
496 buffer_data (&priv
->input_buffer
),
497 buffer_data_size (&priv
->input_buffer
),
498 buffer_data (&priv
->converted_buffer
),
499 buffer_tailspace (&priv
->converted_buffer
),
500 priv
->at_input_end
? G_CONVERTER_INPUT_AT_END
: 0,
504 if (res
!= G_CONVERTER_ERROR
)
506 priv
->converted_buffer
.end
+= bytes_written
;
507 buffer_consumed (&priv
->input_buffer
, bytes_read
);
509 /* Maybe we consumed without producing any output */
510 if (buffer_data_size (&priv
->converted_buffer
) == 0 && res
!= G_CONVERTER_FINISHED
)
511 continue; /* Convert more */
513 if (res
== G_CONVERTER_FINISHED
)
514 priv
->finished
= TRUE
;
516 total_bytes_read
= MIN (count
, buffer_data_size (&priv
->converted_buffer
));
517 buffer_read (&priv
->converted_buffer
, buffer
, total_bytes_read
);
519 g_assert (priv
->finished
|| total_bytes_read
> 0);
521 return total_bytes_read
;
524 /* There was some kind of error filling our buffer */
526 if (g_error_matches (my_error
,
528 G_IO_ERROR_PARTIAL_INPUT
) &&
533 nread
= fill_input_buffer (cstream
,
534 buffer_data_size (&priv
->input_buffer
) + 4096,
540 /* Can't read any more data, return that error */
541 g_error_free (my_error
);
542 g_propagate_error (error
, my_error2
);
543 priv
->need_input
= TRUE
;
548 /* End of file, try INPUT_AT_END */
549 priv
->at_input_end
= TRUE
;
551 g_error_free (my_error
);
555 if (g_error_matches (my_error
,
557 G_IO_ERROR_NO_SPACE
))
559 /* Need more destination space, grow it
560 * Note: if we actually grow the buffer (as opposed to compacting it),
561 * this will double the size, not just add one byte. */
562 buffer_ensure_space (&priv
->converted_buffer
,
563 priv
->converted_buffer
.size
+ 1);
564 g_error_free (my_error
);
568 /* Any other random error, return it */
569 g_propagate_error (error
, my_error
);
573 g_assert_not_reached ();
577 g_converter_input_stream_read (GInputStream
*stream
,
580 GCancellable
*cancellable
,
583 return read_internal (stream
, buffer
, count
, TRUE
, cancellable
, error
);
587 g_converter_input_stream_can_poll (GPollableInputStream
*stream
)
589 GInputStream
*base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
591 return (G_IS_POLLABLE_INPUT_STREAM (base_stream
) &&
592 g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (base_stream
)));
596 g_converter_input_stream_is_readable (GPollableInputStream
*stream
)
598 GInputStream
*base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
599 GConverterInputStream
*cstream
= G_CONVERTER_INPUT_STREAM (stream
);
601 if (buffer_data_size (&cstream
->priv
->converted_buffer
))
603 else if (buffer_data_size (&cstream
->priv
->input_buffer
) &&
604 !cstream
->priv
->need_input
)
607 return g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (base_stream
));
611 g_converter_input_stream_read_nonblocking (GPollableInputStream
*stream
,
616 return read_internal (G_INPUT_STREAM (stream
), buffer
, count
,
621 g_converter_input_stream_create_source (GPollableInputStream
*stream
,
622 GCancellable
*cancellable
)
624 GInputStream
*base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
625 GSource
*base_source
, *pollable_source
;
627 if (g_pollable_input_stream_is_readable (stream
))
628 base_source
= g_timeout_source_new (0);
630 base_source
= g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (base_stream
), NULL
);
632 pollable_source
= g_pollable_source_new_full (stream
, base_source
,
634 g_source_unref (base_source
);
636 return pollable_source
;
641 * g_converter_input_stream_get_converter:
642 * @converter_stream: a #GConverterInputStream
644 * Gets the #GConverter that is used by @converter_stream.
646 * Returns: (transfer none): the converter of the converter input stream
651 g_converter_input_stream_get_converter (GConverterInputStream
*converter_stream
)
653 return converter_stream
->priv
->converter
;