1#ifndef lint 2static char *rcsid = "$Id: filemapper.c,v 1.1 2003/06/04 00:25:53 marka Exp $"; 3#endif 4 5/* 6 * Copyright (c) 2001,2002 Japan Network Information Center. 7 * All rights reserved. 8 * 9 * By using this file, you agree to the terms and conditions set forth bellow. 10 * 11 * LICENSE TERMS AND CONDITIONS 12 * 13 * The following License Terms and Conditions apply, unless a different 14 * license is obtained from Japan Network Information Center ("JPNIC"), 15 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, 16 * Chiyoda-ku, Tokyo 101-0047, Japan. 17 * 18 * 1. Use, Modification and Redistribution (including distribution of any 19 * modified or derived work) in source and/or binary forms is permitted 20 * under this License Terms and Conditions. 21 * 22 * 2. Redistribution of source code must retain the copyright notices as they 23 * appear in each source code file, this License Terms and Conditions. 24 * 25 * 3. Redistribution in binary form must reproduce the Copyright Notice, 26 * this License Terms and Conditions, in the documentation and/or other 27 * materials provided with the distribution. For the purposes of binary 28 * distribution the "Copyright Notice" refers to the following language: 29 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." 30 * 31 * 4. The name of JPNIC may not be used to endorse or promote products 32 * derived from this Software without specific prior written approval of 33 * JPNIC. 34 * 35 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC 36 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 38 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE 39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 40 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 43 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 44 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 45 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 46 */ 47 48#include <config.h> 49 50#include <stdlib.h> 51#include <stdio.h> 52#include <string.h> 53#include <ctype.h> 54 55#include <idn/result.h> 56#include <idn/assert.h> 57#include <idn/log.h> 58#include <idn/logmacro.h> 59#include <idn/debug.h> 60#include <idn/ucs4.h> 61#include <idn/ucsmap.h> 62#include <idn/filemapper.h> 63 64#define SUPPORT_VERSIONING 65 66#define UCSBUF_LOCAL_SIZE 20 67 68typedef struct ucsbuf { 69 unsigned long *ucs; 70 size_t size; 71 size_t len; 72 unsigned long local[UCSBUF_LOCAL_SIZE]; 73} ucsbuf_t; 74 75struct idn__filemapper { 76 idn_ucsmap_t map; 77}; 78 79static void ucsbuf_init(ucsbuf_t *b); 80static idn_result_t ucsbuf_grow(ucsbuf_t *b); 81static idn_result_t ucsbuf_append(ucsbuf_t *b, unsigned long v); 82static void ucsbuf_free(ucsbuf_t *b); 83static idn_result_t read_file(const char *file, FILE *fp, 84 idn_ucsmap_t map); 85static idn_result_t get_map(char *p, ucsbuf_t *b); 86static char *get_ucs(char *p, unsigned long *vp); 87 88 89idn_result_t 90idn__filemapper_create(const char *file, idn__filemapper_t *ctxp) { 91 FILE *fp; 92 idn__filemapper_t ctx; 93 idn_result_t r; 94 95 assert(file != NULL && ctxp != NULL); 96 97 TRACE(("idn__filemapper_create(file=\"%-.100s\")\n", file)); 98 99 if ((fp = fopen(file, "r")) == NULL) { 100 WARNING(("idn__filemapper_create: cannot open %-.100s\n", 101 file)); 102 return (idn_nofile); 103 } 104 if ((ctx = malloc(sizeof(struct idn__filemapper))) == NULL) 105 return (idn_nomemory); 106 107 if ((r = idn_ucsmap_create(&ctx->map)) != idn_success) { 108 free(ctx); 109 return (r); 110 } 111 112 r = read_file(file, fp, ctx->map); 113 fclose(fp); 114 115 if (r == idn_success) { 116 idn_ucsmap_fix(ctx->map); 117 *ctxp = ctx; 118 } else { 119 idn_ucsmap_destroy(ctx->map); 120 free(ctx); 121 } 122 return (r); 123} 124 125void 126idn__filemapper_destroy(idn__filemapper_t ctx) { 127 128 assert(ctx != NULL); 129 130 TRACE(("idn__filemapper_destroy()\n")); 131 132 idn_ucsmap_destroy(ctx->map); 133 free(ctx); 134} 135 136idn_result_t 137idn__filemapper_map(idn__filemapper_t ctx, const unsigned long *from, 138 unsigned long *to, size_t tolen) 139{ 140 idn_result_t r = idn_success; 141 ucsbuf_t ub; 142 143 assert(ctx != NULL && from != NULL && to != NULL); 144 145 TRACE(("idn__filemapper_map(from=\"%s\")\n", 146 idn__debug_ucs4xstring(from, 50))); 147 148 /* Initialize temporary buffer. */ 149 ucsbuf_init(&ub); 150 151 while (*from != '\0') { 152 /* Try mapping. */ 153 r = idn_ucsmap_map(ctx->map, *from, ub.ucs, ub.size, &ub.len); 154 switch (r) { 155 case idn_buffer_overflow: 156 /* Temporary buffer too small. Enlarge and retry. */ 157 if ((r = ucsbuf_grow(&ub)) != idn_success) 158 break; 159 continue; 160 case idn_nomapping: 161 /* There is no mapping. */ 162 r = idn_success; 163 /* fallthrough */ 164 case idn_success: 165 if (tolen < ub.len) { 166 r = idn_buffer_overflow; 167 goto ret; 168 } 169 memcpy(to, ub.ucs, sizeof(*to) * ub.len); 170 to += ub.len; 171 tolen -= ub.len; 172 break; 173 default: 174 goto ret; 175 } 176 from++; 177 } 178 179 ret: 180 ucsbuf_free(&ub); 181 182 if (r == idn_success) { 183 /* Terminate with NUL. */ 184 if (tolen == 0) 185 return (idn_buffer_overflow); 186 *to = '\0'; 187 } 188 189 return (r); 190} 191 192static void 193ucsbuf_init(ucsbuf_t *b) { 194 b->ucs = b->local; 195 b->size = UCSBUF_LOCAL_SIZE; 196 b->len = 0; 197} 198 199static idn_result_t 200ucsbuf_grow(ucsbuf_t *b) { 201 unsigned long *newbuf; 202 203 b->size *= 2; 204 if (b->ucs == b->local) { 205 b->ucs = malloc(sizeof(unsigned long) * b->size); 206 if (b->ucs == NULL) 207 return (idn_nomemory); 208 memcpy(b->ucs, b->local, sizeof(b->local)); 209 } else { 210 newbuf = realloc(b->ucs, sizeof(unsigned long) * b->size); 211 if (newbuf == NULL) 212 return (idn_nomemory); 213 b->ucs = newbuf; 214 } 215 return (idn_success); 216} 217 218static idn_result_t 219ucsbuf_append(ucsbuf_t *b, unsigned long v) { 220 idn_result_t r; 221 222 if (b->len + 1 > b->size) { 223 r = ucsbuf_grow(b); 224 if (r != idn_success) 225 return (r); 226 } 227 b->ucs[b->len++] = v; 228 return (idn_success); 229} 230 231static void 232ucsbuf_free(ucsbuf_t *b) { 233 if (b->ucs != b->local && b->ucs != NULL) 234 free(b->ucs); 235} 236 237static idn_result_t 238read_file(const char *file, FILE *fp, idn_ucsmap_t map) { 239 char line[1024]; 240 ucsbuf_t ub; 241 idn_result_t r = idn_success; 242 int lineno = 0; 243 244 ucsbuf_init(&ub); 245 246 while (fgets(line, sizeof(line), fp) != NULL) { 247 char *p = line; 248 249 lineno++; 250 while (isspace((unsigned char)*p)) 251 p++; 252 if (*p == '\0' || *p == '#') 253 continue; 254#ifdef SUPPORT_VERSIONING 255 /* Skip version tag. */ 256 if (lineno == 1 && strncmp("version=", line, 8) == 0) 257 continue; 258#endif 259 again: 260 ub.len = 0; 261 r = get_map(p, &ub); 262 switch (r) { 263 case idn_success: 264 r = idn_ucsmap_add(map, ub.ucs[0], 265 &ub.ucs[1], ub.len - 1); 266 break; 267 case idn_buffer_overflow: 268 if ((r = ucsbuf_grow(&ub)) != idn_success) 269 break; 270 goto again; 271 case idn_invalid_syntax: 272 WARNING(("syntax error in file \"%-.100s\" line %d: " 273 "%-.100s", file, lineno, line)); 274 /* fall through */ 275 default: 276 ucsbuf_free(&ub); 277 return (r); 278 } 279 } 280 ucsbuf_free(&ub); 281 return (r); 282} 283 284static idn_result_t 285get_map(char *p, ucsbuf_t *b) { 286 unsigned long v; 287 idn_result_t r = idn_success; 288 289 for (;;) { 290 if ((p = get_ucs(p, &v)) == NULL) 291 return (idn_invalid_syntax); 292 if ((r = ucsbuf_append(b, v)) != idn_success) 293 return (r); 294 if (b->len == 1) { 295 if (*p != ';') 296 return (idn_invalid_syntax); 297 p++; 298 while (isspace((unsigned char)*p)) 299 p++; 300 } 301 302 if (*p == ';' || *p == '#' || *p == '\0') 303 return (r); 304 } 305 return (r); 306} 307 308static char * 309get_ucs(char *p, unsigned long *vp) { 310 char *end; 311 312 /* Skip leading space */ 313 while (isspace((unsigned char)*p)) 314 p++; 315 316 /* Skip optional 'U+' */ 317 if (strncmp(p, "U+", 2) == 0) 318 p += 2; 319 320 *vp = strtoul(p, &end, 16); 321 if (end == p) { 322 INFO(("idn__filemapper_create: UCS code point expected\n")); 323 return (NULL); 324 } 325 p = end; 326 327 /* Skip trailing space */ 328 while (isspace((unsigned char)*p)) 329 p++; 330 return p; 331} 332 333idn_result_t 334idn__filemapper_createproc(const char *parameter, void **ctxp) { 335 return idn__filemapper_create(parameter, (idn__filemapper_t *)ctxp); 336} 337 338void 339idn__filemapper_destroyproc(void *ctxp) { 340 idn__filemapper_destroy((idn__filemapper_t)ctxp); 341} 342 343idn_result_t 344idn__filemapper_mapproc(void *ctx, const unsigned long *from, 345 unsigned long *to, size_t tolen) { 346 return idn__filemapper_map((idn__filemapper_t)ctx, from, to, tolen); 347} 348