summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuo Jinghua <sunmoon1997@gmail.com>2010-01-08 15:04:40 +0800
committerLuo Jinghua <sunmoon1997@gmail.com>2010-01-08 15:04:40 +0800
commit5b5e96599e90a94c5d8f40e570c56faec8af9dc1 (patch)
tree06d4788e07f63f736703c70ed1a5fbfc3207c73b
parent0cc7474bf942f308cbfea3e3baf33809cf3b0fe3 (diff)
uniconv: be compatible with system's iconv
-rw-r--r--uniconv.c57
1 files changed, 33 insertions, 24 deletions
diff --git a/uniconv.c b/uniconv.c
index 22a70ee..7e9fe1e 100644
--- a/uniconv.c
+++ b/uniconv.c
@@ -94,8 +94,6 @@ uniconv_conv(uniconv_t *uc,
size_t *outleft)
{
int ret;
- uc_char_t local_ucs4[UNICONV_MAX_LOCAL];
- uc_char_t *ucs4, *inucs4;
size_t ucs4len;
const char *saved_inbuf;
const char *saved_outbuf;
@@ -112,38 +110,49 @@ uniconv_conv(uniconv_t *uc,
/* converting/pushing input data */
if (inbuf) {
- if (*inleft < UNICONV_MAX_LOCAL)
- ucs4 = local_ucs4;
- else
- ucs4 = malloc(sizeof(uc_char_t) * (*inleft));
- if (!ucs4)
- return UNICONV_EINVAL;
+ uc_char_t ucs4;
+ uc_char_t *ucsbuf;
- inucs4 = ucs4;
- ucs4len = *inleft;
saved_inbuf = *inbuf;
saved_outbuf = *outbuf;
- ret = uc->from->decode(uc->from, inbuf, *inleft, &inucs4, ucs4len);
- *inleft -= *inbuf - saved_inbuf;
- if (ret)
- goto error_decode;
-
- ucs4len = inucs4 - ucs4;
- inucs4 = ucs4;
- ret = uc->to->encode(uc->to, (const ucs4_t **)&inucs4, ucs4len,
- outbuf, *outleft);
+ while (*inleft) {
+ size_t i = 0;
+ const char *abuf;
+ const char *aoutbuf;
+
+ /* decode a char at a time */
+ for (i = 1; i <= *inleft; i++) {
+ ucsbuf = &ucs4;
+ abuf = *inbuf;
+ ret = uc->from->decode(uc->from, &abuf, i, &ucsbuf, 1);
+ if (ret < 0 && ret == UNICONV_EINVAL)
+ continue;
+ break;
+ }
+ if (ret == UNICONV_E2BIG)
+ ret = UNICONV_EILSEQ;
+ if (ret < 0)
+ return ret;
+
+ ucs4len = ucsbuf - &ucs4;
+ ucsbuf = &ucs4;
+ aoutbuf = *outbuf;
+ ret = uc->to->encode(uc->to, (const ucs4_t **)&ucsbuf, ucs4len,
+ outbuf, *outleft);
+ *outleft -= *outbuf - aoutbuf;
+ if (ret < 0)
+ break;
+ *inleft -= i;
+ (*inbuf) += i;
+ }
} else {
- ucs4 = NULL;
/* converting pending data in buffer */
saved_inbuf = NULL;
saved_outbuf = *outbuf;
ret = uc->to->encode(uc->to, NULL, 0, outbuf, *outleft);
+ *outleft -= *outbuf - saved_outbuf;
}
- *outleft -= *outbuf - saved_outbuf;
- error_decode:
- if (ucs4 && ucs4 != local_ucs4)
- free (ucs4);
return ret;
}