michael@0: /* michael@0: * Copyright (c) 2001,2002 Japan Network Information Center. michael@0: * All rights reserved. michael@0: * michael@0: * By using this file, you agree to the terms and conditions set forth bellow. michael@0: * michael@0: * LICENSE TERMS AND CONDITIONS michael@0: * michael@0: * The following License Terms and Conditions apply, unless a different michael@0: * license is obtained from Japan Network Information Center ("JPNIC"), michael@0: * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, michael@0: * Chiyoda-ku, Tokyo 101-0047, Japan. michael@0: * michael@0: * 1. Use, Modification and Redistribution (including distribution of any michael@0: * modified or derived work) in source and/or binary forms is permitted michael@0: * under this License Terms and Conditions. michael@0: * michael@0: * 2. Redistribution of source code must retain the copyright notices as they michael@0: * appear in each source code file, this License Terms and Conditions. michael@0: * michael@0: * 3. Redistribution in binary form must reproduce the Copyright Notice, michael@0: * this License Terms and Conditions, in the documentation and/or other michael@0: * materials provided with the distribution. For the purposes of binary michael@0: * distribution the "Copyright Notice" refers to the following language: michael@0: * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." michael@0: * michael@0: * 4. The name of JPNIC may not be used to endorse or promote products michael@0: * derived from this Software without specific prior written approval of michael@0: * JPNIC. michael@0: * michael@0: * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC michael@0: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A michael@0: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE michael@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR michael@0: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF michael@0: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR michael@0: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, michael@0: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR michael@0: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF michael@0: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. michael@0: */ michael@0: michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "nsIDNKitInterface.h" michael@0: michael@0: #define UCS_MAX 0x7fffffff michael@0: #define UNICODE_MAX 0x10ffff michael@0: michael@0: michael@0: /* michael@0: * Load NAMEPREP compiled tables. michael@0: */ michael@0: #include "nameprepdata.c" michael@0: michael@0: /* michael@0: * Define mapping/checking functions for each version of the draft. michael@0: */ michael@0: michael@0: #define VERSION id11 michael@0: #include "nameprep_template.c" michael@0: #undef VERSION michael@0: michael@0: typedef const char *(*nameprep_mapproc)(uint32_t v); michael@0: typedef int (*nameprep_checkproc)(uint32_t v); michael@0: typedef idn_biditype_t (*nameprep_biditypeproc)(uint32_t v); michael@0: michael@0: static struct idn_nameprep { michael@0: char *version; michael@0: nameprep_mapproc map_proc; michael@0: nameprep_checkproc prohibited_proc; michael@0: nameprep_checkproc unassigned_proc; michael@0: nameprep_biditypeproc biditype_proc; michael@0: } nameprep_versions[] = { michael@0: #define MAKE_NAMEPREP_HANDLE(version, id) \ michael@0: { version, \ michael@0: compose_sym2(nameprep_map_, id), \ michael@0: compose_sym2(nameprep_prohibited_, id), \ michael@0: compose_sym2(nameprep_unassigned_, id), \ michael@0: compose_sym2(nameprep_biditype_, id), } michael@0: MAKE_NAMEPREP_HANDLE("nameprep-11", id11), michael@0: { NULL, NULL, NULL, NULL, NULL }, michael@0: }; michael@0: michael@0: static idn_result_t idn_nameprep_check(nameprep_checkproc proc, michael@0: const uint32_t *str, michael@0: const uint32_t **found); michael@0: michael@0: idn_result_t michael@0: idn_nameprep_create(const char *version, idn_nameprep_t *handlep) { michael@0: idn_nameprep_t handle; michael@0: michael@0: assert(handlep != NULL); michael@0: michael@0: TRACE(("idn_nameprep_create(version=%-.50s)\n", michael@0: version == NULL ? "" : version)); michael@0: michael@0: if (version == NULL) michael@0: version = IDN_NAMEPREP_CURRENT; michael@0: michael@0: /* michael@0: * Lookup table for the specified version. Since the number of michael@0: * versions won't be large (I don't want see draft-23 or such :-), michael@0: * simple linear search is OK. michael@0: */ michael@0: for (handle = nameprep_versions; handle->version != NULL; handle++) { michael@0: if (strcmp(handle->version, version) == 0) { michael@0: *handlep = handle; michael@0: return (idn_success); michael@0: } michael@0: } michael@0: return (idn_notfound); michael@0: } michael@0: michael@0: void michael@0: idn_nameprep_destroy(idn_nameprep_t handle) { michael@0: assert(handle != NULL); michael@0: michael@0: TRACE(("idn_nameprep_destroy()\n")); michael@0: michael@0: /* Nothing to do. */ michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_map(idn_nameprep_t handle, const uint32_t *from, michael@0: uint32_t *to, size_t tolen) { michael@0: assert(handle != NULL && from != NULL && to != NULL); michael@0: michael@0: TRACE(("idn_nameprep_map(ctx=%s, from=\"%s\")\n", michael@0: handle->version, idn__debug_ucs4xstring(from, 50))); michael@0: michael@0: while (*from != '\0') { michael@0: uint32_t v = *from; michael@0: const char *mapped; michael@0: michael@0: if (v > UCS_MAX) { michael@0: /* This cannot happen, but just in case.. */ michael@0: return (idn_invalid_codepoint); michael@0: } else if (v > UNICODE_MAX) { michael@0: /* No mapping is possible. */ michael@0: mapped = NULL; michael@0: } else { michael@0: /* Try mapping. */ michael@0: mapped = (*handle->map_proc)(v); michael@0: } michael@0: michael@0: if (mapped == NULL) { michael@0: /* No mapping. Just copy verbatim. */ michael@0: if (tolen < 1) michael@0: return (idn_buffer_overflow); michael@0: *to++ = v; michael@0: tolen--; michael@0: } else { michael@0: const unsigned char *mappeddata; michael@0: size_t mappedlen; michael@0: michael@0: mappeddata = (const unsigned char *)mapped + 1; michael@0: mappedlen = *mapped; michael@0: michael@0: if (tolen < (mappedlen + 3) / 4) michael@0: return (idn_buffer_overflow); michael@0: tolen -= (mappedlen + 3) / 4; michael@0: while (mappedlen >= 4) { michael@0: *to = *mappeddata++; michael@0: *to |= *mappeddata++ << 8; michael@0: *to |= *mappeddata++ << 16; michael@0: *to |= *mappeddata++ << 24; michael@0: mappedlen -= 4; michael@0: to++; michael@0: } michael@0: if (mappedlen > 0) { michael@0: *to = *mappeddata++; michael@0: *to |= (mappedlen >= 2) ? michael@0: *mappeddata++ << 8: 0; michael@0: *to |= (mappedlen >= 3) ? michael@0: *mappeddata++ << 16: 0; michael@0: to++; michael@0: } michael@0: } michael@0: from++; michael@0: } michael@0: if (tolen == 0) michael@0: return (idn_buffer_overflow); michael@0: *to = '\0'; michael@0: return (idn_success); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_isprohibited(idn_nameprep_t handle, const uint32_t *str, michael@0: const uint32_t **found) { michael@0: assert(handle != NULL && str != NULL && found != NULL); michael@0: michael@0: TRACE(("idn_nameprep_isprohibited(ctx=%s, str=\"%s\")\n", michael@0: handle->version, idn__debug_ucs4xstring(str, 50))); michael@0: michael@0: return (idn_nameprep_check(handle->prohibited_proc, str, found)); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_isunassigned(idn_nameprep_t handle, const uint32_t *str, michael@0: const uint32_t **found) { michael@0: assert(handle != NULL && str != NULL && found != NULL); michael@0: michael@0: TRACE(("idn_nameprep_isunassigned(handle->version, str=\"%s\")\n", michael@0: handle->version, idn__debug_ucs4xstring(str, 50))); michael@0: michael@0: return (idn_nameprep_check(handle->unassigned_proc, str, found)); michael@0: } michael@0: michael@0: static idn_result_t michael@0: idn_nameprep_check(nameprep_checkproc proc, const uint32_t *str, michael@0: const uint32_t **found) { michael@0: uint32_t v; michael@0: michael@0: while (*str != '\0') { michael@0: v = *str; michael@0: michael@0: if (v > UCS_MAX) { michael@0: /* This cannot happen, but just in case.. */ michael@0: return (idn_invalid_codepoint); michael@0: } else if (v > UNICODE_MAX) { michael@0: /* It is invalid.. */ michael@0: *found = str; michael@0: return (idn_success); michael@0: } else if ((*proc)(v)) { michael@0: *found = str; michael@0: return (idn_success); michael@0: } michael@0: str++; michael@0: } michael@0: *found = NULL; michael@0: return (idn_success); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_isvalidbidi(idn_nameprep_t handle, const uint32_t *str, michael@0: const uint32_t **found) { michael@0: uint32_t v; michael@0: idn_biditype_t first_char; michael@0: idn_biditype_t last_char; michael@0: int found_r_al; michael@0: michael@0: assert(handle != NULL && str != NULL && found != NULL); michael@0: michael@0: TRACE(("idn_nameprep_isvalidbidi(ctx=%s, str=\"%s\")\n", michael@0: handle->version, idn__debug_ucs4xstring(str, 50))); michael@0: michael@0: if (*str == '\0') { michael@0: *found = NULL; michael@0: return (idn_success); michael@0: } michael@0: michael@0: /* michael@0: * check first character's type and initialize variables. michael@0: */ michael@0: found_r_al = 0; michael@0: if (*str > UCS_MAX) { michael@0: /* This cannot happen, but just in case.. */ michael@0: return (idn_invalid_codepoint); michael@0: } else if (*str > UNICODE_MAX) { michael@0: /* It is invalid.. */ michael@0: *found = str; michael@0: return (idn_success); michael@0: } michael@0: first_char = last_char = (*(handle->biditype_proc))(*str); michael@0: if (first_char == idn_biditype_r_al) { michael@0: found_r_al = 1; michael@0: } michael@0: str++; michael@0: michael@0: /* michael@0: * see whether string is valid or not. michael@0: */ michael@0: while (*str != '\0') { michael@0: v = *str; michael@0: michael@0: if (v > UCS_MAX) { michael@0: /* This cannot happen, but just in case.. */ michael@0: return (idn_invalid_codepoint); michael@0: } else if (v > UNICODE_MAX) { michael@0: /* It is invalid.. */ michael@0: *found = str; michael@0: return (idn_success); michael@0: } else { michael@0: last_char = (*(handle->biditype_proc))(v); michael@0: if (found_r_al && last_char == idn_biditype_l) { michael@0: *found = str; michael@0: return (idn_success); michael@0: } michael@0: if (first_char != idn_biditype_r_al && last_char == idn_biditype_r_al) { michael@0: *found = str; michael@0: return (idn_success); michael@0: } michael@0: if (last_char == idn_biditype_r_al) { michael@0: found_r_al = 1; michael@0: } michael@0: } michael@0: str++; michael@0: } michael@0: michael@0: if (found_r_al) { michael@0: if (last_char != idn_biditype_r_al) { michael@0: *found = str - 1; michael@0: return (idn_success); michael@0: } michael@0: } michael@0: michael@0: *found = NULL; michael@0: return (idn_success); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_createproc(const char *parameter, void **handlep) { michael@0: return idn_nameprep_create(parameter, (idn_nameprep_t *)handlep); michael@0: } michael@0: michael@0: void michael@0: idn_nameprep_destroyproc(void *handle) { michael@0: idn_nameprep_destroy((idn_nameprep_t)handle); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_mapproc(void *handle, const uint32_t *from, michael@0: uint32_t *to, size_t tolen) { michael@0: return idn_nameprep_map((idn_nameprep_t)handle, from, to, tolen); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_prohibitproc(void *handle, const uint32_t *str, michael@0: const uint32_t **found) { michael@0: return idn_nameprep_isprohibited((idn_nameprep_t)handle, str, found); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_unassignedproc(void *handle, const uint32_t *str, michael@0: const uint32_t **found) { michael@0: return idn_nameprep_isunassigned((idn_nameprep_t)handle, str, found); michael@0: } michael@0: michael@0: idn_result_t michael@0: idn_nameprep_bidiproc(void *handle, const uint32_t *str, michael@0: const uint32_t **found) { michael@0: return idn_nameprep_isvalidbidi((idn_nameprep_t)handle, str, found); michael@0: }