From: Bruno Haible Date: Tue, 7 Nov 2006 14:48:46 +0000 (+0000) Subject: New module 'iconv-stream': Output stream that converts the output to another X-Git-Tag: v0.17~665 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a74ce820cc47e420e3b648291e84d9199305c95;p=thirdparty%2Fgettext.git New module 'iconv-stream': Output stream that converts the output to another encoding. --- diff --git a/gnulib-local/lib/iconv-ostream.oo.c b/gnulib-local/lib/iconv-ostream.oo.c new file mode 100644 index 000000000..12d142a64 --- /dev/null +++ b/gnulib-local/lib/iconv-ostream.oo.c @@ -0,0 +1,239 @@ +/* Output stream that converts the output to another encoding. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include + +/* Specification. */ +#include "iconv-ostream.h" + +#if HAVE_ICONV + +#include +#include +#include +#include + +#include "c-strcase.h" +#include "error.h" +#include "exit.h" +#include "xalloc.h" +#include "gettext.h" + +#define _(str) gettext (str) + +#endif /* HAVE_ICONV */ + +struct iconv_ostream : struct ostream +{ +fields: +#if HAVE_ICONV + /* The destination stream. */ + ostream_t destination; + /* The from and to encodings. */ + char *from_encoding; + char *to_encoding; + /* The converter. */ + iconv_t cd; + /* Last few bytes that could not yet be converted. */ + #define BUFSIZE 64 + char buf[BUFSIZE]; + size_t buflen; +#endif /* HAVE_ICONV */ +}; + +#if HAVE_ICONV + +/* Implementation of ostream_t methods. */ + +static void +iconv_ostream::write_mem (iconv_ostream_t stream, const void *data, size_t len) +{ + if (len > 0) + { + #define BUFFERSIZE 256 + char inbuffer[BUFFERSIZE]; + size_t inbufcount; + + inbufcount = stream->buflen; + if (inbufcount > 0) + memcpy (inbuffer, stream->buf, inbufcount); + for (;;) + { + /* At this point, inbuffer[0..inbufcount-1] is filled. */ + { + /* Combine the previous rest with a chunk of new input. */ + size_t n = + (len <= BUFFERSIZE - inbufcount ? len : BUFFERSIZE - inbufcount); + + if (n > 0) + { + memcpy (inbuffer + inbufcount, data, n); + data = (char *) data + n; + inbufcount += n; + len -= n; + } + } + { + /* Attempt to convert the combined input. */ + char outbuffer[8*BUFFERSIZE]; + + const char *inptr = inbuffer; + size_t insize = inbufcount; + char *outptr = outbuffer; + size_t outsize = sizeof (outbuffer); + + size_t res = iconv (stream->cd, + (ICONV_CONST char **) &inptr, &insize, + &outptr, &outsize); + #if !defined _LIBICONV_VERSION && !defined __GLIBC__ + /* Irix iconv() inserts a NUL byte if it cannot convert. + NetBSD iconv() inserts a question mark if it cannot convert. + Only GNU libiconv and GNU libc are known to prefer to fail rather + than doing a lossy conversion. */ + if (res > 0) + { + errno = EILSEQ; + res = -1; + } + #endif + if (res == (size_t)(-1) && errno != EINVAL) + error (EXIT_FAILURE, 0, _("%s: cannot convert from %s to %s"), + "iconv_ostream", + stream->from_encoding, stream->to_encoding); + /* Output the converted part. */ + if (sizeof (outbuffer) - outsize > 0) + ostream_write_mem (stream->destination, + outbuffer, sizeof (outbuffer) - outsize); + /* Put back the unconverted part. */ + if (insize > BUFSIZE) + error (EXIT_FAILURE, 0, _("%s: shift sequence too long"), + "iconv_ostream"); + if (len == 0) + { + if (insize > 0) + memcpy (stream->buf, inptr, insize); + stream->buflen = insize; + break; + } + if (insize > 0) + memmove (inbuffer, inptr, insize); + inbufcount = insize; + } + } + #undef BUFFERSIZE + } +} + +static void +iconv_ostream::flush (iconv_ostream_t stream) +{ + /* There's nothing we can do here, since stream->buf[] contains only a few + bytes that don't correspond to a character. */ +} + +static void +iconv_ostream::free (iconv_ostream_t stream) +{ + /* Silently ignore the few bytes in stream->buf[] that don't correspond to a + character. */ + + /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */ + #if defined _LIBICONV_VERSION \ + || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun) + { + char outbuffer[2048]; + char *outptr = outbuffer; + size_t outsize = sizeof (outbuffer); + size_t res = iconv (stream->cd, NULL, NULL, &outptr, &outsize); + if (res == (size_t)(-1)) + error (EXIT_FAILURE, 0, _("%s: cannot convert from %s to %s"), + "iconv_ostream", stream->from_encoding, stream->to_encoding); + /* Output the converted part. */ + if (sizeof (outbuffer) - outsize > 0) + ostream_write_mem (stream->destination, + outbuffer, sizeof (outbuffer) - outsize); + } + #endif + + iconv_close (stream->cd); + free (stream->from_encoding); + free (stream->to_encoding); + free (stream); +} + +/* Constructor. */ + +iconv_ostream_t +iconv_ostream_create (const char *from_encoding, const char *to_encoding, + ostream_t destination) +{ + iconv_ostream_t stream = XMALLOC (struct iconv_ostream_representation); + + stream->base.vtable = &iconv_ostream_vtable; + stream->destination = destination; + stream->from_encoding = xstrdup (from_encoding); + stream->to_encoding = xstrdup (to_encoding); + + /* Avoid glibc-2.1 bug with EUC-KR. */ + #if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION + if (c_strcasecmp (from_encoding, "EUC-KR") == 0 + || c_strcasecmp (to_encoding, "EUC-KR") == 0) + stream->cd = (iconv_t)(-1): + else + #endif + stream->cd = iconv_open (to_encoding, from_encoding); + if (stream->cd == (iconv_t)(-1)) + { + if (iconv_open ("UTF-8", from_encoding) == (iconv_t)(-1)) + error (EXIT_FAILURE, 0, _("%s does not support conversion from %s"), + "iconv", from_encoding); + else if (iconv_open (to_encoding, "UTF-8") == (iconv_t)(-1)) + error (EXIT_FAILURE, 0, _("%s does not support conversion to %s"), + "iconv", to_encoding); + else + error (EXIT_FAILURE, 0, + _("%s does not support conversion from %s to %s"), + "iconv", from_encoding, to_encoding); + } + + stream->buflen = 0; + + return stream; +} + +#else + +static void +iconv_ostream::write_mem (iconv_ostream_t stream, const void *data, size_t len) +{ + abort (); +} + +static void +iconv_ostream::flush (iconv_ostream_t stream) +{ + abort (); +} + +static void +iconv_ostream::free (iconv_ostream_t stream) +{ + abort (); +} + +#endif /* HAVE_ICONV */ diff --git a/gnulib-local/lib/iconv-ostream.oo.h b/gnulib-local/lib/iconv-ostream.oo.h new file mode 100644 index 000000000..d1f30da51 --- /dev/null +++ b/gnulib-local/lib/iconv-ostream.oo.h @@ -0,0 +1,54 @@ +/* Output stream that converts the output to another encoding. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _ICONV_OSTREAM_H +#define _ICONV_OSTREAM_H + +/* Note that this stream does not provide accurate error messages with line + and column number when the conversion fails. */ + +#include "ostream.h" + + +struct iconv_ostream : struct ostream +{ +methods: +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + +#if HAVE_ICONV + +/* Create an output stream that converts from FROM_ENCODING to TO_ENCODING, + writing the result to DESTINATION. */ +extern iconv_ostream_t iconv_ostream_create (const char *from_encoding, + const char *to_encoding, + ostream_t destination); + +#endif /* HAVE_ICONV */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _ICONV_OSTREAM_H */ diff --git a/gnulib-local/modules/iconv-ostream b/gnulib-local/modules/iconv-ostream new file mode 100644 index 000000000..b297d9dd1 --- /dev/null +++ b/gnulib-local/modules/iconv-ostream @@ -0,0 +1,34 @@ +Description: +Output stream that converts the output to another encoding. + +Files: +lib/iconv-ostream.oo.h +lib/iconv-ostream.oo.c + +Depends-on: +ostream +c-strcase +error +exit +gettext +iconv +xalloc + +configure.ac: + +Makefile.am: +lib_SOURCES += iconv-ostream.c +iconv-ostream.h iconv-ostream.c : $(top_srcdir)/build-aux/moopp iconv-ostream.oo.h iconv-ostream.oo.c ostream.oo.h + $(top_srcdir)/build-aux/moopp $(srcdir)/iconv-ostream.oo.c $(srcdir)/iconv-ostream.oo.h $(srcdir)/ostream.oo.h +BUILT_SOURCES += iconv-ostream.h iconv-ostream.c iconv_ostream.priv.h iconv_ostream.vt.h +CLEANFILES += iconv-ostream.h iconv-ostream.c iconv_ostream.priv.h iconv_ostream.vt.h + +Include: +"iconv-ostream.h" + +License: +GPL + +Maintainer: +Bruno Haible +