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