#include "unicode/utypes.h"
#include "unicode/uchar.h"
#include "unicode/udata.h"
#include "unicode/uloc.h"
#include "unicode/uiter.h"
#include "unicode/uset.h"
#include "umutex.h"
#include "cmemory.h"
#include "ucln_cmn.h"
#include "utrie.h"
#include "ustr_imp.h"
#include "uprops.h"
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
static const char DATA_NAME[] = "uprops";
static const char DATA_TYPE[] = "icu";
static UDataMemory *propsData=NULL;
static UErrorCode dataErrorCode=U_ZERO_ERROR;
static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
static UVersionInfo dataVersion={ 0, 0, 0, 0 };
static UTrie propsTrie={ 0 }, propsVectorsTrie={ 0 };
static const uint32_t *pData32=NULL, *props32Table=NULL, *exceptionsTable=NULL, *propsVectors=NULL;
static const UChar *ucharsTable=NULL;
static int32_t countPropsVectors=0, propsVectorsColumns=0;
static int8_t havePropsData=0;
static int32_t indexes[UPROPS_INDEX_COUNT];
static int32_t U_CALLCONV
getFoldingPropsOffset(uint32_t data) {
if(data&0x8000) {
return (int32_t)(data&0x7fff);
} else {
return 0;
}
}
static UBool U_CALLCONV
isAcceptable(void *context,
const char *type, const char *name,
const UDataInfo *pInfo) {
if(
pInfo->size>=20 &&
pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
pInfo->charsetFamily==U_CHARSET_FAMILY &&
pInfo->dataFormat[0]==0x55 &&
pInfo->dataFormat[1]==0x50 &&
pInfo->dataFormat[2]==0x72 &&
pInfo->dataFormat[3]==0x6f &&
pInfo->formatVersion[0]==3 &&
pInfo->formatVersion[2]==UTRIE_SHIFT &&
pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
) {
uprv_memcpy(formatVersion, pInfo->formatVersion, 4);
uprv_memcpy(dataVersion, pInfo->dataVersion, 4);
return TRUE;
} else {
return FALSE;
}
}
UBool
uchar_cleanup()
{
if (propsData) {
udata_close(propsData);
propsData=NULL;
}
pData32=NULL;
props32Table=NULL;
exceptionsTable=NULL;
ucharsTable=NULL;
propsVectors=NULL;
countPropsVectors=0;
dataErrorCode=U_ZERO_ERROR;
havePropsData=FALSE;
return TRUE;
}
static int8_t
loadPropsData(void) {
if(havePropsData==0) {
UTrie trie={ 0 }, trie2={ 0 };
UErrorCode errorCode=U_ZERO_ERROR;
UDataMemory *data;
const uint32_t *p=NULL;
int32_t length;
data=udata_openChoice(NULL, DATA_TYPE, DATA_NAME, isAcceptable, NULL, &errorCode);
dataErrorCode=errorCode;
if(U_FAILURE(errorCode)) {
return havePropsData=-1;
}
p=(const uint32_t *)udata_getMemory(data);
length=(int32_t)p[UPROPS_PROPS32_INDEX]*4;
length=utrie_unserialize(&trie, (const uint8_t *)(p+UPROPS_INDEX_COUNT), length-64, &errorCode);
if(U_FAILURE(errorCode)) {
dataErrorCode=errorCode;
udata_close(data);
return havePropsData=-1;
}
trie.getFoldingOffset=getFoldingPropsOffset;
if( p[UPROPS_ADDITIONAL_TRIE_INDEX]!=0 &&
p[UPROPS_ADDITIONAL_VECTORS_INDEX]!=0
) {
length=(int32_t)(p[UPROPS_ADDITIONAL_VECTORS_INDEX]-p[UPROPS_ADDITIONAL_TRIE_INDEX])*4;
length=utrie_unserialize(&trie2, (const uint8_t *)(p+p[UPROPS_ADDITIONAL_TRIE_INDEX]), length, &errorCode);
if(U_FAILURE(errorCode)) {
uprv_memset(&trie2, 0, sizeof(trie2));
} else {
trie2.getFoldingOffset=getFoldingPropsOffset;
}
}
umtx_lock(NULL);
if(propsData==NULL) {
propsData=data;
data=NULL;
pData32=p;
p=NULL;
uprv_memcpy(&propsTrie, &trie, sizeof(trie));
uprv_memcpy(&propsVectorsTrie, &trie2, sizeof(trie2));
}
umtx_unlock(NULL);
uprv_memcpy(indexes, pData32, sizeof(indexes));
props32Table=pData32+indexes[UPROPS_PROPS32_INDEX];
exceptionsTable=pData32+indexes[UPROPS_EXCEPTIONS_INDEX];
ucharsTable=(const UChar *)(pData32+indexes[UPROPS_EXCEPTIONS_TOP_INDEX]);
if(indexes[UPROPS_ADDITIONAL_VECTORS_INDEX]!=0) {
propsVectors=pData32+indexes[UPROPS_ADDITIONAL_VECTORS_INDEX];
countPropsVectors=indexes[UPROPS_RESERVED_INDEX]-indexes[UPROPS_ADDITIONAL_VECTORS_INDEX];
propsVectorsColumns=indexes[UPROPS_ADDITIONAL_VECTORS_COLUMNS_INDEX];
}
havePropsData=1;
if(data!=NULL) {
udata_close(data);
}
}
return havePropsData;
}
#define HAVE_DATA (havePropsData>0 || (havePropsData==0 && loadPropsData()>0))
#define VALIDATE(c) (((uint32_t)(c))<=0x10ffff && HAVE_DATA)
#define GET_PROPS_UNSAFE(c, result) \
UTRIE_GET16(&propsTrie, c, result); \
(result)=props32Table[(result)]
#define GET_PROPS(c, result) \
if(HAVE_DATA) { \
GET_PROPS_UNSAFE(c, result); \
} else { \
(result)=0; \
}
#define HAVE_EXCEPTION_VALUE(flags, index) ((flags)&(1UL<<(index)))
#define EXC_GROUP 8
static const uint8_t flagsOffset[256]={
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
#define ADD_EXCEPTION_OFFSET(flags, index, offset) { \
if((index)>=EXC_GROUP) { \
(offset)+=flagsOffset[(flags)&((1<<EXC_GROUP)-1)]; \
(flags)>>=EXC_GROUP; \
(index)-=EXC_GROUP; \
} \
(offset)+=flagsOffset[(flags)&((1<<(index))-1)]; \
}
U_CFUNC UBool
uprv_haveProperties(UErrorCode *pErrorCode) {
if(HAVE_DATA) {
return TRUE;
} else {
*pErrorCode=dataErrorCode;
return FALSE;
}
}
U_CAPI int8_t U_EXPORT2
u_charType(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (int8_t)GET_CATEGORY(props);
}
struct _EnumTypeCallback {
UCharEnumTypeRange *enumRange;
const void *context;
};
static uint32_t U_CALLCONV
_enumTypeValue(const void *context, uint32_t value) {
return GET_CATEGORY(props32Table[value]);
}
static UBool U_CALLCONV
_enumTypeRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
return ((struct _EnumTypeCallback *)context)->
enumRange(((struct _EnumTypeCallback *)context)->context,
start, limit, (UCharCategory)value);
}
U_CAPI void U_EXPORT2
u_enumCharTypes(UCharEnumTypeRange *enumRange, const void *context) {
struct _EnumTypeCallback callback;
if(enumRange==NULL || !HAVE_DATA) {
return;
}
callback.enumRange=enumRange;
callback.context=context;
utrie_enum(&propsTrie, _enumTypeValue, _enumTypeRange, &callback);
}
U_CAPI UBool U_EXPORT2
u_islower(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(GET_CATEGORY(props)==U_LOWERCASE_LETTER);
}
U_CAPI UBool U_EXPORT2
u_isupper(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(GET_CATEGORY(props)==U_UPPERCASE_LETTER);
}
U_CAPI UBool U_EXPORT2
u_istitle(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(GET_CATEGORY(props)==U_TITLECASE_LETTER);
}
U_CAPI UBool U_EXPORT2
u_isdigit(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(GET_CATEGORY(props)==U_DECIMAL_DIGIT_NUMBER);
}
U_CAPI UBool U_EXPORT2
u_isxdigit(UChar32 c) {
uint32_t props;
if(
(c<=0x66 && c>=0x41 && (c<=0x46 || c>=0x61)) ||
(c>=0xff21 && c<=0xff46 && (c<=0xff26 || c>=0xff41))
) {
return TRUE;
}
GET_PROPS(c, props);
return (UBool)(GET_CATEGORY(props)==U_DECIMAL_DIGIT_NUMBER);
}
U_CAPI UBool U_EXPORT2
u_isalpha(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&U_GC_L_MASK)!=0);
}
U_CAPI UBool U_EXPORT2
u_isalnum(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_ND_MASK))!=0);
}
U_CAPI UBool U_EXPORT2
u_isdefined(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(GET_CATEGORY(props)!=0);
}
U_CAPI UBool U_EXPORT2
u_isbase(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_N_MASK|U_GC_MC_MASK|U_GC_ME_MASK))!=0);
}
U_CAPI UBool U_EXPORT2
u_iscntrl(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&(U_GC_CC_MASK|U_GC_CF_MASK|U_GC_ZL_MASK|U_GC_ZP_MASK))!=0);
}
U_CAPI UBool U_EXPORT2
u_isISOControl(UChar32 c) {
return (uint32_t)c<=0x9f && (c<=0x1f || c>=0x7f);
}
#define IS_THAT_CONTROL_SPACE(c) \
(c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==NL))
U_CAPI UBool U_EXPORT2
u_isspace(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&U_GC_Z_MASK)!=0 || IS_THAT_CONTROL_SPACE(c));
}
U_CAPI UBool U_EXPORT2
u_isJavaSpaceChar(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&U_GC_Z_MASK)!=0);
}
U_CAPI UBool U_EXPORT2
u_isWhitespace(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(
((CAT_MASK(props)&U_GC_Z_MASK)!=0 &&
c!=NBSP && c!=FIGURESP && c!=NNBSP) ||
IS_THAT_CONTROL_SPACE(c)
);
}
U_CAPI UBool U_EXPORT2
u_isblank(UChar32 c) {
if((uint32_t)c<=0x9f) {
return c==9 || c==0x20;
} else {
return u_isUWhiteSpace(c) && ((c&0xfffffffe)!=0x2028);
}
}
U_CAPI UBool U_EXPORT2
u_isprint(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&U_GC_C_MASK)==0);
}
U_CAPI UBool U_EXPORT2
u_isgraph(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&
(U_GC_CC_MASK|U_GC_CF_MASK|U_GC_CS_MASK|U_GC_CN_MASK|U_GC_Z_MASK))
==0);
}
U_CAPI UBool U_EXPORT2
u_ispunct(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&U_GC_P_MASK)!=0);
}
U_CAPI UBool U_EXPORT2
u_isIDStart(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_NL_MASK))!=0);
}
U_CAPI UBool U_EXPORT2
u_isIDPart(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(
(CAT_MASK(props)&
(U_GC_ND_MASK|U_GC_NL_MASK|
U_GC_L_MASK|
U_GC_PC_MASK|U_GC_MC_MASK|U_GC_MN_MASK)
)!=0 ||
u_isIDIgnorable(c));
}
U_CAPI UBool U_EXPORT2
u_isIDIgnorable(UChar32 c) {
if(c<=0x9f) {
return u_isISOControl(c) && !IS_THAT_CONTROL_SPACE(c);
} else {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(GET_CATEGORY(props)==U_FORMAT_CHAR);
}
}
U_CAPI UBool U_EXPORT2
u_isJavaIDStart(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_SC_MASK|U_GC_PC_MASK))!=0);
}
U_CAPI UBool U_EXPORT2
u_isJavaIDPart(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(
(CAT_MASK(props)&
(U_GC_ND_MASK|U_GC_NL_MASK|
U_GC_L_MASK|
U_GC_SC_MASK|U_GC_PC_MASK|
U_GC_MC_MASK|U_GC_MN_MASK)
)!=0 ||
u_isIDIgnorable(c));
}
U_CAPI UChar32 U_EXPORT2
u_tolower(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(CAT_MASK(props)&(U_GC_LU_MASK|U_GC_LT_MASK)) {
return c+GET_SIGNED_VALUE(props);
}
} else {
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_LOWERCASE)) {
int i=EXC_LOWERCASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
return (UChar32)*pe;
}
}
return c;
}
U_CAPI UChar32 U_EXPORT2
u_toupper(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(GET_CATEGORY(props)==U_LOWERCASE_LETTER) {
return c-GET_SIGNED_VALUE(props);
}
} else {
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_UPPERCASE)) {
int i=EXC_UPPERCASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
return (UChar32)*pe;
}
}
return c;
}
U_CAPI UChar32 U_EXPORT2
u_totitle(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(GET_CATEGORY(props)==U_LOWERCASE_LETTER) {
return c-GET_SIGNED_VALUE(props);
}
} else {
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_TITLECASE)) {
int i=EXC_TITLECASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
return (UChar32)*pe;
} else if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_UPPERCASE)) {
int i=EXC_UPPERCASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
return (UChar32)*pe;
}
}
return c;
}
U_CAPI int32_t U_EXPORT2
u_charDigitValue(UChar32 c) {
uint32_t props, numericType;
GET_PROPS(c, props);
numericType=GET_NUMERIC_TYPE(props);
if(numericType==1) {
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
return GET_SIGNED_VALUE(props);
} else {
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_NUMERIC_VALUE)) {
int i=EXC_NUMERIC_VALUE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
return (int32_t)*pe;
}
}
}
return -1;
}
U_CAPI double U_EXPORT2
u_getNumericValue(UChar32 c) {
uint32_t props, numericType;
GET_PROPS(c, props);
numericType=GET_NUMERIC_TYPE(props);
if(numericType==0 || numericType>=(int32_t)U_NT_COUNT) {
return U_NO_NUMERIC_VALUE;
} else {
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
return GET_SIGNED_VALUE(props);
} else {
const uint32_t *pe;
uint32_t firstExceptionValue;
double numValue;
uint32_t denominator;
pe=GET_EXCEPTIONS(props);
firstExceptionValue=*pe++;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_NUMERIC_VALUE)) {
uint32_t flags=firstExceptionValue;
int i=EXC_NUMERIC_VALUE;
const uint32_t *p=pe;
int32_t numerator;
ADD_EXCEPTION_OFFSET(flags, i, p);
numerator=(int32_t)*p;
if(numerator<0x7fffff00) {
numValue=(double)numerator;
} else {
numerator&=0xff;
numValue=1.;
while(numerator>=4) {
numValue*=10000.;
numerator-=4;
}
switch(numerator) {
case 3:
numValue*=1000.;
break;
case 2:
numValue*=100.;
break;
case 1:
numValue*=10.;
break;
case 0:
default:
break;
}
}
} else {
numValue=0.;
}
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_DENOMINATOR_VALUE)) {
uint32_t flags=firstExceptionValue;
int i=EXC_DENOMINATOR_VALUE;
const uint32_t *p=pe;
ADD_EXCEPTION_OFFSET(flags, i, p);
denominator=*p;
} else {
denominator=0;
}
switch(firstExceptionValue&((1UL<<EXC_NUMERIC_VALUE)|(1UL<<EXC_DENOMINATOR_VALUE))) {
case 1UL<<EXC_NUMERIC_VALUE:
return numValue;
case 1UL<<EXC_DENOMINATOR_VALUE:
return (double)1./(double)denominator;
case (1UL<<EXC_NUMERIC_VALUE)|(1UL<<EXC_DENOMINATOR_VALUE):
return numValue/(double)denominator;
case 0:
default:
return U_NO_NUMERIC_VALUE;
}
}
}
}
U_CAPI UCharDirection U_EXPORT2
u_charDirection(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UCharDirection)GET_BIDI_CLASS(props);
}
U_CAPI UBool U_EXPORT2
u_isMirrored(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
return (UBool)(props&(1UL<<UPROPS_MIRROR_SHIFT) ? TRUE : FALSE);
}
U_CAPI UChar32 U_EXPORT2
u_charMirror(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
if((props&(1UL<<UPROPS_MIRROR_SHIFT))==0) {
return c;
} else if(!PROPS_VALUE_IS_EXCEPTION(props)) {
return c+GET_SIGNED_VALUE(props);
} else {
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_MIRROR_MAPPING)) {
int i=EXC_MIRROR_MAPPING;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
return (UChar32)*pe;
} else {
return c;
}
}
}
U_CAPI int32_t U_EXPORT2
u_digit(UChar32 ch, int8_t radix) {
int8_t value;
if((uint8_t)(radix-2)<=(36-2)) {
value=(int8_t)u_charDigitValue(ch);
if(value<0) {
if(ch>=0x61 && ch<=0x7A) {
value=(int8_t)(ch-0x57);
} else if(ch>=0x41 && ch<=0x5A) {
value=(int8_t)(ch-0x37);
} else if(ch>=0xFF41 && ch<=0xFF5A) {
value=(int8_t)(ch-0xFF37);
} else if(ch>=0xFF21 && ch<=0xFF3A) {
value=(int8_t)(ch-0xFF17);
}
}
} else {
value=-1;
}
return (int8_t)((value<radix) ? value : -1);
}
U_CAPI UChar32 U_EXPORT2
u_forDigit(int32_t digit, int8_t radix) {
if((uint8_t)(radix-2)>(36-2) || (uint32_t)digit>=(uint32_t)radix) {
return 0;
} else if(digit<10) {
return (UChar32)(0x30+digit);
} else {
return (UChar32)((0x61-10)+digit);
}
}
U_CAPI void U_EXPORT2
u_getUnicodeVersion(UVersionInfo versionArray) {
if(versionArray!=NULL) {
if(HAVE_DATA) {
uprv_memcpy(versionArray, dataVersion, U_MAX_VERSION_LENGTH);
} else {
uprv_memset(versionArray, 0, U_MAX_VERSION_LENGTH);
}
}
}
U_CFUNC uint32_t
u_getUnicodeProperties(UChar32 c, int32_t column) {
uint16_t vecIndex;
if(column==-1) {
uint32_t props;
GET_PROPS(c, props);
return props;
} else if( !HAVE_DATA || countPropsVectors==0 ||
(uint32_t)c>0x10ffff ||
column<0 || column>=propsVectorsColumns
) {
return 0;
} else {
UTRIE_GET16(&propsVectorsTrie, c, vecIndex);
return propsVectors[vecIndex+column];
}
}
U_CFUNC int32_t
uprv_getMaxValues(int32_t column) {
if(HAVE_DATA) {
switch(column) {
case 0:
return indexes[UPROPS_MAX_VALUES_INDEX];
case 2:
return indexes[UPROPS_MAX_VALUES_2_INDEX];
default:
return 0;
}
} else {
return 0;
}
}
static UBool U_CALLCONV
_enumPropertyStartsRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
uset_add((USet *)context, start);
return TRUE;
}
#define USET_ADD_CP_AND_NEXT(set, cp) uset_add(set, cp); uset_add(set, cp+1)
U_CAPI void U_EXPORT2
uchar_addPropertyStarts(USet *set, UErrorCode *pErrorCode) {
UChar32 c;
int32_t value, value2;
if(!HAVE_DATA) {
*pErrorCode=dataErrorCode;
return;
}
utrie_enum(&propsTrie, NULL, _enumPropertyStartsRange, set);
utrie_enum(&propsVectorsTrie, NULL, _enumPropertyStartsRange, set);
uset_add(set, TAB);
uset_add(set, CR+1);
uset_add(set, 0x1c);
uset_add(set, 0x1f+1);
USET_ADD_CP_AND_NEXT(set, NL);
uset_add(set, DEL);
uset_add(set, HAIRSP);
uset_add(set, RLM+1);
uset_add(set, INHSWAP);
uset_add(set, NOMDIG+1);
USET_ADD_CP_AND_NEXT(set, ZWNBSP);
USET_ADD_CP_AND_NEXT(set, NBSP);
USET_ADD_CP_AND_NEXT(set, FIGURESP);
USET_ADD_CP_AND_NEXT(set, NNBSP);
USET_ADD_CP_AND_NEXT(set, 0x3007);
USET_ADD_CP_AND_NEXT(set, 0x4e00);
USET_ADD_CP_AND_NEXT(set, 0x4e8c);
USET_ADD_CP_AND_NEXT(set, 0x4e09);
USET_ADD_CP_AND_NEXT(set, 0x56db);
USET_ADD_CP_AND_NEXT(set, 0x4e94);
USET_ADD_CP_AND_NEXT(set, 0x516d);
USET_ADD_CP_AND_NEXT(set, 0x4e03);
USET_ADD_CP_AND_NEXT(set, 0x516b);
USET_ADD_CP_AND_NEXT(set, 0x4e5d);
uset_add(set, U_a);
uset_add(set, U_z+1);
uset_add(set, U_A);
uset_add(set, U_Z+1);
uset_add(set, WJ);
uset_add(set, 0xfff0);
uset_add(set, 0xfffb+1);
uset_add(set, 0xe0000);
uset_add(set, 0xe0fff+1);
USET_ADD_CP_AND_NEXT(set, CGJ);
uset_add(set, ZWNJ);
uset_add(set, ZWJ+1);
uset_add(set, 0x1100);
value=U_HST_LEADING_JAMO;
for(c=0x115a; c<=0x115f; ++c) {
value2=u_getIntPropertyValue(c, UCHAR_HANGUL_SYLLABLE_TYPE);
if(value!=value2) {
value=value2;
uset_add(set, c);
}
}
uset_add(set, 0x1160);
value=U_HST_VOWEL_JAMO;
for(c=0x11a3; c<=0x11a7; ++c) {
value2=u_getIntPropertyValue(c, UCHAR_HANGUL_SYLLABLE_TYPE);
if(value!=value2) {
value=value2;
uset_add(set, c);
}
}
uset_add(set, 0x11a8);
value=U_HST_TRAILING_JAMO;
for(c=0x11fa; c<=0x11ff; ++c) {
value2=u_getIntPropertyValue(c, UCHAR_HANGUL_SYLLABLE_TYPE);
if(value!=value2) {
value=value2;
uset_add(set, c);
}
}
}
#if UCONFIG_NO_NORMALIZATION
static U_INLINE uint8_t
u_getCombiningClass(UChar32 c) {
return 0;
}
#endif
enum {
LOC_ROOT,
LOC_TURKISH,
LOC_LITHUANIAN
};
static int32_t
getCaseLocale(const char *locale) {
char lang[32];
UErrorCode errorCode;
int32_t length;
errorCode=U_ZERO_ERROR;
length=uloc_getLanguage(locale, lang, sizeof(lang), &errorCode);
if(U_FAILURE(errorCode) || length!=2) {
return LOC_ROOT;
}
if( (lang[0]=='t' && lang[1]=='r') ||
(lang[0]=='a' && lang[1]=='z')
) {
return LOC_TURKISH;
} else if(lang[0]=='l' && lang[1]=='t') {
return LOC_LITHUANIAN;
} else {
return LOC_ROOT;
}
}
static U_INLINE UBool
isCaseIgnorable(UChar32 c, uint32_t category) {
return (FLAG(category)&(_Mn|_Me|_Cf|_Lm|_Sk))!=0 ||
c==0x27 || c==0xad || c==0x2019;
}
static U_INLINE UBool
isCased(UChar32 c, uint32_t category) {
return (FLAG(category)&(_Lt|_Lu|_Ll))!=0 ||
(u_getUnicodeProperties(c, 1)&(FLAG(UPROPS_UPPERCASE)|FLAG(UPROPS_LOWERCASE)))!=0;
}
static U_INLINE UBool
isSoftDotted(UChar32 c) {
return (u_getUnicodeProperties(c, 1)&FLAG(UPROPS_SOFT_DOTTED))!=0;
}
static UBool
isFollowedByCasedLetter(UCharIterator *iter, int32_t index) {
volatile uint32_t category;
uint32_t props;
int32_t c;
if(iter==NULL) {
return FALSE;
}
iter->move(iter, index, UITER_ZERO);
for(;;) {
c=uiter_next32(iter);
if(c<0) {
break;
}
GET_PROPS_UNSAFE(c, props);
category=GET_CATEGORY(props);
if(isCased(c, category)) {
return TRUE;
}
if(!isCaseIgnorable(c, category)) {
return FALSE;
}
}
return FALSE;
}
static UBool
isPrecededByCasedLetter(UCharIterator *iter, int32_t index) {
volatile uint32_t category;
uint32_t props;
int32_t c;
if(iter==NULL) {
return FALSE;
}
iter->move(iter, index, UITER_ZERO);
for(;;) {
c=uiter_previous32(iter);
if(c<0) {
break;
}
GET_PROPS_UNSAFE(c, props);
category=GET_CATEGORY(props);
if(isCased(c, category)) {
return TRUE;
}
if(!isCaseIgnorable(c, category)) {
return FALSE;
}
}
return FALSE;
}
static UBool
isPrecededBySoftDotted(UCharIterator *iter, int32_t index) {
int32_t c;
uint8_t cc;
if(iter==NULL) {
return FALSE;
}
iter->move(iter, index, UITER_ZERO);
for(;;) {
c=uiter_previous32(iter);
if(c<0) {
break;
}
if(isSoftDotted(c)) {
return TRUE;
}
cc=u_getCombiningClass(c);
if(cc==0 || cc==230) {
return FALSE;
}
}
return FALSE;
}
static UBool
isPrecededBy_I(UCharIterator *iter, int32_t index) {
int32_t c;
uint8_t cc;
if(iter==NULL) {
return FALSE;
}
iter->move(iter, index, UITER_ZERO);
for(;;) {
c=uiter_previous32(iter);
if(c<0) {
break;
}
if(c==0x49) {
return TRUE;
}
cc=u_getCombiningClass(c);
if(cc==0 || cc==230) {
return FALSE;
}
}
return FALSE;
}
static UBool
isFollowedByMoreAbove(UCharIterator *iter, int32_t index) {
int32_t c;
uint8_t cc;
if(iter==NULL) {
return FALSE;
}
iter->move(iter, index, UITER_ZERO);
for(;;) {
c=uiter_next32(iter);
if(c<0) {
break;
}
cc=u_getCombiningClass(c);
if(cc==230) {
return TRUE;
}
if(cc==0) {
return FALSE;
}
}
return FALSE;
}
static UBool
isFollowedByDotAbove(UCharIterator *iter, int32_t index) {
int32_t c;
uint8_t cc;
if(iter==NULL) {
return FALSE;
}
iter->move(iter, index, UITER_ZERO);
for(;;) {
c=uiter_next32(iter);
if(c<0) {
break;
}
if(c==0x307) {
return TRUE;
}
cc=u_getCombiningClass(c);
if(cc==0 || cc==230) {
return FALSE;
}
}
return FALSE;
}
U_CAPI int32_t U_EXPORT2
u_internalToLower(UChar32 c, UCharIterator *iter,
UChar *dest, int32_t destCapacity,
const char *locale) {
UChar buffer[8];
uint32_t props;
UChar32 result;
int32_t i, length;
result=c;
GET_PROPS(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(CAT_MASK(props)&(U_GC_LU_MASK|U_GC_LT_MASK)) {
result=c+GET_SIGNED_VALUE(props);
}
} else {
const UChar *u;
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe, specialCasing;
int32_t minLength;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_SPECIAL_CASING)) {
i=EXC_SPECIAL_CASING;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
specialCasing=*pe;
if(specialCasing&0x80000000) {
int32_t loc=getCaseLocale(locale),
srcIndex= iter!=NULL ? iter->getIndex(iter, UITER_CURRENT) : 0;
if( loc==LOC_LITHUANIAN &&
(((c==0x49 || c==0x4a || c==0x12e) &&
isFollowedByMoreAbove(iter, srcIndex)) ||
(c==0xcc || c==0xcd || c==0x128))
) {
u=buffer;
buffer[1]=0x307;
switch(c) {
case 0x49:
buffer[0]=0x69;
length=2;
break;
case 0x4a:
buffer[0]=0x6a;
length=2;
break;
case 0x12e:
buffer[0]=0x12f;
length=2;
break;
case 0xcc:
buffer[0]=0x69;
buffer[2]=0x300;
length=3;
break;
case 0xcd:
buffer[0]=0x69;
buffer[2]=0x301;
length=3;
break;
case 0x128:
buffer[0]=0x69;
buffer[2]=0x303;
length=3;
break;
default:
return 0;
}
} else if(loc==LOC_TURKISH && c==0x130) {
result=0x69;
goto single;
} else if(loc==LOC_TURKISH && c==0x307 && isPrecededBy_I(iter, srcIndex-1)) {
return 0;
} else if(loc==LOC_TURKISH && c==0x49 && !isFollowedByDotAbove(iter, srcIndex)) {
result=0x131;
goto single;
} else if(c==0x130) {
static const UChar iWithDot[2]={ 0x69, 0x307 };
u=iWithDot;
length=2;
} else if( c==0x3a3 &&
!isFollowedByCasedLetter(iter, srcIndex) &&
isPrecededByCasedLetter(iter, srcIndex-1)
) {
result=0x3c2;
goto single;
} else {
pe=GET_EXCEPTIONS(props);
firstExceptionValue=*pe;
goto notSpecial;
}
} else {
u=ucharsTable+(specialCasing&0xffff);
length=(int32_t)((*u++)&0x1f);
}
minLength = (length < destCapacity) ? length : destCapacity;
i=0;
while(i<minLength) {
dest[i++]=*u++;
}
return length;
}
notSpecial:
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_LOWERCASE)) {
i=EXC_LOWERCASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
result=(UChar32)*pe;
}
}
single:
length=UTF_CHAR_LENGTH(result);
if(length<=destCapacity) {
i=0;
UTF_APPEND_CHAR_UNSAFE(dest, i, result);
}
return (result==c) ? -length : length;
}
U_CFUNC int32_t
u_internalStrToLower(UChar *dest, int32_t destCapacity,
const UChar *src, int32_t srcLength,
int32_t srcStart, int32_t srcLimit,
const char *locale,
UErrorCode *pErrorCode) {
UCharIterator iter;
uint32_t props;
int32_t srcIndex, destIndex;
UChar32 c;
if(!HAVE_DATA) {
*pErrorCode=U_FILE_ACCESS_ERROR;
return 0;
}
uiter_setString(&iter, src, srcLength);
srcIndex=srcStart;
destIndex=0;
while(srcIndex<srcLimit) {
UTF_NEXT_CHAR(src, srcIndex, srcLimit, c);
GET_PROPS_UNSAFE(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(CAT_MASK(props)&(U_GC_LU_MASK|U_GC_LT_MASK)) {
c+=GET_SIGNED_VALUE(props);
}
if(c<=0xffff) {
if(destIndex<destCapacity) {
dest[destIndex++]=(UChar)c;
} else {
++destIndex;
}
} else {
if((destIndex+2)<=destCapacity) {
dest[destIndex++]=UTF16_LEAD(c);
dest[destIndex++]=UTF16_TRAIL(c);
} else {
if(destIndex<destCapacity) {
dest[destIndex]=UTF16_LEAD(c);
}
destIndex+=2;
}
}
} else {
int32_t length;
iter.move(&iter, srcIndex, UITER_ZERO);
if(destIndex<destCapacity) {
length=u_internalToLower(c, &iter, dest+destIndex, destCapacity-destIndex, locale);
} else {
length=u_internalToLower(c, &iter, NULL, 0, locale);
}
if(length<0) {
length=-length;
}
destIndex+=length;
}
}
if(destIndex>destCapacity) {
*pErrorCode=U_BUFFER_OVERFLOW_ERROR;
}
return destIndex;
}
static int32_t
u_internalToUpperOrTitle(UChar32 c, UCharIterator *iter,
UChar *dest, int32_t destCapacity,
const char *locale,
UBool upperNotTitle) {
uint32_t props;
UChar32 result;
int32_t i, length;
result=c;
GET_PROPS(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(GET_CATEGORY(props)==U_LOWERCASE_LETTER) {
result=c-GET_SIGNED_VALUE(props);
}
} else {
const UChar *u;
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe, specialCasing;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_SPECIAL_CASING)) {
i=EXC_SPECIAL_CASING;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
specialCasing=*pe;
if(specialCasing&0x80000000) {
int32_t loc=getCaseLocale(locale),
srcIndex= iter!=NULL ? iter->getIndex(iter, UITER_CURRENT) : 0;
if(loc==LOC_TURKISH && c==0x69) {
result=0x130;
goto single;
} else if(loc==LOC_LITHUANIAN && c==0x307 && isPrecededBySoftDotted(iter, srcIndex-1)) {
return 0;
} else {
pe=GET_EXCEPTIONS(props);
firstExceptionValue=*pe;
goto notSpecial;
}
} else {
u=ucharsTable+(specialCasing&0xffff);
length=(int32_t)*u++;
u+=length&0x1f;
if(upperNotTitle) {
length=(length>>5)&0x1f;
} else {
u+=(length>>5)&0x1f;
length=(length>>10)&0x1f;
}
}
i=0;
while(i<length && i<destCapacity) {
dest[i++]=*u++;
}
return length;
}
notSpecial:
if(!upperNotTitle && HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_TITLECASE)) {
i=EXC_TITLECASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
result=(UChar32)*pe;
} else if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_UPPERCASE)) {
i=EXC_UPPERCASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
result=(UChar32)*pe;
}
}
single:
length=UTF_CHAR_LENGTH(result);
if(length<=destCapacity) {
i=0;
UTF_APPEND_CHAR_UNSAFE(dest, i, result);
}
return (result==c) ? -length : length;
}
U_CAPI int32_t U_EXPORT2
u_internalToUpper(UChar32 c, UCharIterator *iter,
UChar *dest, int32_t destCapacity,
const char *locale) {
return u_internalToUpperOrTitle(c, iter, dest, destCapacity, locale, TRUE);
}
U_CFUNC int32_t
u_internalStrToUpper(UChar *dest, int32_t destCapacity,
const UChar *src, int32_t srcLength,
const char *locale,
UErrorCode *pErrorCode) {
UCharIterator iter;
uint32_t props;
int32_t srcIndex, destIndex;
UChar32 c;
if(!HAVE_DATA) {
*pErrorCode=U_FILE_ACCESS_ERROR;
return 0;
}
uiter_setString(&iter, src, srcLength);
srcIndex=destIndex=0;
while(srcIndex<srcLength) {
UTF_NEXT_CHAR(src, srcIndex, srcLength, c);
GET_PROPS_UNSAFE(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(GET_CATEGORY(props)==U_LOWERCASE_LETTER) {
c-=GET_SIGNED_VALUE(props);
}
if(c<=0xffff) {
if(destIndex<destCapacity) {
dest[destIndex++]=(UChar)c;
} else {
++destIndex;
}
} else {
if((destIndex+2)<=destCapacity) {
dest[destIndex++]=UTF16_LEAD(c);
dest[destIndex++]=UTF16_TRAIL(c);
} else {
if(destIndex<destCapacity) {
dest[destIndex]=UTF16_LEAD(c);
}
destIndex+=2;
}
}
} else {
int32_t length;
iter.move(&iter, srcIndex, UITER_ZERO);
if(destIndex<destCapacity) {
length=u_internalToUpperOrTitle(c, &iter, dest+destIndex, destCapacity-destIndex, locale, TRUE);
} else {
length=u_internalToUpperOrTitle(c, &iter, NULL, 0, locale, TRUE);
}
if(length<0) {
length=-length;
}
destIndex+=length;
}
}
if(destIndex>destCapacity) {
*pErrorCode=U_BUFFER_OVERFLOW_ERROR;
}
return destIndex;
}
U_CAPI int32_t U_EXPORT2
u_internalToTitle(UChar32 c, UCharIterator *iter,
UChar *dest, int32_t destCapacity,
const char *locale) {
return u_internalToUpperOrTitle(c, iter, dest, destCapacity, locale, FALSE);
}
U_CAPI UChar32 U_EXPORT2
u_foldCase(UChar32 c, uint32_t options) {
uint32_t props;
GET_PROPS(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(CAT_MASK(props)&(U_GC_LU_MASK|U_GC_LT_MASK)) {
return c+GET_SIGNED_VALUE(props);
}
} else {
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_CASE_FOLDING)) {
const uint32_t *oldPE=pe;
int i=EXC_CASE_FOLDING;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
props=*pe;
if(props!=0) {
const UChar *uchars=ucharsTable+(props&0xffff);
UChar32 simple;
i=0;
UTF_NEXT_CHAR_UNSAFE(uchars, i, simple);
if(simple!=0) {
return simple;
}
pe=oldPE;
} else {
if((options&_FOLD_CASE_OPTIONS_MASK)==U_FOLD_CASE_DEFAULT) {
if(c==0x49) {
return 0x69;
} else if(c==0x130) {
return 0x69;
}
} else {
if(c==0x49) {
return 0x131;
} else if(c==0x130) {
return 0x69;
}
}
return c;
}
}
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_LOWERCASE)) {
int i=EXC_LOWERCASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
return (UChar32)*pe;
}
}
return c;
}
U_CAPI int32_t U_EXPORT2
u_internalFoldCase(UChar32 c,
UChar *dest, int32_t destCapacity,
uint32_t options) {
uint32_t props;
UChar32 result;
int32_t i, length;
result=c;
GET_PROPS_UNSAFE(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(CAT_MASK(props)&(U_GC_LU_MASK|U_GC_LT_MASK)) {
result=c+GET_SIGNED_VALUE(props);
}
} else {
const uint32_t *pe=GET_EXCEPTIONS(props);
uint32_t firstExceptionValue=*pe;
if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_CASE_FOLDING)) {
i=EXC_CASE_FOLDING;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
props=*pe;
if(props!=0) {
const UChar *uchars=ucharsTable+(props&0xffff)+2;
int32_t minLength;
length=props>>24;
minLength = (length < destCapacity) ? length : destCapacity;
i=0;
while(i<minLength) {
dest[i++]=*(uchars++);
}
return length;
} else {
if((options&_FOLD_CASE_OPTIONS_MASK)==U_FOLD_CASE_DEFAULT) {
if(c==0x49) {
result=0x69;
} else if(c==0x130) {
if(0<destCapacity) {
dest[0]=0x69;
}
if(1<destCapacity) {
dest[1]=0x307;
}
return 2;
}
} else {
if(c==0x49) {
result=0x131;
} else if(c==0x130) {
result=0x69;
}
}
}
} else if(HAVE_EXCEPTION_VALUE(firstExceptionValue, EXC_LOWERCASE)) {
i=EXC_LOWERCASE;
++pe;
ADD_EXCEPTION_OFFSET(firstExceptionValue, i, pe);
result=(UChar32)*pe;
}
}
length=UTF_CHAR_LENGTH(result);
if(length<=destCapacity) {
i=0;
UTF_APPEND_CHAR_UNSAFE(dest, i, result);
}
return (result==c) ? -length : length;
}
U_CFUNC int32_t
u_internalStrFoldCase(UChar *dest, int32_t destCapacity,
const UChar *src, int32_t srcLength,
uint32_t options,
UErrorCode *pErrorCode) {
uint32_t props;
int32_t srcIndex, destIndex;
UChar32 c;
if(!HAVE_DATA) {
*pErrorCode=U_FILE_ACCESS_ERROR;
return 0;
}
srcIndex=destIndex=0;
while(srcIndex<srcLength) {
UTF_NEXT_CHAR(src, srcIndex, srcLength, c);
GET_PROPS_UNSAFE(c, props);
if(!PROPS_VALUE_IS_EXCEPTION(props)) {
if(CAT_MASK(props)&(U_GC_LU_MASK|U_GC_LT_MASK)) {
c+=GET_SIGNED_VALUE(props);
}
if(c<=0xffff) {
if(destIndex<destCapacity) {
dest[destIndex++]=(UChar)c;
} else {
++destIndex;
}
} else {
if((destIndex+2)<=destCapacity) {
dest[destIndex++]=UTF16_LEAD(c);
dest[destIndex++]=UTF16_TRAIL(c);
} else {
if(destIndex<destCapacity) {
dest[destIndex]=UTF16_LEAD(c);
}
destIndex+=2;
}
}
} else {
int32_t length;
if(destIndex<destCapacity) {
length=u_internalFoldCase(c, dest+destIndex, destCapacity-destIndex, options);
} else {
length=u_internalFoldCase(c, NULL, 0, options);
}
if(length<0) {
length=-length;
}
destIndex+=length;
}
}
if(destIndex>destCapacity) {
*pErrorCode=U_BUFFER_OVERFLOW_ERROR;
}
return destIndex;
}