1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2009 Red Hat, Inc.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 *
20 * Author: Alexander Larsson <alexl@redhat.com>
21 */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include "gconverterinputstream.h"
28 #include "gpollableinputstream.h"
29 #include "gcancellable.h"
30 #include "gioenumtypes.h"
31 #include "gioerror.h"
32 #include "glibintl.h"
33
34
35 /**
36 * GConverterInputStream:
37 *
38 * Converter input stream implements [class@Gio.InputStream] and allows
39 * conversion of data of various types during reading.
40 *
41 * As of GLib 2.34, `GConverterInputStream` implements
42 * [iface@Gio.PollableInputStream].
43 */
44
45 #define INITIAL_BUFFER_SIZE 4096
46
47 typedef struct {
48 char *data;
49 gsize start;
50 gsize end;
51 gsize size;
52 } Buffer;
53
54 struct _GConverterInputStreamPrivate {
55 gboolean at_input_end;
56 gboolean finished;
57 gboolean need_input;
58 GConverter *converter;
59 Buffer input_buffer;
60 Buffer converted_buffer;
61 };
62
63 enum {
64 PROP_0,
65 PROP_CONVERTER
66 };
67
68 static void g_converter_input_stream_set_property (GObject *object,
69 guint prop_id,
70 const GValue *value,
71 GParamSpec *pspec);
72 static void g_converter_input_stream_get_property (GObject *object,
73 guint prop_id,
74 GValue *value,
75 GParamSpec *pspec);
76 static void g_converter_input_stream_finalize (GObject *object);
77 static gssize g_converter_input_stream_read (GInputStream *stream,
78 void *buffer,
79 gsize count,
80 GCancellable *cancellable,
81 GError **error);
82
83 static gboolean g_converter_input_stream_can_poll (GPollableInputStream *stream);
84 static gboolean g_converter_input_stream_is_readable (GPollableInputStream *stream);
85 static gssize g_converter_input_stream_read_nonblocking (GPollableInputStream *stream,
86 void *buffer,
87 gsize size,
88 GError **error);
89
90 static GSource *g_converter_input_stream_create_source (GPollableInputStream *stream,
91 GCancellable *cancellable);
92
93 static void g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface);
94
95 G_DEFINE_TYPE_WITH_CODE (GConverterInputStream,
96 g_converter_input_stream,
97 G_TYPE_FILTER_INPUT_STREAM,
98 G_ADD_PRIVATE (GConverterInputStream)
99 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
100 g_converter_input_stream_pollable_iface_init))
101
102 static void
103 g_converter_input_stream_class_init (GConverterInputStreamClass *klass)
104 {
105 GObjectClass *object_class;
106 GInputStreamClass *istream_class;
107
108 object_class = G_OBJECT_CLASS (klass);
109 object_class->get_property = g_converter_input_stream_get_property;
110 object_class->set_property = g_converter_input_stream_set_property;
111 object_class->finalize = g_converter_input_stream_finalize;
112
113 istream_class = G_INPUT_STREAM_CLASS (klass);
114 istream_class->read_fn = g_converter_input_stream_read;
115
116 /**
117 * GConverterInputStream:converter:
118 *
119 * The converter object.
120 */
121 g_object_class_install_property (object_class,
122 PROP_CONVERTER,
123 g_param_spec_object ("converter", NULL, NULL,
124 G_TYPE_CONVERTER,
125 G_PARAM_READWRITE|
126 G_PARAM_CONSTRUCT_ONLY|
127 G_PARAM_STATIC_STRINGS));
128
129 }
130
131 static void
132 g_converter_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
133 {
134 iface->can_poll = g_converter_input_stream_can_poll;
135 iface->is_readable = g_converter_input_stream_is_readable;
136 iface->read_nonblocking = g_converter_input_stream_read_nonblocking;
137 iface->create_source = g_converter_input_stream_create_source;
138 }
139
140 static void
141 g_converter_input_stream_finalize (GObject *object)
142 {
143 GConverterInputStreamPrivate *priv;
144 GConverterInputStream *stream;
145
146 stream = G_CONVERTER_INPUT_STREAM (object);
147 priv = stream->priv;
148
149 g_free (priv->input_buffer.data);
150 g_free (priv->converted_buffer.data);
151 if (priv->converter)
152 g_object_unref (priv->converter);
153
154 G_OBJECT_CLASS (g_converter_input_stream_parent_class)->finalize (object);
155 }
156
157 static void
158 g_converter_input_stream_set_property (GObject *object,
159 guint prop_id,
160 const GValue *value,
161 GParamSpec *pspec)
162 {
163 GConverterInputStream *cstream;
164
165 cstream = G_CONVERTER_INPUT_STREAM (object);
166
167 switch (prop_id)
168 {
169 case PROP_CONVERTER:
170 cstream->priv->converter = g_value_dup_object (value);
171 break;
172
173 default:
174 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
175 break;
176 }
177
178 }
179
180 static void
181 g_converter_input_stream_get_property (GObject *object,
182 guint prop_id,
183 GValue *value,
184 GParamSpec *pspec)
185 {
186 GConverterInputStreamPrivate *priv;
187 GConverterInputStream *cstream;
188
189 cstream = G_CONVERTER_INPUT_STREAM (object);
190 priv = cstream->priv;
191
192 switch (prop_id)
193 {
194 case PROP_CONVERTER:
195 g_value_set_object (value, priv->converter);
196 break;
197
198 default:
199 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
200 break;
201 }
202
203 }
204 static void
205 g_converter_input_stream_init (GConverterInputStream *stream)
206 {
207 stream->priv = g_converter_input_stream_get_instance_private (stream);
208 }
209
210 /**
211 * g_converter_input_stream_new:
212 * @base_stream: a #GInputStream
213 * @converter: a #GConverter
214 *
215 * Creates a new converter input stream for the @base_stream.
216 *
217 * Returns: a new #GInputStream.
218 **/
219 GInputStream *
220 g_converter_input_stream_new (GInputStream *base_stream,
221 GConverter *converter)
222 {
223 GInputStream *stream;
224
225 g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
226
227 stream = g_object_new (G_TYPE_CONVERTER_INPUT_STREAM,
228 "base-stream", base_stream,
229 "converter", converter,
230 NULL);
231
232 return stream;
233 }
234
235 static gsize
236 buffer_data_size (Buffer *buffer)
237 {
238 return buffer->end - buffer->start;
239 }
240
241 static gsize
242 buffer_tailspace (Buffer *buffer)
243 {
244 return buffer->size - buffer->end;
245 }
246
247 static char *
248 buffer_data (Buffer *buffer)
249 {
250 return buffer->data + buffer->start;
251 }
252
253 static void
254 buffer_consumed (Buffer *buffer,
255 gsize count)
256 {
257 buffer->start += count;
258 if (buffer->start == buffer->end)
259 buffer->start = buffer->end = 0;
260 }
261
262 static void
263 buffer_read (Buffer *buffer,
264 char *dest,
265 gsize count)
266 {
267 if (count != 0)
268 memcpy (dest, buffer->data + buffer->start, count);
269
270 buffer_consumed (buffer, count);
271 }
272
273 static void
274 compact_buffer (Buffer *buffer)
275 {
276 gsize in_buffer;
277
278 in_buffer = buffer_data_size (buffer);
279 memmove (buffer->data,
280 buffer->data + buffer->start,
281 in_buffer);
282 buffer->end -= buffer->start;
283 buffer->start = 0;
284 }
285
286 static void
287 grow_buffer (Buffer *buffer)
288 {
289 char *data;
290 gsize size, in_buffer;
291
292 if (buffer->size == 0)
293 size = INITIAL_BUFFER_SIZE;
294 else
295 size = buffer->size * 2;
296
297 data = g_malloc (size);
298 in_buffer = buffer_data_size (buffer);
299
300 if (in_buffer != 0)
301 memcpy (data,
302 buffer->data + buffer->start,
303 in_buffer);
304
305 g_free (buffer->data);
306 buffer->data = data;
307 buffer->end -= buffer->start;
308 buffer->start = 0;
309 buffer->size = size;
310 }
311
312 /* Ensures that the buffer can fit at_least_size bytes,
313 * *including* the current in-buffer data */
314 static void
315 buffer_ensure_space (Buffer *buffer,
316 gsize at_least_size)
317 {
318 gsize in_buffer, left_to_fill;
319
320 in_buffer = buffer_data_size (buffer);
321
322 if (in_buffer >= at_least_size)
323 return;
324
325 left_to_fill = buffer_tailspace (buffer);
326
327 if (in_buffer + left_to_fill >= at_least_size)
328 {
329 /* We fit in remaining space at end */
330 /* If the copy is small, compact now anyway so we can fill more */
331 if (in_buffer < 256)
332 compact_buffer (buffer);
333 }
334 else if (buffer->size >= at_least_size)
335 {
336 /* We fit, but only if we compact */
337 compact_buffer (buffer);
338 }
339 else
340 {
341 /* Need to grow buffer */
342 while (buffer->size < at_least_size)
343 grow_buffer (buffer);
344 }
345 }
346
347 static gssize
348 fill_input_buffer (GConverterInputStream *stream,
349 gsize at_least_size,
350 gboolean blocking,
351 GCancellable *cancellable,
352 GError **error)
353 {
354 GConverterInputStreamPrivate *priv;
355 GInputStream *base_stream;
356 gssize nread;
357
358 priv = stream->priv;
359
360 buffer_ensure_space (&priv->input_buffer, at_least_size);
361
362 base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
363 nread = g_pollable_stream_read (base_stream,
364 priv->input_buffer.data + priv->input_buffer.end,
365 buffer_tailspace (&priv->input_buffer),
366 blocking,
367 cancellable,
368 error);
369
370 if (nread > 0)
371 {
372 priv->input_buffer.end += nread;
373 priv->need_input = FALSE;
374 }
375
376 return nread;
377 }
378
379
380 static gssize
381 read_internal (GInputStream *stream,
382 void *buffer,
383 gsize count,
384 gboolean blocking,
385 GCancellable *cancellable,
386 GError **error)
387 {
388 GConverterInputStream *cstream;
389 GConverterInputStreamPrivate *priv;
390 gsize available, total_bytes_read;
391 gssize nread;
392 GConverterResult res;
393 gsize bytes_read;
394 gsize bytes_written;
395 GError *my_error;
396 GError *my_error2;
397
398 cstream = G_CONVERTER_INPUT_STREAM (stream);
399 priv = cstream->priv;
400
401 available = buffer_data_size (&priv->converted_buffer);
402
403 if (available > 0 &&
404 count <= available)
405 {
406 /* Converted data available, return that */
407 buffer_read (&priv->converted_buffer, buffer, count);
408 return count;
409 }
410
411 /* Full request not available, read all currently available and request
412 refill/conversion for more */
413
414 buffer_read (&priv->converted_buffer, buffer, available);
415
416 total_bytes_read = available;
417 buffer = (char *) buffer + available;
418 count -= available;
419
420 /* If there is no data to convert, and no pre-converted data,
421 do some i/o for more input */
422 if (buffer_data_size (&priv->input_buffer) == 0 &&
423 total_bytes_read == 0 &&
424 !priv->at_input_end)
425 {
426 nread = fill_input_buffer (cstream, count, blocking, cancellable, error);
427 if (nread < 0)
428 return -1;
429 if (nread == 0)
430 priv->at_input_end = TRUE;
431 }
432
433 /* First try to convert any available data (or state) directly to the user buffer: */
434 if (!priv->finished)
435 {
436 my_error = NULL;
437 res = g_converter_convert (priv->converter,
438 buffer_data (&priv->input_buffer),
439 buffer_data_size (&priv->input_buffer),
440 buffer, count,
441 priv->at_input_end ? G_CONVERTER_INPUT_AT_END : 0,
442 &bytes_read,
443 &bytes_written,
444 &my_error);
445 if (res != G_CONVERTER_ERROR)
446 {
447 total_bytes_read += bytes_written;
448 buffer_consumed (&priv->input_buffer, bytes_read);
449 if (res == G_CONVERTER_FINISHED)
450 priv->finished = TRUE; /* We're done converting */
451 }
452 else if (total_bytes_read == 0 &&
453 !g_error_matches (my_error,
454 G_IO_ERROR,
455 G_IO_ERROR_PARTIAL_INPUT) &&
456 !g_error_matches (my_error,
457 G_IO_ERROR,
458 G_IO_ERROR_NO_SPACE))
459 {
460 /* No previously read data and no "special" error, return error */
461 g_propagate_error (error, my_error);
462 return -1;
463 }
464 else
465 g_error_free (my_error);
466 }
467
468 /* We had some pre-converted data and/or we converted directly to the
469 user buffer */
470 if (total_bytes_read > 0)
471 return total_bytes_read;
472
473 /* If there is no more to convert, return EOF */
474 if (priv->finished)
475 {
476 g_assert (buffer_data_size (&priv->converted_buffer) == 0);
477 return 0;
478 }
479
480 /* There was "complexity" in the straight-to-buffer conversion,
481 * convert to our own buffer and write from that.
482 * At this point we didn't produce any data into @buffer.
483 */
484
485 /* Ensure we have *some* initial target space */
486 buffer_ensure_space (&priv->converted_buffer, count);
487
488 while (TRUE)
489 {
490 g_assert (!priv->finished);
491
492 /* Try to convert to our buffer */
493 my_error = NULL;
494 res = g_converter_convert (priv->converter,
495 buffer_data (&priv->input_buffer),
496 buffer_data_size (&priv->input_buffer),
497 buffer_data (&priv->converted_buffer),
498 buffer_tailspace (&priv->converted_buffer),
499 priv->at_input_end ? G_CONVERTER_INPUT_AT_END : 0,
500 &bytes_read,
501 &bytes_written,
502 &my_error);
503 if (res != G_CONVERTER_ERROR)
504 {
505 priv->converted_buffer.end += bytes_written;
506 buffer_consumed (&priv->input_buffer, bytes_read);
507
508 /* Maybe we consumed without producing any output */
509 if (buffer_data_size (&priv->converted_buffer) == 0 && res != G_CONVERTER_FINISHED)
510 continue; /* Convert more */
511
512 if (res == G_CONVERTER_FINISHED)
513 priv->finished = TRUE;
514
515 total_bytes_read = MIN (count, buffer_data_size (&priv->converted_buffer));
516 buffer_read (&priv->converted_buffer, buffer, total_bytes_read);
517
518 g_assert (priv->finished || total_bytes_read > 0);
519
520 return total_bytes_read;
521 }
522
523 /* There was some kind of error filling our buffer */
524
525 if (g_error_matches (my_error,
526 G_IO_ERROR,
527 G_IO_ERROR_PARTIAL_INPUT) &&
528 !priv->at_input_end)
529 {
530 /* Need more data */
531 my_error2 = NULL;
532 nread = fill_input_buffer (cstream,
533 buffer_data_size (&priv->input_buffer) + 4096,
534 blocking,
535 cancellable,
536 &my_error2);
537 if (nread < 0)
538 {
539 /* Can't read any more data, return that error */
540 g_error_free (my_error);
541 g_propagate_error (error, my_error2);
542 priv->need_input = TRUE;
543 return -1;
544 }
545 else if (nread == 0)
546 {
547 /* End of file, try INPUT_AT_END */
548 priv->at_input_end = TRUE;
549 }
550 g_error_free (my_error);
551 continue;
552 }
553
554 if (g_error_matches (my_error,
555 G_IO_ERROR,
556 G_IO_ERROR_NO_SPACE))
557 {
558 /* Need more destination space, grow it
559 * Note: if we actually grow the buffer (as opposed to compacting it),
560 * this will double the size, not just add one byte. */
561 buffer_ensure_space (&priv->converted_buffer,
562 priv->converted_buffer.size + 1);
563 g_error_free (my_error);
564 continue;
565 }
566
567 /* Any other random error, return it */
568 g_propagate_error (error, my_error);
569 return -1;
570 }
571
572 g_assert_not_reached ();
573 }
574
575 static gssize
576 g_converter_input_stream_read (GInputStream *stream,
577 void *buffer,
578 gsize count,
579 GCancellable *cancellable,
580 GError **error)
581 {
582 return read_internal (stream, buffer, count, TRUE, cancellable, error);
583 }
584
585 static gboolean
586 g_converter_input_stream_can_poll (GPollableInputStream *stream)
587 {
588 GInputStream *base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
589
590 return (G_IS_POLLABLE_INPUT_STREAM (base_stream) &&
591 g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (base_stream)));
592 }
593
594 static gboolean
595 g_converter_input_stream_is_readable (GPollableInputStream *stream)
596 {
597 GInputStream *base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
598 GConverterInputStream *cstream = G_CONVERTER_INPUT_STREAM (stream);
599
600 if (buffer_data_size (&cstream->priv->converted_buffer))
601 return TRUE;
602 else if (buffer_data_size (&cstream->priv->input_buffer) &&
603 !cstream->priv->need_input)
604 return TRUE;
605 else
606 return g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (base_stream));
607 }
608
609 static gssize
610 g_converter_input_stream_read_nonblocking (GPollableInputStream *stream,
611 void *buffer,
612 gsize count,
613 GError **error)
614 {
615 return read_internal (G_INPUT_STREAM (stream), buffer, count,
616 FALSE, NULL, error);
617 }
618
619 static GSource *
620 g_converter_input_stream_create_source (GPollableInputStream *stream,
621 GCancellable *cancellable)
622 {
623 GInputStream *base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
624 GSource *base_source, *pollable_source;
625
626 if (g_pollable_input_stream_is_readable (stream))
627 base_source = g_timeout_source_new (0);
628 else
629 base_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (base_stream), NULL);
630
631 pollable_source = g_pollable_source_new_full (stream, base_source,
632 cancellable);
633 g_source_unref (base_source);
634
635 return pollable_source;
636 }
637
638
639 /**
640 * g_converter_input_stream_get_converter:
641 * @converter_stream: a #GConverterInputStream
642 *
643 * Gets the #GConverter that is used by @converter_stream.
644 *
645 * Returns: (transfer none): the converter of the converter input stream
646 *
647 * Since: 2.24
648 */
649 GConverter *
650 g_converter_input_stream_get_converter (GConverterInputStream *converter_stream)
651 {
652 return converter_stream->priv->converter;
653 }