#ifndef lint
#endif
/*
* Copyright (c) 2000,2002 Japan Network Information Center.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set forth bellow.
*
* LICENSE TERMS AND CONDITIONS
*
* The following License Terms and Conditions apply, unless a different
* license is obtained from Japan Network Information Center ("JPNIC"),
* a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
* Chiyoda-ku, Tokyo 101-0047, Japan.
*
* 1. Use, Modification and Redistribution (including distribution of any
* under this License Terms and Conditions.
*
* 2. Redistribution of source code must retain the copyright notices as they
* appear in each source code file, this License Terms and Conditions.
*
* 3. Redistribution in binary form must reproduce the Copyright Notice,
* materials provided with the distribution. For the purposes of binary
* distribution the "Copyright Notice" refers to the following language:
* "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved."
*
* 4. The name of JPNIC may not be used to endorse or promote products
* derived from this Software without specific prior written approval of
* JPNIC.
*
* 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <config.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#ifndef WITHOUT_ICONV
#include <iconv.h>
#endif
#include <idn/logmacro.h>
#include <idn/converter.h>
#include <idn/aliaslist.h>
#include <idn/punycode.h>
#ifndef IDN_UTF8_ENCODING_NAME
#endif
#ifndef IDN_RACE_ENCODING_NAME
#endif
#ifndef IDN_AMCACEZ_ENCODING_NAME
#endif
#ifndef IDN_PUNYCODE_ENCODING_NAME
#endif
#ifdef WIN32
#else /* WIN32 */
#ifndef IDN_RESCONF_DIR
#endif
#endif /* WIN32 */
typedef struct {
int encoding_type;
struct idn_converter {
char *local_encoding_name;
int flags;
int opened_convfromucs4;
int opened_convtoucs4;
int reference_count;
void *private_data;
};
static idn_result_t register_standard_encoding(void);
const unsigned long *from,
const char *to);
static idn_result_t
static idn_result_t
static idn_result_t
void *privdata,
const unsigned long *from,
static idn_result_t
#ifndef WITHOUT_ICONV
static idn_result_t
static idn_result_t
static idn_result_t
static idn_result_t
void *privdata,
const unsigned long *from,
static idn_result_t
void *privdata,
const char *from,
static idn_result_t
iconv_initialize_privdata(void **privdata);
static void
iconv_finalize_privdata(void *privdata);
static char * get_system_aliasfile(void);
static int file_exist(const char *filename);
#endif /* !WITHOUT_ICONV */
#ifdef DEBUG
static idn_result_t
void *privdata,
const unsigned long *from,
static idn_result_t
void *privdata,
const char *from,
unsigned long *to,
#endif /* DEBUG */
};
#ifndef WITHOUT_ICONV
};
#endif
/*
* Initialize.
*/
idn_converter_initialize(void) {
idn_result_t r;
#ifndef WITHOUT_ICONV
const char *fname;
#endif
TRACE(("idn_converter_initialize()\n"));
if (encoding_name_hash == NULL) {
goto ret;
r = register_standard_encoding();
}
if (encoding_alias_list == NULL) {
goto ret;
#ifndef WITHOUT_ICONV
#endif
}
r = idn_success;
ret:
return (r);
}
#ifndef WITHOUT_ICONV
static char *
#ifdef WIN32
alias_path, sizeof(alias_path))) {
return (alias_path);
} else {
return (NULL);
}
#else
return (IDN_ALIAS_FILE);
#endif
}
static int
return (0);
return (1);
}
#endif
const char *realname;
idn_result_t r;
void *v;
#ifdef DEBUG
}
#endif
/* Allocate memory for a converter context and the name. */
r = idn_nomemory;
goto ret;
}
ctx->opened_convfromucs4 = 0;
ctx->opened_convtoucs4 = 0;
/* No conversion needed */
== idn_success) {
/* Special converter found */
} else {
/* General case */
#ifdef WITHOUT_ICONV
r = idn_invalid_name;
goto ret;
#else
#endif
}
if ((flags & IDN_CONVERTER_DELAYEDOPEN) == 0) {
if (r != idn_success) {
WARNING(("idn_converter_create(): open failed "
"(ucs4->local)\n"));
goto ret;
}
if (r != idn_success) {
WARNING(("idn_converter_create(): open failed "
"(local->ucs4)\n"));
goto ret;
}
}
r = idn_success;
ret:
return (r);
}
void
ctx->reference_count--;
if (ctx->reference_count <= 0) {
TRACE(("idn_converter_destroy(): the object is destroyed\n"));
} else {
TRACE(("idn_converter_destroy(): "
"update reference count (%d->%d)\n",
}
}
void
TRACE(("idn_converter_incrref: update reference count (%d->%d)\n",
ctx->reference_count++;
}
char *
TRACE(("idn_converter_localencoding(ctx=%s)\n",
return (ctx->local_encoding_name);
}
int
int encoding_type;
TRACE(("idn_converter_encodingtype(ctx=%s)\n",
return (encoding_type);
}
int
int iscompat;
TRACE(("idn_converter_isasciicompatible(ctx=%s)\n",
return (iscompat);
}
idn_result_t r;
TRACE(("idn_converter_convfromucs4(ctx=%s, from=\"%s\", tolen=%d)\n",
(int)tolen));
if (!ctx->opened_convfromucs4) {
if (r != idn_success)
goto ret;
}
if (r != idn_success)
goto ret;
if (r != idn_success)
goto ret;
}
r = idn_success;
ret:
if (r == idn_success) {
TRACE(("idn_converter_convfromucs4(): success (to=\"%s\")\n",
} else {
TRACE(("idn_converter_convfromucs4(): %s\n",
idn_result_tostring(r)));
}
return (r);
}
idn_result_t r;
TRACE(("idn_converter_convtoucs4(ctx=%s, from=\"%s\", tolen=%d)\n",
(int)tolen));
if (!ctx->opened_convtoucs4) {
if (r != idn_success)
goto ret;
}
ret:
if (r == idn_success) {
TRACE(("idn_converter_convtoucs4(): success (to=\"%s\")\n",
} else {
TRACE(("idn_converter_convtoucs4(): %s\n",
idn_result_tostring(r)));
}
return (r);
}
/*
* Encoding registration.
*/
int encoding_type) {
idn_result_t r;
r = idn_nomemory;
goto ret;
}
if (openfromucs4 == NULL)
if (opentoucs4 == NULL)
if (r != idn_success) {
goto ret;
}
r = idn_success;
ret:
return (r);
}
static idn_result_t
register_standard_encoding(void) {
idn_result_t r;
NULL,
NULL,
if (r != idn_success)
return (r);
#ifdef IDN_EXTRA_ACE
NULL,
NULL,
if (r != idn_success)
return (r);
NULL,
NULL,
if (r != idn_success)
return (r);
#endif /* IDN_EXTRA_ACE */
#ifdef DEBUG
/* This is convenient for debug. Not useful for other purposes. */
r = idn_converter_register("U-escape",
NULL,
NULL,
NULL,
if (r != idn_success)
return (r);
#endif /* DEBUG */
return (r);
}
/*
* Encoding alias support.
*/
int first_item) {
idn_result_t r;
TRACE(("idn_converter_addalias(alias_name=%s,real_name=%s)\n",
alias_name, real_name));
return idn_invalid_syntax;
}
r = idn_success;
goto ret;
}
if (encoding_alias_list == NULL) {
WARNING(("idn_converter_addalias(): the module is not "
"initialized\n"));
r = idn_failure;
goto ret;
}
ret:
return (r);
}
idn_result_t r;
if (encoding_alias_list == NULL) {
WARNING(("idn_converter_aliasfile(): the module is not "
"initialized\n"));
return (idn_failure);
}
return (r);
}
idn_converter_resetalias(void) {
idn_result_t r;
TRACE(("idn_converter_resetalias()\n"));
if (encoding_alias_list == NULL) {
WARNING(("idn_converter_resetalias(): the module is not "
"initialized\n"));
return (idn_failure);
}
r = idn__aliaslist_create(&list);
return (r);
}
const char *
char *realname;
idn_result_t r;
TRACE(("idn_converter_getrealname()\n"));
if (encoding_alias_list == NULL) {
WARNING(("idn_converter_getrealname(): the module is not "
"initialized\n"));
return (name);
}
if (r != idn_success) {
return (name);
}
return (realname);
}
/*
* Round trip check.
*/
static idn_result_t
{
/*
* One problem with iconv() convertion is that
* iconv() doesn't signal an error if the input
* string contains characters which are valid but
* do not have mapping to the output codeset.
* (the behavior of iconv() for that case is defined as
* `implementation dependent')
* One way to check this case is to perform round-trip
* conversion and see if it is same as the original string.
*/
idn_result_t r;
unsigned long *back;
TRACE(("idn_converter_convert: round-trip checking (from=\"%s\")\n",
/* Allocate enough buffer. */
} else {
return (idn_nomemory);
}
/*
* Perform backward conversion.
*/
switch (r) {
case idn_success:
r = idn_nomapping;
break;
case idn_invalid_encoding:
case idn_buffer_overflow:
r = idn_nomapping;
break;
default:
break;
}
if (r != idn_success) {
TRACE(("round-trip check failed: %s\n",
idn_result_tostring(r)));
}
return (r);
}
/*
* Identity conversion (or, no conversion at all).
*/
static idn_result_t
return (idn_success);
}
static idn_result_t
return (idn_success);
}
static idn_result_t
}
static idn_result_t
}
#ifndef WITHOUT_ICONV
/*
* Conversion using iconv() interface.
*/
static idn_result_t
idn_result_t r;
if (r != idn_success)
return (r);
switch (errno) {
case ENOMEM:
return (idn_nomemory);
case EINVAL:
return (idn_invalid_name);
default:
return (idn_failure);
}
}
return (idn_success);
}
static idn_result_t
idn_result_t r;
if (r != idn_success)
return (r);
switch (errno) {
case ENOMEM:
return (idn_nomemory);
case EINVAL:
return (idn_invalid_name);
default:
return (idn_failure);
}
}
return (idn_success);
}
static idn_result_t
return (idn_nomemory);
}
return (idn_success);
}
static void
iconv_close(*ictxp);
ictxp++;
iconv_close(*ictxp);
}
}
static idn_result_t
return (idn_success);
}
static idn_result_t
idn_result_t r;
if (tolen <= 0) {
r = idn_buffer_overflow; /* need space for NUL */
goto ret;
}
/*
* UCS4 -> UTF-8 conversion.
*/
r = idn_nomemory;
goto ret;
}
if (r == idn_buffer_overflow) {
char *new_utf8;
utf8size *= 2;
r = idn_nomemory;
goto ret;
}
goto try_again;
} else if (r != idn_success) {
goto ret;
}
/*
* Reset internal state.
*
* The following code should work according to the SUSv2 spec,
* but causes segmentation fault with Solaris 2.6.
* So.. a work-around.
*
* (void)iconv(ictx, (const char **)NULL, (size_t *)NULL,
* (char **)NULL, (size_t *)NULL);
*/
inleft = 0;
outleft = 0;
switch (errno) {
case EILSEQ:
case EINVAL:
/*
* We already checked the validity of the input
* string. So we assume a mapping error.
*/
r = idn_nomapping;
goto ret;
case E2BIG:
r = idn_buffer_overflow;
goto ret;
default:
r = idn_failure;
goto ret;
}
}
/*
* For UTF-8 -> local conversion, append a sequence of
* state reset.
*/
inleft = 0;
switch (errno) {
case EILSEQ:
case EINVAL:
r = idn_invalid_encoding;
goto ret;
case E2BIG:
r = idn_buffer_overflow;
goto ret;
default:
r = idn_failure;
goto ret;
}
}
*to = '\0';
r = idn_success;
ret:
return (r);
}
static idn_result_t
idn_result_t r;
const char *from_ptr;
char *outbuf;
if (tolen <= 0) {
r = idn_buffer_overflow; /* need space for NUL */
goto ret;
}
r = idn_nomemory;
goto ret;
}
/*
* Reset internal state.
*/
inleft = 0;
outleft = 0;
char *new_utf8;
switch (errno) {
case EILSEQ:
case EINVAL:
/*
* We assume all the characters in the local
* codeset are included in UCS. This means mapping
* error is not possible, so the input string must
* have some problem.
*/
r = idn_invalid_encoding;
goto ret;
case E2BIG:
utf8size *= 2;
r = idn_nomemory;
goto ret;
}
goto try_again;
default:
r = idn_failure;
goto ret;
}
}
*outbuf = '\0';
/*
* UTF-8 -> UCS4 conversion.
*/
ret:
return (r);
}
#endif /* !WITHOUT_ICONV */
#ifdef DEBUG
/*
* Arbitrary UCS-4 character can be specified by a special sequence
* \u{XXXXXX}
* where XXXXX denotes any hexadecimal string up to FFFFFFFF.
* This is designed for debugging.
*/
static idn_result_t
idn_result_t r;
unsigned long v;
while (*from != '\0') {
v = *from++;
if (v <= 0x7f) {
if (tolen < 1) {
r = idn_buffer_overflow;
goto failure;
}
*to++ = v;
tolen--;
} else if (v <= 0xffffffff) {
int len;
r = idn_buffer_overflow;
goto failure;
}
} else {
r = idn_invalid_encoding;
goto failure;
}
}
if (tolen <= 0) {
r = idn_buffer_overflow;
goto failure;
}
*to = '\0';
return (idn_success);
if (r != idn_buffer_overflow) {
WARNING(("idn_uescape_convfromucs4(): %s\n",
idn_result_tostring(r)));
}
return (r);
}
static idn_result_t
{
idn_result_t r;
while (*from != '\0') {
if (tolen <= 0) {
r = idn_buffer_overflow;
goto failure;
}
unsigned long v;
char *end;
*to = v;
} else {
*to = '\\';
from++;
fromlen--;
}
} else {
int c = *(unsigned char *)from;
if (c < 0x80)
width = 1;
else if (c < 0xc0)
width = 0;
else if (c < 0xe0)
width = 2;
else if (c < 0xf0)
width = 3;
else if (c < 0xf8)
width = 4;
else if (c < 0xfc)
width = 5;
else if (c < 0xfe)
width = 6;
else
width = 0;
r = idn_invalid_encoding;
goto failure;
}
if (r != idn_success) {
r = idn_invalid_encoding;
goto failure;
}
}
to++;
tolen--;
}
if (tolen <= 0) {
r = idn_buffer_overflow;
goto failure;
}
*to = '\0';
return (idn_success);
if (r != idn_buffer_overflow) {
WARNING(("idn_uescape_convtoucs4(): %s\n",
idn_result_tostring(r)));
}
return (r);
}
#endif