#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;
const UChar *unfold;
UTrie trie;
uint8_t formatVersion[4];
};
#if UCASE_HARDCODE_DATA
#include "ucase_props_data.c"
#else
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;
cspProto->indexes=(const int32_t *)bin;
if( (length>=0 && length<16*4) ||
cspProto->indexes[UCASE_IX_INDEX_TOP]<16
) {
*pErrorCode=U_INVALID_FORMAT_ERROR;
return NULL;
}
size=cspProto->indexes[UCASE_IX_INDEX_TOP]*4;
if(length>=0) {
if(length>=size && length>=cspProto->indexes[UCASE_IX_LENGTH]) {
length-=size;
} else {
*pErrorCode=U_INVALID_FORMAT_ERROR;
return NULL;
}
}
bin+=size;
size=cspProto->indexes[UCASE_IX_TRIE_SIZE];
utrie_unserialize(&cspProto->trie, bin, size, pErrorCode);
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
bin+=size;
size=2*cspProto->indexes[UCASE_IX_EXC_LENGTH];
cspProto->exceptions=(const uint16_t *)bin;
bin+=size;
size=2*cspProto->indexes[UCASE_IX_UNFOLD_LENGTH];
if(size!=0) {
cspProto->unfold=(const UChar *)bin;
bin+=size;
} else {
cspProto->unfold=NULL;
}
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);
}
#endif
U_CAPI void U_EXPORT2
ucase_close(UCaseProps *csp) {
if(csp!=NULL) {
#if !UCASE_HARDCODE_DATA
udata_close(csp->mem);
#endif
uprv_free(csp);
}
}
#if !UCASE_HARDCODE_DATA
static UCaseProps *gCsp=NULL;
static UCaseProps *gCspDummy=NULL;
static UErrorCode gErrorCode=U_ZERO_ERROR;
static int8_t gHaveData=0;
#endif
#if !UCASE_HARDCODE_DATA
static UBool U_CALLCONV ucase_cleanup(void) {
ucase_close(gCsp);
gCsp=NULL;
ucase_close(gCspDummy);
gCspDummy=NULL;
gErrorCode=U_ZERO_ERROR;
gHaveData=0;
return TRUE;
}
#endif
U_CAPI const UCaseProps * U_EXPORT2
ucase_getSingleton(UErrorCode *pErrorCode) {
#if UCASE_HARDCODE_DATA
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
return &ucase_props_singleton;
#else
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;
}
#endif
}
#if !UCASE_HARDCODE_DATA
U_CAPI const UCaseProps * U_EXPORT2
ucase_getDummy(UErrorCode *pErrorCode) {
UCaseProps *csp;
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
UMTX_CHECK(NULL, gCspDummy, csp);
if(csp!=NULL) {
return csp;
} else {
int32_t *indexes;
csp=(UCaseProps *)uprv_malloc(sizeof(UCaseProps)+UCASE_IX_TOP*4+UTRIE_DUMMY_SIZE);
if(csp==NULL) {
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
uprv_memset(csp, 0, sizeof(UCaseProps)+UCASE_IX_TOP*4);
csp->indexes=indexes=(int32_t *)(csp+1);
indexes[UCASE_IX_INDEX_TOP]=UCASE_IX_TOP;
indexes[UCASE_IX_TRIE_SIZE]=
utrie_unserializeDummy(&csp->trie, indexes+UCASE_IX_TOP, UTRIE_DUMMY_SIZE, 0, 0, TRUE, pErrorCode);
if(U_FAILURE(*pErrorCode)) {
uprv_free(csp);
return NULL;
}
csp->formatVersion[0]=1;
csp->formatVersion[2]=UTRIE_SHIFT;
csp->formatVersion[3]=UTRIE_INDEX_SHIFT;
umtx_lock(NULL);
if(gCspDummy==NULL) {
gCspDummy=csp;
csp=NULL;
ucln_common_registerCleanup(UCLN_COMMON_UCASE, ucase_cleanup);
}
umtx_unlock(NULL);
uprv_free(csp);
return gCspDummy;
}
}
#endif
static UBool U_CALLCONV
_enumPropertyStartsRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
const USetAdder *sa=(const USetAdder *)context;
sa->add(sa->set, start);
return TRUE;
}
U_CFUNC void U_EXPORT2
ucase_addPropertyStarts(const UCaseProps *csp, const 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_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(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
c+=UCASE_GET_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(UCASE_GET_TYPE(props)==UCASE_LOWER) {
c+=UCASE_GET_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(UCASE_GET_TYPE(props)==UCASE_LOWER) {
c+=UCASE_GET_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;
}
static const UChar iDot[2] = { 0x69, 0x307 };
static const UChar jDot[2] = { 0x6a, 0x307 };
static const UChar iOgonekDot[3] = { 0x12f, 0x307 };
static const UChar iDotGrave[3] = { 0x69, 0x307, 0x300 };
static const UChar iDotAcute[3] = { 0x69, 0x307, 0x301 };
static const UChar iDotTilde[3] = { 0x69, 0x307, 0x303 };
U_CFUNC void U_EXPORT2
ucase_addCaseClosure(const UCaseProps *csp, UChar32 c, const USetAdder *sa) {
uint16_t props;
switch(c) {
case 0x49:
sa->add(sa->set, 0x69);
return;
case 0x69:
sa->add(sa->set, 0x49);
return;
case 0x130:
sa->addString(sa->set, iDot, 2);
return;
case 0x131:
return;
default:
break;
}
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(UCASE_GET_TYPE(props)!=UCASE_NONE) {
int32_t delta=UCASE_GET_DELTA(props);
if(delta!=0) {
sa->add(sa->set, c+delta);
}
}
} else {
const uint16_t *pe0, *pe=GET_EXCEPTIONS(csp, props);
const UChar *closure;
uint16_t excWord=*pe++;
int32_t index, closureLength, fullLength, length;
pe0=pe;
for(index=UCASE_EXC_LOWER; index<=UCASE_EXC_TITLE; ++index) {
if(HAS_SLOT(excWord, index)) {
pe=pe0;
GET_SLOT_VALUE(excWord, index, pe, c);
sa->add(sa->set, c);
}
}
if(HAS_SLOT(excWord, UCASE_EXC_CLOSURE)) {
pe=pe0;
GET_SLOT_VALUE(excWord, UCASE_EXC_CLOSURE, pe, closureLength);
closureLength&=UCASE_CLOSURE_MAX_LENGTH;
closure=(const UChar *)pe+1;
} else {
closureLength=0;
closure=NULL;
}
if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
pe=pe0;
GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, fullLength);
++pe;
fullLength&=0xffff;
pe+=fullLength&UCASE_FULL_LOWER;
fullLength>>=4;
length=fullLength&0xf;
if(length!=0) {
sa->addString(sa->set, (const UChar *)pe, length);
pe+=length;
}
fullLength>>=4;
pe+=fullLength&0xf;
fullLength>>=4;
pe+=fullLength;
closure=(const UChar *)pe;
}
for(index=0; index<closureLength;) {
U16_NEXT_UNSAFE(closure, index, c);
sa->add(sa->set, c);
}
}
}
static U_INLINE int32_t
strcmpMax(const UChar *s, int32_t length, const UChar *t, int32_t max) {
int32_t c1, c2;
max-=length;
do {
c1=*s++;
c2=*t++;
if(c2==0) {
return 1;
}
c1-=c2;
if(c1!=0) {
return c1;
}
} while(--length>0);
if(max==0 || *t==0) {
return 0;
} else {
return -max;
}
}
U_CFUNC UBool U_EXPORT2
ucase_addStringCaseClosure(const UCaseProps *csp, const UChar *s, int32_t length, const USetAdder *sa) {
const UChar *unfold, *p;
int32_t i, start, limit, result, unfoldRows, unfoldRowWidth, unfoldStringWidth;
if(csp->unfold==NULL || s==NULL) {
return FALSE;
}
if(length<=1) {
return FALSE;
}
unfold=csp->unfold;
unfoldRows=unfold[UCASE_UNFOLD_ROWS];
unfoldRowWidth=unfold[UCASE_UNFOLD_ROW_WIDTH];
unfoldStringWidth=unfold[UCASE_UNFOLD_STRING_WIDTH];
unfold+=unfoldRowWidth;
if(length>unfoldStringWidth) {
return FALSE;
}
start=0;
limit=unfoldRows;
while(start<limit) {
i=(start+limit)/2;
p=unfold+(i*unfoldRowWidth);
result=strcmpMax(s, length, p, unfoldStringWidth);
if(result==0) {
UChar32 c;
for(i=unfoldStringWidth; i<unfoldRowWidth && p[i]!=0;) {
U16_NEXT_UNSAFE(p, i, c);
sa->add(sa->set, c);
ucase_addCaseClosure(csp, c, sa);
}
return TRUE;
} else if(result<0) {
limit=i;
} else {
start=i+1;
}
}
return FALSE;
}
U_CAPI int32_t U_EXPORT2
ucase_getType(const UCaseProps *csp, UChar32 c) {
uint16_t props;
GET_PROPS(csp, c, props);
return UCASE_GET_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=UCASE_GET_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);
}
#define is_a(c) ((c)=='a' || (c)=='A')
#define is_d(c) ((c)=='d' || (c)=='D')
#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_n(c) ((c)=='n' || (c)=='N')
#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)
U_CFUNC int32_t
ucase_getCaseLocale(const char *locale, int32_t *locCache) {
int32_t result;
char c;
if(locCache!=NULL && (result=*locCache)!=UCASE_LOC_UNKNOWN) {
return result;
}
result=UCASE_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=UCASE_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=UCASE_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=UCASE_LOC_LITHUANIAN;
}
}
} else if(is_n(c)) {
c=*locale++;
if(is_l(c)) {
c=*locale++;
if(is_d(c)) {
c=*locale;
}
if(is_sep(c)) {
result=UCASE_LOC_DUTCH;
}
}
}
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(UCASE_GET_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)
{
UChar32 result;
uint16_t props;
result=c;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
result=c+UCASE_GET_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=ucase_getCaseLocale(locale, locCache);
if( loc==UCASE_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==UCASE_LOC_TURKISH && c==0x130) {
return 0x69;
} else if(loc==UCASE_LOC_TURKISH && c==0x307 && isPrecededBy_I(csp, iter, context)) {
return 0;
} else if(loc==UCASE_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(UCASE_GET_TYPE(props)==UCASE_LOWER) {
result=c+UCASE_GET_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=ucase_getCaseLocale(locale, locCache);
if(loc==UCASE_LOC_TURKISH && c==0x69) {
return 0x130;
} else if(loc==UCASE_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(const UCaseProps *csp, UChar32 c, uint32_t options) {
uint16_t props;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
c+=UCASE_GET_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 c;
}
} 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)
{
UChar32 result;
uint16_t props;
result=c;
GET_PROPS(csp, c, props);
if(!PROPS_HAS_EXCEPTION(props)) {
if(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
result=c+UCASE_GET_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;
}
#if !UCASE_HARDCODE_DATA
static const UCaseProps *
getCaseProps() {
const UCaseProps *csp;
UErrorCode errorCode=U_ZERO_ERROR;
csp=ucase_getSingleton(&errorCode);
if(U_FAILURE(errorCode)) {
errorCode=U_ZERO_ERROR;
csp=ucase_getDummy(&errorCode);
if(U_FAILURE(errorCode)) {
return NULL;
}
}
return csp;
}
#endif
#if !UCASE_HARDCODE_DATA
#define GET_CASE_PROPS() (gCsp!=NULL ? gCsp : getCaseProps())
#else
#define GET_CASE_PROPS() &ucase_props_singleton
#endif
U_CAPI UBool U_EXPORT2
u_isULowercase(UChar32 c) {
return (UBool)(UCASE_LOWER==ucase_getType(GET_CASE_PROPS(), c));
}
U_CAPI UBool U_EXPORT2
u_isUUppercase(UChar32 c) {
return (UBool)(UCASE_UPPER==ucase_getType(GET_CASE_PROPS(), c));
}
U_CAPI UChar32 U_EXPORT2
u_tolower(UChar32 c) {
return ucase_tolower(GET_CASE_PROPS(), c);
}
U_CAPI UChar32 U_EXPORT2
u_toupper(UChar32 c) {
return ucase_toupper(GET_CASE_PROPS(), c);
}
U_CAPI UChar32 U_EXPORT2
u_totitle(UChar32 c) {
return ucase_totitle(GET_CASE_PROPS(), c);
}
U_CAPI UChar32 U_EXPORT2
u_foldCase(UChar32 c, uint32_t options) {
return ucase_fold(GET_CASE_PROPS(), c, options);
}
U_CFUNC int32_t U_EXPORT2
ucase_hasBinaryProperty(UChar32 c, UProperty which) {
const UCaseProps *csp=GET_CASE_PROPS();
if(csp==NULL) {
return FALSE;
}
switch(which) {
case UCHAR_LOWERCASE:
return (UBool)(UCASE_LOWER==ucase_getType(csp, c));
case UCHAR_UPPERCASE:
return (UBool)(UCASE_UPPER==ucase_getType(csp, c));
case UCHAR_SOFT_DOTTED:
return ucase_isSoftDotted(csp, c);
case UCHAR_CASE_SENSITIVE:
return ucase_isCaseSensitive(csp, c);
default:
return FALSE;
}
}