Back to index

lightning-sunbird  0.9+nobinonly
nameprep.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001,2002 Japan Network Information Center.
00003  * All rights reserved.
00004  *  
00005  * By using this file, you agree to the terms and conditions set forth bellow.
00006  * 
00007  *                   LICENSE TERMS AND CONDITIONS 
00008  * 
00009  * The following License Terms and Conditions apply, unless a different
00010  * license is obtained from Japan Network Information Center ("JPNIC"),
00011  * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
00012  * Chiyoda-ku, Tokyo 101-0047, Japan.
00013  * 
00014  * 1. Use, Modification and Redistribution (including distribution of any
00015  *    modified or derived work) in source and/or binary forms is permitted
00016  *    under this License Terms and Conditions.
00017  * 
00018  * 2. Redistribution of source code must retain the copyright notices as they
00019  *    appear in each source code file, this License Terms and Conditions.
00020  * 
00021  * 3. Redistribution in binary form must reproduce the Copyright Notice,
00022  *    this License Terms and Conditions, in the documentation and/or other
00023  *    materials provided with the distribution.  For the purposes of binary
00024  *    distribution the "Copyright Notice" refers to the following language:
00025  *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
00026  * 
00027  * 4. The name of JPNIC may not be used to endorse or promote products
00028  *    derived from this Software without specific prior written approval of
00029  *    JPNIC.
00030  * 
00031  * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
00032  *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00033  *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00034  *    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
00035  *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00036  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00037  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00038  *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00039  *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00040  *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00041  *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
00042  */
00043 
00044 
00045 #include <stdlib.h>
00046 #include <string.h>
00047 
00048 #include "nsIDNKitInterface.h"
00049 
00050 #define UCS_MAX             0x7fffffff
00051 #define UNICODE_MAX  0x10ffff
00052 
00053 
00054 /*
00055  * Load NAMEPREP compiled tables.
00056  */
00057 #include "nameprepdata.c"
00058 
00059 /*
00060  * Define mapping/checking functions for each version of the draft.
00061  */
00062 
00063 #define VERSION id11
00064 #include "nameprep_template.c"
00065 #undef VERSION
00066 
00067 typedef const char   *(*nameprep_mapproc)(PRUint32 v);
00068 typedef int          (*nameprep_checkproc)(PRUint32 v);
00069 typedef idn_biditype_t      (*nameprep_biditypeproc)(PRUint32 v);
00070 
00071 static struct idn_nameprep {
00072        char *version;
00073        nameprep_mapproc map_proc;
00074        nameprep_checkproc prohibited_proc;
00075        nameprep_checkproc unassigned_proc;
00076        nameprep_biditypeproc biditype_proc;
00077 } nameprep_versions[] = {
00078 #define MAKE_NAMEPREP_HANDLE(version, id) \
00079        { version, \
00080          compose_sym2(nameprep_map_, id), \
00081          compose_sym2(nameprep_prohibited_, id), \
00082          compose_sym2(nameprep_unassigned_, id), \
00083          compose_sym2(nameprep_biditype_, id), }
00084        MAKE_NAMEPREP_HANDLE("nameprep-11", id11),
00085        { NULL, NULL, NULL, NULL, NULL },
00086 };
00087 
00088 static idn_result_t  idn_nameprep_check(nameprep_checkproc proc,
00089                                       const PRUint32 *str,
00090                                       const PRUint32 **found);
00091 
00092 idn_result_t
00093 idn_nameprep_create(const char *version, idn_nameprep_t *handlep) {
00094        idn_nameprep_t handle;
00095 
00096        assert(handlep != NULL);
00097 
00098        TRACE(("idn_nameprep_create(version=%-.50s)\n",
00099               version == NULL ? "<NULL>" : version));
00100 
00101        if (version == NULL)
00102               version = IDN_NAMEPREP_CURRENT;
00103 
00104        /*
00105         * Lookup table for the specified version.  Since the number of
00106         * versions won't be large (I don't want see draft-23 or such :-),
00107         * simple linear search is OK.
00108         */
00109        for (handle = nameprep_versions; handle->version != NULL; handle++) {
00110               if (strcmp(handle->version, version) == 0) {
00111                      *handlep = handle;
00112                      return (idn_success);
00113               }
00114        }
00115        return (idn_notfound);
00116 }
00117 
00118 void
00119 idn_nameprep_destroy(idn_nameprep_t handle) {
00120        assert(handle != NULL);
00121 
00122        TRACE(("idn_nameprep_destroy()\n"));
00123 
00124        /* Nothing to do. */
00125 }
00126 
00127 idn_result_t
00128 idn_nameprep_map(idn_nameprep_t handle, const PRUint32 *from,
00129                PRUint32 *to, size_t tolen) {
00130        assert(handle != NULL && from != NULL && to != NULL);
00131 
00132        TRACE(("idn_nameprep_map(ctx=%s, from=\"%s\")\n",
00133               handle->version, idn__debug_ucs4xstring(from, 50)));
00134 
00135        while (*from != '\0') {
00136               PRUint32 v = *from;
00137               const char *mapped;
00138 
00139               if (v > UCS_MAX) {
00140                      /* This cannot happen, but just in case.. */
00141                      return (idn_invalid_codepoint);
00142               } else if (v > UNICODE_MAX) {
00143                      /* No mapping is possible. */
00144                      mapped = NULL;
00145               } else {
00146                      /* Try mapping. */
00147                      mapped = (*handle->map_proc)(v);
00148               }
00149 
00150               if (mapped == NULL) {
00151                      /* No mapping. Just copy verbatim. */
00152                      if (tolen < 1)
00153                             return (idn_buffer_overflow);
00154                      *to++ = v;
00155                      tolen--;
00156               } else {
00157                      const unsigned char *mappeddata;
00158                      size_t mappedlen;
00159 
00160                      mappeddata = (const unsigned char *)mapped + 1;
00161                      mappedlen = *mapped;
00162 
00163                      if (tolen < (mappedlen + 3) / 4)
00164                             return (idn_buffer_overflow);
00165                      tolen -= (mappedlen + 3) / 4;
00166                      while (mappedlen >= 4) {
00167                             *to  = *mappeddata++;
00168                             *to |= *mappeddata++ <<  8;
00169                             *to |= *mappeddata++ << 16;
00170                             *to |= *mappeddata++ << 24;
00171                             mappedlen -= 4;
00172                             to++;
00173                      }
00174                      if (mappedlen > 0) {
00175                             *to  = *mappeddata++;
00176                             *to |= (mappedlen >= 2) ?
00177                                    *mappeddata++ <<  8: 0;
00178                             *to |= (mappedlen >= 3) ?
00179                                    *mappeddata++ << 16: 0;
00180                             to++;
00181                      }
00182               }
00183               from++;
00184        }
00185        if (tolen == 0)
00186               return (idn_buffer_overflow);
00187        *to = '\0';
00188        return (idn_success);
00189 }
00190 
00191 idn_result_t
00192 idn_nameprep_isprohibited(idn_nameprep_t handle, const PRUint32 *str,
00193                        const PRUint32 **found) {
00194        assert(handle != NULL && str != NULL && found != NULL);
00195 
00196        TRACE(("idn_nameprep_isprohibited(ctx=%s, str=\"%s\")\n",
00197               handle->version, idn__debug_ucs4xstring(str, 50)));
00198 
00199        return (idn_nameprep_check(handle->prohibited_proc, str, found));
00200 }
00201               
00202 idn_result_t
00203 idn_nameprep_isunassigned(idn_nameprep_t handle, const PRUint32 *str,
00204                        const PRUint32 **found) {
00205        assert(handle != NULL && str != NULL && found != NULL);
00206 
00207        TRACE(("idn_nameprep_isunassigned(handle->version, str=\"%s\")\n",
00208               handle->version, idn__debug_ucs4xstring(str, 50)));
00209 
00210        return (idn_nameprep_check(handle->unassigned_proc, str, found));
00211 }
00212               
00213 static idn_result_t
00214 idn_nameprep_check(nameprep_checkproc proc, const PRUint32 *str,
00215                  const PRUint32 **found) {
00216        PRUint32 v;
00217 
00218        while (*str != '\0') {
00219               v = *str;
00220 
00221               if (v > UCS_MAX) {
00222                      /* This cannot happen, but just in case.. */
00223                      return (idn_invalid_codepoint);
00224               } else if (v > UNICODE_MAX) {
00225                      /* It is invalid.. */
00226                      *found = str;
00227                      return (idn_success);
00228               } else if ((*proc)(v)) {
00229                      *found = str;
00230                      return (idn_success);
00231               }
00232               str++;
00233        }
00234        *found = NULL;
00235        return (idn_success);
00236 }
00237 
00238 idn_result_t
00239 idn_nameprep_isvalidbidi(idn_nameprep_t handle, const PRUint32 *str,
00240                       const PRUint32 **found) {
00241        PRUint32 v;
00242        idn_biditype_t first_char;
00243        idn_biditype_t last_char;
00244        int found_r_al;
00245 
00246        assert(handle != NULL && str != NULL && found != NULL);
00247 
00248        TRACE(("idn_nameprep_isvalidbidi(ctx=%s, str=\"%s\")\n",
00249               handle->version, idn__debug_ucs4xstring(str, 50)));
00250 
00251        if (*str == '\0') {
00252               *found = NULL;
00253               return (idn_success);
00254        }
00255 
00256        /*
00257         * check first character's type and initialize variables.
00258         */
00259        found_r_al = 0;
00260        if (*str > UCS_MAX) {
00261               /* This cannot happen, but just in case.. */
00262               return (idn_invalid_codepoint);
00263        } else if (*str > UNICODE_MAX) {
00264               /* It is invalid.. */
00265               *found = str;
00266               return (idn_success);
00267        }
00268        first_char = last_char = (*(handle->biditype_proc))(*str);
00269        if (first_char == idn_biditype_r_al) {
00270               found_r_al = 1;
00271        }
00272        str++;
00273 
00274        /*
00275         * see whether string is valid or not.
00276         */
00277        while (*str != '\0') {
00278               v = *str;
00279 
00280               if (v > UCS_MAX) {
00281                      /* This cannot happen, but just in case.. */
00282                      return (idn_invalid_codepoint);
00283               } else if (v > UNICODE_MAX) {
00284                      /* It is invalid.. */
00285                      *found = str;
00286                      return (idn_success);
00287               } else { 
00288                      last_char = (*(handle->biditype_proc))(v);
00289                      if (found_r_al && last_char == idn_biditype_l) {
00290                             *found = str;
00291                             return (idn_success);
00292                      }
00293                      if (first_char != idn_biditype_r_al && last_char == idn_biditype_r_al) {
00294                             *found = str;
00295                             return (idn_success);
00296                      }
00297                      if (last_char == idn_biditype_r_al) {
00298                             found_r_al = 1;
00299                      }
00300               }
00301               str++;
00302        }
00303 
00304        if (found_r_al) {
00305               if (last_char != idn_biditype_r_al) {
00306                      *found = str - 1;
00307                      return (idn_success);
00308               }
00309        }
00310 
00311        *found = NULL;
00312        return (idn_success);
00313 }
00314 
00315 idn_result_t
00316 idn_nameprep_createproc(const char *parameter, void **handlep) {
00317        return idn_nameprep_create(parameter, (idn_nameprep_t *)handlep);
00318 }
00319 
00320 void
00321 idn_nameprep_destroyproc(void *handle) {
00322        idn_nameprep_destroy((idn_nameprep_t)handle);
00323 }
00324 
00325 idn_result_t
00326 idn_nameprep_mapproc(void *handle, const PRUint32 *from,
00327                     PRUint32 *to, size_t tolen) {
00328        return idn_nameprep_map((idn_nameprep_t)handle, from, to, tolen);
00329 }
00330 
00331 idn_result_t
00332 idn_nameprep_prohibitproc(void *handle, const PRUint32 *str,
00333                         const PRUint32 **found) {
00334        return idn_nameprep_isprohibited((idn_nameprep_t)handle, str, found);
00335 }
00336 
00337 idn_result_t
00338 idn_nameprep_unassignedproc(void *handle, const PRUint32 *str,
00339                           const PRUint32 **found) {
00340        return idn_nameprep_isunassigned((idn_nameprep_t)handle, str, found);
00341 }
00342 
00343 idn_result_t
00344 idn_nameprep_bidiproc(void *handle, const PRUint32 *str,
00345                     const PRUint32 **found) {
00346        return idn_nameprep_isvalidbidi((idn_nameprep_t)handle, str, found);
00347 }