a4393f8db9
Make these C++ classes a part of the ICU namespace. Use static const arrays for strings instead of pointers to strings. X-SVN-Rev: 10677
250 lines
7.7 KiB
C++
250 lines
7.7 KiB
C++
/*
|
|
**********************************************************************
|
|
* Copyright (c) 2002, International Business Machines
|
|
* Corporation and others. All Rights Reserved.
|
|
**********************************************************************
|
|
* Author: Alan Liu
|
|
* Created: October 30 2002
|
|
* Since: ICU 2.4
|
|
**********************************************************************
|
|
*/
|
|
#include "propname.h"
|
|
#include "unicode/uchar.h"
|
|
#include "unicode/udata.h"
|
|
#include "umutex.h"
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
//----------------------------------------------------------------------
|
|
// PropertyAliases implementation
|
|
|
|
const char*
|
|
PropertyAliases::chooseNameInGroup(Offset offset,
|
|
UPropertyNameChoice choice) const {
|
|
int32_t c = choice;
|
|
if (!offset || c < 0) {
|
|
return NULL;
|
|
}
|
|
const Offset* p = (const Offset*) getPointer(offset);
|
|
while (c-- > 0) {
|
|
if (*p++ < 0) return NULL;
|
|
}
|
|
Offset a = *p;
|
|
if (a < 0) a = -a;
|
|
return (const char*) getPointerNull(a);
|
|
}
|
|
|
|
const ValueMap*
|
|
PropertyAliases::getValueMap(EnumValue prop) const {
|
|
NonContiguousEnumToOffset* e2o = (NonContiguousEnumToOffset*) getPointer(enumToValue_offset);
|
|
Offset a = e2o->getOffset(prop);
|
|
return (const ValueMap*) (a ? getPointerNull(a) : NULL);
|
|
}
|
|
|
|
inline const char*
|
|
PropertyAliases::getPropertyName(EnumValue prop,
|
|
UPropertyNameChoice choice) const {
|
|
NonContiguousEnumToOffset* e2n = (NonContiguousEnumToOffset*) getPointer(enumToName_offset);
|
|
return chooseNameInGroup(e2n->getOffset(prop), choice);
|
|
}
|
|
|
|
inline EnumValue
|
|
PropertyAliases::getPropertyEnum(const char* alias) const {
|
|
NameToEnum* n2e = (NameToEnum*) getPointer(nameToEnum_offset);
|
|
return n2e->getEnum(alias, *this);
|
|
}
|
|
|
|
inline const char*
|
|
PropertyAliases::getPropertyValueName(EnumValue prop,
|
|
EnumValue value,
|
|
UPropertyNameChoice choice) const {
|
|
const ValueMap* vm = getValueMap(prop);
|
|
if (!vm) return NULL;
|
|
Offset a;
|
|
if (vm->enumToName_offset) {
|
|
a = ((EnumToOffset*) getPointer(vm->enumToName_offset))->
|
|
getOffset(value);
|
|
} else {
|
|
a = ((NonContiguousEnumToOffset*) getPointer(vm->ncEnumToName_offset))->
|
|
getOffset(value);
|
|
}
|
|
return chooseNameInGroup(a, choice);
|
|
}
|
|
|
|
inline EnumValue
|
|
PropertyAliases::getPropertyValueEnum(EnumValue prop,
|
|
const char* alias) const {
|
|
const ValueMap* vm = getValueMap(prop);
|
|
if (!vm) return UCHAR_INVALID_CODE;
|
|
NameToEnum* n2e = (NameToEnum*) getPointer(vm->nameToEnum_offset);
|
|
return n2e->getEnum(alias, *this);
|
|
}
|
|
|
|
U_NAMESPACE_END
|
|
|
|
//----------------------------------------------------------------------
|
|
// UDataMemory structures
|
|
|
|
static const PropertyAliases* PNAME = NULL;
|
|
static UDataMemory* UDATA = NULL;
|
|
|
|
//----------------------------------------------------------------------
|
|
// UDataMemory loading/unloading
|
|
|
|
/**
|
|
* udata callback to verify the zone data.
|
|
*/
|
|
U_CDECL_BEGIN
|
|
static UBool U_CALLCONV
|
|
isAcceptable(void* /*context*/,
|
|
const char* /*type*/, const char* /*name*/,
|
|
const UDataInfo* info) {
|
|
return
|
|
info->size >= sizeof(UDataInfo) &&
|
|
info->isBigEndian == U_IS_BIG_ENDIAN &&
|
|
info->charsetFamily == U_CHARSET_FAMILY &&
|
|
info->dataFormat[0] == PNAME_SIG_0 &&
|
|
info->dataFormat[1] == PNAME_SIG_1 &&
|
|
info->dataFormat[2] == PNAME_SIG_2 &&
|
|
info->dataFormat[3] == PNAME_SIG_3 &&
|
|
info->formatVersion[0] == PNAME_FORMAT_VERSION;
|
|
}
|
|
|
|
UBool
|
|
pname_cleanup() {
|
|
if (UDATA) {
|
|
udata_close(UDATA);
|
|
UDATA = NULL;
|
|
}
|
|
PNAME = NULL;
|
|
return TRUE;
|
|
}
|
|
U_CDECL_END
|
|
|
|
static UBool load() {
|
|
if (!PNAME) {
|
|
UErrorCode ec = U_ZERO_ERROR;
|
|
UDataMemory* data =
|
|
udata_openChoice(0, PNAME_DATA_TYPE, PNAME_DATA_NAME,
|
|
isAcceptable, 0, &ec);
|
|
if (U_SUCCESS(ec)) {
|
|
umtx_lock(NULL);
|
|
if (UDATA == NULL) {
|
|
UDATA = data;
|
|
PNAME = (const PropertyAliases*) udata_getMemory(UDATA);
|
|
data = NULL;
|
|
}
|
|
umtx_unlock(NULL);
|
|
}
|
|
if (data) {
|
|
udata_close(data);
|
|
}
|
|
}
|
|
return PNAME!=NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Public API implementation
|
|
|
|
// The C API is just a thin wrapper. Each function obtains a pointer
|
|
// to the singleton PropertyAliases, and calls the appropriate method
|
|
// on it. If it cannot obtain a pointer, because valid data is not
|
|
// available, then it returns NULL or UCHAR_INVALID_CODE.
|
|
|
|
// NOTE (ICU 2.4) For the 2.4 release it was decided late in the cycle
|
|
// to add a new enum to UProperty, UCHAR_GENERAL_CATEGORY_MASK. This
|
|
// enum would specify UCharCategory mask values. Because of time
|
|
// constraints, the underlying binary data and genprop scripts were
|
|
// not updated. So the PNAME->... API takes UCHAR_GENERAL_CATEGORY
|
|
// and associates it with a MASK value. We munge things to make this
|
|
// associate with a UCharCategory value, and we make
|
|
// UCHAR_GENERAL_CATEGORY_MASK correspond to the mask value.
|
|
|
|
// We add a synthetic (not in PropertyAliases.txt) pair of property
|
|
// names corresponding to UCHAR_GENERAL_CATEGORY_MASK:
|
|
// gcm ; General_Category_Mask
|
|
|
|
// TODO: Remove the munge code, marked "//TODO:munge" below, after the
|
|
// script/binary data are updated (probably in ICU 2.6).
|
|
|
|
static const char SHORT_GCM_NAME[] = "gcm";
|
|
static const char LONG_GCM_NAME[] = "General_Category_Mask";
|
|
|
|
U_CAPI const char* U_EXPORT2
|
|
u_getPropertyName(UProperty property,
|
|
UPropertyNameChoice nameChoice) {
|
|
//TODO:munge
|
|
if (property == UCHAR_GENERAL_CATEGORY_MASK) {
|
|
switch (nameChoice) {
|
|
case U_SHORT_PROPERTY_NAME:
|
|
return SHORT_GCM_NAME;
|
|
case U_LONG_PROPERTY_NAME:
|
|
return LONG_GCM_NAME;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
return load() ? PNAME->getPropertyName(property, nameChoice)
|
|
: NULL;
|
|
}
|
|
|
|
U_CAPI UProperty U_EXPORT2
|
|
u_getPropertyEnum(const char* alias) {
|
|
UProperty p = load() ? (UProperty) PNAME->getPropertyEnum(alias)
|
|
: UCHAR_INVALID_CODE;
|
|
//TODO:munge
|
|
if (p == UCHAR_INVALID_CODE) {
|
|
if (0 == uprv_comparePropertyNames(alias, SHORT_GCM_NAME) ||
|
|
0 == uprv_comparePropertyNames(alias, LONG_GCM_NAME)) {
|
|
p = UCHAR_GENERAL_CATEGORY_MASK;
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
U_CAPI const char* U_EXPORT2
|
|
u_getPropertyValueName(UProperty property,
|
|
int32_t value,
|
|
UPropertyNameChoice nameChoice) {
|
|
//TODO:munge
|
|
switch (property) {
|
|
case UCHAR_GENERAL_CATEGORY:
|
|
value = (value < 32) ? U_MASK(value) : 0;
|
|
break;
|
|
case UCHAR_GENERAL_CATEGORY_MASK:
|
|
property = UCHAR_GENERAL_CATEGORY;
|
|
break;
|
|
}
|
|
return load() ? PNAME->getPropertyValueName(property, value, nameChoice)
|
|
: NULL;
|
|
}
|
|
|
|
U_CAPI int32_t U_EXPORT2
|
|
u_getPropertyValueEnum(UProperty property,
|
|
const char* alias) {
|
|
//TODO:munge
|
|
UProperty p = (property == UCHAR_GENERAL_CATEGORY_MASK) ?
|
|
UCHAR_GENERAL_CATEGORY : property;
|
|
int32_t v = load() ? PNAME->getPropertyValueEnum(p, alias)
|
|
: UCHAR_INVALID_CODE;
|
|
//TODO:munge
|
|
if (property == UCHAR_GENERAL_CATEGORY) {
|
|
int32_t gc = 0;
|
|
for (;;) {
|
|
if (v == 1) {
|
|
return gc;
|
|
}
|
|
if ((v & 1) != 0) {
|
|
// More than one bit is set; we can't map this mask to
|
|
// a UCharCategory.
|
|
return UCHAR_INVALID_CODE;
|
|
}
|
|
v >>= 1;
|
|
gc += 1;
|
|
}
|
|
}
|
|
return v;
|
|
}
|
|
|
|
//eof
|