2 *******************************************************************************
3 * Copyright (C) 1996-2012, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
8 * tab size: 8 (not used)
11 * Modification history
13 * 1996-1999 various members of ICU team maintained C API for collation framework
14 * 02/16/2001 synwee Added internal method getPrevSpecialCE
15 * 03/01/2001 synwee Added maxexpansion functionality.
16 * 03/16/2001 weiv Collation framework is rewritten in C and made UCA compliant
19 #include "unicode/utypes.h"
21 #if !UCONFIG_NO_COLLATION
23 #include "unicode/bytestream.h"
24 #include "unicode/coleitr.h"
25 #include "unicode/unorm.h"
26 #include "unicode/udata.h"
27 #include "unicode/ustring.h"
28 #include "unicode/utf8.h"
33 #include "normalizer2impl.h"
42 #include "unicode/coll.h"
50 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
52 #define LAST_BYTE_MASK_ 0xFF
53 #define SECOND_LAST_BYTE_SHIFT_ 8
55 #define ZERO_CC_LIMIT_ 0xC0
57 // These are static pointers to the NFC/NFD implementation instance.
58 // Each of them is always the same between calls to u_cleanup
59 // and therefore writing to it is not synchronized.
60 // They are cleaned in ucol_cleanup
61 static const Normalizer2
*g_nfd
= NULL
;
62 static const Normalizer2Impl
*g_nfcImpl
= NULL
;
64 // These are values from UCA required for
65 // implicit generation and supressing sort key compression
66 // they should regularly be in the UCA, but if one
67 // is running without UCA, it could be a problem
68 static const int32_t maxRegularPrimary
= 0x7A;
69 static const int32_t minImplicitPrimary
= 0xE0;
70 static const int32_t maxImplicitPrimary
= 0xE4;
73 static UBool U_CALLCONV
81 static int32_t U_CALLCONV
82 _getFoldingOffset(uint32_t data
) {
83 return (int32_t)(data
&0xFFFFFF);
89 UBool
initializeNFD(UErrorCode
*status
) {
93 // The result is constant, until the library is reloaded.
94 g_nfd
= Normalizer2Factory::getNFDInstance(*status
);
95 ucln_i18n_registerCleanup(UCLN_I18N_UCOL
, ucol_cleanup
);
96 return U_SUCCESS(*status
);
102 UBool
initializeFCD(UErrorCode
*status
) {
103 if (g_nfcImpl
!= NULL
) {
106 // The result is constant, until the library is reloaded.
107 g_nfcImpl
= Normalizer2Factory::getNFCImpl(*status
);
108 // Note: Alternatively, we could also store this pointer in each collIterate struct,
109 // same as Normalizer2Factory::getImpl(collIterate->nfd).
110 ucln_i18n_registerCleanup(UCLN_I18N_UCOL
, ucol_cleanup
);
111 return U_SUCCESS(*status
);
116 inline void IInit_collIterate(const UCollator
*collator
, const UChar
*sourceString
,
117 int32_t sourceLen
, collIterate
*s
,
120 (s
)->string
= (s
)->pos
= sourceString
;
123 if (sourceLen
>= 0) {
124 s
->flags
|= UCOL_ITER_HASLEN
;
125 (s
)->endp
= (UChar
*)sourceString
+sourceLen
;
128 /* change to enable easier checking for end of string for fcdpositon */
131 (s
)->extendCEs
= NULL
;
132 (s
)->extendCEsSize
= 0;
133 (s
)->CEpos
= (s
)->toReturn
= (s
)->CEs
;
134 (s
)->offsetBuffer
= NULL
;
135 (s
)->offsetBufferSize
= 0;
136 (s
)->offsetReturn
= (s
)->offsetStore
= NULL
;
137 (s
)->offsetRepeatCount
= (s
)->offsetRepeatValue
= 0;
138 (s
)->coll
= (collator
);
139 if (initializeNFD(status
)) {
144 (s
)->fcdPosition
= 0;
145 if(collator
->normalizationMode
== UCOL_ON
) {
146 (s
)->flags
|= UCOL_ITER_NORM
;
148 if(collator
->hiraganaQ
== UCOL_ON
&& collator
->strength
>= UCOL_QUATERNARY
) {
149 (s
)->flags
|= UCOL_HIRAGANA_Q
;
151 (s
)->iterator
= NULL
;
152 //(s)->iteratorIndex = 0;
155 U_CAPI
void U_EXPORT2
156 uprv_init_collIterate(const UCollator
*collator
, const UChar
*sourceString
,
157 int32_t sourceLen
, collIterate
*s
,
158 UErrorCode
*status
) {
159 /* Out-of-line version for use from other files. */
160 IInit_collIterate(collator
, sourceString
, sourceLen
, s
, status
);
163 U_CAPI collIterate
* U_EXPORT2
164 uprv_new_collIterate(UErrorCode
*status
) {
165 if(U_FAILURE(*status
)) {
168 collIterate
*s
= new collIterate
;
170 *status
= U_MEMORY_ALLOCATION_ERROR
;
176 U_CAPI
void U_EXPORT2
177 uprv_delete_collIterate(collIterate
*s
) {
181 U_CAPI UBool U_EXPORT2
182 uprv_collIterateAtEnd(collIterate
*s
) {
183 return s
== NULL
|| s
->pos
== s
->endp
;
187 * Backup the state of the collIterate struct data
188 * @param data collIterate to backup
189 * @param backup storage
192 inline void backupState(const collIterate
*data
, collIterateState
*backup
)
194 backup
->fcdPosition
= data
->fcdPosition
;
195 backup
->flags
= data
->flags
;
196 backup
->origFlags
= data
->origFlags
;
197 backup
->pos
= data
->pos
;
198 backup
->bufferaddress
= data
->writableBuffer
.getBuffer();
199 backup
->buffersize
= data
->writableBuffer
.length();
200 backup
->iteratorMove
= 0;
201 backup
->iteratorIndex
= 0;
202 if(data
->iterator
!= NULL
) {
203 //backup->iteratorIndex = data->iterator->getIndex(data->iterator, UITER_CURRENT);
204 backup
->iteratorIndex
= data
->iterator
->getState(data
->iterator
);
205 // no we try to fixup if we're using a normalizing iterator and we get UITER_NO_STATE
206 if(backup
->iteratorIndex
== UITER_NO_STATE
) {
207 while((backup
->iteratorIndex
= data
->iterator
->getState(data
->iterator
)) == UITER_NO_STATE
) {
208 backup
->iteratorMove
++;
209 data
->iterator
->move(data
->iterator
, -1, UITER_CURRENT
);
211 data
->iterator
->move(data
->iterator
, backup
->iteratorMove
, UITER_CURRENT
);
217 * Loads the state into the collIterate struct data
218 * @param data collIterate to backup
219 * @param backup storage
220 * @param forwards boolean to indicate if forwards iteration is used,
221 * false indicates backwards iteration
224 inline void loadState(collIterate
*data
, const collIterateState
*backup
,
227 UErrorCode status
= U_ZERO_ERROR
;
228 data
->flags
= backup
->flags
;
229 data
->origFlags
= backup
->origFlags
;
230 if(data
->iterator
!= NULL
) {
231 //data->iterator->move(data->iterator, backup->iteratorIndex, UITER_ZERO);
232 data
->iterator
->setState(data
->iterator
, backup
->iteratorIndex
, &status
);
233 if(backup
->iteratorMove
!= 0) {
234 data
->iterator
->move(data
->iterator
, backup
->iteratorMove
, UITER_CURRENT
);
237 data
->pos
= backup
->pos
;
239 if ((data
->flags
& UCOL_ITER_INNORMBUF
) &&
240 data
->writableBuffer
.getBuffer() != backup
->bufferaddress
) {
242 this is when a new buffer has been reallocated and we'll have to
243 calculate the new position.
244 note the new buffer has to contain the contents of the old buffer.
247 data
->pos
= data
->writableBuffer
.getTerminatedBuffer() +
248 (data
->pos
- backup
->bufferaddress
);
251 /* backwards direction */
252 int32_t temp
= backup
->buffersize
-
253 (int32_t)(data
->pos
- backup
->bufferaddress
);
254 data
->pos
= data
->writableBuffer
.getTerminatedBuffer() + (data
->writableBuffer
.length() - temp
);
257 if ((data
->flags
& UCOL_ITER_INNORMBUF
) == 0) {
259 this is alittle tricky.
260 if we are initially not in the normalization buffer, even if we
261 normalize in the later stage, the data in the buffer will be
262 ignored, since we skip back up to the data string.
263 however if we are already in the normalization buffer, any
264 further normalization will pull data into the normalization
265 buffer and modify the fcdPosition.
266 since we are keeping the data in the buffer for use, the
267 fcdPosition can not be reverted back.
270 data
->fcdPosition
= backup
->fcdPosition
;
275 reallocCEs(collIterate
*data
, int32_t newCapacity
) {
276 uint32_t *oldCEs
= data
->extendCEs
;
280 int32_t length
= data
->CEpos
- oldCEs
;
281 uint32_t *newCEs
= (uint32_t *)uprv_malloc(newCapacity
* 4);
285 uprv_memcpy(newCEs
, oldCEs
, length
* 4);
286 uprv_free(data
->extendCEs
);
287 data
->extendCEs
= newCEs
;
288 data
->extendCEsSize
= newCapacity
;
289 data
->CEpos
= newCEs
+ length
;
294 increaseCEsCapacity(collIterate
*data
) {
296 if(data
->extendCEs
!= NULL
) {
297 oldCapacity
= data
->extendCEsSize
;
299 oldCapacity
= LENGTHOF(data
->CEs
);
301 return reallocCEs(data
, 2 * oldCapacity
);
305 ensureCEsCapacity(collIterate
*data
, int32_t minCapacity
) {
307 if(data
->extendCEs
!= NULL
) {
308 oldCapacity
= data
->extendCEsSize
;
310 oldCapacity
= LENGTHOF(data
->CEs
);
312 if(minCapacity
<= oldCapacity
) {
316 return reallocCEs(data
, minCapacity
> oldCapacity
? minCapacity
: oldCapacity
);
319 void collIterate::appendOffset(int32_t offset
, UErrorCode
&errorCode
) {
320 if(U_FAILURE(errorCode
)) {
323 int32_t length
= offsetStore
== NULL
? 0 : (int32_t)(offsetStore
- offsetBuffer
);
324 U_ASSERT(length
>= offsetBufferSize
|| offsetStore
!= NULL
);
325 if(length
>= offsetBufferSize
) {
326 int32_t newCapacity
= 2 * offsetBufferSize
+ UCOL_EXPAND_CE_BUFFER_SIZE
;
327 int32_t *newBuffer
= static_cast<int32_t *>(uprv_malloc(newCapacity
* 4));
328 if(newBuffer
== NULL
) {
329 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
333 uprv_memcpy(newBuffer
, offsetBuffer
, length
* 4);
335 uprv_free(offsetBuffer
);
336 offsetBuffer
= newBuffer
;
337 offsetStore
= offsetBuffer
+ length
;
338 offsetBufferSize
= newCapacity
;
340 *offsetStore
++ = offset
;
345 * Checks for a collIterate being positioned at the end of
350 inline UBool
collIter_eos(collIterate
*s
) {
351 if(s
->flags
& UCOL_USE_ITERATOR
) {
352 return !(s
->iterator
->hasNext(s
->iterator
));
354 if ((s
->flags
& UCOL_ITER_HASLEN
) == 0 && *s
->pos
!= 0) {
355 // Null terminated string, but not at null, so not at end.
356 // Whether in main or normalization buffer doesn't matter.
360 // String with length. Can't be in normalization buffer, which is always
362 if (s
->flags
& UCOL_ITER_HASLEN
) {
363 return (s
->pos
== s
->endp
);
366 // We are at a null termination, could be either normalization buffer or main string.
367 if ((s
->flags
& UCOL_ITER_INNORMBUF
) == 0) {
368 // At null at end of main string.
372 // At null at end of normalization buffer. Need to check whether there there are
373 // any characters left in the main buffer.
374 if(s
->origFlags
& UCOL_USE_ITERATOR
) {
375 return !(s
->iterator
->hasNext(s
->iterator
));
376 } else if ((s
->origFlags
& UCOL_ITER_HASLEN
) == 0) {
377 // Null terminated main string. fcdPosition is the 'return' position into main buf.
378 return (*s
->fcdPosition
== 0);
381 // Main string with an end pointer.
382 return s
->fcdPosition
== s
->endp
;
388 * Checks for a collIterate being positioned at the start of
393 inline UBool
collIter_bos(collIterate
*source
) {
394 // if we're going backwards, we need to know whether there is more in the
395 // iterator, even if we are in the side buffer
396 if(source
->flags
& UCOL_USE_ITERATOR
|| source
->origFlags
& UCOL_USE_ITERATOR
) {
397 return !source
->iterator
->hasPrevious(source
->iterator
);
399 if (source
->pos
<= source
->string
||
400 ((source
->flags
& UCOL_ITER_INNORMBUF
) &&
401 *(source
->pos
- 1) == 0 && source
->fcdPosition
== NULL
)) {
408 inline UBool collIter_SimpleBos(collIterate *source) {
409 // if we're going backwards, we need to know whether there is more in the
410 // iterator, even if we are in the side buffer
411 if(source->flags & UCOL_USE_ITERATOR || source->origFlags & UCOL_USE_ITERATOR) {
412 return !source->iterator->hasPrevious(source->iterator);
414 if (source->pos == source->string) {
419 //return (data->pos == data->string) ||
422 /****************************************************************************/
423 /* Following are the open/close functions */
425 /****************************************************************************/
428 ucol_initFromBinary(const uint8_t *bin
, int32_t length
,
429 const UCollator
*base
,
433 UCollator
*result
= fillIn
;
434 if(U_FAILURE(*status
)) {
439 // we don't support null base yet
440 *status = U_ILLEGAL_ARGUMENT_ERROR;
444 // We need these and we could be running without UCA
445 uprv_uca_initImplicitConstants(status
);
446 UCATableHeader
*colData
= (UCATableHeader
*)bin
;
447 // do we want version check here? We're trying to figure out whether collators are compatible
448 if((base
&& (uprv_memcmp(colData
->UCAVersion
, base
->image
->UCAVersion
, sizeof(UVersionInfo
)) != 0 ||
449 uprv_memcmp(colData
->UCDVersion
, base
->image
->UCDVersion
, sizeof(UVersionInfo
)) != 0)) ||
450 colData
->version
[0] != UCOL_BUILDER_VERSION
)
452 *status
= U_COLLATOR_VERSION_MISMATCH
;
456 if((uint32_t)length
> (paddedsize(sizeof(UCATableHeader
)) + paddedsize(sizeof(UColOptionSet
)))) {
457 result
= ucol_initCollator((const UCATableHeader
*)bin
, result
, base
, status
);
458 if(U_FAILURE(*status
)){
461 result
->hasRealData
= TRUE
;
465 result
= ucol_initCollator(base
->image
, result
, base
, status
);
466 ucol_setOptionsFromHeader(result
, (UColOptionSet
*)(bin
+((const UCATableHeader
*)bin
)->options
), status
);
467 if(U_FAILURE(*status
)){
470 result
->hasRealData
= FALSE
;
473 *status
= U_USELESS_COLLATOR_ERROR
;
477 result
->freeImageOnClose
= FALSE
;
479 result
->actualLocale
= NULL
;
480 result
->validLocale
= NULL
;
481 result
->requestedLocale
= NULL
;
482 result
->rules
= NULL
;
483 result
->rulesLength
= 0;
484 result
->freeRulesOnClose
= FALSE
;
485 result
->ucaRules
= NULL
;
489 U_CAPI UCollator
* U_EXPORT2
490 ucol_openBinary(const uint8_t *bin
, int32_t length
,
491 const UCollator
*base
,
494 return ucol_initFromBinary(bin
, length
, base
, NULL
, status
);
497 U_CAPI
int32_t U_EXPORT2
498 ucol_cloneBinary(const UCollator
*coll
,
499 uint8_t *buffer
, int32_t capacity
,
503 if(U_FAILURE(*status
)) {
507 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
510 if(coll
->hasRealData
== TRUE
) {
511 length
= coll
->image
->size
;
512 if(length
<= capacity
) {
513 uprv_memcpy(buffer
, coll
->image
, length
);
515 *status
= U_BUFFER_OVERFLOW_ERROR
;
518 length
= (int32_t)(paddedsize(sizeof(UCATableHeader
))+paddedsize(sizeof(UColOptionSet
)));
519 if(length
<= capacity
) {
520 /* build the UCATableHeader with minimal entries */
521 /* do not copy the header from the UCA file because its values are wrong! */
522 /* uprv_memcpy(result, UCA->image, sizeof(UCATableHeader)); */
524 /* reset everything */
525 uprv_memset(buffer
, 0, length
);
527 /* set the tailoring-specific values */
528 UCATableHeader
*myData
= (UCATableHeader
*)buffer
;
529 myData
->size
= length
;
531 /* offset for the options, the only part of the data that is present after the header */
532 myData
->options
= sizeof(UCATableHeader
);
534 /* need to always set the expansion value for an upper bound of the options */
535 myData
->expansion
= myData
->options
+ sizeof(UColOptionSet
);
537 myData
->magic
= UCOL_HEADER_MAGIC
;
538 myData
->isBigEndian
= U_IS_BIG_ENDIAN
;
539 myData
->charSetFamily
= U_CHARSET_FAMILY
;
541 /* copy UCA's version; genrb will override all but the builder version with tailoring data */
542 uprv_memcpy(myData
->version
, coll
->image
->version
, sizeof(UVersionInfo
));
544 uprv_memcpy(myData
->UCAVersion
, coll
->image
->UCAVersion
, sizeof(UVersionInfo
));
545 uprv_memcpy(myData
->UCDVersion
, coll
->image
->UCDVersion
, sizeof(UVersionInfo
));
546 uprv_memcpy(myData
->formatVersion
, coll
->image
->formatVersion
, sizeof(UVersionInfo
));
547 myData
->jamoSpecial
= coll
->image
->jamoSpecial
;
549 /* copy the collator options */
550 uprv_memcpy(buffer
+paddedsize(sizeof(UCATableHeader
)), coll
->options
, sizeof(UColOptionSet
));
552 *status
= U_BUFFER_OVERFLOW_ERROR
;
558 U_CAPI UCollator
* U_EXPORT2
559 ucol_safeClone(const UCollator
*coll
, void *stackBuffer
, int32_t * pBufferSize
, UErrorCode
*status
)
561 UCollator
* localCollator
;
562 int32_t bufferSizeNeeded
= (int32_t)sizeof(UCollator
);
563 char *stackBufferChars
= (char *)stackBuffer
;
564 int32_t imageSize
= 0;
565 int32_t rulesSize
= 0;
566 int32_t rulesPadding
= 0;
567 int32_t defaultReorderCodesSize
= 0;
568 int32_t reorderCodesSize
= 0;
571 int32_t* defaultReorderCodes
;
572 int32_t* reorderCodes
;
573 uint8_t* leadBytePermutationTable
;
574 UBool colAllocated
= FALSE
;
575 UBool imageAllocated
= FALSE
;
577 if (status
== NULL
|| U_FAILURE(*status
)){
580 if ((stackBuffer
&& !pBufferSize
) || !coll
){
581 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
585 if (coll
->rules
&& coll
->freeRulesOnClose
) {
586 rulesSize
= (int32_t)(coll
->rulesLength
+ 1)*sizeof(UChar
);
587 rulesPadding
= (int32_t)(bufferSizeNeeded
% sizeof(UChar
));
588 bufferSizeNeeded
+= rulesSize
+ rulesPadding
;
590 // no padding for alignment needed from here since the next two are 4 byte quantities
591 if (coll
->defaultReorderCodes
) {
592 defaultReorderCodesSize
= coll
->defaultReorderCodesLength
* sizeof(int32_t);
593 bufferSizeNeeded
+= defaultReorderCodesSize
;
595 if (coll
->reorderCodes
) {
596 reorderCodesSize
= coll
->reorderCodesLength
* sizeof(int32_t);
597 bufferSizeNeeded
+= reorderCodesSize
;
599 if (coll
->leadBytePermutationTable
) {
600 bufferSizeNeeded
+= 256 * sizeof(uint8_t);
603 if (stackBuffer
&& *pBufferSize
<= 0) { /* 'preflighting' request - set needed size into *pBufferSize */
604 *pBufferSize
= bufferSizeNeeded
;
608 /* Pointers on 64-bit platforms need to be aligned
609 * on a 64-bit boundry in memory.
611 if (U_ALIGNMENT_OFFSET(stackBuffer
) != 0) {
612 int32_t offsetUp
= (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars
);
613 if (*pBufferSize
> offsetUp
) {
614 *pBufferSize
-= offsetUp
;
615 stackBufferChars
+= offsetUp
;
618 /* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */
622 stackBuffer
= (void *)stackBufferChars
;
624 if (stackBuffer
== NULL
|| *pBufferSize
< bufferSizeNeeded
) {
625 /* allocate one here...*/
626 stackBufferChars
= (char *)uprv_malloc(bufferSizeNeeded
);
627 // Null pointer check.
628 if (stackBufferChars
== NULL
) {
629 *status
= U_MEMORY_ALLOCATION_ERROR
;
633 if (U_SUCCESS(*status
)) {
634 *status
= U_SAFECLONE_ALLOCATED_WARNING
;
637 localCollator
= (UCollator
*)stackBufferChars
;
638 rules
= (UChar
*)(stackBufferChars
+ sizeof(UCollator
) + rulesPadding
);
639 defaultReorderCodes
= (int32_t*)((uint8_t*)rules
+ rulesSize
);
640 reorderCodes
= (int32_t*)((uint8_t*)defaultReorderCodes
+ defaultReorderCodesSize
);
641 leadBytePermutationTable
= (uint8_t*)reorderCodes
+ reorderCodesSize
;
644 UErrorCode tempStatus
= U_ZERO_ERROR
;
645 imageSize
= ucol_cloneBinary(coll
, NULL
, 0, &tempStatus
);
647 if (coll
->freeImageOnClose
) {
648 image
= (uint8_t *)uprv_malloc(imageSize
);
649 // Null pointer check
651 *status
= U_MEMORY_ALLOCATION_ERROR
;
654 ucol_cloneBinary(coll
, image
, imageSize
, status
);
655 imageAllocated
= TRUE
;
658 image
= (uint8_t *)coll
->image
;
660 localCollator
= ucol_initFromBinary(image
, imageSize
, coll
->UCA
, localCollator
, status
);
661 if (U_FAILURE(*status
)) {
666 if (coll
->freeRulesOnClose
) {
667 localCollator
->rules
= u_strcpy(rules
, coll
->rules
);
668 //bufferEnd += rulesSize;
671 localCollator
->rules
= coll
->rules
;
673 localCollator
->freeRulesOnClose
= FALSE
;
674 localCollator
->rulesLength
= coll
->rulesLength
;
677 // collator reordering
678 if (coll
->defaultReorderCodes
) {
679 localCollator
->defaultReorderCodes
=
680 (int32_t*) uprv_memcpy(defaultReorderCodes
, coll
->defaultReorderCodes
, coll
->defaultReorderCodesLength
* sizeof(int32_t));
681 localCollator
->defaultReorderCodesLength
= coll
->defaultReorderCodesLength
;
682 localCollator
->freeDefaultReorderCodesOnClose
= FALSE
;
684 if (coll
->reorderCodes
) {
685 localCollator
->reorderCodes
=
686 (int32_t*)uprv_memcpy(reorderCodes
, coll
->reorderCodes
, coll
->reorderCodesLength
* sizeof(int32_t));
687 localCollator
->reorderCodesLength
= coll
->reorderCodesLength
;
688 localCollator
->freeReorderCodesOnClose
= FALSE
;
690 if (coll
->leadBytePermutationTable
) {
691 localCollator
->leadBytePermutationTable
=
692 (uint8_t*) uprv_memcpy(leadBytePermutationTable
, coll
->leadBytePermutationTable
, 256);
693 localCollator
->freeLeadBytePermutationTableOnClose
= FALSE
;
697 for(i
= 0; i
< UCOL_ATTRIBUTE_COUNT
; i
++) {
698 ucol_setAttribute(localCollator
, (UColAttribute
)i
, ucol_getAttribute(coll
, (UColAttribute
)i
, status
), status
);
700 // zero copies of pointers
701 localCollator
->actualLocale
= NULL
;
702 localCollator
->validLocale
= NULL
;
703 localCollator
->requestedLocale
= NULL
;
704 localCollator
->ucaRules
= coll
->ucaRules
; // There should only be one copy here.
705 localCollator
->freeOnClose
= colAllocated
;
706 localCollator
->freeImageOnClose
= imageAllocated
;
707 return localCollator
;
710 U_CAPI
void U_EXPORT2
711 ucol_close(UCollator
*coll
)
713 UTRACE_ENTRY_OC(UTRACE_UCOL_CLOSE
);
714 UTRACE_DATA1(UTRACE_INFO
, "coll = %p", coll
);
716 // these are always owned by each UCollator struct,
717 // so we always free them
718 if(coll
->validLocale
!= NULL
) {
719 uprv_free(coll
->validLocale
);
721 if(coll
->actualLocale
!= NULL
) {
722 uprv_free(coll
->actualLocale
);
724 if(coll
->requestedLocale
!= NULL
) {
725 uprv_free(coll
->requestedLocale
);
727 if(coll
->latinOneCEs
!= NULL
) {
728 uprv_free(coll
->latinOneCEs
);
730 if(coll
->options
!= NULL
&& coll
->freeOptionsOnClose
) {
731 uprv_free(coll
->options
);
733 if(coll
->rules
!= NULL
&& coll
->freeRulesOnClose
) {
734 uprv_free((UChar
*)coll
->rules
);
736 if(coll
->image
!= NULL
&& coll
->freeImageOnClose
) {
737 uprv_free((UCATableHeader
*)coll
->image
);
740 if(coll
->leadBytePermutationTable
!= NULL
&& coll
->freeLeadBytePermutationTableOnClose
== TRUE
) {
741 uprv_free(coll
->leadBytePermutationTable
);
743 if(coll
->defaultReorderCodes
!= NULL
&& coll
->freeDefaultReorderCodesOnClose
== TRUE
) {
744 uprv_free(coll
->defaultReorderCodes
);
746 if(coll
->reorderCodes
!= NULL
&& coll
->freeReorderCodesOnClose
== TRUE
) {
747 uprv_free(coll
->reorderCodes
);
750 if(coll
->delegate
!= NULL
) {
751 delete (Collator
*)coll
->delegate
;
754 /* Here, it would be advisable to close: */
755 /* - UData for UCA (unless we stuff it in the root resb */
756 /* Again, do we need additional housekeeping... HMMM! */
757 UTRACE_DATA1(UTRACE_INFO
, "coll->freeOnClose: %d", coll
->freeOnClose
);
758 if(coll
->freeOnClose
){
759 /* for safeClone, if freeOnClose is FALSE,
760 don't free the other instance data */
767 /* This one is currently used by genrb & tests. After constructing from rules (tailoring),*/
768 /* you should be able to get the binary chunk to write out... Doesn't look very full now */
769 U_CFUNC
uint8_t* U_EXPORT2
770 ucol_cloneRuleData(const UCollator
*coll
, int32_t *length
, UErrorCode
*status
)
772 uint8_t *result
= NULL
;
773 if(U_FAILURE(*status
)) {
776 if(coll
->hasRealData
== TRUE
) {
777 *length
= coll
->image
->size
;
778 result
= (uint8_t *)uprv_malloc(*length
);
780 if (result
== NULL
) {
781 *status
= U_MEMORY_ALLOCATION_ERROR
;
784 uprv_memcpy(result
, coll
->image
, *length
);
786 *length
= (int32_t)(paddedsize(sizeof(UCATableHeader
))+paddedsize(sizeof(UColOptionSet
)));
787 result
= (uint8_t *)uprv_malloc(*length
);
789 if (result
== NULL
) {
790 *status
= U_MEMORY_ALLOCATION_ERROR
;
794 /* build the UCATableHeader with minimal entries */
795 /* do not copy the header from the UCA file because its values are wrong! */
796 /* uprv_memcpy(result, UCA->image, sizeof(UCATableHeader)); */
798 /* reset everything */
799 uprv_memset(result
, 0, *length
);
801 /* set the tailoring-specific values */
802 UCATableHeader
*myData
= (UCATableHeader
*)result
;
803 myData
->size
= *length
;
805 /* offset for the options, the only part of the data that is present after the header */
806 myData
->options
= sizeof(UCATableHeader
);
808 /* need to always set the expansion value for an upper bound of the options */
809 myData
->expansion
= myData
->options
+ sizeof(UColOptionSet
);
811 myData
->magic
= UCOL_HEADER_MAGIC
;
812 myData
->isBigEndian
= U_IS_BIG_ENDIAN
;
813 myData
->charSetFamily
= U_CHARSET_FAMILY
;
815 /* copy UCA's version; genrb will override all but the builder version with tailoring data */
816 uprv_memcpy(myData
->version
, coll
->image
->version
, sizeof(UVersionInfo
));
818 uprv_memcpy(myData
->UCAVersion
, coll
->image
->UCAVersion
, sizeof(UVersionInfo
));
819 uprv_memcpy(myData
->UCDVersion
, coll
->image
->UCDVersion
, sizeof(UVersionInfo
));
820 uprv_memcpy(myData
->formatVersion
, coll
->image
->formatVersion
, sizeof(UVersionInfo
));
821 myData
->jamoSpecial
= coll
->image
->jamoSpecial
;
823 /* copy the collator options */
824 uprv_memcpy(result
+paddedsize(sizeof(UCATableHeader
)), coll
->options
, sizeof(UColOptionSet
));
829 void ucol_setOptionsFromHeader(UCollator
* result
, UColOptionSet
* opts
, UErrorCode
*status
) {
830 if(U_FAILURE(*status
)) {
833 result
->caseFirst
= (UColAttributeValue
)opts
->caseFirst
;
834 result
->caseLevel
= (UColAttributeValue
)opts
->caseLevel
;
835 result
->frenchCollation
= (UColAttributeValue
)opts
->frenchCollation
;
836 result
->normalizationMode
= (UColAttributeValue
)opts
->normalizationMode
;
837 if(result
->normalizationMode
== UCOL_ON
&& !initializeFCD(status
)) {
840 result
->strength
= (UColAttributeValue
)opts
->strength
;
841 result
->variableTopValue
= opts
->variableTopValue
;
842 result
->alternateHandling
= (UColAttributeValue
)opts
->alternateHandling
;
843 result
->hiraganaQ
= (UColAttributeValue
)opts
->hiraganaQ
;
844 result
->numericCollation
= (UColAttributeValue
)opts
->numericCollation
;
845 result
->caseFirstisDefault
= TRUE
;
846 result
->caseLevelisDefault
= TRUE
;
847 result
->frenchCollationisDefault
= TRUE
;
848 result
->normalizationModeisDefault
= TRUE
;
849 result
->strengthisDefault
= TRUE
;
850 result
->variableTopValueisDefault
= TRUE
;
851 result
->alternateHandlingisDefault
= TRUE
;
852 result
->hiraganaQisDefault
= TRUE
;
853 result
->numericCollationisDefault
= TRUE
;
855 ucol_updateInternalState(result
, status
);
857 result
->options
= opts
;
862 * Approximate determination if a character is at a contraction end.
863 * Guaranteed to be TRUE if a character is at the end of a contraction,
864 * otherwise it is not deterministic.
865 * @param c character to be determined
866 * @param coll collator
869 inline UBool
ucol_contractionEndCP(UChar c
, const UCollator
*coll
) {
870 if (c
< coll
->minContrEndCP
) {
876 if (hash
>= UCOL_UNSAFECP_TABLE_SIZE
*8) {
877 if (U16_IS_TRAIL(c
)) {
880 hash
= (hash
& UCOL_UNSAFECP_TABLE_MASK
) + 256;
882 htbyte
= coll
->contrEndCP
[hash
>>3];
883 return (((htbyte
>> (hash
& 7)) & 1) == 1);
889 * i_getCombiningClass()
890 * A fast, at least partly inline version of u_getCombiningClass()
891 * This is a candidate for further optimization. Used heavily
892 * in contraction processing.
895 inline uint8_t i_getCombiningClass(UChar32 c
, const UCollator
*coll
) {
897 if ((c
>= 0x300 && ucol_unsafeCP(c
, coll
)) || c
> 0xFFFF) {
898 sCC
= u_getCombiningClass(c
);
903 UCollator
* ucol_initCollator(const UCATableHeader
*image
, UCollator
*fillIn
, const UCollator
*UCA
, UErrorCode
*status
) {
905 UCollator
*result
= fillIn
;
906 if(U_FAILURE(*status
) || image
== NULL
) {
911 result
= (UCollator
*)uprv_malloc(sizeof(UCollator
));
913 *status
= U_MEMORY_ALLOCATION_ERROR
;
916 result
->freeOnClose
= TRUE
;
918 result
->freeOnClose
= FALSE
;
921 result
->delegate
= NULL
;
923 result
->image
= image
;
924 result
->mapping
.getFoldingOffset
= _getFoldingOffset
;
925 const uint8_t *mapping
= (uint8_t*)result
->image
+result
->image
->mappingPosition
;
926 utrie_unserialize(&result
->mapping
, mapping
, result
->image
->endExpansionCE
- result
->image
->mappingPosition
, status
);
927 if(U_FAILURE(*status
)) {
928 if(result
->freeOnClose
== TRUE
) {
935 result
->latinOneMapping
= UTRIE_GET32_LATIN1(&result
->mapping
);
936 result
->contractionCEs
= (uint32_t*)((uint8_t*)result
->image
+result
->image
->contractionCEs
);
937 result
->contractionIndex
= (UChar
*)((uint8_t*)result
->image
+result
->image
->contractionIndex
);
938 result
->expansion
= (uint32_t*)((uint8_t*)result
->image
+result
->image
->expansion
);
939 result
->rules
= NULL
;
940 result
->rulesLength
= 0;
941 result
->freeRulesOnClose
= FALSE
;
942 result
->defaultReorderCodes
= NULL
;
943 result
->defaultReorderCodesLength
= 0;
944 result
->freeDefaultReorderCodesOnClose
= FALSE
;
945 result
->reorderCodes
= NULL
;
946 result
->reorderCodesLength
= 0;
947 result
->freeReorderCodesOnClose
= FALSE
;
948 result
->leadBytePermutationTable
= NULL
;
949 result
->freeLeadBytePermutationTableOnClose
= FALSE
;
951 /* get the version info from UCATableHeader and populate the Collator struct*/
952 result
->dataVersion
[0] = result
->image
->version
[0]; /* UCA Builder version*/
953 result
->dataVersion
[1] = result
->image
->version
[1]; /* UCA Tailoring rules version*/
954 result
->dataVersion
[2] = 0;
955 result
->dataVersion
[3] = 0;
957 result
->unsafeCP
= (uint8_t *)result
->image
+ result
->image
->unsafeCP
;
958 result
->minUnsafeCP
= 0;
959 for (c
=0; c
<0x300; c
++) { // Find the smallest unsafe char.
960 if (ucol_unsafeCP(c
, result
)) break;
962 result
->minUnsafeCP
= c
;
964 result
->contrEndCP
= (uint8_t *)result
->image
+ result
->image
->contrEndCP
;
965 result
->minContrEndCP
= 0;
966 for (c
=0; c
<0x300; c
++) { // Find the Contraction-ending char.
967 if (ucol_contractionEndCP(c
, result
)) break;
969 result
->minContrEndCP
= c
;
971 /* max expansion tables */
972 result
->endExpansionCE
= (uint32_t*)((uint8_t*)result
->image
+
973 result
->image
->endExpansionCE
);
974 result
->lastEndExpansionCE
= result
->endExpansionCE
+
975 result
->image
->endExpansionCECount
- 1;
976 result
->expansionCESize
= (uint8_t*)result
->image
+
977 result
->image
->expansionCESize
;
980 //result->errorCode = *status;
982 result
->latinOneCEs
= NULL
;
984 result
->latinOneRegenTable
= FALSE
;
985 result
->latinOneFailed
= FALSE
;
988 /* Normally these will be set correctly later. This is the default if you use UCA or the default. */
989 result
->ucaRules
= NULL
;
990 result
->actualLocale
= NULL
;
991 result
->validLocale
= NULL
;
992 result
->requestedLocale
= NULL
;
993 result
->hasRealData
= FALSE
; // real data lives in .dat file...
994 result
->freeImageOnClose
= FALSE
;
997 ucol_setOptionsFromHeader(
999 (UColOptionSet
*)((uint8_t*)result
->image
+result
->image
->options
),
1001 result
->freeOptionsOnClose
= FALSE
;
1006 /* new Mark's code */
1009 * For generation of Implicit CEs
1012 * Cleaned up so that changes can be made more easily.
1014 # First Implicit: E26A792D
1015 # Last Implicit: E3DC70C0
1016 # First CJK: E0030300
1017 # Last CJK: E0A9DD00
1018 # First CJK_A: E0A9DF00
1019 # Last CJK_A: E0DE3100
1021 /* Following is a port of Mark's code for new treatment of implicits.
1022 * It is positioned here, since ucol_initUCA need to initialize the
1023 * variables below according to the data in the fractional UCA.
1028 * a) collapse the 2 different Han ranges from UCA into one (in the right order), and
1029 * b) bump any non-CJK characters by 10FFFF.
1030 * The relevant blocks are:
1031 * A: 4E00..9FFF; CJK Unified Ideographs
1032 * F900..FAFF; CJK Compatibility Ideographs
1033 * B: 3400..4DBF; CJK Unified Ideographs Extension A
1034 * 20000..XX; CJK Unified Ideographs Extension B (and others later on)
1036 * no new B characters are allocated between 4E00 and FAFF, and
1037 * no new A characters are outside of this range,
1038 * (very high probability) this simple code will work.
1039 * The reordered blocks are:
1041 * Block2 is CJK_COMPAT_USED
1044 * Any other CJK gets its normal code point
1045 * Any non-CJK gets +10FFFF
1046 * When we reorder Block1, we make sure that it is at the very start,
1047 * so that it will use a 3-byte form.
1048 * Warning: the we only pick up the compatibility characters that are
1049 * NOT decomposed, so that block is smaller!
1053 static const UChar32
1054 NON_CJK_OFFSET
= 0x110000,
1055 UCOL_MAX_INPUT
= 0x220001; // 2 * Unicode range + 2
1058 * Precomputed by initImplicitConstants()
1061 final3Multiplier
= 0,
1062 final4Multiplier
= 0,
1075 static const UChar32
1076 // 4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
1077 // 9FCC;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; (Unicode 6.1)
1079 CJK_LIMIT
= 0x9FCC+1,
1080 // Unified CJK ideographs in the compatibility ideographs block.
1081 CJK_COMPAT_USED_BASE
= 0xFA0E,
1082 CJK_COMPAT_USED_LIMIT
= 0xFA2F+1,
1083 // 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
1084 // 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
1085 CJK_A_BASE
= 0x3400,
1086 CJK_A_LIMIT
= 0x4DB5+1,
1087 // 20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
1088 // 2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
1089 CJK_B_BASE
= 0x20000,
1090 CJK_B_LIMIT
= 0x2A6D6+1,
1091 // 2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;
1092 // 2B734;<CJK Ideograph Extension C, Last>;Lo;0;L;;;;;N;;;;;
1093 CJK_C_BASE
= 0x2A700,
1094 CJK_C_LIMIT
= 0x2B734+1,
1095 // 2B740;<CJK Ideograph Extension D, First>;Lo;0;L;;;;;N;;;;;
1096 // 2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;;
1097 CJK_D_BASE
= 0x2B740,
1098 CJK_D_LIMIT
= 0x2B81D+1;
1099 // when adding to this list, look for all occurrences (in project)
1100 // of CJK_C_BASE and CJK_C_LIMIT, etc. to check for code that needs changing!!!!
1102 static UChar32
swapCJK(UChar32 i
) {
1103 if (i
< CJK_A_BASE
) {
1105 } else if (i
< CJK_A_LIMIT
) {
1106 // Extension A has lower code points than the original Unihan+compat
1107 // but sorts higher.
1108 return i
- CJK_A_BASE
1109 + (CJK_LIMIT
- CJK_BASE
)
1110 + (CJK_COMPAT_USED_LIMIT
- CJK_COMPAT_USED_BASE
);
1111 } else if (i
< CJK_BASE
) {
1113 } else if (i
< CJK_LIMIT
) {
1114 return i
- CJK_BASE
;
1115 } else if (i
< CJK_COMPAT_USED_BASE
) {
1117 } else if (i
< CJK_COMPAT_USED_LIMIT
) {
1118 return i
- CJK_COMPAT_USED_BASE
1119 + (CJK_LIMIT
- CJK_BASE
);
1120 } else if (i
< CJK_B_BASE
) {
1122 } else if (i
< CJK_B_LIMIT
) {
1123 return i
; // non-BMP-CJK
1124 } else if (i
< CJK_C_BASE
) {
1126 } else if (i
< CJK_C_LIMIT
) {
1127 return i
; // non-BMP-CJK
1128 } else if (i
< CJK_D_BASE
) {
1130 } else if (i
< CJK_D_LIMIT
) {
1131 return i
; // non-BMP-CJK
1133 return i
+ NON_CJK_OFFSET
; // non-CJK
1136 U_CAPI UChar32 U_EXPORT2
1137 uprv_uca_getRawFromCodePoint(UChar32 i
) {
1138 return swapCJK(i
)+1;
1141 U_CAPI UChar32 U_EXPORT2
1142 uprv_uca_getCodePointFromRaw(UChar32 i
) {
1145 if(i
>= NON_CJK_OFFSET
) {
1146 result
= i
- NON_CJK_OFFSET
;
1147 } else if(i
>= CJK_B_BASE
) {
1149 } else if(i
< CJK_A_LIMIT
+ (CJK_LIMIT
- CJK_BASE
) + (CJK_COMPAT_USED_LIMIT
- CJK_COMPAT_USED_BASE
)) { // rest of CJKs, compacted
1150 if(i
< CJK_LIMIT
- CJK_BASE
) {
1151 result
= i
+ CJK_BASE
;
1152 } else if(i
< (CJK_LIMIT
- CJK_BASE
) + (CJK_COMPAT_USED_LIMIT
- CJK_COMPAT_USED_BASE
)) {
1153 result
= i
+ CJK_COMPAT_USED_BASE
- (CJK_LIMIT
- CJK_BASE
);
1155 result
= i
+ CJK_A_BASE
- (CJK_LIMIT
- CJK_BASE
) - (CJK_COMPAT_USED_LIMIT
- CJK_COMPAT_USED_BASE
);
1163 // GET IMPLICIT PRIMARY WEIGHTS
1164 // Return value is left justified primary key
1165 U_CAPI
uint32_t U_EXPORT2
1166 uprv_uca_getImplicitFromRaw(UChar32 cp
) {
1168 if (cp < 0 || cp > UCOL_MAX_INPUT) {
1169 throw new IllegalArgumentException("Code point out of range " + Utility.hex(cp));
1172 int32_t last0
= cp
- min4Boundary
;
1174 int32_t last1
= cp
/ final3Count
;
1175 last0
= cp
% final3Count
;
1177 int32_t last2
= last1
/ medialCount
;
1178 last1
%= medialCount
;
1180 last0
= minTrail
+ last0
*final3Multiplier
; // spread out, leaving gap at start
1181 last1
= minTrail
+ last1
; // offset
1182 last2
= min3Primary
+ last2
; // offset
1184 if (last2 >= min4Primary) {
1185 throw new IllegalArgumentException("4-byte out of range: " + Utility.hex(cp) + ", " + Utility.hex(last2));
1188 return (last2
<< 24) + (last1
<< 16) + (last0
<< 8);
1190 int32_t last1
= last0
/ final4Count
;
1191 last0
%= final4Count
;
1193 int32_t last2
= last1
/ medialCount
;
1194 last1
%= medialCount
;
1196 int32_t last3
= last2
/ medialCount
;
1197 last2
%= medialCount
;
1199 last0
= minTrail
+ last0
*final4Multiplier
; // spread out, leaving gap at start
1200 last1
= minTrail
+ last1
; // offset
1201 last2
= minTrail
+ last2
; // offset
1202 last3
= min4Primary
+ last3
; // offset
1204 if (last3 > max4Primary) {
1205 throw new IllegalArgumentException("4-byte out of range: " + Utility.hex(cp) + ", " + Utility.hex(last3));
1208 return (last3
<< 24) + (last2
<< 16) + (last1
<< 8) + last0
;
1212 static uint32_t U_EXPORT2
1213 uprv_uca_getImplicitPrimary(UChar32 cp
) {
1214 //fprintf(stdout, "Incoming: %04x\n", cp);
1215 //if (DEBUG) System.out.println("Incoming: " + Utility.hex(cp));
1219 // we now have a range of numbers from 0 to 21FFFF.
1221 //if (DEBUG) System.out.println("CJK swapped: " + Utility.hex(cp));
1222 //fprintf(stdout, "CJK swapped: %04x\n", cp);
1224 return uprv_uca_getImplicitFromRaw(cp
);
1228 * Converts implicit CE into raw integer ("code point")
1230 * @return -1 if illegal format
1232 U_CAPI UChar32 U_EXPORT2
1233 uprv_uca_getRawFromImplicit(uint32_t implicit
) {
1235 UChar32 b3
= implicit
& 0xFF;
1236 UChar32 b2
= (implicit
>> 8) & 0xFF;
1237 UChar32 b1
= (implicit
>> 16) & 0xFF;
1238 UChar32 b0
= (implicit
>> 24) & 0xFF;
1240 // simple parameter checks
1241 if (b0
< min3Primary
|| b0
> max4Primary
1242 || b1
< minTrail
|| b1
> maxTrail
)
1247 // take care of the final values, and compose
1248 if (b0
< min4Primary
) {
1249 if (b2
< minTrail
|| b2
> max3Trail
|| b3
!= 0)
1252 UChar32 remainder
= b2
% final3Multiplier
;
1256 b2
/= final3Multiplier
;
1257 result
= ((b0
* medialCount
) + b1
) * final3Count
+ b2
;
1259 if (b2
< minTrail
|| b2
> maxTrail
1260 || b3
< minTrail
|| b3
> max4Trail
)
1264 UChar32 remainder
= b3
% final4Multiplier
;
1267 b3
/= final4Multiplier
;
1269 result
= (((b0
* medialCount
) + b1
) * medialCount
+ b2
) * final4Count
+ b3
+ min4Boundary
;
1272 if (result
< 0 || result
> UCOL_MAX_INPUT
)
1278 static inline int32_t divideAndRoundUp(int a
, int b
) {
1282 /* this function is either called from initUCA or from genUCA before
1283 * doing canonical closure for the UCA.
1287 * Set up to generate implicits.
1288 * Maintenance Note: this function may end up being called more than once, due
1289 * to threading races during initialization. Make sure that
1290 * none of the Constants is ever transiently assigned an
1294 * @param minTrail final byte
1295 * @param maxTrail final byte
1296 * @param gap3 the gap we leave for tailoring for 3-byte forms
1297 * @param gap4 the gap we leave for tailoring for 4-byte forms
1299 static void initImplicitConstants(int minPrimary
, int maxPrimary
,
1300 int minTrailIn
, int maxTrailIn
,
1301 int gap3
, int primaries3count
,
1302 UErrorCode
*status
) {
1303 // some simple parameter checks
1304 if ((minPrimary
< 0 || minPrimary
>= maxPrimary
|| maxPrimary
> 0xFF)
1305 || (minTrailIn
< 0 || minTrailIn
>= maxTrailIn
|| maxTrailIn
> 0xFF)
1306 || (primaries3count
< 1))
1308 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
1312 minTrail
= minTrailIn
;
1313 maxTrail
= maxTrailIn
;
1315 min3Primary
= minPrimary
;
1316 max4Primary
= maxPrimary
;
1317 // compute constants for use later.
1318 // number of values we can use in trailing bytes
1319 // leave room for empty values between AND above, e.g. if gap = 2
1320 // range 3..7 => +3 -4 -5 -6 -7: so 1 value
1321 // range 3..8 => +3 -4 -5 +6 -7 -8: so 2 values
1322 // range 3..9 => +3 -4 -5 +6 -7 -8 -9: so 2 values
1323 final3Multiplier
= gap3
+ 1;
1324 final3Count
= (maxTrail
- minTrail
+ 1) / final3Multiplier
;
1325 max3Trail
= minTrail
+ (final3Count
- 1) * final3Multiplier
;
1327 // medials can use full range
1328 medialCount
= (maxTrail
- minTrail
+ 1);
1329 // find out how many values fit in each form
1330 int32_t threeByteCount
= medialCount
* final3Count
;
1331 // now determine where the 3/4 boundary is.
1332 // we use 3 bytes below the boundary, and 4 above
1333 int32_t primariesAvailable
= maxPrimary
- minPrimary
+ 1;
1334 int32_t primaries4count
= primariesAvailable
- primaries3count
;
1337 int32_t min3ByteCoverage
= primaries3count
* threeByteCount
;
1338 min4Primary
= minPrimary
+ primaries3count
;
1339 min4Boundary
= min3ByteCoverage
;
1340 // Now expand out the multiplier for the 4 bytes, and redo.
1342 int32_t totalNeeded
= UCOL_MAX_INPUT
- min4Boundary
;
1343 int32_t neededPerPrimaryByte
= divideAndRoundUp(totalNeeded
, primaries4count
);
1344 int32_t neededPerFinalByte
= divideAndRoundUp(neededPerPrimaryByte
, medialCount
* medialCount
);
1345 int32_t gap4
= (maxTrail
- minTrail
- 1) / neededPerFinalByte
;
1347 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
1350 final4Multiplier
= gap4
+ 1;
1351 final4Count
= neededPerFinalByte
;
1352 max4Trail
= minTrail
+ (final4Count
- 1) * final4Multiplier
;
1356 * Supply parameters for generating implicit CEs
1358 U_CAPI
void U_EXPORT2
1359 uprv_uca_initImplicitConstants(UErrorCode
*status
) {
1360 // 13 is the largest 4-byte gap we can use without getting 2 four-byte forms.
1361 //initImplicitConstants(minPrimary, maxPrimary, 0x04, 0xFE, 1, 1, status);
1362 initImplicitConstants(minImplicitPrimary
, maxImplicitPrimary
, 0x04, 0xFE, 1, 1, status
);
1366 /* collIterNormalize Incremental Normalization happens here. */
1367 /* pick up the range of chars identifed by FCD, */
1368 /* normalize it into the collIterate's writable buffer, */
1369 /* switch the collIterate's state to use the writable buffer. */
1372 void collIterNormalize(collIterate
*collationSource
)
1374 UErrorCode status
= U_ZERO_ERROR
;
1375 const UChar
*srcP
= collationSource
->pos
- 1; /* Start of chars to normalize */
1376 const UChar
*endP
= collationSource
->fcdPosition
; /* End of region to normalize+1 */
1378 collationSource
->nfd
->normalize(UnicodeString(FALSE
, srcP
, (int32_t)(endP
- srcP
)),
1379 collationSource
->writableBuffer
,
1381 if (U_FAILURE(status
)) {
1383 fprintf(stderr
, "collIterNormalize(), NFD failed, status = %s\n", u_errorName(status
));
1388 collationSource
->pos
= collationSource
->writableBuffer
.getTerminatedBuffer();
1389 collationSource
->origFlags
= collationSource
->flags
;
1390 collationSource
->flags
|= UCOL_ITER_INNORMBUF
;
1391 collationSource
->flags
&= ~(UCOL_ITER_NORM
| UCOL_ITER_HASLEN
| UCOL_USE_ITERATOR
);
1395 // This function takes the iterator and extracts normalized stuff up to the next boundary
1396 // It is similar in the end results to the collIterNormalize, but for the cases when we
1399 inline void normalizeIterator(collIterate *collationSource) {
1400 UErrorCode status = U_ZERO_ERROR;
1401 UBool wasNormalized = FALSE;
1402 //int32_t iterIndex = collationSource->iterator->getIndex(collationSource->iterator, UITER_CURRENT);
1403 uint32_t iterIndex = collationSource->iterator->getState(collationSource->iterator);
1404 int32_t normLen = unorm_next(collationSource->iterator, collationSource->writableBuffer,
1405 (int32_t)collationSource->writableBufSize, UNORM_FCD, 0, TRUE, &wasNormalized, &status);
1406 if(status == U_BUFFER_OVERFLOW_ERROR || normLen == (int32_t)collationSource->writableBufSize) {
1407 // reallocate and terminate
1408 if(!u_growBufferFromStatic(collationSource->stackWritableBuffer,
1409 &collationSource->writableBuffer,
1410 (int32_t *)&collationSource->writableBufSize, normLen + 1,
1414 fprintf(stderr, "normalizeIterator(), out of memory\n");
1418 status = U_ZERO_ERROR;
1419 //collationSource->iterator->move(collationSource->iterator, iterIndex, UITER_ZERO);
1420 collationSource->iterator->setState(collationSource->iterator, iterIndex, &status);
1421 normLen = unorm_next(collationSource->iterator, collationSource->writableBuffer,
1422 (int32_t)collationSource->writableBufSize, UNORM_FCD, 0, TRUE, &wasNormalized, &status);
1424 // Terminate the buffer - we already checked that it is big enough
1425 collationSource->writableBuffer[normLen] = 0;
1426 if(collationSource->writableBuffer != collationSource->stackWritableBuffer) {
1427 collationSource->flags |= UCOL_ITER_ALLOCATED;
1429 collationSource->pos = collationSource->writableBuffer;
1430 collationSource->origFlags = collationSource->flags;
1431 collationSource->flags |= UCOL_ITER_INNORMBUF;
1432 collationSource->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
1436 /* Incremental FCD check and normalize */
1437 /* Called from getNextCE when normalization state is suspect. */
1438 /* When entering, the state is known to be this: */
1439 /* o We are working in the main buffer of the collIterate, not the side */
1440 /* writable buffer. When in the side buffer, normalization mode is always off, */
1441 /* so we won't get here. */
1442 /* o The leading combining class from the current character is 0 or */
1443 /* the trailing combining class of the previous char was zero. */
1444 /* True because the previous call to this function will have always exited */
1445 /* that way, and we get called for every char where cc might be non-zero. */
1447 inline UBool
collIterFCD(collIterate
*collationSource
) {
1448 const UChar
*srcP
, *endP
;
1450 uint8_t prevTrailingCC
= 0;
1452 UBool needNormalize
= FALSE
;
1454 srcP
= collationSource
->pos
-1;
1456 if (collationSource
->flags
& UCOL_ITER_HASLEN
) {
1457 endP
= collationSource
->endp
;
1462 // Get the trailing combining class of the current character. If it's zero, we are OK.
1463 fcd
= g_nfcImpl
->nextFCD16(srcP
, endP
);
1465 prevTrailingCC
= (uint8_t)(fcd
& LAST_BYTE_MASK_
);
1467 if (prevTrailingCC
!= 0) {
1468 // The current char has a non-zero trailing CC. Scan forward until we find
1469 // a char with a leading cc of zero.
1470 while (endP
== NULL
|| srcP
!= endP
)
1472 const UChar
*savedSrcP
= srcP
;
1474 fcd
= g_nfcImpl
->nextFCD16(srcP
, endP
);
1475 leadingCC
= (uint8_t)(fcd
>> SECOND_LAST_BYTE_SHIFT_
);
1476 if (leadingCC
== 0) {
1477 srcP
= savedSrcP
; // Hit char that is not part of combining sequence.
1478 // back up over it. (Could be surrogate pair!)
1482 if (leadingCC
< prevTrailingCC
) {
1483 needNormalize
= TRUE
;
1486 prevTrailingCC
= (uint8_t)(fcd
& LAST_BYTE_MASK_
);
1491 collationSource
->fcdPosition
= (UChar
*)srcP
;
1493 return needNormalize
;
1496 /****************************************************************************/
1497 /* Following are the CE retrieval functions */
1499 /****************************************************************************/
1501 static uint32_t getImplicit(UChar32 cp
, collIterate
*collationSource
);
1502 static uint32_t getPrevImplicit(UChar32 cp
, collIterate
*collationSource
);
1504 /* there should be a macro version of this function in the header file */
1505 /* This is the first function that tries to fetch a collation element */
1506 /* If it's not succesfull or it encounters a more difficult situation */
1507 /* some more sofisticated and slower functions are invoked */
1509 inline uint32_t ucol_IGetNextCE(const UCollator
*coll
, collIterate
*collationSource
, UErrorCode
*status
) {
1511 if (collationSource
->CEpos
> collationSource
->toReturn
) { /* Are there any CEs from previous expansions? */
1512 order
= *(collationSource
->toReturn
++); /* if so, return them */
1513 if(collationSource
->CEpos
== collationSource
->toReturn
) {
1514 collationSource
->CEpos
= collationSource
->toReturn
= collationSource
->extendCEs
? collationSource
->extendCEs
: collationSource
->CEs
;
1520 collationSource
->offsetReturn
= NULL
;
1523 for (;;) /* Loop handles case when incremental normalize switches */
1524 { /* to or from the side buffer / original string, and we */
1525 /* need to start again to get the next character. */
1527 if ((collationSource
->flags
& (UCOL_ITER_HASLEN
| UCOL_ITER_INNORMBUF
| UCOL_ITER_NORM
| UCOL_HIRAGANA_Q
| UCOL_USE_ITERATOR
)) == 0)
1529 // The source string is null terminated and we're not working from the side buffer,
1530 // and we're not normalizing. This is the fast path.
1531 // (We can be in the side buffer for Thai pre-vowel reordering even when not normalizing.)
1532 ch
= *collationSource
->pos
++;
1537 return UCOL_NO_MORE_CES
;
1541 if (collationSource
->flags
& UCOL_ITER_HASLEN
) {
1542 // Normal path for strings when length is specified.
1543 // (We can't be in side buffer because it is always null terminated.)
1544 if (collationSource
->pos
>= collationSource
->endp
) {
1545 // Ran off of the end of the main source string. We're done.
1546 return UCOL_NO_MORE_CES
;
1548 ch
= *collationSource
->pos
++;
1550 else if(collationSource
->flags
& UCOL_USE_ITERATOR
) {
1551 UChar32 iterCh
= collationSource
->iterator
->next(collationSource
->iterator
);
1552 if(iterCh
== U_SENTINEL
) {
1553 return UCOL_NO_MORE_CES
;
1559 // Null terminated string.
1560 ch
= *collationSource
->pos
++;
1562 // Ran off end of buffer.
1563 if ((collationSource
->flags
& UCOL_ITER_INNORMBUF
) == 0) {
1564 // Ran off end of main string. backing up one character.
1565 collationSource
->pos
--;
1566 return UCOL_NO_MORE_CES
;
1570 // Hit null in the normalize side buffer.
1571 // Usually this means the end of the normalized data,
1572 // except for one odd case: a null followed by combining chars,
1573 // which is the case if we are at the start of the buffer.
1574 if (collationSource
->pos
== collationSource
->writableBuffer
.getBuffer()+1) {
1578 // Null marked end of side buffer.
1579 // Revert to the main string and
1580 // loop back to top to try again to get a character.
1581 collationSource
->pos
= collationSource
->fcdPosition
;
1582 collationSource
->flags
= collationSource
->origFlags
;
1588 if(collationSource
->flags
&UCOL_HIRAGANA_Q
) {
1589 /* Codepoints \u3099-\u309C are both Hiragana and Katakana. Set the flag
1590 * based on whether the previous codepoint was Hiragana or Katakana.
1592 if(((ch
>=0x3040 && ch
<=0x3096) || (ch
>= 0x309d && ch
<= 0x309f)) ||
1593 ((collationSource
->flags
& UCOL_WAS_HIRAGANA
) && (ch
>= 0x3099 && ch
<= 0x309C))) {
1594 collationSource
->flags
|= UCOL_WAS_HIRAGANA
;
1596 collationSource
->flags
&= ~UCOL_WAS_HIRAGANA
;
1600 // We've got a character. See if there's any fcd and/or normalization stuff to do.
1601 // Note that UCOL_ITER_NORM flag is always zero when we are in the side buffer.
1602 if ((collationSource
->flags
& UCOL_ITER_NORM
) == 0) {
1606 if (collationSource
->fcdPosition
>= collationSource
->pos
) {
1607 // An earlier FCD check has already covered the current character.
1608 // We can go ahead and process this char.
1612 if (ch
< ZERO_CC_LIMIT_
) {
1613 // Fast fcd safe path. Trailing combining class == 0. This char is OK.
1617 if (ch
< NFC_ZERO_CC_BLOCK_LIMIT_
) {
1618 // We need to peek at the next character in order to tell if we are FCD
1619 if ((collationSource
->flags
& UCOL_ITER_HASLEN
) && collationSource
->pos
>= collationSource
->endp
) {
1620 // We are at the last char of source string.
1621 // It is always OK for FCD check.
1625 // Not at last char of source string (or we'll check against terminating null). Do the FCD fast test
1626 if (*collationSource
->pos
< NFC_ZERO_CC_BLOCK_LIMIT_
) {
1632 // Need a more complete FCD check and possible normalization.
1633 if (collIterFCD(collationSource
)) {
1634 collIterNormalize(collationSource
);
1636 if ((collationSource
->flags
& UCOL_ITER_INNORMBUF
) == 0) {
1637 // No normalization was needed. Go ahead and process the char we already had.
1641 // Some normalization happened. Next loop iteration will pick up a char
1642 // from the normalization buffer.
1648 /* For latin-1 characters we never need to fall back to the UCA table */
1649 /* because all of the UCA data is replicated in the latinOneMapping array */
1650 order
= coll
->latinOneMapping
[ch
];
1651 if (order
> UCOL_NOT_FOUND
) {
1652 order
= ucol_prv_getSpecialCE(coll
, ch
, order
, collationSource
, status
);
1657 // Always use UCA for Han, Hangul
1658 // (Han extension A is before main Han block)
1659 // **** Han compatibility chars ?? ****
1660 if ((collationSource
->flags
& UCOL_FORCE_HAN_IMPLICIT
) != 0 &&
1661 (ch
>= UCOL_FIRST_HAN_A
&& ch
<= UCOL_LAST_HANGUL
)) {
1662 if (ch
> UCOL_LAST_HAN
&& ch
< UCOL_FIRST_HANGUL
) {
1663 // between the two target ranges; do normal lookup
1664 // **** this range is YI, Modifier tone letters, ****
1665 // **** Latin-D, Syloti Nagari, Phagas-pa. ****
1666 // **** Latin-D might be tailored, so we need to ****
1667 // **** do the normal lookup for these guys. ****
1668 order
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, ch
);
1670 // in one of the target ranges; use UCA
1671 order
= UCOL_NOT_FOUND
;
1674 order
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, ch
);
1677 if(order
> UCOL_NOT_FOUND
) { /* if a CE is special */
1678 order
= ucol_prv_getSpecialCE(coll
, ch
, order
, collationSource
, status
); /* and try to get the special CE */
1681 if(order
== UCOL_NOT_FOUND
&& coll
->UCA
) { /* We couldn't find a good CE in the tailoring */
1682 /* if we got here, the codepoint MUST be over 0xFF - so we look directly in the trie */
1683 order
= UTRIE_GET32_FROM_LEAD(&coll
->UCA
->mapping
, ch
);
1685 if(order
> UCOL_NOT_FOUND
) { /* UCA also gives us a special CE */
1686 order
= ucol_prv_getSpecialCE(coll
->UCA
, ch
, order
, collationSource
, status
);
1690 } while ( order
== UCOL_IGNORABLE
&& ch
>= UCOL_FIRST_HANGUL
&& ch
<= UCOL_LAST_HANGUL
);
1692 if(order
== UCOL_NOT_FOUND
) {
1693 order
= getImplicit(ch
, collationSource
);
1695 return order
; /* return the CE */
1698 /* ucol_getNextCE, out-of-line version for use from other files. */
1699 U_CAPI
uint32_t U_EXPORT2
1700 ucol_getNextCE(const UCollator
*coll
, collIterate
*collationSource
, UErrorCode
*status
) {
1701 return ucol_IGetNextCE(coll
, collationSource
, status
);
1706 * Incremental previous normalization happens here. Pick up the range of chars
1707 * identifed by FCD, normalize it into the collIterate's writable buffer,
1708 * switch the collIterate's state to use the writable buffer.
1709 * @param data collation iterator data
1712 void collPrevIterNormalize(collIterate
*data
)
1714 UErrorCode status
= U_ZERO_ERROR
;
1715 const UChar
*pEnd
= data
->pos
; /* End normalize + 1 */
1716 const UChar
*pStart
;
1718 /* Start normalize */
1719 if (data
->fcdPosition
== NULL
) {
1720 pStart
= data
->string
;
1723 pStart
= data
->fcdPosition
+ 1;
1727 data
->nfd
->normalize(UnicodeString(FALSE
, pStart
, (int32_t)((pEnd
- pStart
) + 1)),
1728 data
->writableBuffer
,
1731 if(U_FAILURE(status
)) {
1735 this puts the null termination infront of the normalized string instead
1738 data
->writableBuffer
.insert(0, (UChar
)0);
1741 * The usual case at this point is that we've got a base
1742 * character followed by marks that were normalized. If
1743 * fcdPosition is NULL, that means that we backed up to
1744 * the beginning of the string and there's no base character.
1746 * Forward processing will usually normalize when it sees
1747 * the first mark, so that mark will get it's natural offset
1748 * and the rest will get the offset of the character following
1749 * the marks. The base character will also get its natural offset.
1751 * We write the offset of the base character, if there is one,
1752 * followed by the offset of the first mark and then the offsets
1753 * of the rest of the marks.
1755 int32_t firstMarkOffset
= 0;
1756 int32_t trailOffset
= (int32_t)(data
->pos
- data
->string
+ 1);
1757 int32_t trailCount
= normLen
- 1;
1759 if (data
->fcdPosition
!= NULL
) {
1760 int32_t baseOffset
= (int32_t)(data
->fcdPosition
- data
->string
);
1761 UChar baseChar
= *data
->fcdPosition
;
1763 firstMarkOffset
= baseOffset
+ 1;
1766 * If the base character is the start of a contraction, forward processing
1767 * will normalize the marks while checking for the contraction, which means
1768 * that the offset of the first mark will the same as the other marks.
1770 * **** THIS IS PROBABLY NOT A COMPLETE TEST ****
1772 if (baseChar
>= 0x100) {
1773 uint32_t baseOrder
= UTRIE_GET32_FROM_LEAD(&data
->coll
->mapping
, baseChar
);
1775 if (baseOrder
== UCOL_NOT_FOUND
&& data
->coll
->UCA
) {
1776 baseOrder
= UTRIE_GET32_FROM_LEAD(&data
->coll
->UCA
->mapping
, baseChar
);
1779 if (baseOrder
> UCOL_NOT_FOUND
&& getCETag(baseOrder
) == CONTRACTION_TAG
) {
1780 firstMarkOffset
= trailOffset
;
1784 data
->appendOffset(baseOffset
, status
);
1787 data
->appendOffset(firstMarkOffset
, status
);
1789 for (int32_t i
= 0; i
< trailCount
; i
+= 1) {
1790 data
->appendOffset(trailOffset
, status
);
1793 data
->offsetRepeatValue
= trailOffset
;
1795 data
->offsetReturn
= data
->offsetStore
- 1;
1796 if (data
->offsetReturn
== data
->offsetBuffer
) {
1797 data
->offsetStore
= data
->offsetBuffer
;
1800 data
->pos
= data
->writableBuffer
.getTerminatedBuffer() + 1 + normLen
;
1801 data
->origFlags
= data
->flags
;
1802 data
->flags
|= UCOL_ITER_INNORMBUF
;
1803 data
->flags
&= ~(UCOL_ITER_NORM
| UCOL_ITER_HASLEN
);
1808 * Incremental FCD check for previous iteration and normalize. Called from
1809 * getPrevCE when normalization state is suspect.
1810 * When entering, the state is known to be this:
1811 * o We are working in the main buffer of the collIterate, not the side
1812 * writable buffer. When in the side buffer, normalization mode is always
1813 * off, so we won't get here.
1814 * o The leading combining class from the current character is 0 or the
1815 * trailing combining class of the previous char was zero.
1816 * True because the previous call to this function will have always exited
1817 * that way, and we get called for every char where cc might be non-zero.
1818 * @param data collation iterate struct
1819 * @return normalization status, TRUE for normalization to be done, FALSE
1823 inline UBool
collPrevIterFCD(collIterate
*data
)
1825 const UChar
*src
, *start
;
1827 uint8_t trailingCC
= 0;
1829 UBool result
= FALSE
;
1831 start
= data
->string
;
1832 src
= data
->pos
+ 1;
1834 /* Get the trailing combining class of the current character. */
1835 fcd
= g_nfcImpl
->previousFCD16(start
, src
);
1837 leadingCC
= (uint8_t)(fcd
>> SECOND_LAST_BYTE_SHIFT_
);
1839 if (leadingCC
!= 0) {
1841 The current char has a non-zero leading combining class.
1842 Scan backward until we find a char with a trailing cc of zero.
1847 data
->fcdPosition
= NULL
;
1851 fcd
= g_nfcImpl
->previousFCD16(start
, src
);
1853 trailingCC
= (uint8_t)(fcd
& LAST_BYTE_MASK_
);
1855 if (trailingCC
== 0) {
1859 if (leadingCC
< trailingCC
) {
1863 leadingCC
= (uint8_t)(fcd
>> SECOND_LAST_BYTE_SHIFT_
);
1867 data
->fcdPosition
= (UChar
*)src
;
1872 /** gets a code unit from the string at a given offset
1873 * Handles both normal and iterative cases.
1874 * No error checking - caller beware!
1877 UChar
peekCodeUnit(collIterate
*source
, int32_t offset
) {
1878 if(source
->pos
!= NULL
) {
1879 return *(source
->pos
+ offset
);
1880 } else if(source
->iterator
!= NULL
) {
1883 source
->iterator
->move(source
->iterator
, offset
, UITER_CURRENT
);
1884 c
= source
->iterator
->next(source
->iterator
);
1885 source
->iterator
->move(source
->iterator
, -offset
-1, UITER_CURRENT
);
1887 c
= source
->iterator
->current(source
->iterator
);
1889 return c
>= 0 ? (UChar
)c
: 0xfffd; // If the caller works properly, we should never see c<0.
1895 // Code point version. Treats the offset as a _code point_ delta.
1896 // We cannot use U16_FWD_1_UNSAFE and similar because we might not have well-formed UTF-16.
1897 // We cannot use U16_FWD_1 and similar because we do not know the start and limit of the buffer.
1899 UChar32
peekCodePoint(collIterate
*source
, int32_t offset
) {
1901 if(source
->pos
!= NULL
) {
1902 const UChar
*p
= source
->pos
;
1904 // Skip forward over (offset-1) code points.
1905 while(--offset
>= 0) {
1906 if(U16_IS_LEAD(*p
++) && U16_IS_TRAIL(*p
)) {
1910 // Read the code point there.
1913 if(U16_IS_LEAD(c
) && U16_IS_TRAIL(trail
= *p
)) {
1914 c
= U16_GET_SUPPLEMENTARY(c
, trail
);
1916 } else /* offset<0 */ {
1917 // Skip backward over (offset-1) code points.
1918 while(++offset
< 0) {
1919 if(U16_IS_TRAIL(*--p
) && U16_IS_LEAD(*(p
- 1))) {
1923 // Read the code point before that.
1926 if(U16_IS_TRAIL(c
) && U16_IS_LEAD(lead
= *(p
- 1))) {
1927 c
= U16_GET_SUPPLEMENTARY(lead
, c
);
1930 } else if(source
->iterator
!= NULL
) {
1932 // Skip forward over (offset-1) code points.
1933 int32_t fwd
= offset
;
1935 uiter_next32(source
->iterator
);
1937 // Read the code point there.
1938 c
= uiter_current32(source
->iterator
);
1939 // Return to the starting point, skipping backward over (offset-1) code points.
1940 while(offset
-- > 0) {
1941 uiter_previous32(source
->iterator
);
1943 } else /* offset<0 */ {
1944 // Read backward, reading offset code points, remember only the last-read one.
1945 int32_t back
= offset
;
1947 c
= uiter_previous32(source
->iterator
);
1948 } while(++back
< 0);
1949 // Return to the starting position, skipping forward over offset code points.
1951 uiter_next32(source
->iterator
);
1952 } while(++offset
< 0);
1961 * Determines if we are at the start of the data string in the backwards
1962 * collation iterator
1963 * @param data collation iterator
1964 * @return TRUE if we are at the start
1967 inline UBool
isAtStartPrevIterate(collIterate
*data
) {
1968 if(data
->pos
== NULL
&& data
->iterator
!= NULL
) {
1969 return !data
->iterator
->hasPrevious(data
->iterator
);
1971 //return (collIter_bos(data)) ||
1972 return (data
->pos
== data
->string
) ||
1973 ((data
->flags
& UCOL_ITER_INNORMBUF
) && (data
->pos
!= NULL
) &&
1974 *(data
->pos
- 1) == 0 && data
->fcdPosition
== NULL
);
1978 inline void goBackOne(collIterate
*data
) {
1980 // somehow, it looks like we need to keep iterator synced up
1981 // at all times, as above.
1985 if(data
->iterator
) {
1986 data
->iterator
->previous(data
->iterator
);
1989 if(data
->iterator
&& (data
->flags
& UCOL_USE_ITERATOR
)) {
1990 data
->iterator
->previous(data
->iterator
);
1998 * Inline function that gets a simple CE.
1999 * So what it does is that it will first check the expansion buffer. If the
2000 * expansion buffer is not empty, ie the end pointer to the expansion buffer
2001 * is different from the string pointer, we return the collation element at the
2002 * return pointer and decrement it.
2003 * For more complicated CEs it resorts to getComplicatedCE.
2004 * @param coll collator data
2005 * @param data collation iterator struct
2006 * @param status error status
2009 inline uint32_t ucol_IGetPrevCE(const UCollator
*coll
, collIterate
*data
,
2012 uint32_t result
= (uint32_t)UCOL_NULLORDER
;
2014 if (data
->offsetReturn
!= NULL
) {
2015 if (data
->offsetRepeatCount
> 0) {
2016 data
->offsetRepeatCount
-= 1;
2018 if (data
->offsetReturn
== data
->offsetBuffer
) {
2019 data
->offsetReturn
= NULL
;
2020 data
->offsetStore
= data
->offsetBuffer
;
2022 data
->offsetReturn
-= 1;
2027 if ((data
->extendCEs
&& data
->toReturn
> data
->extendCEs
) ||
2028 (!data
->extendCEs
&& data
->toReturn
> data
->CEs
))
2030 data
->toReturn
-= 1;
2031 result
= *(data
->toReturn
);
2032 if (data
->CEs
== data
->toReturn
|| data
->extendCEs
== data
->toReturn
) {
2033 data
->CEpos
= data
->toReturn
;
2041 Loop handles case when incremental normalize switches to or from the
2042 side buffer / original string, and we need to start again to get the
2046 if (data
->flags
& UCOL_ITER_HASLEN
) {
2048 Normal path for strings when length is specified.
2049 Not in side buffer because it is always null terminated.
2051 if (data
->pos
<= data
->string
) {
2052 /* End of the main source string */
2053 return UCOL_NO_MORE_CES
;
2058 // we are using an iterator to go back. Pray for us!
2059 else if (data
->flags
& UCOL_USE_ITERATOR
) {
2060 UChar32 iterCh
= data
->iterator
->previous(data
->iterator
);
2061 if(iterCh
== U_SENTINEL
) {
2062 return UCOL_NO_MORE_CES
;
2070 /* we are in the side buffer. */
2073 At the start of the normalize side buffer.
2075 Because pointer points to the last accessed character,
2076 hence we have to increment it by one here.
2078 data
->flags
= data
->origFlags
;
2079 data
->offsetRepeatValue
= 0;
2081 if (data
->fcdPosition
== NULL
) {
2082 data
->pos
= data
->string
;
2083 return UCOL_NO_MORE_CES
;
2086 data
->pos
= data
->fcdPosition
+ 1;
2093 if(data
->flags
&UCOL_HIRAGANA_Q
) {
2094 if(ch
>=0x3040 && ch
<=0x309f) {
2095 data
->flags
|= UCOL_WAS_HIRAGANA
;
2097 data
->flags
&= ~UCOL_WAS_HIRAGANA
;
2102 * got a character to determine if there's fcd and/or normalization
2104 * if the current character is not fcd.
2105 * if current character is at the start of the string
2106 * Trailing combining class == 0.
2107 * Note if pos is in the writablebuffer, norm is always 0
2109 if (ch
< ZERO_CC_LIMIT_
||
2110 // this should propel us out of the loop in the iterator case
2111 (data
->flags
& UCOL_ITER_NORM
) == 0 ||
2112 (data
->fcdPosition
!= NULL
&& data
->fcdPosition
<= data
->pos
)
2113 || data
->string
== data
->pos
) {
2117 if (ch
< NFC_ZERO_CC_BLOCK_LIMIT_
) {
2118 /* if next character is FCD */
2119 if (data
->pos
== data
->string
) {
2120 /* First char of string is always OK for FCD check */
2124 /* Not first char of string, do the FCD fast test */
2125 if (*(data
->pos
- 1) < NFC_ZERO_CC_BLOCK_LIMIT_
) {
2130 /* Need a more complete FCD check and possible normalization. */
2131 if (collPrevIterFCD(data
)) {
2132 collPrevIterNormalize(data
);
2135 if ((data
->flags
& UCOL_ITER_INNORMBUF
) == 0) {
2136 /* No normalization. Go ahead and process the char. */
2141 Some normalization happened.
2142 Next loop picks up a char from the normalization buffer.
2146 /* attempt to handle contractions, after removal of the backwards
2149 if (ucol_contractionEndCP(ch
, coll
) && !isAtStartPrevIterate(data
)) {
2150 result
= ucol_prv_getSpecialPrevCE(coll
, ch
, UCOL_CONTRACTION
, data
, status
);
2153 result
= coll
->latinOneMapping
[ch
];
2156 // Always use UCA for [3400..9FFF], [AC00..D7AF]
2157 // **** [FA0E..FA2F] ?? ****
2158 if ((data
->flags
& UCOL_FORCE_HAN_IMPLICIT
) != 0 &&
2159 (ch
>= 0x3400 && ch
<= 0xD7AF)) {
2160 if (ch
> 0x9FFF && ch
< 0xAC00) {
2161 // between the two target ranges; do normal lookup
2162 // **** this range is YI, Modifier tone letters, ****
2163 // **** Latin-D, Syloti Nagari, Phagas-pa. ****
2164 // **** Latin-D might be tailored, so we need to ****
2165 // **** do the normal lookup for these guys. ****
2166 result
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, ch
);
2168 result
= UCOL_NOT_FOUND
;
2171 result
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, ch
);
2174 if (result
> UCOL_NOT_FOUND
) {
2175 result
= ucol_prv_getSpecialPrevCE(coll
, ch
, result
, data
, status
);
2177 if (result
== UCOL_NOT_FOUND
) { // Not found in master list
2178 if (!isAtStartPrevIterate(data
) &&
2179 ucol_contractionEndCP(ch
, data
->coll
))
2181 result
= UCOL_CONTRACTION
;
2184 result
= UTRIE_GET32_FROM_LEAD(&coll
->UCA
->mapping
, ch
);
2188 if (result
> UCOL_NOT_FOUND
) {
2190 result
= ucol_prv_getSpecialPrevCE(coll
->UCA
, ch
, result
, data
, status
);
2195 } while ( result
== UCOL_IGNORABLE
&& ch
>= UCOL_FIRST_HANGUL
&& ch
<= UCOL_LAST_HANGUL
);
2197 if(result
== UCOL_NOT_FOUND
) {
2198 result
= getPrevImplicit(ch
, data
);
2206 /* ucol_getPrevCE, out-of-line version for use from other files. */
2207 U_CFUNC
uint32_t U_EXPORT2
2208 ucol_getPrevCE(const UCollator
*coll
, collIterate
*data
,
2209 UErrorCode
*status
) {
2210 return ucol_IGetPrevCE(coll
, data
, status
);
2214 /* this should be connected to special Jamo handling */
2215 U_CFUNC
uint32_t U_EXPORT2
2216 ucol_getFirstCE(const UCollator
*coll
, UChar u
, UErrorCode
*status
) {
2218 IInit_collIterate(coll
, &u
, 1, &colIt
, status
);
2219 if(U_FAILURE(*status
)) {
2222 return ucol_IGetNextCE(coll
, &colIt
, status
);
2226 * Inserts the argument character into the end of the buffer pushing back the
2228 * @param data collIterate struct data
2229 * @param ch character to be appended
2230 * @return the position of the new addition
2233 inline const UChar
* insertBufferEnd(collIterate
*data
, UChar ch
)
2235 int32_t oldLength
= data
->writableBuffer
.length();
2236 return data
->writableBuffer
.append(ch
).getTerminatedBuffer() + oldLength
;
2240 * Inserts the argument string into the end of the buffer pushing back the
2242 * @param data collIterate struct data
2243 * @param string to be appended
2244 * @param length of the string to be appended
2245 * @return the position of the new addition
2248 inline const UChar
* insertBufferEnd(collIterate
*data
, const UChar
*str
, int32_t length
)
2250 int32_t oldLength
= data
->writableBuffer
.length();
2251 return data
->writableBuffer
.append(str
, length
).getTerminatedBuffer() + oldLength
;
2255 * Special normalization function for contraction in the forwards iterator.
2256 * This normalization sequence will place the current character at source->pos
2257 * and its following normalized sequence into the buffer.
2258 * The fcd position, pos will be changed.
2259 * pos will now point to positions in the buffer.
2260 * Flags will be changed accordingly.
2261 * @param data collation iterator data
2264 inline void normalizeNextContraction(collIterate
*data
)
2267 UErrorCode status
= U_ZERO_ERROR
;
2268 /* because the pointer points to the next character */
2269 const UChar
*pStart
= data
->pos
- 1;
2272 if ((data
->flags
& UCOL_ITER_INNORMBUF
) == 0) {
2273 data
->writableBuffer
.setTo(*(pStart
- 1));
2277 strsize
= data
->writableBuffer
.length();
2280 pEnd
= data
->fcdPosition
;
2282 data
->writableBuffer
.append(
2283 data
->nfd
->normalize(UnicodeString(FALSE
, pStart
, (int32_t)(pEnd
- pStart
)), status
));
2284 if(U_FAILURE(status
)) {
2288 data
->pos
= data
->writableBuffer
.getTerminatedBuffer() + strsize
;
2289 data
->origFlags
= data
->flags
;
2290 data
->flags
|= UCOL_ITER_INNORMBUF
;
2291 data
->flags
&= ~(UCOL_ITER_NORM
| UCOL_ITER_HASLEN
);
2295 * Contraction character management function that returns the next character
2296 * for the forwards iterator.
2297 * Does nothing if the next character is in buffer and not the first character
2299 * Else it checks next character in data string to see if it is normalizable.
2300 * If it is not, the character is simply copied into the buffer, else
2301 * the whole normalized substring is copied into the buffer, including the
2302 * current character.
2303 * @param data collation element iterator data
2304 * @return next character
2307 inline UChar
getNextNormalizedChar(collIterate
*data
)
2311 // Here we need to add the iterator code. One problem is the way
2312 // end of string is handled. If we just return next char, it could
2313 // be the sentinel. Most of the cases already check for this, but we
2315 if ((data
->flags
& (UCOL_ITER_NORM
| UCOL_ITER_INNORMBUF
)) == 0 ) {
2316 /* if no normalization and not in buffer. */
2317 if(data
->flags
& UCOL_USE_ITERATOR
) {
2318 return (UChar
)data
->iterator
->next(data
->iterator
);
2320 return *(data
->pos
++);
2324 //if (data->flags & UCOL_ITER_NORM && data->flags & UCOL_USE_ITERATOR) {
2325 //normalizeIterator(data);
2328 UBool innormbuf
= (UBool
)(data
->flags
& UCOL_ITER_INNORMBUF
);
2329 if ((innormbuf
&& *data
->pos
!= 0) ||
2330 (data
->fcdPosition
!= NULL
&& !innormbuf
&&
2331 data
->pos
< data
->fcdPosition
)) {
2333 if next character is in normalized buffer, no further normalization
2336 return *(data
->pos
++);
2339 if (data
->flags
& UCOL_ITER_HASLEN
) {
2340 /* in data string */
2341 if (data
->pos
+ 1 == data
->endp
) {
2342 return *(data
->pos
++);
2347 // inside the normalization buffer, but at the end
2348 // (since we encountered zero). This means, in the
2349 // case we're using char iterator, that we need to
2350 // do another round of normalization.
2351 //if(data->origFlags & UCOL_USE_ITERATOR) {
2352 // we need to restore original flags,
2353 // otherwise, we'll lose them
2354 //data->flags = data->origFlags;
2355 //normalizeIterator(data);
2356 //return *(data->pos++);
2359 in writable buffer, at this point fcdPosition can not be
2360 pointing to the end of the data string. see contracting tag.
2362 if(data
->fcdPosition
) {
2363 if (*(data
->fcdPosition
+ 1) == 0 ||
2364 data
->fcdPosition
+ 1 == data
->endp
) {
2365 /* at the end of the string, dump it into the normalizer */
2366 data
->pos
= insertBufferEnd(data
, *(data
->fcdPosition
)) + 1;
2367 // Check if data->pos received a null pointer
2368 if (data
->pos
== NULL
) {
2369 return (UChar
)-1; // Return to indicate error.
2371 return *(data
->fcdPosition
++);
2373 data
->pos
= data
->fcdPosition
;
2374 } else if(data
->origFlags
& UCOL_USE_ITERATOR
) {
2375 // if we are here, we're using a normalizing iterator.
2376 // we should just continue further.
2377 data
->flags
= data
->origFlags
;
2379 return (UChar
)data
->iterator
->next(data
->iterator
);
2384 if (*(data
->pos
+ 1) == 0) {
2385 return *(data
->pos
++);
2391 nextch
= *data
->pos
;
2394 * if the current character is not fcd.
2395 * Trailing combining class == 0.
2397 if ((data
->fcdPosition
== NULL
|| data
->fcdPosition
< data
->pos
) &&
2398 (nextch
>= NFC_ZERO_CC_BLOCK_LIMIT_
||
2399 ch
>= NFC_ZERO_CC_BLOCK_LIMIT_
)) {
2401 Need a more complete FCD check and possible normalization.
2402 normalize substring will be appended to buffer
2404 if (collIterFCD(data
)) {
2405 normalizeNextContraction(data
);
2406 return *(data
->pos
++);
2408 else if (innormbuf
) {
2409 /* fcdposition shifted even when there's no normalization, if we
2410 don't input the rest into this, we'll get the wrong position when
2411 we reach the end of the writableBuffer */
2412 int32_t length
= (int32_t)(data
->fcdPosition
- data
->pos
+ 1);
2413 data
->pos
= insertBufferEnd(data
, data
->pos
- 1, length
);
2414 // Check if data->pos received a null pointer
2415 if (data
->pos
== NULL
) {
2416 return (UChar
)-1; // Return to indicate error.
2418 return *(data
->pos
++);
2424 no normalization is to be done hence only one character will be
2425 appended to the buffer.
2427 data
->pos
= insertBufferEnd(data
, ch
) + 1;
2428 // Check if data->pos received a null pointer
2429 if (data
->pos
== NULL
) {
2430 return (UChar
)-1; // Return to indicate error.
2434 /* points back to the pos in string */
2441 * Function to copy the buffer into writableBuffer and sets the fcd position to
2442 * the correct position
2443 * @param source data string source
2444 * @param buffer character buffer
2447 inline void setDiscontiguosAttribute(collIterate
*source
, const UnicodeString
&buffer
)
2449 /* okay confusing part here. to ensure that the skipped characters are
2450 considered later, we need to place it in the appropriate position in the
2451 normalization buffer and reassign the pos pointer. simple case if pos
2452 reside in string, simply copy to normalization buffer and
2453 fcdposition = pos, pos = start of normalization buffer. if pos in
2454 normalization buffer, we'll insert the copy infront of pos and point pos
2455 to the start of the normalization buffer. why am i doing these copies?
2456 well, so that the whole chunk of codes in the getNextCE, ucol_prv_getSpecialCE does
2457 not require any changes, which be really painful. */
2458 if (source
->flags
& UCOL_ITER_INNORMBUF
) {
2459 int32_t replaceLength
= source
->pos
- source
->writableBuffer
.getBuffer();
2460 source
->writableBuffer
.replace(0, replaceLength
, buffer
);
2463 source
->fcdPosition
= source
->pos
;
2464 source
->origFlags
= source
->flags
;
2465 source
->flags
|= UCOL_ITER_INNORMBUF
;
2466 source
->flags
&= ~(UCOL_ITER_NORM
| UCOL_ITER_HASLEN
| UCOL_USE_ITERATOR
);
2467 source
->writableBuffer
= buffer
;
2470 source
->pos
= source
->writableBuffer
.getTerminatedBuffer();
2474 * Function to get the discontiguos collation element within the source.
2475 * Note this function will set the position to the appropriate places.
2476 * @param coll current collator used
2477 * @param source data string source
2478 * @param constart index to the start character in the contraction table
2479 * @return discontiguos collation element offset
2482 uint32_t getDiscontiguous(const UCollator
*coll
, collIterate
*source
,
2483 const UChar
*constart
)
2485 /* source->pos currently points to the second combining character after
2486 the start character */
2487 const UChar
*temppos
= source
->pos
;
2488 UnicodeString buffer
;
2489 const UChar
*tempconstart
= constart
;
2490 uint8_t tempflags
= source
->flags
;
2491 UBool multicontraction
= FALSE
;
2492 collIterateState discState
;
2494 backupState(source
, &discState
);
2496 buffer
.setTo(peekCodePoint(source
, -1));
2503 if (((source
->flags
& UCOL_ITER_HASLEN
) && source
->pos
>= source
->endp
)
2504 || (peekCodeUnit(source
, 0) == 0 &&
2505 //|| (*source->pos == 0 &&
2506 ((source
->flags
& UCOL_ITER_INNORMBUF
) == 0 ||
2507 source
->fcdPosition
== NULL
||
2508 source
->fcdPosition
== source
->endp
||
2509 *(source
->fcdPosition
) == 0 ||
2510 u_getCombiningClass(*(source
->fcdPosition
)) == 0)) ||
2511 /* end of string in null terminated string or stopped by a
2512 null character, note fcd does not always point to a base
2513 character after the discontiguos change */
2514 u_getCombiningClass(peekCodePoint(source
, 0)) == 0) {
2515 //u_getCombiningClass(*(source->pos)) == 0) {
2516 //constart = (UChar *)coll->image + getContractOffset(CE);
2517 if (multicontraction
) {
2518 source
->pos
= temppos
- 1;
2519 setDiscontiguosAttribute(source
, buffer
);
2520 return *(coll
->contractionCEs
+
2521 (tempconstart
- coll
->contractionIndex
));
2523 constart
= tempconstart
;
2527 UCharOffset
= (UChar
*)(tempconstart
+ 1); /* skip the backward offset*/
2528 schar
= getNextNormalizedChar(source
);
2530 while (schar
> (tchar
= *UCharOffset
)) {
2534 if (schar
!= tchar
) {
2535 /* not the correct codepoint. we stuff the current codepoint into
2536 the discontiguos buffer and try the next character */
2537 buffer
.append(schar
);
2541 if (u_getCombiningClass(schar
) ==
2542 u_getCombiningClass(peekCodePoint(source
, -2))) {
2543 buffer
.append(schar
);
2546 result
= *(coll
->contractionCEs
+
2547 (UCharOffset
- coll
->contractionIndex
));
2550 if (result
== UCOL_NOT_FOUND
) {
2552 } else if (isContraction(result
)) {
2553 /* this is a multi-contraction*/
2554 tempconstart
= (UChar
*)coll
->image
+ getContractOffset(result
);
2555 if (*(coll
->contractionCEs
+ (constart
- coll
->contractionIndex
))
2556 != UCOL_NOT_FOUND
) {
2557 multicontraction
= TRUE
;
2558 temppos
= source
->pos
+ 1;
2561 setDiscontiguosAttribute(source
, buffer
);
2566 /* no problems simply reverting just like that,
2567 if we are in string before getting into this function, points back to
2568 string hence no problem.
2569 if we are in normalization buffer before getting into this function,
2570 since we'll never use another normalization within this function, we
2571 know that fcdposition points to a base character. the normalization buffer
2572 never change, hence this revert works. */
2573 loadState(source
, &discState
, TRUE
);
2576 //source->pos = temppos - 1;
2577 source
->flags
= tempflags
;
2578 return *(coll
->contractionCEs
+ (constart
- coll
->contractionIndex
));
2581 /* now uses Mark's getImplicitPrimary code */
2583 inline uint32_t getImplicit(UChar32 cp
, collIterate
*collationSource
) {
2584 uint32_t r
= uprv_uca_getImplicitPrimary(cp
);
2585 *(collationSource
->CEpos
++) = ((r
& 0x0000FFFF)<<16) | 0x000000C0;
2586 collationSource
->offsetRepeatCount
+= 1;
2587 return (r
& UCOL_PRIMARYMASK
) | 0x00000505; // This was 'order'
2591 * Inserts the argument character into the front of the buffer replacing the
2592 * front null terminator.
2593 * @param data collation element iterator data
2594 * @param ch character to be appended
2597 inline void insertBufferFront(collIterate
*data
, UChar ch
)
2599 data
->pos
= data
->writableBuffer
.setCharAt(0, ch
).insert(0, (UChar
)0).getTerminatedBuffer() + 2;
2603 * Special normalization function for contraction in the previous iterator.
2604 * This normalization sequence will place the current character at source->pos
2605 * and its following normalized sequence into the buffer.
2606 * The fcd position, pos will be changed.
2607 * pos will now point to positions in the buffer.
2608 * Flags will be changed accordingly.
2609 * @param data collation iterator data
2612 inline void normalizePrevContraction(collIterate
*data
, UErrorCode
*status
)
2614 const UChar
*pEnd
= data
->pos
+ 1; /* End normalize + 1 */
2615 const UChar
*pStart
;
2617 UnicodeString endOfBuffer
;
2618 if (data
->flags
& UCOL_ITER_HASLEN
) {
2620 normalization buffer not used yet, we'll pull down the next
2621 character into the end of the buffer
2623 endOfBuffer
.setTo(*pEnd
);
2626 endOfBuffer
.setTo(data
->writableBuffer
, 1); // after the leading NUL
2629 if (data
->fcdPosition
== NULL
) {
2630 pStart
= data
->string
;
2633 pStart
= data
->fcdPosition
+ 1;
2636 data
->nfd
->normalize(UnicodeString(FALSE
, pStart
, (int32_t)(pEnd
- pStart
)),
2637 data
->writableBuffer
,
2640 if(U_FAILURE(*status
)) {
2644 this puts the null termination infront of the normalized string instead
2648 data
->writableBuffer
.insert(0, (UChar
)0).append(endOfBuffer
).getTerminatedBuffer() +
2650 data
->origFlags
= data
->flags
;
2651 data
->flags
|= UCOL_ITER_INNORMBUF
;
2652 data
->flags
&= ~(UCOL_ITER_NORM
| UCOL_ITER_HASLEN
);
2656 * Contraction character management function that returns the previous character
2657 * for the backwards iterator.
2658 * Does nothing if the previous character is in buffer and not the first
2660 * Else it checks previous character in data string to see if it is
2662 * If it is not, the character is simply copied into the buffer, else
2663 * the whole normalized substring is copied into the buffer, including the
2664 * current character.
2665 * @param data collation element iterator data
2666 * @return previous character
2669 inline UChar
getPrevNormalizedChar(collIterate
*data
, UErrorCode
*status
)
2674 UBool innormbuf
= (UBool
)(data
->flags
& UCOL_ITER_INNORMBUF
);
2675 if ((data
->flags
& (UCOL_ITER_NORM
| UCOL_ITER_INNORMBUF
)) == 0 ||
2676 (innormbuf
&& *(data
->pos
- 1) != 0)) {
2678 if no normalization.
2679 if previous character is in normalized buffer, no further normalization
2682 if(data
->flags
& UCOL_USE_ITERATOR
) {
2683 data
->iterator
->move(data
->iterator
, -1, UITER_CURRENT
);
2684 return (UChar
)data
->iterator
->next(data
->iterator
);
2686 return *(data
->pos
- 1);
2691 if ((data
->fcdPosition
==NULL
)||(data
->flags
& UCOL_ITER_HASLEN
)) {
2692 /* in data string */
2693 if ((start
- 1) == data
->string
) {
2694 return *(start
- 1);
2698 prevch
= *(start
- 1);
2702 in writable buffer, at this point fcdPosition can not be NULL.
2703 see contracting tag.
2705 if (data
->fcdPosition
== data
->string
) {
2706 /* at the start of the string, just dump it into the normalizer */
2707 insertBufferFront(data
, *(data
->fcdPosition
));
2708 data
->fcdPosition
= NULL
;
2709 return *(data
->pos
- 1);
2711 start
= data
->fcdPosition
;
2713 prevch
= *(start
- 1);
2716 * if the current character is not fcd.
2717 * Trailing combining class == 0.
2719 if (data
->fcdPosition
> start
&&
2720 (ch
>= NFC_ZERO_CC_BLOCK_LIMIT_
|| prevch
>= NFC_ZERO_CC_BLOCK_LIMIT_
))
2723 Need a more complete FCD check and possible normalization.
2724 normalize substring will be appended to buffer
2726 const UChar
*backuppos
= data
->pos
;
2728 if (collPrevIterFCD(data
)) {
2729 normalizePrevContraction(data
, status
);
2730 return *(data
->pos
- 1);
2732 data
->pos
= backuppos
;
2733 data
->fcdPosition
++;
2738 no normalization is to be done hence only one character will be
2739 appended to the buffer.
2741 insertBufferFront(data
, ch
);
2742 data
->fcdPosition
--;
2748 /* This function handles the special CEs like contractions, expansions, surrogates, Thai */
2749 /* It is called by getNextCE */
2751 /* The following should be even */
2752 #define UCOL_MAX_DIGITS_FOR_NUMBER 254
2754 uint32_t ucol_prv_getSpecialCE(const UCollator
*coll
, UChar ch
, uint32_t CE
, collIterate
*source
, UErrorCode
*status
) {
2755 collIterateState entryState
;
2756 backupState(source
, &entryState
);
2760 // This loop will repeat only in the case of contractions, and only when a contraction
2761 // is found and the first CE resulting from that contraction is itself a special
2762 // (an expansion, for example.) All other special CE types are fully handled the
2763 // first time through, and the loop exits.
2765 const uint32_t *CEOffset
= NULL
;
2766 switch(getCETag(CE
)) {
2768 /* This one is not found, and we'll let somebody else bother about it... no more games */
2772 // Special processing is getting a CE that is preceded by a certain prefix
2773 // Currently this is only needed for optimizing Japanese length and iteration marks.
2774 // When we encouter a special processing tag, we go backwards and try to see if
2776 // Contraction tables are used - so the whole process is not unlike contraction.
2777 // prefix data is stored backwards in the table.
2778 const UChar
*UCharOffset
;
2780 collIterateState prefixState
;
2781 backupState(source
, &prefixState
);
2782 loadState(source
, &entryState
, TRUE
);
2783 goBackOne(source
); // We want to look at the point where we entered - actually one
2787 // This loop will run once per source string character, for as long as we
2788 // are matching a potential contraction sequence
2790 // First we position ourselves at the begining of contraction sequence
2791 const UChar
*ContractionStart
= UCharOffset
= (UChar
*)coll
->image
+getContractOffset(CE
);
2792 if (collIter_bos(source
)) {
2793 CE
= *(coll
->contractionCEs
+ (UCharOffset
- coll
->contractionIndex
));
2796 schar
= getPrevNormalizedChar(source
, status
);
2799 while(schar
> (tchar
= *UCharOffset
)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
2803 if (schar
== tchar
) {
2804 // Found the source string char in the table.
2805 // Pick up the corresponding CE from the table.
2806 CE
= *(coll
->contractionCEs
+
2807 (UCharOffset
- coll
->contractionIndex
));
2811 // Source string char was not in the table.
2812 // We have not found the prefix.
2813 CE
= *(coll
->contractionCEs
+
2814 (ContractionStart
- coll
->contractionIndex
));
2818 // The source string char was in the contraction table, and the corresponding
2819 // CE is not a prefix CE. We found the prefix, break
2820 // out of loop, this CE will end up being returned. This is the normal
2821 // way out of prefix handling when the source actually contained
2826 if(CE
!= UCOL_NOT_FOUND
) { // we found something and we can merilly continue
2827 loadState(source
, &prefixState
, TRUE
);
2828 if(source
->origFlags
& UCOL_USE_ITERATOR
) {
2829 source
->flags
= source
->origFlags
;
2831 } else { // prefix search was a failure, we have to backup all the way to the start
2832 loadState(source
, &entryState
, TRUE
);
2836 case CONTRACTION_TAG
:
2838 /* This should handle contractions */
2839 collIterateState state
;
2840 backupState(source
, &state
);
2841 uint32_t firstCE
= *(coll
->contractionCEs
+ ((UChar
*)coll
->image
+getContractOffset(CE
) - coll
->contractionIndex
)); //UCOL_NOT_FOUND;
2842 const UChar
*UCharOffset
;
2846 /* This loop will run once per source string character, for as long as we */
2847 /* are matching a potential contraction sequence */
2849 /* First we position ourselves at the begining of contraction sequence */
2850 const UChar
*ContractionStart
= UCharOffset
= (UChar
*)coll
->image
+getContractOffset(CE
);
2852 if (collIter_eos(source
)) {
2853 // Ran off the end of the source string.
2854 CE
= *(coll
->contractionCEs
+ (UCharOffset
- coll
->contractionIndex
));
2855 // So we'll pick whatever we have at the point...
2856 if (CE
== UCOL_NOT_FOUND
) {
2857 // back up the source over all the chars we scanned going into this contraction.
2859 loadState(source
, &state
, TRUE
);
2860 if(source
->origFlags
& UCOL_USE_ITERATOR
) {
2861 source
->flags
= source
->origFlags
;
2867 uint8_t maxCC
= (uint8_t)(*(UCharOffset
)&0xFF); /*get the discontiguos stuff */ /* skip the backward offset, see above */
2868 uint8_t allSame
= (uint8_t)(*(UCharOffset
++)>>8);
2870 schar
= getNextNormalizedChar(source
);
2871 while(schar
> (tchar
= *UCharOffset
)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
2875 if (schar
== tchar
) {
2876 // Found the source string char in the contraction table.
2877 // Pick up the corresponding CE from the table.
2878 CE
= *(coll
->contractionCEs
+
2879 (UCharOffset
- coll
->contractionIndex
));
2883 // Source string char was not in contraction table.
2884 // Unless we have a discontiguous contraction, we have finished
2885 // with this contraction.
2886 // in order to do the proper detection, we
2887 // need to see if we're dealing with a supplementary
2888 /* We test whether the next two char are surrogate pairs.
2889 * This test is done if the iterator is not NULL.
2890 * If there is no surrogate pair, the iterator
2891 * goes back one if needed. */
2892 UChar32 miss
= schar
;
2893 if (source
->iterator
) {
2894 UChar32 surrNextChar
; /* the next char in the iteration to test */
2895 int32_t prevPos
; /* holds the previous position before move forward of the source iterator */
2896 if(U16_IS_LEAD(schar
) && source
->iterator
->hasNext(source
->iterator
)) {
2897 prevPos
= source
->iterator
->index
;
2898 surrNextChar
= getNextNormalizedChar(source
);
2899 if (U16_IS_TRAIL(surrNextChar
)) {
2900 miss
= U16_GET_SUPPLEMENTARY(schar
, surrNextChar
);
2901 } else if (prevPos
< source
->iterator
->index
){
2905 } else if (U16_IS_LEAD(schar
)) {
2906 miss
= U16_GET_SUPPLEMENTARY(schar
, getNextNormalizedChar(source
));
2912 (sCC
= i_getCombiningClass(miss
, coll
)) == 0 ||
2914 (allSame
!= 0 && sCC
== maxCC
) ||
2915 collIter_eos(source
))
2917 // Contraction can not be discontiguous.
2918 goBackOne(source
); // back up the source string by one,
2919 // because the character we just looked at was
2920 // not part of the contraction. */
2921 if(U_IS_SUPPLEMENTARY(miss
)) {
2924 CE
= *(coll
->contractionCEs
+
2925 (ContractionStart
- coll
->contractionIndex
));
2928 // Contraction is possibly discontiguous.
2929 // Scan more of source string looking for a match
2932 /* find the next character if schar is not a base character
2933 and we are not yet at the end of the string */
2934 tempchar
= getNextNormalizedChar(source
);
2935 // probably need another supplementary thingie here
2937 if (i_getCombiningClass(tempchar
, coll
) == 0) {
2939 if(U_IS_SUPPLEMENTARY(miss
)) {
2942 /* Spit out the last char of the string, wasn't tasty enough */
2943 CE
= *(coll
->contractionCEs
+
2944 (ContractionStart
- coll
->contractionIndex
));
2946 CE
= getDiscontiguous(coll
, source
, ContractionStart
);
2949 } // else after if(schar == tchar)
2951 if(CE
== UCOL_NOT_FOUND
) {
2952 /* The Source string did not match the contraction that we were checking. */
2953 /* Back up the source position to undo the effects of having partially */
2954 /* scanned through what ultimately proved to not be a contraction. */
2955 loadState(source
, &state
, TRUE
);
2960 if(!isContraction(CE
)) {
2961 // The source string char was in the contraction table, and the corresponding
2962 // CE is not a contraction CE. We completed the contraction, break
2963 // out of loop, this CE will end up being returned. This is the normal
2964 // way out of contraction handling when the source actually contained
2970 // The source string char was in the contraction table, and the corresponding
2971 // CE is IS a contraction CE. We will continue looping to check the source
2972 // string for the remaining chars in the contraction.
2973 uint32_t tempCE
= *(coll
->contractionCEs
+ (ContractionStart
- coll
->contractionIndex
));
2974 if(tempCE
!= UCOL_NOT_FOUND
) {
2975 // We have scanned a a section of source string for which there is a
2976 // CE from the contraction table. Remember the CE and scan position, so
2977 // that we can return to this point if further scanning fails to
2978 // match a longer contraction sequence.
2982 backupState(source
, &state
);
2983 getNextNormalizedChar(source
);
2985 // Another way to do this is:
2986 //collIterateState tempState;
2987 //backupState(source, &tempState);
2988 //goBackOne(source);
2989 //backupState(source, &state);
2990 //loadState(source, &tempState, TRUE);
2992 // The problem is that for incomplete contractions we have to remember the previous
2993 // position. Before, the only thing I needed to do was state.pos--;
2994 // After iterator introduction and especially after introduction of normalizing
2995 // iterators, it became much more difficult to decrease the saved state.
2996 // I'm not yet sure which of the two methods above is faster.
3000 } // case CONTRACTION_TAG:
3001 case LONG_PRIMARY_TAG
:
3003 *(source
->CEpos
++) = ((CE
& 0xFF)<<24)|UCOL_CONTINUATION_MARKER
;
3004 CE
= ((CE
& 0xFFFF00) << 8) | (UCOL_BYTE_COMMON
<< 8) | UCOL_BYTE_COMMON
;
3005 source
->offsetRepeatCount
+= 1;
3010 /* This should handle expansion. */
3011 /* NOTE: we can encounter both continuations and expansions in an expansion! */
3012 /* I have to decide where continuations are going to be dealt with */
3014 uint32_t i
; /* general counter */
3016 CEOffset
= (uint32_t *)coll
->image
+getExpansionOffset(CE
); /* find the offset to expansion table */
3017 size
= getExpansionCount(CE
);
3019 //source->offsetRepeatCount = -1;
3021 if(size
!= 0) { /* if there are less than 16 elements in expansion, we don't terminate */
3022 for(i
= 1; i
<size
; i
++) {
3023 *(source
->CEpos
++) = *CEOffset
++;
3024 source
->offsetRepeatCount
+= 1;
3026 } else { /* else, we do */
3027 while(*CEOffset
!= 0) {
3028 *(source
->CEpos
++) = *CEOffset
++;
3029 source
->offsetRepeatCount
+= 1;
3038 We do a check to see if we want to collate digits as numbers; if so we generate
3039 a custom collation key. Otherwise we pull out the value stored in the expansion table.
3042 uint32_t i
; /* general counter */
3044 if (source
->coll
->numericCollation
== UCOL_ON
){
3045 collIterateState digitState
= {0,0,0,0,0,0,0,0,0};
3049 uint32_t digIndx
= 0;
3050 uint32_t endIndex
= 0;
3051 uint32_t trailingZeroIndex
= 0;
3053 uint8_t collateVal
= 0;
3055 UBool nonZeroValReached
= FALSE
;
3057 uint8_t numTempBuf
[UCOL_MAX_DIGITS_FOR_NUMBER
/2 + 3]; // I just need a temporary place to store my generated CEs.
3059 We parse the source string until we hit a char that's NOT a digit.
3060 Use this u_charDigitValue. This might be slow because we have to
3061 handle surrogates...
3064 if (U16_IS_LEAD(ch)){
3065 if (!collIter_eos(source)) {
3066 backupState(source, &digitState);
3067 UChar trail = getNextNormalizedChar(source);
3068 if(U16_IS_TRAIL(trail)) {
3069 char32 = U16_GET_SUPPLEMENTARY(ch, trail);
3071 loadState(source, &digitState, TRUE);
3080 digVal = u_charDigitValue(char32);
3082 digVal
= u_charDigitValue(cp
); // if we have arrived here, we have
3083 // already processed possible supplementaries that trigered the digit tag -
3084 // all supplementaries are marked in the UCA.
3086 We pad a zero in front of the first element anyways. This takes
3087 care of the (probably) most common case where people are sorting things followed
3092 // Make sure we have enough space. No longer needed;
3093 // at this point digIndx now has a max value of UCOL_MAX_DIGITS_FOR_NUMBER
3094 // (it has been pre-incremented) so we just ensure that numTempBuf is big enough
3095 // (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 3).
3097 // Skipping over leading zeroes.
3099 nonZeroValReached
= TRUE
;
3101 if (nonZeroValReached
) {
3103 We parse the digit string into base 100 numbers (this fits into a byte).
3104 We only add to the buffer in twos, thus if we are parsing an odd character,
3105 that serves as the 'tens' digit while the if we are parsing an even one, that
3106 is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
3107 a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
3108 overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
3109 than all the other bytes.
3112 if (digIndx
% 2 == 1){
3113 collateVal
+= (uint8_t)digVal
;
3115 // We don't enter the low-order-digit case unless we've already seen
3116 // the high order, or for the first digit, which is always non-zero.
3117 if (collateVal
!= 0)
3118 trailingZeroIndex
= 0;
3120 numTempBuf
[(digIndx
/2) + 2] = collateVal
*2 + 6;
3124 // We drop the collation value into the buffer so if we need to do
3125 // a "front patch" we don't have to check to see if we're hitting the
3127 collateVal
= (uint8_t)(digVal
* 10);
3129 // Check for trailing zeroes.
3130 if (collateVal
== 0)
3132 if (!trailingZeroIndex
)
3133 trailingZeroIndex
= (digIndx
/2) + 2;
3136 trailingZeroIndex
= 0;
3138 numTempBuf
[(digIndx
/2) + 2] = collateVal
*2 + 6;
3143 // Get next character.
3144 if (!collIter_eos(source
)){
3145 ch
= getNextNormalizedChar(source
);
3146 if (U16_IS_LEAD(ch
)){
3147 if (!collIter_eos(source
)) {
3148 backupState(source
, &digitState
);
3149 UChar trail
= getNextNormalizedChar(source
);
3150 if(U16_IS_TRAIL(trail
)) {
3151 char32
= U16_GET_SUPPLEMENTARY(ch
, trail
);
3153 loadState(source
, &digitState
, TRUE
);
3161 if ((digVal
= u_charDigitValue(char32
)) == -1 || digIndx
> UCOL_MAX_DIGITS_FOR_NUMBER
){
3162 // Resetting position to point to the next unprocessed char. We
3163 // overshot it when doing our test/set for numbers.
3164 if (char32
> 0xFFFF) { // For surrogates.
3165 loadState(source
, &digitState
, TRUE
);
3166 //goBackOne(source);
3176 if (nonZeroValReached
== FALSE
){
3181 endIndex
= trailingZeroIndex
? trailingZeroIndex
: ((digIndx
/2) + 2) ;
3182 if (digIndx
% 2 != 0){
3184 We missed a value. Since digIndx isn't even, stuck too many values into the buffer (this is what
3185 we get for padding the first byte with a zero). "Front-patch" now by pushing all nybbles forward.
3186 Doing it this way ensures that at least 50% of the time (statistically speaking) we'll only be doing a
3187 single pass and optimizes for strings with single digits. I'm just assuming that's the more common case.
3190 for(i
= 2; i
< endIndex
; i
++){
3191 numTempBuf
[i
] = (((((numTempBuf
[i
] - 6)/2) % 10) * 10) +
3192 (((numTempBuf
[i
+1])-6)/2) / 10) * 2 + 6;
3197 // Subtract one off of the last byte.
3198 numTempBuf
[endIndex
-1] -= 1;
3201 We want to skip over the first two slots in the buffer. The first slot
3202 is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
3203 sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
3205 numTempBuf
[0] = UCOL_CODAN_PLACEHOLDER
;
3206 numTempBuf
[1] = (uint8_t)(0x80 + ((digIndx
/2) & 0x7F));
3208 // Now transfer the collation key to our collIterate struct.
3209 // The total size for our collation key is endIndx bumped up to the next largest even value divided by two.
3210 //size = ((endIndex+1) & ~1)/2;
3211 CE
= (((numTempBuf
[0] << 8) | numTempBuf
[1]) << UCOL_PRIMARYORDERSHIFT
) | //Primary weight
3212 (UCOL_BYTE_COMMON
<< UCOL_SECONDARYORDERSHIFT
) | // Secondary weight
3213 UCOL_BYTE_COMMON
; // Tertiary weight.
3214 i
= 2; // Reset the index into the buffer.
3217 uint32_t primWeight
= numTempBuf
[i
++] << 8;
3219 primWeight
|= numTempBuf
[i
++];
3220 *(source
->CEpos
++) = (primWeight
<< UCOL_PRIMARYORDERSHIFT
) | UCOL_CONTINUATION_MARKER
;
3224 // no numeric mode, we'll just switch to whatever we stashed and continue
3225 CEOffset
= (uint32_t *)coll
->image
+getExpansionOffset(CE
); /* find the offset to expansion table */
3231 /* various implicits optimization */
3232 case IMPLICIT_TAG
: /* everything that is not defined otherwise */
3233 /* UCA is filled with these. Tailorings are NOT_FOUND */
3234 return getImplicit(cp
, source
);
3235 case CJK_IMPLICIT_TAG
: /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
3236 // TODO: remove CJK_IMPLICIT_TAG completely - handled by the getImplicit
3237 return getImplicit(cp
, source
);
3238 case HANGUL_SYLLABLE_TAG
: /* AC00-D7AF*/
3240 static const uint32_t
3241 SBase
= 0xAC00, LBase
= 0x1100, VBase
= 0x1161, TBase
= 0x11A7;
3242 //const uint32_t LCount = 19;
3243 static const uint32_t VCount
= 21;
3244 static const uint32_t TCount
= 28;
3245 //const uint32_t NCount = VCount * TCount; // 588
3246 //const uint32_t SCount = LCount * NCount; // 11172
3247 uint32_t L
= ch
- SBase
;
3249 // divide into pieces
3251 uint32_t T
= L
% TCount
; // we do it in this order since some compilers can do % and / in one operation
3253 uint32_t V
= L
% VCount
;
3262 // return the first CE, but first put the rest into the expansion buffer
3263 if (!source
->coll
->image
->jamoSpecial
) { // FAST PATH
3265 *(source
->CEpos
++) = UTRIE_GET32_FROM_LEAD(&coll
->mapping
, V
);
3267 *(source
->CEpos
++) = UTRIE_GET32_FROM_LEAD(&coll
->mapping
, T
);
3270 return UTRIE_GET32_FROM_LEAD(&coll
->mapping
, L
);
3272 } else { // Jamo is Special
3273 // Since Hanguls pass the FCD check, it is
3274 // guaranteed that we won't be in
3275 // the normalization buffer if something like this happens
3277 // However, if we are using a uchar iterator and normalization
3278 // is ON, the Hangul that lead us here is going to be in that
3279 // normalization buffer. Here we want to restore the uchar
3280 // iterator state and pull out of the normalization buffer
3281 if(source
->iterator
!= NULL
&& source
->flags
& UCOL_ITER_INNORMBUF
) {
3282 source
->flags
= source
->origFlags
; // restore the iterator
3286 // Move Jamos into normalization buffer
3287 UChar
*buffer
= source
->writableBuffer
.getBuffer(4);
3288 int32_t bufferLength
;
3289 buffer
[0] = (UChar
)L
;
3290 buffer
[1] = (UChar
)V
;
3292 buffer
[2] = (UChar
)T
;
3297 source
->writableBuffer
.releaseBuffer(bufferLength
);
3299 // Indicate where to continue in main input string after exhausting the writableBuffer
3300 source
->fcdPosition
= source
->pos
;
3302 source
->pos
= source
->writableBuffer
.getTerminatedBuffer();
3303 source
->origFlags
= source
->flags
;
3304 source
->flags
|= UCOL_ITER_INNORMBUF
;
3305 source
->flags
&= ~(UCOL_ITER_NORM
| UCOL_ITER_HASLEN
);
3307 return(UCOL_IGNORABLE
);
3311 /* we encountered a leading surrogate. We shall get the CE by using the following code unit */
3312 /* two things can happen here: next code point can be a trailing surrogate - we will use it */
3313 /* to retrieve the CE, or it is not a trailing surrogate (or the string is done). In that case */
3314 /* we treat it like an unassigned code point. */
3317 collIterateState state
;
3318 backupState(source
, &state
);
3319 if (collIter_eos(source
) || !(U16_IS_TRAIL((trail
= getNextNormalizedChar(source
))))) {
3320 // we chould have stepped one char forward and it might have turned that it
3321 // was not a trail surrogate. In that case, we have to backup.
3322 loadState(source
, &state
, TRUE
);
3323 return UCOL_NOT_FOUND
;
3325 /* TODO: CE contain the data from the previous CE + the mask. It should at least be unmasked */
3326 CE
= UTRIE_GET32_FROM_OFFSET_TRAIL(&coll
->mapping
, CE
&0xFFFFFF, trail
);
3327 if(CE
== UCOL_NOT_FOUND
) { // there are tailored surrogates in this block, but not this one.
3328 // We need to backup
3329 loadState(source
, &state
, TRUE
);
3332 // calculate the supplementary code point value, if surrogate was not tailored
3333 cp
= ((((uint32_t)ch
)<<10UL)+(trail
)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
3337 case LEAD_SURROGATE_TAG
: /* D800-DBFF*/
3339 if( source
->flags
& UCOL_USE_ITERATOR
) {
3340 if(U_IS_TRAIL(nextChar
= (UChar
)source
->iterator
->current(source
->iterator
))) {
3341 cp
= U16_GET_SUPPLEMENTARY(ch
, nextChar
);
3342 source
->iterator
->next(source
->iterator
);
3343 return getImplicit(cp
, source
);
3345 } else if((((source
->flags
& UCOL_ITER_HASLEN
) == 0 ) || (source
->pos
<source
->endp
)) &&
3346 U_IS_TRAIL((nextChar
=*source
->pos
))) {
3347 cp
= U16_GET_SUPPLEMENTARY(ch
, nextChar
);
3349 return getImplicit(cp
, source
);
3351 return UCOL_NOT_FOUND
;
3352 case TRAIL_SURROGATE_TAG
: /* DC00-DFFF*/
3353 return UCOL_NOT_FOUND
; /* broken surrogate sequence */
3355 /* not yet implemented */
3356 /* probably after 1.8 */
3357 return UCOL_NOT_FOUND
;
3359 *status
= U_INTERNAL_PROGRAM_ERROR
;
3363 if (CE
<= UCOL_NOT_FOUND
) break;
3369 /* now uses Mark's getImplicitPrimary code */
3371 inline uint32_t getPrevImplicit(UChar32 cp
, collIterate
*collationSource
) {
3372 uint32_t r
= uprv_uca_getImplicitPrimary(cp
);
3374 *(collationSource
->CEpos
++) = (r
& UCOL_PRIMARYMASK
) | 0x00000505;
3375 collationSource
->toReturn
= collationSource
->CEpos
;
3377 // **** doesn't work if using iterator ****
3378 if (collationSource
->flags
& UCOL_ITER_INNORMBUF
) {
3379 collationSource
->offsetRepeatCount
= 1;
3381 int32_t firstOffset
= (int32_t)(collationSource
->pos
- collationSource
->string
);
3383 UErrorCode errorCode
= U_ZERO_ERROR
;
3384 collationSource
->appendOffset(firstOffset
, errorCode
);
3385 collationSource
->appendOffset(firstOffset
+ 1, errorCode
);
3387 collationSource
->offsetReturn
= collationSource
->offsetStore
- 1;
3388 *(collationSource
->offsetBuffer
) = firstOffset
;
3389 if (collationSource
->offsetReturn
== collationSource
->offsetBuffer
) {
3390 collationSource
->offsetStore
= collationSource
->offsetBuffer
;
3394 return ((r
& 0x0000FFFF)<<16) | 0x000000C0;
3398 * This function handles the special CEs like contractions, expansions,
3400 * It is called by both getPrevCE
3402 uint32_t ucol_prv_getSpecialPrevCE(const UCollator
*coll
, UChar ch
, uint32_t CE
,
3403 collIterate
*source
,
3406 const uint32_t *CEOffset
= NULL
;
3407 UChar
*UCharOffset
= NULL
;
3409 const UChar
*constart
= NULL
;
3411 UChar buffer
[UCOL_MAX_BUFFER
];
3412 uint32_t *endCEBuffer
;
3414 int32_t noChars
= 0;
3415 int32_t CECount
= 0;
3419 /* the only ces that loops are thai and contractions */
3420 switch (getCETag(CE
))
3422 case NOT_FOUND_TAG
: /* this tag always returns */
3427 // Special processing is getting a CE that is preceded by a certain prefix
3428 // Currently this is only needed for optimizing Japanese length and iteration marks.
3429 // When we encouter a special processing tag, we go backwards and try to see if
3431 // Contraction tables are used - so the whole process is not unlike contraction.
3432 // prefix data is stored backwards in the table.
3433 const UChar
*UCharOffset
;
3435 collIterateState prefixState
;
3436 backupState(source
, &prefixState
);
3438 // This loop will run once per source string character, for as long as we
3439 // are matching a potential contraction sequence
3441 // First we position ourselves at the begining of contraction sequence
3442 const UChar
*ContractionStart
= UCharOffset
= (UChar
*)coll
->image
+getContractOffset(CE
);
3444 if (collIter_bos(source
)) {
3445 CE
= *(coll
->contractionCEs
+ (UCharOffset
- coll
->contractionIndex
));
3448 schar
= getPrevNormalizedChar(source
, status
);
3451 while(schar
> (tchar
= *UCharOffset
)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
3455 if (schar
== tchar
) {
3456 // Found the source string char in the table.
3457 // Pick up the corresponding CE from the table.
3458 CE
= *(coll
->contractionCEs
+
3459 (UCharOffset
- coll
->contractionIndex
));
3463 // if there is a completely ignorable code point in the middle of
3464 // a prefix, we need to act as if it's not there
3465 // assumption: 'real' noncharacters (*fffe, *ffff, fdd0-fdef are set to zero)
3466 // lone surrogates cannot be set to zero as it would break other processing
3467 uint32_t isZeroCE
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, schar
);
3468 // it's easy for BMP code points
3471 } else if(U16_IS_SURROGATE(schar
)) {
3472 // for supplementary code points, we have to check the next one
3473 // situations where we are going to ignore
3474 // 1. beginning of the string: schar is a lone surrogate
3475 // 2. schar is a lone surrogate
3476 // 3. schar is a trail surrogate in a valid surrogate sequence
3477 // that is explicitly set to zero.
3478 if (!collIter_bos(source
)) {
3480 if(!U16_IS_SURROGATE_LEAD(schar
) && U16_IS_LEAD(lead
= getPrevNormalizedChar(source
, status
))) {
3481 isZeroCE
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, lead
);
3482 if(isSpecial(isZeroCE
) && getCETag(isZeroCE
) == SURROGATE_TAG
) {
3483 uint32_t finalCE
= UTRIE_GET32_FROM_OFFSET_TRAIL(&coll
->mapping
, isZeroCE
&0xFFFFFF, schar
);
3485 // this is a real, assigned completely ignorable code point
3491 // lone surrogate, treat like unassigned
3492 return UCOL_NOT_FOUND
;
3495 // lone surrogate at the beggining, treat like unassigned
3496 return UCOL_NOT_FOUND
;
3499 // Source string char was not in the table.
3500 // We have not found the prefix.
3501 CE
= *(coll
->contractionCEs
+
3502 (ContractionStart
- coll
->contractionIndex
));
3506 // The source string char was in the contraction table, and the corresponding
3507 // CE is not a prefix CE. We found the prefix, break
3508 // out of loop, this CE will end up being returned. This is the normal
3509 // way out of prefix handling when the source actually contained
3514 loadState(source
, &prefixState
, TRUE
);
3518 case CONTRACTION_TAG
: {
3519 /* to ensure that the backwards and forwards iteration matches, we
3520 take the current region of most possible match and pass it through
3521 the forward iteration. this will ensure that the obstinate problem of
3522 overlapping contractions will not occur.
3524 schar
= peekCodeUnit(source
, 0);
3525 constart
= (UChar
*)coll
->image
+ getContractOffset(CE
);
3526 if (isAtStartPrevIterate(source
)
3527 /* commented away contraction end checks after adding the checks
3529 /* start of string or this is not the end of any contraction */
3530 CE
= *(coll
->contractionCEs
+
3531 (constart
- coll
->contractionIndex
));
3535 UCharOffset
= strbuffer
+ (UCOL_MAX_BUFFER
- 1);
3536 *(UCharOffset
--) = 0;
3538 // have to swap thai characters
3539 while (ucol_unsafeCP(schar
, coll
)) {
3540 *(UCharOffset
) = schar
;
3543 schar
= getPrevNormalizedChar(source
, status
);
3545 // TODO: when we exhaust the contraction buffer,
3546 // it needs to get reallocated. The problem is
3547 // that the size depends on the string which is
3548 // not iterated over. However, since we're travelling
3549 // backwards, we already had to set the iterator at
3550 // the end - so we might as well know where we are?
3551 if (UCharOffset
+ 1 == buffer
) {
3552 /* we have exhausted the buffer */
3553 int32_t newsize
= 0;
3554 if(source
->pos
) { // actually dealing with a position
3555 newsize
= (int32_t)(source
->pos
- source
->string
+ 1);
3556 } else { // iterator
3557 newsize
= 4 * UCOL_MAX_BUFFER
;
3559 strbuffer
= (UChar
*)uprv_malloc(sizeof(UChar
) *
3560 (newsize
+ UCOL_MAX_BUFFER
));
3562 if (strbuffer
== NULL
) {
3563 *status
= U_MEMORY_ALLOCATION_ERROR
;
3564 return UCOL_NO_MORE_CES
;
3566 UCharOffset
= strbuffer
+ newsize
;
3567 uprv_memcpy(UCharOffset
, buffer
,
3568 UCOL_MAX_BUFFER
* sizeof(UChar
));
3571 if ((source
->pos
&& (source
->pos
== source
->string
||
3572 ((source
->flags
& UCOL_ITER_INNORMBUF
) &&
3573 *(source
->pos
- 1) == 0 && source
->fcdPosition
== NULL
)))
3574 || (source
->iterator
&& !source
->iterator
->hasPrevious(source
->iterator
))) {
3578 /* adds the initial base character to the string */
3579 *(UCharOffset
) = schar
;
3584 // **** doesn't work if using iterator ****
3585 if (source
->flags
& UCOL_ITER_INNORMBUF
) {
3588 offsetBias
= (int32_t)(source
->pos
- source
->string
);
3591 /* a new collIterate is used to simplify things, since using the current
3592 collIterate will mean that the forward and backwards iteration will
3593 share and change the same buffers. we don't want to get into that. */
3597 IInit_collIterate(coll
, UCharOffset
, noChars
, &temp
, status
);
3598 if(U_FAILURE(*status
)) {
3599 return (uint32_t)UCOL_NULLORDER
;
3601 temp
.flags
&= ~UCOL_ITER_NORM
;
3602 temp
.flags
|= source
->flags
& UCOL_FORCE_HAN_IMPLICIT
;
3604 rawOffset
= (int32_t)(temp
.pos
- temp
.string
); // should always be zero?
3605 CE
= ucol_IGetNextCE(coll
, &temp
, status
);
3607 if (source
->extendCEs
) {
3608 endCEBuffer
= source
->extendCEs
+ source
->extendCEsSize
;
3609 CECount
= (int32_t)((source
->CEpos
- source
->extendCEs
)/sizeof(uint32_t));
3611 endCEBuffer
= source
->CEs
+ UCOL_EXPAND_CE_BUFFER_SIZE
;
3612 CECount
= (int32_t)((source
->CEpos
- source
->CEs
)/sizeof(uint32_t));
3615 while (CE
!= UCOL_NO_MORE_CES
) {
3616 *(source
->CEpos
++) = CE
;
3618 if (offsetBias
>= 0) {
3619 source
->appendOffset(rawOffset
+ offsetBias
, *status
);
3623 if (source
->CEpos
== endCEBuffer
) {
3624 /* ran out of CE space, reallocate to new buffer.
3625 If reallocation fails, reset pointers and bail out,
3626 there's no guarantee of the right character position after
3628 if (!increaseCEsCapacity(source
)) {
3629 *status
= U_MEMORY_ALLOCATION_ERROR
;
3633 endCEBuffer
= source
->extendCEs
+ source
->extendCEsSize
;
3636 if ((temp
.flags
& UCOL_ITER_INNORMBUF
) != 0) {
3637 rawOffset
= (int32_t)(temp
.fcdPosition
- temp
.string
);
3639 rawOffset
= (int32_t)(temp
.pos
- temp
.string
);
3642 CE
= ucol_IGetNextCE(coll
, &temp
, status
);
3645 if (strbuffer
!= buffer
) {
3646 uprv_free(strbuffer
);
3648 if (U_FAILURE(*status
)) {
3649 return (uint32_t)UCOL_NULLORDER
;
3652 if (source
->offsetRepeatValue
!= 0) {
3653 if (CECount
> noChars
) {
3654 source
->offsetRepeatCount
+= temp
.offsetRepeatCount
;
3656 // **** does this really skip the right offsets? ****
3657 source
->offsetReturn
-= (noChars
- CECount
);
3661 if (offsetBias
>= 0) {
3662 source
->offsetReturn
= source
->offsetStore
- 1;
3663 if (source
->offsetReturn
== source
->offsetBuffer
) {
3664 source
->offsetStore
= source
->offsetBuffer
;
3668 source
->toReturn
= source
->CEpos
- 1;
3669 if (source
->toReturn
== source
->CEs
) {
3670 source
->CEpos
= source
->CEs
;
3673 return *(source
->toReturn
);
3675 case LONG_PRIMARY_TAG
:
3677 *(source
->CEpos
++) = ((CE
& 0xFFFF00) << 8) | (UCOL_BYTE_COMMON
<< 8) | UCOL_BYTE_COMMON
;
3678 *(source
->CEpos
++) = ((CE
& 0xFF)<<24)|UCOL_CONTINUATION_MARKER
;
3679 source
->toReturn
= source
->CEpos
- 1;
3681 if (source
->flags
& UCOL_ITER_INNORMBUF
) {
3682 source
->offsetRepeatCount
= 1;
3684 int32_t firstOffset
= (int32_t)(source
->pos
- source
->string
);
3686 source
->appendOffset(firstOffset
, *status
);
3687 source
->appendOffset(firstOffset
+ 1, *status
);
3689 source
->offsetReturn
= source
->offsetStore
- 1;
3690 *(source
->offsetBuffer
) = firstOffset
;
3691 if (source
->offsetReturn
== source
->offsetBuffer
) {
3692 source
->offsetStore
= source
->offsetBuffer
;
3697 return *(source
->toReturn
);
3700 case EXPANSION_TAG
: /* this tag always returns */
3703 This should handle expansion.
3704 NOTE: we can encounter both continuations and expansions in an expansion!
3705 I have to decide where continuations are going to be dealt with
3707 int32_t firstOffset
= (int32_t)(source
->pos
- source
->string
);
3709 // **** doesn't work if using iterator ****
3710 if (source
->offsetReturn
!= NULL
) {
3711 if (! (source
->flags
& UCOL_ITER_INNORMBUF
) && source
->offsetReturn
== source
->offsetBuffer
) {
3712 source
->offsetStore
= source
->offsetBuffer
;
3718 /* find the offset to expansion table */
3719 CEOffset
= (uint32_t *)coll
->image
+ getExpansionOffset(CE
);
3720 size
= getExpansionCount(CE
);
3723 if there are less than 16 elements in expansion, we don't terminate
3727 for (count
= 0; count
< size
; count
++) {
3728 *(source
->CEpos
++) = *CEOffset
++;
3730 if (firstOffset
>= 0) {
3731 source
->appendOffset(firstOffset
+ 1, *status
);
3736 while (*CEOffset
!= 0) {
3737 *(source
->CEpos
++) = *CEOffset
++;
3739 if (firstOffset
>= 0) {
3740 source
->appendOffset(firstOffset
+ 1, *status
);
3745 if (firstOffset
>= 0) {
3746 source
->offsetReturn
= source
->offsetStore
- 1;
3747 *(source
->offsetBuffer
) = firstOffset
;
3748 if (source
->offsetReturn
== source
->offsetBuffer
) {
3749 source
->offsetStore
= source
->offsetBuffer
;
3752 source
->offsetRepeatCount
+= size
- 1;
3755 source
->toReturn
= source
->CEpos
- 1;
3756 // in case of one element expansion, we
3757 // want to immediately return CEpos
3758 if(source
->toReturn
== source
->CEs
) {
3759 source
->CEpos
= source
->CEs
;
3762 return *(source
->toReturn
);
3768 We do a check to see if we want to collate digits as numbers; if so we generate
3769 a custom collation key. Otherwise we pull out the value stored in the expansion table.
3771 uint32_t i
; /* general counter */
3773 if (source
->coll
->numericCollation
== UCOL_ON
){
3774 uint32_t digIndx
= 0;
3775 uint32_t endIndex
= 0;
3776 uint32_t leadingZeroIndex
= 0;
3777 uint32_t trailingZeroCount
= 0;
3779 uint8_t collateVal
= 0;
3781 UBool nonZeroValReached
= FALSE
;
3783 uint8_t numTempBuf
[UCOL_MAX_DIGITS_FOR_NUMBER
/2 + 2]; // I just need a temporary place to store my generated CEs.
3785 We parse the source string until we hit a char that's NOT a digit.
3786 Use this u_charDigitValue. This might be slow because we have to
3787 handle surrogates...
3790 We need to break up the digit string into collection elements of UCOL_MAX_DIGITS_FOR_NUMBER or less,
3791 with any chunks smaller than that being on the right end of the digit string - i.e. the first collation
3792 element we process when going backward. To determine how long that chunk might be, we may need to make
3793 two passes through the loop that collects digits - one to see how long the string is (and how much is
3794 leading zeros) to determine the length of that right-hand chunk, and a second (if the whole string has
3795 more than UCOL_MAX_DIGITS_FOR_NUMBER non-leading-zero digits) to actually process that collation
3796 element chunk after resetting the state to the initialState at the right side of the digit string.
3798 uint32_t ceLimit
= 0;
3799 UChar initial_ch
= ch
;
3800 collIterateState initialState
= {0,0,0,0,0,0,0,0,0};
3801 backupState(source
, &initialState
);
3804 collIterateState state
= {0,0,0,0,0,0,0,0,0};
3808 if (U16_IS_TRAIL (ch
)) {
3809 if (!collIter_bos(source
)){
3810 UChar lead
= getPrevNormalizedChar(source
, status
);
3811 if(U16_IS_LEAD(lead
)) {
3812 char32
= U16_GET_SUPPLEMENTARY(lead
,ch
);
3823 digVal
= u_charDigitValue(char32
);
3826 // Make sure we have enough space. No longer needed;
3827 // at this point the largest value of digIndx when we need to save data in numTempBuf
3828 // is UCOL_MAX_DIGITS_FOR_NUMBER-1 (digIndx is post-incremented) so we just ensure
3829 // that numTempBuf is big enough (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 2).
3831 // Skip over trailing zeroes, and keep a count of them.
3833 nonZeroValReached
= TRUE
;
3835 if (nonZeroValReached
) {
3837 We parse the digit string into base 100 numbers (this fits into a byte).
3838 We only add to the buffer in twos, thus if we are parsing an odd character,
3839 that serves as the 'tens' digit while the if we are parsing an even one, that
3840 is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
3841 a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
3842 overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
3843 than all the other bytes.
3845 Since we're doing in this reverse we want to put the first digit encountered into the
3846 ones place and the second digit encountered into the tens place.
3849 if ((digIndx
+ trailingZeroCount
) % 2 == 1) {
3850 // High-order digit case (tens place)
3851 collateVal
+= (uint8_t)(digVal
* 10);
3853 // We cannot set leadingZeroIndex unless it has been set for the
3854 // low-order digit. Therefore, all we can do for the high-order
3855 // digit is turn it off, never on.
3856 // The only time we will have a high digit without a low is for
3857 // the very first non-zero digit, so no zero check is necessary.
3858 if (collateVal
!= 0)
3859 leadingZeroIndex
= 0;
3861 // The first pass through, digIndx may exceed the limit, but in that case
3862 // we no longer care about numTempBuf contents since they will be discarded
3863 if ( digIndx
< UCOL_MAX_DIGITS_FOR_NUMBER
) {
3864 numTempBuf
[(digIndx
/2) + 2] = collateVal
*2 + 6;
3868 // Low-order digit case (ones place)
3869 collateVal
= (uint8_t)digVal
;
3871 // Check for leading zeroes.
3872 if (collateVal
== 0) {
3873 if (!leadingZeroIndex
)
3874 leadingZeroIndex
= (digIndx
/2) + 2;
3876 leadingZeroIndex
= 0;
3878 // No need to write to buffer; the case of a last odd digit
3879 // is handled below.
3883 ++trailingZeroCount
;
3885 if (!collIter_bos(source
)) {
3886 ch
= getPrevNormalizedChar(source
, status
);
3887 //goBackOne(source);
3888 if (U16_IS_TRAIL(ch
)) {
3889 backupState(source
, &state
);
3890 if (!collIter_bos(source
)) {
3892 UChar lead
= getPrevNormalizedChar(source
, status
);
3894 if(U16_IS_LEAD(lead
)) {
3895 char32
= U16_GET_SUPPLEMENTARY(lead
,ch
);
3897 loadState(source
, &state
, FALSE
);
3904 if ((digVal
= u_charDigitValue(char32
)) == -1 || (ceLimit
> 0 && (digIndx
+ trailingZeroCount
) >= ceLimit
)) {
3905 if (char32
> 0xFFFF) {// For surrogates.
3906 loadState(source
, &state
, FALSE
);
3908 // Don't need to "reverse" the goBackOne call,
3909 // as this points to the next position to process..
3910 //if (char32 > 0xFFFF) // For surrogates.
3911 //getNextNormalizedChar(source);
3920 if (digIndx
+ trailingZeroCount
<= UCOL_MAX_DIGITS_FOR_NUMBER
) {
3921 // our collation element is not too big, go ahead and finish with it
3924 // our digit string is too long for a collation element;
3925 // set the limit for it, reset the state and begin again
3926 ceLimit
= (digIndx
+ trailingZeroCount
) % UCOL_MAX_DIGITS_FOR_NUMBER
;
3927 if ( ceLimit
== 0 ) {
3928 ceLimit
= UCOL_MAX_DIGITS_FOR_NUMBER
;
3931 loadState(source
, &initialState
, FALSE
);
3932 digIndx
= endIndex
= leadingZeroIndex
= trailingZeroCount
= 0;
3934 nonZeroValReached
= FALSE
;
3937 if (! nonZeroValReached
) {
3939 trailingZeroCount
= 0;
3943 if ((digIndx
+ trailingZeroCount
) % 2 != 0) {
3944 numTempBuf
[((digIndx
)/2) + 2] = collateVal
*2 + 6;
3945 digIndx
+= 1; // The implicit leading zero
3947 if (trailingZeroCount
% 2 != 0) {
3948 // We had to consume one trailing zero for the low digit
3949 // of the least significant byte
3950 digIndx
+= 1; // The trailing zero not in the exponent
3951 trailingZeroCount
-= 1;
3954 endIndex
= leadingZeroIndex
? leadingZeroIndex
: ((digIndx
/2) + 2) ;
3956 // Subtract one off of the last byte. Really the first byte here, but it's reversed...
3960 We want to skip over the first two slots in the buffer. The first slot
3961 is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
3962 sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
3963 The exponent must be adjusted by the number of leading zeroes, and the number of
3966 numTempBuf
[0] = UCOL_CODAN_PLACEHOLDER
;
3967 uint32_t exponent
= (digIndx
+trailingZeroCount
)/2;
3968 if (leadingZeroIndex
)
3969 exponent
-= ((digIndx
/2) + 2 - leadingZeroIndex
);
3970 numTempBuf
[1] = (uint8_t)(0x80 + (exponent
& 0x7F));
3972 // Now transfer the collation key to our collIterate struct.
3973 // The total size for our collation key is half of endIndex, rounded up.
3974 int32_t size
= (endIndex
+1)/2;
3975 if(!ensureCEsCapacity(source
, size
)) {
3976 return (uint32_t)UCOL_NULLORDER
;
3978 *(source
->CEpos
++) = (((numTempBuf
[0] << 8) | numTempBuf
[1]) << UCOL_PRIMARYORDERSHIFT
) | //Primary weight
3979 (UCOL_BYTE_COMMON
<< UCOL_SECONDARYORDERSHIFT
) | // Secondary weight
3980 UCOL_BYTE_COMMON
; // Tertiary weight.
3981 i
= endIndex
- 1; // Reset the index into the buffer.
3983 uint32_t primWeight
= numTempBuf
[i
--] << 8;
3985 primWeight
|= numTempBuf
[i
--];
3986 *(source
->CEpos
++) = (primWeight
<< UCOL_PRIMARYORDERSHIFT
) | UCOL_CONTINUATION_MARKER
;
3989 source
->toReturn
= source
->CEpos
-1;
3990 return *(source
->toReturn
);
3992 CEOffset
= (uint32_t *)coll
->image
+ getExpansionOffset(CE
);
3998 case HANGUL_SYLLABLE_TAG
: /* AC00-D7AF*/
4000 static const uint32_t
4001 SBase
= 0xAC00, LBase
= 0x1100, VBase
= 0x1161, TBase
= 0x11A7;
4002 //const uint32_t LCount = 19;
4003 static const uint32_t VCount
= 21;
4004 static const uint32_t TCount
= 28;
4005 //const uint32_t NCount = VCount * TCount; /* 588 */
4006 //const uint32_t SCount = LCount * NCount; /* 11172 */
4008 uint32_t L
= ch
- SBase
;
4011 we do it in this order since some compilers can do % and / in one
4014 uint32_t T
= L
% TCount
;
4016 uint32_t V
= L
% VCount
;
4024 int32_t firstOffset
= (int32_t)(source
->pos
- source
->string
);
4025 source
->appendOffset(firstOffset
, *status
);
4028 * return the first CE, but first put the rest into the expansion buffer
4030 if (!source
->coll
->image
->jamoSpecial
) {
4031 *(source
->CEpos
++) = UTRIE_GET32_FROM_LEAD(&coll
->mapping
, L
);
4032 *(source
->CEpos
++) = UTRIE_GET32_FROM_LEAD(&coll
->mapping
, V
);
4033 source
->appendOffset(firstOffset
+ 1, *status
);
4036 *(source
->CEpos
++) = UTRIE_GET32_FROM_LEAD(&coll
->mapping
, T
);
4037 source
->appendOffset(firstOffset
+ 1, *status
);
4040 source
->toReturn
= source
->CEpos
- 1;
4042 source
->offsetReturn
= source
->offsetStore
- 1;
4043 if (source
->offsetReturn
== source
->offsetBuffer
) {
4044 source
->offsetStore
= source
->offsetBuffer
;
4047 return *(source
->toReturn
);
4049 // Since Hanguls pass the FCD check, it is
4050 // guaranteed that we won't be in
4051 // the normalization buffer if something like this happens
4053 // Move Jamos into normalization buffer
4054 UChar
*tempbuffer
= source
->writableBuffer
.getBuffer(5);
4055 int32_t tempbufferLength
, jamoOffset
;
4057 tempbuffer
[1] = (UChar
)L
;
4058 tempbuffer
[2] = (UChar
)V
;
4060 tempbuffer
[3] = (UChar
)T
;
4061 tempbufferLength
= 4;
4063 tempbufferLength
= 3;
4065 source
->writableBuffer
.releaseBuffer(tempbufferLength
);
4067 // Indicate where to continue in main input string after exhausting the writableBuffer
4068 if (source
->pos
== source
->string
) {
4070 source
->fcdPosition
= NULL
;
4072 jamoOffset
= source
->pos
- source
->string
;
4073 source
->fcdPosition
= source
->pos
-1;
4076 // Append offsets for the additional chars
4077 // (not the 0, and not the L whose offsets match the original Hangul)
4078 int32_t jamoRemaining
= tempbufferLength
- 2;
4079 jamoOffset
++; // appended offsets should match end of original Hangul
4080 while (jamoRemaining
-- > 0) {
4081 source
->appendOffset(jamoOffset
, *status
);
4084 source
->offsetRepeatValue
= jamoOffset
;
4086 source
->offsetReturn
= source
->offsetStore
- 1;
4087 if (source
->offsetReturn
== source
->offsetBuffer
) {
4088 source
->offsetStore
= source
->offsetBuffer
;
4091 source
->pos
= source
->writableBuffer
.getTerminatedBuffer() + tempbufferLength
;
4092 source
->origFlags
= source
->flags
;
4093 source
->flags
|= UCOL_ITER_INNORMBUF
;
4094 source
->flags
&= ~(UCOL_ITER_NORM
| UCOL_ITER_HASLEN
);
4096 return(UCOL_IGNORABLE
);
4100 case IMPLICIT_TAG
: /* everything that is not defined otherwise */
4101 return getPrevImplicit(ch
, source
);
4103 // TODO: Remove CJK implicits as they are handled by the getImplicitPrimary function
4104 case CJK_IMPLICIT_TAG
: /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
4105 return getPrevImplicit(ch
, source
);
4107 case SURROGATE_TAG
: /* This is a surrogate pair */
4108 /* essentially an engaged lead surrogate. */
4109 /* if you have encountered it here, it means that a */
4110 /* broken sequence was encountered and this is an error */
4111 return UCOL_NOT_FOUND
;
4113 case LEAD_SURROGATE_TAG
: /* D800-DBFF*/
4114 return UCOL_NOT_FOUND
; /* broken surrogate sequence */
4116 case TRAIL_SURROGATE_TAG
: /* DC00-DFFF*/
4121 if (isAtStartPrevIterate(source
)) {
4122 /* we are at the start of the string, wrong place to be at */
4123 return UCOL_NOT_FOUND
;
4125 if (source
->pos
!= source
->writableBuffer
.getBuffer()) {
4126 prev
= source
->pos
- 1;
4128 prev
= source
->fcdPosition
;
4132 /* Handles Han and Supplementary characters here.*/
4133 if (U16_IS_LEAD(prevChar
)) {
4134 cp
= ((((uint32_t)prevChar
)<<10UL)+(ch
)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
4137 return UCOL_NOT_FOUND
; /* like unassigned */
4140 return getPrevImplicit(cp
, source
);
4143 /* UCA is filled with these. Tailorings are NOT_FOUND */
4144 /* not yet implemented */
4145 case CHARSET_TAG
: /* this tag always returns */
4146 /* probably after 1.8 */
4147 return UCOL_NOT_FOUND
;
4149 default: /* this tag always returns */
4150 *status
= U_INTERNAL_PROGRAM_ERROR
;
4155 if (CE
<= UCOL_NOT_FOUND
) {
4163 /* This should really be a macro */
4164 /* This function is used to reverse parts of a buffer. We need this operation when doing continuation */
4165 /* secondaries in French */
4167 void uprv_ucol_reverse_buffer(uint8_t *start, uint8_t *end) {
4177 #define uprv_ucol_reverse_buffer(TYPE, start, end) { \
4179 while((start)<(end)) { \
4181 *(start)++ = *(end); \
4186 /****************************************************************************/
4187 /* Following are the sortkey generation functions */
4189 /****************************************************************************/
4191 U_CAPI
int32_t U_EXPORT2
4192 ucol_mergeSortkeys(const uint8_t *src1
, int32_t src1Length
,
4193 const uint8_t *src2
, int32_t src2Length
,
4194 uint8_t *dest
, int32_t destCapacity
) {
4195 /* check arguments */
4196 if( src1
==NULL
|| src1Length
<-1 || src1Length
==0 || (src1Length
>0 && src1
[src1Length
-1]!=0) ||
4197 src2
==NULL
|| src2Length
<-1 || src2Length
==0 || (src2Length
>0 && src2
[src2Length
-1]!=0) ||
4198 destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)
4200 /* error, attempt to write a zero byte and return 0 */
4201 if(dest
!=NULL
&& destCapacity
>0) {
4207 /* check lengths and capacity */
4209 src1Length
=(int32_t)uprv_strlen((const char *)src1
)+1;
4212 src2Length
=(int32_t)uprv_strlen((const char *)src2
)+1;
4215 int32_t destLength
=src1Length
+src2Length
;
4216 if(destLength
>destCapacity
) {
4217 /* the merged sort key does not fit into the destination */
4221 /* merge the sort keys with the same number of levels */
4224 /* copy level from src1 not including 00 or 01 */
4226 while((b
=*src1
)>=2) {
4231 /* add a 02 merge separator */
4234 /* copy level from src2 not including 00 or 01 */
4235 while((b
=*src2
)>=2) {
4240 /* if both sort keys have another level, then add a 01 level separator and continue */
4241 if(*src1
==1 && *src2
==1) {
4251 * here, at least one sort key is finished now, but the other one
4252 * might have some contents left from containing more levels;
4253 * that contents is just appended to the result
4256 /* src1 is not finished, therefore *src2==0, and src1 is appended */
4259 /* append src2, "the other, unfinished sort key" */
4260 while((*p
++=*src2
++)!=0) {}
4262 /* the actual length might be less than destLength if either sort key contained illegally embedded zero bytes */
4263 return (int32_t)(p
-dest
);
4268 class SortKeyByteSink
: public ByteSink
{
4270 SortKeyByteSink(char *dest
, int32_t destCapacity
)
4271 : buffer_(dest
), capacity_(destCapacity
),
4273 if (buffer_
== NULL
) {
4275 } else if(capacity_
< 0) {
4280 virtual ~SortKeyByteSink();
4282 virtual void Append(const char *bytes
, int32_t n
);
4283 void Append(uint32_t b
) {
4284 if (appended_
< capacity_
|| Resize(1, appended_
)) {
4285 buffer_
[appended_
] = (char)b
;
4289 void Append(uint32_t b1
, uint32_t b2
) {
4290 int32_t a2
= appended_
+ 2;
4291 if (a2
<= capacity_
|| Resize(2, appended_
)) {
4292 buffer_
[appended_
] = (char)b1
;
4293 buffer_
[appended_
+ 1] = (char)b2
;
4294 } else if(appended_
< capacity_
) {
4295 buffer_
[appended_
] = (char)b1
;
4299 virtual char *GetAppendBuffer(int32_t min_capacity
,
4300 int32_t desired_capacity_hint
,
4301 char *scratch
, int32_t scratch_capacity
,
4302 int32_t *result_capacity
);
4303 int32_t NumberOfBytesAppended() const { return appended_
; }
4304 /** @return FALSE if memory allocation failed */
4305 UBool
IsOk() const { return buffer_
!= NULL
; }
4308 virtual void AppendBeyondCapacity(const char *bytes
, int32_t n
, int32_t length
) = 0;
4309 virtual UBool
Resize(int32_t appendCapacity
, int32_t length
) = 0;
4321 SortKeyByteSink(const SortKeyByteSink
&); // copy constructor not implemented
4322 SortKeyByteSink
&operator=(const SortKeyByteSink
&); // assignment operator not implemented
4325 SortKeyByteSink::~SortKeyByteSink() {}
4328 SortKeyByteSink::Append(const char *bytes
, int32_t n
) {
4329 if (n
<= 0 || bytes
== NULL
) {
4332 int32_t length
= appended_
;
4334 if ((buffer_
+ length
) == bytes
) {
4335 return; // the caller used GetAppendBuffer() and wrote the bytes already
4337 int32_t available
= capacity_
- length
;
4338 if (n
<= available
) {
4339 uprv_memcpy(buffer_
+ length
, bytes
, n
);
4341 AppendBeyondCapacity(bytes
, n
, length
);
4346 SortKeyByteSink::GetAppendBuffer(int32_t min_capacity
,
4347 int32_t desired_capacity_hint
,
4349 int32_t scratch_capacity
,
4350 int32_t *result_capacity
) {
4351 if (min_capacity
< 1 || scratch_capacity
< min_capacity
) {
4352 *result_capacity
= 0;
4355 int32_t available
= capacity_
- appended_
;
4356 if (available
>= min_capacity
) {
4357 *result_capacity
= available
;
4358 return buffer_
+ appended_
;
4359 } else if (Resize(desired_capacity_hint
, appended_
)) {
4360 *result_capacity
= capacity_
- appended_
;
4361 return buffer_
+ appended_
;
4363 *result_capacity
= scratch_capacity
;
4368 class FixedSortKeyByteSink
: public SortKeyByteSink
{
4370 FixedSortKeyByteSink(char *dest
, int32_t destCapacity
)
4371 : SortKeyByteSink(dest
, destCapacity
) {}
4372 virtual ~FixedSortKeyByteSink();
4375 virtual void AppendBeyondCapacity(const char *bytes
, int32_t n
, int32_t length
);
4376 virtual UBool
Resize(int32_t appendCapacity
, int32_t length
);
4379 FixedSortKeyByteSink::~FixedSortKeyByteSink() {}
4382 FixedSortKeyByteSink::AppendBeyondCapacity(const char *bytes
, int32_t /*n*/, int32_t length
) {
4383 // buffer_ != NULL && bytes != NULL && n > 0 && appended_ > capacity_
4384 // Fill the buffer completely.
4385 int32_t available
= capacity_
- length
;
4386 if (available
> 0) {
4387 uprv_memcpy(buffer_
+ length
, bytes
, available
);
4392 FixedSortKeyByteSink::Resize(int32_t /*appendCapacity*/, int32_t /*length*/) {
4396 class CollationKeyByteSink
: public SortKeyByteSink
{
4398 CollationKeyByteSink(CollationKey
&key
)
4399 : SortKeyByteSink(reinterpret_cast<char *>(key
.getBytes()), key
.getCapacity()),
4401 virtual ~CollationKeyByteSink();
4404 virtual void AppendBeyondCapacity(const char *bytes
, int32_t n
, int32_t length
);
4405 virtual UBool
Resize(int32_t appendCapacity
, int32_t length
);
4410 CollationKeyByteSink::~CollationKeyByteSink() {}
4413 CollationKeyByteSink::AppendBeyondCapacity(const char *bytes
, int32_t n
, int32_t length
) {
4414 // buffer_ != NULL && bytes != NULL && n > 0 && appended_ > capacity_
4415 if (Resize(n
, length
)) {
4416 uprv_memcpy(buffer_
+ length
, bytes
, n
);
4421 CollationKeyByteSink::Resize(int32_t appendCapacity
, int32_t length
) {
4422 if (buffer_
== NULL
) {
4423 return FALSE
; // allocation failed before already
4425 int32_t newCapacity
= 2 * capacity_
;
4426 int32_t altCapacity
= length
+ 2 * appendCapacity
;
4427 if (newCapacity
< altCapacity
) {
4428 newCapacity
= altCapacity
;
4430 if (newCapacity
< 200) {
4433 uint8_t *newBuffer
= key_
.reallocate(newCapacity
, length
);
4434 if (newBuffer
== NULL
) {
4438 buffer_
= reinterpret_cast<char *>(newBuffer
);
4439 capacity_
= newCapacity
;
4444 * uint8_t byte buffer, similar to CharString but simpler.
4446 class SortKeyLevel
: public UMemory
{
4448 SortKeyLevel() : len(0), ok(TRUE
) {}
4451 /** @return FALSE if memory allocation failed */
4452 UBool
isOk() const { return ok
; }
4453 UBool
isEmpty() const { return len
== 0; }
4454 int32_t length() const { return len
; }
4455 const uint8_t *data() const { return buffer
.getAlias(); }
4456 uint8_t operator[](int32_t index
) const { return buffer
[index
]; }
4458 void appendByte(uint32_t b
);
4460 void appendTo(ByteSink
&sink
) const {
4461 sink
.Append(reinterpret_cast<const char *>(buffer
.getAlias()), len
);
4464 uint8_t &lastByte() {
4466 return buffer
[len
- 1];
4469 uint8_t *getLastFewBytes(int32_t n
) {
4470 if (ok
&& len
>= n
) {
4471 return buffer
.getAlias() + len
- n
;
4478 MaybeStackArray
<uint8_t, 40> buffer
;
4482 UBool
ensureCapacity(int32_t appendCapacity
);
4484 SortKeyLevel(const SortKeyLevel
&other
); // forbid copying of this class
4485 SortKeyLevel
&operator=(const SortKeyLevel
&other
); // forbid copying of this class
4488 void SortKeyLevel::appendByte(uint32_t b
) {
4489 if(len
< buffer
.getCapacity() || ensureCapacity(1)) {
4490 buffer
[len
++] = (uint8_t)b
;
4494 UBool
SortKeyLevel::ensureCapacity(int32_t appendCapacity
) {
4498 int32_t newCapacity
= 2 * buffer
.getCapacity();
4499 int32_t altCapacity
= len
+ 2 * appendCapacity
;
4500 if (newCapacity
< altCapacity
) {
4501 newCapacity
= altCapacity
;
4503 if (newCapacity
< 200) {
4506 if(buffer
.resize(newCapacity
, len
)==NULL
) {
4515 U_CAPI
int32_t U_EXPORT2
4516 ucol_getSortKey(const UCollator
*coll
,
4517 const UChar
*source
,
4518 int32_t sourceLength
,
4520 int32_t resultLength
)
4522 UTRACE_ENTRY(UTRACE_UCOL_GET_SORTKEY
);
4523 if (UTRACE_LEVEL(UTRACE_VERBOSE
)) {
4524 UTRACE_DATA3(UTRACE_VERBOSE
, "coll=%p, source string = %vh ", coll
, source
,
4525 ((sourceLength
==-1 && source
!=NULL
) ? u_strlen(source
) : sourceLength
));
4528 if(coll
->delegate
!= NULL
) {
4529 return ((const Collator
*)coll
->delegate
)->getSortKey(source
, sourceLength
, result
, resultLength
);
4532 UErrorCode status
= U_ZERO_ERROR
;
4533 int32_t keySize
= 0;
4535 if(source
!= NULL
) {
4536 // source == NULL is actually an error situation, but we would need to
4537 // have an error code to return it. Until we introduce a new
4538 // API, it stays like this
4540 /* this uses the function pointer that is set in updateinternalstate */
4541 /* currently, there are two funcs: */
4542 /*ucol_calcSortKey(...);*/
4543 /*ucol_calcSortKeySimpleTertiary(...);*/
4545 uint8_t noDest
[1] = { 0 };
4546 if(result
== NULL
) {
4547 // Distinguish pure preflighting from an allocation error.
4551 FixedSortKeyByteSink
sink(reinterpret_cast<char *>(result
), resultLength
);
4552 coll
->sortKeyGen(coll
, source
, sourceLength
, sink
, &status
);
4553 if(U_SUCCESS(status
)) {
4554 keySize
= sink
.NumberOfBytesAppended();
4557 UTRACE_DATA2(UTRACE_VERBOSE
, "Sort Key = %vb", result
, keySize
);
4558 UTRACE_EXIT_STATUS(status
);
4563 ucol_getCollationKey(const UCollator
*coll
,
4564 const UChar
*source
, int32_t sourceLength
,
4566 UErrorCode
&errorCode
) {
4567 CollationKeyByteSink
sink(key
);
4568 coll
->sortKeyGen(coll
, source
, sourceLength
, sink
, &errorCode
);
4569 return sink
.NumberOfBytesAppended();
4572 // Is this primary weight compressible?
4573 // Returns false for multi-lead-byte scripts (digits, Latin, Han, implicit).
4574 // TODO: This should use per-lead-byte flags from FractionalUCA.txt.
4576 isCompressible(const UCollator
* /*coll*/, uint8_t primary1
) {
4577 return UCOL_BYTE_FIRST_NON_LATIN_PRIMARY
<= primary1
&& primary1
<= maxRegularPrimary
;
4581 inline void doCaseShift(SortKeyLevel
&cases
, uint32_t &caseShift
) {
4582 if (caseShift
== 0) {
4583 cases
.appendByte(UCOL_CASE_BYTE_START
);
4584 caseShift
= UCOL_CASE_SHIFT_START
;
4588 // Packs the secondary buffer when processing French locale.
4590 packFrench(const uint8_t *secondaries
, int32_t secsize
, SortKeyByteSink
&result
) {
4591 secondaries
+= secsize
; // We read the secondary-level bytes back to front.
4595 // we use i here since the key size already accounts for terminators, so we'll discard the increment
4596 for(i
= 0; i
<secsize
; i
++) {
4597 secondary
= *(secondaries
-i
-1);
4598 /* This is compression code. */
4599 if (secondary
== UCOL_COMMON2
) {
4603 if (secondary
> UCOL_COMMON2
) { // not necessary for 4th level.
4604 while (count2
> UCOL_TOP_COUNT2
) {
4605 result
.Append(UCOL_COMMON_TOP2
- UCOL_TOP_COUNT2
);
4606 count2
-= (uint32_t)UCOL_TOP_COUNT2
;
4608 result
.Append(UCOL_COMMON_TOP2
- (count2
-1));
4610 while (count2
> UCOL_BOT_COUNT2
) {
4611 result
.Append(UCOL_COMMON_BOT2
+ UCOL_BOT_COUNT2
);
4612 count2
-= (uint32_t)UCOL_BOT_COUNT2
;
4614 result
.Append(UCOL_COMMON_BOT2
+ (count2
-1));
4618 result
.Append(secondary
);
4622 while (count2
> UCOL_BOT_COUNT2
) {
4623 result
.Append(UCOL_COMMON_BOT2
+ UCOL_BOT_COUNT2
);
4624 count2
-= (uint32_t)UCOL_BOT_COUNT2
;
4626 result
.Append(UCOL_COMMON_BOT2
+ (count2
-1));
4630 #define DEFAULT_ERROR_SIZE_FOR_CALCSORTKEY 0
4632 /* This is the sortkey work horse function */
4633 U_CFUNC
void U_CALLCONV
4634 ucol_calcSortKey(const UCollator
*coll
,
4635 const UChar
*source
,
4636 int32_t sourceLength
,
4637 SortKeyByteSink
&result
,
4640 if(U_FAILURE(*status
)) {
4644 SortKeyByteSink
&primaries
= result
;
4645 SortKeyLevel secondaries
;
4646 SortKeyLevel tertiaries
;
4650 UnicodeString normSource
;
4652 int32_t len
= (sourceLength
== -1 ? u_strlen(source
) : sourceLength
);
4654 UColAttributeValue strength
= coll
->strength
;
4656 uint8_t compareSec
= (uint8_t)((strength
>= UCOL_SECONDARY
)?0:0xFF);
4657 uint8_t compareTer
= (uint8_t)((strength
>= UCOL_TERTIARY
)?0:0xFF);
4658 uint8_t compareQuad
= (uint8_t)((strength
>= UCOL_QUATERNARY
)?0:0xFF);
4659 UBool compareIdent
= (strength
== UCOL_IDENTICAL
);
4660 UBool doCase
= (coll
->caseLevel
== UCOL_ON
);
4661 UBool isFrenchSec
= (coll
->frenchCollation
== UCOL_ON
) && (compareSec
== 0);
4662 UBool shifted
= (coll
->alternateHandling
== UCOL_SHIFTED
);
4663 //UBool qShifted = shifted && (compareQuad == 0);
4664 UBool doHiragana
= (coll
->hiraganaQ
== UCOL_ON
) && (compareQuad
== 0);
4666 uint32_t variableTopValue
= coll
->variableTopValue
;
4667 // TODO: UCOL_COMMON_BOT4 should be a function of qShifted. If we have no
4668 // qShifted, we don't need to set UCOL_COMMON_BOT4 so high.
4669 uint8_t UCOL_COMMON_BOT4
= (uint8_t)((coll
->variableTopValue
>>8)+1);
4670 uint8_t UCOL_HIRAGANA_QUAD
= 0;
4672 UCOL_HIRAGANA_QUAD
=UCOL_COMMON_BOT4
++;
4673 /* allocate one more space for hiragana, value for hiragana */
4675 uint8_t UCOL_BOT_COUNT4
= (uint8_t)(0xFF - UCOL_COMMON_BOT4
);
4677 /* support for special features like caselevel and funky secondaries */
4678 int32_t lastSecondaryLength
= 0;
4679 uint32_t caseShift
= 0;
4681 /* If we need to normalize, we'll do it all at once at the beginning! */
4682 const Normalizer2
*norm2
;
4684 norm2
= Normalizer2Factory::getNFDInstance(*status
);
4685 } else if(coll
->normalizationMode
!= UCOL_OFF
) {
4686 norm2
= Normalizer2Factory::getFCDInstance(*status
);
4691 normSource
.setTo(FALSE
, source
, len
);
4692 int32_t qcYesLength
= norm2
->spanQuickCheckYes(normSource
, *status
);
4693 if(qcYesLength
!= len
) {
4694 UnicodeString unnormalized
= normSource
.tempSubString(qcYesLength
);
4695 normSource
.truncate(qcYesLength
);
4696 norm2
->normalizeSecondAndAppend(normSource
, unnormalized
, *status
);
4697 source
= normSource
.getBuffer();
4698 len
= normSource
.length();
4702 IInit_collIterate(coll
, source
, len
, &s
, status
);
4703 if(U_FAILURE(*status
)) {
4706 s
.flags
&= ~UCOL_ITER_NORM
; // source passed the FCD test or else was normalized.
4710 uint8_t primary1
= 0;
4711 uint8_t primary2
= 0;
4712 uint8_t secondary
= 0;
4713 uint8_t tertiary
= 0;
4714 uint8_t caseSwitch
= coll
->caseSwitch
;
4715 uint8_t tertiaryMask
= coll
->tertiaryMask
;
4716 int8_t tertiaryAddition
= coll
->tertiaryAddition
;
4717 uint8_t tertiaryTop
= coll
->tertiaryTop
;
4718 uint8_t tertiaryBottom
= coll
->tertiaryBottom
;
4719 uint8_t tertiaryCommon
= coll
->tertiaryCommon
;
4720 uint8_t caseBits
= 0;
4722 UBool wasShifted
= FALSE
;
4723 UBool notIsContinuation
= FALSE
;
4725 uint32_t count2
= 0, count3
= 0, count4
= 0;
4726 uint8_t leadPrimary
= 0;
4729 order
= ucol_IGetNextCE(coll
, &s
, status
);
4730 if(order
== UCOL_NO_MORE_CES
) {
4738 notIsContinuation
= !isContinuation(order
);
4740 if(notIsContinuation
) {
4741 tertiary
= (uint8_t)(order
& UCOL_BYTE_SIZE_MASK
);
4743 tertiary
= (uint8_t)((order
& UCOL_REMOVE_CONTINUATION
));
4746 secondary
= (uint8_t)((order
>>= 8) & UCOL_BYTE_SIZE_MASK
);
4747 primary2
= (uint8_t)((order
>>= 8) & UCOL_BYTE_SIZE_MASK
);
4748 primary1
= (uint8_t)(order
>> 8);
4750 uint8_t originalPrimary1
= primary1
;
4751 if(notIsContinuation
&& coll
->leadBytePermutationTable
!= NULL
) {
4752 primary1
= coll
->leadBytePermutationTable
[primary1
];
4755 if((shifted
&& ((notIsContinuation
&& order
<= variableTopValue
&& primary1
> 0)
4756 || (!notIsContinuation
&& wasShifted
)))
4757 || (wasShifted
&& primary1
== 0)) /* amendment to the UCA says that primary ignorables */
4759 /* and other ignorables should be removed if following a shifted code point */
4760 if(primary1
== 0) { /* if we were shifted and we got an ignorable code point */
4761 /* we should just completely ignore it */
4764 if(compareQuad
== 0) {
4766 while (count4
> UCOL_BOT_COUNT4
) {
4767 quads
.appendByte(UCOL_COMMON_BOT4
+ UCOL_BOT_COUNT4
);
4768 count4
-= UCOL_BOT_COUNT4
;
4770 quads
.appendByte(UCOL_COMMON_BOT4
+ (count4
-1));
4773 /* We are dealing with a variable and we're treating them as shifted */
4774 /* This is a shifted ignorable */
4775 if(primary1
!= 0) { /* we need to check this since we could be in continuation */
4776 quads
.appendByte(primary1
);
4779 quads
.appendByte(primary2
);
4785 /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
4786 /* Usually, we'll have non-zero primary1 & primary2, except in cases of a-z and friends, when primary2 will */
4787 /* regular and simple sortkey calc */
4788 if(primary1
!= UCOL_IGNORABLE
) {
4789 if(notIsContinuation
) {
4790 if(leadPrimary
== primary1
) {
4791 primaries
.Append(primary2
);
4793 if(leadPrimary
!= 0) {
4794 primaries
.Append((primary1
> leadPrimary
) ? UCOL_BYTE_UNSHIFTED_MAX
: UCOL_BYTE_UNSHIFTED_MIN
);
4796 if(primary2
== UCOL_IGNORABLE
) {
4797 /* one byter, not compressed */
4798 primaries
.Append(primary1
);
4800 } else if(isCompressible(coll
, originalPrimary1
)) {
4802 primaries
.Append(leadPrimary
= primary1
, primary2
);
4805 primaries
.Append(primary1
, primary2
);
4808 } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
4809 if(primary2
== UCOL_IGNORABLE
) {
4810 primaries
.Append(primary1
);
4812 primaries
.Append(primary1
, primary2
);
4817 if(secondary
> compareSec
) {
4819 /* This is compression code. */
4820 if (secondary
== UCOL_COMMON2
&& notIsContinuation
) {
4824 if (secondary
> UCOL_COMMON2
) { // not necessary for 4th level.
4825 while (count2
> UCOL_TOP_COUNT2
) {
4826 secondaries
.appendByte(UCOL_COMMON_TOP2
- UCOL_TOP_COUNT2
);
4827 count2
-= (uint32_t)UCOL_TOP_COUNT2
;
4829 secondaries
.appendByte(UCOL_COMMON_TOP2
- (count2
-1));
4831 while (count2
> UCOL_BOT_COUNT2
) {
4832 secondaries
.appendByte(UCOL_COMMON_BOT2
+ UCOL_BOT_COUNT2
);
4833 count2
-= (uint32_t)UCOL_BOT_COUNT2
;
4835 secondaries
.appendByte(UCOL_COMMON_BOT2
+ (count2
-1));
4839 secondaries
.appendByte(secondary
);
4842 /* Do the special handling for French secondaries */
4843 /* We need to get continuation elements and do intermediate restore */
4844 /* abc1c2c3de with french secondaries need to be edc1c2c3ba NOT edc3c2c1ba */
4845 if(notIsContinuation
) {
4846 if (lastSecondaryLength
> 1) {
4847 uint8_t *frenchStartPtr
= secondaries
.getLastFewBytes(lastSecondaryLength
);
4848 if (frenchStartPtr
!= NULL
) {
4849 /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
4850 uint8_t *frenchEndPtr
= frenchStartPtr
+ lastSecondaryLength
- 1;
4851 uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr
, frenchEndPtr
);
4854 lastSecondaryLength
= 1;
4856 ++lastSecondaryLength
;
4858 secondaries
.appendByte(secondary
);
4862 if(doCase
&& (primary1
> 0 || strength
>= UCOL_SECONDARY
)) {
4863 // do the case level if we need to do it. We don't want to calculate
4864 // case level for primary ignorables if we have only primary strength and case level
4865 // otherwise we would break well formedness of CEs
4866 doCaseShift(cases
, caseShift
);
4867 if(notIsContinuation
) {
4868 caseBits
= (uint8_t)(tertiary
& 0xC0);
4871 if(coll
->caseFirst
== UCOL_UPPER_FIRST
) {
4872 if((caseBits
& 0xC0) == 0) {
4873 cases
.lastByte() |= 1 << (--caseShift
);
4875 cases
.lastByte() |= 0 << (--caseShift
);
4877 doCaseShift(cases
, caseShift
);
4878 cases
.lastByte() |= ((caseBits
>>6)&1) << (--caseShift
);
4881 if((caseBits
& 0xC0) == 0) {
4882 cases
.lastByte() |= 0 << (--caseShift
);
4884 cases
.lastByte() |= 1 << (--caseShift
);
4886 doCaseShift(cases
, caseShift
);
4887 cases
.lastByte() |= ((caseBits
>>7)&1) << (--caseShift
);
4893 if(notIsContinuation
) {
4894 tertiary
^= caseSwitch
;
4898 tertiary
&= tertiaryMask
;
4899 if(tertiary
> compareTer
) {
4900 /* This is compression code. */
4901 /* sequence size check is included in the if clause */
4902 if (tertiary
== tertiaryCommon
&& notIsContinuation
) {
4905 if(tertiary
> tertiaryCommon
&& tertiaryCommon
== UCOL_COMMON3_NORMAL
) {
4906 tertiary
+= tertiaryAddition
;
4907 } else if(tertiary
<= tertiaryCommon
&& tertiaryCommon
== UCOL_COMMON3_UPPERFIRST
) {
4908 tertiary
-= tertiaryAddition
;
4911 if ((tertiary
> tertiaryCommon
)) {
4912 while (count3
> coll
->tertiaryTopCount
) {
4913 tertiaries
.appendByte(tertiaryTop
- coll
->tertiaryTopCount
);
4914 count3
-= (uint32_t)coll
->tertiaryTopCount
;
4916 tertiaries
.appendByte(tertiaryTop
- (count3
-1));
4918 while (count3
> coll
->tertiaryBottomCount
) {
4919 tertiaries
.appendByte(tertiaryBottom
+ coll
->tertiaryBottomCount
);
4920 count3
-= (uint32_t)coll
->tertiaryBottomCount
;
4922 tertiaries
.appendByte(tertiaryBottom
+ (count3
-1));
4926 tertiaries
.appendByte(tertiary
);
4930 if(/*qShifted*/(compareQuad
==0) && notIsContinuation
) {
4931 if(s
.flags
& UCOL_WAS_HIRAGANA
) { // This was Hiragana and we need to note it
4932 if(count4
>0) { // Close this part
4933 while (count4
> UCOL_BOT_COUNT4
) {
4934 quads
.appendByte(UCOL_COMMON_BOT4
+ UCOL_BOT_COUNT4
);
4935 count4
-= UCOL_BOT_COUNT4
;
4937 quads
.appendByte(UCOL_COMMON_BOT4
+ (count4
-1));
4940 quads
.appendByte(UCOL_HIRAGANA_QUAD
); // Add the Hiragana
4941 } else { // This wasn't Hiragana, so we can continue adding stuff
4948 /* Here, we are generally done with processing */
4949 /* bailing out would not be too productive */
4952 if(U_SUCCESS(*status
)) {
4953 /* we have done all the CE's, now let's put them together to form a key */
4954 if(compareSec
== 0) {
4956 while (count2
> UCOL_BOT_COUNT2
) {
4957 secondaries
.appendByte(UCOL_COMMON_BOT2
+ UCOL_BOT_COUNT2
);
4958 count2
-= (uint32_t)UCOL_BOT_COUNT2
;
4960 secondaries
.appendByte(UCOL_COMMON_BOT2
+ (count2
-1));
4962 result
.Append(UCOL_LEVELTERMINATOR
);
4963 if(!secondaries
.isOk()) {
4965 } else if(!isFrenchSec
) {
4966 secondaries
.appendTo(result
);
4968 // If there are any unresolved continuation secondaries,
4969 // reverse them here so that we can reverse the whole secondary thing.
4970 if (lastSecondaryLength
> 1) {
4971 uint8_t *frenchStartPtr
= secondaries
.getLastFewBytes(lastSecondaryLength
);
4972 if (frenchStartPtr
!= NULL
) {
4973 /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
4974 uint8_t *frenchEndPtr
= frenchStartPtr
+ lastSecondaryLength
- 1;
4975 uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr
, frenchEndPtr
);
4978 packFrench(secondaries
.data(), secondaries
.length(), result
);
4984 result
.Append(UCOL_LEVELTERMINATOR
);
4985 cases
.appendTo(result
);
4988 if(compareTer
== 0) {
4990 if (coll
->tertiaryCommon
!= UCOL_COMMON_BOT3
) {
4991 while (count3
>= coll
->tertiaryTopCount
) {
4992 tertiaries
.appendByte(tertiaryTop
- coll
->tertiaryTopCount
);
4993 count3
-= (uint32_t)coll
->tertiaryTopCount
;
4995 tertiaries
.appendByte(tertiaryTop
- count3
);
4997 while (count3
> coll
->tertiaryBottomCount
) {
4998 tertiaries
.appendByte(tertiaryBottom
+ coll
->tertiaryBottomCount
);
4999 count3
-= (uint32_t)coll
->tertiaryBottomCount
;
5001 tertiaries
.appendByte(tertiaryBottom
+ (count3
-1));
5004 ok
&= tertiaries
.isOk();
5005 result
.Append(UCOL_LEVELTERMINATOR
);
5006 tertiaries
.appendTo(result
);
5008 if(compareQuad
== 0/*qShifted == TRUE*/) {
5010 while (count4
> UCOL_BOT_COUNT4
) {
5011 quads
.appendByte(UCOL_COMMON_BOT4
+ UCOL_BOT_COUNT4
);
5012 count4
-= UCOL_BOT_COUNT4
;
5014 quads
.appendByte(UCOL_COMMON_BOT4
+ (count4
-1));
5017 result
.Append(UCOL_LEVELTERMINATOR
);
5018 quads
.appendTo(result
);
5022 result
.Append(UCOL_LEVELTERMINATOR
);
5023 u_writeIdenticalLevelRun(s
.string
, len
, result
);
5029 /* To avoid memory leak, free the offset buffer if necessary. */
5030 ucol_freeOffsetBuffer(&s
);
5032 ok
&= result
.IsOk();
5033 if(!ok
&& U_SUCCESS(*status
)) { *status
= U_MEMORY_ALLOCATION_ERROR
; }
5037 U_CFUNC
void U_CALLCONV
5038 ucol_calcSortKeySimpleTertiary(const UCollator
*coll
,
5039 const UChar
*source
,
5040 int32_t sourceLength
,
5041 SortKeyByteSink
&result
,
5046 if(U_FAILURE(*status
)) {
5050 SortKeyByteSink
&primaries
= result
;
5051 SortKeyLevel secondaries
;
5052 SortKeyLevel tertiaries
;
5054 UnicodeString normSource
;
5056 int32_t len
= sourceLength
;
5058 /* If we need to normalize, we'll do it all at once at the beginning! */
5059 if(coll
->normalizationMode
!= UCOL_OFF
) {
5060 normSource
.setTo(len
< 0, source
, len
);
5061 const Normalizer2
*norm2
= Normalizer2Factory::getFCDInstance(*status
);
5062 int32_t qcYesLength
= norm2
->spanQuickCheckYes(normSource
, *status
);
5063 if(qcYesLength
!= normSource
.length()) {
5064 UnicodeString unnormalized
= normSource
.tempSubString(qcYesLength
);
5065 normSource
.truncate(qcYesLength
);
5066 norm2
->normalizeSecondAndAppend(normSource
, unnormalized
, *status
);
5067 source
= normSource
.getBuffer();
5068 len
= normSource
.length();
5072 IInit_collIterate(coll
, (UChar
*)source
, len
, &s
, status
);
5073 if(U_FAILURE(*status
)) {
5076 s
.flags
&= ~UCOL_ITER_NORM
; // source passed the FCD test or else was normalized.
5080 uint8_t primary1
= 0;
5081 uint8_t primary2
= 0;
5082 uint8_t secondary
= 0;
5083 uint8_t tertiary
= 0;
5084 uint8_t caseSwitch
= coll
->caseSwitch
;
5085 uint8_t tertiaryMask
= coll
->tertiaryMask
;
5086 int8_t tertiaryAddition
= coll
->tertiaryAddition
;
5087 uint8_t tertiaryTop
= coll
->tertiaryTop
;
5088 uint8_t tertiaryBottom
= coll
->tertiaryBottom
;
5089 uint8_t tertiaryCommon
= coll
->tertiaryCommon
;
5091 UBool notIsContinuation
= FALSE
;
5093 uint32_t count2
= 0, count3
= 0;
5094 uint8_t leadPrimary
= 0;
5097 order
= ucol_IGetNextCE(coll
, &s
, status
);
5103 if(order
== UCOL_NO_MORE_CES
) {
5107 notIsContinuation
= !isContinuation(order
);
5109 if(notIsContinuation
) {
5110 tertiary
= (uint8_t)((order
& tertiaryMask
));
5112 tertiary
= (uint8_t)((order
& UCOL_REMOVE_CONTINUATION
));
5115 secondary
= (uint8_t)((order
>>= 8) & UCOL_BYTE_SIZE_MASK
);
5116 primary2
= (uint8_t)((order
>>= 8) & UCOL_BYTE_SIZE_MASK
);
5117 primary1
= (uint8_t)(order
>> 8);
5119 uint8_t originalPrimary1
= primary1
;
5120 if (coll
->leadBytePermutationTable
!= NULL
&& notIsContinuation
) {
5121 primary1
= coll
->leadBytePermutationTable
[primary1
];
5124 /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
5125 /* Usually, we'll have non-zero primary1 & primary2, except in cases of a-z and friends, when primary2 will */
5126 /* be zero with non zero primary1. primary3 is different than 0 only for long primaries - see above. */
5127 /* regular and simple sortkey calc */
5128 if(primary1
!= UCOL_IGNORABLE
) {
5129 if(notIsContinuation
) {
5130 if(leadPrimary
== primary1
) {
5131 primaries
.Append(primary2
);
5133 if(leadPrimary
!= 0) {
5134 primaries
.Append((primary1
> leadPrimary
) ? UCOL_BYTE_UNSHIFTED_MAX
: UCOL_BYTE_UNSHIFTED_MIN
);
5136 if(primary2
== UCOL_IGNORABLE
) {
5137 /* one byter, not compressed */
5138 primaries
.Append(primary1
);
5140 } else if(isCompressible(coll
, originalPrimary1
)) {
5142 primaries
.Append(leadPrimary
= primary1
, primary2
);
5145 primaries
.Append(primary1
, primary2
);
5148 } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
5149 if(primary2
== UCOL_IGNORABLE
) {
5150 primaries
.Append(primary1
);
5152 primaries
.Append(primary1
, primary2
);
5157 if(secondary
> 0) { /* I think that != 0 test should be != IGNORABLE */
5158 /* This is compression code. */
5159 if (secondary
== UCOL_COMMON2
&& notIsContinuation
) {
5163 if (secondary
> UCOL_COMMON2
) { // not necessary for 4th level.
5164 while (count2
> UCOL_TOP_COUNT2
) {
5165 secondaries
.appendByte(UCOL_COMMON_TOP2
- UCOL_TOP_COUNT2
);
5166 count2
-= (uint32_t)UCOL_TOP_COUNT2
;
5168 secondaries
.appendByte(UCOL_COMMON_TOP2
- (count2
-1));
5170 while (count2
> UCOL_BOT_COUNT2
) {
5171 secondaries
.appendByte(UCOL_COMMON_BOT2
+ UCOL_BOT_COUNT2
);
5172 count2
-= (uint32_t)UCOL_BOT_COUNT2
;
5174 secondaries
.appendByte(UCOL_COMMON_BOT2
+ (count2
-1));
5178 secondaries
.appendByte(secondary
);
5182 if(notIsContinuation
) {
5183 tertiary
^= caseSwitch
;
5187 /* This is compression code. */
5188 /* sequence size check is included in the if clause */
5189 if (tertiary
== tertiaryCommon
&& notIsContinuation
) {
5192 if(tertiary
> tertiaryCommon
&& tertiaryCommon
== UCOL_COMMON3_NORMAL
) {
5193 tertiary
+= tertiaryAddition
;
5194 } else if (tertiary
<= tertiaryCommon
&& tertiaryCommon
== UCOL_COMMON3_UPPERFIRST
) {
5195 tertiary
-= tertiaryAddition
;
5198 if ((tertiary
> tertiaryCommon
)) {
5199 while (count3
> coll
->tertiaryTopCount
) {
5200 tertiaries
.appendByte(tertiaryTop
- coll
->tertiaryTopCount
);
5201 count3
-= (uint32_t)coll
->tertiaryTopCount
;
5203 tertiaries
.appendByte(tertiaryTop
- (count3
-1));
5205 while (count3
> coll
->tertiaryBottomCount
) {
5206 tertiaries
.appendByte(tertiaryBottom
+ coll
->tertiaryBottomCount
);
5207 count3
-= (uint32_t)coll
->tertiaryBottomCount
;
5209 tertiaries
.appendByte(tertiaryBottom
+ (count3
-1));
5213 tertiaries
.appendByte(tertiary
);
5219 if(U_SUCCESS(*status
)) {
5220 /* we have done all the CE's, now let's put them together to form a key */
5222 while (count2
> UCOL_BOT_COUNT2
) {
5223 secondaries
.appendByte(UCOL_COMMON_BOT2
+ UCOL_BOT_COUNT2
);
5224 count2
-= (uint32_t)UCOL_BOT_COUNT2
;
5226 secondaries
.appendByte(UCOL_COMMON_BOT2
+ (count2
-1));
5228 ok
&= secondaries
.isOk();
5229 result
.Append(UCOL_LEVELTERMINATOR
);
5230 secondaries
.appendTo(result
);
5233 if (coll
->tertiaryCommon
!= UCOL_COMMON3_NORMAL
) {
5234 while (count3
>= coll
->tertiaryTopCount
) {
5235 tertiaries
.appendByte(tertiaryTop
- coll
->tertiaryTopCount
);
5236 count3
-= (uint32_t)coll
->tertiaryTopCount
;
5238 tertiaries
.appendByte(tertiaryTop
- count3
);
5240 while (count3
> coll
->tertiaryBottomCount
) {
5241 tertiaries
.appendByte(tertiaryBottom
+ coll
->tertiaryBottomCount
);
5242 count3
-= (uint32_t)coll
->tertiaryBottomCount
;
5244 tertiaries
.appendByte(tertiaryBottom
+ (count3
-1));
5247 ok
&= tertiaries
.isOk();
5248 result
.Append(UCOL_LEVELTERMINATOR
);
5249 tertiaries
.appendTo(result
);
5254 /* To avoid memory leak, free the offset buffer if necessary. */
5255 ucol_freeOffsetBuffer(&s
);
5257 ok
&= result
.IsOk();
5258 if(!ok
&& U_SUCCESS(*status
)) { *status
= U_MEMORY_ALLOCATION_ERROR
; }
5262 UBool
isShiftedCE(uint32_t CE
, uint32_t LVT
, UBool
*wasShifted
) {
5263 UBool notIsContinuation
= !isContinuation(CE
);
5264 uint8_t primary1
= (uint8_t)((CE
>> 24) & 0xFF);
5265 if((LVT
&& ((notIsContinuation
&& (CE
& 0xFFFF0000)<= LVT
&& primary1
> 0)
5266 || (!notIsContinuation
&& *wasShifted
)))
5267 || (*wasShifted
&& primary1
== 0)) /* amendment to the UCA says that primary ignorables */
5269 // The stuff below should probably be in the sortkey code... maybe not...
5270 if(primary1
!= 0) { /* if we were shifted and we got an ignorable code point */
5271 /* we should just completely ignore it */
5275 //*wasShifted = TRUE;
5278 *wasShifted
= FALSE
;
5283 void terminatePSKLevel(int32_t level
, int32_t maxLevel
, int32_t &i
, uint8_t *dest
) {
5284 if(level
< maxLevel
) {
5285 dest
[i
++] = UCOL_LEVELTERMINATOR
;
5291 /** enumeration of level identifiers for partial sort key generation */
5293 UCOL_PSK_PRIMARY
= 0,
5294 UCOL_PSK_SECONDARY
= 1,
5296 UCOL_PSK_TERTIARY
= 3,
5297 UCOL_PSK_QUATERNARY
= 4,
5298 UCOL_PSK_QUIN
= 5, /** This is an extra level, not used - but we have three bits to blow */
5299 UCOL_PSK_IDENTICAL
= 6,
5300 UCOL_PSK_NULL
= 7, /** level for the end of sort key. Will just produce zeros */
5304 /** collation state enum. *_SHIFT value is how much to shift right
5305 * to get the state piece to the right. *_MASK value should be
5306 * ANDed with the shifted state. This data is stored in state[1]
5310 UCOL_PSK_LEVEL_SHIFT
= 0, /** level identificator. stores an enum value from above */
5311 UCOL_PSK_LEVEL_MASK
= 7, /** three bits */
5312 UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT
= 3, /** number of bytes of primary or quaternary already written */
5313 UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK
= 1,
5314 /** can be only 0 or 1, since we get up to two bytes from primary or quaternary
5315 * This field is also used to denote that the French secondary level is finished
5317 UCOL_PSK_WAS_SHIFTED_SHIFT
= 4,/** was the last value shifted */
5318 UCOL_PSK_WAS_SHIFTED_MASK
= 1, /** can be 0 or 1 (Boolean) */
5319 UCOL_PSK_USED_FRENCH_SHIFT
= 5,/** how many French bytes have we already written */
5320 UCOL_PSK_USED_FRENCH_MASK
= 3, /** up to 4 bytes. See comment just below */
5321 /** When we do French we need to reverse secondary values. However, continuations
5322 * need to stay the same. So if you had abc1c2c3de, you need to have edc1c2c3ba
5324 UCOL_PSK_BOCSU_BYTES_SHIFT
= 7,
5325 UCOL_PSK_BOCSU_BYTES_MASK
= 3,
5326 UCOL_PSK_CONSUMED_CES_SHIFT
= 9,
5327 UCOL_PSK_CONSUMED_CES_MASK
= 0x7FFFF
5330 // macro calculating the number of expansion CEs available
5331 #define uprv_numAvailableExpCEs(s) (s).CEpos - (s).toReturn
5334 /** main sortkey part procedure. On the first call,
5335 * you should pass in a collator, an iterator, empty state
5336 * state[0] == state[1] == 0, a buffer to hold results
5337 * number of bytes you need and an error code pointer.
5338 * Make sure your buffer is big enough to hold the wanted
5339 * number of sortkey bytes. I don't check.
5340 * The only meaningful status you can get back is
5341 * U_BUFFER_OVERFLOW_ERROR, which basically means that you
5342 * have been dealt a raw deal and that you probably won't
5343 * be able to use partial sortkey generation for this
5344 * particular combination of string and collator. This
5345 * is highly unlikely, but you should still check the error code.
5346 * Any other status means that you're not in a sane situation
5347 * anymore. After the first call, preserve state values and
5348 * use them on subsequent calls to obtain more bytes of a sortkey.
5349 * Use until the number of bytes written is smaller than the requested
5350 * number of bytes. Generated sortkey is not compatible with the
5351 * one generated by ucol_getSortKey, as we don't do any compression.
5352 * However, levels are still terminated by a 1 (one) and the sortkey
5353 * is terminated by a 0 (zero). Identical level is the same as in the
5354 * regular sortkey - internal bocu-1 implementation is used.
5355 * For curious, although you cannot do much about this, here is
5356 * the structure of state words.
5357 * state[0] - iterator state. Depends on the iterator implementation,
5358 * but allows the iterator to continue where it stopped in
5359 * the last iteration.
5360 * state[1] - collation processing state. Here is the distribution
5362 * 0, 1, 2 - level of the sortkey - primary, secondary, case, tertiary
5363 * quaternary, quin (we don't use this one), identical and
5364 * null (producing only zeroes - first one to terminate the
5365 * sortkey and subsequent to fill the buffer).
5366 * 3 - byte count. Number of bytes written on the primary level.
5367 * 4 - was shifted. Whether the previous iteration finished in the
5369 * 5, 6 - French continuation bytes written. See the comment in the enum
5370 * 7,8 - Bocsu bytes used. Number of bytes from a bocu sequence on
5371 * the identical level.
5372 * 9..31 - CEs consumed. Number of getCE or next32 operations performed
5373 * since thes last successful update of the iterator state.
5375 U_CAPI
int32_t U_EXPORT2
5376 ucol_nextSortKeyPart(const UCollator
*coll
,
5377 UCharIterator
*iter
,
5379 uint8_t *dest
, int32_t count
,
5382 /* error checking */
5383 if(status
==NULL
|| U_FAILURE(*status
)) {
5386 UTRACE_ENTRY(UTRACE_UCOL_NEXTSORTKEYPART
);
5387 if( coll
==NULL
|| iter
==NULL
||
5389 count
<0 || (count
>0 && dest
==NULL
)
5391 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
5392 UTRACE_EXIT_STATUS(status
);
5396 UTRACE_DATA6(UTRACE_VERBOSE
, "coll=%p, iter=%p, state=%d %d, dest=%p, count=%d",
5397 coll
, iter
, state
[0], state
[1], dest
, count
);
5401 UTRACE_EXIT_VALUE(0);
5404 /** Setting up situation according to the state we got from the previous iteration */
5405 // The state of the iterator from the previous invocation
5406 uint32_t iterState
= state
[0];
5407 // Has the last iteration ended in the shifted state
5408 UBool wasShifted
= ((state
[1] >> UCOL_PSK_WAS_SHIFTED_SHIFT
) & UCOL_PSK_WAS_SHIFTED_MASK
)?TRUE
:FALSE
;
5409 // What is the current level of the sortkey?
5410 int32_t level
= (state
[1] >> UCOL_PSK_LEVEL_SHIFT
) & UCOL_PSK_LEVEL_MASK
;
5411 // Have we written only one byte from a two byte primary in the previous iteration?
5412 // Also on secondary level - have we finished with the French secondary?
5413 int32_t byteCountOrFrenchDone
= (state
[1] >> UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT
) & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK
;
5414 // number of bytes in the continuation buffer for French
5415 int32_t usedFrench
= (state
[1] >> UCOL_PSK_USED_FRENCH_SHIFT
) & UCOL_PSK_USED_FRENCH_MASK
;
5416 // Number of bytes already written from a bocsu sequence. Since
5417 // the longes bocsu sequence is 4 long, this can be up to 3.
5418 int32_t bocsuBytesUsed
= (state
[1] >> UCOL_PSK_BOCSU_BYTES_SHIFT
) & UCOL_PSK_BOCSU_BYTES_MASK
;
5419 // Number of elements that need to be consumed in this iteration because
5420 // the iterator returned UITER_NO_STATE at the end of the last iteration,
5421 // so we had to save the last valid state.
5422 int32_t cces
= (state
[1] >> UCOL_PSK_CONSUMED_CES_SHIFT
) & UCOL_PSK_CONSUMED_CES_MASK
;
5424 /** values that depend on the collator attributes */
5425 // strength of the collator.
5426 int32_t strength
= ucol_getAttribute(coll
, UCOL_STRENGTH
, status
);
5427 // maximal level of the partial sortkey. Need to take whether case level is done
5428 int32_t maxLevel
= 0;
5429 if(strength
< UCOL_TERTIARY
) {
5430 if(ucol_getAttribute(coll
, UCOL_CASE_LEVEL
, status
) == UCOL_ON
) {
5431 maxLevel
= UCOL_PSK_CASE
;
5433 maxLevel
= strength
;
5436 if(strength
== UCOL_TERTIARY
) {
5437 maxLevel
= UCOL_PSK_TERTIARY
;
5438 } else if(strength
== UCOL_QUATERNARY
) {
5439 maxLevel
= UCOL_PSK_QUATERNARY
;
5440 } else { // identical
5441 maxLevel
= UCOL_IDENTICAL
;
5444 // value for the quaternary level if Hiragana is encountered. Used for JIS X 4061 collation
5445 uint8_t UCOL_HIRAGANA_QUAD
=
5446 (ucol_getAttribute(coll
, UCOL_HIRAGANA_QUATERNARY_MODE
, status
) == UCOL_ON
)?0xFE:0xFF;
5447 // Boundary value that decides whether a CE is shifted or not
5448 uint32_t LVT
= (coll
->alternateHandling
== UCOL_SHIFTED
)?(coll
->variableTopValue
<<16):0;
5449 // Are we doing French collation?
5450 UBool doingFrench
= (ucol_getAttribute(coll
, UCOL_FRENCH_COLLATION
, status
) == UCOL_ON
);
5452 /** initializing the collation state */
5453 UBool notIsContinuation
= FALSE
;
5454 uint32_t CE
= UCOL_NO_MORE_CES
;
5457 IInit_collIterate(coll
, NULL
, -1, &s
, status
);
5458 if(U_FAILURE(*status
)) {
5459 UTRACE_EXIT_STATUS(*status
);
5463 s
.flags
|= UCOL_USE_ITERATOR
;
5464 // This variable tells us whether we have produced some other levels in this iteration
5465 // before we moved to the identical level. In that case, we need to switch the
5466 // type of the iterator.
5467 UBool doingIdenticalFromStart
= FALSE
;
5468 // Normalizing iterator
5469 // The division for the array length may truncate the array size to
5470 // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
5471 // for all platforms anyway.
5472 UAlignedMemory stackNormIter
[UNORM_ITER_SIZE
/sizeof(UAlignedMemory
)];
5473 UNormIterator
*normIter
= NULL
;
5474 // If the normalization is turned on for the collator and we are below identical level
5475 // we will use a FCD normalizing iterator
5476 if(ucol_getAttribute(coll
, UCOL_NORMALIZATION_MODE
, status
) == UCOL_ON
&& level
< UCOL_PSK_IDENTICAL
) {
5477 normIter
= unorm_openIter(stackNormIter
, sizeof(stackNormIter
), status
);
5478 s
.iterator
= unorm_setIter(normIter
, iter
, UNORM_FCD
, status
);
5479 s
.flags
&= ~UCOL_ITER_NORM
;
5480 if(U_FAILURE(*status
)) {
5481 UTRACE_EXIT_STATUS(*status
);
5484 } else if(level
== UCOL_PSK_IDENTICAL
) {
5485 // for identical level, we need a NFD iterator. We need to instantiate it here, since we
5486 // will be updating the state - and this cannot be done on an ordinary iterator.
5487 normIter
= unorm_openIter(stackNormIter
, sizeof(stackNormIter
), status
);
5488 s
.iterator
= unorm_setIter(normIter
, iter
, UNORM_NFD
, status
);
5489 s
.flags
&= ~UCOL_ITER_NORM
;
5490 if(U_FAILURE(*status
)) {
5491 UTRACE_EXIT_STATUS(*status
);
5494 doingIdenticalFromStart
= TRUE
;
5497 // This is the tentative new state of the iterator. The problem
5498 // is that the iterator might return an undefined state, in
5499 // which case we should save the last valid state and increase
5500 // the iterator skip value.
5501 uint32_t newState
= 0;
5503 // First, we set the iterator to the last valid position
5504 // from the last iteration. This was saved in state[0].
5505 if(iterState
== 0) {
5507 if(level
== UCOL_PSK_SECONDARY
&& doingFrench
&& !byteCountOrFrenchDone
) {
5508 s
.iterator
->move(s
.iterator
, 0, UITER_LIMIT
);
5510 s
.iterator
->move(s
.iterator
, 0, UITER_START
);
5513 /* reset to previous state */
5514 s
.iterator
->setState(s
.iterator
, iterState
, status
);
5515 if(U_FAILURE(*status
)) {
5516 UTRACE_EXIT_STATUS(*status
);
5523 // This variable tells us whether we can attempt to update the state
5524 // of iterator. Situations where we don't want to update iterator state
5525 // are the existence of expansion CEs that are not yet processed, and
5526 // finishing the case level without enough space in the buffer to insert
5527 // a level terminator.
5528 UBool canUpdateState
= TRUE
;
5530 // Consume all the CEs that were consumed at the end of the previous
5531 // iteration without updating the iterator state. On identical level,
5532 // consume the code points.
5533 int32_t counter
= cces
;
5534 if(level
< UCOL_PSK_IDENTICAL
) {
5535 while(counter
-->0) {
5536 // If we're doing French and we are on the secondary level,
5538 if(level
== UCOL_PSK_SECONDARY
&& doingFrench
) {
5539 CE
= ucol_IGetPrevCE(coll
, &s
, status
);
5541 CE
= ucol_IGetNextCE(coll
, &s
, status
);
5543 if(CE
==UCOL_NO_MORE_CES
) {
5544 /* should not happen */
5545 *status
=U_INTERNAL_PROGRAM_ERROR
;
5546 UTRACE_EXIT_STATUS(*status
);
5549 if(uprv_numAvailableExpCEs(s
)) {
5550 canUpdateState
= FALSE
;
5554 while(counter
-->0) {
5555 uiter_next32(s
.iterator
);
5559 // French secondary needs to know whether the iterator state of zero came from previous level OR
5560 // from a new invocation...
5561 UBool wasDoingPrimary
= FALSE
;
5562 // destination buffer byte counter. When this guy
5563 // gets to count, we're done with the iteration
5565 // used to count the zero bytes written after we
5566 // have finished with the sort key
5570 // Hm.... I think we're ready to plunge in. Basic story is as following:
5571 // we have a fall through case based on level. This is used for initial
5572 // positioning on iteration start. Every level processor contains a
5573 // for(;;) which will be broken when we exhaust all the CEs. Other
5574 // way to exit is a goto saveState, which happens when we have filled
5577 case UCOL_PSK_PRIMARY
:
5578 wasDoingPrimary
= TRUE
;
5583 // We should save the state only if we
5584 // are sure that we are done with the
5585 // previous iterator state
5586 if(canUpdateState
&& byteCountOrFrenchDone
== 0) {
5587 newState
= s
.iterator
->getState(s
.iterator
);
5588 if(newState
!= UITER_NO_STATE
) {
5589 iterState
= newState
;
5593 CE
= ucol_IGetNextCE(coll
, &s
, status
);
5595 if(CE
==UCOL_NO_MORE_CES
) {
5596 // Add the level separator
5597 terminatePSKLevel(level
, maxLevel
, i
, dest
);
5598 byteCountOrFrenchDone
=0;
5599 // Restart the iteration an move to the
5601 s
.iterator
->move(s
.iterator
, 0, UITER_START
);
5603 level
= UCOL_PSK_SECONDARY
;
5606 if(!isContinuation(CE
)){
5607 if(coll
->leadBytePermutationTable
!= NULL
){
5608 CE
= (coll
->leadBytePermutationTable
[CE
>>24] << 24) | (CE
& 0x00FFFFFF);
5611 if(!isShiftedCE(CE
, LVT
, &wasShifted
)) {
5612 CE
>>= UCOL_PRIMARYORDERSHIFT
; /* get primary */
5614 if(byteCountOrFrenchDone
== 0) {
5615 // get the second byte of primary
5616 dest
[i
++]=(uint8_t)(CE
>> 8);
5618 byteCountOrFrenchDone
= 0;
5620 if((CE
&=0xff)!=0) {
5623 byteCountOrFrenchDone
= 1;
5627 dest
[i
++]=(uint8_t)CE
;
5631 if(uprv_numAvailableExpCEs(s
)) {
5632 canUpdateState
= FALSE
;
5634 canUpdateState
= TRUE
;
5637 /* fall through to next level */
5638 case UCOL_PSK_SECONDARY
:
5639 if(strength
>= UCOL_SECONDARY
) {
5645 // We should save the state only if we
5646 // are sure that we are done with the
5647 // previous iterator state
5648 if(canUpdateState
) {
5649 newState
= s
.iterator
->getState(s
.iterator
);
5650 if(newState
!= UITER_NO_STATE
) {
5651 iterState
= newState
;
5655 CE
= ucol_IGetNextCE(coll
, &s
, status
);
5657 if(CE
==UCOL_NO_MORE_CES
) {
5658 // Add the level separator
5659 terminatePSKLevel(level
, maxLevel
, i
, dest
);
5660 byteCountOrFrenchDone
= 0;
5661 // Restart the iteration an move to the
5663 s
.iterator
->move(s
.iterator
, 0, UITER_START
);
5665 level
= UCOL_PSK_CASE
;
5668 if(!isShiftedCE(CE
, LVT
, &wasShifted
)) {
5669 CE
>>= 8; /* get secondary */
5671 dest
[i
++]=(uint8_t)CE
;
5674 if(uprv_numAvailableExpCEs(s
)) {
5675 canUpdateState
= FALSE
;
5677 canUpdateState
= TRUE
;
5680 } else { // French secondary processing
5681 uint8_t frenchBuff
[UCOL_MAX_BUFFER
];
5682 int32_t frenchIndex
= 0;
5683 // Here we are going backwards.
5684 // If the iterator is at the beggining, it should be
5686 if(wasDoingPrimary
) {
5687 s
.iterator
->move(s
.iterator
, 0, UITER_LIMIT
);
5694 if(canUpdateState
) {
5695 newState
= s
.iterator
->getState(s
.iterator
);
5696 if(newState
!= UITER_NO_STATE
) {
5697 iterState
= newState
;
5701 CE
= ucol_IGetPrevCE(coll
, &s
, status
);
5703 if(CE
==UCOL_NO_MORE_CES
) {
5704 // Add the level separator
5705 terminatePSKLevel(level
, maxLevel
, i
, dest
);
5706 byteCountOrFrenchDone
= 0;
5707 // Restart the iteration an move to the next level
5708 s
.iterator
->move(s
.iterator
, 0, UITER_START
);
5709 level
= UCOL_PSK_CASE
;
5712 if(isContinuation(CE
)) { // if it's a continuation, we want to save it and
5713 // reverse when we get a first non-continuation CE.
5715 frenchBuff
[frenchIndex
++] = (uint8_t)CE
;
5716 } else if(!isShiftedCE(CE
, LVT
, &wasShifted
)) {
5717 CE
>>= 8; /* get secondary */
5720 dest
[i
++]=(uint8_t)CE
;
5723 frenchBuff
[frenchIndex
++] = (uint8_t)CE
;
5724 frenchIndex
-= usedFrench
;
5726 while(i
< count
&& frenchIndex
) {
5727 dest
[i
++] = frenchBuff
[--frenchIndex
];
5732 if(uprv_numAvailableExpCEs(s
)) {
5733 canUpdateState
= FALSE
;
5735 canUpdateState
= TRUE
;
5740 level
= UCOL_PSK_CASE
;
5742 /* fall through to next level */
5744 if(ucol_getAttribute(coll
, UCOL_CASE_LEVEL
, status
) == UCOL_ON
) {
5745 uint32_t caseShift
= UCOL_CASE_SHIFT_START
;
5746 uint8_t caseByte
= UCOL_CASE_BYTE_START
;
5747 uint8_t caseBits
= 0;
5750 U_ASSERT(caseShift
<= UCOL_CASE_SHIFT_START
);
5754 // We should save the state only if we
5755 // are sure that we are done with the
5756 // previous iterator state
5757 if(canUpdateState
) {
5758 newState
= s
.iterator
->getState(s
.iterator
);
5759 if(newState
!= UITER_NO_STATE
) {
5760 iterState
= newState
;
5764 CE
= ucol_IGetNextCE(coll
, &s
, status
);
5766 if(CE
==UCOL_NO_MORE_CES
) {
5767 // On the case level we might have an unfinished
5768 // case byte. Add one if it's started.
5769 if(caseShift
!= UCOL_CASE_SHIFT_START
) {
5770 dest
[i
++] = caseByte
;
5773 // We have finished processing CEs on this level.
5774 // However, we don't know if we have enough space
5775 // to add a case level terminator.
5777 // Add the level separator
5778 terminatePSKLevel(level
, maxLevel
, i
, dest
);
5779 // Restart the iteration and move to the
5781 s
.iterator
->move(s
.iterator
, 0, UITER_START
);
5782 level
= UCOL_PSK_TERTIARY
;
5784 canUpdateState
= FALSE
;
5789 if(!isShiftedCE(CE
, LVT
, &wasShifted
)) {
5790 if(!isContinuation(CE
) && ((CE
& UCOL_PRIMARYMASK
) != 0 || strength
> UCOL_PRIMARY
)) {
5791 // do the case level if we need to do it. We don't want to calculate
5792 // case level for primary ignorables if we have only primary strength and case level
5793 // otherwise we would break well formedness of CEs
5794 CE
= (uint8_t)(CE
& UCOL_BYTE_SIZE_MASK
);
5795 caseBits
= (uint8_t)(CE
& 0xC0);
5796 // this copies the case level logic from the
5797 // sort key generation code
5799 if (caseShift
== 0) {
5800 dest
[i
++] = caseByte
;
5801 caseShift
= UCOL_CASE_SHIFT_START
;
5802 caseByte
= UCOL_CASE_BYTE_START
;
5804 if(coll
->caseFirst
== UCOL_UPPER_FIRST
) {
5805 if((caseBits
& 0xC0) == 0) {
5806 caseByte
|= 1 << (--caseShift
);
5808 caseByte
|= 0 << (--caseShift
);
5810 if(caseShift
== 0) {
5811 dest
[i
++] = caseByte
;
5812 caseShift
= UCOL_CASE_SHIFT_START
;
5813 caseByte
= UCOL_CASE_BYTE_START
;
5815 caseByte
|= ((caseBits
>>6)&1) << (--caseShift
);
5818 if((caseBits
& 0xC0) == 0) {
5819 caseByte
|= 0 << (--caseShift
);
5821 caseByte
|= 1 << (--caseShift
);
5823 if(caseShift
== 0) {
5824 dest
[i
++] = caseByte
;
5825 caseShift
= UCOL_CASE_SHIFT_START
;
5826 caseByte
= UCOL_CASE_BYTE_START
;
5828 caseByte
|= ((caseBits
>>7)&1) << (--caseShift
);
5835 // Not sure this is correct for the case level - revisit
5836 if(uprv_numAvailableExpCEs(s
)) {
5837 canUpdateState
= FALSE
;
5839 canUpdateState
= TRUE
;
5843 level
= UCOL_PSK_TERTIARY
;
5845 /* fall through to next level */
5846 case UCOL_PSK_TERTIARY
:
5847 if(strength
>= UCOL_TERTIARY
) {
5852 // We should save the state only if we
5853 // are sure that we are done with the
5854 // previous iterator state
5855 if(canUpdateState
) {
5856 newState
= s
.iterator
->getState(s
.iterator
);
5857 if(newState
!= UITER_NO_STATE
) {
5858 iterState
= newState
;
5862 CE
= ucol_IGetNextCE(coll
, &s
, status
);
5864 if(CE
==UCOL_NO_MORE_CES
) {
5865 // Add the level separator
5866 terminatePSKLevel(level
, maxLevel
, i
, dest
);
5867 byteCountOrFrenchDone
= 0;
5868 // Restart the iteration an move to the
5870 s
.iterator
->move(s
.iterator
, 0, UITER_START
);
5872 level
= UCOL_PSK_QUATERNARY
;
5875 if(!isShiftedCE(CE
, LVT
, &wasShifted
)) {
5876 notIsContinuation
= !isContinuation(CE
);
5878 if(notIsContinuation
) {
5879 CE
= (uint8_t)(CE
& UCOL_BYTE_SIZE_MASK
);
5880 CE
^= coll
->caseSwitch
;
5881 CE
&= coll
->tertiaryMask
;
5883 CE
= (uint8_t)((CE
& UCOL_REMOVE_CONTINUATION
));
5887 dest
[i
++]=(uint8_t)CE
;
5890 if(uprv_numAvailableExpCEs(s
)) {
5891 canUpdateState
= FALSE
;
5893 canUpdateState
= TRUE
;
5897 // if we're not doing tertiary
5899 level
= UCOL_PSK_NULL
;
5901 /* fall through to next level */
5902 case UCOL_PSK_QUATERNARY
:
5903 if(strength
>= UCOL_QUATERNARY
) {
5908 // We should save the state only if we
5909 // are sure that we are done with the
5910 // previous iterator state
5911 if(canUpdateState
) {
5912 newState
= s
.iterator
->getState(s
.iterator
);
5913 if(newState
!= UITER_NO_STATE
) {
5914 iterState
= newState
;
5918 CE
= ucol_IGetNextCE(coll
, &s
, status
);
5920 if(CE
==UCOL_NO_MORE_CES
) {
5921 // Add the level separator
5922 terminatePSKLevel(level
, maxLevel
, i
, dest
);
5923 //dest[i++] = UCOL_LEVELTERMINATOR;
5924 byteCountOrFrenchDone
= 0;
5925 // Restart the iteration an move to the
5927 s
.iterator
->move(s
.iterator
, 0, UITER_START
);
5929 level
= UCOL_PSK_QUIN
;
5934 if(isShiftedCE(CE
, LVT
, &wasShifted
)) {
5935 CE
>>= 16; /* get primary */
5937 if(byteCountOrFrenchDone
== 0) {
5938 dest
[i
++]=(uint8_t)(CE
>> 8);
5940 byteCountOrFrenchDone
= 0;
5942 if((CE
&=0xff)!=0) {
5945 byteCountOrFrenchDone
= 1;
5948 dest
[i
++]=(uint8_t)CE
;
5952 notIsContinuation
= !isContinuation(CE
);
5953 if(notIsContinuation
) {
5954 if(s
.flags
& UCOL_WAS_HIRAGANA
) { // This was Hiragana and we need to note it
5955 dest
[i
++] = UCOL_HIRAGANA_QUAD
;
5961 if(uprv_numAvailableExpCEs(s
)) {
5962 canUpdateState
= FALSE
;
5964 canUpdateState
= TRUE
;
5968 // if we're not doing quaternary
5970 level
= UCOL_PSK_NULL
;
5972 /* fall through to next level */
5974 level
= UCOL_PSK_IDENTICAL
;
5975 /* fall through to next level */
5976 case UCOL_PSK_IDENTICAL
:
5977 if(strength
>= UCOL_IDENTICAL
) {
5978 UChar32 first
, second
;
5979 int32_t bocsuBytesWritten
= 0;
5980 // We always need to do identical on
5981 // the NFD form of the string.
5982 if(normIter
== NULL
) {
5983 // we arrived from the level below and
5984 // normalization was not turned on.
5985 // therefore, we need to make a fresh NFD iterator
5986 normIter
= unorm_openIter(stackNormIter
, sizeof(stackNormIter
), status
);
5987 s
.iterator
= unorm_setIter(normIter
, iter
, UNORM_NFD
, status
);
5988 } else if(!doingIdenticalFromStart
) {
5989 // there is an iterator, but we did some other levels.
5990 // therefore, we have a FCD iterator - need to make
5992 // normIter being at the beginning does not guarantee
5993 // that the underlying iterator is at the beginning
5994 iter
->move(iter
, 0, UITER_START
);
5995 s
.iterator
= unorm_setIter(normIter
, iter
, UNORM_NFD
, status
);
5997 // At this point we have a NFD iterator that is positioned
5998 // in the right place
5999 if(U_FAILURE(*status
)) {
6000 UTRACE_EXIT_STATUS(*status
);
6003 first
= uiter_previous32(s
.iterator
);
6004 // maybe we're at the start of the string
6005 if(first
== U_SENTINEL
) {
6008 uiter_next32(s
.iterator
);
6014 if(j
+1 < bocsuBytesWritten
) {
6015 bocsuBytesUsed
= j
+1;
6020 // On identical level, we will always save
6021 // the state if we reach this point, since
6022 // we don't depend on getNextCE for content
6023 // all the content is in our buffer and we
6024 // already either stored the full buffer OR
6025 // otherwise we won't arrive here.
6026 newState
= s
.iterator
->getState(s
.iterator
);
6027 if(newState
!= UITER_NO_STATE
) {
6028 iterState
= newState
;
6033 second
= uiter_next32(s
.iterator
);
6036 // end condition for identical level
6037 if(second
== U_SENTINEL
) {
6038 terminatePSKLevel(level
, maxLevel
, i
, dest
);
6039 level
= UCOL_PSK_NULL
;
6042 bocsuBytesWritten
= u_writeIdenticalLevelRunTwoChars(first
, second
, buff
);
6046 if(bocsuBytesUsed
!= 0) {
6047 while(bocsuBytesUsed
-->0) {
6052 while(i
< count
&& j
< bocsuBytesWritten
) {
6053 dest
[i
++] = buff
[j
++];
6058 level
= UCOL_PSK_NULL
;
6060 /* fall through to next level */
6068 *status
= U_INTERNAL_PROGRAM_ERROR
;
6069 UTRACE_EXIT_STATUS(*status
);
6074 // Now we need to return stuff. First we want to see whether we have
6075 // done everything for the current state of iterator.
6076 if(byteCountOrFrenchDone
6077 || canUpdateState
== FALSE
6078 || (newState
= s
.iterator
->getState(s
.iterator
)) == UITER_NO_STATE
)
6080 // Any of above mean that the previous transaction
6081 // wasn't finished and that we should store the
6082 // previous iterator state.
6083 state
[0] = iterState
;
6085 // The transaction is complete. We will continue in the next iteration.
6086 state
[0] = s
.iterator
->getState(s
.iterator
);
6089 // Store the number of bocsu bytes written.
6090 if((bocsuBytesUsed
& UCOL_PSK_BOCSU_BYTES_MASK
) != bocsuBytesUsed
) {
6091 *status
= U_INDEX_OUTOFBOUNDS_ERROR
;
6093 state
[1] = (bocsuBytesUsed
& UCOL_PSK_BOCSU_BYTES_MASK
) << UCOL_PSK_BOCSU_BYTES_SHIFT
;
6095 // Next we put in the level of comparison
6096 state
[1] |= ((level
& UCOL_PSK_LEVEL_MASK
) << UCOL_PSK_LEVEL_SHIFT
);
6098 // If we are doing French, we need to store whether we have just finished the French level
6099 if(level
== UCOL_PSK_SECONDARY
&& doingFrench
) {
6100 state
[1] |= (((int32_t)(state
[0] == 0) & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK
) << UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT
);
6102 state
[1] |= ((byteCountOrFrenchDone
& UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK
) << UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT
);
6105 // Was the latest CE shifted
6107 state
[1] |= 1 << UCOL_PSK_WAS_SHIFTED_SHIFT
;
6109 // Check for cces overflow
6110 if((cces
& UCOL_PSK_CONSUMED_CES_MASK
) != cces
) {
6111 *status
= U_INDEX_OUTOFBOUNDS_ERROR
;
6114 state
[1] |= ((cces
& UCOL_PSK_CONSUMED_CES_MASK
) << UCOL_PSK_CONSUMED_CES_SHIFT
);
6116 // Check for French overflow
6117 if((usedFrench
& UCOL_PSK_USED_FRENCH_MASK
) != usedFrench
) {
6118 *status
= U_INDEX_OUTOFBOUNDS_ERROR
;
6120 // Store number of bytes written in the French secondary continuation sequence
6121 state
[1] |= ((usedFrench
& UCOL_PSK_USED_FRENCH_MASK
) << UCOL_PSK_USED_FRENCH_SHIFT
);
6124 // If we have used normalizing iterator, get rid of it
6125 if(normIter
!= NULL
) {
6126 unorm_closeIter(normIter
);
6129 /* To avoid memory leak, free the offset buffer if necessary. */
6130 ucol_freeOffsetBuffer(&s
);
6132 // Return number of meaningful sortkey bytes.
6133 UTRACE_DATA4(UTRACE_VERBOSE
, "dest = %vb, state=%d %d",
6134 dest
,i
, state
[0], state
[1]);
6135 UTRACE_EXIT_VALUE(i
);
6140 * Produce a bound for a given sortkey and a number of levels.
6142 U_CAPI
int32_t U_EXPORT2
6143 ucol_getBound(const uint8_t *source
,
6144 int32_t sourceLength
,
6145 UColBoundMode boundType
,
6146 uint32_t noOfLevels
,
6148 int32_t resultLength
,
6151 // consistency checks
6152 if(status
== NULL
|| U_FAILURE(*status
)) {
6155 if(source
== NULL
) {
6156 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6160 int32_t sourceIndex
= 0;
6161 // Scan the string until we skip enough of the key OR reach the end of the key
6164 if(source
[sourceIndex
] == UCOL_LEVELTERMINATOR
) {
6167 } while (noOfLevels
> 0
6168 && (source
[sourceIndex
] != 0 || sourceIndex
< sourceLength
));
6170 if((source
[sourceIndex
] == 0 || sourceIndex
== sourceLength
)
6171 && noOfLevels
> 0) {
6172 *status
= U_SORT_KEY_TOO_SHORT_WARNING
;
6176 // READ ME: this code assumes that the values for boundType
6177 // enum will not changes. They are set so that the enum value
6178 // corresponds to the number of extra bytes each bound type
6180 if(result
!= NULL
&& resultLength
>= sourceIndex
+boundType
) {
6181 uprv_memcpy(result
, source
, sourceIndex
);
6183 // Lower bound just gets terminated. No extra bytes
6184 case UCOL_BOUND_LOWER
: // = 0
6186 // Upper bound needs one extra byte
6187 case UCOL_BOUND_UPPER
: // = 1
6188 result
[sourceIndex
++] = 2;
6190 // Upper long bound needs two extra bytes
6191 case UCOL_BOUND_UPPER_LONG
: // = 2
6192 result
[sourceIndex
++] = 0xFF;
6193 result
[sourceIndex
++] = 0xFF;
6196 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6199 result
[sourceIndex
++] = 0;
6203 return sourceIndex
+boundType
+1;
6207 /****************************************************************************/
6208 /* Following are the functions that deal with the properties of a collator */
6209 /* there are new APIs and some compatibility APIs */
6210 /****************************************************************************/
6213 ucol_addLatinOneEntry(UCollator
*coll
, UChar ch
, uint32_t CE
,
6214 int32_t *primShift
, int32_t *secShift
, int32_t *terShift
)
6216 uint8_t primary1
= 0, primary2
= 0, secondary
= 0, tertiary
= 0;
6217 UBool reverseSecondary
= FALSE
;
6218 UBool continuation
= isContinuation(CE
);
6220 tertiary
= (uint8_t)((CE
& coll
->tertiaryMask
));
6221 tertiary
^= coll
->caseSwitch
;
6222 reverseSecondary
= TRUE
;
6224 tertiary
= (uint8_t)((CE
& UCOL_REMOVE_CONTINUATION
));
6225 tertiary
&= UCOL_REMOVE_CASE
;
6226 reverseSecondary
= FALSE
;
6229 secondary
= (uint8_t)((CE
>>= 8) & UCOL_BYTE_SIZE_MASK
);
6230 primary2
= (uint8_t)((CE
>>= 8) & UCOL_BYTE_SIZE_MASK
);
6231 primary1
= (uint8_t)(CE
>> 8);
6234 if (coll
->leadBytePermutationTable
!= NULL
&& !continuation
) {
6235 primary1
= coll
->leadBytePermutationTable
[primary1
];
6238 coll
->latinOneCEs
[ch
] |= (primary1
<< *primShift
);
6242 if(*primShift
< 0) {
6243 coll
->latinOneCEs
[ch
] = UCOL_BAIL_OUT_CE
;
6244 coll
->latinOneCEs
[coll
->latinOneTableLen
+ch
] = UCOL_BAIL_OUT_CE
;
6245 coll
->latinOneCEs
[2*coll
->latinOneTableLen
+ch
] = UCOL_BAIL_OUT_CE
;
6248 coll
->latinOneCEs
[ch
] |= (primary2
<< *primShift
);
6251 if(secondary
!= 0) {
6252 if(reverseSecondary
&& coll
->frenchCollation
== UCOL_ON
) { // reverse secondary
6253 coll
->latinOneCEs
[coll
->latinOneTableLen
+ch
] >>= 8; // make space for secondary
6254 coll
->latinOneCEs
[coll
->latinOneTableLen
+ch
] |= (secondary
<< 24);
6255 } else { // normal case
6256 coll
->latinOneCEs
[coll
->latinOneTableLen
+ch
] |= (secondary
<< *secShift
);
6261 coll
->latinOneCEs
[2*coll
->latinOneTableLen
+ch
] |= (tertiary
<< *terShift
);
6267 ucol_resizeLatinOneTable(UCollator
*coll
, int32_t size
, UErrorCode
*status
) {
6268 uint32_t *newTable
= (uint32_t *)uprv_malloc(size
*sizeof(uint32_t)*3);
6269 if(newTable
== NULL
) {
6270 *status
= U_MEMORY_ALLOCATION_ERROR
;
6271 coll
->latinOneFailed
= TRUE
;
6274 int32_t sizeToCopy
= ((size
<coll
->latinOneTableLen
)?size
:coll
->latinOneTableLen
)*sizeof(uint32_t);
6275 uprv_memset(newTable
, 0, size
*sizeof(uint32_t)*3);
6276 uprv_memcpy(newTable
, coll
->latinOneCEs
, sizeToCopy
);
6277 uprv_memcpy(newTable
+size
, coll
->latinOneCEs
+coll
->latinOneTableLen
, sizeToCopy
);
6278 uprv_memcpy(newTable
+2*size
, coll
->latinOneCEs
+2*coll
->latinOneTableLen
, sizeToCopy
);
6279 coll
->latinOneTableLen
= size
;
6280 uprv_free(coll
->latinOneCEs
);
6281 coll
->latinOneCEs
= newTable
;
6286 ucol_setUpLatinOne(UCollator
*coll
, UErrorCode
*status
) {
6287 UBool result
= TRUE
;
6288 if(coll
->latinOneCEs
== NULL
) {
6289 coll
->latinOneCEs
= (uint32_t *)uprv_malloc(sizeof(uint32_t)*UCOL_LATINONETABLELEN
*3);
6290 if(coll
->latinOneCEs
== NULL
) {
6291 *status
= U_MEMORY_ALLOCATION_ERROR
;
6294 coll
->latinOneTableLen
= UCOL_LATINONETABLELEN
;
6297 UCollationElements
*it
= ucol_openElements(coll
, &ch
, 1, status
);
6298 // Check for null pointer
6299 if (U_FAILURE(*status
)) {
6300 ucol_closeElements(it
);
6303 uprv_memset(coll
->latinOneCEs
, 0, sizeof(uint32_t)*coll
->latinOneTableLen
*3);
6305 int32_t primShift
= 24, secShift
= 24, terShift
= 24;
6307 int32_t contractionOffset
= UCOL_ENDOFLATINONERANGE
+1;
6309 // TODO: make safe if you get more than you wanted...
6310 for(ch
= 0; ch
<= UCOL_ENDOFLATINONERANGE
; ch
++) {
6311 primShift
= 24; secShift
= 24; terShift
= 24;
6313 CE
= coll
->latinOneMapping
[ch
];
6315 CE
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, ch
);
6316 if(CE
== UCOL_NOT_FOUND
&& coll
->UCA
) {
6317 CE
= UTRIE_GET32_FROM_LEAD(&coll
->UCA
->mapping
, ch
);
6320 if(CE
< UCOL_NOT_FOUND
) {
6321 ucol_addLatinOneEntry(coll
, ch
, CE
, &primShift
, &secShift
, &terShift
);
6323 switch (getCETag(CE
)) {
6326 ucol_setText(it
, &ch
, 1, status
);
6327 while((int32_t)(CE
= ucol_next(it
, status
)) != UCOL_NULLORDER
) {
6328 if(primShift
< 0 || secShift
< 0 || terShift
< 0) {
6329 coll
->latinOneCEs
[ch
] = UCOL_BAIL_OUT_CE
;
6330 coll
->latinOneCEs
[coll
->latinOneTableLen
+ch
] = UCOL_BAIL_OUT_CE
;
6331 coll
->latinOneCEs
[2*coll
->latinOneTableLen
+ch
] = UCOL_BAIL_OUT_CE
;
6334 ucol_addLatinOneEntry(coll
, ch
, CE
, &primShift
, &secShift
, &terShift
);
6337 case CONTRACTION_TAG
:
6338 // here is the trick
6339 // F2 is contraction. We do something very similar to contractions
6340 // but have two indices, one in the real contraction table and the
6341 // other to where we stuffed things. This hopes that we don't have
6342 // many contractions (this should work for latin-1 tables).
6344 if((CE
& 0x00FFF000) != 0) {
6345 *status
= U_UNSUPPORTED_ERROR
;
6346 goto cleanup_after_failure
;
6349 const UChar
*UCharOffset
= (UChar
*)coll
->image
+getContractOffset(CE
);
6351 CE
|= (contractionOffset
& 0xFFF) << 12; // insert the offset in latin-1 table
6353 coll
->latinOneCEs
[ch
] = CE
;
6354 coll
->latinOneCEs
[coll
->latinOneTableLen
+ch
] = CE
;
6355 coll
->latinOneCEs
[2*coll
->latinOneTableLen
+ch
] = CE
;
6357 // We're going to jump into contraction table, pick the elements
6360 CE
= *(coll
->contractionCEs
+
6361 (UCharOffset
- coll
->contractionIndex
));
6362 if(CE
> UCOL_NOT_FOUND
&& getCETag(CE
) == EXPANSION_TAG
) {
6364 uint32_t i
; /* general counter */
6365 uint32_t *CEOffset
= (uint32_t *)coll
->image
+getExpansionOffset(CE
); /* find the offset to expansion table */
6366 size
= getExpansionCount(CE
);
6368 if(size
!= 0) { /* if there are less than 16 elements in expansion, we don't terminate */
6369 for(i
= 0; i
<size
; i
++) {
6370 if(primShift
< 0 || secShift
< 0 || terShift
< 0) {
6371 coll
->latinOneCEs
[(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6372 coll
->latinOneCEs
[coll
->latinOneTableLen
+(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6373 coll
->latinOneCEs
[2*coll
->latinOneTableLen
+(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6376 ucol_addLatinOneEntry(coll
, (UChar
)contractionOffset
, *CEOffset
++, &primShift
, &secShift
, &terShift
);
6378 } else { /* else, we do */
6379 while(*CEOffset
!= 0) {
6380 if(primShift
< 0 || secShift
< 0 || terShift
< 0) {
6381 coll
->latinOneCEs
[(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6382 coll
->latinOneCEs
[coll
->latinOneTableLen
+(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6383 coll
->latinOneCEs
[2*coll
->latinOneTableLen
+(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6386 ucol_addLatinOneEntry(coll
, (UChar
)contractionOffset
, *CEOffset
++, &primShift
, &secShift
, &terShift
);
6389 contractionOffset
++;
6390 } else if(CE
< UCOL_NOT_FOUND
) {
6391 ucol_addLatinOneEntry(coll
, (UChar
)contractionOffset
++, CE
, &primShift
, &secShift
, &terShift
);
6393 coll
->latinOneCEs
[(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6394 coll
->latinOneCEs
[coll
->latinOneTableLen
+(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6395 coll
->latinOneCEs
[2*coll
->latinOneTableLen
+(UChar
)contractionOffset
] = UCOL_BAIL_OUT_CE
;
6396 contractionOffset
++;
6399 primShift
= 24; secShift
= 24; terShift
= 24;
6400 if(contractionOffset
== coll
->latinOneTableLen
) { // we need to reallocate
6401 if(!ucol_resizeLatinOneTable(coll
, 2*coll
->latinOneTableLen
, status
)) {
6402 goto cleanup_after_failure
;
6405 } while(*UCharOffset
!= 0xFFFF);
6410 // 0xB7 is a precontext character defined in UCA5.1, a special
6411 // handle is implemeted in order to save LatinOne table for
6414 ucol_addLatinOneEntry(coll
, ch
, CE
, &primShift
, &secShift
, &terShift
);
6417 goto cleanup_after_failure
;
6422 goto cleanup_after_failure
;
6427 if(contractionOffset
< coll
->latinOneTableLen
) {
6428 if(!ucol_resizeLatinOneTable(coll
, contractionOffset
, status
)) {
6429 goto cleanup_after_failure
;
6432 ucol_closeElements(it
);
6435 cleanup_after_failure
:
6436 // status should already be set before arriving here.
6437 coll
->latinOneFailed
= TRUE
;
6438 ucol_closeElements(it
);
6442 void ucol_updateInternalState(UCollator
*coll
, UErrorCode
*status
) {
6443 if(U_SUCCESS(*status
)) {
6444 if(coll
->caseFirst
== UCOL_UPPER_FIRST
) {
6445 coll
->caseSwitch
= UCOL_CASE_SWITCH
;
6447 coll
->caseSwitch
= UCOL_NO_CASE_SWITCH
;
6450 if(coll
->caseLevel
== UCOL_ON
|| coll
->caseFirst
== UCOL_OFF
) {
6451 coll
->tertiaryMask
= UCOL_REMOVE_CASE
;
6452 coll
->tertiaryCommon
= UCOL_COMMON3_NORMAL
;
6453 coll
->tertiaryAddition
= (int8_t)UCOL_FLAG_BIT_MASK_CASE_SW_OFF
; /* Should be 0x80 */
6454 coll
->tertiaryTop
= UCOL_COMMON_TOP3_CASE_SW_OFF
;
6455 coll
->tertiaryBottom
= UCOL_COMMON_BOT3
;
6457 coll
->tertiaryMask
= UCOL_KEEP_CASE
;
6458 coll
->tertiaryAddition
= UCOL_FLAG_BIT_MASK_CASE_SW_ON
;
6459 if(coll
->caseFirst
== UCOL_UPPER_FIRST
) {
6460 coll
->tertiaryCommon
= UCOL_COMMON3_UPPERFIRST
;
6461 coll
->tertiaryTop
= UCOL_COMMON_TOP3_CASE_SW_UPPER
;
6462 coll
->tertiaryBottom
= UCOL_COMMON_BOTTOM3_CASE_SW_UPPER
;
6464 coll
->tertiaryCommon
= UCOL_COMMON3_NORMAL
;
6465 coll
->tertiaryTop
= UCOL_COMMON_TOP3_CASE_SW_LOWER
;
6466 coll
->tertiaryBottom
= UCOL_COMMON_BOTTOM3_CASE_SW_LOWER
;
6470 /* Set the compression values */
6471 uint8_t tertiaryTotal
= (uint8_t)(coll
->tertiaryTop
- coll
->tertiaryBottom
- 1);
6472 coll
->tertiaryTopCount
= (uint8_t)(UCOL_PROPORTION3
*tertiaryTotal
); /* we multilply double with int, but need only int */
6473 coll
->tertiaryBottomCount
= (uint8_t)(tertiaryTotal
- coll
->tertiaryTopCount
);
6475 if(coll
->caseLevel
== UCOL_OFF
&& coll
->strength
== UCOL_TERTIARY
6476 && coll
->frenchCollation
== UCOL_OFF
&& coll
->alternateHandling
== UCOL_NON_IGNORABLE
)
6478 coll
->sortKeyGen
= ucol_calcSortKeySimpleTertiary
;
6480 coll
->sortKeyGen
= ucol_calcSortKey
;
6482 if(coll
->caseLevel
== UCOL_OFF
&& coll
->strength
<= UCOL_TERTIARY
&& coll
->numericCollation
== UCOL_OFF
6483 && coll
->alternateHandling
== UCOL_NON_IGNORABLE
&& !coll
->latinOneFailed
)
6485 if(coll
->latinOneCEs
== NULL
|| coll
->latinOneRegenTable
) {
6486 if(ucol_setUpLatinOne(coll
, status
)) { // if we succeed in building latin1 table, we'll use it
6487 //fprintf(stderr, "F");
6488 coll
->latinOneUse
= TRUE
;
6490 coll
->latinOneUse
= FALSE
;
6492 if(*status
== U_UNSUPPORTED_ERROR
) {
6493 *status
= U_ZERO_ERROR
;
6495 } else { // latin1Table exists and it doesn't need to be regenerated, just use it
6496 coll
->latinOneUse
= TRUE
;
6499 coll
->latinOneUse
= FALSE
;
6504 U_CAPI
uint32_t U_EXPORT2
6505 ucol_setVariableTop(UCollator
*coll
, const UChar
*varTop
, int32_t len
, UErrorCode
*status
) {
6506 if(U_FAILURE(*status
) || coll
== NULL
) {
6510 len
= u_strlen(varTop
);
6513 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6517 if(coll
->delegate
!=NULL
) {
6518 return ((Collator
*)coll
->delegate
)->setVariableTop(varTop
, len
, *status
);
6523 IInit_collIterate(coll
, varTop
, len
, &s
, status
);
6524 if(U_FAILURE(*status
)) {
6528 uint32_t CE
= ucol_IGetNextCE(coll
, &s
, status
);
6530 /* here we check if we have consumed all characters */
6531 /* you can put in either one character or a contraction */
6532 /* you shouldn't put more... */
6533 if(s
.pos
!= s
.endp
|| CE
== UCOL_NO_MORE_CES
) {
6534 *status
= U_CE_NOT_FOUND_ERROR
;
6538 uint32_t nextCE
= ucol_IGetNextCE(coll
, &s
, status
);
6540 if(isContinuation(nextCE
) && (nextCE
& UCOL_PRIMARYMASK
) != 0) {
6541 *status
= U_PRIMARY_TOO_LONG_ERROR
;
6544 if(coll
->variableTopValue
!= (CE
& UCOL_PRIMARYMASK
)>>16) {
6545 coll
->variableTopValueisDefault
= FALSE
;
6546 coll
->variableTopValue
= (CE
& UCOL_PRIMARYMASK
)>>16;
6549 /* To avoid memory leak, free the offset buffer if necessary. */
6550 ucol_freeOffsetBuffer(&s
);
6552 return CE
& UCOL_PRIMARYMASK
;
6555 U_CAPI
uint32_t U_EXPORT2
ucol_getVariableTop(const UCollator
*coll
, UErrorCode
*status
) {
6556 if(U_FAILURE(*status
) || coll
== NULL
) {
6559 if(coll
->delegate
!=NULL
) {
6560 return ((const Collator
*)coll
->delegate
)->getVariableTop(*status
);
6562 return coll
->variableTopValue
<<16;
6565 U_CAPI
void U_EXPORT2
6566 ucol_restoreVariableTop(UCollator
*coll
, const uint32_t varTop
, UErrorCode
*status
) {
6567 if(U_FAILURE(*status
) || coll
== NULL
) {
6571 if(coll
->variableTopValue
!= (varTop
& UCOL_PRIMARYMASK
)>>16) {
6572 coll
->variableTopValueisDefault
= FALSE
;
6573 coll
->variableTopValue
= (varTop
& UCOL_PRIMARYMASK
)>>16;
6576 /* Attribute setter API */
6577 U_CAPI
void U_EXPORT2
6578 ucol_setAttribute(UCollator
*coll
, UColAttribute attr
, UColAttributeValue value
, UErrorCode
*status
) {
6579 if(U_FAILURE(*status
) || coll
== NULL
) {
6583 if(coll
->delegate
!= NULL
) {
6584 ((Collator
*)coll
->delegate
)->setAttribute(attr
,value
,*status
);
6588 UColAttributeValue oldFrench
= coll
->frenchCollation
;
6589 UColAttributeValue oldCaseFirst
= coll
->caseFirst
;
6591 case UCOL_NUMERIC_COLLATION
: /* sort substrings of digits as numbers */
6592 if(value
== UCOL_ON
) {
6593 coll
->numericCollation
= UCOL_ON
;
6594 coll
->numericCollationisDefault
= FALSE
;
6595 } else if (value
== UCOL_OFF
) {
6596 coll
->numericCollation
= UCOL_OFF
;
6597 coll
->numericCollationisDefault
= FALSE
;
6598 } else if (value
== UCOL_DEFAULT
) {
6599 coll
->numericCollationisDefault
= TRUE
;
6600 coll
->numericCollation
= (UColAttributeValue
)coll
->options
->numericCollation
;
6602 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6605 case UCOL_HIRAGANA_QUATERNARY_MODE
: /* special quaternary values for Hiragana */
6606 if(value
== UCOL_ON
|| value
== UCOL_OFF
|| value
== UCOL_DEFAULT
) {
6607 // This attribute is an implementation detail of the CLDR Japanese tailoring.
6608 // The implementation might change to use a different mechanism
6609 // to achieve the same Japanese sort order.
6610 // Since ICU 50, this attribute is not settable any more via API functions.
6612 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6615 case UCOL_FRENCH_COLLATION
: /* attribute for direction of secondary weights*/
6616 if(value
== UCOL_ON
) {
6617 coll
->frenchCollation
= UCOL_ON
;
6618 coll
->frenchCollationisDefault
= FALSE
;
6619 } else if (value
== UCOL_OFF
) {
6620 coll
->frenchCollation
= UCOL_OFF
;
6621 coll
->frenchCollationisDefault
= FALSE
;
6622 } else if (value
== UCOL_DEFAULT
) {
6623 coll
->frenchCollationisDefault
= TRUE
;
6624 coll
->frenchCollation
= (UColAttributeValue
)coll
->options
->frenchCollation
;
6626 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6629 case UCOL_ALTERNATE_HANDLING
: /* attribute for handling variable elements*/
6630 if(value
== UCOL_SHIFTED
) {
6631 coll
->alternateHandling
= UCOL_SHIFTED
;
6632 coll
->alternateHandlingisDefault
= FALSE
;
6633 } else if (value
== UCOL_NON_IGNORABLE
) {
6634 coll
->alternateHandling
= UCOL_NON_IGNORABLE
;
6635 coll
->alternateHandlingisDefault
= FALSE
;
6636 } else if (value
== UCOL_DEFAULT
) {
6637 coll
->alternateHandlingisDefault
= TRUE
;
6638 coll
->alternateHandling
= (UColAttributeValue
)coll
->options
->alternateHandling
;
6640 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6643 case UCOL_CASE_FIRST
: /* who goes first, lower case or uppercase */
6644 if(value
== UCOL_LOWER_FIRST
) {
6645 coll
->caseFirst
= UCOL_LOWER_FIRST
;
6646 coll
->caseFirstisDefault
= FALSE
;
6647 } else if (value
== UCOL_UPPER_FIRST
) {
6648 coll
->caseFirst
= UCOL_UPPER_FIRST
;
6649 coll
->caseFirstisDefault
= FALSE
;
6650 } else if (value
== UCOL_OFF
) {
6651 coll
->caseFirst
= UCOL_OFF
;
6652 coll
->caseFirstisDefault
= FALSE
;
6653 } else if (value
== UCOL_DEFAULT
) {
6654 coll
->caseFirst
= (UColAttributeValue
)coll
->options
->caseFirst
;
6655 coll
->caseFirstisDefault
= TRUE
;
6657 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6660 case UCOL_CASE_LEVEL
: /* do we have an extra case level */
6661 if(value
== UCOL_ON
) {
6662 coll
->caseLevel
= UCOL_ON
;
6663 coll
->caseLevelisDefault
= FALSE
;
6664 } else if (value
== UCOL_OFF
) {
6665 coll
->caseLevel
= UCOL_OFF
;
6666 coll
->caseLevelisDefault
= FALSE
;
6667 } else if (value
== UCOL_DEFAULT
) {
6668 coll
->caseLevel
= (UColAttributeValue
)coll
->options
->caseLevel
;
6669 coll
->caseLevelisDefault
= TRUE
;
6671 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6674 case UCOL_NORMALIZATION_MODE
: /* attribute for normalization */
6675 if(value
== UCOL_ON
) {
6676 coll
->normalizationMode
= UCOL_ON
;
6677 coll
->normalizationModeisDefault
= FALSE
;
6678 initializeFCD(status
);
6679 } else if (value
== UCOL_OFF
) {
6680 coll
->normalizationMode
= UCOL_OFF
;
6681 coll
->normalizationModeisDefault
= FALSE
;
6682 } else if (value
== UCOL_DEFAULT
) {
6683 coll
->normalizationModeisDefault
= TRUE
;
6684 coll
->normalizationMode
= (UColAttributeValue
)coll
->options
->normalizationMode
;
6685 if(coll
->normalizationMode
== UCOL_ON
) {
6686 initializeFCD(status
);
6689 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6692 case UCOL_STRENGTH
: /* attribute for strength */
6693 if (value
== UCOL_DEFAULT
) {
6694 coll
->strengthisDefault
= TRUE
;
6695 coll
->strength
= (UColAttributeValue
)coll
->options
->strength
;
6696 } else if (value
<= UCOL_IDENTICAL
) {
6697 coll
->strengthisDefault
= FALSE
;
6698 coll
->strength
= value
;
6700 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6703 case UCOL_ATTRIBUTE_COUNT
:
6705 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6708 if(oldFrench
!= coll
->frenchCollation
|| oldCaseFirst
!= coll
->caseFirst
) {
6709 coll
->latinOneRegenTable
= TRUE
;
6711 coll
->latinOneRegenTable
= FALSE
;
6713 ucol_updateInternalState(coll
, status
);
6716 U_CAPI UColAttributeValue U_EXPORT2
6717 ucol_getAttribute(const UCollator
*coll
, UColAttribute attr
, UErrorCode
*status
) {
6718 if(U_FAILURE(*status
) || coll
== NULL
) {
6719 return UCOL_DEFAULT
;
6722 if(coll
->delegate
!= NULL
) {
6723 return ((Collator
*)coll
->delegate
)->getAttribute(attr
,*status
);
6727 case UCOL_NUMERIC_COLLATION
:
6728 return coll
->numericCollation
;
6729 case UCOL_HIRAGANA_QUATERNARY_MODE
:
6730 return coll
->hiraganaQ
;
6731 case UCOL_FRENCH_COLLATION
: /* attribute for direction of secondary weights*/
6732 return coll
->frenchCollation
;
6733 case UCOL_ALTERNATE_HANDLING
: /* attribute for handling variable elements*/
6734 return coll
->alternateHandling
;
6735 case UCOL_CASE_FIRST
: /* who goes first, lower case or uppercase */
6736 return coll
->caseFirst
;
6737 case UCOL_CASE_LEVEL
: /* do we have an extra case level */
6738 return coll
->caseLevel
;
6739 case UCOL_NORMALIZATION_MODE
: /* attribute for normalization */
6740 return coll
->normalizationMode
;
6741 case UCOL_STRENGTH
: /* attribute for strength */
6742 return coll
->strength
;
6743 case UCOL_ATTRIBUTE_COUNT
:
6745 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6748 return UCOL_DEFAULT
;
6751 U_CAPI
void U_EXPORT2
6752 ucol_setStrength( UCollator
*coll
,
6753 UCollationStrength strength
)
6755 UErrorCode status
= U_ZERO_ERROR
;
6756 ucol_setAttribute(coll
, UCOL_STRENGTH
, strength
, &status
);
6759 U_CAPI UCollationStrength U_EXPORT2
6760 ucol_getStrength(const UCollator
*coll
)
6762 UErrorCode status
= U_ZERO_ERROR
;
6763 return ucol_getAttribute(coll
, UCOL_STRENGTH
, &status
);
6766 U_CAPI
int32_t U_EXPORT2
6767 ucol_getReorderCodes(const UCollator
*coll
,
6769 int32_t destCapacity
,
6770 UErrorCode
*status
) {
6771 if (U_FAILURE(*status
)) {
6775 if(coll
->delegate
!=NULL
) {
6776 return ((const Collator
*)coll
->delegate
)->getReorderCodes(dest
, destCapacity
, *status
);
6779 if (destCapacity
< 0 || (destCapacity
> 0 && dest
== NULL
)) {
6780 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6785 printf("coll->reorderCodesLength = %d\n", coll
->reorderCodesLength
);
6786 printf("coll->defaultReorderCodesLength = %d\n", coll
->defaultReorderCodesLength
);
6789 if (coll
->reorderCodesLength
> destCapacity
) {
6790 *status
= U_BUFFER_OVERFLOW_ERROR
;
6791 return coll
->reorderCodesLength
;
6793 for (int32_t i
= 0; i
< coll
->reorderCodesLength
; i
++) {
6794 dest
[i
] = coll
->reorderCodes
[i
];
6796 return coll
->reorderCodesLength
;
6799 U_CAPI
void U_EXPORT2
6800 ucol_setReorderCodes(UCollator
* coll
,
6801 const int32_t* reorderCodes
,
6802 int32_t reorderCodesLength
,
6803 UErrorCode
*status
) {
6804 if (U_FAILURE(*status
)) {
6808 if (reorderCodesLength
< 0 || (reorderCodesLength
> 0 && reorderCodes
== NULL
)) {
6809 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
6813 if(coll
->delegate
!=NULL
) {
6814 ((Collator
*)coll
->delegate
)->setReorderCodes(reorderCodes
, reorderCodesLength
, *status
);
6818 if (coll
->reorderCodes
!= NULL
&& coll
->freeReorderCodesOnClose
== TRUE
) {
6819 uprv_free(coll
->reorderCodes
);
6821 coll
->reorderCodes
= NULL
;
6822 coll
->reorderCodesLength
= 0;
6823 if (reorderCodesLength
== 0) {
6824 if (coll
->leadBytePermutationTable
!= NULL
&& coll
->freeLeadBytePermutationTableOnClose
== TRUE
) {
6825 uprv_free(coll
->leadBytePermutationTable
);
6827 coll
->leadBytePermutationTable
= NULL
;
6830 coll
->reorderCodes
= (int32_t*) uprv_malloc(reorderCodesLength
* sizeof(int32_t));
6831 if (coll
->reorderCodes
== NULL
) {
6832 *status
= U_MEMORY_ALLOCATION_ERROR
;
6835 coll
->freeReorderCodesOnClose
= TRUE
;
6836 for (int32_t i
= 0; i
< reorderCodesLength
; i
++) {
6837 coll
->reorderCodes
[i
] = reorderCodes
[i
];
6839 coll
->reorderCodesLength
= reorderCodesLength
;
6840 ucol_buildPermutationTable(coll
, status
);
6843 U_CAPI
int32_t U_EXPORT2
6844 ucol_getEquivalentReorderCodes(int32_t reorderCode
,
6846 int32_t destCapacity
,
6847 UErrorCode
*pErrorCode
) {
6848 bool equivalentCodesSet
[USCRIPT_CODE_LIMIT
];
6849 uint16_t leadBytes
[256];
6852 int16_t reorderCodesForLeadByte
[USCRIPT_CODE_LIMIT
];
6853 int reorderCodesForLeadByteCount
;
6854 int reorderCodeIndex
;
6856 int32_t equivalentCodesCount
= 0;
6859 if (U_FAILURE(*pErrorCode
)) {
6863 if (destCapacity
< 0 || (destCapacity
> 0 && dest
== NULL
)) {
6864 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
6868 uprv_memset(equivalentCodesSet
, 0, USCRIPT_CODE_LIMIT
* sizeof(bool));
6870 const UCollator
* uca
= ucol_initUCA(pErrorCode
);
6871 if (U_FAILURE(*pErrorCode
)) {
6874 leadBytesCount
= ucol_getLeadBytesForReorderCode(uca
, reorderCode
, leadBytes
, 256);
6875 for (leadByteIndex
= 0; leadByteIndex
< leadBytesCount
; leadByteIndex
++) {
6876 reorderCodesForLeadByteCount
= ucol_getReorderCodesForLeadByte(
6877 uca
, leadBytes
[leadByteIndex
], reorderCodesForLeadByte
, USCRIPT_CODE_LIMIT
);
6878 for (reorderCodeIndex
= 0; reorderCodeIndex
< reorderCodesForLeadByteCount
; reorderCodeIndex
++) {
6879 equivalentCodesSet
[reorderCodesForLeadByte
[reorderCodeIndex
]] = true;
6883 for (setIndex
= 0; setIndex
< USCRIPT_CODE_LIMIT
; setIndex
++) {
6884 if (equivalentCodesSet
[setIndex
] == true) {
6885 equivalentCodesCount
++;
6889 if (destCapacity
== 0) {
6890 return equivalentCodesCount
;
6893 equivalentCodesCount
= 0;
6894 for (setIndex
= 0; setIndex
< USCRIPT_CODE_LIMIT
; setIndex
++) {
6895 if (equivalentCodesSet
[setIndex
] == true) {
6896 dest
[equivalentCodesCount
++] = setIndex
;
6897 if (equivalentCodesCount
>= destCapacity
) {
6902 return equivalentCodesCount
;
6906 /****************************************************************************/
6907 /* Following are misc functions */
6908 /* there are new APIs and some compatibility APIs */
6909 /****************************************************************************/
6911 U_CAPI
void U_EXPORT2
6912 ucol_getVersion(const UCollator
* coll
,
6913 UVersionInfo versionInfo
)
6915 if(coll
->delegate
!=NULL
) {
6916 ((const Collator
*)coll
->delegate
)->getVersion(versionInfo
);
6919 /* RunTime version */
6920 uint8_t rtVersion
= UCOL_RUNTIME_VERSION
;
6921 /* Builder version*/
6922 uint8_t bdVersion
= coll
->image
->version
[0];
6924 /* Charset Version. Need to get the version from cnv files
6925 * makeconv should populate cnv files with version and
6926 * an api has to be provided in ucnv.h to obtain this version
6928 uint8_t csVersion
= 0;
6930 /* combine the version info */
6931 uint16_t cmbVersion
= (uint16_t)((rtVersion
<<11) | (bdVersion
<<6) | (csVersion
));
6933 /* Tailoring rules */
6934 versionInfo
[0] = (uint8_t)(cmbVersion
>>8);
6935 versionInfo
[1] = (uint8_t)cmbVersion
;
6936 versionInfo
[2] = coll
->image
->version
[1];
6938 /* Include the minor number when getting the UCA version. (major & 1f) << 3 | (minor & 7) */
6939 versionInfo
[3] = (coll
->UCA
->image
->UCAVersion
[0] & 0x1f) << 3 | (coll
->UCA
->image
->UCAVersion
[1] & 0x07);
6946 /* This internal API checks whether a character is tailored or not */
6947 U_CAPI UBool U_EXPORT2
6948 ucol_isTailored(const UCollator
*coll
, const UChar u
, UErrorCode
*status
) {
6949 if(U_FAILURE(*status
) || coll
== NULL
|| coll
== coll
->UCA
) {
6953 uint32_t CE
= UCOL_NOT_FOUND
;
6954 const UChar
*ContractionStart
= NULL
;
6955 if(u
< 0x100) { /* latin-1 */
6956 CE
= coll
->latinOneMapping
[u
];
6957 if(coll
->UCA
&& CE
== coll
->UCA
->latinOneMapping
[u
]) {
6960 } else { /* regular */
6961 CE
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, u
);
6964 if(isContraction(CE
)) {
6965 ContractionStart
= (UChar
*)coll
->image
+getContractOffset(CE
);
6966 CE
= *(coll
->contractionCEs
+ (ContractionStart
- coll
->contractionIndex
));
6969 return (UBool
)(CE
!= UCOL_NOT_FOUND
);
6973 /****************************************************************************/
6974 /* Following are the string compare functions */
6976 /****************************************************************************/
6979 /* ucol_checkIdent internal function. Does byte level string compare. */
6980 /* Used by strcoll if strength == identical and strings */
6981 /* are otherwise equal. */
6983 /* Comparison must be done on NFD normalized strings. */
6984 /* FCD is not good enough. */
6987 UCollationResult
ucol_checkIdent(collIterate
*sColl
, collIterate
*tColl
, UBool normalize
, UErrorCode
*status
)
6989 // When we arrive here, we can have normal strings or UCharIterators. Currently they are both
6990 // of same type, but that doesn't really mean that it will stay that way.
6993 if (sColl
->flags
& UCOL_USE_ITERATOR
) {
6994 // The division for the array length may truncate the array size to
6995 // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
6996 // for all platforms anyway.
6997 UAlignedMemory stackNormIter1
[UNORM_ITER_SIZE
/sizeof(UAlignedMemory
)];
6998 UAlignedMemory stackNormIter2
[UNORM_ITER_SIZE
/sizeof(UAlignedMemory
)];
6999 UNormIterator
*sNIt
= NULL
, *tNIt
= NULL
;
7000 sNIt
= unorm_openIter(stackNormIter1
, sizeof(stackNormIter1
), status
);
7001 tNIt
= unorm_openIter(stackNormIter2
, sizeof(stackNormIter2
), status
);
7002 sColl
->iterator
->move(sColl
->iterator
, 0, UITER_START
);
7003 tColl
->iterator
->move(tColl
->iterator
, 0, UITER_START
);
7004 UCharIterator
*sIt
= unorm_setIter(sNIt
, sColl
->iterator
, UNORM_NFD
, status
);
7005 UCharIterator
*tIt
= unorm_setIter(tNIt
, tColl
->iterator
, UNORM_NFD
, status
);
7006 comparison
= u_strCompareIter(sIt
, tIt
, TRUE
);
7007 unorm_closeIter(sNIt
);
7008 unorm_closeIter(tNIt
);
7010 int32_t sLen
= (sColl
->flags
& UCOL_ITER_HASLEN
) ? (int32_t)(sColl
->endp
- sColl
->string
) : -1;
7011 const UChar
*sBuf
= sColl
->string
;
7012 int32_t tLen
= (tColl
->flags
& UCOL_ITER_HASLEN
) ? (int32_t)(tColl
->endp
- tColl
->string
) : -1;
7013 const UChar
*tBuf
= tColl
->string
;
7016 *status
= U_ZERO_ERROR
;
7017 // Note: We could use Normalizer::compare() or similar, but for short strings
7018 // which may not be in FCD it might be faster to just NFD them.
7019 // Note: spanQuickCheckYes() + normalizeSecondAndAppend() rather than
7020 // NFD'ing immediately might be faster for long strings,
7021 // but string comparison is usually done on relatively short strings.
7022 sColl
->nfd
->normalize(UnicodeString((sColl
->flags
& UCOL_ITER_HASLEN
) == 0, sBuf
, sLen
),
7023 sColl
->writableBuffer
,
7025 tColl
->nfd
->normalize(UnicodeString((tColl
->flags
& UCOL_ITER_HASLEN
) == 0, tBuf
, tLen
),
7026 tColl
->writableBuffer
,
7028 if(U_FAILURE(*status
)) {
7031 comparison
= sColl
->writableBuffer
.compareCodePointOrder(tColl
->writableBuffer
);
7033 comparison
= u_strCompare(sBuf
, sLen
, tBuf
, tLen
, TRUE
);
7037 if (comparison
< 0) {
7039 } else if (comparison
== 0) {
7041 } else /* comparison > 0 */ {
7042 return UCOL_GREATER
;
7046 /* CEBuf - A struct and some inline functions to handle the saving */
7047 /* of CEs in a buffer within ucol_strcoll */
7049 #define UCOL_CEBUF_SIZE 512
7050 typedef struct ucol_CEBuf
{
7054 uint32_t localArray
[UCOL_CEBUF_SIZE
];
7059 inline void UCOL_INIT_CEBUF(ucol_CEBuf
*b
) {
7060 (b
)->buf
= (b
)->pos
= (b
)->localArray
;
7061 (b
)->endp
= (b
)->buf
+ UCOL_CEBUF_SIZE
;
7065 void ucol_CEBuf_Expand(ucol_CEBuf
*b
, collIterate
*ci
, UErrorCode
*status
) {
7070 ci
->flags
|= UCOL_ITER_ALLOCATED
;
7071 oldSize
= (uint32_t)(b
->pos
- b
->buf
);
7072 newSize
= oldSize
* 2;
7073 newBuf
= (uint32_t *)uprv_malloc(newSize
* sizeof(uint32_t));
7074 if(newBuf
== NULL
) {
7075 *status
= U_MEMORY_ALLOCATION_ERROR
;
7078 uprv_memcpy(newBuf
, b
->buf
, oldSize
* sizeof(uint32_t));
7079 if (b
->buf
!= b
->localArray
) {
7083 b
->endp
= b
->buf
+ newSize
;
7084 b
->pos
= b
->buf
+ oldSize
;
7089 inline void UCOL_CEBUF_PUT(ucol_CEBuf
*b
, uint32_t ce
, collIterate
*ci
, UErrorCode
*status
) {
7090 if (b
->pos
== b
->endp
) {
7091 ucol_CEBuf_Expand(b
, ci
, status
);
7093 if (U_SUCCESS(*status
)) {
7098 /* This is a trick string compare function that goes in and uses sortkeys to compare */
7099 /* It is used when compare gets in trouble and needs to bail out */
7100 static UCollationResult
ucol_compareUsingSortKeys(collIterate
*sColl
,
7104 uint8_t sourceKey
[UCOL_MAX_BUFFER
], targetKey
[UCOL_MAX_BUFFER
];
7105 uint8_t *sourceKeyP
= sourceKey
;
7106 uint8_t *targetKeyP
= targetKey
;
7107 int32_t sourceKeyLen
= UCOL_MAX_BUFFER
, targetKeyLen
= UCOL_MAX_BUFFER
;
7108 const UCollator
*coll
= sColl
->coll
;
7109 const UChar
*source
= NULL
;
7110 const UChar
*target
= NULL
;
7111 int32_t result
= UCOL_EQUAL
;
7112 UnicodeString sourceString
, targetString
;
7113 int32_t sourceLength
;
7114 int32_t targetLength
;
7116 if(sColl
->flags
& UCOL_USE_ITERATOR
) {
7117 sColl
->iterator
->move(sColl
->iterator
, 0, UITER_START
);
7118 tColl
->iterator
->move(tColl
->iterator
, 0, UITER_START
);
7120 while((c
=sColl
->iterator
->next(sColl
->iterator
))>=0) {
7121 sourceString
.append((UChar
)c
);
7123 while((c
=tColl
->iterator
->next(tColl
->iterator
))>=0) {
7124 targetString
.append((UChar
)c
);
7126 source
= sourceString
.getBuffer();
7127 sourceLength
= sourceString
.length();
7128 target
= targetString
.getBuffer();
7129 targetLength
= targetString
.length();
7130 } else { // no iterators
7131 sourceLength
= (sColl
->flags
&UCOL_ITER_HASLEN
)?(int32_t)(sColl
->endp
-sColl
->string
):-1;
7132 targetLength
= (tColl
->flags
&UCOL_ITER_HASLEN
)?(int32_t)(tColl
->endp
-tColl
->string
):-1;
7133 source
= sColl
->string
;
7134 target
= tColl
->string
;
7139 sourceKeyLen
= ucol_getSortKey(coll
, source
, sourceLength
, sourceKeyP
, sourceKeyLen
);
7140 if(sourceKeyLen
> UCOL_MAX_BUFFER
) {
7141 sourceKeyP
= (uint8_t*)uprv_malloc(sourceKeyLen
*sizeof(uint8_t));
7142 if(sourceKeyP
== NULL
) {
7143 *status
= U_MEMORY_ALLOCATION_ERROR
;
7144 goto cleanup_and_do_compare
;
7146 sourceKeyLen
= ucol_getSortKey(coll
, source
, sourceLength
, sourceKeyP
, sourceKeyLen
);
7149 targetKeyLen
= ucol_getSortKey(coll
, target
, targetLength
, targetKeyP
, targetKeyLen
);
7150 if(targetKeyLen
> UCOL_MAX_BUFFER
) {
7151 targetKeyP
= (uint8_t*)uprv_malloc(targetKeyLen
*sizeof(uint8_t));
7152 if(targetKeyP
== NULL
) {
7153 *status
= U_MEMORY_ALLOCATION_ERROR
;
7154 goto cleanup_and_do_compare
;
7156 targetKeyLen
= ucol_getSortKey(coll
, target
, targetLength
, targetKeyP
, targetKeyLen
);
7159 result
= uprv_strcmp((const char*)sourceKeyP
, (const char*)targetKeyP
);
7161 cleanup_and_do_compare
:
7162 if(sourceKeyP
!= NULL
&& sourceKeyP
!= sourceKey
) {
7163 uprv_free(sourceKeyP
);
7166 if(targetKeyP
!= NULL
&& targetKeyP
!= targetKey
) {
7167 uprv_free(targetKeyP
);
7172 } else if(result
>0) {
7173 return UCOL_GREATER
;
7180 static UCollationResult
7181 ucol_strcollRegular(collIterate
*sColl
, collIterate
*tColl
, UErrorCode
*status
)
7185 const UCollator
*coll
= sColl
->coll
;
7188 // setting up the collator parameters
7189 UColAttributeValue strength
= coll
->strength
;
7190 UBool initialCheckSecTer
= (strength
>= UCOL_SECONDARY
);
7192 UBool checkSecTer
= initialCheckSecTer
;
7193 UBool checkTertiary
= (strength
>= UCOL_TERTIARY
);
7194 UBool checkQuad
= (strength
>= UCOL_QUATERNARY
);
7195 UBool checkIdent
= (strength
== UCOL_IDENTICAL
);
7196 UBool checkCase
= (coll
->caseLevel
== UCOL_ON
);
7197 UBool isFrenchSec
= (coll
->frenchCollation
== UCOL_ON
) && checkSecTer
;
7198 UBool shifted
= (coll
->alternateHandling
== UCOL_SHIFTED
);
7199 UBool qShifted
= shifted
&& checkQuad
;
7200 UBool doHiragana
= (coll
->hiraganaQ
== UCOL_ON
) && checkQuad
;
7202 if(doHiragana
&& shifted
) {
7203 return (ucol_compareUsingSortKeys(sColl
, tColl
, status
));
7205 uint8_t caseSwitch
= coll
->caseSwitch
;
7206 uint8_t tertiaryMask
= coll
->tertiaryMask
;
7208 // This is the lowest primary value that will not be ignored if shifted
7209 uint32_t LVT
= (shifted
)?(coll
->variableTopValue
<<16):0;
7211 UCollationResult result
= UCOL_EQUAL
;
7212 UCollationResult hirResult
= UCOL_EQUAL
;
7214 // Preparing the CE buffers. They will be filled during the primary phase
7217 UCOL_INIT_CEBUF(&sCEs
);
7218 UCOL_INIT_CEBUF(&tCEs
);
7220 uint32_t secS
= 0, secT
= 0;
7221 uint32_t sOrder
=0, tOrder
=0;
7223 // Non shifted primary processing is quite simple
7227 // We fetch CEs until we hit a non ignorable primary or end.
7229 // We get the next CE
7230 sOrder
= ucol_IGetNextCE(coll
, sColl
, status
);
7231 // Stuff it in the buffer
7232 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7233 // And keep just the primary part.
7234 sOrder
&= UCOL_PRIMARYMASK
;
7235 } while(sOrder
== 0);
7237 // see the comments on the above block
7239 tOrder
= ucol_IGetNextCE(coll
, tColl
, status
);
7240 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7241 tOrder
&= UCOL_PRIMARYMASK
;
7242 } while(tOrder
== 0);
7244 // if both primaries are the same
7245 if(sOrder
== tOrder
) {
7246 // and there are no more CEs, we advance to the next level
7247 if(sOrder
== UCOL_NO_MORE_CES_PRIMARY
) {
7250 if(doHiragana
&& hirResult
== UCOL_EQUAL
) {
7251 if((sColl
->flags
& UCOL_WAS_HIRAGANA
) != (tColl
->flags
& UCOL_WAS_HIRAGANA
)) {
7252 hirResult
= ((sColl
->flags
& UCOL_WAS_HIRAGANA
) > (tColl
->flags
& UCOL_WAS_HIRAGANA
))
7253 ? UCOL_LESS
:UCOL_GREATER
;
7257 // only need to check one for continuation
7258 // if one is then the other must be or the preceding CE would be a prefix of the other
7259 if (coll
->leadBytePermutationTable
!= NULL
&& !isContinuation(sOrder
)) {
7260 sOrder
= (coll
->leadBytePermutationTable
[sOrder
>>24] << 24) | (sOrder
& 0x00FFFFFF);
7261 tOrder
= (coll
->leadBytePermutationTable
[tOrder
>>24] << 24) | (tOrder
& 0x00FFFFFF);
7263 // if two primaries are different, we are done
7264 result
= (sOrder
< tOrder
) ? UCOL_LESS
: UCOL_GREATER
;
7267 } // no primary difference... do the rest from the buffers
7268 } else { // shifted - do a slightly more complicated processing :)
7270 UBool sInShifted
= FALSE
;
7271 UBool tInShifted
= FALSE
;
7272 // This version of code can be refactored. However, it seems easier to understand this way.
7273 // Source loop. Sam as the target loop.
7275 sOrder
= ucol_IGetNextCE(coll
, sColl
, status
);
7276 if(sOrder
== UCOL_NO_MORE_CES
) {
7277 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7279 } else if(sOrder
== 0 || (sInShifted
&& (sOrder
& UCOL_PRIMARYMASK
) == 0)) {
7280 /* UCA amendment - ignore ignorables that follow shifted code points */
7282 } else if(isContinuation(sOrder
)) {
7283 if((sOrder
& UCOL_PRIMARYMASK
) > 0) { /* There is primary value */
7285 sOrder
= (sOrder
& UCOL_PRIMARYMASK
) | 0xC0; /* preserve interesting continuation */
7286 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7289 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7292 } else { /* Just lower level values */
7296 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7300 } else { /* regular */
7301 if(coll
->leadBytePermutationTable
!= NULL
){
7302 sOrder
= (coll
->leadBytePermutationTable
[sOrder
>>24] << 24) | (sOrder
& 0x00FFFFFF);
7304 if((sOrder
& UCOL_PRIMARYMASK
) > LVT
) {
7305 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7308 if((sOrder
& UCOL_PRIMARYMASK
) > 0) {
7310 sOrder
&= UCOL_PRIMARYMASK
;
7311 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7314 UCOL_CEBUF_PUT(&sCEs
, sOrder
, sColl
, status
);
7321 sOrder
&= UCOL_PRIMARYMASK
;
7325 tOrder
= ucol_IGetNextCE(coll
, tColl
, status
);
7326 if(tOrder
== UCOL_NO_MORE_CES
) {
7327 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7329 } else if(tOrder
== 0 || (tInShifted
&& (tOrder
& UCOL_PRIMARYMASK
) == 0)) {
7330 /* UCA amendment - ignore ignorables that follow shifted code points */
7332 } else if(isContinuation(tOrder
)) {
7333 if((tOrder
& UCOL_PRIMARYMASK
) > 0) { /* There is primary value */
7335 tOrder
= (tOrder
& UCOL_PRIMARYMASK
) | 0xC0; /* preserve interesting continuation */
7336 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7339 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7342 } else { /* Just lower level values */
7346 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7350 } else { /* regular */
7351 if(coll
->leadBytePermutationTable
!= NULL
){
7352 tOrder
= (coll
->leadBytePermutationTable
[tOrder
>>24] << 24) | (tOrder
& 0x00FFFFFF);
7354 if((tOrder
& UCOL_PRIMARYMASK
) > LVT
) {
7355 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7358 if((tOrder
& UCOL_PRIMARYMASK
) > 0) {
7360 tOrder
&= UCOL_PRIMARYMASK
;
7361 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7364 UCOL_CEBUF_PUT(&tCEs
, tOrder
, tColl
, status
);
7371 tOrder
&= UCOL_PRIMARYMASK
;
7374 if(sOrder
== tOrder
) {
7376 if(doHiragana && hirResult == UCOL_EQUAL) {
7377 if((sColl.flags & UCOL_WAS_HIRAGANA) != (tColl.flags & UCOL_WAS_HIRAGANA)) {
7378 hirResult = ((sColl.flags & UCOL_WAS_HIRAGANA) > (tColl.flags & UCOL_WAS_HIRAGANA))
7379 ? UCOL_LESS:UCOL_GREATER;
7383 if(sOrder
== UCOL_NO_MORE_CES_PRIMARY
) {
7391 result
= (sOrder
< tOrder
) ? UCOL_LESS
: UCOL_GREATER
;
7394 } /* no primary difference... do the rest from the buffers */
7397 /* now, we're gonna reexamine collected CEs */
7401 /* This is the secondary level of comparison */
7403 if(!isFrenchSec
) { /* normal */
7408 secS
= *(sCE
++) & UCOL_SECONDARYMASK
;
7412 secT
= *(tCE
++) & UCOL_SECONDARYMASK
;
7416 if(secS
== UCOL_NO_MORE_CES_SECONDARY
) {
7423 result
= (secS
< secT
) ? UCOL_LESS
: UCOL_GREATER
;
7427 } else { /* do the French */
7428 uint32_t *sCESave
= NULL
;
7429 uint32_t *tCESave
= NULL
;
7430 sCE
= sCEs
.pos
-2; /* this could also be sCEs-- if needs to be optimized */
7433 while (secS
== 0 && sCE
>= sCEs
.buf
) {
7434 if(sCESave
== NULL
) {
7436 if(isContinuation(secS
)) {
7437 while(isContinuation(secS
= *(sCE
--)))
7439 /* after this, secS has the start of continuation, and sCEs points before that */
7440 sCESave
= sCE
; /* we save it, so that we know where to come back AND that we need to go forward */
7441 sCE
+=2; /* need to point to the first continuation CP */
7442 /* However, now you can just continue doing stuff */
7446 if(!isContinuation(secS
)) { /* This means we have finished with this cont */
7447 sCE
= sCESave
; /* reset the pointer to before continuation */
7449 secS
= 0; /* Fetch a fresh CE before the continuation sequence. */
7453 secS
&= UCOL_SECONDARYMASK
; /* remove the continuation bit */
7456 while(secT
== 0 && tCE
>= tCEs
.buf
) {
7457 if(tCESave
== NULL
) {
7459 if(isContinuation(secT
)) {
7460 while(isContinuation(secT
= *(tCE
--)))
7462 /* after this, secS has the start of continuation, and sCEs points before that */
7463 tCESave
= tCE
; /* we save it, so that we know where to come back AND that we need to go forward */
7464 tCE
+=2; /* need to point to the first continuation CP */
7465 /* However, now you can just continue doing stuff */
7469 if(!isContinuation(secT
)) { /* This means we have finished with this cont */
7470 tCE
= tCESave
; /* reset the pointer to before continuation */
7472 secT
= 0; /* Fetch a fresh CE before the continuation sequence. */
7476 secT
&= UCOL_SECONDARYMASK
; /* remove the continuation bit */
7480 if(secS
== UCOL_NO_MORE_CES_SECONDARY
|| (sCE
< sCEs
.buf
&& tCE
< tCEs
.buf
)) {
7487 result
= (secS
< secT
) ? UCOL_LESS
: UCOL_GREATER
;
7494 /* doing the case bit */
7499 while((secS
& UCOL_REMOVE_CASE
) == 0) {
7500 if(!isContinuation(*sCE
++)) {
7502 if(((secS
& UCOL_PRIMARYMASK
) != 0) || strength
> UCOL_PRIMARY
) {
7503 // primary ignorables should not be considered on the case level when the strength is primary
7504 // otherwise, the CEs stop being well-formed
7505 secS
&= UCOL_TERT_CASE_MASK
;
7515 while((secT
& UCOL_REMOVE_CASE
) == 0) {
7516 if(!isContinuation(*tCE
++)) {
7518 if(((secT
& UCOL_PRIMARYMASK
) != 0) || strength
> UCOL_PRIMARY
) {
7519 // primary ignorables should not be considered on the case level when the strength is primary
7520 // otherwise, the CEs stop being well-formed
7521 secT
&= UCOL_TERT_CASE_MASK
;
7531 if((secS
& UCOL_CASE_BIT_MASK
) < (secT
& UCOL_CASE_BIT_MASK
)) {
7534 } else if((secS
& UCOL_CASE_BIT_MASK
) > (secT
& UCOL_CASE_BIT_MASK
)) {
7535 result
= UCOL_GREATER
;
7539 if((secS
& UCOL_REMOVE_CASE
) == UCOL_NO_MORE_CES_TERTIARY
|| (secT
& UCOL_REMOVE_CASE
) == UCOL_NO_MORE_CES_TERTIARY
) {
7548 /* Tertiary level */
7555 while((secS
& UCOL_REMOVE_CASE
) == 0) {
7556 secS
= *(sCE
++) & tertiaryMask
;
7557 if(!isContinuation(secS
)) {
7560 secS
&= UCOL_REMOVE_CASE
;
7564 while((secT
& UCOL_REMOVE_CASE
) == 0) {
7565 secT
= *(tCE
++) & tertiaryMask
;
7566 if(!isContinuation(secT
)) {
7569 secT
&= UCOL_REMOVE_CASE
;
7574 if((secS
& UCOL_REMOVE_CASE
) == 1) {
7581 result
= (secS
< secT
) ? UCOL_LESS
: UCOL_GREATER
;
7588 if(qShifted
/*checkQuad*/) {
7589 UBool sInShifted
= TRUE
;
7590 UBool tInShifted
= TRUE
;
7596 while((secS
== 0 && secS
!= UCOL_NO_MORE_CES
) || (isContinuation(secS
) && !sInShifted
)) {
7598 if(isContinuation(secS
)) {
7602 } else if(secS
> LVT
|| (secS
& UCOL_PRIMARYMASK
) == 0) { /* non continuation */
7603 secS
= UCOL_PRIMARYMASK
;
7609 secS
&= UCOL_PRIMARYMASK
;
7612 while((secT
== 0 && secT
!= UCOL_NO_MORE_CES
) || (isContinuation(secT
) && !tInShifted
)) {
7614 if(isContinuation(secT
)) {
7618 } else if(secT
> LVT
|| (secT
& UCOL_PRIMARYMASK
) == 0) {
7619 secT
= UCOL_PRIMARYMASK
;
7625 secT
&= UCOL_PRIMARYMASK
;
7628 if(secS
== UCOL_NO_MORE_CES_PRIMARY
) {
7635 result
= (secS
< secT
) ? UCOL_LESS
: UCOL_GREATER
;
7639 } else if(doHiragana
&& hirResult
!= UCOL_EQUAL
) {
7640 // If we're fine on quaternaries, we might be different
7641 // on Hiragana. This, however, might fail us in shifted.
7646 /* For IDENTICAL comparisons, we use a bitwise character comparison */
7647 /* as a tiebreaker if all else is equal. */
7648 /* Getting here should be quite rare - strings are not identical - */
7649 /* that is checked first, but compared == through all other checks. */
7652 //result = ucol_checkIdent(&sColl, &tColl, coll->normalizationMode == UCOL_ON);
7653 result
= ucol_checkIdent(sColl
, tColl
, TRUE
, status
);
7657 if ((sColl
->flags
| tColl
->flags
) & UCOL_ITER_ALLOCATED
) {
7658 if (sCEs
.buf
!= sCEs
.localArray
) {
7659 uprv_free(sCEs
.buf
);
7661 if (tCEs
.buf
!= tCEs
.localArray
) {
7662 uprv_free(tCEs
.buf
);
7669 static UCollationResult
7670 ucol_strcollRegular(const UCollator
*coll
,
7671 const UChar
*source
, int32_t sourceLength
,
7672 const UChar
*target
, int32_t targetLength
,
7673 UErrorCode
*status
) {
7674 collIterate sColl
, tColl
;
7675 // Preparing the context objects for iterating over strings
7676 IInit_collIterate(coll
, source
, sourceLength
, &sColl
, status
);
7677 IInit_collIterate(coll
, target
, targetLength
, &tColl
, status
);
7678 if(U_FAILURE(*status
)) {
7681 return ucol_strcollRegular(&sColl
, &tColl
, status
);
7684 static inline uint32_t
7685 ucol_getLatinOneContraction(const UCollator
*coll
, int32_t strength
,
7686 uint32_t CE
, const UChar
*s
, int32_t *index
, int32_t len
)
7688 const UChar
*UCharOffset
= (UChar
*)coll
->image
+getContractOffset(CE
&0xFFF);
7689 int32_t latinOneOffset
= (CE
& 0x00FFF000) >> 12;
7691 UChar schar
= 0, tchar
= 0;
7695 if(s
[*index
] == 0) { // end of string
7696 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
]);
7702 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
]);
7708 while(schar
> (tchar
= *(UCharOffset
+offset
))) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
7712 if (schar
== tchar
) {
7714 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
+offset
]);
7718 if(schar
& 0xFF00 /*> UCOL_ENDOFLATIN1RANGE*/) {
7719 return UCOL_BAIL_OUT_CE
;
7721 // skip completely ignorables
7722 uint32_t isZeroCE
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, schar
);
7723 if(isZeroCE
== 0) { // we have to ignore completely ignorables
7728 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
]);
7735 * This is a fast strcoll, geared towards text in Latin-1.
7736 * It supports contractions of size two, French secondaries
7737 * and case switching. You can use it with strengths primary
7738 * to tertiary. It does not support shifted and case level.
7739 * It relies on the table build by setupLatin1Table. If it
7740 * doesn't understand something, it will go to the regular
7743 static UCollationResult
7744 ucol_strcollUseLatin1( const UCollator
*coll
,
7745 const UChar
*source
,
7747 const UChar
*target
,
7752 int32_t strength
= coll
->strength
;
7754 int32_t sIndex
= 0, tIndex
= 0;
7755 UChar sChar
= 0, tChar
= 0;
7756 uint32_t sOrder
=0, tOrder
=0;
7758 UBool endOfSource
= FALSE
;
7760 uint32_t *elements
= coll
->latinOneCEs
;
7762 UBool haveContractions
= FALSE
; // if we have contractions in our string
7763 // we cannot do French secondary
7765 // Do the primary level
7767 while(sOrder
==0) { // this loop skips primary ignorables
7768 // sOrder=getNextlatinOneCE(source);
7769 if(sLen
==-1) { // handling zero terminated strings
7770 sChar
=source
[sIndex
++];
7775 } else { // handling strings with known length
7780 sChar
=source
[sIndex
++];
7782 if(sChar
&0xFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
7783 //fprintf(stderr, "R");
7784 return ucol_strcollRegular(coll
, source
, sLen
, target
, tLen
, status
);
7786 sOrder
= elements
[sChar
];
7787 if(sOrder
>= UCOL_NOT_FOUND
) { // if we got a special
7788 // specials can basically be either contractions or bail-out signs. If we get anything
7789 // else, we'll bail out anywasy
7790 if(getCETag(sOrder
) == CONTRACTION_TAG
) {
7791 sOrder
= ucol_getLatinOneContraction(coll
, UCOL_PRIMARY
, sOrder
, source
, &sIndex
, sLen
);
7792 haveContractions
= TRUE
; // if there are contractions, we cannot do French secondary
7793 // However, if there are contractions in the table, but we always use just one char,
7794 // we might be able to do French. This should be checked out.
7796 if(sOrder
>= UCOL_NOT_FOUND
/*== UCOL_BAIL_OUT_CE*/) {
7797 //fprintf(stderr, "S");
7798 return ucol_strcollRegular(coll
, source
, sLen
, target
, tLen
, status
);
7803 while(tOrder
==0) { // this loop skips primary ignorables
7804 // tOrder=getNextlatinOneCE(target);
7805 if(tLen
==-1) { // handling zero terminated strings
7806 tChar
=target
[tIndex
++];
7808 if(endOfSource
) { // this is different than source loop,
7809 // as we already know that source loop is done here,
7810 // so we can either finish the primary loop if both
7811 // strings are done or anounce the result if only
7812 // target is done. Same below.
7815 return UCOL_GREATER
;
7818 } else { // handling strings with known length
7823 return UCOL_GREATER
;
7826 tChar
=target
[tIndex
++];
7828 if(tChar
&0xFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
7829 //fprintf(stderr, "R");
7830 return ucol_strcollRegular(coll
, source
, sLen
, target
, tLen
, status
);
7832 tOrder
= elements
[tChar
];
7833 if(tOrder
>= UCOL_NOT_FOUND
) {
7834 // Handling specials, see the comments for source
7835 if(getCETag(tOrder
) == CONTRACTION_TAG
) {
7836 tOrder
= ucol_getLatinOneContraction(coll
, UCOL_PRIMARY
, tOrder
, target
, &tIndex
, tLen
);
7837 haveContractions
= TRUE
;
7839 if(tOrder
>= UCOL_NOT_FOUND
/*== UCOL_BAIL_OUT_CE*/) {
7840 //fprintf(stderr, "S");
7841 return ucol_strcollRegular(coll
, source
, sLen
, target
, tLen
, status
);
7845 if(endOfSource
) { // source is finished, but target is not, say the result.
7849 if(sOrder
== tOrder
) { // if we have same CEs, we continue the loop
7850 sOrder
= 0; tOrder
= 0;
7853 // compare current top bytes
7854 if(((sOrder
^tOrder
)&0xFF000000)!=0) {
7855 // top bytes differ, return difference
7856 if(sOrder
< tOrder
) {
7858 } else if(sOrder
> tOrder
) {
7859 return UCOL_GREATER
;
7861 // instead of return (int32_t)(sOrder>>24)-(int32_t)(tOrder>>24);
7862 // since we must return enum value
7865 // top bytes match, continue with following bytes
7872 // after primary loop, we definitely know the sizes of strings,
7873 // so we set it and use simpler loop for secondaries and tertiaries
7874 sLen
= sIndex
; tLen
= tIndex
;
7875 if(strength
>= UCOL_SECONDARY
) {
7876 // adjust the table beggining
7877 elements
+= coll
->latinOneTableLen
;
7878 endOfSource
= FALSE
;
7880 if(coll
->frenchCollation
== UCOL_OFF
) { // non French
7881 // This loop is a simplified copy of primary loop
7882 // at this point we know that whole strings are latin-1, so we don't
7883 // check for that. We also know that we only have contractions as
7885 sIndex
= 0; tIndex
= 0;
7892 sChar
=source
[sIndex
++];
7893 sOrder
= elements
[sChar
];
7894 if(sOrder
> UCOL_NOT_FOUND
) {
7895 sOrder
= ucol_getLatinOneContraction(coll
, UCOL_SECONDARY
, sOrder
, source
, &sIndex
, sLen
);
7904 return UCOL_GREATER
;
7907 tChar
=target
[tIndex
++];
7908 tOrder
= elements
[tChar
];
7909 if(tOrder
> UCOL_NOT_FOUND
) {
7910 tOrder
= ucol_getLatinOneContraction(coll
, UCOL_SECONDARY
, tOrder
, target
, &tIndex
, tLen
);
7917 if(sOrder
== tOrder
) {
7918 sOrder
= 0; tOrder
= 0;
7921 // see primary loop for comments on this
7922 if(((sOrder
^tOrder
)&0xFF000000)!=0) {
7923 if(sOrder
< tOrder
) {
7925 } else if(sOrder
> tOrder
) {
7926 return UCOL_GREATER
;
7934 if(haveContractions
) { // if we have contractions, we have to bail out
7935 // since we don't really know how to handle them here
7936 return ucol_strcollRegular(coll
, source
, sLen
, target
, tLen
, status
);
7938 // For French, we go backwards
7939 sIndex
= sLen
; tIndex
= tLen
;
7946 sChar
=source
[--sIndex
];
7947 sOrder
= elements
[sChar
];
7948 // don't even look for contractions
7956 return UCOL_GREATER
;
7959 tChar
=target
[--tIndex
];
7960 tOrder
= elements
[tChar
];
7961 // don't even look for contractions
7967 if(sOrder
== tOrder
) {
7968 sOrder
= 0; tOrder
= 0;
7971 // see the primary loop for comments
7972 if(((sOrder
^tOrder
)&0xFF000000)!=0) {
7973 if(sOrder
< tOrder
) {
7975 } else if(sOrder
> tOrder
) {
7976 return UCOL_GREATER
;
7987 if(strength
>= UCOL_TERTIARY
) {
7988 // tertiary loop is the same as secondary (except no French)
7989 elements
+= coll
->latinOneTableLen
;
7990 sIndex
= 0; tIndex
= 0;
7991 endOfSource
= FALSE
;
7998 sChar
=source
[sIndex
++];
7999 sOrder
= elements
[sChar
];
8000 if(sOrder
> UCOL_NOT_FOUND
) {
8001 sOrder
= ucol_getLatinOneContraction(coll
, UCOL_TERTIARY
, sOrder
, source
, &sIndex
, sLen
);
8007 return UCOL_EQUAL
; // if both strings are at the end, they are equal
8009 return UCOL_GREATER
;
8012 tChar
=target
[tIndex
++];
8013 tOrder
= elements
[tChar
];
8014 if(tOrder
> UCOL_NOT_FOUND
) {
8015 tOrder
= ucol_getLatinOneContraction(coll
, UCOL_TERTIARY
, tOrder
, target
, &tIndex
, tLen
);
8021 if(sOrder
== tOrder
) {
8022 sOrder
= 0; tOrder
= 0;
8025 if(((sOrder
^tOrder
)&0xff000000)!=0) {
8026 if(sOrder
< tOrder
) {
8028 } else if(sOrder
> tOrder
) {
8029 return UCOL_GREATER
;
8041 Note: ucol_strcollUTF8 supports null terminated input. Calculating length of
8042 null terminated input string takes extra amount of CPU cycles.
8044 static UCollationResult
8045 ucol_strcollRegularUTF8(
8046 const UCollator
*coll
,
8048 int32_t sourceLength
,
8050 int32_t targetLength
,
8056 uiter_setUTF8(&src
, source
, sourceLength
);
8057 uiter_setUTF8(&tgt
, target
, targetLength
);
8059 // Preparing the context objects for iterating over strings
8060 collIterate sColl
, tColl
;
8061 IInit_collIterate(coll
, NULL
, -1, &sColl
, status
);
8062 IInit_collIterate(coll
, NULL
, -1, &tColl
, status
);
8063 if(U_FAILURE(*status
)) {
8064 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
)
8067 // The division for the array length may truncate the array size to
8068 // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
8069 // for all platforms anyway.
8070 UAlignedMemory stackNormIter1
[UNORM_ITER_SIZE
/sizeof(UAlignedMemory
)];
8071 UAlignedMemory stackNormIter2
[UNORM_ITER_SIZE
/sizeof(UAlignedMemory
)];
8072 UNormIterator
*sNormIter
= NULL
, *tNormIter
= NULL
;
8074 sColl
.iterator
= &src
;
8075 sColl
.flags
|= UCOL_USE_ITERATOR
;
8076 tColl
.flags
|= UCOL_USE_ITERATOR
;
8077 tColl
.iterator
= &tgt
;
8079 if(ucol_getAttribute(coll
, UCOL_NORMALIZATION_MODE
, status
) == UCOL_ON
) {
8080 sNormIter
= unorm_openIter(stackNormIter1
, sizeof(stackNormIter1
), status
);
8081 sColl
.iterator
= unorm_setIter(sNormIter
, &src
, UNORM_FCD
, status
);
8082 sColl
.flags
&= ~UCOL_ITER_NORM
;
8084 tNormIter
= unorm_openIter(stackNormIter2
, sizeof(stackNormIter2
), status
);
8085 tColl
.iterator
= unorm_setIter(tNormIter
, &tgt
, UNORM_FCD
, status
);
8086 tColl
.flags
&= ~UCOL_ITER_NORM
;
8089 return ucol_strcollRegular(&sColl
, &tColl
, status
);
8092 static inline uint32_t
8093 ucol_getLatinOneContractionUTF8(const UCollator
*coll
, int32_t strength
,
8094 uint32_t CE
, const char *s
, int32_t *index
, int32_t len
)
8096 const UChar
*UCharOffset
= (UChar
*)coll
->image
+getContractOffset(CE
&0xFFF);
8097 int32_t latinOneOffset
= (CE
& 0x00FFF000) >> 12;
8099 UChar32 schar
= 0, tchar
= 0;
8102 if (*index
== len
) {
8103 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
]);
8105 U8_GET_OR_FFFD((const uint8_t*)s
, 0, *index
, len
, schar
);
8106 if (len
< 0 && schar
== 0) {
8107 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
]);
8110 while(schar
> (tchar
= *(UCharOffset
+offset
))) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
8114 if (schar
== tchar
) {
8115 U8_FWD_1(s
, *index
, len
);
8116 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
+offset
]);
8120 if(schar
& 0xFF00 /*> UCOL_ENDOFLATIN1RANGE*/) {
8121 return UCOL_BAIL_OUT_CE
;
8123 // skip completely ignorables
8124 uint32_t isZeroCE
= UTRIE_GET32_FROM_LEAD(&coll
->mapping
, schar
);
8125 if(isZeroCE
== 0) { // we have to ignore completely ignorables
8126 U8_FWD_1(s
, *index
, len
);
8130 return(coll
->latinOneCEs
[strength
*coll
->latinOneTableLen
+latinOneOffset
]);
8135 static inline UCollationResult
8136 ucol_strcollUseLatin1UTF8(
8137 const UCollator
*coll
,
8145 int32_t strength
= coll
->strength
;
8147 int32_t sIndex
= 0, tIndex
= 0;
8148 UChar32 sChar
= 0, tChar
= 0;
8149 uint32_t sOrder
=0, tOrder
=0;
8151 UBool endOfSource
= FALSE
;
8153 uint32_t *elements
= coll
->latinOneCEs
;
8155 UBool haveContractions
= FALSE
; // if we have contractions in our string
8156 // we cannot do French secondary
8158 // Do the primary level
8160 while(sOrder
==0) { // this loop skips primary ignorables
8161 // sOrder=getNextlatinOneCE(source);
8162 if (sIndex
== sLen
) {
8166 U8_NEXT_OR_FFFD(source
, sIndex
, sLen
,sChar
);
8167 if (sLen
< 0 && sChar
== 0) {
8172 if(sChar
&0xFFFFFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
8173 //fprintf(stderr, "R");
8174 return ucol_strcollRegularUTF8(coll
, source
, sLen
, target
, tLen
, status
);
8176 sOrder
= elements
[sChar
];
8177 if(sOrder
>= UCOL_NOT_FOUND
) { // if we got a special
8178 // specials can basically be either contractions or bail-out signs. If we get anything
8179 // else, we'll bail out anywasy
8180 if(getCETag(sOrder
) == CONTRACTION_TAG
) {
8181 sOrder
= ucol_getLatinOneContractionUTF8(coll
, UCOL_PRIMARY
, sOrder
, source
, &sIndex
, sLen
);
8182 haveContractions
= TRUE
; // if there are contractions, we cannot do French secondary
8183 // However, if there are contractions in the table, but we always use just one char,
8184 // we might be able to do French. This should be checked out.
8186 if(sOrder
>= UCOL_NOT_FOUND
/*== UCOL_BAIL_OUT_CE*/) {
8187 //fprintf(stderr, "S");
8188 return ucol_strcollRegularUTF8(coll
, source
, sLen
, target
, tLen
, status
);
8193 while(tOrder
==0) { // this loop skips primary ignorables
8194 // tOrder=getNextlatinOneCE(target);
8195 if (tIndex
== tLen
) {
8197 goto endOfPrimLoopU8
;
8199 return UCOL_GREATER
;
8202 U8_NEXT_OR_FFFD(target
, tIndex
, tLen
, tChar
);
8203 if (tLen
< 0 && tChar
== 0) {
8206 goto endOfPrimLoopU8
;
8208 return UCOL_GREATER
;
8211 if(tChar
&0xFFFFFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
8212 //fprintf(stderr, "R");
8213 return ucol_strcollRegularUTF8(coll
, source
, sLen
, target
, tLen
, status
);
8215 tOrder
= elements
[tChar
];
8216 if(tOrder
>= UCOL_NOT_FOUND
) {
8217 // Handling specials, see the comments for source
8218 if(getCETag(tOrder
) == CONTRACTION_TAG
) {
8219 tOrder
= ucol_getLatinOneContractionUTF8(coll
, UCOL_PRIMARY
, tOrder
, target
, &tIndex
, tLen
);
8220 haveContractions
= TRUE
;
8222 if(tOrder
>= UCOL_NOT_FOUND
/*== UCOL_BAIL_OUT_CE*/) {
8223 //fprintf(stderr, "S");
8224 return ucol_strcollRegularUTF8(coll
, source
, sLen
, target
, tLen
, status
);
8228 if(endOfSource
) { // source is finished, but target is not, say the result.
8232 if(sOrder
== tOrder
) { // if we have same CEs, we continue the loop
8233 sOrder
= 0; tOrder
= 0;
8236 // compare current top bytes
8237 if(((sOrder
^tOrder
)&0xFF000000)!=0) {
8238 // top bytes differ, return difference
8239 if(sOrder
< tOrder
) {
8241 } else if(sOrder
> tOrder
) {
8242 return UCOL_GREATER
;
8244 // instead of return (int32_t)(sOrder>>24)-(int32_t)(tOrder>>24);
8245 // since we must return enum value
8248 // top bytes match, continue with following bytes
8255 // after primary loop, we definitely know the sizes of strings,
8256 // so we set it and use simpler loop for secondaries and tertiaries
8257 sLen
= sIndex
; tLen
= tIndex
;
8258 if(strength
>= UCOL_SECONDARY
) {
8259 // adjust the table beggining
8260 elements
+= coll
->latinOneTableLen
;
8261 endOfSource
= FALSE
;
8263 if(coll
->frenchCollation
== UCOL_OFF
) { // non French
8264 // This loop is a simplified copy of primary loop
8265 // at this point we know that whole strings are latin-1, so we don't
8266 // check for that. We also know that we only have contractions as
8268 sIndex
= 0; tIndex
= 0;
8275 U_ASSERT(sLen
>= 0);
8276 U8_NEXT_OR_FFFD(source
, sIndex
, sLen
, sChar
);
8277 U_ASSERT(sChar
>= 0 && sChar
<= 0xFF);
8278 sOrder
= elements
[sChar
];
8279 if(sOrder
> UCOL_NOT_FOUND
) {
8280 sOrder
= ucol_getLatinOneContractionUTF8(coll
, UCOL_SECONDARY
, sOrder
, source
, &sIndex
, sLen
);
8287 goto endOfSecLoopU8
;
8289 return UCOL_GREATER
;
8292 U_ASSERT(tLen
>= 0);
8293 U8_NEXT_OR_FFFD(target
, tIndex
, tLen
, tChar
);
8294 U_ASSERT(tChar
>= 0 && tChar
<= 0xFF);
8295 tOrder
= elements
[tChar
];
8296 if(tOrder
> UCOL_NOT_FOUND
) {
8297 tOrder
= ucol_getLatinOneContractionUTF8(coll
, UCOL_SECONDARY
, tOrder
, target
, &tIndex
, tLen
);
8304 if(sOrder
== tOrder
) {
8305 sOrder
= 0; tOrder
= 0;
8308 // see primary loop for comments on this
8309 if(((sOrder
^tOrder
)&0xFF000000)!=0) {
8310 if(sOrder
< tOrder
) {
8312 } else if(sOrder
> tOrder
) {
8313 return UCOL_GREATER
;
8321 if(haveContractions
) { // if we have contractions, we have to bail out
8322 // since we don't really know how to handle them here
8323 return ucol_strcollRegularUTF8(coll
, source
, sLen
, target
, tLen
, status
);
8325 // For French, we go backwards
8326 sIndex
= sLen
; tIndex
= tLen
;
8333 U8_PREV_OR_FFFD(source
, 0, sIndex
, sChar
);
8334 U_ASSERT(sChar
>= 0 && sChar
<= 0xFF);
8335 sOrder
= elements
[sChar
];
8336 // don't even look for contractions
8342 goto endOfSecLoopU8
;
8344 return UCOL_GREATER
;
8347 U8_PREV_OR_FFFD(target
, 0, tIndex
, tChar
);
8348 U_ASSERT(tChar
>= 0 && tChar
<= 0xFF);
8349 tOrder
= elements
[tChar
];
8350 // don't even look for contractions
8356 if(sOrder
== tOrder
) {
8357 sOrder
= 0; tOrder
= 0;
8360 // see the primary loop for comments
8361 if(((sOrder
^tOrder
)&0xFF000000)!=0) {
8362 if(sOrder
< tOrder
) {
8364 } else if(sOrder
> tOrder
) {
8365 return UCOL_GREATER
;
8376 if(strength
>= UCOL_TERTIARY
) {
8377 // tertiary loop is the same as secondary (except no French)
8378 elements
+= coll
->latinOneTableLen
;
8379 sIndex
= 0; tIndex
= 0;
8380 endOfSource
= FALSE
;
8387 U_ASSERT(sLen
>= 0);
8388 U8_NEXT_OR_FFFD(source
, sIndex
, sLen
, sChar
);
8389 U_ASSERT(sChar
>= 0 && sChar
<= 0xFF);
8390 sOrder
= elements
[sChar
];
8391 if(sOrder
> UCOL_NOT_FOUND
) {
8392 sOrder
= ucol_getLatinOneContractionUTF8(coll
, UCOL_TERTIARY
, sOrder
, source
, &sIndex
, sLen
);
8398 return UCOL_EQUAL
; // if both strings are at the end, they are equal
8400 return UCOL_GREATER
;
8403 U_ASSERT(tLen
>= 0);
8404 U8_NEXT_OR_FFFD(target
, tIndex
, tLen
, tChar
);
8405 U_ASSERT(tChar
>= 0 && tChar
<= 0xFF);
8406 tOrder
= elements
[tChar
];
8407 if(tOrder
> UCOL_NOT_FOUND
) {
8408 tOrder
= ucol_getLatinOneContractionUTF8(coll
, UCOL_TERTIARY
, tOrder
, target
, &tIndex
, tLen
);
8414 if(sOrder
== tOrder
) {
8415 sOrder
= 0; tOrder
= 0;
8418 if(((sOrder
^tOrder
)&0xff000000)!=0) {
8419 if(sOrder
< tOrder
) {
8421 } else if(sOrder
> tOrder
) {
8422 return UCOL_GREATER
;
8433 U_CAPI UCollationResult U_EXPORT2
8434 ucol_strcollIter( const UCollator
*coll
,
8435 UCharIterator
*sIter
,
8436 UCharIterator
*tIter
,
8439 if(!status
|| U_FAILURE(*status
)) {
8443 UTRACE_ENTRY(UTRACE_UCOL_STRCOLLITER
);
8444 UTRACE_DATA3(UTRACE_VERBOSE
, "coll=%p, sIter=%p, tIter=%p", coll
, sIter
, tIter
);
8446 if (sIter
== tIter
) {
8447 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
)
8450 if(sIter
== NULL
|| tIter
== NULL
|| coll
== NULL
) {
8451 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
8452 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
)
8456 UCollationResult result
= UCOL_EQUAL
;
8458 // Preparing the context objects for iterating over strings
8459 collIterate sColl
, tColl
;
8460 IInit_collIterate(coll
, NULL
, -1, &sColl
, status
);
8461 IInit_collIterate(coll
, NULL
, -1, &tColl
, status
);
8462 if(U_FAILURE(*status
)) {
8463 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
)
8466 // The division for the array length may truncate the array size to
8467 // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
8468 // for all platforms anyway.
8469 UAlignedMemory stackNormIter1
[UNORM_ITER_SIZE
/sizeof(UAlignedMemory
)];
8470 UAlignedMemory stackNormIter2
[UNORM_ITER_SIZE
/sizeof(UAlignedMemory
)];
8471 UNormIterator
*sNormIter
= NULL
, *tNormIter
= NULL
;
8473 sColl
.iterator
= sIter
;
8474 sColl
.flags
|= UCOL_USE_ITERATOR
;
8475 tColl
.flags
|= UCOL_USE_ITERATOR
;
8476 tColl
.iterator
= tIter
;
8478 if(ucol_getAttribute(coll
, UCOL_NORMALIZATION_MODE
, status
) == UCOL_ON
) {
8479 sNormIter
= unorm_openIter(stackNormIter1
, sizeof(stackNormIter1
), status
);
8480 sColl
.iterator
= unorm_setIter(sNormIter
, sIter
, UNORM_FCD
, status
);
8481 sColl
.flags
&= ~UCOL_ITER_NORM
;
8483 tNormIter
= unorm_openIter(stackNormIter2
, sizeof(stackNormIter2
), status
);
8484 tColl
.iterator
= unorm_setIter(tNormIter
, tIter
, UNORM_FCD
, status
);
8485 tColl
.flags
&= ~UCOL_ITER_NORM
;
8488 UChar32 sChar
= U_SENTINEL
, tChar
= U_SENTINEL
;
8490 while((sChar
= sColl
.iterator
->next(sColl
.iterator
)) ==
8491 (tChar
= tColl
.iterator
->next(tColl
.iterator
))) {
8492 if(sChar
== U_SENTINEL
) {
8493 result
= UCOL_EQUAL
;
8498 if(sChar
== U_SENTINEL
) {
8499 tChar
= tColl
.iterator
->previous(tColl
.iterator
);
8502 if(tChar
== U_SENTINEL
) {
8503 sChar
= sColl
.iterator
->previous(sColl
.iterator
);
8506 sChar
= sColl
.iterator
->previous(sColl
.iterator
);
8507 tChar
= tColl
.iterator
->previous(tColl
.iterator
);
8509 if (ucol_unsafeCP((UChar
)sChar
, coll
) || ucol_unsafeCP((UChar
)tChar
, coll
))
8511 // We are stopped in the middle of a contraction.
8512 // Scan backwards through the == part of the string looking for the start of the contraction.
8513 // It doesn't matter which string we scan, since they are the same in this region.
8516 sChar
= sColl
.iterator
->previous(sColl
.iterator
);
8517 tChar
= tColl
.iterator
->previous(tColl
.iterator
);
8519 while (sChar
!= U_SENTINEL
&& ucol_unsafeCP((UChar
)sChar
, coll
));
8523 if(U_SUCCESS(*status
)) {
8524 result
= ucol_strcollRegular(&sColl
, &tColl
, status
);
8528 if(sNormIter
|| tNormIter
) {
8529 unorm_closeIter(sNormIter
);
8530 unorm_closeIter(tNormIter
);
8533 UTRACE_EXIT_VALUE_STATUS(result
, *status
)
8539 /* ucol_strcoll Main public API string comparison function */
8541 U_CAPI UCollationResult U_EXPORT2
8542 ucol_strcoll( const UCollator
*coll
,
8543 const UChar
*source
,
8544 int32_t sourceLength
,
8545 const UChar
*target
,
8546 int32_t targetLength
)
8550 UTRACE_ENTRY(UTRACE_UCOL_STRCOLL
);
8551 if (UTRACE_LEVEL(UTRACE_VERBOSE
)) {
8552 UTRACE_DATA3(UTRACE_VERBOSE
, "coll=%p, source=%p, target=%p", coll
, source
, target
);
8553 UTRACE_DATA2(UTRACE_VERBOSE
, "source string = %vh ", source
, sourceLength
);
8554 UTRACE_DATA2(UTRACE_VERBOSE
, "target string = %vh ", target
, targetLength
);
8557 if(source
== NULL
|| target
== NULL
) {
8558 // do not crash, but return. Should have
8559 // status argument to return error.
8560 UTRACE_EXIT_VALUE(UCOL_EQUAL
);
8564 /* Quick check if source and target are same strings. */
8565 /* They should either both be NULL terminated or the explicit length should be set on both. */
8566 if (source
==target
&& sourceLength
==targetLength
) {
8567 UTRACE_EXIT_VALUE(UCOL_EQUAL
);
8571 if(coll
->delegate
!= NULL
) {
8572 UErrorCode status
= U_ZERO_ERROR
;
8573 return ((const Collator
*)coll
->delegate
)->compare(source
,sourceLength
,target
,targetLength
, status
);
8576 /* Scan the strings. Find: */
8577 /* The length of any leading portion that is equal */
8578 /* Whether they are exactly equal. (in which case we just return) */
8579 const UChar
*pSrc
= source
;
8580 const UChar
*pTarg
= target
;
8581 int32_t equalLength
;
8583 if (sourceLength
== -1 && targetLength
== -1) {
8584 // Both strings are null terminated.
8585 // Scan through any leading equal portion.
8586 while (*pSrc
== *pTarg
&& *pSrc
!= 0) {
8590 if (*pSrc
== 0 && *pTarg
== 0) {
8591 UTRACE_EXIT_VALUE(UCOL_EQUAL
);
8594 equalLength
= (int32_t)(pSrc
- source
);
8598 // One or both strings has an explicit length.
8599 const UChar
*pSrcEnd
= source
+ sourceLength
;
8600 const UChar
*pTargEnd
= target
+ targetLength
;
8602 // Scan while the strings are bitwise ==, or until one is exhausted.
8604 if (pSrc
== pSrcEnd
|| pTarg
== pTargEnd
) {
8607 if ((*pSrc
== 0 && sourceLength
== -1) || (*pTarg
== 0 && targetLength
== -1)) {
8610 if (*pSrc
!= *pTarg
) {
8616 equalLength
= (int32_t)(pSrc
- source
);
8618 // If we made it all the way through both strings, we are done. They are ==
8619 if ((pSrc
==pSrcEnd
|| (pSrcEnd
<pSrc
&& *pSrc
==0)) && /* At end of src string, however it was specified. */
8620 (pTarg
==pTargEnd
|| (pTargEnd
<pTarg
&& *pTarg
==0))) /* and also at end of dest string */
8622 UTRACE_EXIT_VALUE(UCOL_EQUAL
);
8626 if (equalLength
> 0) {
8627 /* There is an identical portion at the beginning of the two strings. */
8628 /* If the identical portion ends within a contraction or a comibining */
8629 /* character sequence, back up to the start of that sequence. */
8631 // These values should already be set by the code above.
8632 //pSrc = source + equalLength; /* point to the first differing chars */
8633 //pTarg = target + equalLength;
8634 if ((pSrc
!= source
+sourceLength
&& ucol_unsafeCP(*pSrc
, coll
)) ||
8635 (pTarg
!= target
+targetLength
&& ucol_unsafeCP(*pTarg
, coll
)))
8637 // We are stopped in the middle of a contraction.
8638 // Scan backwards through the == part of the string looking for the start of the contraction.
8639 // It doesn't matter which string we scan, since they are the same in this region.
8645 while (equalLength
>0 && ucol_unsafeCP(*pSrc
, coll
));
8648 source
+= equalLength
;
8649 target
+= equalLength
;
8650 if (sourceLength
> 0) {
8651 sourceLength
-= equalLength
;
8653 if (targetLength
> 0) {
8654 targetLength
-= equalLength
;
8658 UErrorCode status
= U_ZERO_ERROR
;
8659 UCollationResult returnVal
;
8660 if(!coll
->latinOneUse
|| (sourceLength
> 0 && *source
&0xff00) || (targetLength
> 0 && *target
&0xff00)) {
8661 returnVal
= ucol_strcollRegular(coll
, source
, sourceLength
, target
, targetLength
, &status
);
8663 returnVal
= ucol_strcollUseLatin1(coll
, source
, sourceLength
, target
, targetLength
, &status
);
8665 UTRACE_EXIT_VALUE(returnVal
);
8669 U_CAPI UCollationResult U_EXPORT2
8671 const UCollator
*coll
,
8673 int32_t sourceLength
,
8675 int32_t targetLength
,
8680 UTRACE_ENTRY(UTRACE_UCOL_STRCOLLUTF8
);
8681 if (UTRACE_LEVEL(UTRACE_VERBOSE
)) {
8682 UTRACE_DATA3(UTRACE_VERBOSE
, "coll=%p, source=%p, target=%p", coll
, source
, target
);
8683 UTRACE_DATA2(UTRACE_VERBOSE
, "source string = %vb ", source
, sourceLength
);
8684 UTRACE_DATA2(UTRACE_VERBOSE
, "target string = %vb ", target
, targetLength
);
8687 if (U_FAILURE(*status
)) {
8689 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
);
8693 if(source
== NULL
|| target
== NULL
) {
8694 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
8695 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
);
8699 /* Quick check if source and target are same strings. */
8700 /* They should either both be NULL terminated or the explicit length should be set on both. */
8701 if (source
==target
&& sourceLength
==targetLength
) {
8702 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
);
8706 if(coll
->delegate
!= NULL
) {
8707 return ((const Collator
*)coll
->delegate
)->compareUTF8(
8708 StringPiece(source
, (sourceLength
< 0) ? uprv_strlen(source
) : sourceLength
),
8709 StringPiece(target
, (targetLength
< 0) ? uprv_strlen(target
) : targetLength
),
8713 /* Scan the strings. Find: */
8714 /* The length of any leading portion that is equal */
8715 /* Whether they are exactly equal. (in which case we just return) */
8716 const char *pSrc
= source
;
8717 const char *pTarg
= target
;
8718 UBool bSrcLimit
= FALSE
;
8719 UBool bTargLimit
= FALSE
;
8721 if (sourceLength
== -1 && targetLength
== -1) {
8722 // Both strings are null terminated.
8723 // Scan through any leading equal portion.
8724 while (*pSrc
== *pTarg
&& *pSrc
!= 0) {
8728 if (*pSrc
== 0 && *pTarg
== 0) {
8729 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
);
8732 bSrcLimit
= (*pSrc
== 0);
8733 bTargLimit
= (*pTarg
== 0);
8737 // One or both strings has an explicit length.
8738 const char *pSrcEnd
= source
+ sourceLength
;
8739 const char *pTargEnd
= target
+ targetLength
;
8741 // Scan while the strings are bitwise ==, or until one is exhausted.
8743 if (pSrc
== pSrcEnd
|| pTarg
== pTargEnd
) {
8746 if ((*pSrc
== 0 && sourceLength
== -1) || (*pTarg
== 0 && targetLength
== -1)) {
8749 if (*pSrc
!= *pTarg
) {
8755 bSrcLimit
= (pSrc
==pSrcEnd
|| (pSrcEnd
<pSrc
&& *pSrc
==0));
8756 bTargLimit
= (pTarg
==pTargEnd
|| (pTargEnd
<pTarg
&& *pTarg
==0));
8758 // If we made it all the way through both strings, we are done. They are ==
8759 if (bSrcLimit
&& /* At end of src string, however it was specified. */
8760 bTargLimit
) /* and also at end of dest string */
8762 UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL
, *status
);
8767 U_ASSERT(!(bSrcLimit
&& bTargLimit
));
8769 int32_t equalLength
= pSrc
- source
;
8770 UBool bSawNonLatin1
= FALSE
;
8772 if (equalLength
> 0) {
8773 // Align position to the start of UTF-8 code point.
8775 U8_SET_CP_START((const uint8_t*)source
, 0, equalLength
);
8777 U8_SET_CP_START((const uint8_t*)target
, 0, equalLength
);
8779 pSrc
= source
+ equalLength
;
8780 pTarg
= target
+ equalLength
;
8783 if (equalLength
> 0) {
8784 /* There is an identical portion at the beginning of the two strings. */
8785 /* If the identical portion ends within a contraction or a comibining */
8786 /* character sequence, back up to the start of that sequence. */
8787 UBool bUnsafeCP
= FALSE
;
8791 U8_GET_OR_FFFD((const uint8_t*)source
, 0, equalLength
, sourceLength
, uc32
);
8792 if (uc32
>= 0x10000 || ucol_unsafeCP((UChar
)uc32
, coll
)) {
8795 bSawNonLatin1
|= (uc32
> 0xff);
8798 U8_GET_OR_FFFD((const uint8_t*)target
, 0, equalLength
, targetLength
, uc32
);
8799 if (uc32
>= 0x10000 || ucol_unsafeCP((UChar
)uc32
, coll
)) {
8802 bSawNonLatin1
|= (uc32
> 0xff);
8806 while (equalLength
> 0) {
8807 // We are stopped in the middle of a contraction.
8808 // Scan backwards through the == part of the string looking for the start of the contraction.
8809 // It doesn't matter which string we scan, since they are the same in this region.
8810 U8_PREV_OR_FFFD((uint8_t*)source
, 0, equalLength
, uc32
);
8811 bSawNonLatin1
|= (uc32
> 0xff);
8812 if (uc32
< 0x10000 && !ucol_unsafeCP((UChar
)uc32
, coll
)) {
8817 source
+= equalLength
;
8818 target
+= equalLength
;
8819 if (sourceLength
> 0) {
8820 sourceLength
-= equalLength
;
8822 if (targetLength
> 0) {
8823 targetLength
-= equalLength
;
8826 // Lead byte of Latin 1 character is 0x00 - 0xC3
8827 bSawNonLatin1
= (source
&& (sourceLength
!= 0) && (uint8_t)*source
> 0xc3);
8828 bSawNonLatin1
|= (target
&& (targetLength
!= 0) && (uint8_t)*target
> 0xc3);
8831 UCollationResult returnVal
;
8833 if(!coll
->latinOneUse
|| bSawNonLatin1
) {
8834 returnVal
= ucol_strcollRegularUTF8(coll
, source
, sourceLength
, target
, targetLength
, status
);
8836 returnVal
= ucol_strcollUseLatin1UTF8(coll
, source
, sourceLength
, target
, targetLength
, status
);
8838 UTRACE_EXIT_VALUE_STATUS(returnVal
, *status
);
8843 /* convenience function for comparing strings */
8844 U_CAPI UBool U_EXPORT2
8845 ucol_greater( const UCollator
*coll
,
8846 const UChar
*source
,
8847 int32_t sourceLength
,
8848 const UChar
*target
,
8849 int32_t targetLength
)
8851 return (ucol_strcoll(coll
, source
, sourceLength
, target
, targetLength
)
8855 /* convenience function for comparing strings */
8856 U_CAPI UBool U_EXPORT2
8857 ucol_greaterOrEqual( const UCollator
*coll
,
8858 const UChar
*source
,
8859 int32_t sourceLength
,
8860 const UChar
*target
,
8861 int32_t targetLength
)
8863 return (ucol_strcoll(coll
, source
, sourceLength
, target
, targetLength
)
8867 /* convenience function for comparing strings */
8868 U_CAPI UBool U_EXPORT2
8869 ucol_equal( const UCollator
*coll
,
8870 const UChar
*source
,
8871 int32_t sourceLength
,
8872 const UChar
*target
,
8873 int32_t targetLength
)
8875 return (ucol_strcoll(coll
, source
, sourceLength
, target
, targetLength
)
8879 U_CAPI
void U_EXPORT2
8880 ucol_getUCAVersion(const UCollator
* coll
, UVersionInfo info
) {
8881 if(coll
&& coll
->UCA
) {
8882 uprv_memcpy(info
, coll
->UCA
->image
->UCAVersion
, sizeof(UVersionInfo
));
8886 #endif /* #if !UCONFIG_NO_COLLATION */