forked from Mirrors/freeswitch
245060e5a9
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3738 d0543943-73ff-0310-b7d9-9358b9ac24b2
146 lines
3.2 KiB
C
146 lines
3.2 KiB
C
#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
|