Index: source/common/uresbund.cpp |
diff --git a/source/common/uresbund.cpp b/source/common/uresbund.cpp |
index e74afb8a483db2ed251c39a82de835ca216901f4..b2d071a09f93835b9f5a3d0fd4ce69e738b53993 100644 |
--- a/source/common/uresbund.cpp |
+++ b/source/common/uresbund.cpp |
@@ -1882,6 +1882,121 @@ ures_getByKeyWithFallback(const UResourceBundle *resB, |
return fillIn; |
} |
+namespace { |
+ |
+void getAllContainerItemsWithFallback( |
+ const UResourceBundle *bundle, ResourceDataValue &value, |
+ 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 |
+ // 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. |
+ // 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); |
+ } |
+ } |
+ UResourceDataEntry *entry = bundle->fData->fParent; |
+ if (entry != NULL && U_SUCCESS(entry->fBogus)) { |
+ // We might try to query the sink whether |
+ // any fallback from the parent bundle is still possible. |
+ |
+ // Turn the parent UResourceDataEntry into a UResourceBundle, |
+ // much like in ures_openWithType(). |
+ // TODO: See if we can refactor ures_getByKeyWithFallback() |
+ // and pull out an inner function that takes and returns a UResourceDataEntry |
+ // so that we need not create UResourceBundle objects. |
+ UResourceBundle parentBundle; |
+ ures_initStackObject(&parentBundle); |
+ parentBundle.fTopLevelData = parentBundle.fData = entry; |
+ // TODO: What is the difference between bundle fData and fTopLevelData? |
+ uprv_memcpy(&parentBundle.fResData, &entry->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); |
+ |
+ // Look up the container item in the parent bundle. |
+ UResourceBundle containerBundle; |
+ ures_initStackObject(&containerBundle); |
+ const UResourceBundle *rb; |
+ if (bundle->fResPath == NULL || *bundle->fResPath == 0) { |
+ rb = &parentBundle; |
+ } else { |
+ rb = ures_getByKeyWithFallback(&parentBundle, bundle->fResPath, |
+ &containerBundle, &errorCode); |
+ } |
+ if (U_SUCCESS(errorCode) && ures_getType(rb) == expectedType) { |
+ getAllContainerItemsWithFallback(rb, value, |
+ arraySink, tableSink, errorCode); |
+ } |
+ ures_close(&containerBundle); |
+ ures_close(&parentBundle); |
+ } |
+} |
+ |
+void getAllContainerItemsWithFallback( |
+ const UResourceBundle *bundle, const char *path, |
+ ResourceArraySink *arraySink, ResourceTableSink *tableSink, |
+ UErrorCode &errorCode) { |
+ if (U_FAILURE(errorCode)) { return; } |
+ if (path == NULL) { |
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR; |
+ return; |
+ } |
+ UResourceBundle stackBundle; |
+ ures_initStackObject(&stackBundle); |
+ const UResourceBundle *rb; |
+ if (*path == 0) { |
+ // empty path |
+ rb = bundle; |
+ } else { |
+ rb = ures_getByKeyWithFallback(bundle, path, &stackBundle, &errorCode); |
+ if (U_FAILURE(errorCode)) { |
+ ures_close(&stackBundle); |
+ return; |
+ } |
+ } |
+ 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); |
+ ures_close(&stackBundle); |
+} |
+ |
+} // namespace |
+ |
+U_CAPI void U_EXPORT2 |
+ures_getAllArrayItemsWithFallback(const UResourceBundle *bundle, const char *path, |
+ ResourceArraySink &sink, UErrorCode &errorCode) { |
+ getAllContainerItemsWithFallback(bundle, path, &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); |
+} |
U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) { |
Resource res = RES_BOGUS; |