#define ICONV_INTERNAL #include "iconv.h" #include #include struct iconv_uc { struct iconv_ces * from; struct iconv_ces * to; int ignore_ilseq; ucs_t missing; }; static iconv_open_t iconv_uc_open; static iconv_close_t iconv_uc_close; static iconv_conv_t iconv_uc_conv; struct iconv_converter_desc iconv_uc_desc = { iconv_uc_open, iconv_uc_close, iconv_uc_conv }; /* * It is call by apr_iconv_open: (*idesc)->icd_open() */ apr_status_t iconv_uc_open(const char *to, const char *from, void **data, apr_pool_t *ctx) { struct iconv_uc *ic; int error; ic = malloc(sizeof(*ic)); if (ic == NULL) return APR_ENOMEM; memset(ic, 0, sizeof(*ic)); error = apr_iconv_ces_open(from, &ic->from, ctx); if (error!=APR_SUCCESS) { goto bad; } error = apr_iconv_ces_open(to, &ic->to, ctx); if (error!=APR_SUCCESS) { goto bad; } ic->ignore_ilseq = 0; ic->missing = '_'; *data = (void*)ic; return APR_SUCCESS; bad: iconv_uc_close(ic,ctx); return error; } apr_status_t iconv_uc_close(void *data, apr_pool_t *ctx) { struct iconv_uc *ic = (struct iconv_uc *)data; if (ic == NULL) return APR_EBADF; if (ic->from) apr_iconv_ces_close(ic->from, ctx); if (ic->to) apr_iconv_ces_close(ic->to, ctx); free(ic); return APR_SUCCESS; } apr_status_t iconv_uc_conv(void *data, const unsigned char **inbuf, apr_size_t *inbytesleft, unsigned char **outbuf, apr_size_t *outbytesleft, apr_size_t *res) { struct iconv_uc *ic = (struct iconv_uc *)data; const unsigned char *ptr; ucs_t ch; apr_ssize_t size; *res = (apr_size_t)(0); if (data == NULL) { *res = (apr_size_t) -1; return APR_EBADF; } if (inbuf == NULL || *inbuf == NULL) { if (ICONV_CES_CONVERT_FROM_UCS(ic->to, UCS_CHAR_NONE, outbuf, outbytesleft) <= 0) { *res = (apr_size_t) -1; return APR_BADARG; /* too big */ } ICONV_CES_RESET(ic->from); ICONV_CES_RESET(ic->to); return APR_SUCCESS; } if (inbytesleft == NULL || *inbytesleft == 0) return APR_SUCCESS; while (*inbytesleft > 0 && *outbytesleft > 0) { ptr = *inbuf; ch = ICONV_CES_CONVERT_TO_UCS(ic->from, inbuf, inbytesleft); if (ch == UCS_CHAR_NONE) return APR_EINVAL; if (ch == UCS_CHAR_INVALID) { /* Invalid character in source buffer */ if (ic->ignore_ilseq) continue; *inbytesleft += *inbuf - ptr; *inbuf = ptr; return APR_BADCH; /* eilseq invalid */ } size = ICONV_CES_CONVERT_FROM_UCS(ic->to, ch, outbuf, outbytesleft); if (size < 0) { /* No equivalent in destination charset */ size = ICONV_CES_CONVERT_FROM_UCS(ic->to, ic->missing, outbuf, outbytesleft); if (size) *res ++; } if (!size) { /* No space to write to */ *inbytesleft += *inbuf - ptr; *inbuf = ptr; return APR_BADARG; /* too big */ } } return APR_SUCCESS; } #if 0 /* iconv_byteratio(cd) returns the byte ratio between OUTPUT and INPUT * stream lengths * -1: unknown * 0: 1/2 * 1: 1/1 * 2: 2/1 */ int iconv_byteratio(apr_iconv_t cd) { iconv_data *idata = (iconv_data *)cd; int from, to; to = (*idata->to->data->nbytes)(idata->to); if (to == 0) return -1; from = (*idata->from->data->nbytes)(idata->from); return (from) ? to / from : -1; } #endif