blob: 1fb7f56813a306a53a5afa5311789f40af1e7598 [file] [log] [blame]
/*
**********************************************************************
* 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"
//----------------------------------------------------------------------
// 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);
}
//----------------------------------------------------------------------
// 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