2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* CFUnicodeDecomposition.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Aki Inoue
33 #include "CFUnicodeDecomposition.h"
34 #include "CFUniCharNonBaseData.h"
35 #include "CFUniCharDecompData.h"
36 #include "CFUniCharCombiningPriorityData.h"
38 #include <CoreFoundation/CFBase.h>
39 #include <CoreFoundation/CFCharacterSet.h>
40 #include "CFUniChar.h"
41 #include "CFUnicodeDecomposition.h"
42 #include "CFInternal.h"
43 #include "CFUniCharPriv.h"
46 // Canonical Decomposition
48 static const uint32_t __CFUniCharDecompositionTableLength
= (sizeof(__CFUniCharDecompositionTable
) / (sizeof(uint32_t) * 2));
49 // The kernel version of __CFUniCharIsDecomposableCharacter doesn't have exception ranges
50 #define __CFUniCharIsDecomposableCharacterWithFlag(character,isHFSPlus) (__CFUniCharIsDecomposableCharacter(character))
52 uint8_t **CFUniCharCombiningPriorityTable
= __CFUniCharCombiningPriorityTable
;
53 uint8_t **CFUniCharCombiningPriorityExtraTable
= __CFUniCharCombiningPriorityExtraTable
;
54 uint8_t CFUniCharNumberOfPlanesForCombiningPriority
= sizeof(__CFUniCharCombiningPriorityTable
) / sizeof(*__CFUniCharCombiningPriorityTable
);
55 uint8_t **CFUniCharNonBaseBitmap
= __CFUniCharNonBaseBitmap
;
56 uint8_t CFUniCharNumberOfPlanesForNonBaseBitmap
= sizeof(__CFUniCharNonBaseBitmap
) / sizeof(*__CFUniCharNonBaseBitmap
);
58 static UTF32Char
*__CFUniCharDecompositionTable
= NULL
;
59 static uint32_t __CFUniCharDecompositionTableLength
= 0;
60 static UTF32Char
*__CFUniCharMultipleDecompositionTable
= NULL
;
62 static const uint8_t *__CFUniCharDecomposableBitmapForBMP
= NULL
;
63 static const uint8_t *__CFUniCharHFSPlusDecomposableBitmapForBMP
= NULL
;
64 static const uint8_t *__CFUniCharNonBaseBitmapForBMP
= NULL
;
66 static CFSpinLock_t __CFUniCharDecompositionTableLock
= 0;
68 static const uint8_t **__CFUniCharCombiningPriorityTable
= NULL
;
69 static uint8_t __CFUniCharCombiningPriorityTableNumPlane
= 0;
71 static void __CFUniCharLoadDecompositionTable(void) {
73 __CFSpinLock(&__CFUniCharDecompositionTableLock
);
75 if (NULL
== __CFUniCharDecompositionTable
) {
76 const void *bytes
= CFUniCharGetMappingData(kCFUniCharCanonicalDecompMapping
);
79 __CFSpinUnlock(&__CFUniCharDecompositionTableLock
);
83 __CFUniCharDecompositionTableLength
= *(((uint32_t *)bytes
)++);
84 __CFUniCharDecompositionTable
= (UTF32Char
*)bytes
;
85 __CFUniCharMultipleDecompositionTable
= (UTF32Char
*)((intptr_t)bytes
+ __CFUniCharDecompositionTableLength
);
87 __CFUniCharDecompositionTableLength
/= (sizeof(uint32_t) * 2);
88 __CFUniCharDecomposableBitmapForBMP
= CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet
, 0);
89 __CFUniCharHFSPlusDecomposableBitmapForBMP
= CFUniCharGetBitmapPtrForPlane(kCFUniCharHFSPlusDecomposableCharacterSet
, 0);
90 __CFUniCharNonBaseBitmapForBMP
= CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet
, 0);
93 __CFSpinUnlock(&__CFUniCharDecompositionTableLock
);
96 static CFSpinLock_t __CFUniCharCompatibilityDecompositionTableLock
= 0;
97 static UTF32Char
*__CFUniCharCompatibilityDecompositionTable
= NULL
;
98 static uint32_t __CFUniCharCompatibilityDecompositionTableLength
= 0;
99 static UTF32Char
*__CFUniCharCompatibilityMultipleDecompositionTable
= NULL
;
101 static void __CFUniCharLoadCompatibilityDecompositionTable(void) {
103 __CFSpinLock(&__CFUniCharCompatibilityDecompositionTableLock
);
105 if (NULL
== __CFUniCharCompatibilityDecompositionTable
) {
106 const void *bytes
= CFUniCharGetMappingData(kCFUniCharCompatibilityDecompMapping
);
109 __CFSpinUnlock(&__CFUniCharCompatibilityDecompositionTableLock
);
113 __CFUniCharCompatibilityDecompositionTableLength
= *(((uint32_t *)bytes
)++);
114 __CFUniCharCompatibilityDecompositionTable
= (UTF32Char
*)bytes
;
115 __CFUniCharCompatibilityMultipleDecompositionTable
= (UTF32Char
*)((intptr_t)bytes
+ __CFUniCharCompatibilityDecompositionTableLength
);
117 __CFUniCharCompatibilityDecompositionTableLength
/= (sizeof(uint32_t) * 2);
120 __CFSpinUnlock(&__CFUniCharCompatibilityDecompositionTableLock
);
123 CF_INLINE
bool __CFUniCharIsDecomposableCharacterWithFlag(UTF32Char character
, bool isHFSPlus
) {
124 return CFUniCharIsMemberOfBitmap(character
, (character
< 0x10000 ? (isHFSPlus
? __CFUniCharHFSPlusDecomposableBitmapForBMP
: __CFUniCharDecomposableBitmapForBMP
) : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet
, ((character
>> 16) & 0xFF))));
127 CF_INLINE
bool __CFUniCharIsNonBaseCharacter(UTF32Char character
) {
128 return CFUniCharIsMemberOfBitmap(character
, (character
< 0x10000 ? __CFUniCharNonBaseBitmapForBMP
: CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet
, ((character
>> 16) & 0xFF))));
135 } __CFUniCharDecomposeMappings
;
137 static uint32_t __CFUniCharGetMappedValue(const __CFUniCharDecomposeMappings
*theTable
, uint32_t numElem
, UTF32Char character
) {
138 const __CFUniCharDecomposeMappings
*p
, *q
, *divider
;
140 if ((character
< theTable
[0]._key
) || (character
> theTable
[numElem
-1]._key
)) {
146 divider
= p
+ ((q
- p
) >> 1); /* divide by 2 */
147 if (character
< divider
->_key
) { q
= divider
- 1; }
148 else if (character
> divider
->_key
) { p
= divider
+ 1; }
149 else { return divider
->_value
; }
155 #define __CFUniCharGetCombiningPropertyForCharacter(character) __CFUniCharGetCombiningPriority(character)
157 #define __CFUniCharGetCombiningPropertyForCharacter(character) CFUniCharGetCombiningPropertyForCharacter(character, (((character) >> 16) < __CFUniCharCombiningPriorityTableNumPlane ? __CFUniCharCombiningPriorityTable[(character) >> 16] : NULL))
160 static void __CFUniCharPrioritySort(UTF32Char
*characters
, uint32_t length
) {
162 UTF32Char
*ch1
, *ch2
;
164 UTF32Char
*end
= characters
+ length
;
167 if (NULL
== __CFUniCharCombiningPriorityTable
) {
168 __CFSpinLock(&__CFUniCharDecompositionTableLock
);
169 if (NULL
== __CFUniCharCombiningPriorityTable
) {
170 uint32_t numPlanes
= CFUniCharGetNumberOfPlanesForUnicodePropertyData(kCFUniCharCombiningProperty
);
173 __CFUniCharCombiningPriorityTable
= (const uint8_t **)CFAllocatorAllocate(NULL
, sizeof(uint8_t *) * numPlanes
, 0);
174 for (idx
= 0;idx
< numPlanes
;idx
++) __CFUniCharCombiningPriorityTable
[idx
] = CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty
, idx
);
175 __CFUniCharCombiningPriorityTableNumPlane
= numPlanes
;
177 __CFSpinUnlock(&__CFUniCharDecompositionTableLock
);
181 if (length
< 2) return;
185 ch1
= characters
; ch2
= characters
+ 1;
186 p2
= __CFUniCharGetCombiningPropertyForCharacter(*ch1
);
188 p1
= p2
; p2
= __CFUniCharGetCombiningPropertyForCharacter(*ch2
);
190 UTF32Char tmp
= *ch1
; *ch1
= *ch2
; *ch2
= tmp
;
198 static uint32_t __CFUniCharRecursivelyDecomposeCharacter(UTF32Char character
, UTF32Char
*convertedChars
, uint32_t maxBufferLength
) {
199 uint32_t value
= __CFUniCharGetMappedValue((const __CFUniCharDecomposeMappings
*)__CFUniCharDecompositionTable
, __CFUniCharDecompositionTableLength
, character
);
200 uint32_t length
= CFUniCharConvertFlagToCount(value
);
201 UTF32Char firstChar
= value
& 0xFFFFFF;
203 const UTF32Char
*mappings
= (kCFUniCharNonBmpFlag
& value
? (length
== 1 ? &firstChar
: __CFUniCharNonBMPMultipleDecompositionTable
+ firstChar
) : NULL
);
204 UTF16Char theChar
= (UTF16Char
)firstChar
;
205 const UTF16Char
*bmpMappings
= (mappings
? NULL
: (length
== 1 ? &theChar
: __CFUniCharMultipleDecompositionTable
+ firstChar
));
207 UTF32Char
*mappings
= (length
> 1 ? __CFUniCharMultipleDecompositionTable
+ firstChar
: &firstChar
);
209 uint32_t usedLength
= 0;
211 if (maxBufferLength
< length
) return 0;
215 if (value
& kCFUniCharRecursiveDecompositionFlag
) {
216 usedLength
= __CFUniCharRecursivelyDecomposeCharacter((UTF32Char
)*bmpMappings
, convertedChars
, maxBufferLength
- length
);
218 --length
; // Decrement for the first char
219 if (!usedLength
|| usedLength
+ length
> maxBufferLength
) return 0;
221 convertedChars
+= usedLength
;
224 usedLength
+= length
;
226 while (length
--) *(convertedChars
++) = *(bmpMappings
++);
231 if (value
& kCFUniCharRecursiveDecompositionFlag
) {
232 usedLength
= __CFUniCharRecursivelyDecomposeCharacter(*mappings
, convertedChars
, maxBufferLength
- length
);
234 --length
; // Decrement for the first char
235 if (!usedLength
|| usedLength
+ length
> maxBufferLength
) return 0;
237 convertedChars
+= usedLength
;
240 usedLength
+= length
;
242 while (length
--) *(convertedChars
++) = *(mappings
++);
247 #define HANGUL_SBASE 0xAC00
248 #define HANGUL_LBASE 0x1100
249 #define HANGUL_VBASE 0x1161
250 #define HANGUL_TBASE 0x11A7
251 #define HANGUL_SCOUNT 11172
252 #define HANGUL_LCOUNT 19
253 #define HANGUL_VCOUNT 21
254 #define HANGUL_TCOUNT 28
255 #define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT)
257 uint32_t CFUniCharDecomposeCharacter(UTF32Char character
, UTF32Char
*convertedChars
, uint32_t maxBufferLength
) {
259 if (NULL
== __CFUniCharDecompositionTable
) __CFUniCharLoadDecompositionTable();
261 if (character
>= HANGUL_SBASE
&& character
<= (HANGUL_SBASE
+ HANGUL_SCOUNT
)) {
264 character
-= HANGUL_SBASE
;
266 length
= (character
% HANGUL_TCOUNT
? 3 : 2);
268 if (maxBufferLength
< length
) return 0;
270 *(convertedChars
++) = character
/ HANGUL_NCOUNT
+ HANGUL_LBASE
;
271 *(convertedChars
++) = (character
% HANGUL_NCOUNT
) / HANGUL_TCOUNT
+ HANGUL_VBASE
;
272 if (length
> 2) *convertedChars
= (character
% HANGUL_TCOUNT
) + HANGUL_TBASE
;
275 return __CFUniCharRecursivelyDecomposeCharacter(character
, convertedChars
, maxBufferLength
);
280 #define CFAllocatorAllocate(a,size,flag) malloc((size))
281 #define CFAllocatorDeallocate(a,ptr) free((ptr))
284 #define MAX_BUFFER_LENGTH (32)
285 bool CFUniCharDecompose(const UTF16Char
*src
, uint32_t length
, uint32_t *consumedLength
, void *dst
, uint32_t maxLength
, uint32_t *filledLength
, bool needToReorder
, uint32_t dstFormat
, bool isHFSPlus
) {
286 uint32_t usedLength
= 0;
287 uint32_t originalLength
= length
;
288 UTF32Char buffer
[MAX_BUFFER_LENGTH
];
289 UTF32Char
*decompBuffer
= buffer
;
290 uint32_t decompBufferLen
= MAX_BUFFER_LENGTH
;
291 UTF32Char currentChar
;
293 bool isDecomp
= false;
294 bool isNonBase
= false;
297 if (NULL
== __CFUniCharDecompositionTable
) __CFUniCharLoadDecompositionTable();
301 currentChar
= *(src
++);
304 if (currentChar
< 0x80) {
306 if (usedLength
< maxLength
) {
308 case kCFUniCharUTF8Format
: *(((uint8_t *)dst
)++) = currentChar
; break;
309 case kCFUniCharUTF16Format
: *(((UTF16Char
*)dst
)++) = currentChar
; break;
310 case kCFUniCharUTF32Format
: *(((UTF32Char
*)dst
)++) = currentChar
; break;
313 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
314 if (consumedLength
) *consumedLength
= originalLength
- length
- 1;
315 if (filledLength
) *filledLength
= usedLength
;
323 if (CFUniCharIsSurrogateHighCharacter(currentChar
) && (length
> 0) && CFUniCharIsSurrogateLowCharacter(*src
)) {
324 currentChar
= CFUniCharGetLongCharacterForSurrogatePair(currentChar
, *(src
++));
328 isDecomp
= __CFUniCharIsDecomposableCharacterWithFlag(currentChar
, isHFSPlus
);
329 isNonBase
= (needToReorder
&& __CFUniCharIsNonBaseCharacter(currentChar
));
331 if (!isDecomp
|| isNonBase
) {
334 idx
= CFUniCharDecomposeCharacter(currentChar
, decompBuffer
, MAX_BUFFER_LENGTH
);
337 *decompBuffer
= currentChar
;
341 if (CFUniCharIsSurrogateHighCharacter(*src
) && ((length
+ 1) > 0) && CFUniCharIsSurrogateLowCharacter(*(src
+ 1))) {
342 currentChar
= CFUniCharGetLongCharacterForSurrogatePair(*src
, *(src
+ 1));
346 if (__CFUniCharIsNonBaseCharacter(currentChar
)) {
347 if (currentChar
> 0xFFFF) { // Non-BMP
354 if ((idx
+ 1) >= decompBufferLen
) {
355 UTF32Char
*newBuffer
;
357 decompBufferLen
+= MAX_BUFFER_LENGTH
;
358 newBuffer
= (UTF32Char
*)CFAllocatorAllocate(NULL
, sizeof(UTF32Char
) * decompBufferLen
, 0);
359 memmove(newBuffer
, decompBuffer
, (decompBufferLen
- MAX_BUFFER_LENGTH
) * sizeof(UTF32Char
));
360 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
361 decompBuffer
= newBuffer
;
364 if (__CFUniCharIsDecomposableCharacterWithFlag(currentChar
, isHFSPlus
)) { // Vietnamese accent, etc.
365 idx
+= CFUniCharDecomposeCharacter(currentChar
, decompBuffer
+ idx
, MAX_BUFFER_LENGTH
- idx
);
367 decompBuffer
[idx
++] = currentChar
;
374 if (idx
> 1) { // Need to reorder
375 __CFUniCharPrioritySort(decompBuffer
, idx
);
377 if (!CFUniCharFillDestinationBuffer(decompBuffer
, idx
, &dst
, maxLength
, &usedLength
, dstFormat
)) {
378 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
379 if (consumedLength
) *consumedLength
= originalLength
- length
;
380 if (filledLength
) *filledLength
= usedLength
;
384 if (dstFormat
== kCFUniCharUTF32Format
) {
387 if (usedLength
> maxLength
) {
388 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
389 if (consumedLength
) *consumedLength
= originalLength
- length
;
390 if (filledLength
) *filledLength
= usedLength
;
393 *(((UTF32Char
*)dst
)++) = currentChar
;
396 if (!CFUniCharFillDestinationBuffer(¤tChar
, 1, &dst
, maxLength
, &usedLength
, dstFormat
)) {
397 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
398 if (consumedLength
) *consumedLength
= originalLength
- length
;
399 if (filledLength
) *filledLength
= usedLength
;
405 if (dstFormat
== kCFUniCharUTF32Format
&& maxLength
) {
406 idx
= CFUniCharDecomposeCharacter(currentChar
, dst
, maxLength
- usedLength
);
409 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
410 if (consumedLength
) *consumedLength
= originalLength
- length
;
411 if (filledLength
) *filledLength
= usedLength
;
413 } else if (needToReorder
&& (idx
> 1)) { // Need to reorder
414 bool moreCombiningMarks
= false;
415 ++((UTF32Char
*)dst
); --idx
; ++usedLength
; // Skip the base
418 if (CFUniCharIsSurrogateHighCharacter(*src
) && ((length
+ 1) > 0) && CFUniCharIsSurrogateLowCharacter(*(src
+ 1))) {
419 currentChar
= CFUniCharGetLongCharacterForSurrogatePair(*src
, *(src
+ 1));
423 if (__CFUniCharIsNonBaseCharacter(currentChar
)) {
424 if (currentChar
> 0xFFFF) { // Non-BMP
431 if ((idx
+ usedLength
+ 1) >= maxLength
) {
432 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
433 if (consumedLength
) *consumedLength
= originalLength
- length
;
434 if (filledLength
) *filledLength
= usedLength
;
437 ((UTF32Char
*)dst
)[idx
++] = currentChar
;
438 moreCombiningMarks
= true;
443 if (moreCombiningMarks
) __CFUniCharPrioritySort(((UTF32Char
*)dst
), idx
);
447 ((UTF32Char
*)dst
) += idx
;
449 idx
= CFUniCharDecomposeCharacter(currentChar
, decompBuffer
, decompBufferLen
);
451 if (maxLength
&& idx
+ usedLength
> maxLength
) {
452 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
453 if (consumedLength
) *consumedLength
= originalLength
- length
;
454 if (filledLength
) *filledLength
= usedLength
;
456 } else if (needToReorder
&& (idx
> 1)) { // Need to reorder
457 bool moreCombiningMarks
= false;
460 if (CFUniCharIsSurrogateHighCharacter(*src
) && ((length
+ 1) > 0) && CFUniCharIsSurrogateLowCharacter(*(src
+ 1))) {
461 currentChar
= CFUniCharGetLongCharacterForSurrogatePair(*src
, *(src
+ 1));
465 if (__CFUniCharIsNonBaseCharacter(currentChar
)) {
466 if (currentChar
> 0xFFFF) { // Non-BMP
473 if ((idx
+ 1) >= decompBufferLen
) {
474 UTF32Char
*newBuffer
;
476 decompBufferLen
+= MAX_BUFFER_LENGTH
;
477 newBuffer
= (UTF32Char
*)CFAllocatorAllocate(NULL
, sizeof(UTF32Char
) * decompBufferLen
, 0);
478 memmove(newBuffer
, decompBuffer
, (decompBufferLen
- MAX_BUFFER_LENGTH
) * sizeof(UTF32Char
));
479 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
480 decompBuffer
= newBuffer
;
482 decompBuffer
[idx
++] = currentChar
;
483 moreCombiningMarks
= true;
488 if (moreCombiningMarks
) __CFUniCharPrioritySort(decompBuffer
+ 1, idx
- 1);
490 if (!CFUniCharFillDestinationBuffer(decompBuffer
, idx
, &dst
, maxLength
, &usedLength
, dstFormat
)) {
491 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
492 if (consumedLength
) *consumedLength
= originalLength
- length
;
493 if (filledLength
) *filledLength
= usedLength
;
499 if (decompBuffer
!= buffer
) CFAllocatorDeallocate(NULL
, decompBuffer
);
501 if (consumedLength
) *consumedLength
= originalLength
- length
;
502 if (filledLength
) *filledLength
= usedLength
;
509 #define MAX_COMP_DECOMP_LEN (32)
511 static uint32_t __CFUniCharRecursivelyCompatibilityDecomposeCharacter(UTF32Char character
, UTF32Char
*convertedChars
) {
512 uint32_t value
= __CFUniCharGetMappedValue((const __CFUniCharDecomposeMappings
*)__CFUniCharCompatibilityDecompositionTable
, __CFUniCharCompatibilityDecompositionTableLength
, character
);
513 uint32_t length
= CFUniCharConvertFlagToCount(value
);
514 UTF32Char firstChar
= value
& 0xFFFFFF;
515 const UTF32Char
*mappings
= (length
> 1 ? __CFUniCharCompatibilityMultipleDecompositionTable
+ firstChar
: &firstChar
);
516 uint32_t usedLength
= length
;
517 UTF32Char currentChar
;
518 uint32_t currentLength
;
520 while (length
-- > 0) {
521 currentChar
= *(mappings
++);
522 if (__CFUniCharIsDecomposableCharacterWithFlag(currentChar
, false)) {
523 currentLength
= __CFUniCharRecursivelyDecomposeCharacter(currentChar
, convertedChars
, MAX_COMP_DECOMP_LEN
- length
);
524 convertedChars
+= currentLength
;
525 usedLength
+= (currentLength
- 1);
526 } else if (CFUniCharIsMemberOf(currentChar
, kCFUniCharCompatibilityDecomposableCharacterSet
)) {
527 currentLength
= __CFUniCharRecursivelyCompatibilityDecomposeCharacter(currentChar
, convertedChars
);
528 convertedChars
+= currentLength
;
529 usedLength
+= (currentLength
- 1);
531 *(convertedChars
++) = currentChar
;
538 CF_INLINE
void __CFUniCharMoveBufferFromEnd(UTF32Char
*convertedChars
, uint32_t length
, uint32_t delta
) {
539 const UTF32Char
*limit
= convertedChars
;
542 convertedChars
+= length
;
543 dstP
= convertedChars
+ delta
;
545 while (convertedChars
> limit
) *(--dstP
) = *(--convertedChars
);
548 __private_extern__
uint32_t CFUniCharCompatibilityDecompose(UTF32Char
*convertedChars
, uint32_t length
, uint32_t maxBufferLength
) {
549 UTF32Char currentChar
;
550 UTF32Char buffer
[MAX_COMP_DECOMP_LEN
];
551 const UTF32Char
*bufferP
;
552 const UTF32Char
*limit
= convertedChars
+ length
;
553 uint32_t filledLength
;
555 if (NULL
== __CFUniCharCompatibilityDecompositionTable
) __CFUniCharLoadCompatibilityDecompositionTable();
557 while (convertedChars
< limit
) {
558 currentChar
= *convertedChars
;
560 if (CFUniCharIsMemberOf(currentChar
, kCFUniCharCompatibilityDecomposableCharacterSet
)) {
561 filledLength
= __CFUniCharRecursivelyCompatibilityDecomposeCharacter(currentChar
, buffer
);
563 if (filledLength
+ length
- 1 > maxBufferLength
) return 0;
565 if (filledLength
> 1) __CFUniCharMoveBufferFromEnd(convertedChars
+ 1, limit
- convertedChars
- 1, filledLength
- 1);
568 length
+= (filledLength
- 1);
569 while (filledLength
-- > 0) *(convertedChars
++) = *(bufferP
++);
578 CF_EXPORT
void CFUniCharPrioritySort(UTF32Char
*characters
, uint32_t length
) {
579 __CFUniCharPrioritySort(characters
, length
);