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