]> granicus.if.org Git - icu/commitdiff
ICU-22006 icupkg: %%ALIAS & %%Parent do not need truncation parent
authorMarkus Scherer <markus.icu@gmail.com>
Thu, 28 Apr 2022 22:27:00 +0000 (15:27 -0700)
committerMarkus Scherer <markus.icu@gmail.com>
Fri, 29 Apr 2022 17:50:11 +0000 (17:50 +0000)
icu4c/source/test/testdata/structLocale.txt
icu4c/source/tools/toolutil/pkgitems.cpp

index 74ff98ce0443e376e6ba4e7270a5a80564991077..ee04f3511ec900134ae20c5938b08e3ffa3a3841 100644 (file)
@@ -11,7 +11,7 @@
 // Since ICU doesn't follow the traditional fallback model where all keys fallback to root,
 // root can't be used to validate the structure.
 structLocale:table(nofallback){
-    %%Parent{""}
+    %%Parent{"root"}
     BreakDictionaryData:bin {00}
     Countries{
         001{""}
index af458677976b239d117981f18cfa1a44440a7bcb..11e50fbd8ac627d95866fdc18e121ded0613b840 100644 (file)
@@ -277,38 +277,40 @@ checkAlias(const char *itemName,
  * Enumerate one resource item and its children and extract dependencies from
  * aliases.
  */
-static void
+static UBool
 ures_enumDependencies(const char *itemName,
                       const ResourceData *pResData,
                       Resource res, const char *inKey, const char *parentKey, int32_t depth,
                       CheckDependency check, void *context,
                       Package *pkg,
                       UErrorCode *pErrorCode) {
+    UBool doCheckParent = TRUE;  // always remains TRUE if depth>1
     switch(res_getPublicType(res)) {
     case URES_STRING:
-        {
-            UBool useResSuffix = TRUE;
-            // Check for %%ALIAS
-            if(depth==1 && inKey!=NULL) {
-                if(0!=strcmp(inKey, "%%ALIAS")) {
-                    break;
-                }
-            }
-            // Check for %%DEPENDENCY
-            else if(depth==2 && parentKey!=NULL) {
-                if(0!=strcmp(parentKey, "%%DEPENDENCY")) {
-                    break;
-                }
-                useResSuffix = FALSE;
-            } else {
-                // we ignore all other strings
-                break;
-            }
+        if(depth==1 && inKey!=NULL &&
+                (0==strcmp(inKey, "%%ALIAS") || 0==strcmp(inKey, "%%Parent"))) {
+            // Top-level %%ALIAS string:
+            //   The alias resource bundle will be used instead of this one.
+            // Top-level %%Parent string:
+            //   We use this bundle as well as the explicit parent bundle.
+            // Either way, the truncation parent is ignored.
+            doCheckParent = FALSE;
+            // No tracing: build tool
             int32_t length;
+            const UChar *alias=res_getStringNoTrace(pResData, res, &length);
+            checkAlias(itemName, res, alias, length, /*useResSuffix=*/ TRUE,
+                       check, context, pErrorCode);
+            // If there is a %%ALIAS, then there should be nothing else in this resource bundle.
+        } else if(depth==2 && parentKey!=NULL && 0==strcmp(parentKey, "%%DEPENDENCY")) {
+            // Second-level %%DEPENDENCY string:
+            // Explicit declaration of a dependency of this item on that one.
             // No tracing: build tool
+            int32_t length;
             const UChar *alias=res_getStringNoTrace(pResData, res, &length);
-            checkAlias(itemName, res, alias, length, useResSuffix, check, context, pErrorCode);
+            checkAlias(itemName, res, alias, length, /*useResSuffix=*/ FALSE,
+                       check, context, pErrorCode);
         }
+        // we ignore all other strings
         break;
     case URES_ALIAS:
         {
@@ -324,7 +326,9 @@ ures_enumDependencies(const char *itemName,
             for(int32_t i=0; i<count; ++i) {
                 const char *itemKey;
                 Resource item=res_getTableItemByIndex(pResData, res, i, &itemKey);
-                ures_enumDependencies(
+                // This doCheckParent return value is needed to
+                // propagate the possible FALSE value from depth=1 to depth=0.
+                doCheckParent &= ures_enumDependencies(
                         itemName, pResData,
                         item, itemKey,
                         inKey, depth+1,
@@ -363,6 +367,7 @@ ures_enumDependencies(const char *itemName,
     default:
         break;
     }
+    return doCheckParent;
 }
 
 static void
@@ -380,17 +385,6 @@ ures_enumDependencies(const char *itemName, const UDataInfo *pInfo,
         exit(U_UNSUPPORTED_ERROR);
     }
 
-    /*
-     * if the bundle attributes are present and the nofallback flag is not set,
-     * then add the parent bundle as a dependency
-     */
-    if(pInfo->formatVersion[0]>1 || (pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1)) {
-        if(!resData.noFallback) {
-            /* this bundle participates in locale fallback */
-            checkParent(itemName, check, context, pErrorCode);
-        }
-    }
-
     icu::NativeItem nativePool;
 
     if(resData.usesPoolBundle) {
@@ -431,12 +425,26 @@ ures_enumDependencies(const char *itemName, const UDataInfo *pInfo,
         }
     }
 
-    ures_enumDependencies(
+    UBool doCheckParent = ures_enumDependencies(
         itemName, &resData,
         resData.rootRes, NULL, NULL, 0,
         check, context,
         pkg,
         pErrorCode);
+    if(!doCheckParent) {
+        return;
+    }
+
+    /*
+     * if the bundle attributes are present and the nofallback flag is not set,
+     * then add the parent bundle as a dependency
+     */
+    if(pInfo->formatVersion[0]>1 || (pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1)) {
+        if(!resData.noFallback) {
+            /* this bundle participates in locale fallback */
+            checkParent(itemName, check, context, pErrorCode);
+        }
+    }
 }
 
 // get dependencies from conversion tables --------------------------------- ***