gkdbus: Fix underflow and unreachable code bug
[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  * 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  * SECTION:gconverterinputstream
37  * @short_description: Converter Input Stream
38  * @include: gio/gio.h
39  * @see_also: #GInputStream, #GConverter
40  *
41  * Converter input stream implements #GInputStream and allows
42  * conversion of data of various types during reading.
43  *
44  * As of GLib 2.34, #GConverterInputStream implements
45  * #GPollableInputStream.
46  **/
47
48 #define INITIAL_BUFFER_SIZE 4096
49
50 typedef struct {
51   char *data;
52   gsize start;
53   gsize end;
54   gsize size;
55 } Buffer;
56
57 struct _GConverterInputStreamPrivate {
58   gboolean at_input_end;
59   gboolean finished;
60   gboolean need_input;
61   GConverter *converter;
62   Buffer input_buffer;
63   Buffer converted_buffer;
64 };
65
66 enum {
67   PROP_0,
68   PROP_CONVERTER
69 };
70
71 static void   g_converter_input_stream_set_property (GObject       *object,
72                                                      guint          prop_id,
73                                                      const GValue  *value,
74                                                      GParamSpec    *pspec);
75 static void   g_converter_input_stream_get_property (GObject       *object,
76                                                      guint          prop_id,
77                                                      GValue        *value,
78                                                      GParamSpec    *pspec);
79 static void   g_converter_input_stream_finalize     (GObject       *object);
80 static gssize g_converter_input_stream_read         (GInputStream  *stream,
81                                                      void          *buffer,
82                                                      gsize          count,
83                                                      GCancellable  *cancellable,
84                                                      GError       **error);
85
86 static gboolean g_converter_input_stream_can_poll         (GPollableInputStream *stream);
87 static gboolean g_converter_input_stream_is_readable      (GPollableInputStream *stream);
88 static gssize   g_converter_input_stream_read_nonblocking (GPollableInputStream  *stream,
89                                                            void                  *buffer,
90                                                            gsize                  size,
91                                                            GError               **error);
92
93 static GSource *g_converter_input_stream_create_source    (GPollableInputStream *stream,
94                                                            GCancellable          *cancellable);
95
96 static void g_converter_input_stream_pollable_iface_init  (GPollableInputStreamInterface *iface);
97
98 G_DEFINE_TYPE_WITH_CODE (GConverterInputStream,
99                          g_converter_input_stream,
100                          G_TYPE_FILTER_INPUT_STREAM,
101                          G_ADD_PRIVATE (GConverterInputStream)
102                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
103                                                 g_converter_input_stream_pollable_iface_init))
104
105 static void
106 g_converter_input_stream_class_init (GConverterInputStreamClass *klass)
107 {
108   GObjectClass *object_class;
109   GInputStreamClass *istream_class;
110
111   object_class = G_OBJECT_CLASS (klass);
112   object_class->get_property = g_converter_input_stream_get_property;
113   object_class->set_property = g_converter_input_stream_set_property;
114   object_class->finalize     = g_converter_input_stream_finalize;
115
116   istream_class = G_INPUT_STREAM_CLASS (klass);
117   istream_class->read_fn = g_converter_input_stream_read;
118
119   g_object_class_install_property (object_class,
120                                    PROP_CONVERTER,
121                                    g_param_spec_object ("converter",
122                                                         P_("Converter"),
123                                                         P_("The converter object"),
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 }