#include "unicode/utypes.h"
#include "unicode/uset.h"
#include "unicode/udata.h"
#include "ucmndata.h"
#include "udatamem.h"
#include "umutex.h"
#include "uassert.h"
#include "cmemory.h"
#include "utrie.h"
#include "ucase.h"
#include "ucln_cmn.h"
struct UCaseProps {
UDataMemory *mem;
const int32_t *indexes;
const uint16_t *exceptions;
UTrie trie;
uint8_t formatVersion[4];
};
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]==UCASE_FMT_0 &&
pInfo->dataFormat[1]==UCASE_FMT_1 &&
pInfo->dataFormat[2]==UCASE_FMT_2 &&
pInfo->dataFormat[3]==UCASE_FMT_3 &&
pInfo->formatVersion[0]==1 &&
pInfo->formatVersion[2]==UTRIE_SHIFT &&
pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
) {
UCaseProps *csp=(UCaseProps *)context;
uprv_memcpy(csp->formatVersion, pInfo->formatVersion, 4);
return TRUE;
} else {
return FALSE;
}
}
static UCaseProps *
ucase_openData(UCaseProps *cspProto,
const uint8_t *bin, int32_t length, UErrorCode *pErrorCode) {
UCaseProps *csp;
int32_t size, trieSize;
cspProto->indexes=(const int32_t *)bin;
if( cspProto->indexes[UCASE_IX_INDEX_TOP]<16 ||
(length>=0 && length<cspProto->indexes[UCASE_IX_LENGTH])
) {
*pErrorCode=U_INVALID_FORMAT_ERROR;
return NULL;
}
size=cspProto->indexes[UCASE_IX_INDEX_TOP]*4;
bin+=size;
if(length>=0 && (length-=size)<16) {
*pErrorCode=U_INVALID_FORMAT_ERROR;
return NULL;
}
trieSize=cspProto->indexes[UCASE_IX_TRIE_SIZE];
trieSize=utrie_unserialize(&cspProto->trie, bin, length>=0 ? length : trieSize, pErrorCode);
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
bin+=trieSize;
if(length>=0 && (length-=trieSize)<2*cspProto->indexes[UCASE_IX_EXC_LENGTH]) {
*pErrorCode=U_INVALID_FORMAT_ERROR;
return NULL;
}
cspProto->exceptions=(const uint16_t *)bin;
csp=(UCaseProps *)uprv_malloc(sizeof(UCaseProps));
if(csp==NULL) {
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
return NULL;
} else {
uprv_memcpy(csp, cspProto, sizeof(UCaseProps));
return csp;
}
}
U_CAPI UCaseProps * U_EXPORT2
ucase_open(UErrorCode *pErrorCode) {
UCaseProps cspProto={ NULL }, *csp;
cspProto.mem=udata_openChoice(NULL, UCASE_DATA_TYPE, UCASE_DATA_NAME, isAcceptable, &cspProto, pErrorCode);
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
csp=ucase_openData(
&cspProto,
udata_getMemory(cspProto.mem),
udata_getLength(cspProto.mem),
pErrorCode);
if(U_FAILURE(*pErrorCode)) {
udata_close(cspProto.mem);
return NULL;
} else {
return csp;
}
}
U_CAPI UCaseProps * U_EXPORT2
ucase_openBinary(const uint8_t *bin, int32_t length, UErrorCode *pErrorCode) {
UCaseProps cspProto={ NULL };
const DataHeader *hdr;
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
if(bin==NULL) {
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
if(length>=0 && length<20) {
*pErrorCode=U_INVALID_FORMAT_ERROR;
return NULL;
}
hdr=(const DataHeader *)bin;
if(
!(hdr->dataHeader.magic1==0xda && hdr->dataHeader.magic2==0x27 &&
hdr->info.isBigEndian==U_IS_BIG_ENDIAN &&
isAcceptable(&cspProto, UCASE_DATA_TYPE, UCASE_DATA_NAME, &hdr->info))
) {
*pErrorCode=U_INVALID_FORMAT_ERROR;
return NULL;
}
bin+=hdr->dataHeader.headerSize;
if(length>=0) {
length-=hdr->dataHeader.headerSize;
}
return ucase_openData(&cspProto, bin, length, pErrorCode);
}
U_CAPI void U_EXPORT2
ucase_close(UCaseProps *csp) {
if(csp!=NULL) {
udata_close(csp->mem);
uprv_free(csp);
}
}
static UCaseProps *gCsp=NULL;
static UErrorCode gErrorCode=U_ZERO_ERROR;
static int8_t gHaveData=0;
static UBool U_CALLCONV ucase_cleanup(void) {
ucase_close(gCsp);
gCsp=NULL;
gErrorCode=U_ZERO_ERROR;
gHaveData=0;
return TRUE;
}
U_CAPI UCaseProps * U_EXPORT2
ucase_getSingleton(UErrorCode *pErrorCode) {
int8_t haveData;
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
UMTX_CHECK(NULL, gHaveData, haveData);
if(haveData>0) {
return gCsp;
} else if(haveData<0) {
*pErrorCode=gErrorCode;
return NULL;
} else {
UCaseProps *csp=ucase_open(pErrorCode);
if(U_FAILURE(*pErrorCode)) {
gHaveData=-1;
gErrorCode=*pErrorCode;
return NULL;
}
umtx_lock(NULL);
if(gCsp==NULL) {
gCsp=csp;
csp=NULL;
gHaveData=1;
ucln_common_registerCleanup(UCLN_COMMON_UCASE, ucase_cleanup);
}
umtx_unlock(NULL);
ucase_close(csp);
return gCsp;
}
}
U_CAPI int32_t U_EXPORT2
ucase_swap(const UDataSwapper *ds,
const void *inData, int32_t length, void *outData,
UErrorCode *pErrorCode) {
const UDataInfo *pInfo;
int32_t headerSize;
const uint8_t *inBytes;
uint8_t *outBytes;
const int32_t *inIndexes;
int32_t indexes[16];
int32_t i, offset, count, size;
headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
return 0;
}
pInfo=(const UDataInfo *)((const char *)inData+4);
if(!(
pInfo->dataFormat[0]==UCASE_FMT_0 &&
pInfo->dataFormat[1]==UCASE_FMT_1 &&
pInfo->dataFormat[2]==UCASE_FMT_2 &&
pInfo->dataFormat[3]==UCASE_FMT_3 &&
pInfo->formatVersion[0]==1 &&
pInfo->formatVersion[2]==UTRIE_SHIFT &&
pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
)) {
udata_printError(ds, "ucase_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as case mapping data\n",
pInfo->dataFormat[0], pInfo->dataFormat[1],
pInfo->dataFormat[2], pInfo->dataFormat[3],
pInfo->formatVersion[0]);
*pErrorCode=U_UNSUPPORTED_ERROR;
return 0;
}
inBytes=(const uint8_t *)inData+headerSize;
outBytes=(uint8_t *)outData+headerSize;
inIndexes=(const int32_t *)inBytes;
if(length>=0) {
length-=headerSize;
if(length<16*4) {
udata_printError(ds, "ucase_swap(): too few bytes (%d after header) for case mapping data\n",
length);
*pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
return 0;
}
}
for(i=0; i<16; ++i) {
indexes[i]=udata_readInt32(ds, inIndexes[i]);
}
size=indexes[UCASE_IX_LENGTH];
if(length>=0) {
if(length<size) {
udata_printError(ds, "ucase_swap(): too few bytes (%d after header) for all of case mapping data\n",
length);
*pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
return 0;
}
if(inBytes!=outBytes) {
uprv_memcpy(outBytes, inBytes, size);
}
offset=0;
count=indexes[UCASE_IX_INDEX_TOP]*4;
ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
offset+=count;
count=indexes[UCASE_IX_TRIE_SIZE];
utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
offset+=count;
count=indexes[UCASE_IX_EXC_LENGTH]*2;
ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
offset+=count;
U_ASSERT(offset==size);
}
return headerSize+size;
}
static UBool U_CALLCONV
_enumPropertyStartsRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
USetAdder *sa=(USetAdder *)context;
sa->add(sa->set, start);
return TRUE;
}
U_CAPI void U_EXPORT2
ucase_addPropertyStarts(const UCaseProps *csp, USetAdder *sa, UErrorCode *pErrorCode) {
if(U_FAILURE(*pErrorCode)) {
return;
}
utrie_enum(&csp->trie, NULL, _enumPropertyStartsRange, sa);
}
#define GET_PROPS(csp, c, result) \
UTRIE_GET16(&(csp)->trie, c, result);
#define GET_CASE_TYPE(props) ((props)&UCASE_TYPE_MASK)
#define GET_SIGNED_DELTA(props) ((int16_t)(props)>>UCASE_DELTA_SHIFT)
#define GET_EXCEPTIONS(csp, props) ((csp)->exceptions+((props)>>UCASE_EXC_SHIFT))
#define PROPS_HAS_EXCEPTION(props) ((props)&UCASE_EXCEPTION)
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 HAS_SLOT(flags, index) ((flags)&(1<<(index)))
#define SLOT_OFFSET(flags, index) flagsOffset[(flags)&((1<<(index))-1)]
#define GET_SLOT_VALUE(excWord, index, pExc16, value) \
if(((excWord)&UCASE_EXC_DOUBLE_SLOTS)==0) { \
(pExc16)+=SLOT_OFFSET(excWord, index); \
(value)=*pExc16; \
} else { \
(pExc16)+=2*SLOT_OFFSET(excWord, index); \
(value)=*pExc16++; \
(value)=((value)<<16)|*pExc16; \
}
U_CAPI UChar32 U_EXPORT2
ucase_tolower(const UCaseProps *csp, UChar32 c) {
uint16_t props;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(GET_CASE_TYPE(props)>=UCASE_UPPER) {
c+=GET_SIGNED_DELTA(props);
}
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props);
uint16_t excWord=*pe++;
if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
GET_SLOT_VALUE(excWord, UCASE_EXC_LOWER, pe, c);
}
}
return c;
}
U_CAPI UChar32 U_EXPORT2
ucase_toupper(const UCaseProps *csp, UChar32 c) {
uint16_t props;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(GET_CASE_TYPE(props)==UCASE_LOWER) {
c+=GET_SIGNED_DELTA(props);
}
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props);
uint16_t excWord=*pe++;
if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) {
GET_SLOT_VALUE(excWord, UCASE_EXC_UPPER, pe, c);
}
}
return c;
}
U_CAPI UChar32 U_EXPORT2
ucase_totitle(const UCaseProps *csp, UChar32 c) {
uint16_t props;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(GET_CASE_TYPE(props)==UCASE_LOWER) {
c+=GET_SIGNED_DELTA(props);
}
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props);
uint16_t excWord=*pe++;
int32_t index;
if(HAS_SLOT(excWord, UCASE_EXC_TITLE)) {
index=UCASE_EXC_TITLE;
} else if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) {
index=UCASE_EXC_UPPER;
} else {
return c;
}
GET_SLOT_VALUE(excWord, index, pe, c);
}
return c;
}
U_CAPI int32_t U_EXPORT2
ucase_getType(const UCaseProps *csp, UChar32 c) {
uint16_t props;
GET_PROPS(csp, c, props);
return GET_CASE_TYPE(props);
}
U_CAPI int32_t U_EXPORT2
ucase_getTypeOrIgnorable(const UCaseProps *csp, UChar32 c) {
int32_t type;
uint16_t props;
GET_PROPS(csp, c, props);
type=GET_CASE_TYPE(props);
if(type!=UCASE_NONE) {
return type;
} else if(
c==0x307 ||
(props&(UCASE_EXCEPTION|UCASE_CASE_IGNORABLE))==UCASE_CASE_IGNORABLE
) {
return -1;
} else {
return 0;
}
}
static U_INLINE int32_t
getDotType(const UCaseProps *csp, UChar32 c) {
uint16_t props;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
return props&UCASE_DOT_MASK;
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props);
return (*pe>>UCASE_EXC_DOT_SHIFT)&UCASE_DOT_MASK;
}
}
U_CAPI UBool U_EXPORT2
ucase_isSoftDotted(const UCaseProps *csp, UChar32 c) {
return (UBool)(getDotType(csp, c)==UCASE_SOFT_DOTTED);
}
U_CAPI UBool U_EXPORT2
ucase_isCaseSensitive(const UCaseProps *csp, UChar32 c) {
uint16_t props;
GET_PROPS(csp, c, props);
return (UBool)((props&UCASE_SENSITIVE)!=0);
}
U_CAPI UBool U_EXPORT2
u_isULowercase(UChar32 c) {
UErrorCode errorCode=U_ZERO_ERROR;
UCaseProps *csp=ucase_getSingleton(&errorCode);
return (UBool)(csp!=NULL && UCASE_LOWER==ucase_getType(csp, c));
}
U_CAPI UBool U_EXPORT2
u_isUUppercase(UChar32 c) {
UErrorCode errorCode=U_ZERO_ERROR;
UCaseProps *csp=ucase_getSingleton(&errorCode);
return (UBool)(csp!=NULL && UCASE_UPPER==ucase_getType(csp, c));
}
U_CAPI UChar32 U_EXPORT2
u_tolower(UChar32 c) {
UErrorCode errorCode=U_ZERO_ERROR;
UCaseProps *csp=ucase_getSingleton(&errorCode);
if(csp!=NULL) {
return ucase_tolower(csp, c);
} else {
return c;
}
}
U_CAPI UChar32 U_EXPORT2
u_toupper(UChar32 c) {
UErrorCode errorCode=U_ZERO_ERROR;
UCaseProps *csp=ucase_getSingleton(&errorCode);
if(csp!=NULL) {
return ucase_toupper(csp, c);
} else {
return c;
}
}
U_CAPI UChar32 U_EXPORT2
u_totitle(UChar32 c) {
UErrorCode errorCode=U_ZERO_ERROR;
UCaseProps *csp=ucase_getSingleton(&errorCode);
if(csp!=NULL) {
return ucase_totitle(csp, c);
} else {
return c;
}
}
U_CAPI UChar32 U_EXPORT2
u_foldCase(UChar32 c, uint32_t options) {
UErrorCode errorCode=U_ZERO_ERROR;
UCaseProps *csp=ucase_getSingleton(&errorCode);
if(csp!=NULL) {
return ucase_fold(csp, c, options);
} else {
return c;
}
}
enum {
LOC_UNKNOWN,
LOC_ROOT,
LOC_TURKISH,
LOC_LITHUANIAN
};
#define is_a(c) ((c)=='a' || (c)=='A')
#define is_e(c) ((c)=='e' || (c)=='E')
#define is_i(c) ((c)=='i' || (c)=='I')
#define is_l(c) ((c)=='l' || (c)=='L')
#define is_r(c) ((c)=='r' || (c)=='R')
#define is_t(c) ((c)=='t' || (c)=='T')
#define is_u(c) ((c)=='u' || (c)=='U')
#define is_z(c) ((c)=='z' || (c)=='Z')
#define is_sep(c) ((c)=='_' || (c)=='-' || (c)==0)
static int32_t
getCaseLocale(const char *locale, int32_t *locCache) {
int32_t result;
char c;
if(locCache!=NULL && (result=*locCache)!=LOC_UNKNOWN) {
return result;
}
result=LOC_ROOT;
c=*locale++;
if(is_t(c)) {
c=*locale++;
if(is_u(c)) {
c=*locale++;
}
if(is_r(c)) {
c=*locale;
if(is_sep(c)) {
result=LOC_TURKISH;
}
}
} else if(is_a(c)) {
c=*locale++;
if(is_z(c)) {
c=*locale++;
if(is_e(c)) {
c=*locale;
}
if(is_sep(c)) {
result=LOC_TURKISH;
}
}
} else if(is_l(c)) {
c=*locale++;
if(is_i(c)) {
c=*locale++;
}
if(is_t(c)) {
c=*locale;
if(is_sep(c)) {
result=LOC_LITHUANIAN;
}
}
}
if(locCache!=NULL) {
*locCache=result;
}
return result;
}
static UBool
isFollowedByCasedLetter(const UCaseProps *csp, UCaseContextIterator *iter, void *context, int8_t dir) {
UChar32 c;
uint16_t props;
if(iter==NULL) {
return FALSE;
}
for(; (c=iter(context, dir))>=0; dir=0) {
GET_PROPS(csp, c, props);
if(GET_CASE_TYPE(props)!=UCASE_NONE) {
return TRUE;
} else if(c==0x307 || (props&(UCASE_EXCEPTION|UCASE_CASE_IGNORABLE))==UCASE_CASE_IGNORABLE) {
} else {
return FALSE;
}
}
return FALSE;
}
static UBool
isPrecededBySoftDotted(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
UChar32 c;
int32_t dotType;
int8_t dir;
if(iter==NULL) {
return FALSE;
}
for(dir=-1; (c=iter(context, dir))>=0; dir=0) {
dotType=getDotType(csp, c);
if(dotType==UCASE_SOFT_DOTTED) {
return TRUE;
} else if(dotType!=UCASE_OTHER_ACCENT) {
return FALSE;
}
}
return FALSE;
}
static UBool
isPrecededBy_I(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
UChar32 c;
int32_t dotType;
int8_t dir;
if(iter==NULL) {
return FALSE;
}
for(dir=-1; (c=iter(context, dir))>=0; dir=0) {
if(c==0x49) {
return TRUE;
}
dotType=getDotType(csp, c);
if(dotType!=UCASE_OTHER_ACCENT) {
return FALSE;
}
}
return FALSE;
}
static UBool
isFollowedByMoreAbove(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
UChar32 c;
int32_t dotType;
int8_t dir;
if(iter==NULL) {
return FALSE;
}
for(dir=1; (c=iter(context, dir))>=0; dir=0) {
dotType=getDotType(csp, c);
if(dotType==UCASE_ABOVE) {
return TRUE;
} else if(dotType!=UCASE_OTHER_ACCENT) {
return FALSE;
}
}
return FALSE;
}
static UBool
isFollowedByDotAbove(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
UChar32 c;
int32_t dotType;
int8_t dir;
if(iter==NULL) {
return FALSE;
}
for(dir=1; (c=iter(context, dir))>=0; dir=0) {
if(c==0x307) {
return TRUE;
}
dotType=getDotType(csp, c);
if(dotType!=UCASE_OTHER_ACCENT) {
return FALSE;
}
}
return FALSE;
}
U_CAPI int32_t U_EXPORT2
ucase_toFullLower(const UCaseProps *csp, UChar32 c,
UCaseContextIterator *iter, void *context,
const UChar **pString,
const char *locale, int32_t *locCache) {
static const UChar
iDot[2]= { 0x69, 0x307 },
jDot[2]= { 0x6a, 0x307 },
iOgonekDot[3]= { 0x12f, 0x307 },
iDotGrave[3]= { 0x69, 0x307, 0x300 },
iDotAcute[3]= { 0x69, 0x307, 0x301 },
iDotTilde[3]= { 0x69, 0x307, 0x303 };
UChar32 result;
uint16_t props;
result=c;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(GET_CASE_TYPE(props)>=UCASE_UPPER) {
result=c+GET_SIGNED_DELTA(props);
}
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props), *pe2;
uint16_t excWord=*pe++;
int32_t full;
pe2=pe;
if(excWord&UCASE_EXC_CONDITIONAL_SPECIAL) {
int32_t loc=getCaseLocale(locale, locCache);
if( loc==LOC_LITHUANIAN &&
(((c==0x49 || c==0x4a || c==0x12e) &&
isFollowedByMoreAbove(csp, iter, context)) ||
(c==0xcc || c==0xcd || c==0x128))
) {
switch(c) {
case 0x49:
*pString=iDot;
return 2;
case 0x4a:
*pString=jDot;
return 2;
case 0x12e:
*pString=iOgonekDot;
return 2;
case 0xcc:
*pString=iDotGrave;
return 3;
case 0xcd:
*pString=iDotAcute;
return 3;
case 0x128:
*pString=iDotTilde;
return 3;
default:
return 0;
}
} else if(loc==LOC_TURKISH && c==0x130) {
return 0x69;
} else if(loc==LOC_TURKISH && c==0x307 && isPrecededBy_I(csp, iter, context)) {
return 0;
} else if(loc==LOC_TURKISH && c==0x49 && !isFollowedByDotAbove(csp, iter, context)) {
return 0x131;
} else if(c==0x130) {
*pString=iDot;
return 2;
} else if( c==0x3a3 &&
!isFollowedByCasedLetter(csp, iter, context, 1) &&
isFollowedByCasedLetter(csp, iter, context, -1)
) {
return 0x3c2;
} else {
}
} else if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, full);
full&=UCASE_FULL_LOWER;
if(full!=0) {
*pString=pe+1;
return full;
}
}
if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
GET_SLOT_VALUE(excWord, UCASE_EXC_LOWER, pe2, result);
}
}
return (result==c) ? ~result : result;
}
static int32_t
toUpperOrTitle(const UCaseProps *csp, UChar32 c,
UCaseContextIterator *iter, void *context,
const UChar **pString,
const char *locale, int32_t *locCache,
UBool upperNotTitle) {
UChar32 result;
uint16_t props;
result=c;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(GET_CASE_TYPE(props)==UCASE_LOWER) {
result=c+GET_SIGNED_DELTA(props);
}
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props), *pe2;
uint16_t excWord=*pe++;
int32_t full, index;
pe2=pe;
if(excWord&UCASE_EXC_CONDITIONAL_SPECIAL) {
int32_t loc=getCaseLocale(locale, locCache);
if(loc==LOC_TURKISH && c==0x69) {
return 0x130;
} else if(loc==LOC_LITHUANIAN && c==0x307 && isPrecededBySoftDotted(csp, iter, context)) {
return 0;
} else {
}
} else if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, full);
++pe;
pe+=full&UCASE_FULL_LOWER;
full>>=4;
pe+=full&0xf;
full>>=4;
if(upperNotTitle) {
full&=0xf;
} else {
pe+=full&0xf;
full=(full>>4)&0xf;
}
if(full!=0) {
*pString=pe;
return full;
}
}
if(!upperNotTitle && HAS_SLOT(excWord, UCASE_EXC_TITLE)) {
index=UCASE_EXC_TITLE;
} else if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) {
index=UCASE_EXC_UPPER;
} else {
return ~c;
}
GET_SLOT_VALUE(excWord, index, pe2, result);
}
return (result==c) ? ~result : result;
}
U_CAPI int32_t U_EXPORT2
ucase_toFullUpper(const UCaseProps *csp, UChar32 c,
UCaseContextIterator *iter, void *context,
const UChar **pString,
const char *locale, int32_t *locCache) {
return toUpperOrTitle(csp, c, iter, context, pString, locale, locCache, TRUE);
}
U_CAPI int32_t U_EXPORT2
ucase_toFullTitle(const UCaseProps *csp, UChar32 c,
UCaseContextIterator *iter, void *context,
const UChar **pString,
const char *locale, int32_t *locCache) {
return toUpperOrTitle(csp, c, iter, context, pString, locale, locCache, FALSE);
}
U_CAPI UChar32 U_EXPORT2
ucase_fold(UCaseProps *csp, UChar32 c, uint32_t options) {
uint16_t props;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(GET_CASE_TYPE(props)>=UCASE_UPPER) {
c+=GET_SIGNED_DELTA(props);
}
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props);
uint16_t excWord=*pe++;
int32_t index;
if(excWord&UCASE_EXC_CONDITIONAL_FOLD) {
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;
}
}
}
if(HAS_SLOT(excWord, UCASE_EXC_FOLD)) {
index=UCASE_EXC_FOLD;
} else if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
index=UCASE_EXC_LOWER;
} else {
return c;
}
GET_SLOT_VALUE(excWord, index, pe, c);
}
return c;
}
U_CAPI int32_t U_EXPORT2
ucase_toFullFolding(const UCaseProps *csp, UChar32 c,
const UChar **pString,
uint32_t options) {
static const UChar
iDot[2]= { 0x69, 0x307 };
UChar32 result;
uint16_t props;
result=c;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(GET_CASE_TYPE(props)>=UCASE_UPPER) {
result=c+GET_SIGNED_DELTA(props);
}
} else {
const uint16_t *pe=GET_EXCEPTIONS(csp, props), *pe2;
uint16_t excWord=*pe++;
int32_t full, index;
pe2=pe;
if(excWord&UCASE_EXC_CONDITIONAL_FOLD) {
if((options&_FOLD_CASE_OPTIONS_MASK)==U_FOLD_CASE_DEFAULT) {
if(c==0x49) {
return 0x69;
} else if(c==0x130) {
*pString=iDot;
return 2;
}
} else {
if(c==0x49) {
return 0x131;
} else if(c==0x130) {
return 0x69;
}
}
} else if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, full);
++pe;
pe+=full&UCASE_FULL_LOWER;
full=(full>>4)&0xf;
if(full!=0) {
*pString=pe;
return full;
}
}
if(HAS_SLOT(excWord, UCASE_EXC_FOLD)) {
index=UCASE_EXC_FOLD;
} else if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
index=UCASE_EXC_LOWER;
} else {
return ~c;
}
GET_SLOT_VALUE(excWord, index, pe2, result);
}
return (result==c) ? ~result : result;
}