summaryrefslogtreecommitdiffabout
path: root/libetpan/src/data-types/charconv.c
Side-by-side diff
Diffstat (limited to 'libetpan/src/data-types/charconv.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/data-types/charconv.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/libetpan/src/data-types/charconv.c b/libetpan/src/data-types/charconv.c
new file mode 100644
index 0000000..28549c9
--- a/dev/null
+++ b/libetpan/src/data-types/charconv.c
@@ -0,0 +1,251 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "charconv.h"
+
+#include "config.h"
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "mmapstring.h"
+
+#ifdef HAVE_ICONV
+static size_t mail_iconv (iconv_t cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft,
+ char **inrepls, char *outrepl)
+{
+ size_t ret = 0, ret1;
+ /* XXX - force const to mutable */
+ char *ib = (char *) *inbuf;
+ size_t ibl = *inbytesleft;
+ char *ob = *outbuf;
+ size_t obl = *outbytesleft;
+
+ for (;;)
+ {
+#ifdef HAVE_ICONV_PROTO_CONST
+ ret1 = iconv (cd, (const char **) &ib, &ibl, &ob, &obl);
+#else
+ ret1 = iconv (cd, &ib, &ibl, &ob, &obl);
+#endif
+ if (ret1 != (size_t)-1)
+ ret += ret1;
+ if (ibl && obl && errno == EILSEQ)
+ {
+ if (inrepls)
+ {
+ /* Try replacing the input */
+ char **t;
+ for (t = inrepls; *t; t++)
+ {
+ char *ib1 = *t;
+ size_t ibl1 = strlen (*t);
+ char *ob1 = ob;
+ size_t obl1 = obl;
+#ifdef HAVE_ICONV_PROTO_CONST
+ iconv (cd, (const char **) &ib1, &ibl1, &ob1, &obl1);
+#else
+ iconv (cd, &ib1, &ibl1, &ob1, &obl1);
+#endif
+ if (!ibl1)
+ {
+ ++ib, --ibl;
+ ob = ob1, obl = obl1;
+ ++ret;
+ break;
+ }
+ }
+ if (*t)
+ continue;
+ }
+ if (outrepl)
+ {
+ /* Try replacing the output */
+ size_t n = strlen (outrepl);
+ if (n <= obl)
+ {
+ memcpy (ob, outrepl, n);
+ ++ib, --ibl;
+ ob += n, obl -= n;
+ ++ret;
+ continue;
+ }
+ }
+ }
+ *inbuf = ib, *inbytesleft = ibl;
+ *outbuf = ob, *outbytesleft = obl;
+ return ret;
+ }
+}
+#endif
+
+int charconv(const char * tocode, const char * fromcode,
+ const char * str, size_t length,
+ char ** result)
+{
+#ifndef HAVE_ICONV
+ return MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET;
+#else
+ iconv_t conv;
+ size_t r;
+ char * out;
+ char * pout;
+ size_t out_size;
+ size_t old_out_size;
+ size_t count;
+ int res;
+
+ conv = iconv_open(tocode, fromcode);
+ if (conv == (iconv_t) -1) {
+ res = MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET;
+ goto err;
+ }
+
+ out_size = 4 * length;
+
+ out = malloc(out_size + 1);
+ if (out == NULL) {
+ res = MAIL_CHARCONV_ERROR_MEMORY;
+ goto close_iconv;
+ }
+
+ pout = out;
+ old_out_size = out_size;
+
+ r = mail_iconv(conv, &str, &length, &pout, &out_size, NULL, "?");
+
+ if (r == (size_t) -1) {
+ res = MAIL_CHARCONV_ERROR_CONV;
+ goto free;
+ }
+
+ iconv_close(conv);
+
+ * pout = '\0';
+ count = old_out_size - out_size;
+ pout = realloc(out, count + 1);
+ if (pout != NULL)
+ out = pout;
+
+ * result = out;
+
+ return MAIL_CHARCONV_NO_ERROR;
+
+ free:
+ free(out);
+ close_iconv:
+ iconv_close(conv);
+ err:
+ return res;
+#endif
+};
+
+int charconv_buffer(const char * tocode, const char * fromcode,
+ const char * str, size_t length,
+ char ** result, size_t * result_len)
+{
+#ifndef HAVE_ICONV
+ return MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET;
+#else
+ iconv_t conv;
+ size_t iconv_r;
+ int r;
+ char * out;
+ char * pout;
+ size_t out_size;
+ size_t old_out_size;
+ size_t count;
+ MMAPString * mmapstr;
+ int res;
+
+ conv = iconv_open(tocode, fromcode);
+ if (conv == (iconv_t) -1) {
+ res = MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET;
+ goto err;
+ }
+
+ out_size = 4 * length;
+
+ mmapstr = mmap_string_sized_new(out_size + 1);
+ if (mmapstr == NULL) {
+ res = MAIL_CHARCONV_ERROR_MEMORY;
+ goto err;
+ }
+
+ out = mmapstr->str;
+
+ pout = out;
+ old_out_size = out_size;
+
+ iconv_r = mail_iconv(conv, &str, &length, &pout, &out_size, NULL, "?");
+
+ if (iconv_r == (size_t) -1) {
+ res = MAIL_CHARCONV_ERROR_CONV;
+ goto free;
+ }
+
+ iconv_close(conv);
+
+ * pout = '\0';
+
+ count = old_out_size - out_size;
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_CHARCONV_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = out;
+ * result_len = count;
+
+ return MAIL_CHARCONV_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ err:
+ return -1;
+#endif
+};
+
+void charconv_buffer_free(char * str)
+{
+ mmap_string_unref(str);
+}