diff options
author | Luo Jinghua <sunmoon1997@gmail.com> | 2010-01-08 15:04:40 +0800 |
---|---|---|
committer | Luo Jinghua <sunmoon1997@gmail.com> | 2010-01-08 15:04:40 +0800 |
commit | 5b5e96599e90a94c5d8f40e570c56faec8af9dc1 (patch) | |
tree | 06d4788e07f63f736703c70ed1a5fbfc3207c73b | |
parent | 0cc7474bf942f308cbfea3e3baf33809cf3b0fe3 (diff) |
uniconv: be compatible with system's iconv
-rw-r--r-- | uniconv.c | 57 |
1 files changed, 33 insertions, 24 deletions
@@ -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; } |