/ 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