]> granicus.if.org Git - icu/commitdiff
ICU-10823 add ures_openNoDefault() and use it from collation data loader and BreakIte...
authorMarkus Scherer <markus.icu@gmail.com>
Thu, 4 Dec 2014 21:11:26 +0000 (21:11 +0000)
committerMarkus Scherer <markus.icu@gmail.com>
Thu, 4 Dec 2014 21:11:26 +0000 (21:11 +0000)
X-SVN-Rev: 36806

icu4c/source/common/brkiter.cpp
icu4c/source/common/uresbund.cpp
icu4c/source/common/uresimp.h
icu4c/source/i18n/ucol_res.cpp
icu4c/source/test/cintltst/capitst.c
icu4c/source/test/intltest/alphaindextst.cpp
icu4c/source/test/intltest/apicoll.cpp

index a4e4466808a3dae236d45bab302185bb070024c7..b30e1778eedb27ace488b9900c39cccb0ea73cac 100644 (file)
@@ -69,13 +69,7 @@ BreakIterator::buildInstance(const Locale& loc, const char *type, int32_t kind,
     ures_initStackObject(brkName);
 
     // Get the locale
-    UResourceBundle *b = ures_open(U_ICUDATA_BRKITR, loc.getName(), &status);
-    /* this is a hack for now. Should be fixed when the data is fetched from
-        brk_index.txt */
-    if(status==U_USING_DEFAULT_WARNING){
-        status=U_ZERO_ERROR;
-        ures_openFillIn(b, U_ICUDATA_BRKITR, "", &status);
-    }
+    UResourceBundle *b = ures_openNoDefault(U_ICUDATA_BRKITR, loc.getName(), &status);
 
     // Get the "boundaries" array.
     if (U_SUCCESS(status)) {
index 266ed0af13a3a4a1dabf202f5a752c7392d6babe..cce226fb3d5436cd921325f21c4750be7ef1db00 100644 (file)
@@ -446,7 +446,9 @@ getPoolEntry(const char *path, UErrorCode *status) {
 
 /* INTERNAL: */
 /*   CAUTION:  resbMutex must be locked when calling this function! */
-static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
+static UResourceDataEntry *
+findFirstExisting(const char* path, char* name,
+                  UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
     UResourceDataEntry *r = NULL;
     UBool hasRealData = FALSE;
     const char *defaultLoc = uloc_getDefault();
@@ -502,15 +504,106 @@ U_CFUNC void ures_initStackObject(UResourceBundle* resB) {
   ures_setIsStackObject(resB, TRUE);
 }
 
-static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UErrorCode* status) {
-    UErrorCode intStatus = U_ZERO_ERROR;
+static UBool  // returns U_SUCCESS(*status)
+loadParentsExceptRoot(UResourceDataEntry *&t1,
+                      char name[], int32_t nameCapacity,
+                      UBool usingUSRData, char usrDataPath[], UErrorCode *status) {
+    if (U_FAILURE(*status)) { return FALSE; }
+    UBool hasChopped = TRUE;
+    while (hasChopped && t1->fParent == NULL && !t1->fData.noFallback &&
+            res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
+        Resource parentRes = res_getResource(&t1->fData, "%%Parent");
+        if (parentRes != RES_BOGUS) {  // An explicit parent was found.
+            int32_t parentLocaleLen = 0;
+            const UChar *parentLocaleName = res_getString(&(t1->fData), parentRes, &parentLocaleLen);
+            if(parentLocaleName != NULL && 0 < parentLocaleLen && parentLocaleLen < nameCapacity) {
+                u_UCharsToChars(parentLocaleName, name, parentLocaleLen + 1);
+                if (uprv_strcmp(name, kRootLocaleName) == 0) {
+                    return TRUE;
+                }
+            }
+        }
+        // Insert regular parents.
+        UErrorCode parentStatus = U_ZERO_ERROR;
+        UResourceDataEntry *t2 = init_entry(name, t1->fPath, &parentStatus);
+        if (U_FAILURE(parentStatus)) {
+            *status = parentStatus;
+            return FALSE;
+        }
+        UResourceDataEntry *u2 = NULL;
+        UErrorCode usrStatus = U_ZERO_ERROR;
+        if (usingUSRData) {  // This code inserts user override data into the inheritance chain.
+            u2 = init_entry(name, usrDataPath, &usrStatus);
+        }
+
+        if (usingUSRData && U_SUCCESS(usrStatus) && u2->fBogus == U_ZERO_ERROR) {
+            t1->fParent = u2;
+            u2->fParent = t2;
+        } else {
+            t1->fParent = t2;
+            if (usingUSRData) {
+                // The USR override data wasn't found, set it to be deleted.
+                u2->fCountExisting = 0;
+            }
+        }
+        t1 = t2;
+        hasChopped = chopLocale(name);
+    }
+    return TRUE;
+}
+
+static UBool  // returns U_SUCCESS(*status)
+insertRootBundle(UResourceDataEntry *&t1, UErrorCode *status) {
+    if (U_FAILURE(*status)) { return FALSE; }
     UErrorCode parentStatus = U_ZERO_ERROR;
-    UErrorCode usrStatus = U_ZERO_ERROR;
+    UResourceDataEntry *t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus);
+    if (U_FAILURE(parentStatus)) {
+        *status = parentStatus;
+        return FALSE;
+    }
+    t1->fParent = t2;
+    t1 = t2;
+    return TRUE;
+}
+
+enum UResOpenType {
+    /**
+     * Open a resource bundle for the locale;
+     * if there is not even a base language bundle, then fall back to the default locale;
+     * if there is no bundle for that either, then load the root bundle.
+     *
+     * This is the default bundle loading behavior.
+     */
+    URES_OPEN_LOCALE_DEFAULT_ROOT,
+    // TODO: ICU ticket #11271 "consistent default locale across locale trees"
+    // Add an option to look at the main locale tree for whether to
+    // fall back to root directly (if the locale has main data) or
+    // fall back to the default locale first (if the locale does not even have main data).
+    /**
+     * Open a resource bundle for the locale;
+     * if there is not even a base language bundle, then load the root bundle;
+     * never fall back to the default locale.
+     *
+     * This is used for algorithms that have good pan-Unicode default behavior,
+     * such as case mappings, collation, and segmentation (BreakIterator).
+     */
+    URES_OPEN_LOCALE_ROOT,
+    /**
+     * Open a resource bundle for the exact bundle name as requested;
+     * no fallbacks, do not load parent bundles.
+     *
+     * This is used for supplemental (non-locale) data.
+     */
+    URES_OPEN_DIRECT
+};
+typedef enum UResOpenType UResOpenType;
+
+static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
+                                     UResOpenType openType, UErrorCode* status) {
+    U_ASSERT(openType != URES_OPEN_DIRECT);
+    UErrorCode intStatus = U_ZERO_ERROR;
     UResourceDataEntry *r = NULL;
     UResourceDataEntry *t1 = NULL;
-    UResourceDataEntry *t2 = NULL;
-    UResourceDataEntry *u1 = NULL;
-    UResourceDataEntry *u2 = NULL;
     UBool isDefault = FALSE;
     UBool isRoot = FALSE;
     UBool hasRealData = FALSE;
@@ -550,7 +643,8 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
             t1 = r;
             hasRealData = TRUE;
             if ( usingUSRData ) {  /* This code inserts user override data into the inheritance chain */
-               u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
+                UErrorCode usrStatus = U_ZERO_ERROR;
+                UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
                if ( u1 != NULL ) {
                  if(u1->fBogus == U_ZERO_ERROR) {
                    u1->fParent = t1;
@@ -561,48 +655,16 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
                  }
                }
             }
-            while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.noFallback) {
-                if ( res_getResource(&t1->fData,"%%Parent") != RES_BOGUS) { /* An explicit parent was found */
-                    int32_t parentLocaleLen = 0;
-                    const UChar *parentLocaleName = res_getString(&(t1->fData), res_getResource(&t1->fData,"%%Parent") , &parentLocaleLen);
-                    if(parentLocaleName != NULL && parentLocaleLen > 0) {
-                        u_UCharsToChars(parentLocaleName, name, parentLocaleLen+1);
-                        if ( !uprv_strcmp(name,"root") ) { /* If parent is root, we just terminate the loop */
-                            hasChopped = FALSE;
-                            continue;
-                        }
-                    }
-                }
-                /* insert regular parents */
-                t2 = init_entry(name, t1->fPath, &parentStatus);
-                if ( usingUSRData ) {  /* This code inserts user override data into the inheritance chain */
-                    usrStatus = U_ZERO_ERROR;
-                    u2 = init_entry(name, usrDataPath, &usrStatus);
-                }
-                /* Check for null pointer. */
-                if (t2 == NULL || ( usingUSRData && u2 == NULL)) {
-                    *status = U_MEMORY_ALLOCATION_ERROR;
+            if (hasChopped && !isRoot) {
+                if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
                     goto finishUnlock;
                 }
-                
-                if ( usingUSRData && u2->fBogus == U_ZERO_ERROR ) {
-                    t1->fParent = u2;
-                    u2->fParent = t2;
-                } else {
-                    t1->fParent = t2;
-                    if(usingUSRData) {
-                        /* the USR override data wasn't found, set it to be deleted */
-                        u2->fCountExisting = 0;
-                    }
-                }
-                t1 = t2;
-                hasChopped = chopLocale(name);
             }
         }
 
         /* we could have reached this point without having any real data */
         /* if that is the case, we need to chain in the default locale   */
-        if(r==NULL && !isDefault && !isRoot /*&& t1->fParent == NULL*/) {
+        if(r==NULL && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault && !isRoot) {
             /* insert default locale */
             uprv_strcpy(name, uloc_getDefault());
             r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
@@ -611,31 +673,11 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
                 t1 = r;
                 hasRealData = TRUE;
                 isDefault = TRUE;
-                while (hasChopped && t1->fParent == NULL) {
-                    if ( res_getResource(&t1->fData,"%%Parent") != RES_BOGUS) { /* An explicit parent was found */
-                        int32_t parentLocaleLen = 0;
-                        const UChar *parentLocaleName = res_getString(&(t1->fData), res_getResource(&t1->fData,"%%Parent") , &parentLocaleLen);
-                        if(parentLocaleName != NULL && parentLocaleLen > 0) {
-                            u_UCharsToChars(parentLocaleName, name, parentLocaleLen+1);
-                            if ( !uprv_strcmp(name,"root") ) { /* If parent is root, we just terminate the loop */
-                                hasChopped = FALSE;
-                                continue;
-                            }
-                        }
-                    }
-                    /* insert chopped defaults */
-                    t2 = init_entry(name, t1->fPath, &parentStatus);
-                    /* Check for null pointer. */
-                    if (t2 == NULL) {
-                        *status = U_MEMORY_ALLOCATION_ERROR;
+                // TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
+                if (hasChopped && !isRoot) {
+                    if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
                         goto finishUnlock;
                     }
-
-                    if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
-                        t1->fParent = t2;
-                        t1 = t2;
-                    }
-                    hasChopped = chopLocale(name);
                 }
             } 
         }
@@ -653,46 +695,89 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
                 *status = U_MISSING_RESOURCE_ERROR;
                 goto finishUnlock;
             }
-        } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL && !r->fData.noFallback) {
-            /* insert root locale */
-            t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus);
-            /* Check for null pointer. */
-            if (t2 == NULL) {
-                *status = U_MEMORY_ALLOCATION_ERROR;
+        } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 &&
+                t1->fParent == NULL && !r->fData.noFallback) {
+            if (!insertRootBundle(t1, status)) {
                 goto finishUnlock;
             }
             if(!hasRealData) {
                 r->fBogus = U_USING_DEFAULT_WARNING;
             }
-            hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) || hasRealData);
-            t1->fParent = t2;
-            t1 = t2;
         }
 
+        // TODO: Does this ever loop?
         while(r != NULL && !isRoot && t1->fParent != NULL) {
             t1->fParent->fCountExisting++;
             t1 = t1->fParent;
-            hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) || hasRealData);
         }
     } /* umtx_lock */
 finishUnlock:
     umtx_unlock(&resbMutex);
 
     if(U_SUCCESS(*status)) {
-        if(U_SUCCESS(parentStatus)) {
-            if(intStatus != U_ZERO_ERROR) {
-                *status = intStatus;  
-            }
-            return r;
-        } else {
-            *status = parentStatus;
-            return NULL;
+        if(intStatus != U_ZERO_ERROR) {
+            *status = intStatus;  
         }
+        return r;
     } else {
         return NULL;
     }
 }
 
+/**
+ * Version of entryOpen() and findFirstExisting() for ures_openDirect(),
+ * with no fallbacks.
+ * Parent and root locale bundles are loaded if
+ * the requested bundle does not have the "nofallback" flag.
+ */
+static UResourceDataEntry *
+entryOpenDirect(const char* path, const char* localeID, UErrorCode* status) {
+    initCache(status);
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    umtx_lock(&resbMutex);
+    // findFirstExisting() without fallbacks.
+    UResourceDataEntry *r = init_entry(localeID, path, status);
+    if(U_SUCCESS(*status)) {
+        if(r->fBogus != U_ZERO_ERROR) {
+            r->fCountExisting--;
+            r = NULL;
+        }
+    } else {
+        r = NULL;
+    }
+
+    // Some code depends on the ures_openDirect() bundle to have a parent bundle chain,
+    // unless it is marked with "nofallback".
+    UResourceDataEntry *t1 = r;
+    if(r != NULL && uprv_strcmp(localeID, kRootLocaleName) != 0 &&  // not root
+            r->fParent == NULL && !r->fData.noFallback &&
+            uprv_strlen(localeID) < ULOC_FULLNAME_CAPACITY) {
+        char name[ULOC_FULLNAME_CAPACITY];
+        uprv_strcpy(name, localeID);
+        if(!chopLocale(name) || uprv_strcmp(name, kRootLocaleName) == 0 ||
+                loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), FALSE, NULL, status)) {
+            if(uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL) {
+                insertRootBundle(t1, status);
+            }
+        }
+        if(U_FAILURE(*status)) {
+            r = NULL;
+        }
+    }
+
+    if(r != NULL) {
+        // TODO: Does this ever loop?
+        while(t1->fParent != NULL) {
+            t1->fParent->fCountExisting++;
+            t1 = t1->fParent;
+        }
+    }
+    umtx_unlock(&resbMutex);
+    return r;
+}
 
 /**
  * Functions to create and destroy resource bundles.
@@ -2013,172 +2098,93 @@ U_CFUNC const char* ures_getPath(const UResourceBundle* resB) {
 }
 #endif
 
-/* OLD API implementation */
+static UResourceBundle*
+ures_openWithType(UResourceBundle *r, const char* path, const char* localeID,
+                  UResOpenType openType, UErrorCode* status) {
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
 
-/**
- *  API: This function is used to open a resource bundle 
- *  proper fallback chaining is executed while initialization. 
- *  The result is stored in cache for later fallback search.
- */
-U_CAPI void  U_EXPORT2
-ures_openFillIn(UResourceBundle *r, const char* path,
-                    const char* localeID, UErrorCode* status) {
-    if(r == NULL) {
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
-    } else {
-        UResourceDataEntry *firstData;
-        UBool isStackObject = ures_isStackObject(r);
+    UResourceDataEntry *entry;
+    if(openType != URES_OPEN_DIRECT) {
+        /* first "canonicalize" the locale ID */
         char canonLocaleID[ULOC_FULLNAME_CAPACITY];
-
-        uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
+        uloc_getBaseName(localeID, canonLocaleID, UPRV_LENGTHOF(canonLocaleID), status);
         if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
             *status = U_ILLEGAL_ARGUMENT_ERROR;
-            return;
-        }
-
-        ures_closeBundle(r, FALSE);
-        uprv_memset(r, 0, sizeof(UResourceBundle));
-        ures_setIsStackObject(r, isStackObject);
-        r->fHasFallback = TRUE;
-        r->fIsTopLevel = TRUE;
-        r->fIndex = -1;
-        r->fData = entryOpen(path, canonLocaleID, status);
-        if(U_FAILURE(*status)) {
-            return;
-        }
-        /* this is a quick fix to get regular data in bundle - until construction is cleaned up */
-        firstData = r->fData;
-        while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) {
-            firstData = firstData->fParent;
+            return NULL;
         }
-        uprv_memcpy(&r->fResData, &firstData->fData, sizeof(ResourceData));
-        r->fHasFallback=(UBool)!r->fResData.noFallback;
-        r->fRes = r->fResData.rootRes;
-        r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
-        r->fTopLevelData = r->fData;
+        entry = entryOpen(path, canonLocaleID, openType, status);
+    } else {
+        entry = entryOpenDirect(path, localeID, status);
     }
-}
-
-U_CAPI UResourceBundle*  U_EXPORT2
-ures_open(const char* path,
-                    const char* localeID,
-                    UErrorCode* status)
-{
-    char canonLocaleID[ULOC_FULLNAME_CAPACITY];
-    UResourceDataEntry *hasData = NULL;
-    UResourceBundle *r;
-
-    if(status == NULL || U_FAILURE(*status)) {
+    if(U_FAILURE(*status)) {
         return NULL;
     }
-
-    /* first "canonicalize" the locale ID */
-    uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
-    if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
+    if(entry == NULL) {
+        *status = U_MISSING_RESOURCE_ERROR;
         return NULL;
     }
 
-    r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
+    UBool isStackObject;
     if(r == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return NULL;
-    }
-
-    uprv_memset(r, 0, sizeof(UResourceBundle));
-    r->fHasFallback = TRUE;
-    r->fIsTopLevel = TRUE;
-    ures_setIsStackObject(r, FALSE);
-    r->fIndex = -1;
-    r->fData = entryOpen(path, canonLocaleID, status);
-    if(U_FAILURE(*status)) {
-        uprv_free(r);
-        return NULL;
-    }
-    r->fTopLevelData = r->fData;
-
-    hasData = r->fData;
-    while(hasData->fBogus != U_ZERO_ERROR) {
-        hasData = hasData->fParent;
-        if(hasData == NULL) {
-          /* This can happen only if fallback chain gets broken by an act of God */
-          /* TODO: this unlikely to happen, consider removing it */
-            entryClose(r->fData);
-            uprv_free(r);
-            *status = U_MISSING_RESOURCE_ERROR;
+        r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
+        if(r == NULL) {
+            entryClose(entry);
+            *status = U_MEMORY_ALLOCATION_ERROR;
             return NULL;
         }
+        isStackObject = FALSE;
+    } else {  // fill-in
+        isStackObject = ures_isStackObject(r);
+        ures_closeBundle(r, FALSE);
     }
+    uprv_memset(r, 0, sizeof(UResourceBundle));
+    ures_setIsStackObject(r, isStackObject);
 
-    uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData));
-    r->fHasFallback=(UBool)!r->fResData.noFallback;
+    r->fTopLevelData = r->fData = entry;
+    uprv_memcpy(&r->fResData, &entry->fData, sizeof(ResourceData));
+    r->fHasFallback = openType != URES_OPEN_DIRECT && !r->fResData.noFallback;
+    r->fIsTopLevel = TRUE;
     r->fRes = r->fResData.rootRes;
     r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
-    /*
-    if(r->fData->fPath != NULL) {
-      ures_setResPath(r, r->fData->fPath);
-      ures_appendResPath(r, RES_PATH_PACKAGE_S);
-      ures_appendResPath(r, r->fData->fName);
-    } else {
-      ures_setResPath(r, r->fData->fName);
-    }
-    */
-
+    r->fIndex = -1;
 
     return r;
 }
 
+U_CAPI UResourceBundle* U_EXPORT2
+ures_open(const char* path, const char* localeID, UErrorCode* status) {
+    return ures_openWithType(NULL, path, localeID, URES_OPEN_LOCALE_DEFAULT_ROOT, status);
+}
+
+U_CAPI UResourceBundle* U_EXPORT2
+ures_openNoDefault(const char* path, const char* localeID, UErrorCode* status) {
+    return ures_openWithType(NULL, path, localeID, URES_OPEN_LOCALE_ROOT, status);
+}
+
 /**
  *  Opens a resource bundle without "canonicalizing" the locale name. No fallback will be performed 
  *  or sought. However, alias substitution will happen!
  */
 U_CAPI UResourceBundle*  U_EXPORT2
 ures_openDirect(const char* path, const char* localeID, UErrorCode* status) {
-    UResourceBundle *r;
-    UErrorCode subStatus = U_ZERO_ERROR;
-
-    if(status == NULL || U_FAILURE(*status)) {
-        return NULL;
-    }
-
-    r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
-    if(r == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return NULL;
-    }
+    return ures_openWithType(NULL, path, localeID, URES_OPEN_DIRECT, status);
+}
 
-    r->fHasFallback = FALSE;
-    r->fIsTopLevel = TRUE;
-    ures_setIsStackObject(r, FALSE);
-    r->fIndex = -1;
-    r->fData = entryOpen(path, localeID, &subStatus);
-    if(U_FAILURE(subStatus)) {
-        *status = subStatus;
-        uprv_free(r);
-        return NULL;
-    }
-    if(subStatus != U_ZERO_ERROR /*r->fData->fBogus != U_ZERO_ERROR*/) {
-      /* we didn't find one we were looking for - so openDirect */
-      /* should fail */
-        entryClose(r->fData);
-        uprv_free(r);
-        *status = U_MISSING_RESOURCE_ERROR;
-        return NULL;
+/**
+ *  API: This function is used to open a resource bundle 
+ *  proper fallback chaining is executed while initialization. 
+ *  The result is stored in cache for later fallback search.
+ */
+U_CAPI void U_EXPORT2
+ures_openFillIn(UResourceBundle *r, const char* path,
+                const char* localeID, UErrorCode* status) {
+    if(U_SUCCESS(*status) && r == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
     }
-
-    r->fKey = NULL;
-    r->fVersion = NULL;
-    uprv_memcpy(&r->fResData, &r->fData->fData, sizeof(ResourceData));
-    /* r->fHasFallback remains FALSE here in ures_openDirect() */
-    r->fRes = r->fResData.rootRes;
-    /*r->fParent = RES_BOGUS;*/
-    r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
-    r->fResPath = NULL;
-    r->fResPathLen = 0;
-    /*r->fParentRes = NULL;*/
-    r->fTopLevelData = r->fData;
-
-    return r;
+    ures_openWithType(r, path, localeID, URES_OPEN_LOCALE_DEFAULT_ROOT, status);
 }
 
 /**
index 11c3fdd6a121b27024f722449c1e8683f3d7cd15..b8ec5a61cac83089e51a98dfe7fe2c7fc15f4b72 100644 (file)
@@ -1,6 +1,6 @@
 /*
 **********************************************************************
-*   Copyright (C) 2000-2011, International Business Machines
+*   Copyright (C) 2000-2014, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 **********************************************************************
 */
 
 #define EMPTY_SET 0x2205
 
-/*
-enum UResEntryType {
-    ENTRY_OK = 0,
-    ENTRY_GOTO_ROOT = 1,
-    ENTRY_GOTO_DEFAULT = 2,
-    ENTRY_INVALID = 3
-};
-
-typedef enum UResEntryType UResEntryType;
-*/
-
 struct UResourceDataEntry;
 typedef struct UResourceDataEntry UResourceDataEntry;
 
@@ -91,6 +80,17 @@ struct UResourceBundle {
 
 U_CAPI void U_EXPORT2 ures_initStackObject(UResourceBundle* resB);
 
+/**
+ * Opens a resource bundle for the locale;
+ * if there is not even a base language bundle, then loads the root bundle;
+ * never falls back to the default locale.
+ *
+ * This is used for algorithms that have good pan-Unicode default behavior,
+ * such as case mappings, collation, and segmentation (BreakIterator).
+ */
+U_CAPI UResourceBundle* U_EXPORT2
+ures_openNoDefault(const char* path, const char* localeID, UErrorCode* status);
+
 /* Some getters used by the copy constructor */
 U_CFUNC const char* ures_getName(const UResourceBundle* resB);
 #ifdef URES_DEBUG
index b8d7ee7e9712c313437d69227c983f66ce6b12a9..55138ae0ecf85795486f2fc42f79f21d13516202 100644 (file)
@@ -224,7 +224,7 @@ const CollationCacheEntry *
 CollationLoader::loadFromLocale(UErrorCode &errorCode) {
     if(U_FAILURE(errorCode)) { return NULL; }
     U_ASSERT(bundle == NULL);
-    bundle = ures_open(U_ICUDATA_COLL, locale.getBaseName(), &errorCode);
+    bundle = ures_openNoDefault(U_ICUDATA_COLL, locale.getBaseName(), &errorCode);
     if(errorCode == U_MISSING_RESOURCE_ERROR) {
         errorCode = U_USING_DEFAULT_WARNING;
 
index 0d2fdccda3193c0d2b5d3b5cacd76d8b12a43cd7..4a5bef3a3e339c2aa06486196c2db12099437b56 100644 (file)
@@ -1446,7 +1446,7 @@ void TestGetLocale() {
     ucol_close(coll);
   }
 
-  /* completely non-existant locale for collator should get a default collator */
+  /* completely non-existent locale for collator should get a root collator */
   {
     UCollator *defaultColl = ucol_open(NULL, &status);
     coll = ucol_open("blahaha", &status);
@@ -1455,15 +1455,13 @@ void TestGetLocale() {
       if(strcmp(ucol_getLocaleByType(coll, ULOC_REQUESTED_LOCALE, &status), "blahaha")) {
         log_err("Nonexisting locale didn't preserve the requested locale\n");
       } */
-      if(strcmp(ucol_getLocaleByType(coll, ULOC_VALID_LOCALE, &status),
-        ucol_getLocaleByType(defaultColl, ULOC_VALID_LOCALE, &status))) {
-        log_err("Valid locale for nonexisting locale locale collator differs "
-          "from valid locale for default collator\n");
+      const char *name = ucol_getLocaleByType(coll, ULOC_VALID_LOCALE, &status);
+      if(*name != 0 && strcmp(name, "root") != 0) {
+        log_err("Valid locale for nonexisting-locale collator is \"%s\" not root\n", name);
       }
-      if(strcmp(ucol_getLocaleByType(coll, ULOC_ACTUAL_LOCALE, &status),
-        ucol_getLocaleByType(defaultColl, ULOC_ACTUAL_LOCALE, &status))) {
-        log_err("Actual locale for nonexisting locale locale collator differs "
-          "from actual locale for default collator\n");
+      name = ucol_getLocaleByType(coll, ULOC_ACTUAL_LOCALE, &status);
+      if(*name != 0 && strcmp(name, "root") != 0) {
+        log_err("Actual locale for nonexisting-locale collator is \"%s\" not root\n", name);
       }
       ucol_close(coll);
       ucol_close(defaultColl);
index 847434704e0943b168047bda0ebe6fa68fc1a628..e910ffefbbe2a5461c9937c6f123e279b4ff374f 100644 (file)
@@ -494,6 +494,7 @@ static const char *localeAndIndexCharactersLists[][2] = {
     /* English*/    {"en", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z"},
     /* Spanish*/    {"es", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:\\u00D1:O:P:Q:R:S:T:U:V:W:X:Y:Z"},
     /* Estonian*/   {"et", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:\\u0160:Z:\\u017D:T:U:V:\\u00D5:\\u00C4:\\u00D6:\\u00DC:X:Y"},
+    /* Basque*/ {"eu", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z"},
     /* Finnish*/    {"fi", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z:\\u00C5:\\u00C4:\\u00D6"},
     /* Filipino*/   {"fil", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z"},
     /* French*/ {"fr", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z"},
@@ -519,15 +520,6 @@ static const char *localeAndIndexCharactersLists[][2] = {
     /* Vietnamese*/ {"vi", "A:\\u0102:\\u00C2:B:C:D:\\u0110:E:\\u00CA:F:G:H:I:J:K:L:M:N:O:\\u00D4:\\u01A0:P:Q:R:S:T:U:\\u01AF:V:W:X:Y:Z"},
     /* Chinese*/    {"zh", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z"},
     /* Chinese (Traditional Han)*/  {"zh_Hant", "1\\u5283:2\\u5283:3\\u5283:4\\u5283:5\\u5283:6\\u5283:7\\u5283:8\\u5283:9\\u5283:10\\u5283:11\\u5283:12\\u5283:13\\u5283:14\\u5283:15\\u5283:16\\u5283:17\\u5283:18\\u5283:19\\u5283:20\\u5283:21\\u5283:22\\u5283:23\\u5283:24\\u5283:25\\u5283:26\\u5283:27\\u5283:28\\u5283:29\\u5283:30\\u5283:31\\u5283:32\\u5283:33\\u5283:35\\u5283:36\\u5283:39\\u5283:48\\u5283"},
-
-    // As of ICU 52, ICU does not have collation data for the following language.
-    // Therefore, constructing an AlphabeticIndex for it
-    // ends up with a collator for the default locale
-    // which makes the test unreliable. (see ticket #10277)
-    // It exposes a bigger problem in that it may not be desirable for collation
-    // to fall back to the default locale.
-
-    // /* Basque*/ {"eu", "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z"},
 };
 
 void AlphabeticIndexTest::TestIndexCharactersList() {
index 9d87bf07ce515a46a214628cc3073e28be507cc0..b3d9c7ec8d9bb461d0f0f887881a115743842fcb 100644 (file)
@@ -191,6 +191,7 @@ CollationAPITest::TestProperty(/* char* par */)
     doAssert((col->getStrength() == Collator::TERTIARY), "collation object's strength is not tertiary difference");
     doAssert((col->getStrength() != Collator::PRIMARY), "collation object's strength is primary difference");
     doAssert((col->getStrength() != Collator::SECONDARY), "collation object's strength is secondary difference");
+    delete col;
 
     logln("Create junk collation: ");
     Locale abcd("ab", "CD", "");
@@ -201,26 +202,15 @@ CollationAPITest::TestProperty(/* char* par */)
     if (U_FAILURE(success))
     {
         errln("Junk collation creation failed, should at least return default.");
-        delete col;
         return;
     }
 
-    delete col;
-    col = Collator::createInstance(success);
-    if (U_FAILURE(success))
-    {
-        errln("Creating default collator failed.");
-        delete junk;
-        return;
-    }
-
-    doAssert(((RuleBasedCollator *)col)->getRules() == ((RuleBasedCollator *)junk)->getRules(),
-               "The default collation should be returned.");
+    doAssert(((RuleBasedCollator *)junk)->getRules().isEmpty(),
+               "The root collation should be returned for an unsupported language.");
     Collator *frCol = Collator::createInstance(Locale::getCanadaFrench(), success);
     if (U_FAILURE(success))
     {
         errln("Creating fr_CA collator failed.");
-        delete col;
         delete junk;
         return;
     }
@@ -234,7 +224,6 @@ CollationAPITest::TestProperty(/* char* par */)
     doAssert((*frCol == *aFrCol), "The cloning of a fr_CA collator failed.");
     logln("Collator property test ended.");
 
-    delete col;
     delete frCol;
     delete aFrCol;
     delete junk;
@@ -1707,28 +1696,23 @@ void CollationAPITest::TestGetLocale() {
     delete coll;
   }
 
-  /* completely non-existant locale for collator should get a default collator */
+  /* completely non-existent locale for collator should get a root collator */
   {
-    Collator *defaultColl = Collator::createInstance((const Locale)NULL, status);
-    coll = Collator::createInstance("blahaha", status);
+    LocalPointer<Collator> coll(Collator::createInstance("blahaha", status));
     if(U_FAILURE(status)) {
       errln("Failed to open collator with %s", u_errorName(status));
-      delete coll;
-      delete defaultColl;
       return;
     }
-    if(coll->getLocale(ULOC_VALID_LOCALE, status) !=
-      defaultColl->getLocale(ULOC_VALID_LOCALE, status)) {
-      errln("Valid locale for nonexisting locale locale collator differs "
-        "from valid locale for default collator");
+    Locale valid = coll->getLocale(ULOC_VALID_LOCALE, status);
+    const char *name = valid.getName();
+    if(*name != 0 && strcmp(name, "root") != 0) {
+      errln("Valid locale for nonexisting-locale collator is \"%s\" not root", name);
     }
-    if(coll->getLocale(ULOC_ACTUAL_LOCALE, status) !=
-      defaultColl->getLocale(ULOC_ACTUAL_LOCALE, status)) {
-      errln("Actual locale for nonexisting locale locale collator differs "
-        "from actual locale for default collator");
+    Locale actual = coll->getLocale(ULOC_ACTUAL_LOCALE, status);
+    name = actual.getName();
+    if(*name != 0 && strcmp(name, "root") != 0) {
+      errln("Actual locale for nonexisting-locale collator is \"%s\" not root", name);
     }
-    delete coll;
-    delete defaultColl;
   }