#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <link.h>
#include <sys/utsname.h>
#include <ctype.h>
#include <strings.h>
#include <string.h>
#include <idn/api.h>
#include <idn/version.h>
#include "ace.h"
void *
_icv_open()
{
ace_state_t *cd;
cd = (ace_state_t *)calloc(1, sizeof(ace_state_t));
if (cd == (ace_state_t *)NULL) {
errno = ENOMEM;
return ((void *)-1);
}
cd->libidnkit = dlopen(ICV_LIBIDNKITPATH, RTLD_LAZY);
if (cd->libidnkit == (void *)NULL) {
free((void *)cd);
errno = EINVAL;
return ((void *)-1);
}
cd->idn_function = (idn_result_t(*)(int, const char *, char *,
#if defined(ICV_ACE_TO_UTF8)
size_t))dlsym(cd->libidnkit, "idn_decodename");
#else
size_t))dlsym(cd->libidnkit, "idn_encodename");
#endif
if (cd->idn_function ==
(idn_result_t(*)(int, const char *, char *, size_t))NULL) {
(void) dlclose(cd->libidnkit);
free((void *)cd);
errno = EINVAL;
return ((void *)-1);
}
cd->ib = (uchar_t *)malloc(_SYS_NMLN);
if (cd->ib == (uchar_t *)NULL) {
(void) dlclose(cd->libidnkit);
free((void *)cd);
errno = ENOMEM;
return ((void *)-1);
}
cd->ob = (uchar_t *)malloc(_SYS_NMLN);
if (cd->ob == (uchar_t *)NULL) {
(void) dlclose(cd->libidnkit);
free((void *)cd->ib);
free((void *)cd);
errno = ENOMEM;
return ((void *)-1);
}
cd->ibl = cd->obl = _SYS_NMLN;
cd->iblconsumed = cd->oblremaining = 0;
return ((void *)cd);
}
void
_icv_close(ace_state_t *cd)
{
if (! cd)
errno = EBADF;
else {
(void) dlclose(cd->libidnkit);
free((void *)cd->ib);
free((void *)cd->ob);
free((void *)cd);
}
}
size_t
_icv_iconv(ace_state_t *cd, char **inbuf, size_t *inbufleft, char **outbuf,
size_t *outbufleft)
{
size_t ret_val = 0;
uchar_t *ib;
uchar_t *ob;
uchar_t *ibtail;
uchar_t *obtail;
uchar_t *tmps;
idn_result_t idnres;
idn_action_t actions;
int i;
if (! cd) {
errno = EBADF;
return((size_t)-1);
}
if (!outbuf || !(*outbuf)) {
errno = E2BIG;
return ((size_t)-1);
}
ob = (uchar_t *)*outbuf;
obtail = ob + *outbufleft;
for (i = 0; i < cd->oblremaining; i++) {
if (ob >= obtail) {
errno = E2BIG;
cd->oblremaining -= i;
(void) memmove((void *)cd->ob,
(const void *)(cd->ob + i), cd->oblremaining);
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN_TWO;
}
*ob++ = cd->ob[i];
}
cd->oblremaining = 0;
#ifdef IDNKIT_VERSION_LIBIDN
actions =
IDN_RTCONV
|IDN_PROHCHECK
|IDN_NFCCHECK
|IDN_PREFCHECK
|IDN_COMBCHECK
|IDN_CTXOLITECHECK
|IDN_BIDICHECK
|IDN_LOCALCHECK
|IDN_IDNCONV
|IDN_LENCHECK;
# if defined(ICV_ACE_TO_UTF8)
actions |= IDN_RTCHECK;
# else
actions |= IDN_MAP;
# endif
#else
actions =
IDN_DELIMMAP
|IDN_NAMEPREP
|IDN_IDNCONV
|IDN_ASCCHECK;
# if defined(ICV_ACE_TO_UTF8)
actions |= IDN_RTCHECK;
# else
actions |= IDN_LOCALMAP;
# endif
#endif
#if !defined(ICV_IDN_ALLOW_UNASSIGNED)
actions |= IDN_UNASCHECK;
#endif
if (!inbuf || !(*inbuf)) {
if (cd->iblconsumed > 0) {
if (cd->iblconsumed >= cd->ibl) {
cd->ibl += _SYS_NMLN;
tmps = (uchar_t *)realloc((void *)cd->ib,
cd->ibl);
if (tmps == (uchar_t *)NULL) {
cd->ibl -= _SYS_NMLN;
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN_TWO;
}
cd->ib = tmps;
}
*(cd->ib + cd->iblconsumed++) = '\0';
i = 0;
ICV_ICONV_LOOP_ONE:
idnres = (*(cd->idn_function))(actions,
(const char *)cd->ib, (char *)cd->ob,
cd->obl);
switch (idnres) {
case idn_success:
break;
case idn_buffer_overflow:
if (++i >= 2) {
errno = EILSEQ;
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN_TWO;
}
cd->obl += _SYS_NMLN;
tmps = (uchar_t *)realloc((void *)cd->ob,
cd->obl);
if (tmps == (uchar_t *)NULL) {
cd->obl -= _SYS_NMLN;
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN_TWO;
}
cd->ob = tmps;
goto ICV_ICONV_LOOP_ONE;
default:
errno = EILSEQ;
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN_TWO;
}
cd->iblconsumed = 0;
cd->oblremaining = strlen((const char *)cd->ob);
for (i = 0; i < cd->oblremaining; i++) {
if (ob >= obtail) {
errno = E2BIG;
cd->oblremaining -= i;
(void) memmove((void *)cd->ob,
(const void *)(cd->ob + i),
cd->oblremaining);
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN_TWO;
}
*ob++ = cd->ob[i];
}
cd->oblremaining = 0;
}
ret_val = (size_t)0;
goto ICV_ICONV_RETURN_TWO;
}
ib = (uchar_t *)*inbuf;
ibtail = ib + *inbufleft;
while (ib < ibtail) {
if (isspace(*ib)) {
if (cd->iblconsumed > 0) {
if (cd->iblconsumed >= cd->ibl) {
cd->ibl += _SYS_NMLN;
tmps = (uchar_t *)realloc(
(void *)cd->ib, cd->ibl);
if (tmps == (uchar_t *)NULL) {
cd->ibl -= _SYS_NMLN;
ret_val = (size_t)-1;
break;
}
cd->ib = tmps;
}
*(cd->ib + cd->iblconsumed) = '\0';
i = 0;
ICV_ICONV_LOOP:
idnres = (*(cd->idn_function))(actions,
(const char *)cd->ib, (char *)cd->ob,
cd->obl);
switch (idnres) {
case idn_success:
break;
case idn_buffer_overflow:
if (++i >= 2) {
errno = EILSEQ;
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN;
}
cd->obl += _SYS_NMLN;
tmps = (uchar_t *)realloc(
(void *)cd->ob, cd->obl);
if (tmps == (uchar_t *)NULL) {
cd->obl -= _SYS_NMLN;
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN;
}
cd->ob = tmps;
goto ICV_ICONV_LOOP;
default:
errno = EILSEQ;
ret_val = (size_t)-1;
goto ICV_ICONV_RETURN;
}
cd->iblconsumed = 0;
cd->oblremaining = strlen((const char *)cd->ob);
for (i = 0; i < cd->oblremaining; i++) {
if (ob >= obtail) {
errno = E2BIG;
ret_val = (size_t)-1;
cd->oblremaining -= i;
(void) memmove((void *)cd->ob,
(const void *)(cd->ob + i),
cd->oblremaining);
goto ICV_ICONV_RETURN;
}
*ob++ = cd->ob[i];
}
cd->oblremaining = 0;
}
if (ob >= obtail) {
errno = E2BIG;
ret_val = (size_t)-1;
break;
}
*ob++ = *ib++;
} else {
if (cd->iblconsumed >= cd->ibl) {
cd->ibl += _SYS_NMLN;
tmps = (uchar_t *)realloc((void *)cd->ib,
cd->ibl);
if (tmps == (uchar_t *)NULL) {
cd->ibl -= _SYS_NMLN;
ret_val = (size_t)-1;
break;
}
cd->ib = tmps;
}
*(cd->ib + cd->iblconsumed++) = *ib++;
}
}
ICV_ICONV_RETURN:
*inbuf = (char *)ib;
*inbufleft = ibtail - ib;
ICV_ICONV_RETURN_TWO:
*outbuf = (char *)ob;
*outbufleft = obtail - ob;
return(ret_val);
}