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, see <http://www.gnu.org/licenses/>.
18 * Author: Alexander Larsson <alexl@redhat.com>
25 #include "gconverterinputstream.h"
26 #include "gpollableinputstream.h"
27 #include "gsimpleasyncresult.h"
28 #include "gcancellable.h"
29 #include "gioenumtypes.h"
35 * SECTION:gconverterinputstream
36 * @short_description: Converter Input Stream
38 * @see_also: #GInputStream, #GConverter
40 * Converter input stream implements #GInputStream and allows
41 * conversion of data of various types during reading.
43 * As of GLib 2.34, #GConverterInputStream implements
44 * #GPollableInputStream.
47 #define INITIAL_BUFFER_SIZE 4096
56 struct _GConverterInputStreamPrivate
{
57 gboolean at_input_end
;
60 GConverter
*converter
;
62 Buffer converted_buffer
;
70 static void g_converter_input_stream_set_property (GObject
*object
,
74 static void g_converter_input_stream_get_property (GObject
*object
,
78 static void g_converter_input_stream_finalize (GObject
*object
);
79 static gssize
g_converter_input_stream_read (GInputStream
*stream
,
82 GCancellable
*cancellable
,
85 static gboolean
g_converter_input_stream_can_poll (GPollableInputStream
*stream
);
86 static gboolean
g_converter_input_stream_is_readable (GPollableInputStream
*stream
);
87 static gssize
g_converter_input_stream_read_nonblocking (GPollableInputStream
*stream
,
92 static GSource
*g_converter_input_stream_create_source (GPollableInputStream
*stream
,
93 GCancellable
*cancellable
);
95 static void g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface
*iface
);
97 G_DEFINE_TYPE_WITH_CODE (GConverterInputStream
,
98 g_converter_input_stream
,
99 G_TYPE_FILTER_INPUT_STREAM
,
100 G_ADD_PRIVATE (GConverterInputStream
)
101 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM
,
102 g_converter_input_stream_pollable_iface_init
))
105 g_converter_input_stream_class_init (GConverterInputStreamClass
*klass
)
107 GObjectClass
*object_class
;
108 GInputStreamClass
*istream_class
;
110 object_class
= G_OBJECT_CLASS (klass
);
111 object_class
->get_property
= g_converter_input_stream_get_property
;
112 object_class
->set_property
= g_converter_input_stream_set_property
;
113 object_class
->finalize
= g_converter_input_stream_finalize
;
115 istream_class
= G_INPUT_STREAM_CLASS (klass
);
116 istream_class
->read_fn
= g_converter_input_stream_read
;
118 g_object_class_install_property (object_class
,
120 g_param_spec_object ("converter",
122 P_("The converter object"),
125 G_PARAM_CONSTRUCT_ONLY
|
126 G_PARAM_STATIC_STRINGS
));
131 g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface
*iface
)
133 iface
->can_poll
= g_converter_input_stream_can_poll
;
134 iface
->is_readable
= g_converter_input_stream_is_readable
;
135 iface
->read_nonblocking
= g_converter_input_stream_read_nonblocking
;
136 iface
->create_source
= g_converter_input_stream_create_source
;
140 g_converter_input_stream_finalize (GObject
*object
)
142 GConverterInputStreamPrivate
*priv
;
143 GConverterInputStream
*stream
;
145 stream
= G_CONVERTER_INPUT_STREAM (object
);
148 g_free (priv
->input_buffer
.data
);
149 g_free (priv
->converted_buffer
.data
);
151 g_object_unref (priv
->converter
);
153 G_OBJECT_CLASS (g_converter_input_stream_parent_class
)->finalize (object
);
157 g_converter_input_stream_set_property (GObject
*object
,
162 GConverterInputStream
*cstream
;
164 cstream
= G_CONVERTER_INPUT_STREAM (object
);
169 cstream
->priv
->converter
= g_value_dup_object (value
);
173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
180 g_converter_input_stream_get_property (GObject
*object
,
185 GConverterInputStreamPrivate
*priv
;
186 GConverterInputStream
*cstream
;
188 cstream
= G_CONVERTER_INPUT_STREAM (object
);
189 priv
= cstream
->priv
;
194 g_value_set_object (value
, priv
->converter
);
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
204 g_converter_input_stream_init (GConverterInputStream
*stream
)
206 stream
->priv
= g_converter_input_stream_get_instance_private (stream
);
210 * g_converter_input_stream_new:
211 * @base_stream: a #GInputStream
212 * @converter: a #GConverter
214 * Creates a new converter input stream for the @base_stream.
216 * Returns: a new #GInputStream.
219 g_converter_input_stream_new (GInputStream
*base_stream
,
220 GConverter
*converter
)
222 GInputStream
*stream
;
224 g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream
), NULL
);
226 stream
= g_object_new (G_TYPE_CONVERTER_INPUT_STREAM
,
227 "base-stream", base_stream
,
228 "converter", converter
,
235 buffer_data_size (Buffer
*buffer
)
237 return buffer
->end
- buffer
->start
;
241 buffer_tailspace (Buffer
*buffer
)
243 return buffer
->size
- buffer
->end
;
247 buffer_data (Buffer
*buffer
)
249 return buffer
->data
+ buffer
->start
;
253 buffer_consumed (Buffer
*buffer
,
256 buffer
->start
+= count
;
257 if (buffer
->start
== buffer
->end
)
258 buffer
->start
= buffer
->end
= 0;
262 buffer_read (Buffer
*buffer
,
266 memcpy (dest
, buffer
->data
+ buffer
->start
, count
);
267 buffer_consumed (buffer
, count
);
271 compact_buffer (Buffer
*buffer
)
275 in_buffer
= buffer_data_size (buffer
);
276 memmove (buffer
->data
,
277 buffer
->data
+ buffer
->start
,
279 buffer
->end
-= buffer
->start
;
284 grow_buffer (Buffer
*buffer
)
287 gsize size
, in_buffer
;
289 if (buffer
->size
== 0)
290 size
= INITIAL_BUFFER_SIZE
;
292 size
= buffer
->size
* 2;
294 data
= g_malloc (size
);
295 in_buffer
= buffer_data_size (buffer
);
298 buffer
->data
+ buffer
->start
,
300 g_free (buffer
->data
);
302 buffer
->end
-= buffer
->start
;
307 /* Ensures that the buffer can fit at_least_size bytes,
308 * *including* the current in-buffer data */
310 buffer_ensure_space (Buffer
*buffer
,
313 gsize in_buffer
, left_to_fill
;
315 in_buffer
= buffer_data_size (buffer
);
317 if (in_buffer
>= at_least_size
)
320 left_to_fill
= buffer_tailspace (buffer
);
322 if (in_buffer
+ left_to_fill
>= at_least_size
)
324 /* We fit in remaining space at end */
325 /* If the copy is small, compact now anyway so we can fill more */
327 compact_buffer (buffer
);
329 else if (buffer
->size
>= at_least_size
)
331 /* We fit, but only if we compact */
332 compact_buffer (buffer
);
336 /* Need to grow buffer */
337 while (buffer
->size
< at_least_size
)
338 grow_buffer (buffer
);
343 fill_input_buffer (GConverterInputStream
*stream
,
346 GCancellable
*cancellable
,
349 GConverterInputStreamPrivate
*priv
;
350 GInputStream
*base_stream
;
355 buffer_ensure_space (&priv
->input_buffer
, at_least_size
);
357 base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
358 nread
= g_pollable_stream_read (base_stream
,
359 priv
->input_buffer
.data
+ priv
->input_buffer
.end
,
360 buffer_tailspace (&priv
->input_buffer
),
367 priv
->input_buffer
.end
+= nread
;
368 priv
->need_input
= FALSE
;
376 read_internal (GInputStream
*stream
,
380 GCancellable
*cancellable
,
383 GConverterInputStream
*cstream
;
384 GConverterInputStreamPrivate
*priv
;
385 gsize available
, total_bytes_read
;
387 GConverterResult res
;
393 cstream
= G_CONVERTER_INPUT_STREAM (stream
);
394 priv
= cstream
->priv
;
396 available
= buffer_data_size (&priv
->converted_buffer
);
401 /* Converted data available, return that */
402 buffer_read (&priv
->converted_buffer
, buffer
, count
);
406 /* Full request not available, read all currently available and request
407 refill/conversion for more */
409 buffer_read (&priv
->converted_buffer
, buffer
, available
);
411 total_bytes_read
= available
;
412 buffer
= (char *) buffer
+ available
;
415 /* If there is no data to convert, and no pre-converted data,
416 do some i/o for more input */
417 if (buffer_data_size (&priv
->input_buffer
) == 0 &&
418 total_bytes_read
== 0 &&
421 nread
= fill_input_buffer (cstream
, count
, blocking
, cancellable
, error
);
425 priv
->at_input_end
= TRUE
;
428 /* First try to convert any available data (or state) directly to the user buffer: */
432 res
= g_converter_convert (priv
->converter
,
433 buffer_data (&priv
->input_buffer
),
434 buffer_data_size (&priv
->input_buffer
),
436 priv
->at_input_end
? G_CONVERTER_INPUT_AT_END
: 0,
440 if (res
!= G_CONVERTER_ERROR
)
442 total_bytes_read
+= bytes_written
;
443 buffer_consumed (&priv
->input_buffer
, bytes_read
);
444 if (res
== G_CONVERTER_FINISHED
)
445 priv
->finished
= TRUE
; /* We're done converting */
447 else if (total_bytes_read
== 0 &&
448 !g_error_matches (my_error
,
450 G_IO_ERROR_PARTIAL_INPUT
) &&
451 !g_error_matches (my_error
,
453 G_IO_ERROR_NO_SPACE
))
455 /* No previously read data and no "special" error, return error */
456 g_propagate_error (error
, my_error
);
460 g_error_free (my_error
);
463 /* We had some pre-converted data and/or we converted directly to the
465 if (total_bytes_read
> 0)
466 return total_bytes_read
;
468 /* If there is no more to convert, return EOF */
471 g_assert (buffer_data_size (&priv
->converted_buffer
) == 0);
475 /* There was "complexity" in the straight-to-buffer conversion,
476 * convert to our own buffer and write from that.
477 * At this point we didn't produce any data into @buffer.
480 /* Ensure we have *some* initial target space */
481 buffer_ensure_space (&priv
->converted_buffer
, count
);
485 g_assert (!priv
->finished
);
487 /* Try to convert to our buffer */
489 res
= g_converter_convert (priv
->converter
,
490 buffer_data (&priv
->input_buffer
),
491 buffer_data_size (&priv
->input_buffer
),
492 buffer_data (&priv
->converted_buffer
),
493 buffer_tailspace (&priv
->converted_buffer
),
494 priv
->at_input_end
? G_CONVERTER_INPUT_AT_END
: 0,
498 if (res
!= G_CONVERTER_ERROR
)
500 priv
->converted_buffer
.end
+= bytes_written
;
501 buffer_consumed (&priv
->input_buffer
, bytes_read
);
503 /* Maybe we consumed without producing any output */
504 if (buffer_data_size (&priv
->converted_buffer
) == 0 && res
!= G_CONVERTER_FINISHED
)
505 continue; /* Convert more */
507 if (res
== G_CONVERTER_FINISHED
)
508 priv
->finished
= TRUE
;
510 total_bytes_read
= MIN (count
, buffer_data_size (&priv
->converted_buffer
));
511 buffer_read (&priv
->converted_buffer
, buffer
, total_bytes_read
);
513 g_assert (priv
->finished
|| total_bytes_read
> 0);
515 return total_bytes_read
;
518 /* There was some kind of error filling our buffer */
520 if (g_error_matches (my_error
,
522 G_IO_ERROR_PARTIAL_INPUT
) &&
527 nread
= fill_input_buffer (cstream
,
528 buffer_data_size (&priv
->input_buffer
) + 4096,
534 /* Can't read any more data, return that error */
535 g_error_free (my_error
);
536 g_propagate_error (error
, my_error2
);
537 priv
->need_input
= TRUE
;
542 /* End of file, try INPUT_AT_END */
543 priv
->at_input_end
= TRUE
;
545 g_error_free (my_error
);
549 if (g_error_matches (my_error
,
551 G_IO_ERROR_NO_SPACE
))
553 /* Need more destination space, grow it
554 * Note: if we actually grow the buffer (as opposed to compacting it),
555 * this will double the size, not just add one byte. */
556 buffer_ensure_space (&priv
->converted_buffer
,
557 priv
->converted_buffer
.size
+ 1);
558 g_error_free (my_error
);
562 /* Any other random error, return it */
563 g_propagate_error (error
, my_error
);
567 g_assert_not_reached ();
571 g_converter_input_stream_read (GInputStream
*stream
,
574 GCancellable
*cancellable
,
577 return read_internal (stream
, buffer
, count
, TRUE
, cancellable
, error
);
581 g_converter_input_stream_can_poll (GPollableInputStream
*stream
)
583 GInputStream
*base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
585 return (G_IS_POLLABLE_INPUT_STREAM (base_stream
) &&
586 g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (base_stream
)));
590 g_converter_input_stream_is_readable (GPollableInputStream
*stream
)
592 GInputStream
*base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
593 GConverterInputStream
*cstream
= G_CONVERTER_INPUT_STREAM (stream
);
595 if (buffer_data_size (&cstream
->priv
->converted_buffer
))
597 else if (buffer_data_size (&cstream
->priv
->input_buffer
) &&
598 !cstream
->priv
->need_input
)
601 return g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (base_stream
));
605 g_converter_input_stream_read_nonblocking (GPollableInputStream
*stream
,
610 return read_internal (G_INPUT_STREAM (stream
), buffer
, count
,
615 g_converter_input_stream_create_source (GPollableInputStream
*stream
,
616 GCancellable
*cancellable
)
618 GInputStream
*base_stream
= G_FILTER_INPUT_STREAM (stream
)->base_stream
;
619 GSource
*base_source
, *pollable_source
;
621 if (g_pollable_input_stream_is_readable (stream
))
622 base_source
= g_timeout_source_new (0);
624 base_source
= g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (base_stream
), NULL
);
626 pollable_source
= g_pollable_source_new_full (stream
, base_source
,
628 g_source_unref (base_source
);
630 return pollable_source
;
635 * g_converter_input_stream_get_converter:
636 * @converter_stream: a #GConverterInputStream
638 * Gets the #GConverter that is used by @converter_stream.
640 * Returns: (transfer none): the converter of the converter input stream
645 g_converter_input_stream_get_converter (GConverterInputStream
*converter_stream
)
647 return converter_stream
->priv
->converter
;