1 /* $NetBSD: filemapper.c,v 1.4 2014/12/10 04:37:55 christos Exp $ */ 2 3 #ifndef lint 4 static char *rcsid = "Id: filemapper.c,v 1.1 2003/06/04 00:25:53 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 <stdlib.h> 53 #include <stdio.h> 54 #include <string.h> 55 #include <ctype.h> 56 57 #include <idn/result.h> 58 #include <idn/assert.h> 59 #include <idn/log.h> 60 #include <idn/logmacro.h> 61 #include <idn/debug.h> 62 #include <idn/ucs4.h> 63 #include <idn/ucsmap.h> 64 #include <idn/filemapper.h> 65 66 #define SUPPORT_VERSIONING 67 68 #define UCSBUF_LOCAL_SIZE 20 69 70 typedef struct ucsbuf { 71 unsigned long *ucs; 72 size_t size; 73 size_t len; 74 unsigned long local[UCSBUF_LOCAL_SIZE]; 75 } ucsbuf_t; 76 77 struct idn__filemapper { 78 idn_ucsmap_t map; 79 }; 80 81 static void ucsbuf_init(ucsbuf_t *b); 82 static idn_result_t ucsbuf_grow(ucsbuf_t *b); 83 static idn_result_t ucsbuf_append(ucsbuf_t *b, unsigned long v); 84 static void ucsbuf_free(ucsbuf_t *b); 85 static idn_result_t read_file(const char *file, FILE *fp, 86 idn_ucsmap_t map); 87 static idn_result_t get_map(char *p, ucsbuf_t *b); 88 static char *get_ucs(char *p, unsigned long *vp); 89 90 91 idn_result_t 92 idn__filemapper_create(const char *file, idn__filemapper_t *ctxp) { 93 FILE *fp; 94 idn__filemapper_t ctx; 95 idn_result_t r; 96 97 assert(file != NULL && ctxp != NULL); 98 99 TRACE(("idn__filemapper_create(file=\"%-.100s\")\n", file)); 100 101 if ((fp = fopen(file, "r")) == NULL) { 102 WARNING(("idn__filemapper_create: cannot open %-.100s\n", 103 file)); 104 return (idn_nofile); 105 } 106 if ((ctx = malloc(sizeof(struct idn__filemapper))) == NULL) 107 return (idn_nomemory); 108 109 if ((r = idn_ucsmap_create(&ctx->map)) != idn_success) { 110 free(ctx); 111 return (r); 112 } 113 114 r = read_file(file, fp, ctx->map); 115 fclose(fp); 116 117 if (r == idn_success) { 118 idn_ucsmap_fix(ctx->map); 119 *ctxp = ctx; 120 } else { 121 idn_ucsmap_destroy(ctx->map); 122 free(ctx); 123 } 124 return (r); 125 } 126 127 void 128 idn__filemapper_destroy(idn__filemapper_t ctx) { 129 130 assert(ctx != NULL); 131 132 TRACE(("idn__filemapper_destroy()\n")); 133 134 idn_ucsmap_destroy(ctx->map); 135 free(ctx); 136 } 137 138 idn_result_t 139 idn__filemapper_map(idn__filemapper_t ctx, const unsigned long *from, 140 unsigned long *to, size_t tolen) 141 { 142 idn_result_t r = idn_success; 143 ucsbuf_t ub; 144 145 assert(ctx != NULL && from != NULL && to != NULL); 146 147 TRACE(("idn__filemapper_map(from=\"%s\")\n", 148 idn__debug_ucs4xstring(from, 50))); 149 150 /* Initialize temporary buffer. */ 151 ucsbuf_init(&ub); 152 153 while (*from != '\0') { 154 /* Try mapping. */ 155 r = idn_ucsmap_map(ctx->map, *from, ub.ucs, ub.size, &ub.len); 156 switch (r) { 157 case idn_buffer_overflow: 158 /* Temporary buffer too small. Enlarge and retry. */ 159 if ((r = ucsbuf_grow(&ub)) != idn_success) 160 break; 161 continue; 162 case idn_nomapping: 163 /* There is no mapping. */ 164 r = idn_success; 165 /* fallthrough */ 166 case idn_success: 167 if (tolen < ub.len) { 168 r = idn_buffer_overflow; 169 goto ret; 170 } 171 memcpy(to, ub.ucs, sizeof(*to) * ub.len); 172 to += ub.len; 173 tolen -= ub.len; 174 break; 175 default: 176 goto ret; 177 } 178 from++; 179 } 180 181 ret: 182 ucsbuf_free(&ub); 183 184 if (r == idn_success) { 185 /* Terminate with NUL. */ 186 if (tolen == 0) 187 return (idn_buffer_overflow); 188 *to = '\0'; 189 } 190 191 return (r); 192 } 193 194 static void 195 ucsbuf_init(ucsbuf_t *b) { 196 b->ucs = b->local; 197 b->size = UCSBUF_LOCAL_SIZE; 198 b->len = 0; 199 } 200 201 static idn_result_t 202 ucsbuf_grow(ucsbuf_t *b) { 203 unsigned long *newbuf; 204 205 b->size *= 2; 206 if (b->ucs == b->local) { 207 b->ucs = malloc(sizeof(unsigned long) * b->size); 208 if (b->ucs == NULL) 209 return (idn_nomemory); 210 memcpy(b->ucs, b->local, sizeof(b->local)); 211 } else { 212 newbuf = realloc(b->ucs, sizeof(unsigned long) * b->size); 213 if (newbuf == NULL) 214 return (idn_nomemory); 215 b->ucs = newbuf; 216 } 217 return (idn_success); 218 } 219 220 static idn_result_t 221 ucsbuf_append(ucsbuf_t *b, unsigned long v) { 222 idn_result_t r; 223 224 if (b->len + 1 > b->size) { 225 r = ucsbuf_grow(b); 226 if (r != idn_success) 227 return (r); 228 } 229 b->ucs[b->len++] = v; 230 return (idn_success); 231 } 232 233 static void 234 ucsbuf_free(ucsbuf_t *b) { 235 if (b->ucs != b->local && b->ucs != NULL) 236 free(b->ucs); 237 } 238 239 static idn_result_t 240 read_file(const char *file, FILE *fp, idn_ucsmap_t map) { 241 char line[1024]; 242 ucsbuf_t ub; 243 idn_result_t r = idn_success; 244 int lineno = 0; 245 246 ucsbuf_init(&ub); 247 248 while (fgets(line, sizeof(line), fp) != NULL) { 249 char *p = line; 250 251 lineno++; 252 while (isspace((unsigned char)*p)) 253 p++; 254 if (*p == '\0' || *p == '#') 255 continue; 256 #ifdef SUPPORT_VERSIONING 257 /* Skip version tag. */ 258 if (lineno == 1 && strncmp("version=", line, 8) == 0) 259 continue; 260 #endif 261 again: 262 ub.len = 0; 263 r = get_map(p, &ub); 264 switch (r) { 265 case idn_success: 266 r = idn_ucsmap_add(map, ub.ucs[0], 267 &ub.ucs[1], ub.len - 1); 268 break; 269 case idn_buffer_overflow: 270 if ((r = ucsbuf_grow(&ub)) != idn_success) 271 break; 272 goto again; 273 case idn_invalid_syntax: 274 WARNING(("syntax error in file \"%-.100s\" line %d: " 275 "%-.100s", file, lineno, line)); 276 /* fall through */ 277 default: 278 ucsbuf_free(&ub); 279 return (r); 280 } 281 } 282 ucsbuf_free(&ub); 283 return (r); 284 } 285 286 static idn_result_t 287 get_map(char *p, ucsbuf_t *b) { 288 unsigned long v; 289 idn_result_t r = idn_success; 290 291 for (;;) { 292 if ((p = get_ucs(p, &v)) == NULL) 293 return (idn_invalid_syntax); 294 if ((r = ucsbuf_append(b, v)) != idn_success) 295 return (r); 296 if (b->len == 1) { 297 if (*p != ';') 298 return (idn_invalid_syntax); 299 p++; 300 while (isspace((unsigned char)*p)) 301 p++; 302 } 303 304 if (*p == ';' || *p == '#' || *p == '\0') 305 return (r); 306 } 307 return (r); 308 } 309 310 static char * 311 get_ucs(char *p, unsigned long *vp) { 312 char *end; 313 314 /* Skip leading space */ 315 while (isspace((unsigned char)*p)) 316 p++; 317 318 /* Skip optional 'U+' */ 319 if (strncmp(p, "U+", 2) == 0) 320 p += 2; 321 322 *vp = strtoul(p, &end, 16); 323 if (end == p) { 324 INFO(("idn__filemapper_create: UCS code point expected\n")); 325 return (NULL); 326 } 327 p = end; 328 329 /* Skip trailing space */ 330 while (isspace((unsigned char)*p)) 331 p++; 332 return p; 333 } 334 335 idn_result_t 336 idn__filemapper_createproc(const char *parameter, void **ctxp) { 337 return idn__filemapper_create(parameter, (idn__filemapper_t *)ctxp); 338 } 339 340 void 341 idn__filemapper_destroyproc(void *ctxp) { 342 idn__filemapper_destroy((idn__filemapper_t)ctxp); 343 } 344 345 idn_result_t 346 idn__filemapper_mapproc(void *ctx, const unsigned long *from, 347 unsigned long *to, size_t tolen) { 348 return idn__filemapper_map((idn__filemapper_t)ctx, from, to, tolen); 349 } 350