ICU-12510 resource data enumeration: get array/table objects from ResourceValue, iterate with nested code & functions not by returning nested sinks; use this in DateTimePatternGenerator AllowedHourFormatsSink
X-SVN-Rev: 38655
This commit is contained in:
parent
8f7dd3149c
commit
192500a361
@ -19,6 +19,7 @@ U_NAMESPACE_BEGIN
|
||||
|
||||
ResourceValue::~ResourceValue() {}
|
||||
|
||||
ResourceSink::~ResourceSink() {}
|
||||
|
||||
ResourceArraySink::~ResourceArraySink() {}
|
||||
|
||||
|
@ -27,13 +27,81 @@
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/ures.h"
|
||||
|
||||
struct ResourceData;
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class ResourceTableSink;
|
||||
class ResourceValue;
|
||||
|
||||
// Note: In C++, we use const char * pointers for keys,
|
||||
// rather than an abstraction like Java UResource.Key.
|
||||
|
||||
/**
|
||||
* Interface for iterating over a resource bundle array resource.
|
||||
*/
|
||||
class U_COMMON_API ResourceArray {
|
||||
public:
|
||||
/** Constructs an empty array object. */
|
||||
ResourceArray() : items16(NULL), items32(NULL), length(0) {}
|
||||
|
||||
/** Only for implementation use. @internal */
|
||||
ResourceArray(const uint16_t *i16, const uint32_t *i32, int32_t len) :
|
||||
items16(i16), items32(i32), length(len) {}
|
||||
|
||||
/**
|
||||
* @return The number of items in the array resource.
|
||||
*/
|
||||
int32_t getSize() const { return length; }
|
||||
/**
|
||||
* @param i Array item index.
|
||||
* @param value Output-only, receives the value of the i'th item.
|
||||
* @return TRUE if i is non-negative and less than getSize().
|
||||
*/
|
||||
UBool getValue(int32_t i, ResourceValue &value) const;
|
||||
|
||||
/** Only for implementation use. @internal */
|
||||
uint32_t internalGetResource(const ResourceData *pResData, int32_t i) const;
|
||||
|
||||
private:
|
||||
const uint16_t *items16;
|
||||
const uint32_t *items32;
|
||||
int32_t length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for iterating over a resource bundle table resource.
|
||||
*/
|
||||
class U_COMMON_API ResourceTable {
|
||||
public:
|
||||
/** Constructs an empty table object. */
|
||||
ResourceTable() : keys16(NULL), keys32(NULL), items16(NULL), items32(NULL), length(0) {}
|
||||
|
||||
/** Only for implementation use. @internal */
|
||||
ResourceTable(const uint16_t *k16, const int32_t *k32,
|
||||
const uint16_t *i16, const uint32_t *i32, int32_t len) :
|
||||
keys16(k16), keys32(k32), items16(i16), items32(i32), length(len) {}
|
||||
|
||||
/**
|
||||
* @return The number of items in the array resource.
|
||||
*/
|
||||
int32_t getSize() const { return length; }
|
||||
/**
|
||||
* @param i Array item index.
|
||||
* @param key Output-only, receives the key of the i'th item.
|
||||
* @param value Output-only, receives the value of the i'th item.
|
||||
* @return TRUE if i is non-negative and less than getSize().
|
||||
*/
|
||||
UBool getKeyAndValue(int32_t i, const char *&key, ResourceValue &value) const;
|
||||
|
||||
private:
|
||||
const uint16_t *keys16;
|
||||
const int32_t *keys32;
|
||||
const uint16_t *items16;
|
||||
const uint32_t *items32;
|
||||
int32_t length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a resource bundle item's value.
|
||||
* Avoids object creations as much as possible.
|
||||
@ -100,6 +168,73 @@ public:
|
||||
*/
|
||||
virtual const uint8_t *getBinary(int32_t &length, UErrorCode &errorCode) const = 0;
|
||||
|
||||
/**
|
||||
* Sets U_RESOURCE_TYPE_MISMATCH if this is not an array resource
|
||||
*/
|
||||
virtual ResourceArray getArray(UErrorCode &errorCode) const = 0;
|
||||
|
||||
/**
|
||||
* Sets U_RESOURCE_TYPE_MISMATCH if this is not a table resource
|
||||
*/
|
||||
virtual ResourceTable getTable(UErrorCode &errorCode) const = 0;
|
||||
|
||||
/**
|
||||
* Is this a no-fallback/no-inheritance marker string?
|
||||
* Such a marker is used for
|
||||
* CLDR no-fallback data values of (three empty-set symbols)=={2205, 2205, 2205}
|
||||
* when enumerating tables with fallback from the specific resource bundle to root.
|
||||
*
|
||||
* @return TRUE if this is a no-inheritance marker string
|
||||
*/
|
||||
virtual UBool isNoInheritanceMarker() const = 0;
|
||||
|
||||
/**
|
||||
* Sets the dest strings from the string values in this array resource.
|
||||
*
|
||||
* @return the number of strings in this array resource.
|
||||
* If greater than capacity, then an overflow error is set.
|
||||
*
|
||||
* Sets U_RESOURCE_TYPE_MISMATCH if this is not an array resource
|
||||
* or if any of the array items is not a string
|
||||
*/
|
||||
virtual int32_t getStringArray(UnicodeString *dest, int32_t capacity,
|
||||
UErrorCode &errorCode) const = 0;
|
||||
|
||||
/**
|
||||
* Same as
|
||||
* <pre>
|
||||
* if (getType() == URES_STRING) {
|
||||
* return new String[] { getString(); }
|
||||
* } else {
|
||||
* return getStringArray();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Sets U_RESOURCE_TYPE_MISMATCH if this is
|
||||
* neither a string resource nor an array resource containing strings
|
||||
* @see getString()
|
||||
* @see getStringArray()
|
||||
*/
|
||||
virtual int32_t getStringArrayOrStringAsArray(UnicodeString *dest, int32_t capacity,
|
||||
UErrorCode &errorCode) const = 0;
|
||||
|
||||
/**
|
||||
* Same as
|
||||
* <pre>
|
||||
* if (getType() == URES_STRING) {
|
||||
* return getString();
|
||||
* } else {
|
||||
* return getStringArray()[0];
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Sets U_RESOURCE_TYPE_MISMATCH if this is
|
||||
* neither a string resource nor an array resource containing strings
|
||||
* @see getString()
|
||||
* @see getStringArray()
|
||||
*/
|
||||
virtual UnicodeString getStringOrFirstOfArray(UErrorCode &errorCode) const = 0;
|
||||
|
||||
protected:
|
||||
ResourceValue() {}
|
||||
|
||||
@ -108,6 +243,36 @@ private:
|
||||
ResourceValue &operator=(const ResourceValue &); // no assignment operator
|
||||
};
|
||||
|
||||
/**
|
||||
* Sink for ICU resource bundle contents.
|
||||
*/
|
||||
class U_COMMON_API ResourceSink : public UObject {
|
||||
public:
|
||||
ResourceSink() {}
|
||||
virtual ~ResourceSink();
|
||||
|
||||
/**
|
||||
* Called once for each bundle (child-parent-...-root).
|
||||
* The value is normally an array or table resource,
|
||||
* and implementations of this method normally iterate over the
|
||||
* tree of resource items stored there.
|
||||
*
|
||||
* @param key The key string of the enumeration-start resource.
|
||||
* Empty if the enumeration starts at the top level of the bundle.
|
||||
* @param value Call getArray() or getTable() as appropriate.
|
||||
* Then reuse for output values from Array and Table getters.
|
||||
* @param noFallback true if the bundle has no parent;
|
||||
* that is, its top-level table has the nofallback attribute,
|
||||
* or it is the root bundle of a locale tree.
|
||||
*/
|
||||
virtual void put(const char *key, ResourceValue &value, UBool noFallback,
|
||||
UErrorCode &errorCode) = 0;
|
||||
|
||||
private:
|
||||
ResourceSink(const ResourceSink &); // no copy constructor
|
||||
ResourceSink &operator=(const ResourceSink &); // no assignment operator
|
||||
};
|
||||
|
||||
/**
|
||||
* Sink for ICU resource array contents.
|
||||
* The base class does nothing.
|
||||
|
@ -1885,32 +1885,41 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
|
||||
|
||||
namespace {
|
||||
|
||||
void getAllContainerItemsWithFallback(
|
||||
void getAllItemsWithFallback(
|
||||
const UResourceBundle *bundle, ResourceDataValue &value,
|
||||
ResourceSink *sink,
|
||||
ResourceArraySink *arraySink, ResourceTableSink *tableSink,
|
||||
UErrorCode &errorCode) {
|
||||
if (U_FAILURE(errorCode)) { return; }
|
||||
// We recursively enumerate child-first,
|
||||
// only storing parent items in the absence of child items.
|
||||
// We store a placeholder value for the no-fallback/no-inheritance marker
|
||||
// The sink needs to store a placeholder value for the no-fallback/no-inheritance marker
|
||||
// to prevent a parent item from being stored.
|
||||
//
|
||||
// It would be possible to recursively enumerate parent-first,
|
||||
// overriding parent items with child items.
|
||||
// When we see the no-fallback/no-inheritance marker,
|
||||
// then we would remove the parent's item.
|
||||
// When the sink sees the no-fallback/no-inheritance marker,
|
||||
// then it would remove the parent's item.
|
||||
// We would deserialize parent values even though they are overridden in a child bundle.
|
||||
UResType expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE;
|
||||
if (ures_getType(bundle) == expectedType) {
|
||||
value.pResData = &bundle->fResData;
|
||||
UResourceDataEntry *parentEntry = bundle->fData->fParent;
|
||||
UBool hasParent = parentEntry != NULL && U_SUCCESS(parentEntry->fBogus);
|
||||
UResType expectedType;
|
||||
if (sink != NULL) {
|
||||
expectedType = URES_NONE;
|
||||
value.setResource(bundle->fRes);
|
||||
sink->put(bundle->fKey, value, !hasParent, errorCode);
|
||||
} else {
|
||||
expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE;
|
||||
if (ures_getType(bundle) == expectedType) {
|
||||
if (arraySink != NULL) {
|
||||
ures_getAllArrayItems(&bundle->fResData, bundle->fRes, value, *arraySink, errorCode);
|
||||
} else /* tableSink != NULL */ {
|
||||
ures_getAllTableItems(&bundle->fResData, bundle->fRes, value, *tableSink, errorCode);
|
||||
}
|
||||
}
|
||||
UResourceDataEntry *entry = bundle->fData->fParent;
|
||||
if (entry != NULL && U_SUCCESS(entry->fBogus)) {
|
||||
}
|
||||
if (hasParent) {
|
||||
// We might try to query the sink whether
|
||||
// any fallback from the parent bundle is still possible.
|
||||
|
||||
@ -1921,16 +1930,16 @@ void getAllContainerItemsWithFallback(
|
||||
// so that we need not create UResourceBundle objects.
|
||||
UResourceBundle parentBundle;
|
||||
ures_initStackObject(&parentBundle);
|
||||
parentBundle.fTopLevelData = parentBundle.fData = entry;
|
||||
parentBundle.fTopLevelData = parentBundle.fData = parentEntry;
|
||||
// TODO: What is the difference between bundle fData and fTopLevelData?
|
||||
uprv_memcpy(&parentBundle.fResData, &entry->fData, sizeof(ResourceData));
|
||||
uprv_memcpy(&parentBundle.fResData, &parentEntry->fData, sizeof(ResourceData));
|
||||
// TODO: Try to replace bundle.fResData with just using bundle.fData->fData.
|
||||
parentBundle.fHasFallback = !parentBundle.fResData.noFallback;
|
||||
parentBundle.fIsTopLevel = TRUE;
|
||||
parentBundle.fRes = parentBundle.fResData.rootRes;
|
||||
parentBundle.fSize = res_countArrayItems(&(parentBundle.fResData), parentBundle.fRes);
|
||||
parentBundle.fIndex = -1;
|
||||
entryIncrease(entry);
|
||||
entryIncrease(parentEntry);
|
||||
|
||||
// Look up the container item in the parent bundle.
|
||||
UResourceBundle containerBundle;
|
||||
@ -1942,17 +1951,17 @@ void getAllContainerItemsWithFallback(
|
||||
rb = ures_getByKeyWithFallback(&parentBundle, bundle->fResPath,
|
||||
&containerBundle, &errorCode);
|
||||
}
|
||||
if (U_SUCCESS(errorCode) && ures_getType(rb) == expectedType) {
|
||||
getAllContainerItemsWithFallback(rb, value,
|
||||
arraySink, tableSink, errorCode);
|
||||
if (U_SUCCESS(errorCode) && (expectedType == URES_NONE || ures_getType(rb) == expectedType)) {
|
||||
getAllItemsWithFallback(rb, value, sink, arraySink, tableSink, errorCode);
|
||||
}
|
||||
ures_close(&containerBundle);
|
||||
ures_close(&parentBundle);
|
||||
}
|
||||
}
|
||||
|
||||
void getAllContainerItemsWithFallback(
|
||||
void getAllItemsWithFallback(
|
||||
const UResourceBundle *bundle, const char *path,
|
||||
ResourceSink *sink,
|
||||
ResourceArraySink *arraySink, ResourceTableSink *tableSink,
|
||||
UErrorCode &errorCode) {
|
||||
if (U_FAILURE(errorCode)) { return; }
|
||||
@ -1973,30 +1982,38 @@ void getAllContainerItemsWithFallback(
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (sink == NULL) {
|
||||
UResType expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE;
|
||||
if (ures_getType(rb) != expectedType) {
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
ures_close(&stackBundle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Get all table items with fallback.
|
||||
ResourceDataValue value;
|
||||
getAllContainerItemsWithFallback(rb, value, arraySink, tableSink, errorCode);
|
||||
getAllItemsWithFallback(rb, value, sink, arraySink, tableSink, errorCode);
|
||||
ures_close(&stackBundle);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
ures_getAllItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||
icu::ResourceSink &sink, UErrorCode &errorCode) {
|
||||
getAllItemsWithFallback(bundle, path, &sink, NULL, NULL, errorCode);
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
ures_getAllArrayItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||
ResourceArraySink &sink, UErrorCode &errorCode) {
|
||||
getAllContainerItemsWithFallback(bundle, path, &sink, NULL, errorCode);
|
||||
getAllItemsWithFallback(bundle, path, NULL, &sink, NULL, errorCode);
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
ures_getAllTableItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||
ResourceTableSink &sink, UErrorCode &errorCode) {
|
||||
getAllContainerItemsWithFallback(bundle, path, NULL, &sink, errorCode);
|
||||
getAllItemsWithFallback(bundle, path, NULL, NULL, &sink, errorCode);
|
||||
}
|
||||
|
||||
U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) {
|
||||
|
@ -380,6 +380,36 @@ UBool isNoInheritanceMarker(const ResourceData *pResData, Resource res) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int32_t getStringArray(const ResourceData *pResData, const icu::ResourceArray &array,
|
||||
icu::UnicodeString *dest, int32_t capacity,
|
||||
UErrorCode &errorCode) {
|
||||
if(U_FAILURE(errorCode)) {
|
||||
return 0;
|
||||
}
|
||||
if(dest == NULL ? capacity != 0 : capacity < 0) {
|
||||
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return 0;
|
||||
}
|
||||
int32_t length = array.getSize();
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(length > capacity) {
|
||||
errorCode = U_BUFFER_OVERFLOW_ERROR;
|
||||
return length;
|
||||
}
|
||||
for(int32_t i = 0; i < length; ++i) {
|
||||
int32_t sLength;
|
||||
const UChar *s = res_getString(pResData, array.internalGetResource(pResData, i), &sLength);
|
||||
if(s == NULL) {
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
return 0;
|
||||
}
|
||||
dest[i].setTo(TRUE, s, sLength);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
U_CAPI const UChar * U_EXPORT2
|
||||
@ -535,6 +565,130 @@ const uint8_t *ResourceDataValue::getBinary(int32_t &length, UErrorCode &errorCo
|
||||
return b;
|
||||
}
|
||||
|
||||
ResourceArray ResourceDataValue::getArray(UErrorCode &errorCode) const {
|
||||
if(U_FAILURE(errorCode)) {
|
||||
return ResourceArray();
|
||||
}
|
||||
const uint16_t *items16 = NULL;
|
||||
const Resource *items32 = NULL;
|
||||
uint32_t offset=RES_GET_OFFSET(res);
|
||||
int32_t length = 0;
|
||||
switch(RES_GET_TYPE(res)) {
|
||||
case URES_ARRAY:
|
||||
if (offset!=0) { // empty if offset==0
|
||||
items32 = (const Resource *)pResData->pRoot+offset;
|
||||
length = *items32++;
|
||||
}
|
||||
break;
|
||||
case URES_ARRAY16:
|
||||
items16 = pResData->p16BitUnits+offset;
|
||||
length = *items16++;
|
||||
break;
|
||||
default:
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
return ResourceArray();
|
||||
}
|
||||
return ResourceArray(items16, items32, length);
|
||||
}
|
||||
|
||||
ResourceTable ResourceDataValue::getTable(UErrorCode &errorCode) const {
|
||||
if(U_FAILURE(errorCode)) {
|
||||
return ResourceTable();
|
||||
}
|
||||
const uint16_t *keys16 = NULL;
|
||||
const int32_t *keys32 = NULL;
|
||||
const uint16_t *items16 = NULL;
|
||||
const Resource *items32 = NULL;
|
||||
uint32_t offset = RES_GET_OFFSET(res);
|
||||
int32_t length = 0;
|
||||
switch(RES_GET_TYPE(res)) {
|
||||
case URES_TABLE:
|
||||
if (offset != 0) { // empty if offset==0
|
||||
keys16 = (const uint16_t *)(pResData->pRoot+offset);
|
||||
length = *keys16++;
|
||||
items32 = (const Resource *)(keys16+length+(~length&1));
|
||||
}
|
||||
break;
|
||||
case URES_TABLE16:
|
||||
keys16 = pResData->p16BitUnits+offset;
|
||||
length = *keys16++;
|
||||
items16 = keys16 + length;
|
||||
break;
|
||||
case URES_TABLE32:
|
||||
if (offset != 0) { // empty if offset==0
|
||||
keys32 = pResData->pRoot+offset;
|
||||
length = *keys32++;
|
||||
items32 = (const Resource *)keys32 + length;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
return ResourceTable();
|
||||
}
|
||||
return ResourceTable(keys16, keys32, items16, items32, length);
|
||||
}
|
||||
|
||||
UBool ResourceDataValue::isNoInheritanceMarker() const {
|
||||
return ::isNoInheritanceMarker(pResData, res);
|
||||
}
|
||||
|
||||
int32_t ResourceDataValue::getStringArray(UnicodeString *dest, int32_t capacity,
|
||||
UErrorCode &errorCode) const {
|
||||
return ::getStringArray(pResData, getArray(errorCode), dest, capacity, errorCode);
|
||||
}
|
||||
|
||||
int32_t ResourceDataValue::getStringArrayOrStringAsArray(UnicodeString *dest, int32_t capacity,
|
||||
UErrorCode &errorCode) const {
|
||||
if(URES_IS_ARRAY(res)) {
|
||||
return ::getStringArray(pResData, getArray(errorCode), dest, capacity, errorCode);
|
||||
}
|
||||
if(U_FAILURE(errorCode)) {
|
||||
return 0;
|
||||
}
|
||||
if(dest == NULL ? capacity != 0 : capacity < 0) {
|
||||
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if(capacity < 1) {
|
||||
errorCode = U_BUFFER_OVERFLOW_ERROR;
|
||||
return 1;
|
||||
}
|
||||
int32_t sLength;
|
||||
const UChar *s = res_getString(pResData, res, &sLength);
|
||||
if(s != NULL) {
|
||||
dest[0].setTo(TRUE, s, sLength);
|
||||
return 1;
|
||||
}
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
UnicodeString ResourceDataValue::getStringOrFirstOfArray(UErrorCode &errorCode) const {
|
||||
UnicodeString us;
|
||||
if(U_FAILURE(errorCode)) {
|
||||
return us;
|
||||
}
|
||||
int32_t sLength;
|
||||
const UChar *s = res_getString(pResData, res, &sLength);
|
||||
if(s != NULL) {
|
||||
us.setTo(TRUE, s, sLength);
|
||||
return us;
|
||||
}
|
||||
ResourceArray array = getArray(errorCode);
|
||||
if(U_FAILURE(errorCode)) {
|
||||
return us;
|
||||
}
|
||||
if(array.getSize() > 0) {
|
||||
s = res_getString(pResData, array.internalGetResource(pResData, 0), &sLength);
|
||||
if(s != NULL) {
|
||||
us.setTo(TRUE, s, sLength);
|
||||
return us;
|
||||
}
|
||||
}
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
return us;
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
static Resource
|
||||
@ -673,28 +827,25 @@ ures_getAllTableItems(const ResourceData *pResData, Resource table,
|
||||
uint32_t offset = RES_GET_OFFSET(table);
|
||||
int32_t length = 0;
|
||||
switch(RES_GET_TYPE(table)) {
|
||||
case URES_TABLE: {
|
||||
if (offset != 0) { /* empty if offset==0 */
|
||||
case URES_TABLE:
|
||||
if (offset != 0) { // empty if offset==0
|
||||
keys16 = (const uint16_t *)(pResData->pRoot+offset);
|
||||
length = *keys16++;
|
||||
items32 = (const Resource *)(keys16+length+(~length&1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case URES_TABLE16: {
|
||||
case URES_TABLE16:
|
||||
keys16 = pResData->p16BitUnits+offset;
|
||||
length = *keys16++;
|
||||
items16 = keys16 + length;
|
||||
break;
|
||||
}
|
||||
case URES_TABLE32: {
|
||||
if (offset != 0) { /* empty if offset==0 */
|
||||
case URES_TABLE32:
|
||||
if (offset != 0) { // empty if offset==0
|
||||
keys32 = pResData->pRoot+offset;
|
||||
length = *keys32++;
|
||||
items32 = (const Resource *)keys32 + length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
return;
|
||||
@ -742,6 +893,27 @@ ures_getAllTableItems(const ResourceData *pResData, Resource table,
|
||||
sink.leave(errorCode);
|
||||
}
|
||||
|
||||
UBool icu::ResourceTable::getKeyAndValue(int32_t i,
|
||||
const char *&key, icu::ResourceValue &value) const {
|
||||
if(0 <= i && i < length) {
|
||||
icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value);
|
||||
if (keys16 != NULL) {
|
||||
key = RES_GET_KEY16(rdValue.pResData, keys16[i]);
|
||||
} else {
|
||||
key = RES_GET_KEY32(rdValue.pResData, keys32[i]);
|
||||
}
|
||||
Resource res;
|
||||
if (items16 != NULL) {
|
||||
res = makeResourceFrom16(rdValue.pResData, items16[i]);
|
||||
} else {
|
||||
res = items32[i];
|
||||
}
|
||||
rdValue.setResource(res);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U_CAPI Resource U_EXPORT2
|
||||
res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
|
||||
uint32_t offset=RES_GET_OFFSET(array);
|
||||
@ -779,18 +951,16 @@ ures_getAllArrayItems(const ResourceData *pResData, Resource array,
|
||||
uint32_t offset=RES_GET_OFFSET(array);
|
||||
int32_t length = 0;
|
||||
switch(RES_GET_TYPE(array)) {
|
||||
case URES_ARRAY: {
|
||||
if (offset!=0) { /* empty if offset==0 */
|
||||
case URES_ARRAY:
|
||||
if (offset!=0) { // empty if offset==0
|
||||
items32 = (const Resource *)pResData->pRoot+offset;
|
||||
length = *items32++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case URES_ARRAY16: {
|
||||
case URES_ARRAY16:
|
||||
items16 = pResData->p16BitUnits+offset;
|
||||
length = *items16++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||
return;
|
||||
@ -830,6 +1000,23 @@ ures_getAllArrayItems(const ResourceData *pResData, Resource array,
|
||||
sink.leave(errorCode);
|
||||
}
|
||||
|
||||
uint32_t icu::ResourceArray::internalGetResource(const ResourceData *pResData, int32_t i) const {
|
||||
if (items16 != NULL) {
|
||||
return makeResourceFrom16(pResData, items16[i]);
|
||||
} else {
|
||||
return items32[i];
|
||||
}
|
||||
}
|
||||
|
||||
UBool icu::ResourceArray::getValue(int32_t i, icu::ResourceValue &value) const {
|
||||
if(0 <= i && i < length) {
|
||||
icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value);
|
||||
rdValue.setResource(internalGetResource(rdValue.pResData, i));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U_CFUNC Resource
|
||||
res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key) {
|
||||
char *pathP = *path, *nextSepP = *path;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* Copyright (C) 1999-2015, International Business Machines
|
||||
* Copyright (C) 1999-2016, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
******************************************************************************
|
||||
* file name: uresdata.h
|
||||
@ -379,7 +379,7 @@ enum {
|
||||
/*
|
||||
* Structure for a single, memory-mapped ResourceBundle.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct ResourceData {
|
||||
UDataMemory *data;
|
||||
const int32_t *pRoot;
|
||||
const uint16_t *p16BitUnits;
|
||||
@ -486,6 +486,14 @@ public:
|
||||
virtual uint32_t getUInt(UErrorCode &errorCode) const;
|
||||
virtual const int32_t *getIntVector(int32_t &length, UErrorCode &errorCode) const;
|
||||
virtual const uint8_t *getBinary(int32_t &length, UErrorCode &errorCode) const;
|
||||
virtual ResourceArray getArray(UErrorCode &errorCode) const;
|
||||
virtual ResourceTable getTable(UErrorCode &errorCode) const;
|
||||
virtual UBool isNoInheritanceMarker() const;
|
||||
virtual int32_t getStringArray(UnicodeString *dest, int32_t capacity,
|
||||
UErrorCode &errorCode) const;
|
||||
virtual int32_t getStringArrayOrStringAsArray(UnicodeString *dest, int32_t capacity,
|
||||
UErrorCode &errorCode) const;
|
||||
virtual UnicodeString getStringOrFirstOfArray(UErrorCode &errorCode) const;
|
||||
|
||||
const ResourceData *pResData;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) 2000-2015, International Business Machines
|
||||
* Copyright (C) 2000-2016, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
*/
|
||||
@ -224,6 +224,10 @@ ures_getStringByKeyWithFallback(const UResourceBundle *resB,
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
ures_getAllItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||
icu::ResourceSink &sink, UErrorCode &errorCode);
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
ures_getAllArrayItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||
icu::ResourceArraySink &sink, UErrorCode &errorCode);
|
||||
|
@ -434,79 +434,48 @@ DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
|
||||
|
||||
namespace {
|
||||
|
||||
struct AllowedHourFormatsSink : public ResourceTableSink {
|
||||
struct AllowedHourFormatsSink : public ResourceSink {
|
||||
// Initialize sub-sinks.
|
||||
AllowedHourFormatsSink() : localeSink(*this), allowedListSink(*this) {}
|
||||
AllowedHourFormatsSink() {}
|
||||
virtual ~AllowedHourFormatsSink();
|
||||
|
||||
// Entry point.
|
||||
virtual ResourceTableSink *getOrCreateTableSink(const char *key, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) { return NULL; }
|
||||
|
||||
locale = key;
|
||||
return &localeSink;
|
||||
}
|
||||
|
||||
struct LocaleSink : public ResourceTableSink {
|
||||
AllowedHourFormatsSink &outer;
|
||||
LocaleSink(AllowedHourFormatsSink &outer) : outer(outer) {}
|
||||
virtual ~LocaleSink();
|
||||
|
||||
virtual void put(const char *key, const ResourceValue &value, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
|
||||
if (uprv_strcmp(key, "allowed") == 0) {
|
||||
outer.allowedFormats = static_cast<int32_t *>(uprv_malloc(2 * sizeof(int32_t)));
|
||||
outer.allowedFormatsLength = 1;
|
||||
if (outer.allowedFormats == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
outer.allowedFormats[0] = outer.getHourFormatFromUnicodeString(
|
||||
value.getUnicodeString(status));
|
||||
virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
|
||||
UErrorCode &errorCode) {
|
||||
ResourceTable timeData = value.getTable(errorCode);
|
||||
if (U_FAILURE(errorCode)) { return; }
|
||||
for (int32_t i = 0; timeData.getKeyAndValue(i, key, value); ++i) {
|
||||
const char *regionOrLocale = key;
|
||||
ResourceTable formatList = value.getTable(errorCode);
|
||||
if (U_FAILURE(errorCode)) { return; }
|
||||
for (int32_t j = 0; formatList.getKeyAndValue(j, key, value); ++j) {
|
||||
if (uprv_strcmp(key, "allowed") == 0) { // Ignore "preferred" list.
|
||||
LocalArray<int32_t> list;
|
||||
int32_t length;
|
||||
if (value.getType() == URES_STRING) {
|
||||
list.adoptInsteadAndCheckErrorCode(
|
||||
static_cast<int32_t *>(uprv_malloc(2 * sizeof(int32_t))), errorCode);
|
||||
if (U_FAILURE(errorCode)) { return; }
|
||||
list[0] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
|
||||
length = 1;
|
||||
} else {
|
||||
ResourceArray allowedFormats = value.getArray(errorCode);
|
||||
length = allowedFormats.getSize();
|
||||
list.adoptInsteadAndCheckErrorCode(
|
||||
static_cast<int32_t *>(uprv_malloc((length + 1) * sizeof(int32_t))), errorCode);
|
||||
if (U_FAILURE(errorCode)) { return; }
|
||||
for (int32_t k = 0; k < length; ++k) {
|
||||
allowedFormats.getValue(k, value);
|
||||
list[k] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ResourceArraySink *getOrCreateArraySink(const char *key, UErrorCode &status) {
|
||||
if (U_SUCCESS(status) && uprv_strcmp(key, "allowed") == 0) {
|
||||
return &outer.allowedListSink;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual void leave(UErrorCode &status) {
|
||||
if (U_FAILURE(status) || outer.allowedFormats == NULL) { return; }
|
||||
|
||||
outer.allowedFormats[outer.allowedFormatsLength] = ALLOWED_HOUR_FORMAT_UNKNOWN;
|
||||
uhash_put(localeToAllowedHourFormatsMap, const_cast<char *>(outer.locale), outer.allowedFormats, &status);
|
||||
outer.allowedFormats = NULL;
|
||||
}
|
||||
} localeSink;
|
||||
|
||||
struct AllowedListSink : public ResourceArraySink {
|
||||
AllowedHourFormatsSink &outer;
|
||||
AllowedListSink(AllowedHourFormatsSink &outer) : outer(outer) {}
|
||||
virtual ~AllowedListSink();
|
||||
|
||||
virtual void enter(int32_t size, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
outer.allowedFormats = static_cast<int32_t *>(uprv_malloc((size + 1) * sizeof(int32_t)));
|
||||
outer.allowedFormatsLength = size;
|
||||
if (outer.allowedFormats == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
list[length] = ALLOWED_HOUR_FORMAT_UNKNOWN;
|
||||
uhash_put(localeToAllowedHourFormatsMap,
|
||||
const_cast<char *>(regionOrLocale), list.orphan(), &errorCode);
|
||||
if (U_FAILURE(errorCode)) { return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void put(int32_t index, const ResourceValue &value, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
|
||||
outer.allowedFormats[index] = outer.getHourFormatFromUnicodeString(
|
||||
value.getUnicodeString(status));
|
||||
}
|
||||
} allowedListSink;
|
||||
|
||||
const char *locale;
|
||||
int32_t *allowedFormats;
|
||||
int32_t allowedFormatsLength;
|
||||
|
||||
AllowedHourFormat getHourFormatFromUnicodeString(UnicodeString s) {
|
||||
if (s.length() == 1) {
|
||||
@ -526,8 +495,6 @@ struct AllowedHourFormatsSink : public ResourceTableSink {
|
||||
} // namespace
|
||||
|
||||
AllowedHourFormatsSink::~AllowedHourFormatsSink() {}
|
||||
AllowedHourFormatsSink::LocaleSink::~LocaleSink() {}
|
||||
AllowedHourFormatsSink::AllowedListSink::~AllowedListSink() {}
|
||||
|
||||
void DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
@ -543,7 +510,7 @@ void DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
|
||||
// into the hashmap, store 6 single-value sub-arrays right at the beginning of the
|
||||
// vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime
|
||||
// object. Remember to clean up the vector, too.
|
||||
ures_getAllTableItemsWithFallback(rb.getAlias(), "timeData", sink, status);
|
||||
ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status);
|
||||
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user