(root)/
glib-2.79.0/
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   * 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  }