/ CFUniChar.c
CFUniChar.c
1 /* 2 * Copyright (c) 2015 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 /* CFUniChar.c 25 Copyright (c) 2001-2014, Apple Inc. All rights reserved. 26 Responsibility: Aki Inoue 27 */ 28 29 #include <CoreFoundation/CFByteOrder.h> 30 #include "CFInternal.h" 31 #include "CFUniChar.h" 32 #include "CFStringEncodingConverterExt.h" 33 #include "CFUnicodeDecomposition.h" 34 #include "CFUniCharPriv.h" 35 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD 36 #include <fcntl.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/param.h> 40 #include <sys/mman.h> 41 #include <unistd.h> 42 #include <stdlib.h> 43 #endif 44 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 45 #include <mach/mach.h> 46 #endif 47 48 #if DEPLOYMENT_TARGET_WINDOWS 49 extern void _CFGetFrameworkPath(wchar_t *path, int maxLength); 50 #endif 51 52 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 53 #define __kCFCharacterSetDir "/System/Library/CoreServices" 54 #elif DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD || DEPLOYMENT_TARGET_EMBEDDED_MINI 55 #define __kCFCharacterSetDir "/usr/local/share/CoreFoundation" 56 #elif DEPLOYMENT_TARGET_WINDOWS 57 #define __kCFCharacterSetDir "\\Windows\\CoreFoundation" 58 #endif 59 60 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 61 #define USE_MACHO_SEGMENT 1 62 #endif 63 64 enum { 65 kCFUniCharLastExternalSet = kCFUniCharNewlineCharacterSet, 66 kCFUniCharFirstInternalSet = kCFUniCharCompatibilityDecomposableCharacterSet, 67 kCFUniCharLastInternalSet = kCFUniCharGraphemeExtendCharacterSet, 68 kCFUniCharFirstBitmapSet = kCFUniCharDecimalDigitCharacterSet 69 }; 70 71 CF_INLINE uint32_t __CFUniCharMapExternalSetToInternalIndex(uint32_t cset) { return ((kCFUniCharFirstInternalSet <= cset) ? ((cset - kCFUniCharFirstInternalSet) + kCFUniCharLastExternalSet) : cset) - kCFUniCharFirstBitmapSet; } 72 CF_INLINE uint32_t __CFUniCharMapCompatibilitySetID(uint32_t cset) { return ((cset == kCFUniCharControlCharacterSet) ? kCFUniCharControlAndFormatterCharacterSet : (((cset > kCFUniCharLastExternalSet) && (cset < kCFUniCharFirstInternalSet)) ? ((cset - kCFUniCharLastExternalSet) + kCFUniCharFirstInternalSet) : cset)); } 73 74 #if (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) && USE_MACHO_SEGMENT 75 #include <mach-o/getsect.h> 76 #include <mach-o/dyld.h> 77 #include <mach-o/ldsyms.h> 78 79 extern const void* unicode_csbitmaps_section_start __asm("section$start$__UNICODE$__csbitmaps"); 80 extern const void* unicode_csbitmaps_section_end __asm("section$end$__UNICODE$__csbitmaps"); 81 extern const void* unicode_properties_section_start __asm("section$start$__UNICODE$__properties"); 82 extern const void* unicode_properties_section_end __asm("section$end$__UNICODE$__properties"); 83 extern const void* unicode_data_section_start __asm("section$start$__UNICODE$__data"); 84 extern const void* unicode_data_section_end __asm("section$end$__UNICODE$__data"); 85 86 static const void *__CFGetSectDataPtr(const char *segname, const char *sectname, uint64_t *sizep) { 87 // special case three common sections to have fast access 88 if ( strcmp(segname, "__UNICODE") == 0 ) { 89 if ( strcmp(sectname, "__csbitmaps") == 0) { 90 if (sizep) *sizep = &unicode_csbitmaps_section_end - &unicode_csbitmaps_section_start; 91 return &unicode_csbitmaps_section_start; 92 } 93 else if ( strcmp(sectname, "__properties") == 0 ) { 94 if (sizep) *sizep = &unicode_properties_section_end - &unicode_properties_section_start; 95 return &unicode_properties_section_start; 96 } 97 else if ( strcmp(sectname, "__data") == 0 ) { 98 if (sizep) *sizep = &unicode_data_section_end - &unicode_data_section_start; 99 return &unicode_data_section_start; 100 } 101 } 102 103 uint32_t idx, cnt = _dyld_image_count(); 104 for (idx = 0; idx < cnt; idx++) { 105 void *mh = (void *)_dyld_get_image_header(idx); 106 if (mh != &_mh_dylib_header) continue; 107 #if __LP64__ 108 const struct section_64 *sect = getsectbynamefromheader_64((struct mach_header_64 *)mh, segname, sectname); 109 #else 110 const struct section *sect = getsectbynamefromheader((struct mach_header *)mh, segname, sectname); 111 #endif 112 if (!sect) break; 113 if (sizep) *sizep = (uint64_t)sect->size; 114 return (char *)sect->addr + _dyld_get_image_vmaddr_slide(idx); 115 } 116 if (sizep) *sizep = 0ULL; 117 return NULL; 118 } 119 #endif 120 121 #if !USE_MACHO_SEGMENT 122 123 // Memory map the file 124 125 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX 126 CF_INLINE void __CFUniCharCharacterSetPath(char *cpath) { 127 #elif DEPLOYMENT_TARGET_WINDOWS 128 CF_INLINE void __CFUniCharCharacterSetPath(wchar_t *wpath) { 129 #else 130 #error Unknown or unspecified DEPLOYMENT_TARGET 131 #endif 132 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 133 strlcpy(cpath, __kCFCharacterSetDir, MAXPATHLEN); 134 #elif DEPLOYMENT_TARGET_LINUX 135 strlcpy(cpath, __kCFCharacterSetDir, MAXPATHLEN); 136 #elif DEPLOYMENT_TARGET_WINDOWS 137 wchar_t frameworkPath[MAXPATHLEN]; 138 _CFGetFrameworkPath(frameworkPath, MAXPATHLEN); 139 wcsncpy(wpath, frameworkPath, MAXPATHLEN); 140 wcsncat(wpath, L"\\CoreFoundation.resources\\", MAXPATHLEN - wcslen(wpath)); 141 #else 142 strlcpy(cpath, __kCFCharacterSetDir, MAXPATHLEN); 143 strlcat(cpath, "/CharacterSets/", MAXPATHLEN); 144 #endif 145 } 146 147 #if DEPLOYMENT_TARGET_WINDOWS 148 #define MAX_BITMAP_STATE 512 149 // 150 // If a string is placed into this array, then it has been previously 151 // determined that the bitmap-file cannot be found. Thus, we make 152 // the assumption it won't be there in future calls and we avoid 153 // hitting the disk un-necessarily. This assumption isn't 100% 154 // correct, as bitmap-files can be added. We would have to re-start 155 // the application in order to pick-up the new bitmap info. 156 // 157 // We should probably re-visit this. 158 // 159 static wchar_t *mappedBitmapState[MAX_BITMAP_STATE]; 160 static int __nNumStateEntries = -1; 161 CRITICAL_SECTION __bitmapStateLock = {0}; 162 163 bool __GetBitmapStateForName(const wchar_t *bitmapName) { 164 if (NULL == __bitmapStateLock.DebugInfo) 165 InitializeCriticalSection(&__bitmapStateLock); 166 EnterCriticalSection(&__bitmapStateLock); 167 if (__nNumStateEntries >= 0) { 168 for (int i = 0; i < __nNumStateEntries; i++) { 169 if (wcscmp(mappedBitmapState[i], bitmapName) == 0) { 170 LeaveCriticalSection(&__bitmapStateLock); 171 return true; 172 } 173 } 174 } 175 LeaveCriticalSection(&__bitmapStateLock); 176 return false; 177 } 178 void __AddBitmapStateForName(const wchar_t *bitmapName) { 179 if (NULL == __bitmapStateLock.DebugInfo) 180 InitializeCriticalSection(&__bitmapStateLock); 181 EnterCriticalSection(&__bitmapStateLock); 182 __nNumStateEntries++; 183 mappedBitmapState[__nNumStateEntries] = (wchar_t *)malloc((lstrlenW(bitmapName)+1) * sizeof(wchar_t)); 184 lstrcpyW(mappedBitmapState[__nNumStateEntries], bitmapName); 185 LeaveCriticalSection(&__bitmapStateLock); 186 } 187 #endif 188 189 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX 190 static bool __CFUniCharLoadBytesFromFile(const char *fileName, const void **bytes, int64_t *fileSize) { 191 #elif DEPLOYMENT_TARGET_WINDOWS 192 static bool __CFUniCharLoadBytesFromFile(const wchar_t *fileName, const void **bytes, int64_t *fileSize) { 193 #else 194 #error Unknown or unspecified DEPLOYMENT_TARGET 195 #endif 196 #if DEPLOYMENT_TARGET_WINDOWS 197 HANDLE bitmapFileHandle = NULL; 198 HANDLE mappingHandle = NULL; 199 200 if (__GetBitmapStateForName(fileName)) { 201 // The fileName has been tried in the past, so just return false 202 // and move on. 203 *bytes = NULL; 204 return false; 205 } 206 mappingHandle = OpenFileMappingW(FILE_MAP_READ, TRUE, fileName); 207 if (NULL == mappingHandle) { 208 if ((bitmapFileHandle = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { 209 // We tried to get the bitmap file for mapping, but it's not there. Add to list of non-existant bitmap-files so 210 // we don't have to try this again in the future. 211 __AddBitmapStateForName(fileName); 212 return false; 213 } 214 mappingHandle = CreateFileMapping(bitmapFileHandle, NULL, PAGE_READONLY, 0, 0, NULL); 215 CloseHandle(bitmapFileHandle); 216 if (!mappingHandle) return false; 217 } 218 219 *bytes = MapViewOfFileEx(mappingHandle, FILE_MAP_READ, 0, 0, 0, 0); 220 221 if (NULL != fileSize) { 222 MEMORY_BASIC_INFORMATION memoryInfo; 223 224 if (0 == VirtualQueryEx(mappingHandle, *bytes, &memoryInfo, sizeof(memoryInfo))) { 225 *fileSize = 0; // This indicates no checking. Is it right ? 226 } else { 227 *fileSize = memoryInfo.RegionSize; 228 } 229 } 230 231 CloseHandle(mappingHandle); 232 233 return (*bytes ? true : false); 234 #else 235 struct stat statBuf; 236 int fd = -1; 237 238 if ((fd = open(fileName, O_RDONLY, 0)) < 0) { 239 return false; 240 } 241 if (fstat(fd, &statBuf) < 0 || (*bytes = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1) { 242 close(fd); 243 return false; 244 } 245 close(fd); 246 247 if (NULL != fileSize) *fileSize = statBuf.st_size; 248 249 return true; 250 #endif 251 } 252 253 #endif // USE_MACHO_SEGMENT 254 255 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX 256 static bool __CFUniCharLoadFile(const char *bitmapName, const void **bytes, int64_t *fileSize) { 257 #elif DEPLOYMENT_TARGET_WINDOWS 258 static bool __CFUniCharLoadFile(const wchar_t *bitmapName, const void **bytes, int64_t *fileSize) { 259 #else 260 #error Unknown or unspecified DEPLOYMENT_TARGET 261 #endif 262 #if USE_MACHO_SEGMENT 263 *bytes = __CFGetSectDataPtr("__UNICODE", bitmapName, NULL); 264 265 if (NULL != fileSize) *fileSize = 0; 266 267 return *bytes ? true : false; 268 #else 269 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX 270 char cpath[MAXPATHLEN]; 271 __CFUniCharCharacterSetPath(cpath); 272 strlcat(cpath, bitmapName, MAXPATHLEN); 273 Boolean needToFree = false; 274 const char *possiblyFrameworkRootedCPath = CFPathRelativeToAppleFrameworksRoot(cpath, &needToFree); 275 bool result = __CFUniCharLoadBytesFromFile(possiblyFrameworkRootedCPath, bytes, fileSize); 276 if (needToFree) free((void *)possiblyFrameworkRootedCPath); 277 return result; 278 #elif DEPLOYMENT_TARGET_WINDOWS 279 wchar_t wpath[MAXPATHLEN]; 280 __CFUniCharCharacterSetPath(wpath); 281 wcsncat(wpath, bitmapName, MAXPATHLEN); 282 return __CFUniCharLoadBytesFromFile(wpath, bytes, fileSize); 283 #else 284 #error Unknown or unspecified DEPLOYMENT_TARGET 285 #endif 286 #endif 287 } 288 289 // Bitmap functions 290 /* 291 Currently unused but left in for symmetry/informative purposes 292 CF_INLINE bool isControl(UTF32Char theChar, uint16_t charset, const void *data) { // ISO Control 293 return (((theChar <= 0x001F) || (theChar >= 0x007F && theChar <= 0x009F)) ? true : false); 294 }*/ 295 296 CF_INLINE bool isWhitespace(UTF32Char theChar, uint16_t charset, const void *data) { // Space 297 return (((theChar == 0x0020) || (theChar == 0x0009) || (theChar == 0x00A0) || (theChar == 0x1680) || (theChar >= 0x2000 && theChar <= 0x200B) || (theChar == 0x202F) || (theChar == 0x205F) || (theChar == 0x3000)) ? true : false); 298 } 299 300 CF_INLINE bool isNewline(UTF32Char theChar, uint16_t charset, const void *data) { // White space 301 return (((theChar >= 0x000A && theChar <= 0x000D) || (theChar == 0x0085) || (theChar == 0x2028) || (theChar == 0x2029)) ? true : false); 302 } 303 304 CF_INLINE bool isWhitespaceAndNewline(UTF32Char theChar, uint16_t charset, const void *data) { // White space 305 return ((isWhitespace(theChar, charset, data) || isNewline(theChar, charset, data)) ? true : false); 306 } 307 308 #if USE_MACHO_SEGMENT 309 CF_INLINE bool __CFSimpleFileSizeVerification(const void *bytes, int64_t fileSize) { return true; } 310 #elif 1 311 // <rdar://problem/8961744> __CFSimpleFileSizeVerification is broken 312 static bool __CFSimpleFileSizeVerification(const void *bytes, int64_t fileSize) { return true; } 313 #else 314 static bool __CFSimpleFileSizeVerification(const void *bytes, int64_t fileSize) { 315 bool result = true; 316 317 if (fileSize > 0) { 318 if ((sizeof(uint32_t) * 2) > fileSize) { 319 result = false; 320 } else { 321 uint32_t headerSize = CFSwapInt32BigToHost(*((uint32_t *)((char *)bytes + 4))); 322 323 if ((headerSize < (sizeof(uint32_t) * 4)) || (headerSize > fileSize)) { 324 result = false; 325 } else { 326 const uint32_t *lastElement = (uint32_t *)(((uint8_t *)bytes) + headerSize) - 2; 327 328 if ((headerSize + CFSwapInt32BigToHost(lastElement[0]) + CFSwapInt32BigToHost(lastElement[1])) > headerSize) result = false; 329 } 330 } 331 } 332 333 if (!result) CFLog(kCFLogLevelCritical, CFSTR("File size verification for Unicode database file failed.")); 334 335 return result; 336 } 337 #endif // USE_MACHO_SEGMENT 338 339 typedef struct { 340 uint32_t _numPlanes; 341 const uint8_t **_planes; 342 } __CFUniCharBitmapData; 343 344 static char __CFUniCharUnicodeVersionString[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 345 346 static uint32_t __CFUniCharNumberOfBitmaps = 0; 347 static __CFUniCharBitmapData *__CFUniCharBitmapDataArray = NULL; 348 349 static CFLock_t __CFUniCharBitmapLock = CFLockInit; 350 351 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX 352 #if !defined(CF_UNICHAR_BITMAP_FILE) 353 #if USE_MACHO_SEGMENT 354 #define CF_UNICHAR_BITMAP_FILE "__csbitmaps" 355 #else 356 #define CF_UNICHAR_BITMAP_FILE "/CFCharacterSetBitmaps.bitmap" 357 #endif 358 #endif 359 #elif DEPLOYMENT_TARGET_WINDOWS 360 #if !defined(CF_UNICHAR_BITMAP_FILE) 361 #define CF_UNICHAR_BITMAP_FILE L"CFCharacterSetBitmaps.bitmap" 362 #endif 363 #else 364 #error Unknown or unspecified DEPLOYMENT_TARGET 365 #endif 366 367 static bool __CFUniCharLoadBitmapData(void) { 368 __CFUniCharBitmapData *array; 369 uint32_t headerSize; 370 uint32_t bitmapSize; 371 int numPlanes; 372 uint8_t currentPlane; 373 const void *bytes; 374 const void *bitmapBase; 375 const void *bitmap; 376 int idx, bitmapIndex; 377 int64_t fileSize; 378 379 __CFLock(&__CFUniCharBitmapLock); 380 381 if (__CFUniCharBitmapDataArray || !__CFUniCharLoadFile(CF_UNICHAR_BITMAP_FILE, &bytes, &fileSize) || !__CFSimpleFileSizeVerification(bytes, fileSize)) { 382 __CFUnlock(&__CFUniCharBitmapLock); 383 return false; 384 } 385 386 for (idx = 0;idx < 4 && ((const uint8_t *)bytes)[idx];idx++) { 387 __CFUniCharUnicodeVersionString[idx * 2] = ((const uint8_t *)bytes)[idx]; 388 __CFUniCharUnicodeVersionString[idx * 2 + 1] = '.'; 389 } 390 __CFUniCharUnicodeVersionString[(idx < 4 ? idx * 2 - 1 : 7)] = '\0'; 391 392 headerSize = CFSwapInt32BigToHost(*((uint32_t *)((char *)bytes + 4))); 393 394 bitmapBase = (uint8_t *)bytes + headerSize; 395 bytes = (uint8_t *)bytes + (sizeof(uint32_t) * 2); 396 headerSize -= (sizeof(uint32_t) * 2); 397 398 __CFUniCharNumberOfBitmaps = headerSize / (sizeof(uint32_t) * 2); 399 400 array = (__CFUniCharBitmapData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFUniCharBitmapData) * __CFUniCharNumberOfBitmaps, 0); 401 402 for (idx = 0;idx < (int)__CFUniCharNumberOfBitmaps;idx++) { 403 bitmap = (uint8_t *)bitmapBase + CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes = (uint8_t *)bytes + sizeof(uint32_t); 404 bitmapSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes = (uint8_t *)bytes + sizeof(uint32_t); 405 406 numPlanes = bitmapSize / (8 * 1024); 407 numPlanes = *(const uint8_t *)((char *)bitmap + (((numPlanes - 1) * ((8 * 1024) + 1)) - 1)) + 1; 408 array[idx]._planes = (const uint8_t **)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(const void *) * numPlanes, 0); 409 array[idx]._numPlanes = numPlanes; 410 411 currentPlane = 0; 412 for (bitmapIndex = 0;bitmapIndex < numPlanes;bitmapIndex++) { 413 if (bitmapIndex == currentPlane) { 414 array[idx]._planes[bitmapIndex] = (const uint8_t *)bitmap; 415 bitmap = (uint8_t *)bitmap + (8 * 1024); 416 #if defined (__cplusplus) 417 currentPlane = *(((const uint8_t*&)bitmap)++); 418 #else 419 currentPlane = *((const uint8_t *)bitmap++); 420 #endif 421 422 } else { 423 array[idx]._planes[bitmapIndex] = NULL; 424 } 425 } 426 } 427 428 __CFUniCharBitmapDataArray = array; 429 430 __CFUnlock(&__CFUniCharBitmapLock); 431 432 return true; 433 } 434 435 CF_PRIVATE const char *__CFUniCharGetUnicodeVersionString(void) { 436 if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); 437 return __CFUniCharUnicodeVersionString; 438 } 439 440 bool CFUniCharIsMemberOf(UTF32Char theChar, uint32_t charset) { 441 charset = __CFUniCharMapCompatibilitySetID(charset); 442 443 switch (charset) { 444 case kCFUniCharWhitespaceCharacterSet: 445 return isWhitespace(theChar, charset, NULL); 446 447 case kCFUniCharWhitespaceAndNewlineCharacterSet: 448 return isWhitespaceAndNewline(theChar, charset, NULL); 449 450 case kCFUniCharNewlineCharacterSet: 451 return isNewline(theChar, charset, NULL); 452 453 default: { 454 uint32_t tableIndex = __CFUniCharMapExternalSetToInternalIndex(charset); 455 456 if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); 457 458 if (tableIndex < __CFUniCharNumberOfBitmaps) { 459 __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + tableIndex; 460 uint8_t planeNo = (theChar >> 16) & 0xFF; 461 462 // The bitmap data for kCFUniCharIllegalCharacterSet is actually LEGAL set less Plane 14 ~ 16 463 if (charset == kCFUniCharIllegalCharacterSet) { 464 if (planeNo == 0x0E) { // Plane 14 465 theChar &= 0xFF; 466 return (((theChar == 0x01) || ((theChar > 0x1F) && (theChar < 0x80))) ? false : true); 467 } else if (planeNo == 0x0F || planeNo == 0x10) { // Plane 15 & 16 468 return ((theChar & 0xFF) > 0xFFFD ? true : false); 469 } else { 470 return (planeNo < data->_numPlanes && data->_planes[planeNo] ? !CFUniCharIsMemberOfBitmap(theChar, data->_planes[planeNo]) : true); 471 } 472 } else if (charset == kCFUniCharControlAndFormatterCharacterSet) { 473 if (planeNo == 0x0E) { // Plane 14 474 theChar &= 0xFF; 475 return (((theChar == 0x01) || ((theChar > 0x1F) && (theChar < 0x80))) ? true : false); 476 } else { 477 return (planeNo < data->_numPlanes && data->_planes[planeNo] ? CFUniCharIsMemberOfBitmap(theChar, data->_planes[planeNo]) : false); 478 } 479 } else { 480 return (planeNo < data->_numPlanes && data->_planes[planeNo] ? CFUniCharIsMemberOfBitmap(theChar, data->_planes[planeNo]) : false); 481 } 482 } 483 return false; 484 } 485 } 486 } 487 488 const uint8_t *CFUniCharGetBitmapPtrForPlane(uint32_t charset, uint32_t plane) { 489 if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); 490 491 charset = __CFUniCharMapCompatibilitySetID(charset); 492 493 if ((charset > kCFUniCharWhitespaceAndNewlineCharacterSet) && (charset != kCFUniCharIllegalCharacterSet) && (charset != kCFUniCharNewlineCharacterSet)) { 494 uint32_t tableIndex = __CFUniCharMapExternalSetToInternalIndex(charset); 495 496 if (tableIndex < __CFUniCharNumberOfBitmaps) { 497 __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + tableIndex; 498 499 return (plane < data->_numPlanes ? data->_planes[plane] : NULL); 500 } 501 } 502 return NULL; 503 } 504 505 CF_PRIVATE uint8_t CFUniCharGetBitmapForPlane(uint32_t charset, uint32_t plane, void *bitmap, bool isInverted) { 506 const uint8_t *src = CFUniCharGetBitmapPtrForPlane(charset, plane); 507 int numBytes = (8 * 1024); 508 509 if (src) { 510 if (isInverted) { 511 #if defined (__cplusplus) 512 while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = ~(*(src++)); 513 #else 514 while (numBytes-- > 0) *((uint8_t *)bitmap++) = ~(*(src++)); 515 #endif 516 } else { 517 #if defined (__cplusplus) 518 while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = *(src++); 519 #else 520 while (numBytes-- > 0) *((uint8_t *)bitmap++) = *(src++); 521 #endif 522 } 523 return kCFUniCharBitmapFilled; 524 } else if (charset == kCFUniCharIllegalCharacterSet) { 525 __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + __CFUniCharMapExternalSetToInternalIndex(__CFUniCharMapCompatibilitySetID(charset)); 526 527 if (plane < data->_numPlanes && (src = data->_planes[plane])) { 528 if (isInverted) { 529 #if defined (__cplusplus) 530 while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = *(src++); 531 #else 532 while (numBytes-- > 0) *((uint8_t *)bitmap++) = *(src++); 533 #endif 534 } else { 535 #if defined (__cplusplus) 536 while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = ~(*(src++)); 537 #else 538 while (numBytes-- > 0) *((uint8_t *)bitmap++) = ~(*(src++)); 539 #endif 540 } 541 return kCFUniCharBitmapFilled; 542 } else if (plane == 0x0E) { // Plane 14 543 int idx; 544 uint8_t asciiRange = (isInverted ? (uint8_t)0xFF : (uint8_t)0); 545 uint8_t otherRange = (isInverted ? (uint8_t)0 : (uint8_t)0xFF); 546 547 #if defined (__cplusplus) 548 *(((uint8_t *&)bitmap)++) = 0x02; // UE0001 LANGUAGE TAG 549 #else 550 *((uint8_t *)bitmap++) = 0x02; // UE0001 LANGUAGE TAG 551 #endif 552 for (idx = 1;idx < numBytes;idx++) { 553 #if defined (__cplusplus) 554 *(((uint8_t *&)bitmap)++) = ((idx >= (0x20 / 8) && (idx < (0x80 / 8))) ? asciiRange : otherRange); 555 #else 556 *((uint8_t *)bitmap++) = ((idx >= (0x20 / 8) && (idx < (0x80 / 8))) ? asciiRange : otherRange); 557 #endif 558 } 559 return kCFUniCharBitmapFilled; 560 } else if (plane == 0x0F || plane == 0x10) { // Plane 15 & 16 561 uint32_t value = (isInverted ? ~0 : 0); 562 numBytes /= 4; // for 32bit 563 564 while (numBytes-- > 0) { 565 *((uint32_t *)bitmap) = value; 566 #if defined (__cplusplus) 567 bitmap = (uint8_t *)bitmap + sizeof(uint32_t); 568 #else 569 bitmap += sizeof(uint32_t); 570 #endif 571 } 572 *(((uint8_t *)bitmap) - 5) = (isInverted ? 0x3F : 0xC0); // 0xFFFE & 0xFFFF 573 return kCFUniCharBitmapFilled; 574 } 575 return (isInverted ? kCFUniCharBitmapEmpty : kCFUniCharBitmapAll); 576 } else if ((charset < kCFUniCharDecimalDigitCharacterSet) || (charset == kCFUniCharNewlineCharacterSet)) { 577 if (plane) return (isInverted ? kCFUniCharBitmapAll : kCFUniCharBitmapEmpty); 578 579 uint8_t *bitmapBase = (uint8_t *)bitmap; 580 CFIndex idx; 581 uint8_t nonFillValue = (isInverted ? (uint8_t)0xFF : (uint8_t)0); 582 583 #if defined (__cplusplus) 584 while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = nonFillValue; 585 #else 586 while (numBytes-- > 0) *((uint8_t *)bitmap++) = nonFillValue; 587 #endif 588 589 if ((charset == kCFUniCharWhitespaceAndNewlineCharacterSet) || (charset == kCFUniCharNewlineCharacterSet)) { 590 const UniChar newlines[] = {0x000A, 0x000B, 0x000C, 0x000D, 0x0085, 0x2028, 0x2029}; 591 592 for (idx = 0;idx < (int)(sizeof(newlines) / sizeof(*newlines)); idx++) { 593 if (isInverted) { 594 CFUniCharRemoveCharacterFromBitmap(newlines[idx], bitmapBase); 595 } else { 596 CFUniCharAddCharacterToBitmap(newlines[idx], bitmapBase); 597 } 598 } 599 600 if (charset == kCFUniCharNewlineCharacterSet) return kCFUniCharBitmapFilled; 601 } 602 603 if (isInverted) { 604 CFUniCharRemoveCharacterFromBitmap(0x0009, bitmapBase); 605 CFUniCharRemoveCharacterFromBitmap(0x0020, bitmapBase); 606 CFUniCharRemoveCharacterFromBitmap(0x00A0, bitmapBase); 607 CFUniCharRemoveCharacterFromBitmap(0x1680, bitmapBase); 608 CFUniCharRemoveCharacterFromBitmap(0x202F, bitmapBase); 609 CFUniCharRemoveCharacterFromBitmap(0x205F, bitmapBase); 610 CFUniCharRemoveCharacterFromBitmap(0x3000, bitmapBase); 611 } else { 612 CFUniCharAddCharacterToBitmap(0x0009, bitmapBase); 613 CFUniCharAddCharacterToBitmap(0x0020, bitmapBase); 614 CFUniCharAddCharacterToBitmap(0x00A0, bitmapBase); 615 CFUniCharAddCharacterToBitmap(0x1680, bitmapBase); 616 CFUniCharAddCharacterToBitmap(0x202F, bitmapBase); 617 CFUniCharAddCharacterToBitmap(0x205F, bitmapBase); 618 CFUniCharAddCharacterToBitmap(0x3000, bitmapBase); 619 } 620 621 for (idx = 0x2000;idx <= 0x200B;idx++) { 622 if (isInverted) { 623 CFUniCharRemoveCharacterFromBitmap(idx, bitmapBase); 624 } else { 625 CFUniCharAddCharacterToBitmap(idx, bitmapBase); 626 } 627 } 628 return kCFUniCharBitmapFilled; 629 } 630 return (isInverted ? kCFUniCharBitmapAll : kCFUniCharBitmapEmpty); 631 } 632 633 CF_PRIVATE uint32_t CFUniCharGetNumberOfPlanes(uint32_t charset) { 634 if ((charset == kCFUniCharControlCharacterSet) || (charset == kCFUniCharControlAndFormatterCharacterSet)) { 635 return 15; // 0 to 14 636 } else if (charset < kCFUniCharDecimalDigitCharacterSet) { 637 return 1; 638 } else if (charset == kCFUniCharIllegalCharacterSet) { 639 return 17; 640 } else { 641 uint32_t numPlanes; 642 643 if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); 644 645 numPlanes = __CFUniCharBitmapDataArray[__CFUniCharMapExternalSetToInternalIndex(__CFUniCharMapCompatibilitySetID(charset))]._numPlanes; 646 647 return numPlanes; 648 } 649 } 650 651 // Mapping data loading 652 static const void **__CFUniCharMappingTables = NULL; 653 654 static CFLock_t __CFUniCharMappingTableLock = CFLockInit; 655 656 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX 657 #if __CF_BIG_ENDIAN__ 658 #if USE_MACHO_SEGMENT 659 #define MAPPING_TABLE_FILE "__data" 660 #else 661 #define MAPPING_TABLE_FILE "/CFUnicodeData-B.mapping" 662 #endif 663 #else 664 #if USE_MACHO_SEGMENT 665 #define MAPPING_TABLE_FILE "__data" 666 #else 667 #define MAPPING_TABLE_FILE "/CFUnicodeData-L.mapping" 668 #endif 669 #endif 670 #elif DEPLOYMENT_TARGET_WINDOWS 671 #if __CF_BIG_ENDIAN__ 672 #if USE_MACHO_SEGMENT 673 #define MAPPING_TABLE_FILE "__data" 674 #else 675 #define MAPPING_TABLE_FILE L"CFUnicodeData-B.mapping" 676 #endif 677 #else 678 #if USE_MACHO_SEGMENT 679 #define MAPPING_TABLE_FILE "__data" 680 #else 681 #define MAPPING_TABLE_FILE L"CFUnicodeData-L.mapping" 682 #endif 683 #endif 684 #else 685 #error Unknown or unspecified DEPLOYMENT_TARGET 686 #endif 687 688 CF_PRIVATE const void *CFUniCharGetMappingData(uint32_t type) { 689 690 __CFLock(&__CFUniCharMappingTableLock); 691 692 if (NULL == __CFUniCharMappingTables) { 693 const void *bytes; 694 const void *bodyBase; 695 int headerSize; 696 int idx, count; 697 int64_t fileSize; 698 699 if (!__CFUniCharLoadFile(MAPPING_TABLE_FILE, &bytes, &fileSize) || !__CFSimpleFileSizeVerification(bytes, fileSize)) { 700 __CFUnlock(&__CFUniCharMappingTableLock); 701 return NULL; 702 } 703 704 #if defined (__cplusplus) 705 bytes = (uint8_t *)bytes + 4; // Skip Unicode version 706 headerSize = *((uint8_t *)bytes); bytes = (uint8_t *)bytes + sizeof(uint32_t); 707 #else 708 bytes += 4; // Skip Unicode version 709 headerSize = *((uint32_t *)bytes); bytes += sizeof(uint32_t); 710 #endif 711 headerSize -= (sizeof(uint32_t) * 2); 712 bodyBase = (char *)bytes + headerSize; 713 714 count = headerSize / sizeof(uint32_t); 715 716 __CFUniCharMappingTables = (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(const void *) * count, 0); 717 718 for (idx = 0;idx < count;idx++) { 719 #if defined (__cplusplus) 720 __CFUniCharMappingTables[idx] = (char *)bodyBase + *((uint32_t *)bytes); bytes = (uint8_t *)bytes + sizeof(uint32_t); 721 #else 722 __CFUniCharMappingTables[idx] = (char *)bodyBase + *((uint32_t *)bytes); bytes += sizeof(uint32_t); 723 #endif 724 } 725 } 726 727 __CFUnlock(&__CFUniCharMappingTableLock); 728 729 return __CFUniCharMappingTables[type]; 730 } 731 732 // Case mapping functions 733 #define DO_SPECIAL_CASE_MAPPING 1 734 735 static uint32_t *__CFUniCharCaseMappingTableCounts = NULL; 736 static uint32_t **__CFUniCharCaseMappingTable = NULL; 737 static const uint32_t **__CFUniCharCaseMappingExtraTable = NULL; 738 739 typedef struct { 740 uint32_t _key; 741 uint32_t _value; 742 } __CFUniCharCaseMappings; 743 744 /* Binary searches CFStringEncodingUnicodeTo8BitCharMap */ 745 static uint32_t __CFUniCharGetMappedCase(const __CFUniCharCaseMappings *theTable, uint32_t numElem, UTF32Char character) { 746 const __CFUniCharCaseMappings *p, *q, *divider; 747 748 if ((character < theTable[0]._key) || (character > theTable[numElem-1]._key)) { 749 return 0; 750 } 751 p = theTable; 752 q = p + (numElem-1); 753 while (p <= q) { 754 divider = p + ((q - p) >> 1); /* divide by 2 */ 755 if (character < divider->_key) { q = divider - 1; } 756 else if (character > divider->_key) { p = divider + 1; } 757 else { return divider->_value; } 758 } 759 return 0; 760 } 761 762 #define NUM_CASE_MAP_DATA (kCFUniCharCaseFold + 1) 763 764 static bool __CFUniCharLoadCaseMappingTable(void) { 765 uint32_t *countArray; 766 int idx; 767 768 if (NULL == __CFUniCharMappingTables) (void)CFUniCharGetMappingData(kCFUniCharToLowercase); 769 if (NULL == __CFUniCharMappingTables) return false; 770 771 __CFLock(&__CFUniCharMappingTableLock); 772 773 if (__CFUniCharCaseMappingTableCounts) { 774 __CFUnlock(&__CFUniCharMappingTableLock); 775 return true; 776 } 777 778 countArray = (uint32_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(uint32_t) * NUM_CASE_MAP_DATA + sizeof(uint32_t *) * NUM_CASE_MAP_DATA * 2, 0); 779 __CFUniCharCaseMappingTable = (uint32_t **)((char *)countArray + sizeof(uint32_t) * NUM_CASE_MAP_DATA); 780 __CFUniCharCaseMappingExtraTable = (const uint32_t **)__CFUniCharCaseMappingTable + NUM_CASE_MAP_DATA; 781 782 for (idx = 0;idx < NUM_CASE_MAP_DATA;idx++) { 783 countArray[idx] = *((uint32_t *)__CFUniCharMappingTables[idx]) / (sizeof(uint32_t) * 2); 784 __CFUniCharCaseMappingTable[idx] = ((uint32_t *)__CFUniCharMappingTables[idx]) + 1; 785 __CFUniCharCaseMappingExtraTable[idx] = (const uint32_t *)((char *)__CFUniCharCaseMappingTable[idx] + *((uint32_t *)__CFUniCharMappingTables[idx])); 786 } 787 788 __CFUniCharCaseMappingTableCounts = countArray; 789 790 __CFUnlock(&__CFUniCharMappingTableLock); 791 return true; 792 } 793 794 #if __CF_BIG_ENDIAN__ 795 #define TURKISH_LANG_CODE (0x7472) // tr 796 #define LITHUANIAN_LANG_CODE (0x6C74) // lt 797 #define AZERI_LANG_CODE (0x617A) // az 798 #define DUTCH_LANG_CODE (0x6E6C) // nl 799 #define GREEK_LANG_CODE (0x656C) // el 800 #else 801 #define TURKISH_LANG_CODE (0x7274) // tr 802 #define LITHUANIAN_LANG_CODE (0x746C) // lt 803 #define AZERI_LANG_CODE (0x7A61) // az 804 #define DUTCH_LANG_CODE (0x6C6E) // nl 805 #define GREEK_LANG_CODE (0x6C65) // el 806 #endif 807 808 CFIndex CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, CFIndex maxLength, uint32_t ctype, uint32_t flags, const uint8_t *langCode) { 809 __CFUniCharBitmapData *data; 810 uint8_t planeNo = (theChar >> 16) & 0xFF; 811 812 caseFoldRetry: 813 814 #if DO_SPECIAL_CASE_MAPPING 815 if (flags & kCFUniCharCaseMapFinalSigma) { 816 if (theChar == 0x03A3) { // Final sigma 817 *convertedChar = (ctype == kCFUniCharToLowercase ? 0x03C2 : 0x03A3); 818 return 1; 819 } 820 } 821 822 if (langCode) { 823 if (flags & kCFUniCharCaseMapGreekTonos) { // localized Greek uppercasing 824 if (theChar == 0x0301) { // GREEK TONOS 825 return 0; 826 } else if (theChar == 0x0344) {// COMBINING GREEK DIALYTIKA TONOS 827 *convertedChar = 0x0308; // COMBINING GREEK DIALYTIKA 828 return 1; 829 } else if (CFUniCharIsMemberOf(theChar, kCFUniCharDecomposableCharacterSet)) { 830 UTF32Char buffer[MAX_DECOMPOSED_LENGTH]; 831 CFIndex length = CFUniCharDecomposeCharacter(theChar, buffer, MAX_DECOMPOSED_LENGTH); 832 833 if (length > 1) { 834 UTF32Char *characters = buffer + 1; 835 UTF32Char *tail = buffer + length; 836 837 while (characters < tail) { 838 if (*characters == 0x0301) break; 839 ++characters; 840 } 841 842 if (characters < tail) { // found a tonos 843 CFIndex convertedLength = CFUniCharMapCaseTo(*buffer, convertedChar, maxLength, ctype, 0, langCode); 844 845 if (convertedLength == 0) { 846 *convertedChar = (UTF16Char)*buffer; 847 convertedLength = 1; 848 } 849 850 characters = buffer + 1; 851 852 while (characters < tail) { 853 if (*characters != 0x0301) { // not tonos 854 if (*characters < 0x10000) { // BMP 855 convertedChar[convertedLength] = (UTF16Char)*characters; 856 ++convertedLength; 857 } else { 858 UTF32Char character = *characters - 0x10000; 859 convertedChar[convertedLength++] = (UTF16Char)((character >> 10) + 0xD800UL); 860 convertedChar[convertedLength++] = (UTF16Char)((character & 0x3FF) + 0xDC00UL); 861 } 862 } 863 ++characters; 864 } 865 866 return convertedLength; 867 } 868 } 869 } 870 } 871 switch (*(uint16_t *)langCode) { 872 case LITHUANIAN_LANG_CODE: 873 if (theChar == 0x0307 && (flags & kCFUniCharCaseMapAfter_i)) { 874 return 0; 875 } else if (ctype == kCFUniCharToLowercase) { 876 if (flags & kCFUniCharCaseMapMoreAbove) { 877 switch (theChar) { 878 case 0x0049: // LATIN CAPITAL LETTER I 879 *(convertedChar++) = 0x0069; 880 *(convertedChar++) = 0x0307; 881 return 2; 882 883 case 0x004A: // LATIN CAPITAL LETTER J 884 *(convertedChar++) = 0x006A; 885 *(convertedChar++) = 0x0307; 886 return 2; 887 888 case 0x012E: // LATIN CAPITAL LETTER I WITH OGONEK 889 *(convertedChar++) = 0x012F; 890 *(convertedChar++) = 0x0307; 891 return 2; 892 893 default: break; 894 } 895 } 896 switch (theChar) { 897 case 0x00CC: // LATIN CAPITAL LETTER I WITH GRAVE 898 *(convertedChar++) = 0x0069; 899 *(convertedChar++) = 0x0307; 900 *(convertedChar++) = 0x0300; 901 return 3; 902 903 case 0x00CD: // LATIN CAPITAL LETTER I WITH ACUTE 904 *(convertedChar++) = 0x0069; 905 *(convertedChar++) = 0x0307; 906 *(convertedChar++) = 0x0301; 907 return 3; 908 909 case 0x0128: // LATIN CAPITAL LETTER I WITH TILDE 910 *(convertedChar++) = 0x0069; 911 *(convertedChar++) = 0x0307; 912 *(convertedChar++) = 0x0303; 913 return 3; 914 915 default: break; 916 } 917 } 918 break; 919 920 case TURKISH_LANG_CODE: 921 case AZERI_LANG_CODE: 922 if ((theChar == 0x0049) || (theChar == 0x0131)) { // LATIN CAPITAL LETTER I & LATIN SMALL LETTER DOTLESS I 923 *convertedChar = (((ctype == kCFUniCharToLowercase) || (ctype == kCFUniCharCaseFold)) ? ((kCFUniCharCaseMapMoreAbove & flags) ? 0x0069 : 0x0131) : 0x0049); 924 return 1; 925 } else if ((theChar == 0x0069) || (theChar == 0x0130)) { // LATIN SMALL LETTER I & LATIN CAPITAL LETTER I WITH DOT ABOVE 926 *convertedChar = (((ctype == kCFUniCharToLowercase) || (ctype == kCFUniCharCaseFold)) ? 0x0069 : 0x0130); 927 return 1; 928 } else if (theChar == 0x0307 && (kCFUniCharCaseMapAfter_i & flags)) { // COMBINING DOT ABOVE AFTER_i 929 if (ctype == kCFUniCharToLowercase) { 930 return 0; 931 } else { 932 *convertedChar = 0x0307; 933 return 1; 934 } 935 } 936 break; 937 938 case DUTCH_LANG_CODE: 939 if ((theChar == 0x004A) || (theChar == 0x006A)) { 940 *convertedChar = (((ctype == kCFUniCharToUppercase) || (ctype == kCFUniCharToTitlecase) || (kCFUniCharCaseMapDutchDigraph & flags)) ? 0x004A : 0x006A); 941 return 1; 942 } 943 break; 944 945 default: break; 946 } 947 } 948 #endif // DO_SPECIAL_CASE_MAPPING 949 950 if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); 951 952 data = __CFUniCharBitmapDataArray + __CFUniCharMapExternalSetToInternalIndex(__CFUniCharMapCompatibilitySetID(ctype + kCFUniCharHasNonSelfLowercaseCharacterSet)); 953 954 if (planeNo < data->_numPlanes && data->_planes[planeNo] && CFUniCharIsMemberOfBitmap(theChar, data->_planes[planeNo]) && (__CFUniCharCaseMappingTableCounts || __CFUniCharLoadCaseMappingTable())) { 955 uint32_t value = __CFUniCharGetMappedCase((const __CFUniCharCaseMappings *)__CFUniCharCaseMappingTable[ctype], __CFUniCharCaseMappingTableCounts[ctype], theChar); 956 957 if (!value && ctype == kCFUniCharToTitlecase) { 958 value = __CFUniCharGetMappedCase((const __CFUniCharCaseMappings *)__CFUniCharCaseMappingTable[kCFUniCharToUppercase], __CFUniCharCaseMappingTableCounts[kCFUniCharToUppercase], theChar); 959 if (value) ctype = kCFUniCharToUppercase; 960 } 961 962 if (value) { 963 CFIndex count = CFUniCharConvertFlagToCount(value); 964 965 if (count == 1) { 966 if (value & kCFUniCharNonBmpFlag) { 967 if (maxLength > 1) { 968 value = (value & 0xFFFFFF) - 0x10000; 969 *(convertedChar++) = (UTF16Char)(value >> 10) + 0xD800UL; 970 *(convertedChar++) = (UTF16Char)(value & 0x3FF) + 0xDC00UL; 971 return 2; 972 } 973 } else { 974 *convertedChar = (UTF16Char)value; 975 return 1; 976 } 977 } else if (count < maxLength) { 978 const uint32_t *extraMapping = __CFUniCharCaseMappingExtraTable[ctype] + (value & 0xFFFFFF); 979 980 if (value & kCFUniCharNonBmpFlag) { 981 CFIndex copiedLen = 0; 982 983 while (count-- > 0) { 984 value = *(extraMapping++); 985 if (value > 0xFFFF) { 986 if (copiedLen + 2 >= maxLength) break; 987 value = (value & 0xFFFFFF) - 0x10000; 988 convertedChar[copiedLen++] = (UTF16Char)(value >> 10) + 0xD800UL; 989 convertedChar[copiedLen++] = (UTF16Char)(value & 0x3FF) + 0xDC00UL; 990 } else { 991 if (copiedLen + 1 >= maxLength) break; 992 convertedChar[copiedLen++] = value; 993 } 994 } 995 if (!count) return copiedLen; 996 } else { 997 CFIndex idx; 998 999 for (idx = 0;idx < count;idx++) *(convertedChar++) = (UTF16Char)*(extraMapping++); 1000 return count; 1001 } 1002 } 1003 } 1004 } else if (ctype == kCFUniCharCaseFold) { 1005 ctype = kCFUniCharToLowercase; 1006 goto caseFoldRetry; 1007 } 1008 1009 if (theChar > 0xFFFF) { // non-BMP 1010 theChar = (theChar & 0xFFFFFF) - 0x10000; 1011 *(convertedChar++) = (UTF16Char)(theChar >> 10) + 0xD800UL; 1012 *(convertedChar++) = (UTF16Char)(theChar & 0x3FF) + 0xDC00UL; 1013 return 2; 1014 } else { 1015 *convertedChar = theChar; 1016 return 1; 1017 } 1018 } 1019 1020 CFIndex CFUniCharMapTo(UniChar theChar, UniChar *convertedChar, CFIndex maxLength, uint16_t ctype, uint32_t flags) { 1021 if (ctype == kCFUniCharCaseFold + 1) { // kCFUniCharDecompose 1022 if (CFUniCharIsDecomposableCharacter(theChar, false)) { 1023 UTF32Char buffer[MAX_DECOMPOSED_LENGTH]; 1024 CFIndex usedLength = CFUniCharDecomposeCharacter(theChar, buffer, MAX_DECOMPOSED_LENGTH); 1025 CFIndex idx; 1026 1027 for (idx = 0;idx < usedLength;idx++) *(convertedChar++) = buffer[idx]; 1028 return usedLength; 1029 } else { 1030 *convertedChar = theChar; 1031 return 1; 1032 } 1033 } else { 1034 return CFUniCharMapCaseTo(theChar, convertedChar, maxLength, ctype, flags, NULL); 1035 } 1036 } 1037 1038 CF_INLINE bool __CFUniCharIsMoreAbove(UTF16Char *buffer, CFIndex length) { 1039 UTF32Char currentChar; 1040 uint32_t property; 1041 1042 while (length-- > 0) { 1043 currentChar = *(buffer)++; 1044 if (CFUniCharIsSurrogateHighCharacter(currentChar) && (length > 0) && CFUniCharIsSurrogateLowCharacter(*(buffer + 1))) { 1045 currentChar = CFUniCharGetLongCharacterForSurrogatePair(currentChar, *(buffer++)); 1046 --length; 1047 } 1048 if (!CFUniCharIsMemberOf(currentChar, kCFUniCharNonBaseCharacterSet)) break; 1049 1050 property = CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); 1051 1052 if (property == 230) return true; // Above priority 1053 } 1054 return false; 1055 } 1056 1057 CF_INLINE bool __CFUniCharIsAfter_i(UTF16Char *buffer, CFIndex length) { 1058 UTF32Char currentChar = 0; 1059 uint32_t property; 1060 UTF32Char decomposed[MAX_DECOMPOSED_LENGTH]; 1061 CFIndex decompLength; 1062 CFIndex idx; 1063 1064 if (length < 1) return 0; 1065 1066 buffer += length; 1067 while (length-- > 1) { 1068 currentChar = *(--buffer); 1069 if (CFUniCharIsSurrogateLowCharacter(currentChar)) { 1070 if ((length > 1) && CFUniCharIsSurrogateHighCharacter(*(buffer - 1))) { 1071 currentChar = CFUniCharGetLongCharacterForSurrogatePair(*(--buffer), currentChar); 1072 --length; 1073 } else { 1074 break; 1075 } 1076 } 1077 if (!CFUniCharIsMemberOf(currentChar, kCFUniCharNonBaseCharacterSet)) break; 1078 1079 property = CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); 1080 1081 if (property == 230) return false; // Above priority 1082 } 1083 if (length == 0) { 1084 currentChar = *(--buffer); 1085 } else if (CFUniCharIsSurrogateLowCharacter(currentChar) && CFUniCharIsSurrogateHighCharacter(*(--buffer))) { 1086 currentChar = CFUniCharGetLongCharacterForSurrogatePair(*buffer, currentChar); 1087 } 1088 1089 decompLength = CFUniCharDecomposeCharacter(currentChar, decomposed, MAX_DECOMPOSED_LENGTH); 1090 currentChar = *decomposed; 1091 1092 1093 for (idx = 1;idx < decompLength;idx++) { 1094 currentChar = decomposed[idx]; 1095 property = CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); 1096 1097 if (property == 230) return false; // Above priority 1098 } 1099 return true; 1100 } 1101 1102 CF_PRIVATE uint32_t CFUniCharGetConditionalCaseMappingFlags(UTF32Char theChar, UTF16Char *buffer, CFIndex currentIndex, CFIndex length, uint32_t type, const uint8_t *langCode, uint32_t lastFlags) { 1103 if (theChar == 0x03A3) { // GREEK CAPITAL LETTER SIGMA 1104 if ((type == kCFUniCharToLowercase) && (currentIndex > 0)) { 1105 UTF16Char *start = buffer; 1106 UTF16Char *end = buffer + length; 1107 UTF32Char otherChar; 1108 1109 // First check if we're after a cased character 1110 buffer += (currentIndex - 1); 1111 while (start <= buffer) { 1112 otherChar = *(buffer--); 1113 if (CFUniCharIsSurrogateLowCharacter(otherChar) && (start <= buffer) && CFUniCharIsSurrogateHighCharacter(*buffer)) { 1114 otherChar = CFUniCharGetLongCharacterForSurrogatePair(*(buffer--), otherChar); 1115 } 1116 if (!CFUniCharIsMemberOf(otherChar, kCFUniCharCaseIgnorableCharacterSet)) { 1117 if (!CFUniCharIsMemberOf(otherChar, kCFUniCharUppercaseLetterCharacterSet) && !CFUniCharIsMemberOf(otherChar, kCFUniCharLowercaseLetterCharacterSet)) return 0; // Uppercase set contains titlecase 1118 break; 1119 } 1120 } 1121 1122 // Next check if we're before a cased character 1123 buffer = start + currentIndex + 1; 1124 while (buffer < end) { 1125 otherChar = *(buffer++); 1126 if (CFUniCharIsSurrogateHighCharacter(otherChar) && (buffer < end) && CFUniCharIsSurrogateLowCharacter(*buffer)) { 1127 otherChar = CFUniCharGetLongCharacterForSurrogatePair(otherChar, *(buffer++)); 1128 } 1129 if (!CFUniCharIsMemberOf(otherChar, kCFUniCharCaseIgnorableCharacterSet)) { 1130 if (CFUniCharIsMemberOf(otherChar, kCFUniCharUppercaseLetterCharacterSet) || CFUniCharIsMemberOf(otherChar, kCFUniCharLowercaseLetterCharacterSet)) return 0; // Uppercase set contains titlecase 1131 break; 1132 } 1133 } 1134 return kCFUniCharCaseMapFinalSigma; 1135 } 1136 } else if (langCode) { 1137 if (*((const uint16_t *)langCode) == LITHUANIAN_LANG_CODE) { 1138 if ((theChar == 0x0307) && ((kCFUniCharCaseMapAfter_i|kCFUniCharCaseMapMoreAbove) & lastFlags) == (kCFUniCharCaseMapAfter_i|kCFUniCharCaseMapMoreAbove)) { 1139 return (__CFUniCharIsAfter_i(buffer, currentIndex) ? kCFUniCharCaseMapAfter_i : 0); 1140 } else if (type == kCFUniCharToLowercase) { 1141 if ((theChar == 0x0049) || (theChar == 0x004A) || (theChar == 0x012E)) { 1142 ++currentIndex; 1143 return (__CFUniCharIsMoreAbove(buffer + currentIndex, length - currentIndex) ? kCFUniCharCaseMapMoreAbove : 0); 1144 } 1145 } else if ((theChar == 'i') || (theChar == 'j')) { 1146 ++currentIndex; 1147 return (__CFUniCharIsMoreAbove(buffer + currentIndex, length - currentIndex) ? (kCFUniCharCaseMapAfter_i|kCFUniCharCaseMapMoreAbove) : 0); 1148 } 1149 } else if ((*((const uint16_t *)langCode) == TURKISH_LANG_CODE) || (*((const uint16_t *)langCode) == AZERI_LANG_CODE)) { 1150 if (type == kCFUniCharToLowercase) { 1151 if (theChar == 0x0307) { 1152 return (kCFUniCharCaseMapMoreAbove & lastFlags ? kCFUniCharCaseMapAfter_i : 0); 1153 } else if (theChar == 0x0049) { 1154 return (((++currentIndex < length) && (buffer[currentIndex] == 0x0307)) ? kCFUniCharCaseMapMoreAbove : 0); 1155 } 1156 } 1157 } else if (*((const uint16_t *)langCode) == DUTCH_LANG_CODE) { 1158 if (kCFUniCharCaseMapDutchDigraph & lastFlags) { 1159 return (((theChar == 0x006A) || (theChar == 0x004A)) ? kCFUniCharCaseMapDutchDigraph : 0); 1160 } else { 1161 if ((type == kCFUniCharToTitlecase) && ((theChar == 0x0069) || (theChar == 0x0049))) { 1162 return (((++currentIndex < length) && ((buffer[currentIndex] == 0x006A) || (buffer[currentIndex] == 0x004A))) ? kCFUniCharCaseMapDutchDigraph : 0); 1163 } 1164 } 1165 } 1166 1167 if (kCFUniCharCaseMapGreekTonos & lastFlags) { // still searching for tonos 1168 if (CFUniCharIsMemberOf(theChar, kCFUniCharNonBaseCharacterSet)) { 1169 return kCFUniCharCaseMapGreekTonos; 1170 } 1171 } 1172 if (((theChar >= 0x0370) && (theChar < 0x0400)) || ((theChar >= 0x1F00) && (theChar < 0x2000))) { // Greek/Coptic & Greek extended ranges 1173 if ((type == kCFUniCharToUppercase) && (CFUniCharIsMemberOf(theChar, kCFUniCharLetterCharacterSet))) return kCFUniCharCaseMapGreekTonos; 1174 } 1175 } 1176 return 0; 1177 } 1178 1179 // Unicode property database 1180 static __CFUniCharBitmapData *__CFUniCharUnicodePropertyTable = NULL; 1181 static int __CFUniCharUnicodePropertyTableCount = 0; 1182 1183 static CFLock_t __CFUniCharPropTableLock = CFLockInit; 1184 1185 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX 1186 #if USE_MACHO_SEGMENT 1187 #define PROP_DB_FILE "__properties" 1188 #else 1189 #define PROP_DB_FILE "/CFUniCharPropertyDatabase.data" 1190 #endif 1191 #elif DEPLOYMENT_TARGET_WINDOWS 1192 #if USE_MACHO_SEGMENT 1193 #define PROP_DB_FILE "__properties" 1194 #else 1195 #define PROP_DB_FILE L"CFUniCharPropertyDatabase.data" 1196 #endif 1197 #else 1198 #error Unknown or unspecified DEPLOYMENT_TARGET 1199 #endif 1200 1201 const void *CFUniCharGetUnicodePropertyDataForPlane(uint32_t propertyType, uint32_t plane) { 1202 1203 __CFLock(&__CFUniCharPropTableLock); 1204 1205 if (NULL == __CFUniCharUnicodePropertyTable) { 1206 __CFUniCharBitmapData *table; 1207 const void *bytes; 1208 const void *bodyBase; 1209 const void *planeBase; 1210 int headerSize; 1211 int idx, count; 1212 int planeIndex, planeCount; 1213 int planeSize; 1214 int64_t fileSize; 1215 1216 if (!__CFUniCharLoadFile(PROP_DB_FILE, &bytes, &fileSize) || !__CFSimpleFileSizeVerification(bytes, fileSize)) { 1217 __CFUnlock(&__CFUniCharPropTableLock); 1218 return NULL; 1219 } 1220 1221 #if defined (__cplusplus) 1222 bytes = (uint8_t*)bytes + 4; // Skip Unicode version 1223 headerSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes = (uint8_t *)bytes + sizeof(uint32_t); 1224 #else 1225 bytes += 4; // Skip Unicode version 1226 headerSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes += sizeof(uint32_t); 1227 #endif 1228 1229 headerSize -= (sizeof(uint32_t) * 2); 1230 bodyBase = (char *)bytes + headerSize; 1231 1232 count = headerSize / sizeof(uint32_t); 1233 __CFUniCharUnicodePropertyTableCount = count; 1234 1235 table = (__CFUniCharBitmapData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFUniCharBitmapData) * count, 0); 1236 1237 for (idx = 0;idx < count;idx++) { 1238 planeCount = *((const uint8_t *)bodyBase); 1239 planeBase = (char *)bodyBase + planeCount + (planeCount % 4 ? 4 - (planeCount % 4) : 0); 1240 table[idx]._planes = (const uint8_t **)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(const void *) * planeCount, 0); 1241 1242 for (planeIndex = 0;planeIndex < planeCount;planeIndex++) { 1243 if ((planeSize = ((const uint8_t *)bodyBase)[planeIndex + 1])) { 1244 table[idx]._planes[planeIndex] = (const uint8_t *)planeBase; 1245 #if defined (__cplusplus) 1246 planeBase = (char*)planeBase + (planeSize * 256); 1247 #else 1248 planeBase += (planeSize * 256); 1249 #endif 1250 } else { 1251 table[idx]._planes[planeIndex] = NULL; 1252 } 1253 } 1254 1255 table[idx]._numPlanes = planeCount; 1256 #if defined (__cplusplus) 1257 bodyBase = (const uint8_t *)bodyBase + (CFSwapInt32BigToHost(*(uint32_t *)bytes)); 1258 ((uint32_t *&)bytes) ++; 1259 #else 1260 bodyBase += (CFSwapInt32BigToHost(*((uint32_t *)bytes++))); 1261 #endif 1262 } 1263 1264 __CFUniCharUnicodePropertyTable = table; 1265 } 1266 1267 __CFUnlock(&__CFUniCharPropTableLock); 1268 1269 return (plane < __CFUniCharUnicodePropertyTable[propertyType]._numPlanes ? __CFUniCharUnicodePropertyTable[propertyType]._planes[plane] : NULL); 1270 } 1271 1272 CF_PRIVATE uint32_t CFUniCharGetNumberOfPlanesForUnicodePropertyData(uint32_t propertyType) { 1273 (void)CFUniCharGetUnicodePropertyDataForPlane(propertyType, 0); 1274 return __CFUniCharUnicodePropertyTable[propertyType]._numPlanes; 1275 } 1276 1277 CF_PRIVATE uint32_t CFUniCharGetUnicodeProperty(UTF32Char character, uint32_t propertyType) { 1278 if (propertyType == kCFUniCharCombiningProperty) { 1279 return CFUniCharGetCombiningPropertyForCharacter(character, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(propertyType, (character >> 16) & 0xFF)); 1280 } else if (propertyType == kCFUniCharBidiProperty) { 1281 return CFUniCharGetBidiPropertyForCharacter(character, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(propertyType, (character >> 16) & 0xFF)); 1282 } else { 1283 return 0; 1284 } 1285 } 1286 1287 1288 1289 /* 1290 The UTF8 conversion in the following function is derived from ConvertUTF.c 1291 */ 1292 /* 1293 * Copyright 2001 Unicode, Inc. 1294 * 1295 * Disclaimer 1296 * 1297 * This source code is provided as is by Unicode, Inc. No claims are 1298 * made as to fitness for any particular purpose. No warranties of any 1299 * kind are expressed or implied. The recipient agrees to determine 1300 * applicability of information provided. If this file has been 1301 * purchased on magnetic or optical media from Unicode, Inc., the 1302 * sole remedy for any claim will be exchange of defective media 1303 * within 90 days of receipt. 1304 * 1305 * Limitations on Rights to Redistribute This Code 1306 * 1307 * Unicode, Inc. hereby grants the right to freely use the information 1308 * supplied in this file in the creation of products supporting the 1309 * Unicode Standard, and to make copies of this file in any form 1310 * for internal or external distribution as long as this notice 1311 * remains attached. 1312 */ 1313 #define UNI_REPLACEMENT_CHAR (0x0000FFFDUL) 1314 1315 bool CFUniCharFillDestinationBuffer(const UTF32Char *src, CFIndex srcLength, void **dst, CFIndex dstLength, CFIndex *filledLength, uint32_t dstFormat) { 1316 UTF32Char currentChar; 1317 CFIndex usedLength = *filledLength; 1318 1319 if (dstFormat == kCFUniCharUTF16Format) { 1320 UTF16Char *dstBuffer = (UTF16Char *)*dst; 1321 1322 while (srcLength-- > 0) { 1323 currentChar = *(src++); 1324 1325 if (currentChar > 0xFFFF) { // Non-BMP 1326 usedLength += 2; 1327 if (dstLength) { 1328 if (usedLength > dstLength) return false; 1329 currentChar -= 0x10000; 1330 *(dstBuffer++) = (UTF16Char)((currentChar >> 10) + 0xD800UL); 1331 *(dstBuffer++) = (UTF16Char)((currentChar & 0x3FF) + 0xDC00UL); 1332 } 1333 } else { 1334 ++usedLength; 1335 if (dstLength) { 1336 if (usedLength > dstLength) return false; 1337 *(dstBuffer++) = (UTF16Char)currentChar; 1338 } 1339 } 1340 } 1341 1342 *dst = dstBuffer; 1343 } else if (dstFormat == kCFUniCharUTF8Format) { 1344 uint8_t *dstBuffer = (uint8_t *)*dst; 1345 uint16_t bytesToWrite = 0; 1346 const UTF32Char byteMask = 0xBF; 1347 const UTF32Char byteMark = 0x80; 1348 static const uint8_t firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 1349 1350 while (srcLength-- > 0) { 1351 currentChar = *(src++); 1352 1353 /* Figure out how many bytes the result will require */ 1354 if (currentChar < (UTF32Char)0x80) { 1355 bytesToWrite = 1; 1356 } else if (currentChar < (UTF32Char)0x800) { 1357 bytesToWrite = 2; 1358 } else if (currentChar < (UTF32Char)0x10000) { 1359 bytesToWrite = 3; 1360 } else if (currentChar < (UTF32Char)0x200000) { 1361 bytesToWrite = 4; 1362 } else { 1363 bytesToWrite = 2; 1364 currentChar = UNI_REPLACEMENT_CHAR; 1365 } 1366 1367 usedLength += bytesToWrite; 1368 1369 if (dstLength) { 1370 if (usedLength > dstLength) return false; 1371 1372 dstBuffer += bytesToWrite; 1373 switch (bytesToWrite) { /* note: everything falls through. */ 1374 case 4: *--dstBuffer = (currentChar | byteMark) & byteMask; currentChar >>= 6; 1375 case 3: *--dstBuffer = (currentChar | byteMark) & byteMask; currentChar >>= 6; 1376 case 2: *--dstBuffer = (currentChar | byteMark) & byteMask; currentChar >>= 6; 1377 case 1: *--dstBuffer = currentChar | firstByteMark[bytesToWrite]; 1378 } 1379 dstBuffer += bytesToWrite; 1380 } 1381 } 1382 1383 *dst = dstBuffer; 1384 } else { 1385 UTF32Char *dstBuffer = (UTF32Char *)*dst; 1386 1387 while (srcLength-- > 0) { 1388 currentChar = *(src++); 1389 1390 ++usedLength; 1391 if (dstLength) { 1392 if (usedLength > dstLength) return false; 1393 *(dstBuffer++) = currentChar; 1394 } 1395 } 1396 1397 *dst = dstBuffer; 1398 } 1399 1400 *filledLength = usedLength; 1401 1402 return true; 1403 } 1404 1405 #if DEPLOYMENT_TARGET_WINDOWS 1406 void __CFUniCharCleanup(void) 1407 { 1408 int idx; 1409 1410 // cleanup memory allocated by __CFUniCharLoadBitmapData() 1411 __CFLock(&__CFUniCharBitmapLock); 1412 1413 if (__CFUniCharBitmapDataArray != NULL) { 1414 for (idx = 0; idx < (int)__CFUniCharNumberOfBitmaps; idx++) { 1415 CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharBitmapDataArray[idx]._planes); 1416 __CFUniCharBitmapDataArray[idx]._planes = NULL; 1417 } 1418 1419 CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharBitmapDataArray); 1420 __CFUniCharBitmapDataArray = NULL; 1421 __CFUniCharNumberOfBitmaps = 0; 1422 } 1423 1424 __CFUnlock(&__CFUniCharBitmapLock); 1425 1426 // cleanup memory allocated by CFUniCharGetMappingData() 1427 __CFLock(&__CFUniCharMappingTableLock); 1428 1429 if (__CFUniCharMappingTables != NULL) { 1430 CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharMappingTables); 1431 __CFUniCharMappingTables = NULL; 1432 } 1433 1434 // cleanup memory allocated by __CFUniCharLoadCaseMappingTable() 1435 if (__CFUniCharCaseMappingTableCounts != NULL) { 1436 CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharCaseMappingTableCounts); 1437 __CFUniCharCaseMappingTableCounts = NULL; 1438 1439 __CFUniCharCaseMappingTable = NULL; 1440 __CFUniCharCaseMappingExtraTable = NULL; 1441 } 1442 1443 __CFUnlock(&__CFUniCharMappingTableLock); 1444 1445 // cleanup memory allocated by CFUniCharGetUnicodePropertyDataForPlane() 1446 __CFLock(&__CFUniCharPropTableLock); 1447 1448 if (__CFUniCharUnicodePropertyTable != NULL) { 1449 for (idx = 0; idx < __CFUniCharUnicodePropertyTableCount; idx++) { 1450 CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharUnicodePropertyTable[idx]._planes); 1451 __CFUniCharUnicodePropertyTable[idx]._planes = NULL; 1452 } 1453 1454 CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharUnicodePropertyTable); 1455 __CFUniCharUnicodePropertyTable = NULL; 1456 __CFUniCharUnicodePropertyTableCount = 0; 1457 } 1458 1459 __CFUnlock(&__CFUniCharPropTableLock); 1460 } 1461 #endif 1462 1463 #undef USE_MACHO_SEGMENT 1464