Re: GIOChannel missing binary mode?
- From: Michael Natterer <mitch gimp org>
- To: Ron Steinke <rsteinke w-link net>
- Cc: gtk-devel-list gnome org, otaylor gtk org
- Subject: Re: GIOChannel missing binary mode?
- Date: 30 Aug 2001 02:08:51 +0200
Ron Steinke <rsteinke w-link net> writes:
> > From: Michael Natterer <mitch gimp org>
> >
> > Hi,
> >
> > while porting GIMP <-> plug-in communication to
> > g_io_channel_[read|write]_chars() i noticed that there
> > are two GIOChannel attributes, "do_encode" and "encoding".
> >
> > My impression from looking at the code is that if
> > "do_encode" == FALSE, "encoding" is assumed to be UTF-8.
>
> Actually, it's assumed to be either "UTF-8" or NULL. Use
> NULL for binary encoding. The default just happens to
> be "UTF-8".
>
> > So either I missed something or there seems to be no way
> > to use a GIOChannel in binary mode, because if I say
> > g_io_channel_set_encoding (channel, NULL, NULL),
> > "do_encoding" is set to FALSE automatically.
>
> The do_encode flag is set when we are calling g_iconv to do conversion.
> It just happens this is true for neither UTF-8 or binary encoding.
>
> > A subsequent call to read_chars() or write_chars() however
> > looks at "do_encode", assumes UTF-8 if it is FALSE and
> > calls g_utf8_validate() which of course fails on binary
> > data.
>
> In write_chars(), a binary encoding hits the earlier !channel->encoding
> test and completely avoids checking do_encode. In read_chars(),
> the test for binary encoding is hidden in the USE_BUF() macro.
>
>
> > Please point me to the right direction if I made a mistake :-)
> >
> > (FYI: right now, as a workaround, i use channel->funcs->io_foo())
>
> Just call g_io_channel_set_encoding() with a NULL argument before
> you use the channel. If this isn't in the docs, it should be.
You're right, it was not g_io_channel_set_encoding()'s fault.
In fact, I used g_io_channel_set_encoding() and it didn't work, so my
first (and wrong) glance at giochannel.c made me think I found the bug.
However I additionally have to say g_io_channel_set_buffered (channel, FALSE);
to make it work.
I tried to write a small test program to trigger the failing reads and
writes (attached) but was *not* able to reproduce it, no matter if
reading/writing is done on a tty, file of pipe. Resizing the random_crap
array in the test program also doesn't trigger anything.
Maybe GIMP's IO channel events are a bit more complex and trigger
something completely different :-) If you want to test it, remove
the g_io_channel_set_buffered() from CVS gimp in app/plug_in.c and
libgimp/gimp.c and see what happens.
(Maybe it's just an explicit flush() or something that's missing
to make it work in buffered mode...).
ciao,
--Mitch
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <glib.h>
gint
main (gint argc,
gchar *argv[])
{
GIOChannel *channel0 = NULL;
GIOChannel *channel1;
gchar random_crap[5];
gint i;
GIOStatus status;
GError *error = NULL;
gsize written;
if (! isatty (0))
{
channel0 = g_io_channel_unix_new (0);
g_io_channel_set_encoding (channel0, NULL, NULL);
g_io_channel_set_close_on_unref (channel0, TRUE);
}
channel1 = g_io_channel_unix_new (1);
g_io_channel_set_encoding (channel1, NULL, NULL);
g_io_channel_set_close_on_unref (channel1, TRUE);
if (channel0)
{
g_message ("%s: reading from STDIN", argv[0]);
do
{
status = g_io_channel_read_chars (channel0,
random_crap, G_N_ELEMENTS (random_crap),
&written,
&error);
}
while (status == G_IO_STATUS_AGAIN);
if (status != G_IO_STATUS_NORMAL)
{
if (error)
{
g_warning ("%s: read EEK: %s", argv[0], error->message);
g_error_free (error);
}
else
{
g_warning ("%s: read EEK", argv[0]);
}
return -1;
}
}
else
{
g_message ("%s: producing random_crap", argv[0]);
for (i = 0; i < G_N_ELEMENTS (random_crap); i++)
random_crap[i] = i % 127 + 128;
}
do
{
status = g_io_channel_write_chars (channel1,
random_crap, G_N_ELEMENTS (random_crap),
&written,
&error);
}
while (status == G_IO_STATUS_AGAIN);
if (status != G_IO_STATUS_NORMAL)
{
if (error)
{
g_warning ("%s: write EEK: %s", argv[0], error->message);
g_error_free (error);
}
else
{
g_warning ("%s: write EEK", argv[0]);
}
return -1;
}
if (channel0)
g_io_channel_unref (channel0);
g_io_channel_unref (channel1);
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]