diff --git a/icu4c/source/common/resource.cpp b/icu4c/source/common/resource.cpp index c8c02f033f..0d41dae5c8 100644 --- a/icu4c/source/common/resource.cpp +++ b/icu4c/source/common/resource.cpp @@ -19,6 +19,7 @@ U_NAMESPACE_BEGIN ResourceValue::~ResourceValue() {} +ResourceSink::~ResourceSink() {} ResourceArraySink::~ResourceArraySink() {} diff --git a/icu4c/source/common/resource.h b/icu4c/source/common/resource.h index 20e3e270d5..12d0b16091 100644 --- a/icu4c/source/common/resource.h +++ b/icu4c/source/common/resource.h @@ -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 + *
+     * if (getType() == URES_STRING) {
+     *     return new String[] { getString(); }
+     * } else {
+     *     return getStringArray();
+     * }
+     * 
+ * + * 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 + *
+     * if (getType() == URES_STRING) {
+     *     return getString();
+     * } else {
+     *     return getStringArray()[0];
+     * }
+     * 
+ * + * 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. diff --git a/icu4c/source/common/uresbund.cpp b/icu4c/source/common/uresbund.cpp index 62460f8e20..a14b84a7e9 100644 --- a/icu4c/source/common/uresbund.cpp +++ b/icu4c/source/common/uresbund.cpp @@ -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; - if (arraySink != NULL) { - ures_getAllArrayItems(&bundle->fResData, bundle->fRes, value, *arraySink, errorCode); - } else /* tableSink != NULL */ { - ures_getAllTableItems(&bundle->fResData, bundle->fRes, value, *tableSink, errorCode); + 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; } } - UResType expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE; - if (ures_getType(rb) != expectedType) { - errorCode = U_RESOURCE_TYPE_MISMATCH; - ures_close(&stackBundle); - 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) { diff --git a/icu4c/source/common/uresdata.cpp b/icu4c/source/common/uresdata.cpp index 90034ca241..cc33372d76 100644 --- a/icu4c/source/common/uresdata.cpp +++ b/icu4c/source/common/uresdata.cpp @@ -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(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(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; diff --git a/icu4c/source/common/uresdata.h b/icu4c/source/common/uresdata.h index 1afa77c074..143b8beaa2 100644 --- a/icu4c/source/common/uresdata.h +++ b/icu4c/source/common/uresdata.h @@ -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; diff --git a/icu4c/source/common/uresimp.h b/icu4c/source/common/uresimp.h index 6b264db39b..e8d68e1ec0 100644 --- a/icu4c/source/common/uresimp.h +++ b/icu4c/source/common/uresimp.h @@ -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); diff --git a/icu4c/source/i18n/dtptngen.cpp b/icu4c/source/i18n/dtptngen.cpp index c75d01bb5b..0a6d0fe2cb 100644 --- a/icu4c/source/i18n/dtptngen.cpp +++ b/icu4c/source/i18n/dtptngen.cpp @@ -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(uprv_malloc(2 * sizeof(int32_t))); - outer.allowedFormatsLength = 1; - if (outer.allowedFormats == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return; + 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 list; + int32_t length; + if (value.getType() == URES_STRING) { + list.adoptInsteadAndCheckErrorCode( + static_cast(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(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)); + } + } + list[length] = ALLOWED_HOUR_FORMAT_UNKNOWN; + uhash_put(localeToAllowedHourFormatsMap, + const_cast(regionOrLocale), list.orphan(), &errorCode); + if (U_FAILURE(errorCode)) { return; } } - outer.allowedFormats[0] = outer.getHourFormatFromUnicodeString( - value.getUnicodeString(status)); } } - - 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(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(uprv_malloc((size + 1) * sizeof(int32_t))); - outer.allowedFormatsLength = size; - if (outer.allowedFormats == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } - } - 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); }