utf8proc.c revision 289177
1/* 2 * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23/* 24 * This library contains derived data from a modified version of the 25 * Unicode data files. 26 * 27 * The original data files are available at 28 * http://www.unicode.org/Public/UNIDATA/ 29 * 30 * Please notice the copyright statement in the file "utf8proc_data.c". 31 */ 32 33 34/* 35 * File name: utf8proc.c 36 * 37 * Description: 38 * Implementation of libutf8proc. 39 */ 40 41 42#include "utf8proc.h" 43#include "utf8proc_data.c" 44 45 46UTF8PROC_DATA 47const int8_t utf8proc_utf8class[256] = { 48 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 49 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 50 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 51 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 53 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 54 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 55 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 63 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 }; 64 65#define UTF8PROC_HANGUL_SBASE 0xAC00 66#define UTF8PROC_HANGUL_LBASE 0x1100 67#define UTF8PROC_HANGUL_VBASE 0x1161 68#define UTF8PROC_HANGUL_TBASE 0x11A7 69#define UTF8PROC_HANGUL_LCOUNT 19 70#define UTF8PROC_HANGUL_VCOUNT 21 71#define UTF8PROC_HANGUL_TCOUNT 28 72#define UTF8PROC_HANGUL_NCOUNT 588 73#define UTF8PROC_HANGUL_SCOUNT 11172 74/* END is exclusive */ 75#define UTF8PROC_HANGUL_L_START 0x1100 76#define UTF8PROC_HANGUL_L_END 0x115A 77#define UTF8PROC_HANGUL_L_FILLER 0x115F 78#define UTF8PROC_HANGUL_V_START 0x1160 79#define UTF8PROC_HANGUL_V_END 0x11A3 80#define UTF8PROC_HANGUL_T_START 0x11A8 81#define UTF8PROC_HANGUL_T_END 0x11FA 82#define UTF8PROC_HANGUL_S_START 0xAC00 83#define UTF8PROC_HANGUL_S_END 0xD7A4 84 85 86#define UTF8PROC_BOUNDCLASS_START 0 87#define UTF8PROC_BOUNDCLASS_OTHER 1 88#define UTF8PROC_BOUNDCLASS_CR 2 89#define UTF8PROC_BOUNDCLASS_LF 3 90#define UTF8PROC_BOUNDCLASS_CONTROL 4 91#define UTF8PROC_BOUNDCLASS_EXTEND 5 92#define UTF8PROC_BOUNDCLASS_L 6 93#define UTF8PROC_BOUNDCLASS_V 7 94#define UTF8PROC_BOUNDCLASS_T 8 95#define UTF8PROC_BOUNDCLASS_LV 9 96#define UTF8PROC_BOUNDCLASS_LVT 10 97 98 99UTF8PROC_API 100const char *utf8proc_version(void) { 101 return "1.1.5"; 102} 103 104/* 105 * This macro tells translators that string X should be translated, 106 * but does not look up the translation at run time. This is standard 107 * GNU gettext notation for annotating compile-time constant strings. 108 */ 109#ifndef N_ 110#define N_(x) x 111#endif 112 113UTF8PROC_API 114const char *utf8proc_errmsg(ssize_t errcode) { 115 switch (errcode) { 116 case UTF8PROC_ERROR_NOMEM: 117 return N_("Memory for processing UTF-8 data could not be allocated."); 118 case UTF8PROC_ERROR_OVERFLOW: 119 return N_("UTF-8 string is too long to be processed."); 120 case UTF8PROC_ERROR_INVALIDUTF8: 121 return N_("Invalid UTF-8 string"); 122 case UTF8PROC_ERROR_NOTASSIGNED: 123 return N_("Unassigned Unicode code point found in UTF-8 string."); 124 case UTF8PROC_ERROR_INVALIDOPTS: 125 return N_("Invalid options for UTF-8 processing chosen."); 126 default: 127 return N_("An unknown error occured while processing UTF-8 data."); 128 } 129} 130 131UTF8PROC_API 132ssize_t utf8proc_iterate( 133 const uint8_t *str, ssize_t strlen, int32_t *dst 134) { 135 int length; 136 int i; 137 int32_t uc = -1; 138 *dst = -1; 139 if (!strlen) return 0; 140 length = utf8proc_utf8class[str[0]]; 141 if (!length) return UTF8PROC_ERROR_INVALIDUTF8; 142 if (strlen >= 0 && length > strlen) return UTF8PROC_ERROR_INVALIDUTF8; 143 for (i=1; i<length; i++) { 144 if ((str[i] & 0xC0) != 0x80) return UTF8PROC_ERROR_INVALIDUTF8; 145 } 146 switch (length) { 147 case 1: 148 uc = str[0]; 149 break; 150 case 2: 151 uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F); 152 if (uc < 0x80) uc = -1; 153 break; 154 case 3: 155 uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6) 156 + (str[2] & 0x3F); 157 if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) || 158 (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1; 159 break; 160 case 4: 161 uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) 162 + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F); 163 if (uc < 0x10000 || uc >= 0x110000) uc = -1; 164 break; 165 } 166 if (uc < 0 || ((uc & 0xFFFF) >= 0xFFFE)) 167 return UTF8PROC_ERROR_INVALIDUTF8; 168 *dst = uc; 169 return length; 170} 171 172UTF8PROC_API 173bool utf8proc_codepoint_valid(int32_t uc) { 174 if (uc < 0 || uc >= 0x110000 || 175 ((uc & 0xFFFF) >= 0xFFFE) || (uc >= 0xD800 && uc < 0xE000) || 176 (uc >= 0xFDD0 && uc < 0xFDF0)) return false; 177 else return true; 178} 179 180UTF8PROC_API 181ssize_t utf8proc_encode_char(int32_t uc, uint8_t *dst) { 182 if (uc < 0x00) { 183 return 0; 184 } else if (uc < 0x80) { 185 dst[0] = (uint8_t)uc; 186 return 1; 187 } else if (uc < 0x800) { 188 dst[0] = 0xC0 + (uint8_t)(uc >> 6); 189 dst[1] = 0x80 + (uc & 0x3F); 190 return 2; 191 } else if (uc == 0xFFFF) { 192 dst[0] = 0xFF; 193 return 1; 194 } else if (uc == 0xFFFE) { 195 dst[0] = 0xFE; 196 return 1; 197 } else if (uc < 0x10000) { 198 dst[0] = 0xE0 + (uint8_t)(uc >> 12); 199 dst[1] = 0x80 + ((uc >> 6) & 0x3F); 200 dst[2] = 0x80 + (uc & 0x3F); 201 return 3; 202 } else if (uc < 0x110000) { 203 dst[0] = 0xF0 + (uint8_t)(uc >> 18); 204 dst[1] = 0x80 + ((uc >> 12) & 0x3F); 205 dst[2] = 0x80 + ((uc >> 6) & 0x3F); 206 dst[3] = 0x80 + (uc & 0x3F); 207 return 4; 208 } else return 0; 209} 210 211UTF8PROC_API 212const utf8proc_property_t *utf8proc_get_property(int32_t uc) { 213 /* ASSERT: uc >= 0 && uc < 0x110000 */ 214 return utf8proc_properties + ( 215 utf8proc_stage2table[ 216 utf8proc_stage1table[uc >> 8] + (uc & 0xFF) 217 ] 218 ); 219} 220 221#define utf8proc_decompose_lump(replacement_uc) \ 222 return utf8proc_decompose_char((replacement_uc), dst, bufsize, \ 223 options & ~UTF8PROC_LUMP, last_boundclass) 224 225UTF8PROC_API 226ssize_t utf8proc_decompose_char(int32_t uc, int32_t *dst, ssize_t bufsize, 227 int options, int *last_boundclass) { 228 /* ASSERT: uc >= 0 && uc < 0x110000 */ 229 const utf8proc_property_t *property; 230 utf8proc_propval_t category; 231 int32_t hangul_sindex; 232 property = utf8proc_get_property(uc); 233 category = property->category; 234 hangul_sindex = uc - UTF8PROC_HANGUL_SBASE; 235 if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { 236 if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) { 237 int32_t hangul_tindex; 238 if (bufsize >= 1) { 239 dst[0] = UTF8PROC_HANGUL_LBASE + 240 hangul_sindex / UTF8PROC_HANGUL_NCOUNT; 241 if (bufsize >= 2) dst[1] = UTF8PROC_HANGUL_VBASE + 242 (hangul_sindex % UTF8PROC_HANGUL_NCOUNT) / UTF8PROC_HANGUL_TCOUNT; 243 } 244 hangul_tindex = hangul_sindex % UTF8PROC_HANGUL_TCOUNT; 245 if (!hangul_tindex) return 2; 246 if (bufsize >= 3) dst[2] = UTF8PROC_HANGUL_TBASE + hangul_tindex; 247 return 3; 248 } 249 } 250 if (options & UTF8PROC_REJECTNA) { 251 if (!category) return UTF8PROC_ERROR_NOTASSIGNED; 252 } 253 if (options & UTF8PROC_IGNORE) { 254 if (property->ignorable) return 0; 255 } 256 if (options & UTF8PROC_LUMP) { 257 if (category == UTF8PROC_CATEGORY_ZS) utf8proc_decompose_lump(0x0020); 258 if (uc == 0x2018 || uc == 0x2019 || uc == 0x02BC || uc == 0x02C8) 259 utf8proc_decompose_lump(0x0027); 260 if (category == UTF8PROC_CATEGORY_PD || uc == 0x2212) 261 utf8proc_decompose_lump(0x002D); 262 if (uc == 0x2044 || uc == 0x2215) utf8proc_decompose_lump(0x002F); 263 if (uc == 0x2236) utf8proc_decompose_lump(0x003A); 264 if (uc == 0x2039 || uc == 0x2329 || uc == 0x3008) 265 utf8proc_decompose_lump(0x003C); 266 if (uc == 0x203A || uc == 0x232A || uc == 0x3009) 267 utf8proc_decompose_lump(0x003E); 268 if (uc == 0x2216) utf8proc_decompose_lump(0x005C); 269 if (uc == 0x02C4 || uc == 0x02C6 || uc == 0x2038 || uc == 0x2303) 270 utf8proc_decompose_lump(0x005E); 271 if (category == UTF8PROC_CATEGORY_PC || uc == 0x02CD) 272 utf8proc_decompose_lump(0x005F); 273 if (uc == 0x02CB) utf8proc_decompose_lump(0x0060); 274 if (uc == 0x2223) utf8proc_decompose_lump(0x007C); 275 if (uc == 0x223C) utf8proc_decompose_lump(0x007E); 276 if ((options & UTF8PROC_NLF2LS) && (options & UTF8PROC_NLF2PS)) { 277 if (category == UTF8PROC_CATEGORY_ZL || 278 category == UTF8PROC_CATEGORY_ZP) 279 utf8proc_decompose_lump(0x000A); 280 } 281 } 282 if (options & UTF8PROC_STRIPMARK) { 283 if (category == UTF8PROC_CATEGORY_MN || 284 category == UTF8PROC_CATEGORY_MC || 285 category == UTF8PROC_CATEGORY_ME) return 0; 286 } 287 if (options & UTF8PROC_CASEFOLD) { 288 if (property->casefold_mapping) { 289 const int32_t *casefold_entry; 290 ssize_t written = 0; 291 for (casefold_entry = property->casefold_mapping; 292 *casefold_entry >= 0; casefold_entry++) { 293 written += utf8proc_decompose_char(*casefold_entry, dst+written, 294 (bufsize > written) ? (bufsize - written) : 0, options, 295 last_boundclass); 296 if (written < 0) return UTF8PROC_ERROR_OVERFLOW; 297 } 298 return written; 299 } 300 } 301 if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { 302 if (property->decomp_mapping && 303 (!property->decomp_type || (options & UTF8PROC_COMPAT))) { 304 const int32_t *decomp_entry; 305 ssize_t written = 0; 306 for (decomp_entry = property->decomp_mapping; 307 *decomp_entry >= 0; decomp_entry++) { 308 written += utf8proc_decompose_char(*decomp_entry, dst+written, 309 (bufsize > written) ? (bufsize - written) : 0, options, 310 last_boundclass); 311 if (written < 0) return UTF8PROC_ERROR_OVERFLOW; 312 } 313 return written; 314 } 315 } 316 if (options & UTF8PROC_CHARBOUND) { 317 bool boundary; 318 int tbc, lbc; 319 tbc = 320 (uc == 0x000D) ? UTF8PROC_BOUNDCLASS_CR : 321 (uc == 0x000A) ? UTF8PROC_BOUNDCLASS_LF : 322 ((category == UTF8PROC_CATEGORY_ZL || 323 category == UTF8PROC_CATEGORY_ZP || 324 category == UTF8PROC_CATEGORY_CC || 325 category == UTF8PROC_CATEGORY_CF) && 326 !(uc == 0x200C || uc == 0x200D)) ? UTF8PROC_BOUNDCLASS_CONTROL : 327 property->extend ? UTF8PROC_BOUNDCLASS_EXTEND : 328 ((uc >= UTF8PROC_HANGUL_L_START && uc < UTF8PROC_HANGUL_L_END) || 329 uc == UTF8PROC_HANGUL_L_FILLER) ? UTF8PROC_BOUNDCLASS_L : 330 (uc >= UTF8PROC_HANGUL_V_START && uc < UTF8PROC_HANGUL_V_END) ? 331 UTF8PROC_BOUNDCLASS_V : 332 (uc >= UTF8PROC_HANGUL_T_START && uc < UTF8PROC_HANGUL_T_END) ? 333 UTF8PROC_BOUNDCLASS_T : 334 (uc >= UTF8PROC_HANGUL_S_START && uc < UTF8PROC_HANGUL_S_END) ? ( 335 ((uc-UTF8PROC_HANGUL_SBASE) % UTF8PROC_HANGUL_TCOUNT == 0) ? 336 UTF8PROC_BOUNDCLASS_LV : UTF8PROC_BOUNDCLASS_LVT 337 ) : 338 UTF8PROC_BOUNDCLASS_OTHER; 339 lbc = *last_boundclass; 340 boundary = 341 (tbc == UTF8PROC_BOUNDCLASS_EXTEND) ? false : 342 (lbc == UTF8PROC_BOUNDCLASS_START) ? true : 343 (lbc == UTF8PROC_BOUNDCLASS_CR && 344 tbc == UTF8PROC_BOUNDCLASS_LF) ? false : 345 (lbc == UTF8PROC_BOUNDCLASS_CONTROL) ? true : 346 (tbc == UTF8PROC_BOUNDCLASS_CONTROL) ? true : 347 (lbc == UTF8PROC_BOUNDCLASS_L && 348 (tbc == UTF8PROC_BOUNDCLASS_L || 349 tbc == UTF8PROC_BOUNDCLASS_V || 350 tbc == UTF8PROC_BOUNDCLASS_LV || 351 tbc == UTF8PROC_BOUNDCLASS_LVT)) ? false : 352 ((lbc == UTF8PROC_BOUNDCLASS_LV || 353 lbc == UTF8PROC_BOUNDCLASS_V) && 354 (tbc == UTF8PROC_BOUNDCLASS_V || 355 tbc == UTF8PROC_BOUNDCLASS_T)) ? false : 356 ((lbc == UTF8PROC_BOUNDCLASS_LVT || 357 lbc == UTF8PROC_BOUNDCLASS_T) && 358 tbc == UTF8PROC_BOUNDCLASS_T) ? false : 359 true; 360 *last_boundclass = tbc; 361 if (boundary) { 362 if (bufsize >= 1) dst[0] = 0xFFFF; 363 if (bufsize >= 2) dst[1] = uc; 364 return 2; 365 } 366 } 367 if (bufsize >= 1) *dst = uc; 368 return 1; 369} 370 371UTF8PROC_API 372ssize_t utf8proc_decompose( 373 const uint8_t *str, ssize_t strlen, 374 int32_t *buffer, ssize_t bufsize, int options 375) { 376 /* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */ 377 ssize_t wpos = 0; 378 if ((options & UTF8PROC_COMPOSE) && (options & UTF8PROC_DECOMPOSE)) 379 return UTF8PROC_ERROR_INVALIDOPTS; 380 if ((options & UTF8PROC_STRIPMARK) && 381 !(options & UTF8PROC_COMPOSE) && !(options & UTF8PROC_DECOMPOSE)) 382 return UTF8PROC_ERROR_INVALIDOPTS; 383 { 384 int32_t uc; 385 ssize_t rpos = 0; 386 ssize_t decomp_result; 387 int boundclass = UTF8PROC_BOUNDCLASS_START; 388 while (1) { 389 if (options & UTF8PROC_NULLTERM) { 390 rpos += utf8proc_iterate(str + rpos, -1, &uc); 391 /* checking of return value is not neccessary, 392 as 'uc' is < 0 in case of error */ 393 if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; 394 if (rpos < 0) return UTF8PROC_ERROR_OVERFLOW; 395 if (uc == 0) break; 396 } else { 397 if (rpos >= strlen) break; 398 rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc); 399 if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; 400 } 401 decomp_result = utf8proc_decompose_char( 402 uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options, 403 &boundclass 404 ); 405 if (decomp_result < 0) return decomp_result; 406 wpos += decomp_result; 407 /* prohibiting integer overflows due to too long strings: */ 408 if (wpos < 0 || wpos > SSIZE_MAX/sizeof(int32_t)/2) 409 return UTF8PROC_ERROR_OVERFLOW; 410 } 411 } 412 if ((options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) && bufsize >= wpos) { 413 ssize_t pos = 0; 414 while (pos < wpos-1) { 415 int32_t uc1, uc2; 416 const utf8proc_property_t *property1, *property2; 417 uc1 = buffer[pos]; 418 uc2 = buffer[pos+1]; 419 property1 = utf8proc_get_property(uc1); 420 property2 = utf8proc_get_property(uc2); 421 if (property1->combining_class > property2->combining_class && 422 property2->combining_class > 0) { 423 buffer[pos] = uc2; 424 buffer[pos+1] = uc1; 425 if (pos > 0) pos--; else pos++; 426 } else { 427 pos++; 428 } 429 } 430 } 431 return wpos; 432} 433 434UTF8PROC_API 435ssize_t utf8proc_reencode(int32_t *buffer, ssize_t length, int options) { 436 /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored 437 ASSERT: 'buffer' has one spare byte of free space at the end! */ 438 if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) { 439 ssize_t rpos; 440 ssize_t wpos = 0; 441 int32_t uc; 442 for (rpos = 0; rpos < length; rpos++) { 443 uc = buffer[rpos]; 444 if (uc == 0x000D && rpos < length-1 && buffer[rpos+1] == 0x000A) rpos++; 445 if (uc == 0x000A || uc == 0x000D || uc == 0x0085 || 446 ((options & UTF8PROC_STRIPCC) && (uc == 0x000B || uc == 0x000C))) { 447 if (options & UTF8PROC_NLF2LS) { 448 if (options & UTF8PROC_NLF2PS) { 449 buffer[wpos++] = 0x000A; 450 } else { 451 buffer[wpos++] = 0x2028; 452 } 453 } else { 454 if (options & UTF8PROC_NLF2PS) { 455 buffer[wpos++] = 0x2029; 456 } else { 457 buffer[wpos++] = 0x0020; 458 } 459 } 460 } else if ((options & UTF8PROC_STRIPCC) && 461 (uc < 0x0020 || (uc >= 0x007F && uc < 0x00A0))) { 462 if (uc == 0x0009) buffer[wpos++] = 0x0020; 463 } else { 464 buffer[wpos++] = uc; 465 } 466 } 467 length = wpos; 468 } 469 if (options & UTF8PROC_COMPOSE) { 470 int32_t *starter = NULL; 471 int32_t current_char; 472 const utf8proc_property_t *starter_property = NULL, *current_property; 473 utf8proc_propval_t max_combining_class = -1; 474 ssize_t rpos; 475 ssize_t wpos = 0; 476 int32_t composition; 477 for (rpos = 0; rpos < length; rpos++) { 478 current_char = buffer[rpos]; 479 current_property = utf8proc_get_property(current_char); 480 if (starter && current_property->combining_class > max_combining_class) { 481 /* combination perhaps possible */ 482 int32_t hangul_lindex; 483 int32_t hangul_sindex; 484 hangul_lindex = *starter - UTF8PROC_HANGUL_LBASE; 485 if (hangul_lindex >= 0 && hangul_lindex < UTF8PROC_HANGUL_LCOUNT) { 486 int32_t hangul_vindex; 487 hangul_vindex = current_char - UTF8PROC_HANGUL_VBASE; 488 if (hangul_vindex >= 0 && hangul_vindex < UTF8PROC_HANGUL_VCOUNT) { 489 *starter = UTF8PROC_HANGUL_SBASE + 490 (hangul_lindex * UTF8PROC_HANGUL_VCOUNT + hangul_vindex) * 491 UTF8PROC_HANGUL_TCOUNT; 492 starter_property = NULL; 493 continue; 494 } 495 } 496 hangul_sindex = *starter - UTF8PROC_HANGUL_SBASE; 497 if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT && 498 (hangul_sindex % UTF8PROC_HANGUL_TCOUNT) == 0) { 499 int32_t hangul_tindex; 500 hangul_tindex = current_char - UTF8PROC_HANGUL_TBASE; 501 if (hangul_tindex >= 0 && hangul_tindex < UTF8PROC_HANGUL_TCOUNT) { 502 *starter += hangul_tindex; 503 starter_property = NULL; 504 continue; 505 } 506 } 507 if (!starter_property) { 508 starter_property = utf8proc_get_property(*starter); 509 } 510 if (starter_property->comb1st_index >= 0 && 511 current_property->comb2nd_index >= 0) { 512 composition = utf8proc_combinations[ 513 starter_property->comb1st_index + 514 current_property->comb2nd_index 515 ]; 516 if (composition >= 0 && (!(options & UTF8PROC_STABLE) || 517 !(utf8proc_get_property(composition)->comp_exclusion))) { 518 *starter = composition; 519 starter_property = NULL; 520 continue; 521 } 522 } 523 } 524 buffer[wpos] = current_char; 525 if (current_property->combining_class) { 526 if (current_property->combining_class > max_combining_class) { 527 max_combining_class = current_property->combining_class; 528 } 529 } else { 530 starter = buffer + wpos; 531 starter_property = NULL; 532 max_combining_class = -1; 533 } 534 wpos++; 535 } 536 length = wpos; 537 } 538 { 539 ssize_t rpos, wpos = 0; 540 int32_t uc; 541 for (rpos = 0; rpos < length; rpos++) { 542 uc = buffer[rpos]; 543 wpos += utf8proc_encode_char(uc, ((uint8_t *)buffer) + wpos); 544 } 545 ((uint8_t *)buffer)[wpos] = 0; 546 return wpos; 547 } 548} 549 550UTF8PROC_API 551ssize_t utf8proc_map( 552 const uint8_t *str, ssize_t strlen, uint8_t **dstptr, int options 553) { 554 int32_t *buffer; 555 ssize_t result; 556 *dstptr = NULL; 557 result = utf8proc_decompose(str, strlen, NULL, 0, options); 558 if (result < 0) return result; 559 buffer = malloc(result * sizeof(int32_t) + 1); 560 if (!buffer) return UTF8PROC_ERROR_NOMEM; 561 result = utf8proc_decompose(str, strlen, buffer, result, options); 562 if (result < 0) { 563 free(buffer); 564 return result; 565 } 566 result = utf8proc_reencode(buffer, result, options); 567 if (result < 0) { 568 free(buffer); 569 return result; 570 } 571 { 572 int32_t *newptr; 573 newptr = realloc(buffer, (size_t)result+1); 574 if (newptr) buffer = newptr; 575 } 576 *dstptr = (uint8_t *)buffer; 577 return result; 578} 579 580UTF8PROC_API 581uint8_t *utf8proc_NFD(const uint8_t *str) { 582 uint8_t *retval; 583 utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | 584 UTF8PROC_DECOMPOSE); 585 return retval; 586} 587 588UTF8PROC_API 589uint8_t *utf8proc_NFC(const uint8_t *str) { 590 uint8_t *retval; 591 utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | 592 UTF8PROC_COMPOSE); 593 return retval; 594} 595 596UTF8PROC_API 597uint8_t *utf8proc_NFKD(const uint8_t *str) { 598 uint8_t *retval; 599 utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | 600 UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT); 601 return retval; 602} 603 604UTF8PROC_API 605uint8_t *utf8proc_NFKC(const uint8_t *str) { 606 uint8_t *retval; 607 utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | 608 UTF8PROC_COMPOSE | UTF8PROC_COMPAT); 609 return retval; 610} 611 612