Blame gio/tests/converter-stream.c

Packit ae235b
/* GLib testing framework examples and tests
Packit ae235b
 * Copyright (C) 2009 Red Hat, Inc.
Packit ae235b
 * Authors: Alexander Larsson <alexl@redhat.com>
Packit ae235b
 *
Packit ae235b
 * This work is provided "as is"; redistribution and modification
Packit ae235b
 * in whole or in part, in any medium, physical or electronic is
Packit ae235b
 * permitted without restriction.
Packit ae235b
 *
Packit ae235b
 * This work is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit ae235b
 *
Packit ae235b
 * In no event shall the authors or contributors be liable for any
Packit ae235b
 * direct, indirect, incidental, special, exemplary, or consequential
Packit ae235b
 * damages (including, but not limited to, procurement of substitute
Packit ae235b
 * goods or services; loss of use, data, or profits; or business
Packit ae235b
 * interruption) however caused and on any theory of liability, whether
Packit ae235b
 * in contract, strict liability, or tort (including negligence or
Packit ae235b
 * otherwise) arising in any way out of the use of this software, even
Packit ae235b
 * if advised of the possibility of such damage.
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include <glib/glib.h>
Packit ae235b
#include <gio/gio.h>
Packit ae235b
#include <stdlib.h>
Packit ae235b
#include <string.h>
Packit ae235b
Packit ae235b
#define G_TYPE_EXPANDER_CONVERTER         (g_expander_converter_get_type ())
Packit ae235b
#define G_EXPANDER_CONVERTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverter))
Packit ae235b
#define G_EXPANDER_CONVERTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass))
Packit ae235b
#define G_IS_EXPANDER_CONVERTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_EXPANDER_CONVERTER))
Packit ae235b
#define G_IS_EXPANDER_CONVERTER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_EXPANDER_CONVERTER))
Packit ae235b
#define G_EXPANDER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass))
Packit ae235b
Packit ae235b
typedef struct _GExpanderConverter       GExpanderConverter;
Packit ae235b
typedef struct _GExpanderConverterClass  GExpanderConverterClass;
Packit ae235b
Packit ae235b
struct _GExpanderConverterClass
Packit ae235b
{
Packit ae235b
  GObjectClass parent_class;
Packit ae235b
};
Packit ae235b
Packit ae235b
GType       g_expander_converter_get_type (void) G_GNUC_CONST;
Packit ae235b
GConverter *g_expander_converter_new      (void);
Packit ae235b
Packit ae235b
Packit ae235b
Packit ae235b
static void g_expander_converter_iface_init          (GConverterIface *iface);
Packit ae235b
Packit ae235b
struct _GExpanderConverter
Packit ae235b
{
Packit ae235b
  GObject parent_instance;
Packit ae235b
};
Packit ae235b
Packit ae235b
G_DEFINE_TYPE_WITH_CODE (GExpanderConverter, g_expander_converter, G_TYPE_OBJECT,
Packit ae235b
			 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
Packit ae235b
						g_expander_converter_iface_init))
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_expander_converter_class_init (GExpanderConverterClass *klass)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_expander_converter_init (GExpanderConverter *local)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
GConverter *
Packit ae235b
g_expander_converter_new (void)
Packit ae235b
{
Packit ae235b
  GConverter *conv;
Packit ae235b
Packit ae235b
  conv = g_object_new (G_TYPE_EXPANDER_CONVERTER, NULL);
Packit ae235b
Packit ae235b
  return conv;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_expander_converter_reset (GConverter *converter)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static GConverterResult
Packit ae235b
g_expander_converter_convert (GConverter *converter,
Packit ae235b
			      const void *inbuf,
Packit ae235b
			      gsize       inbuf_size,
Packit ae235b
			      void       *outbuf,
Packit ae235b
			      gsize       outbuf_size,
Packit ae235b
			      GConverterFlags flags,
Packit ae235b
			      gsize      *bytes_read,
Packit ae235b
			      gsize      *bytes_written,
Packit ae235b
			      GError    **error)
Packit ae235b
{
Packit ae235b
  const guint8 *in, *in_end;
Packit ae235b
  guint8 v, *out;
Packit ae235b
  int i;
Packit ae235b
  gsize block_size;
Packit ae235b
Packit ae235b
  in = inbuf;
Packit ae235b
  out = outbuf;
Packit ae235b
  in_end = in + inbuf_size;
Packit ae235b
Packit ae235b
  while (in < in_end)
Packit ae235b
    {
Packit ae235b
      v = *in;
Packit ae235b
Packit ae235b
      if (v == 0)
Packit ae235b
	block_size = 10;
Packit ae235b
      else
Packit ae235b
	block_size = v * 1000;
Packit ae235b
Packit ae235b
      if (outbuf_size < block_size)
Packit ae235b
	{
Packit ae235b
	  if (*bytes_read > 0)
Packit ae235b
	    return G_CONVERTER_CONVERTED;
Packit ae235b
Packit ae235b
	  g_set_error_literal (error, G_IO_ERROR,
Packit ae235b
			       G_IO_ERROR_NO_SPACE,
Packit ae235b
			       "No space in dest");
Packit ae235b
	  return G_CONVERTER_ERROR;
Packit ae235b
	}
Packit ae235b
Packit ae235b
      in++;
Packit ae235b
      *bytes_read += 1;
Packit ae235b
      *bytes_written += block_size;
Packit ae235b
      outbuf_size -= block_size;
Packit ae235b
      for (i = 0; i < block_size; i++)
Packit ae235b
	*out++ = v;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END))
Packit ae235b
    return G_CONVERTER_FINISHED;
Packit ae235b
  return G_CONVERTER_CONVERTED;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_expander_converter_iface_init (GConverterIface *iface)
Packit ae235b
{
Packit ae235b
  iface->convert = g_expander_converter_convert;
Packit ae235b
  iface->reset = g_expander_converter_reset;
Packit ae235b
}
Packit ae235b
Packit ae235b
#define G_TYPE_COMPRESSOR_CONVERTER         (g_compressor_converter_get_type ())
Packit ae235b
#define G_COMPRESSOR_CONVERTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverter))
Packit ae235b
#define G_COMPRESSOR_CONVERTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
Packit ae235b
#define G_IS_COMPRESSOR_CONVERTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_COMPRESSOR_CONVERTER))
Packit ae235b
#define G_IS_COMPRESSOR_CONVERTER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_COMPRESSOR_CONVERTER))
Packit ae235b
#define G_COMPRESSOR_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
Packit ae235b
Packit ae235b
typedef struct _GCompressorConverter       GCompressorConverter;
Packit ae235b
typedef struct _GCompressorConverterClass  GCompressorConverterClass;
Packit ae235b
Packit ae235b
struct _GCompressorConverterClass
Packit ae235b
{
Packit ae235b
  GObjectClass parent_class;
Packit ae235b
};
Packit ae235b
Packit ae235b
GType       g_compressor_converter_get_type (void) G_GNUC_CONST;
Packit ae235b
GConverter *g_compressor_converter_new      (void);
Packit ae235b
Packit ae235b
Packit ae235b
Packit ae235b
static void g_compressor_converter_iface_init          (GConverterIface *iface);
Packit ae235b
Packit ae235b
struct _GCompressorConverter
Packit ae235b
{
Packit ae235b
  GObject parent_instance;
Packit ae235b
};
Packit ae235b
Packit ae235b
G_DEFINE_TYPE_WITH_CODE (GCompressorConverter, g_compressor_converter, G_TYPE_OBJECT,
Packit ae235b
			 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
Packit ae235b
						g_compressor_converter_iface_init))
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_compressor_converter_class_init (GCompressorConverterClass *klass)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_compressor_converter_init (GCompressorConverter *local)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
GConverter *
Packit ae235b
g_compressor_converter_new (void)
Packit ae235b
{
Packit ae235b
  GConverter *conv;
Packit ae235b
Packit ae235b
  conv = g_object_new (G_TYPE_COMPRESSOR_CONVERTER, NULL);
Packit ae235b
Packit ae235b
  return conv;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_compressor_converter_reset (GConverter *converter)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static GConverterResult
Packit ae235b
g_compressor_converter_convert (GConverter *converter,
Packit ae235b
				const void *inbuf,
Packit ae235b
				gsize       inbuf_size,
Packit ae235b
				void       *outbuf,
Packit ae235b
				gsize       outbuf_size,
Packit ae235b
				GConverterFlags flags,
Packit ae235b
				gsize      *bytes_read,
Packit ae235b
				gsize      *bytes_written,
Packit ae235b
				GError    **error)
Packit ae235b
{
Packit ae235b
  const guint8 *in, *in_end;
Packit ae235b
  guint8 v, *out;
Packit ae235b
  int i;
Packit ae235b
  gsize block_size;
Packit ae235b
Packit ae235b
  in = inbuf;
Packit ae235b
  out = outbuf;
Packit ae235b
  in_end = in + inbuf_size;
Packit ae235b
Packit ae235b
  while (in < in_end)
Packit ae235b
    {
Packit ae235b
      v = *in;
Packit ae235b
Packit ae235b
      if (v == 0)
Packit ae235b
	{
Packit ae235b
	  block_size = 0;
Packit ae235b
	  while (in+block_size < in_end && *(in+block_size) == 0)
Packit ae235b
	    block_size ++;
Packit ae235b
	}
Packit ae235b
      else
Packit ae235b
	block_size = v * 1000;
Packit ae235b
Packit ae235b
      /* Not enough data */
Packit ae235b
      if (in_end - in < block_size)
Packit ae235b
	{
Packit ae235b
	  if (*bytes_read > 0)
Packit ae235b
	    break;
Packit ae235b
	  g_set_error_literal (error, G_IO_ERROR,
Packit ae235b
			       G_IO_ERROR_PARTIAL_INPUT,
Packit ae235b
			       "Need more data");
Packit ae235b
	  return G_CONVERTER_ERROR;
Packit ae235b
	}
Packit ae235b
Packit ae235b
      for (i = 0; i < block_size; i++)
Packit ae235b
	{
Packit ae235b
	  if (*(in + i) != v)
Packit ae235b
	    {
Packit ae235b
	      if (*bytes_read > 0)
Packit ae235b
		break;
Packit ae235b
	      g_set_error_literal (error, G_IO_ERROR,
Packit ae235b
				   G_IO_ERROR_INVALID_DATA,
Packit ae235b
				   "invalid data");
Packit ae235b
	      return G_CONVERTER_ERROR;
Packit ae235b
	    }
Packit ae235b
	}
Packit ae235b
Packit ae235b
      if (v == 0 && in_end - in == block_size && (flags & G_CONVERTER_INPUT_AT_END) == 0)
Packit ae235b
	{
Packit ae235b
	  if (*bytes_read > 0)
Packit ae235b
	    break;
Packit ae235b
	  g_set_error_literal (error, G_IO_ERROR,
Packit ae235b
			       G_IO_ERROR_PARTIAL_INPUT,
Packit ae235b
			       "Need more data");
Packit ae235b
	  return G_CONVERTER_ERROR;
Packit ae235b
	}
Packit ae235b
Packit ae235b
      in += block_size;
Packit ae235b
      *out++ = v;
Packit ae235b
      *bytes_read += block_size;
Packit ae235b
      *bytes_written += 1;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END))
Packit ae235b
    return G_CONVERTER_FINISHED;
Packit ae235b
  return G_CONVERTER_CONVERTED;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_compressor_converter_iface_init (GConverterIface *iface)
Packit ae235b
{
Packit ae235b
  iface->convert = g_compressor_converter_convert;
Packit ae235b
  iface->reset = g_compressor_converter_reset;
Packit ae235b
}
Packit ae235b
Packit ae235b
guint8 unexpanded_data[] = { 0,1,3,4,5,6,7,3,12,0,0};
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_expander (void)
Packit ae235b
{
Packit ae235b
  guint8 *converted1, *converted2, *ptr;
Packit ae235b
  gsize n_read, n_written;
Packit ae235b
  gsize total_read;
Packit ae235b
  gssize res;
Packit ae235b
  GConverterResult cres;
Packit ae235b
  GInputStream *mem, *cstream;
Packit ae235b
  GOutputStream *mem_out, *cstream_out;
Packit ae235b
  GConverter *expander;
Packit ae235b
  GConverter *converter;
Packit ae235b
  GError *error;
Packit ae235b
  int i;
Packit ae235b
Packit ae235b
  expander = g_expander_converter_new ();
Packit ae235b
Packit ae235b
  converted1 = g_malloc (100*1000); /* Large enough */
Packit ae235b
  converted2 = g_malloc (100*1000); /* Large enough */
Packit ae235b
Packit ae235b
  cres = g_converter_convert (expander,
Packit ae235b
			      unexpanded_data, sizeof(unexpanded_data),
Packit ae235b
			      converted1, 100*1000,
Packit ae235b
			      G_CONVERTER_INPUT_AT_END,
Packit ae235b
			      &n_read, &n_written, NULL);
Packit ae235b
Packit ae235b
  g_assert (cres == G_CONVERTER_FINISHED);
Packit ae235b
  g_assert (n_read == 11);
Packit ae235b
  g_assert (n_written == 41030);
Packit ae235b
Packit ae235b
  g_converter_reset (expander);
Packit ae235b
Packit ae235b
  mem = g_memory_input_stream_new_from_data (unexpanded_data,
Packit ae235b
					     sizeof (unexpanded_data),
Packit ae235b
					     NULL);
Packit ae235b
  cstream = g_converter_input_stream_new (mem, expander);
Packit ae235b
  g_assert (g_converter_input_stream_get_converter (G_CONVERTER_INPUT_STREAM (cstream)) == expander);
Packit ae235b
  g_object_get (cstream, "converter", &converter, NULL);
Packit ae235b
  g_assert (converter == expander);
Packit ae235b
  g_object_unref (converter);
Packit ae235b
  g_object_unref (mem);
Packit ae235b
Packit ae235b
  total_read = 0;
Packit ae235b
  ptr = converted2;
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_input_stream_read (cstream,
Packit ae235b
				 ptr, 1,
Packit ae235b
				 NULL, &error);
Packit ae235b
      g_assert (res != -1);
Packit ae235b
      if (res == 0)
Packit ae235b
	break;
Packit ae235b
      ptr += res;
Packit ae235b
      total_read += res;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_assert_cmpmem (converted1, n_written, converted2, total_read);
Packit ae235b
Packit ae235b
  g_converter_reset (expander);
Packit ae235b
Packit ae235b
  mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
Packit ae235b
  cstream_out = g_converter_output_stream_new (mem_out, expander);
Packit ae235b
  g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (cstream_out)) == expander);
Packit ae235b
  g_object_get (cstream_out, "converter", &converter, NULL);
Packit ae235b
  g_assert (converter == expander);
Packit ae235b
  g_object_unref (converter);
Packit ae235b
  g_object_unref (mem_out);
Packit ae235b
Packit ae235b
  for (i = 0; i < sizeof(unexpanded_data); i++)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_output_stream_write (cstream_out,
Packit ae235b
				   unexpanded_data + i, 1,
Packit ae235b
				   NULL, &error);
Packit ae235b
      g_assert (res != -1);
Packit ae235b
      if (res == 0)
Packit ae235b
	{
Packit ae235b
	  g_assert (i == sizeof(unexpanded_data) -1);
Packit ae235b
	  break;
Packit ae235b
	}
Packit ae235b
      g_assert (res == 1);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_output_stream_close (cstream_out, NULL, NULL);
Packit ae235b
Packit ae235b
  g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
Packit ae235b
                   g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
Packit ae235b
                   converted1, n_written);
Packit ae235b
Packit ae235b
  g_free (converted1);
Packit ae235b
  g_free (converted2);
Packit ae235b
  g_object_unref (cstream);
Packit ae235b
  g_object_unref (cstream_out);
Packit ae235b
  g_object_unref (expander);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_compressor (void)
Packit ae235b
{
Packit ae235b
  guint8 *converted, *expanded, *ptr;
Packit ae235b
  gsize n_read, expanded_size;
Packit ae235b
  gsize total_read;
Packit ae235b
  gssize res;
Packit ae235b
  GConverterResult cres;
Packit ae235b
  GInputStream *mem, *cstream;
Packit ae235b
  GOutputStream *mem_out, *cstream_out;
Packit ae235b
  GConverter *expander, *compressor;
Packit ae235b
  GError *error;
Packit ae235b
  int i;
Packit ae235b
Packit ae235b
  expander = g_expander_converter_new ();
Packit ae235b
  expanded = g_malloc (100*1000); /* Large enough */
Packit ae235b
  cres = g_converter_convert (expander,
Packit ae235b
			      unexpanded_data, sizeof(unexpanded_data),
Packit ae235b
			      expanded, 100*1000,
Packit ae235b
			      G_CONVERTER_INPUT_AT_END,
Packit ae235b
			      &n_read, &expanded_size, NULL);
Packit ae235b
  g_assert (cres == G_CONVERTER_FINISHED);
Packit ae235b
  g_assert (n_read == 11);
Packit ae235b
  g_assert (expanded_size == 41030);
Packit ae235b
Packit ae235b
  compressor = g_compressor_converter_new ();
Packit ae235b
Packit ae235b
  converted = g_malloc (100*1000); /* Large enough */
Packit ae235b
Packit ae235b
  mem = g_memory_input_stream_new_from_data (expanded,
Packit ae235b
					     expanded_size,
Packit ae235b
					     NULL);
Packit ae235b
  cstream = g_converter_input_stream_new (mem, compressor);
Packit ae235b
  g_object_unref (mem);
Packit ae235b
Packit ae235b
  total_read = 0;
Packit ae235b
  ptr = converted;
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_input_stream_read (cstream,
Packit ae235b
				 ptr, 1,
Packit ae235b
				 NULL, &error);
Packit ae235b
      g_assert (res != -1);
Packit ae235b
      if (res == 0)
Packit ae235b
	break;
Packit ae235b
      ptr += res;
Packit ae235b
      total_read += res;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* "n_read - 1" because last 2 zeros are combined */
Packit ae235b
  g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read);
Packit ae235b
Packit ae235b
  g_object_unref (cstream);
Packit ae235b
Packit ae235b
  g_converter_reset (compressor);
Packit ae235b
Packit ae235b
  mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
Packit ae235b
  cstream_out = g_converter_output_stream_new (mem_out, compressor);
Packit ae235b
  g_object_unref (mem_out);
Packit ae235b
Packit ae235b
  for (i = 0; i < expanded_size; i++)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_output_stream_write (cstream_out,
Packit ae235b
				   expanded + i, 1,
Packit ae235b
				   NULL, &error);
Packit ae235b
      g_assert (res != -1);
Packit ae235b
      if (res == 0)
Packit ae235b
	{
Packit ae235b
	  g_assert (i == expanded_size -1);
Packit ae235b
	  break;
Packit ae235b
	}
Packit ae235b
      g_assert (res == 1);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_output_stream_close (cstream_out, NULL, NULL);
Packit ae235b
Packit ae235b
  /* "n_read - 1" because last 2 zeros are combined */
Packit ae235b
  g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
Packit ae235b
                   g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
Packit ae235b
                   unexpanded_data,
Packit ae235b
                   n_read - 1);
Packit ae235b
Packit ae235b
  g_object_unref (cstream_out);
Packit ae235b
Packit ae235b
  g_converter_reset (compressor);
Packit ae235b
Packit ae235b
  memset (expanded, 5, 5*1000*2);
Packit ae235b
Packit ae235b
  mem = g_memory_input_stream_new_from_data (expanded,
Packit ae235b
					     5*1000,
Packit ae235b
					     NULL);
Packit ae235b
  cstream = g_converter_input_stream_new (mem, compressor);
Packit ae235b
  g_object_unref (mem);
Packit ae235b
Packit ae235b
  total_read = 0;
Packit ae235b
  ptr = converted;
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_input_stream_read (cstream,
Packit ae235b
				 ptr, 1,
Packit ae235b
				 NULL, &error);
Packit ae235b
      g_assert (res != -1);
Packit ae235b
      if (res == 0)
Packit ae235b
	break;
Packit ae235b
      ptr += res;
Packit ae235b
      total_read += res;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_assert (total_read == 1);
Packit ae235b
  g_assert (*converted == 5);
Packit ae235b
Packit ae235b
  g_object_unref (cstream);
Packit ae235b
Packit ae235b
  mem = g_memory_input_stream_new_from_data (expanded,
Packit ae235b
					     5*1000 * 2,
Packit ae235b
					     NULL);
Packit ae235b
  cstream = g_converter_input_stream_new (mem, compressor);
Packit ae235b
  g_object_unref (mem);
Packit ae235b
Packit ae235b
  total_read = 0;
Packit ae235b
  ptr = converted;
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_input_stream_read (cstream,
Packit ae235b
				 ptr, 1,
Packit ae235b
				 NULL, &error);
Packit ae235b
      g_assert (res != -1);
Packit ae235b
      if (res == 0)
Packit ae235b
	break;
Packit ae235b
      ptr += res;
Packit ae235b
      total_read += res;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_assert (total_read == 2);
Packit ae235b
  g_assert (converted[0] == 5);
Packit ae235b
  g_assert (converted[1] == 5);
Packit ae235b
Packit ae235b
  g_object_unref (cstream);
Packit ae235b
Packit ae235b
  g_converter_reset (compressor);
Packit ae235b
Packit ae235b
  mem = g_memory_input_stream_new_from_data (expanded,
Packit ae235b
					     5*1000 * 2 - 1,
Packit ae235b
					     NULL);
Packit ae235b
  cstream = g_converter_input_stream_new (mem, compressor);
Packit ae235b
  g_object_unref (mem);
Packit ae235b
Packit ae235b
  total_read = 0;
Packit ae235b
  ptr = converted;
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_input_stream_read (cstream,
Packit ae235b
				 ptr, 1,
Packit ae235b
				 NULL, &error);
Packit ae235b
      if (res == -1)
Packit ae235b
	{
Packit ae235b
	  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
Packit ae235b
          g_error_free (error);
Packit ae235b
	  break;
Packit ae235b
	}
Packit ae235b
Packit ae235b
      g_assert (res != 0);
Packit ae235b
      ptr += res;
Packit ae235b
      total_read += res;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_assert (total_read == 1);
Packit ae235b
  g_assert (converted[0] == 5);
Packit ae235b
Packit ae235b
  g_object_unref (cstream);
Packit ae235b
Packit ae235b
  g_free (expanded);
Packit ae235b
  g_free (converted);
Packit ae235b
  g_object_unref (expander);
Packit ae235b
  g_object_unref (compressor);
Packit ae235b
}
Packit ae235b
Packit ae235b
#define LEFTOVER_SHORT_READ_SIZE 512
Packit ae235b
Packit ae235b
#define G_TYPE_LEFTOVER_CONVERTER         (g_leftover_converter_get_type ())
Packit ae235b
#define G_LEFTOVER_CONVERTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverter))
Packit ae235b
#define G_LEFTOVER_CONVERTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
Packit ae235b
#define G_IS_LEFTOVER_CONVERTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_LEFTOVER_CONVERTER))
Packit ae235b
#define G_IS_LEFTOVER_CONVERTER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_LEFTOVER_CONVERTER))
Packit ae235b
#define G_LEFTOVER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
Packit ae235b
Packit ae235b
typedef struct _GLeftoverConverter       GLeftoverConverter;
Packit ae235b
typedef struct _GLeftoverConverterClass  GLeftoverConverterClass;
Packit ae235b
Packit ae235b
struct _GLeftoverConverterClass
Packit ae235b
{
Packit ae235b
  GObjectClass parent_class;
Packit ae235b
};
Packit ae235b
Packit ae235b
GType       g_leftover_converter_get_type (void) G_GNUC_CONST;
Packit ae235b
GConverter *g_leftover_converter_new      (void);
Packit ae235b
Packit ae235b
Packit ae235b
Packit ae235b
static void g_leftover_converter_iface_init          (GConverterIface *iface);
Packit ae235b
Packit ae235b
struct _GLeftoverConverter
Packit ae235b
{
Packit ae235b
  GObject parent_instance;
Packit ae235b
};
Packit ae235b
Packit ae235b
G_DEFINE_TYPE_WITH_CODE (GLeftoverConverter, g_leftover_converter, G_TYPE_OBJECT,
Packit ae235b
			 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
Packit ae235b
						g_leftover_converter_iface_init))
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_leftover_converter_class_init (GLeftoverConverterClass *klass)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_leftover_converter_init (GLeftoverConverter *local)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
GConverter *
Packit ae235b
g_leftover_converter_new (void)
Packit ae235b
{
Packit ae235b
  GConverter *conv;
Packit ae235b
Packit ae235b
  conv = g_object_new (G_TYPE_LEFTOVER_CONVERTER, NULL);
Packit ae235b
Packit ae235b
  return conv;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_leftover_converter_reset (GConverter *converter)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static GConverterResult
Packit ae235b
g_leftover_converter_convert (GConverter *converter,
Packit ae235b
			      const void *inbuf,
Packit ae235b
			      gsize       inbuf_size,
Packit ae235b
			      void       *outbuf,
Packit ae235b
			      gsize       outbuf_size,
Packit ae235b
			      GConverterFlags flags,
Packit ae235b
			      gsize      *bytes_read,
Packit ae235b
			      gsize      *bytes_written,
Packit ae235b
			      GError    **error)
Packit ae235b
{
Packit ae235b
  if (outbuf_size == LEFTOVER_SHORT_READ_SIZE)
Packit ae235b
    {
Packit ae235b
      g_set_error_literal (error,
Packit ae235b
			   G_IO_ERROR,
Packit ae235b
			   G_IO_ERROR_PARTIAL_INPUT,
Packit ae235b
			   "partial input");
Packit ae235b
      return G_CONVERTER_ERROR;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (inbuf_size < 100)
Packit ae235b
    *bytes_read = *bytes_written = MIN (inbuf_size, outbuf_size);
Packit ae235b
  else
Packit ae235b
    *bytes_read = *bytes_written = MIN (inbuf_size - 10, outbuf_size);
Packit ae235b
  memcpy (outbuf, inbuf, *bytes_written);
Packit ae235b
Packit ae235b
  if (*bytes_read == inbuf_size && (flags & G_CONVERTER_INPUT_AT_END))
Packit ae235b
    return G_CONVERTER_FINISHED;
Packit ae235b
  return G_CONVERTER_CONVERTED;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_leftover_converter_iface_init (GConverterIface *iface)
Packit ae235b
{
Packit ae235b
  iface->convert = g_leftover_converter_convert;
Packit ae235b
  iface->reset = g_leftover_converter_reset;
Packit ae235b
}
Packit ae235b
Packit ae235b
#define LEFTOVER_BUFSIZE 8192
Packit ae235b
#define INTERNAL_BUFSIZE 4096
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_converter_leftover (void)
Packit ae235b
{
Packit ae235b
  gchar *orig, *converted;
Packit ae235b
  gsize total_read;
Packit ae235b
  gssize res;
Packit ae235b
  goffset offset;
Packit ae235b
  GInputStream *mem, *cstream;
Packit ae235b
  GConverter *converter;
Packit ae235b
  GError *error;
Packit ae235b
  int i;
Packit ae235b
Packit ae235b
  converter = g_leftover_converter_new ();
Packit ae235b
Packit ae235b
  orig = g_malloc (LEFTOVER_BUFSIZE);
Packit ae235b
  converted = g_malloc (LEFTOVER_BUFSIZE);
Packit ae235b
  for (i = 0; i < LEFTOVER_BUFSIZE; i++)
Packit ae235b
    orig[i] = i % 64 + 32;
Packit ae235b
Packit ae235b
  mem = g_memory_input_stream_new_from_data (orig, LEFTOVER_BUFSIZE, NULL);
Packit ae235b
  cstream = g_converter_input_stream_new (mem, G_CONVERTER (converter));
Packit ae235b
  g_object_unref (mem);
Packit ae235b
Packit ae235b
  total_read = 0;
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  res = g_input_stream_read (cstream,
Packit ae235b
			     converted, LEFTOVER_SHORT_READ_SIZE,
Packit ae235b
			     NULL, &error);
Packit ae235b
  g_assert_cmpint (res, ==, LEFTOVER_SHORT_READ_SIZE);
Packit ae235b
  total_read += res;
Packit ae235b
Packit ae235b
  offset = g_seekable_tell (G_SEEKABLE (mem));
Packit ae235b
  g_assert_cmpint (offset, >, LEFTOVER_SHORT_READ_SIZE);
Packit ae235b
  g_assert_cmpint (offset, <, LEFTOVER_BUFSIZE);
Packit ae235b
Packit ae235b
  /* At this point, @cstream has both a non-empty input_buffer
Packit ae235b
   * and a non-empty converted_buffer, which is the case
Packit ae235b
   * we want to test.
Packit ae235b
   */
Packit ae235b
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_input_stream_read (cstream,
Packit ae235b
				 converted + total_read,
Packit ae235b
				 LEFTOVER_BUFSIZE - total_read,
Packit ae235b
				 NULL, &error);
Packit ae235b
      g_assert (res >= 0);
Packit ae235b
      if (res == 0)
Packit ae235b
	break;
Packit ae235b
      total_read += res;
Packit ae235b
  }
Packit ae235b
Packit ae235b
  g_assert_cmpmem (orig, LEFTOVER_BUFSIZE, converted, total_read);
Packit ae235b
Packit ae235b
  g_object_unref (cstream);
Packit ae235b
  g_free (orig);
Packit ae235b
  g_free (converted);
Packit ae235b
  g_object_unref (converter);
Packit ae235b
}
Packit ae235b
Packit ae235b
#define DATA_LENGTH 1000000
Packit ae235b
Packit ae235b
typedef struct {
Packit ae235b
  const gchar *path;
Packit ae235b
  GZlibCompressorFormat format;
Packit ae235b
  gint level;
Packit ae235b
} CompressorTest;
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_roundtrip (gconstpointer data)
Packit ae235b
{
Packit ae235b
  const CompressorTest *test = data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  guint32 *data0, *data1;
Packit ae235b
  gsize data1_size;
Packit ae235b
  gint i;
Packit ae235b
  GInputStream *istream0, *istream1, *cistream1;
Packit ae235b
  GOutputStream *ostream1, *ostream2, *costream1;
Packit ae235b
  GConverter *compressor, *decompressor;
Packit ae235b
  GZlibCompressorFormat fmt;
Packit ae235b
  gint lvl;
Packit ae235b
  GFileInfo *info;
Packit ae235b
  GFileInfo *info2;
Packit ae235b
Packit ae235b
  g_test_bug ("619945");
Packit ae235b
Packit ae235b
  data0 = g_malloc (DATA_LENGTH * sizeof (guint32));
Packit ae235b
  for (i = 0; i < DATA_LENGTH; i++)
Packit ae235b
    data0[i] = g_random_int ();
Packit ae235b
Packit ae235b
  istream0 = g_memory_input_stream_new_from_data (data0,
Packit ae235b
    DATA_LENGTH * sizeof (guint32), NULL);
Packit ae235b
Packit ae235b
  ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
Packit ae235b
  compressor = G_CONVERTER (g_zlib_compressor_new (test->format, test->level));
Packit ae235b
  info = g_file_info_new ();
Packit ae235b
  g_file_info_set_name (info, "foo");
Packit ae235b
  g_object_set (compressor, "file-info", info, NULL);
Packit ae235b
  info2 = g_zlib_compressor_get_file_info (G_ZLIB_COMPRESSOR (compressor));
Packit ae235b
  g_assert (info == info2);
Packit ae235b
  g_object_unref (info);
Packit ae235b
  costream1 = g_converter_output_stream_new (ostream1, compressor);
Packit ae235b
  g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
Packit ae235b
Packit ae235b
  g_output_stream_splice (costream1, istream0, 0, NULL, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
Packit ae235b
  g_object_unref (costream1);
Packit ae235b
Packit ae235b
  g_converter_reset (compressor);
Packit ae235b
  g_object_get (compressor, "format", &fmt, "level", &lvl, NULL);
Packit ae235b
  g_assert_cmpint (fmt, ==, test->format);
Packit ae235b
  g_assert_cmpint (lvl, ==, test->level);
Packit ae235b
  g_object_unref (compressor);
Packit ae235b
  data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1));
Packit ae235b
  data1_size = g_memory_output_stream_get_data_size (
Packit ae235b
    G_MEMORY_OUTPUT_STREAM (ostream1));
Packit ae235b
  g_object_unref (ostream1);
Packit ae235b
  g_object_unref (istream0);
Packit ae235b
Packit ae235b
  istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
Packit ae235b
  decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
Packit ae235b
  cistream1 = g_converter_input_stream_new (istream1, decompressor);
Packit ae235b
Packit ae235b
  ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
Packit ae235b
Packit ae235b
  g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
Packit ae235b
  g_assert_cmpmem (data0, DATA_LENGTH * sizeof (guint32),
Packit ae235b
                   g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (ostream2)),
Packit ae235b
                   g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream2)));
Packit ae235b
  g_object_unref (istream1);
Packit ae235b
  g_converter_reset (decompressor);
Packit ae235b
  g_object_get (decompressor, "format", &fmt, NULL);
Packit ae235b
  g_assert_cmpint (fmt, ==, test->format);
Packit ae235b
  g_object_unref (decompressor);
Packit ae235b
  g_object_unref (cistream1);
Packit ae235b
  g_object_unref (ostream2);
Packit ae235b
  g_free (data0);
Packit ae235b
}
Packit ae235b
Packit ae235b
typedef struct {
Packit ae235b
  const gchar *path;
Packit ae235b
  const gchar *charset_in;
Packit ae235b
  const gchar *text_in;
Packit ae235b
  const gchar *charset_out;
Packit ae235b
  const gchar *text_out;
Packit ae235b
  gint n_fallbacks;
Packit ae235b
} CharsetTest;
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_charset (gconstpointer data)
Packit ae235b
{
Packit ae235b
  const CharsetTest *test = data;
Packit ae235b
  GInputStream *in, *in2;
Packit ae235b
  GConverter *conv;
Packit ae235b
  gchar *buffer;
Packit ae235b
  gsize count;
Packit ae235b
  gsize bytes_read;
Packit ae235b
  GError *error;
Packit ae235b
  gboolean fallback;
Packit ae235b
Packit ae235b
  conv = (GConverter *)g_charset_converter_new (test->charset_out, test->charset_in, NULL);
Packit ae235b
  g_object_get (conv, "use-fallback", &fallback, NULL);
Packit ae235b
  g_assert (!fallback);
Packit ae235b
Packit ae235b
  in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
Packit ae235b
  in2 = g_converter_input_stream_new (in, conv);
Packit ae235b
Packit ae235b
  count = 2 * strlen (test->text_out);
Packit ae235b
  buffer = g_malloc0 (count);
Packit ae235b
  error = NULL;
Packit ae235b
  g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
Packit ae235b
  if (test->n_fallbacks == 0)
Packit ae235b
    {
Packit ae235b
      g_assert_no_error (error);
Packit ae235b
      g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
Packit ae235b
      g_assert_cmpstr (buffer, ==, test->text_out);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_free (buffer);
Packit ae235b
  g_object_unref (in2);
Packit ae235b
  g_object_unref (in);
Packit ae235b
Packit ae235b
  if (test->n_fallbacks == 0)
Packit ae235b
    {
Packit ae235b
       g_object_unref (conv);
Packit ae235b
       return;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_converter_reset (conv);
Packit ae235b
Packit ae235b
  g_assert (!g_charset_converter_get_use_fallback (G_CHARSET_CONVERTER (conv)));
Packit ae235b
  g_charset_converter_set_use_fallback (G_CHARSET_CONVERTER (conv), TRUE);
Packit ae235b
Packit ae235b
  in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
Packit ae235b
  in2 = g_converter_input_stream_new (in, conv);
Packit ae235b
Packit ae235b
  count = 2 * strlen (test->text_out);
Packit ae235b
  buffer = g_malloc0 (count);
Packit ae235b
  error = NULL;
Packit ae235b
  g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_assert_cmpstr (buffer, ==, test->text_out);
Packit ae235b
  g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
Packit ae235b
  g_assert_cmpint (test->n_fallbacks, ==, g_charset_converter_get_num_fallbacks (G_CHARSET_CONVERTER (conv)));
Packit ae235b
Packit ae235b
  g_free (buffer);
Packit ae235b
  g_object_unref (in2);
Packit ae235b
  g_object_unref (in);
Packit ae235b
Packit ae235b
  g_object_unref (conv);
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
static void
Packit ae235b
client_connected (GObject      *source,
Packit ae235b
		  GAsyncResult *result,
Packit ae235b
		  gpointer      user_data)
Packit ae235b
{
Packit ae235b
  GSocketClient *client = G_SOCKET_CLIENT (source);
Packit ae235b
  GSocketConnection **conn = user_data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  *conn = g_socket_client_connect_finish (client, result, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
server_connected (GObject      *source,
Packit ae235b
		  GAsyncResult *result,
Packit ae235b
		  gpointer      user_data)
Packit ae235b
{
Packit ae235b
  GSocketListener *listener = G_SOCKET_LISTENER (source);
Packit ae235b
  GSocketConnection **conn = user_data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  *conn = g_socket_listener_accept_finish (listener, result, NULL, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
make_socketpair (GIOStream **left,
Packit ae235b
		 GIOStream **right)
Packit ae235b
{
Packit ae235b
  GInetAddress *iaddr;
Packit ae235b
  GSocketAddress *saddr, *effective_address;
Packit ae235b
  GSocketListener *listener;
Packit ae235b
  GSocketClient *client;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  GSocketConnection *client_conn = NULL, *server_conn = NULL;
Packit ae235b
Packit ae235b
  iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
Packit ae235b
  saddr = g_inet_socket_address_new (iaddr, 0);
Packit ae235b
  g_object_unref (iaddr);
Packit ae235b
Packit ae235b
  listener = g_socket_listener_new ();
Packit ae235b
  g_socket_listener_add_address (listener, saddr,
Packit ae235b
				 G_SOCKET_TYPE_STREAM,
Packit ae235b
				 G_SOCKET_PROTOCOL_TCP,
Packit ae235b
				 NULL,
Packit ae235b
				 &effective_address,
Packit ae235b
				 &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_object_unref (saddr);
Packit ae235b
Packit ae235b
  client = g_socket_client_new ();
Packit ae235b
Packit ae235b
  g_socket_client_connect_async (client,
Packit ae235b
				 G_SOCKET_CONNECTABLE (effective_address),
Packit ae235b
				 NULL, client_connected, &client_conn);
Packit ae235b
  g_socket_listener_accept_async (listener, NULL,
Packit ae235b
				  server_connected, &server_conn);
Packit ae235b
Packit ae235b
  while (!client_conn || !server_conn)
Packit ae235b
    g_main_context_iteration (NULL, TRUE);
Packit ae235b
Packit ae235b
  g_object_unref (client);
Packit ae235b
  g_object_unref (listener);
Packit ae235b
  g_object_unref (effective_address);
Packit ae235b
Packit ae235b
  *left = G_IO_STREAM (client_conn);
Packit ae235b
  *right = G_IO_STREAM (server_conn);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_converter_pollable (void)
Packit ae235b
{
Packit ae235b
  GIOStream *left, *right;
Packit ae235b
  guint8 *converted, *inptr;
Packit ae235b
  guint8 *expanded, *outptr, *expanded_end;
Packit ae235b
  gsize n_read, expanded_size;
Packit ae235b
  gsize total_read;
Packit ae235b
  gssize res;
Packit ae235b
  gboolean is_readable;
Packit ae235b
  GConverterResult cres;
Packit ae235b
  GInputStream *cstream;
Packit ae235b
  GPollableInputStream *pollable_in;
Packit ae235b
  GOutputStream *socket_out, *mem_out, *cstream_out;
Packit ae235b
  GPollableOutputStream *pollable_out;
Packit ae235b
  GConverter *expander, *compressor;
Packit ae235b
  GError *error;
Packit ae235b
  int i;
Packit ae235b
Packit ae235b
  expander = g_expander_converter_new ();
Packit ae235b
  expanded = g_malloc (100*1000); /* Large enough */
Packit ae235b
  cres = g_converter_convert (expander,
Packit ae235b
			      unexpanded_data, sizeof(unexpanded_data),
Packit ae235b
			      expanded, 100*1000,
Packit ae235b
			      G_CONVERTER_INPUT_AT_END,
Packit ae235b
			      &n_read, &expanded_size, NULL);
Packit ae235b
  g_assert (cres == G_CONVERTER_FINISHED);
Packit ae235b
  g_assert (n_read == 11);
Packit ae235b
  g_assert (expanded_size == 41030);
Packit ae235b
  expanded_end = expanded + expanded_size;
Packit ae235b
Packit ae235b
  make_socketpair (&left, &right);
Packit ae235b
Packit ae235b
  compressor = g_compressor_converter_new ();
Packit ae235b
Packit ae235b
  converted = g_malloc (100*1000); /* Large enough */
Packit ae235b
Packit ae235b
  cstream = g_converter_input_stream_new (g_io_stream_get_input_stream (left),
Packit ae235b
					  compressor);
Packit ae235b
  pollable_in = G_POLLABLE_INPUT_STREAM (cstream);
Packit ae235b
  g_assert (g_pollable_input_stream_can_poll (pollable_in));
Packit ae235b
Packit ae235b
  socket_out = g_io_stream_get_output_stream (right);
Packit ae235b
Packit ae235b
  total_read = 0;
Packit ae235b
  outptr = expanded;
Packit ae235b
  inptr = converted;
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
Packit ae235b
      if (outptr < expanded_end)
Packit ae235b
	{
Packit ae235b
	   res = g_output_stream_write (socket_out,
Packit ae235b
				       outptr,
Packit ae235b
				       MIN (1000, (expanded_end - outptr)),
Packit ae235b
				       NULL, &error);
Packit ae235b
	  g_assert_cmpint (res, >, 0);
Packit ae235b
	  outptr += res;
Packit ae235b
	}
Packit ae235b
      else if (socket_out)
Packit ae235b
	{
Packit ae235b
	  g_object_unref (right);
Packit ae235b
	  socket_out = NULL;
Packit ae235b
	}
Packit ae235b
Packit ae235b
      /* Wait a few ticks to check for the pipe to propagate the
Packit ae235b
       * write. Finesses the race condition in the following test,
Packit ae235b
       * where is_readable fails because the write hasn't propagated,
Packit ae235b
       * but the read then succeeds because it has. */
Packit ae235b
      g_usleep (80L);
Packit ae235b
Packit ae235b
      is_readable = g_pollable_input_stream_is_readable (pollable_in);
Packit ae235b
      res = g_pollable_input_stream_read_nonblocking (pollable_in,
Packit ae235b
						      inptr, 1,
Packit ae235b
						      NULL, &error);
Packit ae235b
Packit ae235b
      /* is_readable can be a false positive, but not a false negative */
Packit ae235b
      if (!is_readable)
Packit ae235b
	g_assert_cmpint (res, ==, -1);
Packit ae235b
Packit ae235b
      /* After closing the write end, we can't get WOULD_BLOCK any more */
Packit ae235b
      if (!socket_out)
Packit ae235b
	g_assert_cmpint (res, !=, -1);
Packit ae235b
Packit ae235b
      if (res == -1)
Packit ae235b
	{
Packit ae235b
	  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
Packit ae235b
	  g_error_free (error);
Packit ae235b
Packit ae235b
	  continue;
Packit ae235b
	}
Packit ae235b
Packit ae235b
      if (res == 0)
Packit ae235b
	break;
Packit ae235b
      inptr += res;
Packit ae235b
      total_read += res;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* "n_read - 1" because last 2 zeros are combined */
Packit ae235b
  g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read);
Packit ae235b
Packit ae235b
  g_object_unref (cstream);
Packit ae235b
  g_object_unref (left);
Packit ae235b
Packit ae235b
  g_converter_reset (compressor);
Packit ae235b
Packit ae235b
  /* This doesn't actually test the behavior on
Packit ae235b
   * G_IO_ERROR_WOULD_BLOCK; to do that we'd need to implement a
Packit ae235b
   * custom GOutputStream that we could control blocking on.
Packit ae235b
   */
Packit ae235b
Packit ae235b
  mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
Packit ae235b
  cstream_out = g_converter_output_stream_new (mem_out, compressor);
Packit ae235b
  g_object_unref (mem_out);
Packit ae235b
  pollable_out = G_POLLABLE_OUTPUT_STREAM (cstream_out);
Packit ae235b
  g_assert (g_pollable_output_stream_can_poll (pollable_out));
Packit ae235b
  g_assert (g_pollable_output_stream_is_writable (pollable_out));
Packit ae235b
Packit ae235b
  for (i = 0; i < expanded_size; i++)
Packit ae235b
    {
Packit ae235b
      error = NULL;
Packit ae235b
      res = g_pollable_output_stream_write_nonblocking (pollable_out,
Packit ae235b
							expanded + i, 1,
Packit ae235b
							NULL, &error);
Packit ae235b
      g_assert (res != -1);
Packit ae235b
      if (res == 0)
Packit ae235b
	{
Packit ae235b
	  g_assert (i == expanded_size -1);
Packit ae235b
	  break;
Packit ae235b
	}
Packit ae235b
      g_assert (res == 1);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_output_stream_close (cstream_out, NULL, NULL);
Packit ae235b
Packit ae235b
  /* "n_read - 1" because last 2 zeros are combined */
Packit ae235b
  g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
Packit ae235b
                   g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
Packit ae235b
                   unexpanded_data,
Packit ae235b
                   n_read - 1);
Packit ae235b
Packit ae235b
  g_object_unref (cstream_out);
Packit ae235b
Packit ae235b
  g_free (expanded);
Packit ae235b
  g_free (converted);
Packit ae235b
  g_object_unref (expander);
Packit ae235b
  g_object_unref (compressor);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_truncation (gconstpointer data)
Packit ae235b
{
Packit ae235b
  const CompressorTest *test = data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  guint32 *data0, *data1;
Packit ae235b
  gsize data1_size;
Packit ae235b
  gint i;
Packit ae235b
  GInputStream *istream0, *istream1, *cistream1;
Packit ae235b
  GOutputStream *ostream1, *ostream2, *costream1;
Packit ae235b
  GConverter *compressor, *decompressor;
Packit ae235b
Packit ae235b
  data0 = g_malloc (DATA_LENGTH * sizeof (guint32));
Packit ae235b
  for (i = 0; i < DATA_LENGTH; i++)
Packit ae235b
    data0[i] = g_random_int ();
Packit ae235b
Packit ae235b
  istream0 = g_memory_input_stream_new_from_data (data0,
Packit ae235b
    DATA_LENGTH * sizeof (guint32), NULL);
Packit ae235b
Packit ae235b
  ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
Packit ae235b
  compressor = G_CONVERTER (g_zlib_compressor_new (test->format, -1));
Packit ae235b
  costream1 = g_converter_output_stream_new (ostream1, compressor);
Packit ae235b
  g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
Packit ae235b
Packit ae235b
  g_output_stream_splice (costream1, istream0, 0, NULL, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
Packit ae235b
  g_object_unref (costream1);
Packit ae235b
  g_object_unref (compressor);
Packit ae235b
Packit ae235b
  data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1));
Packit ae235b
  data1_size = g_memory_output_stream_get_data_size (
Packit ae235b
    G_MEMORY_OUTPUT_STREAM (ostream1));
Packit ae235b
  g_object_unref (ostream1);
Packit ae235b
  g_object_unref (istream0);
Packit ae235b
Packit ae235b
  /* truncate */
Packit ae235b
  data1_size /= 2;
Packit ae235b
Packit ae235b
  istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
Packit ae235b
  decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
Packit ae235b
  cistream1 = g_converter_input_stream_new (istream1, decompressor);
Packit ae235b
Packit ae235b
  ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
Packit ae235b
Packit ae235b
  g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
Packit ae235b
  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
Packit ae235b
  g_error_free (error);
Packit ae235b
Packit ae235b
  g_object_unref (istream1);
Packit ae235b
  g_object_unref (decompressor);
Packit ae235b
  g_object_unref (cistream1);
Packit ae235b
  g_object_unref (ostream2);
Packit ae235b
  g_free (data0);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_converter_basics (void)
Packit ae235b
{
Packit ae235b
  GConverter *converter;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  gchar *to;
Packit ae235b
  gchar *from;
Packit ae235b
Packit ae235b
  converter = (GConverter *)g_charset_converter_new ("utf-8", "latin1", &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_object_get (converter,
Packit ae235b
                "to-charset", &to,
Packit ae235b
                "from-charset", &from,
Packit ae235b
                NULL);
Packit ae235b
Packit ae235b
  g_assert_cmpstr (to, ==, "utf-8");
Packit ae235b
  g_assert_cmpstr (from, ==, "latin1");
Packit ae235b
Packit ae235b
  g_free (to);
Packit ae235b
  g_free (from);
Packit ae235b
  g_object_unref (converter);
Packit ae235b
}
Packit ae235b
Packit ae235b
int
Packit ae235b
main (int   argc,
Packit ae235b
      char *argv[])
Packit ae235b
{
Packit ae235b
  CompressorTest compressor_tests[] = {
Packit ae235b
    { "/converter-output-stream/roundtrip/zlib-0", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
Packit ae235b
    { "/converter-output-stream/roundtrip/zlib-9", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 9 },
Packit ae235b
    { "/converter-output-stream/roundtrip/gzip-0", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
Packit ae235b
    { "/converter-output-stream/roundtrip/gzip-9", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 9 },
Packit ae235b
    { "/converter-output-stream/roundtrip/raw-0", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
Packit ae235b
    { "/converter-output-stream/roundtrip/raw-9", G_ZLIB_COMPRESSOR_FORMAT_RAW, 9 },
Packit ae235b
  };
Packit ae235b
  CompressorTest truncation_tests[] = {
Packit ae235b
    { "/converter-input-stream/truncation/zlib", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
Packit ae235b
    { "/converter-input-stream/truncation/gzip", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
Packit ae235b
    { "/converter-input-stream/truncation/raw", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
Packit ae235b
  };
Packit ae235b
  CharsetTest charset_tests[] = {
Packit ae235b
    { "/converter-input-stream/charset/utf8->latin1", "UTF-8", "\303\205rr Sant\303\251", "ISO-8859-1", "\305rr Sant\351", 0 },
Packit ae235b
    { "/converter-input-stream/charset/latin1->utf8", "ISO-8859-1", "\305rr Sant\351", "UTF-8", "\303\205rr Sant\303\251", 0 },
Packit ae235b
    { "/converter-input-stream/charset/fallbacks", "UTF-8", "Some characters just don't fit into latin1: πא", "ISO-8859-1", "Some characters just don't fit into latin1: \\CF\\80\\D7\\90", 4 },
Packit ae235b
  };
Packit ae235b
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  g_test_init (&argc, &argv, NULL);
Packit ae235b
Packit ae235b
  g_test_bug_base ("http://bugzilla.gnome.org/");
Packit ae235b
Packit ae235b
  g_test_add_func ("/converter/basics", test_converter_basics);
Packit ae235b
  g_test_add_func ("/converter-input-stream/expander", test_expander);
Packit ae235b
  g_test_add_func ("/converter-input-stream/compressor", test_compressor);
Packit ae235b
Packit ae235b
  for (i = 0; i < G_N_ELEMENTS (compressor_tests); i++)
Packit ae235b
    g_test_add_data_func (compressor_tests[i].path, &compressor_tests[i], test_roundtrip);
Packit ae235b
Packit ae235b
  for (i = 0; i < G_N_ELEMENTS (truncation_tests); i++)
Packit ae235b
    g_test_add_data_func (truncation_tests[i].path, &truncation_tests[i], test_truncation);
Packit ae235b
Packit ae235b
  for (i = 0; i < G_N_ELEMENTS (charset_tests); i++)
Packit ae235b
    g_test_add_data_func (charset_tests[i].path, &charset_tests[i], test_charset);
Packit ae235b
Packit ae235b
  g_test_add_func ("/converter-stream/pollable", test_converter_pollable);
Packit ae235b
  g_test_add_func ("/converter-stream/leftover", test_converter_leftover);
Packit ae235b
Packit ae235b
  return g_test_run();
Packit ae235b
}