summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuo Jinghua <sunmoon1997@gmail.com>2010-01-08 15:05:08 +0800
committerLuo Jinghua <sunmoon1997@gmail.com>2010-01-08 15:05:08 +0800
commit106fee9debcd9f1b280133b235ec16a1984f6cd6 (patch)
tree1d9a0a2fad732e9bcb473fa53768df3e76834735
parent5b5e96599e90a94c5d8f40e570c56faec8af9dc1 (diff)
uconv2: add another test program
-rw-r--r--uconv2.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/uconv2.c b/uconv2.c
new file mode 100644
index 0000000..3fb43df
--- /dev/null
+++ b/uconv2.c
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iconv.h>
+#include <assert.h>
+#include <errno.h>
+
+static char*
+convert (const char *str,
+ size_t len,
+ iconv_t converter,
+ size_t *bytes_read,
+ size_t *bytes_written)
+{
+ char *dest;
+ char *outp;
+ const char *p;
+ size_t inbytes_remaining;
+ size_t outbytes_remaining;
+ size_t err;
+ size_t outbuf_size;
+ int have_error = 0;
+ int done = 0;
+ int reset = 0;
+
+ p = str;
+ inbytes_remaining = len;
+ outbuf_size = len + 1; /* + 1 for nul in case len == 1 */
+
+ outbytes_remaining = outbuf_size - 1; /* -1 for nul */
+ outp = dest = malloc (outbuf_size);
+
+ while (!done && !have_error) {
+ if (reset)
+ err = iconv (converter, NULL, &inbytes_remaining, &outp,
+ &outbytes_remaining);
+ else
+ err = iconv (converter, (char **)&p, &inbytes_remaining,
+ &outp, &outbytes_remaining);
+
+ if (err == (size_t) -1) {
+ switch (errno)
+ {
+ case EINVAL:
+ /* Incomplete text, do not report an error */
+ done = 1;
+ break;
+ case E2BIG:
+ {
+ size_t used = outp - dest;
+ printf ("used: %zd, %zd(%zd)\n",
+ used, inbytes_remaining, len);
+
+ outbuf_size *= 2;
+ dest = realloc (dest, outbuf_size);
+
+ outp = dest + used;
+ outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */
+ }
+ break;
+ case EILSEQ:
+ have_error = 1;
+ break;
+ default:
+ have_error = 1;
+ break;
+ }
+ } else {
+ if (!reset) {
+ /* call iconv with NULL inbuf to cleanup shift state */
+ reset = 1;
+ inbytes_remaining = 0;
+ } else {
+ done = 1;
+ }
+ }
+ }
+
+ *outp = '\0';
+ if (bytes_read) {
+ *bytes_read = p - str;
+ } else {
+ if ((p - str) != len) {
+ if (!have_error)
+ have_error = 1;
+ }
+ }
+
+ if (bytes_written)
+ *bytes_written = outp - dest; /* Doesn't include '\0' */
+
+ if (have_error) {
+ free (dest);
+ return NULL;
+ }
+
+ return dest;
+}
+
+#define UCONV_BUFSZ 4096
+int main(int argc, char **argv)
+{
+ FILE *infp, *outfp;
+ const char *from, *to;
+ iconv_t conv;
+ char *inbuf;
+ char *outbuf;
+ size_t inlen;
+ size_t outlen;
+
+ if (argc < 5)
+ return -1;
+
+ from = argv[1];
+ to = argv[2];
+
+ conv = iconv_open(to, from);
+ if (conv == (iconv_t)-1) {
+ fprintf (stderr,
+ "Converting from %s to %s is unsupported.\n",
+ from, to);
+ return -1;
+ }
+
+ infp = fopen(argv[3], "rb");
+ if (!infp)
+ return -1;
+
+ fseek(infp, 0, SEEK_END);
+ inlen = ftell(infp);
+ fseek(infp, 0, SEEK_SET);
+ inbuf = malloc(sizeof(char) * (inlen + 1));
+ if (!inbuf)
+ return -1;
+
+ fread(inbuf, 1, inlen, infp);
+ outbuf = convert(inbuf, inlen, conv, NULL, &outlen);
+ if (!outbuf) {
+ fprintf(stderr, "Failed to convert.\n");
+ }
+
+ outfp = fopen(argv[4], "wb");
+ if (!outfp)
+ return -1;
+
+ if (outbuf)
+ fwrite(outbuf, 1, outlen, outfp);
+
+ free(inbuf);
+ free(outbuf);
+
+ fclose(outfp);
+ fclose(infp);
+
+ iconv_close(conv);
+
+ return 0;
+}