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:
Markus Scherer 2016-04-27 16:19:26 +00:00
parent 8f7dd3149c
commit 192500a361
7 changed files with 463 additions and 114 deletions

View File

@ -19,6 +19,7 @@ U_NAMESPACE_BEGIN
ResourceValue::~ResourceValue() {}
ResourceSink::~ResourceSink() {}
ResourceArraySink::~ResourceArraySink() {}

View File

@ -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.

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
}