1 /* $NetBSD: delimitermap.c,v 1.4 2014/12/10 04:37:55 christos Exp $ */ 2 3 #ifndef lint 4 static char *rcsid = "Id: delimitermap.c,v 1.1 2003/06/04 00:25:52 marka Exp "; 5 #endif 6 7 /* 8 * Copyright (c) 2001,2002 Japan Network Information Center. 9 * All rights reserved. 10 * 11 * By using this file, you agree to the terms and conditions set forth bellow. 12 * 13 * LICENSE TERMS AND CONDITIONS 14 * 15 * The following License Terms and Conditions apply, unless a different 16 * license is obtained from Japan Network Information Center ("JPNIC"), 17 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, 18 * Chiyoda-ku, Tokyo 101-0047, Japan. 19 * 20 * 1. Use, Modification and Redistribution (including distribution of any 21 * modified or derived work) in source and/or binary forms is permitted 22 * under this License Terms and Conditions. 23 * 24 * 2. Redistribution of source code must retain the copyright notices as they 25 * appear in each source code file, this License Terms and Conditions. 26 * 27 * 3. Redistribution in binary form must reproduce the Copyright Notice, 28 * this License Terms and Conditions, in the documentation and/or other 29 * materials provided with the distribution. For the purposes of binary 30 * distribution the "Copyright Notice" refers to the following language: 31 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." 32 * 33 * 4. The name of JPNIC may not be used to endorse or promote products 34 * derived from this Software without specific prior written approval of 35 * JPNIC. 36 * 37 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC 38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 40 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE 41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 42 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 43 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 45 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 46 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 47 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 48 */ 49 50 #include <config.h> 51 52 #include <stddef.h> 53 #include <stdlib.h> 54 #include <string.h> 55 56 #include <idn/result.h> 57 #include <idn/assert.h> 58 #include <idn/logmacro.h> 59 #include <idn/delimitermap.h> 60 #include <idn/util.h> 61 #include <idn/debug.h> 62 #include <idn/ucs4.h> 63 64 /* 65 * Mapper object type. 66 */ 67 struct idn_delimitermap { 68 int ndelimiters; 69 int delimiter_size; 70 unsigned long *delimiters; 71 int reference_count; 72 }; 73 74 #define DELIMITERMAP_INITIAL_DELIMITER_SIZE 4 75 #define UNICODE_MAX 0x10ffff 76 #define IS_SURROGATE_HIGH(v) (0xd800 <= (v) && (v) <= 0xdbff) 77 #define IS_SURROGATE_LOW(v) (0xdc00 <= (v) && (v) <= 0xdfff) 78 79 idn_result_t 80 idn_delimitermap_create(idn_delimitermap_t *ctxp) { 81 idn_delimitermap_t ctx = NULL; 82 idn_result_t r; 83 84 assert(ctxp != NULL); 85 TRACE(("idn_delimitermap_create()\n")); 86 87 ctx = (idn_delimitermap_t) malloc(sizeof(struct idn_delimitermap)); 88 if (ctx == NULL) { 89 WARNING(("idn_mapper_create: malloc failed\n")); 90 r = idn_nomemory; 91 goto ret; 92 } 93 94 ctx->delimiters = (unsigned long *) malloc(sizeof(unsigned long) 95 * DELIMITERMAP_INITIAL_DELIMITER_SIZE); 96 if (ctx->delimiters == NULL) { 97 r = idn_nomemory; 98 goto ret; 99 } 100 ctx->ndelimiters = 0; 101 ctx->delimiter_size = DELIMITERMAP_INITIAL_DELIMITER_SIZE; 102 ctx->reference_count = 1; 103 *ctxp = ctx; 104 r = idn_success; 105 106 ret: 107 if (r != idn_success) 108 free(ctx); 109 TRACE(("idn_delimitermap_create(): %s\n", idn_result_tostring(r))); 110 return (r); 111 } 112 113 void 114 idn_delimitermap_destroy(idn_delimitermap_t ctx) { 115 assert(ctx != NULL); 116 117 TRACE(("idn_delimitermap_destroy()\n")); 118 119 ctx->reference_count--; 120 if (ctx->reference_count <= 0) { 121 TRACE(("idn_mapper_destroy(): the object is destroyed\n")); 122 free(ctx->delimiters); 123 free(ctx); 124 } else { 125 TRACE(("idn_delimitermap_destroy(): " 126 "update reference count (%d->%d)\n", 127 ctx->reference_count + 1, ctx->reference_count)); 128 } 129 } 130 131 void 132 idn_delimitermap_incrref(idn_delimitermap_t ctx) { 133 assert(ctx != NULL); 134 135 TRACE(("idn_delimitermap_incrref()\n")); 136 TRACE(("idn_delimitermap_incrref: update reference count (%d->%d)\n", 137 ctx->reference_count, ctx->reference_count + 1)); 138 139 ctx->reference_count++; 140 } 141 142 idn_result_t 143 idn_delimitermap_add(idn_delimitermap_t ctx, unsigned long delimiter) { 144 idn_result_t r; 145 146 assert(ctx != NULL && ctx->ndelimiters <= ctx->delimiter_size); 147 TRACE(("idn_delimitermap_add(delimiter=\\x%04lx)\n", delimiter)); 148 149 if (delimiter == 0 || delimiter > UNICODE_MAX || 150 IS_SURROGATE_HIGH(delimiter) || IS_SURROGATE_LOW(delimiter)) { 151 r = idn_invalid_codepoint; 152 goto ret; 153 } 154 155 if (ctx->ndelimiters == ctx->delimiter_size) { 156 unsigned long *new_delimiters; 157 158 new_delimiters = (unsigned long *) realloc(ctx->delimiters, 159 sizeof(unsigned long) * ctx->delimiter_size * 2); 160 if (new_delimiters == NULL) { 161 r = idn_nomemory; 162 goto ret; 163 } 164 ctx->delimiters = new_delimiters; 165 ctx->delimiter_size *= 2; 166 } 167 168 ctx->delimiters[ctx->ndelimiters] = delimiter; 169 ctx->ndelimiters++; 170 r = idn_success; 171 172 ret: 173 TRACE(("idn_delimitermap_add(): %s\n", idn_result_tostring(r))); 174 return (r); 175 } 176 177 idn_result_t 178 idn_delimitermap_addall(idn_delimitermap_t ctx, unsigned long *delimiters, 179 int ndelimiters) { 180 idn_result_t r; 181 int i; 182 183 assert(ctx != NULL && delimiters != NULL); 184 185 TRACE(("idn_delimitermap_addall(ndelimiters=%d)\n", ndelimiters)); 186 187 for (i = 0; i < ndelimiters; i++) { 188 r = idn_delimitermap_add(ctx, *delimiters); 189 if (r != idn_success) 190 goto ret; 191 delimiters++; 192 } 193 194 r = idn_success; 195 ret: 196 TRACE(("idn_delimitermap_addall(): %s\n", idn_result_tostring(r))); 197 return (r); 198 } 199 200 idn_result_t 201 idn_delimitermap_map(idn_delimitermap_t ctx, const unsigned long *from, 202 unsigned long *to, size_t tolen) { 203 204 /* default delimiters (label separators) from IDNA specification */ 205 static const unsigned long default_delimiters[] = 206 { 0x002e, /* full stop */ 207 0x3002, /* ideographic full stop */ 208 0xff0e, /* fullwidth full stop */ 209 0xff61, /* halfwidth ideographic full stop */ 210 0x0000 }; 211 212 unsigned long *to_org = to; 213 idn_result_t r; 214 int i, j; 215 int found; 216 217 assert(ctx != NULL && from != NULL && to != NULL); 218 219 TRACE(("idn_delimitermap_map(from=\"%s\", tolen=%d)\n", 220 idn__debug_ucs4xstring(from, 50), (int)tolen)); 221 222 /* 223 * Map. 224 */ 225 while (*from != '\0') { 226 found = 0; 227 if (tolen < 1) { 228 r = idn_buffer_overflow; 229 goto ret; 230 } 231 for (j = 0; default_delimiters[j] != 0x0000; j++) { 232 if (default_delimiters[j] == *from) { 233 found = 1; 234 break; 235 } 236 } 237 if (!found) { 238 for (i = 0; i < ctx->ndelimiters; i++) { 239 if (ctx->delimiters[i] == *from) { 240 found = 1; 241 break; 242 } 243 } 244 } 245 if (found) 246 *to = '.'; 247 else 248 *to = *from; 249 from++; 250 to++; 251 tolen--; 252 } 253 254 if (tolen < 1) { 255 r = idn_buffer_overflow; 256 goto ret; 257 } 258 *to = '\0'; 259 r = idn_success; 260 261 ret: 262 if (r == idn_success) { 263 TRACE(("idn_delimitermap_map(): success (to=\"%s\")\n", 264 idn__debug_ucs4xstring(to_org, 50))); 265 } else { 266 TRACE(("idn_delimitermap_map(): %s\n", 267 idn_result_tostring(r))); 268 } 269 return (r); 270 } 271