summaryrefslogtreecommitdiffstats
path: root/contrib/idn/idnkit-1.0-src/lib/res.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/idn/idnkit-1.0-src/lib/res.c')
-rw-r--r--contrib/idn/idnkit-1.0-src/lib/res.c1726
1 files changed, 1726 insertions, 0 deletions
diff --git a/contrib/idn/idnkit-1.0-src/lib/res.c b/contrib/idn/idnkit-1.0-src/lib/res.c
new file mode 100644
index 0000000..cefd0c3
--- /dev/null
+++ b/contrib/idn/idnkit-1.0-src/lib/res.c
@@ -0,0 +1,1726 @@
+#ifndef lint
+static char *rcsid = "$Id: res.c,v 1.1.1.1 2003/06/04 00:26:10 marka Exp $";
+#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
+ * modified or derived work) in source and/or binary forms is permitted
+ * 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,
+ * this License Terms and Conditions, in the documentation and/or other
+ * 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 <string.h>
+
+#include <idn/result.h>
+#include <idn/assert.h>
+#include <idn/logmacro.h>
+#include <idn/converter.h>
+#include <idn/normalizer.h>
+#include <idn/checker.h>
+#include <idn/mapper.h>
+#include <idn/mapselector.h>
+#include <idn/delimitermap.h>
+#include <idn/resconf.h>
+#include <idn/res.h>
+#include <idn/util.h>
+#include <idn/debug.h>
+#include <idn/ucs4.h>
+
+#ifndef IDN_UTF8_ENCODING_NAME
+#define IDN_UTF8_ENCODING_NAME "UTF-8" /* by IANA */
+#endif
+
+#ifndef WITHOUT_ICONV
+#define ENCODE_MASK \
+ (IDN_LOCALCONV | IDN_DELIMMAP | IDN_LOCALMAP | IDN_MAP | \
+ IDN_NORMALIZE | IDN_PROHCHECK | IDN_UNASCHECK | IDN_BIDICHECK | \
+ IDN_ASCCHECK | IDN_IDNCONV | IDN_LENCHECK | IDN_ENCODE_QUERY | \
+ IDN_UNDOIFERR)
+#define DECODE_MASK \
+ (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | IDN_PROHCHECK | \
+ IDN_UNASCHECK | IDN_BIDICHECK | IDN_IDNCONV | IDN_ASCCHECK | \
+ IDN_RTCHECK | IDN_LOCALCONV | IDN_DECODE_QUERY)
+#else
+#define ENCODE_MASK \
+ (IDN_DELIMMAP | IDN_LOCALMAP | IDN_MAP | IDN_NORMALIZE | \
+ IDN_PROHCHECK | IDN_UNASCHECK | IDN_BIDICHECK | IDN_ASCCHECK | \
+ IDN_IDNCONV | IDN_LENCHECK | IDN_ENCODE_QUERY | IDN_UNDOIFERR)
+#define DECODE_MASK \
+ (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | IDN_PROHCHECK | \
+ IDN_UNASCHECK | IDN_BIDICHECK | IDN_IDNCONV | IDN_ASCCHECK | \
+ IDN_RTCHECK | IDN_DECODE_QUERY)
+#endif
+
+#define MAX_LABEL_LENGTH 63
+
+/*
+ * label to convert.
+ */
+typedef struct labellist * labellist_t;
+struct labellist {
+ unsigned long *name;
+ size_t name_length;
+ unsigned long *undo_name;
+ labellist_t next;
+ labellist_t previous;
+ int dot_followed;
+};
+
+typedef idn_result_t (*res_insnproc_t)(idn_resconf_t ctx,
+ labellist_t label);
+
+static void idn_res_initialize(void);
+static idn_result_t copy_verbatim(const char *from, char *to,
+ size_t tolen);
+static idn_result_t labellist_create(const unsigned long *name,
+ labellist_t *labelp);
+static void labellist_destroy(labellist_t label);
+static idn_result_t labellist_setname(labellist_t label,
+ const unsigned long *name);
+static const unsigned long *
+ labellist_getname(labellist_t label);
+static const unsigned long *
+ labellist_gettldname(labellist_t label);
+static idn_result_t labellist_getnamelist(labellist_t label,
+ unsigned long *name,
+ size_t label_length);
+static void labellist_undo(labellist_t label);
+static labellist_t labellist_tail(labellist_t label);
+static labellist_t labellist_previous(labellist_t label);
+
+#ifndef WITHOUT_ICONV
+static idn_result_t label_localdecodecheck(idn_resconf_t ctx,
+ labellist_t label);
+#endif
+static idn_result_t label_idnencode_ace(idn_resconf_t ctx,
+ labellist_t label);
+static idn_result_t label_idndecode(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_localmap(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_map(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_normalize(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_prohcheck(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_unascheck(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_bidicheck(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_asccheck(idn_resconf_t ctx, labellist_t label);
+static idn_result_t label_lencheck_ace(idn_resconf_t ctx,
+ labellist_t label);
+static idn_result_t label_lencheck_nonace(idn_resconf_t ctx,
+ labellist_t label);
+static idn_result_t label_rtcheck(idn_resconf_t ctx, idn_action_t actions,
+ labellist_t label,
+ const unsigned long *original_name);
+
+static int initialized;
+static int enabled;
+
+void
+idn_res_enable(int on_off) {
+ if (!initialized) {
+ idn_res_initialize();
+ }
+
+ if (on_off == 0) {
+ enabled = 0;
+ } else {
+ enabled = 1;
+ }
+}
+
+static void
+idn_res_initialize(void) {
+ if (!initialized) {
+ char *value = getenv("IDN_DISABLE");
+
+ if (value == NULL) {
+ enabled = 1;
+ } else {
+ enabled = 0;
+ }
+ initialized = 1;
+ }
+}
+
+idn_result_t
+idn_res_encodename(idn_resconf_t ctx, idn_action_t actions, const char *from,
+ char *to, size_t tolen) {
+ idn_converter_t local_converter = NULL;
+ idn_converter_t idn_converter = NULL;
+ idn_delimitermap_t delimiter_mapper;
+ idn_result_t r;
+ labellist_t labels = NULL, l;
+ unsigned long *buffer = NULL;
+ size_t buffer_length;
+ int from_is_root;
+ int idn_is_ace;
+
+ assert(ctx != NULL && from != NULL && to != NULL);
+
+ TRACE(("idn_res_encodename(actions=%s, from=\"%s\", tolen=%d)\n",
+ idn__res_actionstostring(actions),
+ idn__debug_xstring(from, 50), (int)tolen));
+
+ if (actions & ~ENCODE_MASK) {
+ WARNING(("idn_res_encodename: invalid actions 0x%x\n",
+ actions));
+ r = idn_invalid_action;
+ goto ret;
+ }
+
+ if (!initialized)
+ idn_res_initialize();
+ if (!enabled || actions == 0) {
+ r = copy_verbatim(from, to, tolen);
+ goto ret;
+ } else if (tolen <= 0) {
+ r = idn_buffer_overflow;
+ goto ret;
+ }
+
+ if (actions & IDN_ENCODE_QUERY) {
+#ifndef WITHOUT_ICONV
+ actions |= (IDN_LOCALCONV | IDN_DELIMMAP | IDN_LOCALMAP | \
+ IDN_MAP | IDN_NORMALIZE | IDN_PROHCHECK | \
+ IDN_BIDICHECK | IDN_IDNCONV | IDN_LENCHECK);
+#else
+ actions |= (IDN_DELIMMAP | IDN_LOCALMAP | IDN_MAP | \
+ IDN_NORMALIZE | IDN_PROHCHECK | IDN_BIDICHECK | \
+ IDN_IDNCONV | IDN_LENCHECK);
+#endif
+ }
+
+ /*
+ * Convert `from' to UCS4.
+ */
+ local_converter = idn_resconf_getlocalconverter(ctx);
+#ifndef WITHOUT_ICONV
+ if (local_converter == NULL) {
+ r = idn_invalid_name;
+ goto ret;
+ }
+#endif
+
+ idn_converter = idn_resconf_getidnconverter(ctx);
+ if (idn_converter != NULL &&
+ idn_converter_isasciicompatible(idn_converter))
+ idn_is_ace = 1;
+ else
+ idn_is_ace = 0;
+
+ buffer_length = tolen * 2;
+
+ for (;;) {
+ void *new_buffer;
+
+ new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ buffer = (unsigned long *)new_buffer;
+
+ if (actions & IDN_LOCALCONV) {
+ r = idn_converter_convtoucs4(local_converter, from,
+ buffer, buffer_length);
+ } else {
+ r = idn_ucs4_utf8toucs4(from, buffer, buffer_length);
+ }
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+
+ buffer_length *= 2;
+ }
+
+ if (*buffer == '\0') {
+ if (tolen <= 0) {
+ r = idn_buffer_overflow;
+ goto ret;
+ }
+ *to = '\0';
+ r = idn_success;
+ goto ret;
+ }
+
+ /*
+ * Delimiter map.
+ */
+ if (actions & IDN_DELIMMAP) {
+ TRACE(("res delimitermap(name=\"%s\")\n",
+ idn__debug_ucs4xstring(buffer, 50)));
+
+ delimiter_mapper = idn_resconf_getdelimitermap(ctx);
+ if (delimiter_mapper != NULL) {
+ r = idn_delimitermap_map(delimiter_mapper, buffer,
+ buffer, buffer_length);
+ idn_delimitermap_destroy(delimiter_mapper);
+ if (r != idn_success)
+ goto ret;
+ }
+ TRACE(("res delimitermap(): success (name=\"%s\")\n",
+ idn__debug_ucs4xstring(buffer, 50)));
+ }
+
+ from_is_root = (buffer[0] == '.' && buffer[1] == '\0');
+
+ /*
+ * Split the name into a list of labels.
+ */
+ r = labellist_create(buffer, &labels);
+ if (r != idn_success)
+ goto ret;
+
+ /*
+ * Perform conversions and tests.
+ */
+ for (l = labellist_tail(labels); l != NULL;
+ l = labellist_previous(l)) {
+
+ if (!idn__util_ucs4isasciirange(labellist_getname(l))) {
+ if (actions & IDN_LOCALMAP) {
+ r = label_localmap(ctx, l);
+ if (r != idn_success)
+ goto ret;
+ }
+ }
+
+ if (!idn__util_ucs4isasciirange(labellist_getname(l))) {
+ if (actions & IDN_MAP) {
+ r = label_map(ctx, l);
+ if (r != idn_success)
+ goto ret;
+ }
+ if (actions & IDN_NORMALIZE) {
+ r = label_normalize(ctx, l);
+ if (r != idn_success)
+ goto ret;
+ }
+ if (actions & IDN_PROHCHECK) {
+ r = label_prohcheck(ctx, l);
+ if (r == idn_prohibited &&
+ (actions & IDN_UNDOIFERR)) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ if (actions & IDN_UNASCHECK) {
+ r = label_unascheck(ctx, l);
+ if (r == idn_prohibited &&
+ (actions & IDN_UNDOIFERR)) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ if (actions & IDN_BIDICHECK) {
+ r = label_bidicheck(ctx, l);
+ if (r == idn_prohibited &&
+ (actions & IDN_UNDOIFERR)) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ }
+
+ if (actions & IDN_ASCCHECK) {
+ r = label_asccheck(ctx, l);
+ if (r == idn_prohibited && (actions & IDN_UNDOIFERR)) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+
+ if (!idn__util_ucs4isasciirange(labellist_getname(l))) {
+ if ((actions & IDN_IDNCONV) && idn_is_ace) {
+ r = label_idnencode_ace(ctx, l);
+ if (r != idn_success)
+ goto ret;
+ }
+ }
+
+ if (!from_is_root && (actions & IDN_LENCHECK)) {
+ if (idn_is_ace)
+ r = label_lencheck_ace(ctx, l);
+ else
+ r = label_lencheck_nonace(ctx, l);
+ if (r == idn_invalid_length &&
+ (actions & IDN_UNDOIFERR)) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ }
+
+ /*
+ * Concat a list of labels to a name.
+ */
+ for (;;) {
+ void *new_buffer;
+
+ new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ buffer = (unsigned long *)new_buffer;
+
+ r = labellist_getnamelist(labels, buffer, buffer_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+
+ buffer_length *= 2;
+ }
+
+ if ((actions & IDN_IDNCONV) && idn_converter != NULL && !idn_is_ace) {
+ r = idn_converter_convfromucs4(idn_converter, buffer, to,
+ tolen);
+ } else {
+ r = idn_ucs4_ucs4toutf8(buffer, to, tolen);
+ }
+
+ret:
+ if (r == idn_success) {
+ TRACE(("idn_res_encodename(): success (to=\"%s\")\n",
+ idn__debug_xstring(to, 50)));
+ } else {
+ TRACE(("idn_res_encodename(): %s\n", idn_result_tostring(r)));
+ }
+ free(buffer);
+ if (local_converter != NULL)
+ idn_converter_destroy(local_converter);
+ if (idn_converter != NULL)
+ idn_converter_destroy(idn_converter);
+ if (labels != NULL)
+ labellist_destroy(labels);
+ return (r);
+}
+
+idn_result_t
+idn_res_decodename(idn_resconf_t ctx, idn_action_t actions, const char *from,
+ char *to, size_t tolen) {
+ idn_converter_t local_converter = NULL;
+ idn_converter_t idn_converter = NULL;
+ idn_delimitermap_t delimiter_mapper;
+ idn_result_t r;
+ labellist_t labels = NULL, l;
+ unsigned long *buffer = NULL;
+ unsigned long *saved_name = NULL;
+ size_t buffer_length;
+ int idn_is_ace;
+
+ assert(ctx != NULL && from != NULL && to != NULL);
+
+ TRACE(("idn_res_decodename(actions=%s, from=\"%s\", tolen=%d)\n",
+ idn__res_actionstostring(actions),
+ idn__debug_xstring(from, 50), (int)tolen));
+
+ if (actions & ~DECODE_MASK) {
+ WARNING(("idn_res_decodename: invalid actions 0x%x\n",
+ actions));
+ r = idn_invalid_action;
+ goto ret;
+ }
+
+ if (!initialized)
+ idn_res_initialize();
+ if (!enabled || actions == 0) {
+ r = copy_verbatim(from, to, tolen);
+ goto ret;
+ } else if (tolen <= 0) {
+ r = idn_buffer_overflow;
+ goto ret;
+ }
+
+ if (actions & IDN_DECODE_QUERY) {
+#ifndef WITHOUT_ICONV
+ actions |= (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | \
+ IDN_PROHCHECK | IDN_BIDICHECK | IDN_IDNCONV | \
+ IDN_RTCHECK | IDN_LOCALCONV);
+#else
+ actions |= (IDN_DELIMMAP | IDN_MAP | IDN_NORMALIZE | \
+ IDN_PROHCHECK | IDN_BIDICHECK | IDN_IDNCONV | \
+ IDN_RTCHECK);
+#endif
+ }
+
+ /*
+ * Convert `from' to UCS4.
+ */
+ local_converter = idn_resconf_getlocalconverter(ctx);
+#ifndef WITHOUT_ICONV
+ if (local_converter == NULL) {
+ r = idn_invalid_name;
+ goto ret;
+ }
+#endif
+
+ idn_converter = idn_resconf_getidnconverter(ctx);
+ if (idn_converter != NULL &&
+ idn_converter_isasciicompatible(idn_converter))
+ idn_is_ace = 1;
+ else
+ idn_is_ace = 0;
+
+ buffer_length = tolen * 2;
+
+ TRACE(("res idndecode(name=\"%s\")\n", idn__debug_xstring(from, 50)));
+
+ for (;;) {
+ void *new_buffer;
+
+ new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ buffer = (unsigned long *)new_buffer;
+
+ if ((actions & IDN_IDNCONV) &&
+ idn_converter != NULL && !idn_is_ace) {
+ r = idn_converter_convtoucs4(idn_converter, from,
+ buffer, buffer_length);
+ } else {
+ r = idn_ucs4_utf8toucs4(from, buffer, buffer_length);
+ }
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+
+ buffer_length *= 2;
+ }
+
+ if (*buffer == '\0') {
+ if (tolen <= 0) {
+ r = idn_buffer_overflow;
+ goto ret;
+ }
+ *to = '\0';
+ r = idn_success;
+ goto ret;
+ }
+
+ /*
+ * Delimiter map.
+ */
+ if (actions & IDN_DELIMMAP) {
+ TRACE(("res delimitermap(name=\"%s\")\n",
+ idn__debug_ucs4xstring(buffer, 50)));
+
+ delimiter_mapper = idn_resconf_getdelimitermap(ctx);
+ if (delimiter_mapper != NULL) {
+ r = idn_delimitermap_map(delimiter_mapper, buffer,
+ buffer, buffer_length);
+ idn_delimitermap_destroy(delimiter_mapper);
+ if (r != idn_success)
+ goto ret;
+ }
+ TRACE(("res delimitermap(): success (name=\"%s\")\n",
+ idn__debug_ucs4xstring(buffer, 50)));
+ }
+
+ /*
+ * Split the name into a list of labels.
+ */
+ r = labellist_create(buffer, &labels);
+ if (r != idn_success)
+ goto ret;
+
+ /*
+ * Perform conversions and tests.
+ */
+ for (l = labellist_tail(labels); l != NULL;
+ l = labellist_previous(l)) {
+
+ free(saved_name);
+ saved_name = NULL;
+
+ if (!idn__util_ucs4isasciirange(labellist_getname(l))) {
+ if (actions & IDN_MAP) {
+ r = label_map(ctx, l);
+ if (r != idn_success)
+ goto ret;
+ }
+ if (actions & IDN_NORMALIZE) {
+ r = label_normalize(ctx, l);
+ if (r != idn_success)
+ goto ret;
+ }
+ if (actions & IDN_PROHCHECK) {
+ r = label_prohcheck(ctx, l);
+ if (r == idn_prohibited) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ if (actions & IDN_UNASCHECK) {
+ r = label_unascheck(ctx, l);
+ if (r == idn_prohibited) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ if (actions & IDN_BIDICHECK) {
+ r = label_bidicheck(ctx, l);
+ if (r == idn_prohibited) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ }
+
+ if ((actions & IDN_IDNCONV) && idn_is_ace) {
+ saved_name = idn_ucs4_strdup(labellist_getname(l));
+ if (saved_name == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ r = label_idndecode(ctx, l);
+ if (r == idn_invalid_encoding) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+ if ((actions & IDN_RTCHECK) && saved_name != NULL) {
+ r = label_rtcheck(ctx, actions, l, saved_name);
+ if (r == idn_invalid_encoding) {
+ labellist_undo(l);
+ continue;
+ } else if (r != idn_success) {
+ goto ret;
+ }
+ }
+
+#ifndef WITHOUT_ICONV
+ if (actions & IDN_LOCALCONV) {
+ r = label_localdecodecheck(ctx, l);
+ if (r != idn_success)
+ goto ret;
+ }
+#endif
+ }
+
+ /*
+ * Concat a list of labels to a name.
+ */
+ for (;;) {
+ void *new_buffer;
+
+ new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ buffer = (unsigned long *)new_buffer;
+
+ r = labellist_getnamelist(labels, buffer, buffer_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+
+ buffer_length *= 2;
+ }
+
+ if (actions & IDN_LOCALCONV) {
+ r = idn_converter_convfromucs4(local_converter, buffer, to,
+ tolen);
+ } else {
+ r = idn_ucs4_ucs4toutf8(buffer, to, tolen);
+ }
+
+ret:
+ if (r == idn_success) {
+ TRACE(("idn_res_decodename(): success (to=\"%s\")\n",
+ idn__debug_xstring(to, 50)));
+ } else {
+ TRACE(("idn_res_decodename(): %s\n", idn_result_tostring(r)));
+ }
+ free(saved_name);
+ free(buffer);
+ if (local_converter != NULL)
+ idn_converter_destroy(local_converter);
+ if (idn_converter != NULL)
+ idn_converter_destroy(idn_converter);
+ if (labels != NULL)
+ labellist_destroy(labels);
+ return (r);
+}
+
+idn_result_t
+idn_res_decodename2(idn_resconf_t ctx, idn_action_t actions, const char *from,
+ char *to, size_t tolen, const char *auxencoding) {
+#ifdef WITHOUT_ICONV
+ return idn_failure;
+
+#else /* WITHOUT_ICONV */
+ idn_result_t r;
+ idn_converter_t aux_converter = NULL;
+ unsigned long *buffer_ucs4 = NULL;
+ char *buffer_utf8 = NULL;
+ size_t buffer_length;
+
+ assert(ctx != NULL && from != NULL && to != NULL);
+
+ TRACE(("idn_res_decodename2(actions=%s, from=\"%s\", tolen=%d, "
+ "auxencoding=\"%s\")\n",
+ idn__res_actionstostring(actions),
+ idn__debug_xstring(from, 50), (int)tolen,
+ (auxencoding != NULL) ? auxencoding : "<null>"));
+
+ if (!initialized)
+ idn_res_initialize();
+ if (!enabled || actions == 0) {
+ r = copy_verbatim(from, to, tolen);
+ goto ret;
+ } else if (tolen <= 0) {
+ r = idn_buffer_overflow;
+ goto ret;
+ }
+
+ if (auxencoding == NULL ||
+ strcmp(auxencoding, IDN_UTF8_ENCODING_NAME) == 0 ||
+ strcmp(auxencoding, "UTF-8") == 0) {
+ return idn_res_decodename(ctx, actions, from, to, tolen);
+ }
+
+ /*
+ * Convert `from' to UCS4.
+ */
+ r = idn_resconf_setauxidnconvertername(ctx, auxencoding,
+ IDN_CONVERTER_DELAYEDOPEN);
+ if (r != idn_success) {
+ goto ret;
+ }
+
+ aux_converter = idn_resconf_getauxidnconverter(ctx);
+ if (aux_converter == NULL) {
+ r = idn_failure;
+ goto ret;
+ }
+
+ buffer_length = tolen * 2;
+ for (;;) {
+ void *new_buffer;
+
+ new_buffer = realloc(buffer_ucs4,
+ sizeof(*buffer_ucs4) * buffer_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ buffer_ucs4 = (unsigned long *)new_buffer;
+
+ r = idn_converter_convtoucs4(aux_converter, from,
+ buffer_ucs4,
+ buffer_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+
+ buffer_length *= 2;
+ }
+
+ if (*buffer_ucs4 == '\0') {
+ if (tolen <= 0) {
+ r = idn_buffer_overflow;
+ goto ret;
+ }
+ *to = '\0';
+ r = idn_success;
+ goto ret;
+ }
+
+ /*
+ * Convert `buffer_ucs4' to UTF-8.
+ */
+ buffer_length = tolen * 2;
+ for (;;) {
+ void *new_buffer;
+
+ new_buffer = realloc(buffer_utf8,
+ sizeof(*buffer_utf8) * buffer_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ buffer_utf8 = (char *)new_buffer;
+ r = idn_ucs4_ucs4toutf8(buffer_ucs4, buffer_utf8,
+ buffer_length);
+
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+
+ buffer_length *= 2;
+ }
+
+ if (*buffer_utf8 == '\0') {
+ if (tolen <= 0) {
+ r = idn_buffer_overflow;
+ goto ret;
+ }
+ *to = '\0';
+ r = idn_success;
+ goto ret;
+ }
+
+ r = idn_res_decodename(ctx, actions, buffer_utf8, to, tolen);
+
+ret:
+ if (r == idn_success) {
+ TRACE(("idn_res_decodename2(): success (to=\"%s\")\n",
+ idn__debug_xstring(to, 50)));
+ } else {
+ TRACE(("idn_res_decodename2(): %s\n", idn_result_tostring(r)));
+ }
+ free(buffer_ucs4);
+ free(buffer_utf8);
+ if (aux_converter != NULL)
+ idn_converter_destroy(aux_converter);
+
+ return (r);
+
+#endif /* WITHOUT_ICONV */
+}
+
+static idn_result_t
+copy_verbatim(const char *from, char *to, size_t tolen) {
+ size_t fromlen = strlen(from);
+
+ if (fromlen + 1 > tolen)
+ return (idn_buffer_overflow);
+ (void)memcpy(to, from, fromlen + 1);
+ return (idn_success);
+}
+
+static idn_result_t
+labellist_create(const unsigned long *name, labellist_t *labelp) {
+ size_t length, malloc_length;
+ labellist_t head_label = NULL;
+ labellist_t tail_label = NULL;
+ labellist_t new_label = NULL;
+ const unsigned long *endp = NULL;
+ idn_result_t r;
+
+ while (*name != '\0') {
+ for (endp = name; *endp != '.' && *endp != '\0'; endp++)
+ ; /* nothing to be done */
+ length = (endp - name) + 1;
+ malloc_length = length + 15; /* add 15 for margin */
+
+ new_label = (labellist_t)
+ malloc(sizeof(struct labellist));
+ if (new_label == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ if (head_label == NULL)
+ head_label = new_label;
+
+ new_label->name = NULL;
+ new_label->undo_name = NULL;
+ new_label->name_length = malloc_length;
+ new_label->next = NULL;
+ new_label->previous = NULL;
+ new_label->dot_followed = (*endp == '.');
+
+ new_label->name = (unsigned long *)
+ malloc(sizeof(long) * malloc_length);
+ if (new_label->name == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ memcpy(new_label->name, name, sizeof(long) * length);
+ *(new_label->name + length - 1) = '\0';
+
+ new_label->undo_name = (unsigned long *)
+ malloc(sizeof(long) * malloc_length);
+ if (new_label->undo_name == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ memcpy(new_label->undo_name, name, sizeof(long) * length);
+ *(new_label->undo_name + length - 1) = '\0';
+
+ if (tail_label != NULL) {
+ tail_label->next = new_label;
+ new_label->previous = tail_label;
+ }
+ tail_label = new_label;
+
+ if (*endp == '.')
+ name = endp + 1;
+ else
+ name = endp;
+ }
+
+ *labelp = head_label;
+ r = idn_success;
+
+ret:
+ if (r != idn_success) {
+ if (new_label != NULL) {
+ free(new_label->name);
+ free(new_label->undo_name);
+ free(new_label);
+ }
+ if (head_label != NULL)
+ labellist_destroy(head_label);
+ }
+ return (r);
+}
+
+
+static void
+labellist_destroy(labellist_t label) {
+ labellist_t l, l_next;
+
+ for (l = label; l != NULL; l = l_next) {
+ l_next = l->next;
+ free(l->name);
+ free(l->undo_name);
+ free(l);
+ }
+}
+
+static idn_result_t
+labellist_setname(labellist_t label, const unsigned long *name) {
+ unsigned long *new_name;
+ size_t length, new_length;
+
+ length = idn_ucs4_strlen(name) + 1;
+ new_length = length + 15; /* add 15 for margin */
+
+ if (label->name_length < new_length) {
+ new_name = (unsigned long *)
+ realloc(label->name, sizeof(long) * new_length);
+ if (new_name == NULL)
+ return (idn_nomemory);
+ label->name = new_name;
+ label->name_length = new_length;
+ }
+ memcpy(label->name, name, sizeof(long) * length);
+
+ return (idn_success);
+}
+
+static const unsigned long *
+labellist_getname(labellist_t label) {
+ return (label->name);
+}
+
+static const unsigned long *
+labellist_gettldname(labellist_t label) {
+ labellist_t l;
+
+ if (label->previous == NULL && label->next == NULL &&
+ !label->dot_followed)
+ return (idn_mapselector_getnotld());
+
+ for (l = label; l->next != NULL; l = l->next)
+ ; /* nothing to be done */
+
+ return (l->name);
+}
+
+static idn_result_t
+labellist_getnamelist(labellist_t label, unsigned long *name,
+ size_t name_length) {
+ static const unsigned long dot_string[] = {0x002e, 0x0000}; /* "." */
+ size_t length;
+ labellist_t l;
+
+ for (l = label, length = 0; l != NULL; l = l->next)
+ length += idn_ucs4_strlen(l->name) + 1; /* name + `.' */
+ length++; /* for NUL */
+
+ if (name_length < length)
+ return (idn_buffer_overflow);
+
+ *name = '\0';
+ for (l = label; l != NULL; l = l->next) {
+ idn_ucs4_strcat(name, l->name);
+ name += idn_ucs4_strlen(name);
+ if (l->dot_followed)
+ idn_ucs4_strcat(name, dot_string);
+ }
+ return (idn_success);
+}
+
+static void
+labellist_undo(labellist_t label) {
+ size_t length;
+
+ length = idn_ucs4_strlen(label->undo_name) + 1;
+ memcpy(label->name, label->undo_name, sizeof(long) * length);
+}
+
+static labellist_t
+labellist_tail(labellist_t label) {
+ labellist_t l;
+
+ if (label == NULL)
+ return (NULL);
+ for (l = label; l->next != NULL; l = l->next)
+ ; /* nothing to be done */
+ return (l);
+}
+
+static labellist_t
+labellist_previous(labellist_t label) {
+ return (label->previous);
+}
+
+#ifndef WITHOUT_ICONV
+
+static idn_result_t
+label_localdecodecheck(idn_resconf_t ctx, labellist_t label) {
+ idn_converter_t local_converter = NULL;
+ const unsigned long *from;
+ char *to = NULL;
+ size_t to_length;
+ idn_result_t r;
+
+ from = labellist_getname(label);
+ to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */
+ TRACE(("res ucs4tolocal_check(label=\"%s\")\n",
+ idn__debug_ucs4xstring(from, 50)));
+
+ local_converter = idn_resconf_getlocalconverter(ctx);
+ if (local_converter == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+
+ for (;;) {
+ char *new_buffer;
+
+ new_buffer = (char *)realloc(to, to_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ to = new_buffer;
+ r = idn_converter_convfromucs4(local_converter, from, to,
+ to_length);
+ if (r == idn_success)
+ break;
+ else if (r == idn_nomapping) {
+ r = label_idnencode_ace(ctx, label);
+ if (r != idn_success)
+ goto ret;
+ break;
+ } else if (r != idn_buffer_overflow) {
+ goto ret;
+ }
+ to_length *= 2;
+ }
+
+ r = idn_success;
+ret:
+ TRACE(("res ucs4tolocal_check(): %s\n", idn_result_tostring(r)));
+ if (local_converter != NULL)
+ idn_converter_destroy(local_converter);
+ free(to);
+ return (r);
+}
+
+#endif /* !WITHOUT_ICONV */
+
+static idn_result_t
+label_idndecode(idn_resconf_t ctx, labellist_t label) {
+ idn_converter_t idn_converter = NULL;
+ const unsigned long *from;
+ char *ascii_from = NULL;
+ unsigned long *to = NULL;
+ size_t from_length, to_length;
+ idn_result_t r;
+
+ from = labellist_getname(label);
+ from_length = idn_ucs4_strlen(from) + 1;
+ TRACE(("res idntoucs4(label=\"%s\")\n",
+ idn__debug_ucs4xstring(from, 50)));
+
+ idn_converter = idn_resconf_getidnconverter(ctx);
+ if (idn_converter == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+
+ for (;;) {
+ char *new_buffer;
+
+ new_buffer = (char *) realloc(ascii_from, from_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ ascii_from = new_buffer;
+ r = idn_ucs4_ucs4toutf8(from, ascii_from, from_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+ from_length *= 2;
+ }
+
+ to = NULL;
+ to_length = from_length;
+
+ for (;;) {
+ unsigned long *new_buffer;
+
+ new_buffer = (unsigned long *)
+ realloc(to, sizeof(long) * to_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ to = new_buffer;
+ r = idn_converter_convtoucs4(idn_converter, ascii_from, to,
+ to_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+ to_length *= 2;
+ }
+
+ r = labellist_setname(label, to);
+ret:
+ if (r == idn_success) {
+ TRACE(("res idntoucs4(): success (label=\"%s\")\n",
+ idn__debug_ucs4xstring(labellist_getname(label),
+ 50)));
+ } else {
+ TRACE(("res idntoucs4(): %s\n", idn_result_tostring(r)));
+ }
+ if (idn_converter != NULL)
+ idn_converter_destroy(idn_converter);
+ free(to);
+ free(ascii_from);
+ return (r);
+}
+
+static idn_result_t
+label_idnencode_ace(idn_resconf_t ctx, labellist_t label) {
+ idn_converter_t idn_converter = NULL;
+ const unsigned long *from;
+ char *ascii_to = NULL;
+ unsigned long *to = NULL;
+ size_t to_length;
+ idn_result_t r;
+
+ from = labellist_getname(label);
+ TRACE(("res ucs4toidn(label=\"%s\")\n",
+ idn__debug_ucs4xstring(from, 50)));
+
+ idn_converter = idn_resconf_getidnconverter(ctx);
+ if (idn_converter == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+
+ ascii_to = NULL;
+ to_length = idn_ucs4_strlen(from) * 4 + 16; /* add mergin */
+
+ for (;;) {
+ char *new_buffer;
+
+ new_buffer = (char *) realloc(ascii_to, to_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ ascii_to = new_buffer;
+ r = idn_converter_convfromucs4(idn_converter, from, ascii_to,
+ to_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+ to_length *= 2;
+ }
+
+ for (;;) {
+ unsigned long *new_buffer;
+
+ new_buffer = (unsigned long *)
+ realloc(to, sizeof(long) * to_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ to = new_buffer;
+ r = idn_ucs4_utf8toucs4(ascii_to, to, to_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+ to_length *= 2;
+ }
+
+ if (r != idn_success)
+ goto ret;
+
+ r = labellist_setname(label, to);
+ret:
+ if (r == idn_success) {
+ TRACE(("res ucs4toidn(): success (label=\"%s\")\n",
+ idn__debug_ucs4xstring(labellist_getname(label),
+ 50)));
+ } else {
+ TRACE(("res ucs4toidn(): %s\n", idn_result_tostring(r)));
+ }
+ if (idn_converter != NULL)
+ idn_converter_destroy(idn_converter);
+ free(to);
+ free(ascii_to);
+ return (r);
+}
+
+static idn_result_t
+label_localmap(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *from;
+ const unsigned long *tld;
+ unsigned long *to = NULL;
+ size_t to_length;
+ idn_mapselector_t local_mapper;
+ idn_result_t r;
+
+ from = labellist_getname(label);
+ tld = labellist_gettldname(label);
+ TRACE(("res localmap(label=\"%s\", tld=\"%s\")\n",
+ idn__debug_ucs4xstring(from, 50),
+ idn__debug_ucs4xstring(tld, 50)));
+
+ local_mapper = idn_resconf_getlocalmapselector(ctx);
+ if (local_mapper == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+
+ if (tld == from)
+ tld = idn_mapselector_getdefaulttld();
+ to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */
+
+ for (;;) {
+ unsigned long *new_buffer;
+
+ new_buffer = (unsigned long *)
+ realloc(to, sizeof(long) * to_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ to = new_buffer;
+ r = idn_mapselector_map2(local_mapper, from, tld, to,
+ to_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+ to_length *= 2;
+ }
+
+ r = labellist_setname(label, to);
+ret:
+ if (r == idn_success) {
+ TRACE(("res localmap(): success (label=\"%s\")\n",
+ idn__debug_ucs4xstring(labellist_getname(label),
+ 50)));
+ } else {
+ TRACE(("res localmap(): %s\n", idn_result_tostring(r)));
+ }
+ if (local_mapper != NULL)
+ idn_mapselector_destroy(local_mapper);
+ free(to);
+ return (r);
+}
+
+static idn_result_t
+label_map(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *from;
+ unsigned long *to = NULL;
+ size_t to_length;
+ idn_mapper_t mapper;
+ idn_result_t r;
+
+ from = labellist_getname(label);
+ TRACE(("res map(label=\"%s\")\n", idn__debug_ucs4xstring(from, 50)));
+
+ mapper = idn_resconf_getmapper(ctx);
+ if (mapper == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+ to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */
+
+ for (;;) {
+ unsigned long *new_buffer;
+
+ new_buffer = (unsigned long *)
+ realloc(to, sizeof(long) * to_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ to = new_buffer;
+ r = idn_mapper_map(mapper, from, to, to_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+ to_length *= 2;
+ }
+
+ r = labellist_setname(label, to);
+ret:
+ if (r == idn_success) {
+ TRACE(("res map(): success (label=\"%s\")\n",
+ idn__debug_ucs4xstring(labellist_getname(label),
+ 50)));
+ } else {
+ TRACE(("res map(): %s\n", idn_result_tostring(r)));
+ }
+ if (mapper != NULL)
+ idn_mapper_destroy(mapper);
+ free(to);
+ return (r);
+}
+
+static idn_result_t
+label_normalize(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *from;
+ unsigned long *to = NULL;
+ size_t to_length;
+ idn_normalizer_t normalizer;
+ idn_result_t r;
+
+ from = labellist_getname(label);
+ TRACE(("res normalzie(label=\"%s\")\n",
+ idn__debug_ucs4xstring(from, 50)));
+
+ normalizer = idn_resconf_getnormalizer(ctx);
+ if (normalizer == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+ to_length = idn_ucs4_strlen(from) + 1 + 15; /* 15 for margin */
+
+ for (;;) {
+ unsigned long *new_buffer;
+
+ new_buffer = (unsigned long *)
+ realloc(to, sizeof(long) * to_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ to = new_buffer;
+ r = idn_normalizer_normalize(normalizer, from, to, to_length);
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+ to_length *= 2;
+ }
+
+ r = labellist_setname(label, to);
+ret:
+ if (r == idn_success) {
+ TRACE(("res normalize(): success (label=\"%s\")\n",
+ idn__debug_ucs4xstring(labellist_getname(label),
+ 50)));
+ } else {
+ TRACE(("res normalize(): %s\n", idn_result_tostring(r)));
+ }
+ if (normalizer != NULL)
+ idn_normalizer_destroy(normalizer);
+ free(to);
+ return (r);
+}
+
+static idn_result_t
+label_prohcheck(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *name, *found;
+ idn_checker_t prohibit_checker;
+ idn_result_t r;
+
+ name = labellist_getname(label);
+ TRACE(("res prohcheck(label=\"%s\")\n",
+ idn__debug_ucs4xstring(name, 50)));
+
+ prohibit_checker = idn_resconf_getprohibitchecker(ctx);
+ if (prohibit_checker == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+
+ r = idn_checker_lookup(prohibit_checker, name, &found);
+ idn_checker_destroy(prohibit_checker);
+ if (r == idn_success && found != NULL)
+ r = idn_prohibited;
+
+ret:
+ TRACE(("res prohcheck(): %s\n", idn_result_tostring(r)));
+ return (r);
+}
+
+static idn_result_t
+label_unascheck(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *name, *found;
+ idn_checker_t unassigned_checker;
+ idn_result_t r;
+
+ name = labellist_getname(label);
+ TRACE(("res unascheck(label=\"%s\")\n",
+ idn__debug_ucs4xstring(name, 50)));
+
+ unassigned_checker = idn_resconf_getunassignedchecker(ctx);
+ if (unassigned_checker == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+
+ r = idn_checker_lookup(unassigned_checker, name, &found);
+ idn_checker_destroy(unassigned_checker);
+ if (r == idn_success && found != NULL)
+ r = idn_prohibited;
+
+ret:
+ TRACE(("res unascheck(): %s\n", idn_result_tostring(r)));
+ return (r);
+}
+
+static idn_result_t
+label_bidicheck(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *name, *found;
+ idn_checker_t bidi_checker;
+ idn_result_t r;
+
+ name = labellist_getname(label);
+ TRACE(("res bidicheck(label=\"%s\")\n",
+ idn__debug_ucs4xstring(name, 50)));
+
+ bidi_checker = idn_resconf_getbidichecker(ctx);
+ if (bidi_checker == NULL) {
+ r = idn_success;
+ goto ret;
+ }
+
+ r = idn_checker_lookup(bidi_checker, name, &found);
+ idn_checker_destroy(bidi_checker);
+ if (r == idn_success && found != NULL)
+ r = idn_prohibited;
+
+ret:
+ TRACE(("res bidicheck(): %s\n", idn_result_tostring(r)));
+ return (r);
+}
+
+static idn_result_t
+label_asccheck(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *name, *n;
+ idn_result_t r;
+
+ name = labellist_getname(label);
+ TRACE(("res asccheck(label=\"%s\")\n",
+ idn__debug_ucs4xstring(name, 50)));
+
+ if (*name == '-') {
+ r = idn_prohibited;
+ goto ret;
+ }
+
+ for (n = name; *n != '\0'; n++) {
+ if (*n <= '\177') {
+ if ((*n < '0' || *n > '9') &&
+ (*n < 'A' || *n > 'Z') &&
+ (*n < 'a' || *n > 'z') &&
+ *n != '-') {
+ r = idn_prohibited;
+ goto ret;
+ }
+ }
+ }
+
+ if (n > name && *(n - 1) == '-') {
+ r = idn_prohibited;
+ goto ret;
+ }
+
+ r = idn_success;
+ret:
+ TRACE(("res asccheck(): %s\n", idn_result_tostring(r)));
+ return (r);
+}
+
+static idn_result_t
+label_lencheck_ace(idn_resconf_t ctx, labellist_t label) {
+ const unsigned long *name;
+ size_t name_length;
+ idn_result_t r;
+
+ name = labellist_getname(label);
+ name_length = idn_ucs4_strlen(name);
+ TRACE(("res lencheck(label=\"%s\")\n",
+ idn__debug_ucs4xstring(name, 50)));
+
+ if (name_length == 0 || name_length > MAX_LABEL_LENGTH) {
+ r = idn_invalid_length;
+ goto ret;
+ }
+
+ r = idn_success;
+ret:
+ TRACE(("res lencheck(): %s\n", idn_result_tostring(r)));
+ return (r);
+}
+
+static idn_result_t
+label_lencheck_nonace(idn_resconf_t ctx, labellist_t label) {
+ idn_converter_t idn_converter;
+ const unsigned long *from;
+ size_t to_length;
+ idn_result_t r;
+ char *buffer = NULL;
+ size_t buffer_length;
+
+ from = labellist_getname(label);
+ TRACE(("res lencheck(label=\"%s\")\n",
+ idn__debug_ucs4xstring(from, 50)));
+
+ buffer_length = idn_ucs4_strlen(from) * 4 + 16; /* 16 for margin */
+ idn_converter = idn_resconf_getidnconverter(ctx);
+
+ for (;;) {
+ void *new_buffer;
+
+ new_buffer = realloc(buffer, sizeof(*buffer) * buffer_length);
+ if (new_buffer == NULL) {
+ r = idn_nomemory;
+ goto ret;
+ }
+ buffer = (char *)new_buffer;
+
+ if (idn_converter != NULL) {
+ r = idn_converter_convfromucs4(idn_converter, from,
+ buffer, buffer_length);
+ } else {
+ r = idn_ucs4_ucs4toutf8(from, buffer, buffer_length);
+ }
+ if (r == idn_success)
+ break;
+ else if (r != idn_buffer_overflow)
+ goto ret;
+
+ buffer_length *= 2;
+ }
+
+ to_length = strlen(buffer);
+ if (to_length == 0 || to_length > MAX_LABEL_LENGTH) {
+ r = idn_invalid_length;
+ goto ret;
+ }
+
+ r = idn_success;
+ret:
+ TRACE(("res lencheck(): %s\n", idn_result_tostring(r)));
+ if (idn_converter != NULL)
+ idn_converter_destroy(idn_converter);
+ free(buffer);
+ return (r);
+}
+
+static idn_result_t
+label_rtcheck(idn_resconf_t ctx, idn_action_t actions, labellist_t label,
+ const unsigned long *original_name) {
+ labellist_t rt_label = NULL;
+ const unsigned long *rt_name;
+ const unsigned long *cur_name;
+ idn_result_t r;
+
+ cur_name = labellist_getname(label);
+ TRACE(("res rtcheck(label=\"%s\", org_label=\"%s\")\n",
+ idn__debug_ucs4xstring(cur_name, 50),
+ idn__debug_ucs4xstring(original_name, 50)));
+
+ r = labellist_create(cur_name, &rt_label);
+ if (r != idn_success)
+ goto ret;
+ if (rt_label == NULL) {
+ if (*original_name == '\0')
+ r = idn_success;
+ else
+ r = idn_invalid_encoding;
+ goto ret;
+ }
+
+ if (!idn__util_ucs4isasciirange(labellist_getname(rt_label))) {
+ r = label_map(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ r = label_normalize(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ r = label_prohcheck(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ if (actions & IDN_UNASCHECK) {
+ r = label_unascheck(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ }
+ r = label_bidicheck(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ }
+
+ if (actions & IDN_ASCCHECK) {
+ r = label_asccheck(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ }
+ if (!idn__util_ucs4isasciirange(labellist_getname(rt_label))) {
+ r = label_idnencode_ace(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ }
+ r = label_lencheck_ace(ctx, rt_label);
+ if (r != idn_success)
+ goto ret;
+ rt_name = labellist_getname(rt_label);
+
+ if (idn_ucs4_strcasecmp(rt_name, original_name) != 0) {
+ TRACE(("res rtcheck(): round trip failed, org =\"%s\", rt=\"%s\"\n",
+ idn__debug_ucs4xstring(original_name, 50),
+ idn__debug_ucs4xstring(rt_name, 50)));
+ r = idn_invalid_encoding;
+ goto ret;
+ }
+
+ r = idn_success;
+ret:
+ if (r != idn_nomemory && r != idn_success)
+ r = idn_invalid_encoding;
+ TRACE(("res rtcheck(): %s\n", idn_result_tostring(r)));
+ if (rt_label != NULL)
+ labellist_destroy(rt_label);
+ return (r);
+}
+
+const char *
+idn__res_actionstostring(idn_action_t actions) {
+ static char buf[100];
+
+ buf[0] = '\0';
+
+ if (actions == IDN_ENCODE_QUERY)
+ strcpy(buf, "encode-query");
+ else if (actions == IDN_DECODE_QUERY)
+ strcpy(buf, "decode-query");
+ else if (actions == IDN_ENCODE_APP)
+ strcpy(buf, "encode-app");
+ else if (actions == IDN_DECODE_APP)
+ strcpy(buf, "decode-app");
+ else if (actions == IDN_ENCODE_STORED)
+ strcpy(buf, "encode-stored");
+ else if (actions == IDN_DECODE_STORED)
+ strcpy(buf, "decode-stored");
+ else {
+ if (actions & IDN_LOCALCONV)
+ strcat(buf, "|localconv");
+ if (actions & IDN_DELIMMAP)
+ strcat(buf, "|delimmap");
+ if (actions & IDN_LOCALMAP)
+ strcat(buf, "|localmap");
+
+ if (actions & IDN_MAP)
+ strcat(buf, "|map");
+ if (actions & IDN_NORMALIZE)
+ strcat(buf, "|normalize");
+ if (actions & IDN_PROHCHECK)
+ strcat(buf, "|prohcheck");
+ if (actions & IDN_UNASCHECK)
+ strcat(buf, "|unascheck");
+ if (actions & IDN_BIDICHECK)
+ strcat(buf, "|bidicheck");
+
+ if (actions & IDN_IDNCONV)
+ strcat(buf, "|idnconv");
+ if (actions & IDN_ASCCHECK)
+ strcat(buf, "|asccheck");
+ if (actions & IDN_LENCHECK)
+ strcat(buf, "|lencheck");
+ if (actions & IDN_RTCHECK)
+ strcat(buf, "|rtcheck");
+ }
+
+ if (buf[0] == '|')
+ return (buf + 1);
+ else
+ return (buf);
+}