blob: 6b58008d7acd6968ffbfac28e038e246f65765e7 [file] [log] [blame]
#define ICONV_INTERNAL
#include "iconv.h"
#include <stdlib.h>
#include <string.h>
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