]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/uresbund.c
ICU-6.2.4.tar.gz
[apple/icu.git] / icuSources / common / uresbund.c
index d72df6a1f41db54463d70ae2bd2ed3c3da730f5f..c3a7f0cf73eecfdad9a8f99cd86cc963402b1c13 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ******************************************************************************
-* Copyright (C) 1997-2003, International Business Machines Corporation and   *
+* Copyright (C) 1997-2004, International Business Machines Corporation and   *
 * others. All Rights Reserved.                                               *
 ******************************************************************************
 *
 */
 
 #include "unicode/ustring.h"
-
+#include "unicode/ucnv.h"
 #include "uresimp.h"
+#include "ustr_imp.h"
 #include "cwchar.h"
 #include "ucln_cmn.h"
 #include "cmemory.h"
 #include "cstring.h"
 #include "uhash.h"
+#include "unicode/uenum.h"
+#include "uenumimp.h"
+#include "ulocimp.h"
 #include "umutex.h"
+#include "putilimp.h"
 
 
 /*
@@ -134,29 +139,6 @@ static const ResourceData *getFallbackData(const UResourceBundle* resBundle, con
     }
 }
 
-/** INTERNAL: Initializes the cache for resources */
-static void initCache(UErrorCode *status) {
-  UBool makeCache = FALSE;
-  umtx_lock(&resbMutex);
-  makeCache = (cache ==  NULL);
-  umtx_unlock(&resbMutex);
-  if(makeCache) {
-      UHashtable *newCache = uhash_open(hashEntry, compareEntries, status);
-      if (U_FAILURE(*status)) {
-          return;
-      }
-      umtx_lock(&resbMutex);
-      if(cache == NULL) {
-          cache = newCache;
-          newCache = NULL;
-      }
-      umtx_unlock(&resbMutex);
-      if(newCache != NULL) {
-          uhash_close(newCache);
-      }
-  }
-}
-
 /* Works just like ucnv_flushCache() */
 /* TODO: figure out why fCountExisting may not go to zero. Do not make this function public yet. */
 static int32_t ures_flushCache()
@@ -189,6 +171,7 @@ static int32_t ures_flushCache()
         /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's not zero, that means that    */
         /* some resource bundles are still open somewhere. */
 
+        /*U_ASSERT(resB->fCountExisting == 0);*/
         if (resB->fCountExisting == 0) {
             rbDeletedNum++;
             uhash_removeElement(cache, e);
@@ -209,24 +192,45 @@ static int32_t ures_flushCache()
     return rbDeletedNum;
 }
 
-UBool ures_cleanup(void)
+static UBool U_CALLCONV ures_cleanup(void)
 {
     if (cache != NULL) {
         ures_flushCache();
         if (cache != NULL && uhash_count(cache) == 0) {
             uhash_close(cache);
             cache = NULL;
-            umtx_destroy(&resbMutex);
         }
     }
+    if (cache == NULL && resbMutex != NULL) {
+        umtx_destroy(&resbMutex);
+    }
     return (cache == NULL);
 }
 
-U_CFUNC void ures_init(UErrorCode *status) {
-    umtx_init(&resbMutex);
+/** INTERNAL: Initializes the cache for resources */
+static void initCache(UErrorCode *status) {
+    UBool makeCache = FALSE;
+    umtx_lock(&resbMutex);
+    makeCache = (cache ==  NULL);
+    umtx_unlock(&resbMutex);
+    if(makeCache) {
+        UHashtable *newCache = uhash_open(hashEntry, compareEntries, status);
+        if (U_FAILURE(*status)) {
+            return;
+        }
+        umtx_lock(&resbMutex);
+        if(cache == NULL) {
+            cache = newCache;
+            newCache = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_URES, ures_cleanup);
+        }
+        umtx_unlock(&resbMutex);
+        if(newCache != NULL) {
+            uhash_close(newCache);
+        }
+    }
 }
 
-
 /** INTERNAL: sets the name (locale) of the resource bundle to given name */
 
 static void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status) {
@@ -243,6 +247,7 @@ static void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status
 
 /**
  *  INTERNAL: Inits and opens an entry from a data DLL.
+ *    CAUTION:  resbMutex must be locked when calling this function.
  */
 static UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) {
     UResourceDataEntry *r = NULL;
@@ -269,9 +274,7 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
     }
 
     if(path != NULL) { /* if we actually have path, we'll use it */
-        if(uprv_strcmp(path, u_getDataDirectory()) != 0) { /* unless it is system default path */
-            myPath = path;
-        }
+      myPath = path;
     }
 
     find.fName = name;
@@ -374,6 +377,7 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
 }
 
 /* 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) {
   UResourceDataEntry *r = NULL;
   UBool hasRealData = FALSE;
@@ -407,6 +411,26 @@ static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool
   return r;
 }
 
+static void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
+    if(state) {
+        resB->fMagic1 = 0;
+        resB->fMagic2 = 0;
+    } else {
+        resB->fMagic1 = MAGIC1;
+        resB->fMagic2 = MAGIC2;
+    }
+}
+
+static UBool ures_isStackObject(const UResourceBundle* resB) {
+  return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE);
+}
+
+
+U_CFUNC void ures_initStackObject(UResourceBundle* resB) {
+  uprv_memset(resB, 0, sizeof(UResourceBundle));
+  ures_setIsStackObject(resB, TRUE);
+}
+
 static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UErrorCode* status) {
     UErrorCode intStatus = U_ZERO_ERROR;
     UErrorCode parentStatus = U_ZERO_ERROR;
@@ -514,6 +538,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
 
 /**
  * Functions to create and destroy resource bundles.
+ *     CAUTION:  resbMutex must be locked when calling this function.
  */
 /* INTERNAL: */
 static void entryCloseInt(UResourceDataEntry *resB) {
@@ -569,21 +594,54 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
         const UChar *alias = res_getAlias(rdata, r, &len);   
         if(len > 0) {
           /* we have an alias, now let's cut it up */
+          char stackAlias[200];
           char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = NULL;
-          chAlias = (char *)uprv_malloc((len+1)*sizeof(char));
-          /* test for NULL */
-          if(chAlias == NULL) {
-            *status = U_MEMORY_ALLOCATION_ERROR;
-            return NULL;
+          int32_t capacity;
+
+          /*
+           * Allocate enough space for both the char * version
+           * of the alias and parent->fResPath.
+           *
+           * We do this so that res_findResource() can modify the path,
+           * which allows us to remove redundant _res_findResource() variants
+           * in uresdata.c.
+           * res_findResource() now NUL-terminates each segment so that table keys
+           * can always be compared with strcmp() instead of strncmp().
+           * Saves code there and simplifies testing and code coverage.
+           *
+           * markus 2003oct17
+           */
+          ++len; /* count the terminating NUL */
+          if(parent != NULL && parent->fResPath != NULL) {
+            capacity = uprv_strlen(parent->fResPath) + 1;
+          } else {
+            capacity = 0;
+          }
+          if(capacity < len) {
+            capacity = len;
+          }
+          if(capacity <= sizeof(stackAlias)) {
+            capacity = sizeof(stackAlias);
+            chAlias = stackAlias;
+          } else {
+            chAlias = (char *)uprv_malloc(capacity);
+            /* test for NULL */
+            if(chAlias == NULL) {
+              *status = U_MEMORY_ALLOCATION_ERROR;
+              return NULL;
             }
+          }
           u_UCharsToChars(alias, chAlias, len);
-          chAlias[len] = 0;
 
           if(*chAlias == RES_PATH_SEPARATOR) {
             /* there is a path included */
             locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR);
-            *locale = 0;
-            locale++;
+            if(locale == NULL) {
+                locale = uprv_strchr(chAlias, 0); /* avoid locale == NULL to make code below work */
+            } else {
+                *locale = 0;
+                locale++;
+            }
             path = chAlias+1;
             if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */
               path = NULL;
@@ -614,23 +672,40 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
                 /* first, we are going to get a corresponding parent 
                  * resource to the one we are searching.
                  */
-                const char* aKey = parent->fResPath;
+                char *aKey = parent->fResPath;
                 if(aKey) {
+                  uprv_strcpy(chAlias, aKey); /* allocated large enough above */
+                  aKey = chAlias;
                   r = res_findResource(&(mainRes->fResData), mainRes->fRes, &aKey, &temp);
                 } else {
                   r = mainRes->fRes;
                 }
                 if(key) {
-                /* we need to make keyPath from parents fResPath and 
-                 * current key, if there is a key associated
-                 */
-                  aKey = key;
+                  /* we need to make keyPath from parent's fResPath and
+                   * current key, if there is a key associated
+                   */
+                  len = uprv_strlen(key) + 1;
+                  if(len > capacity) {
+                    capacity = len;
+                    if(chAlias == stackAlias) {
+                      chAlias = (char *)uprv_malloc(capacity);
+                    } else {
+                      chAlias = (char *)uprv_realloc(chAlias, capacity);
+                    }
+                    if(chAlias == NULL) {
+                      ures_close(mainRes);
+                      *status = U_MEMORY_ALLOCATION_ERROR;
+                      return NULL;
+                    }
+                  }
+                  uprv_memcpy(chAlias, key, len);
+                  aKey = chAlias;
                   r = res_findResource(&(mainRes->fResData), r, &aKey, &temp);
                 } else if(index != -1) {
                 /* if there is no key, but there is an index, try to get by the index */
                 /* here we have either a table or an array, so get the element */
-                  if(RES_GET_TYPE(r) == URES_TABLE) {
-                    r = res_getTableItemByIndex(&(mainRes->fResData), r, index, &aKey);
+                  if(RES_GET_TYPE(r) == URES_TABLE || RES_GET_TYPE(r) == URES_TABLE32) {
+                    r = res_getTableItemByIndex(&(mainRes->fResData), r, index, (const char **)&aKey);
                   } else { /* array */
                     r = res_getArrayItem(&(mainRes->fResData), r, index);
                   }
@@ -651,7 +726,7 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
                  */
                 result = mainRes;
                 while(*keyPath && U_SUCCESS(*status)) {
-                  r = res_findResource(&(result->fResData), result->fRes, (const char**)&keyPath, &temp);
+                  r = res_findResource(&(result->fResData), result->fRes, &keyPath, &temp);
                   if(r == RES_BOGUS) {
                     *status = U_MISSING_RESOURCE_ERROR;
                     result = resB;
@@ -664,8 +739,12 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
             } else { /* we failed to open the resource we're aliasing to */
               *status = intStatus;
             }
-            uprv_free(chAlias);
-            ures_close(mainRes);
+            if(chAlias != stackAlias) {
+              uprv_free(chAlias);
+            }
+            if(mainRes != result) {
+              ures_close(mainRes);
+            }
             return result;
           }
         } else {
@@ -687,6 +766,7 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
         }
         ures_setIsStackObject(resB, FALSE);
         resB->fResPath = NULL;
+        resB->fResPathLen = 0;
     } else {
         if(resB->fData != NULL) {
             entryClose(resB->fData);
@@ -697,6 +777,9 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
         if(ures_isStackObject(resB) != FALSE) {
             ures_initStackObject(resB);
         }
+        if(parent != resB) {
+            ures_freeResPath(resB);
+        }
     }
     resB->fData = realData;
     entryIncrease(resB->fData);
@@ -704,8 +787,9 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
     resB->fIsTopLevel = FALSE;
     resB->fIndex = -1;
     resB->fKey = key;
-    ures_freeResPath(resB);
-    if(parent->fResPath) {
+    resB->fParentRes = parent;
+    resB->fTopLevelData = parent->fTopLevelData;
+    if(parent->fResPath && parent != resB) {
       ures_appendResPath(resB, parent->fResPath, parent->fResPathLen);
     }
     if(key != NULL) {
@@ -759,6 +843,7 @@ UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *origin
         }
         uprv_memcpy(r, original, sizeof(UResourceBundle));
         r->fResPath = NULL;
+        r->fResPathLen = 0;
         if(original->fResPath) {
           ures_appendResPath(r, original->fResPath, original->fResPathLen);
         }
@@ -794,6 +879,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_
         case URES_BINARY:
         case URES_ARRAY:
         case URES_TABLE:
+        case URES_TABLE32:
         default:
             *status = U_RESOURCE_TYPE_MISMATCH;
     }
@@ -818,6 +904,7 @@ U_CAPI const uint8_t* U_EXPORT2 ures_getBinary(const UResourceBundle* resB, int3
   case URES_INT_VECTOR:
   case URES_ARRAY:
   case URES_TABLE:
+  case URES_TABLE32:
   default:
     *status = U_RESOURCE_TYPE_MISMATCH;
   }
@@ -842,6 +929,7 @@ U_CAPI const int32_t* U_EXPORT2 ures_getIntVector(const UResourceBundle* resB, i
   case URES_ARRAY:
   case URES_BINARY:
   case URES_TABLE:
+  case URES_TABLE32:
   default:
     *status = U_RESOURCE_TYPE_MISMATCH;
   }
@@ -882,14 +970,17 @@ U_CAPI uint32_t U_EXPORT2 ures_getUInt(const UResourceBundle* resB, UErrorCode *
 }
 
 
-U_CAPI UResType U_EXPORT2 ures_getType(UResourceBundle *resB) {
+U_CAPI UResType U_EXPORT2 ures_getType(const UResourceBundle *resB) {
+  UResType type;
+
   if(resB == NULL) {
     return URES_NONE;
   }
-  return (UResType) (RES_GET_TYPE(resB->fRes));
+  type = (UResType) RES_GET_TYPE(resB->fRes);
+  return type == URES_TABLE32 ? URES_TABLE : type;
 }
 
-U_CAPI const char * U_EXPORT2 ures_getKey(UResourceBundle *resB) {
+U_CAPI const char * U_EXPORT2 ures_getKey(const UResourceBundle *resB) {
   if(resB == NULL) {
     return NULL;
   }
@@ -897,7 +988,7 @@ U_CAPI const char * U_EXPORT2 ures_getKey(UResourceBundle *resB) {
   return(resB->fKey);
 }
 
-U_CAPI int32_t U_EXPORT2 ures_getSize(UResourceBundle *resB) {
+U_CAPI int32_t U_EXPORT2 ures_getSize(const UResourceBundle *resB) {
   if(resB == NULL) {
     return 0;
   }
@@ -924,7 +1015,7 @@ U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resB){
   resB->fIndex = -1;
 }
 
-U_CAPI UBool U_EXPORT2 ures_hasNext(UResourceBundle *resB) {
+U_CAPI UBool U_EXPORT2 ures_hasNext(const UResourceBundle *resB) {
   if(resB == NULL) {
     return FALSE;
   }
@@ -952,6 +1043,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resB, int32_t*
     case URES_STRING:
       return res_getString(&(resB->fResData), resB->fRes, len); 
     case URES_TABLE:
+    case URES_TABLE32:
       r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, key);
       if(r == RES_BOGUS && resB->fHasFallback) {
         /* TODO: do the fallback */
@@ -1000,6 +1092,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resB, UR
         case URES_STRING:
             return ures_copyResb(fillIn, resB, status);
         case URES_TABLE:
+        case URES_TABLE32:
             r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, &key);
             if(r == RES_BOGUS && resB->fHasFallback) {
                 /* TODO: do the fallback */
@@ -1042,6 +1135,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resB, i
         case URES_STRING:
             return ures_copyResb(fillIn, resB, status);
         case URES_TABLE:
+        case URES_TABLE32:
             r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexR, &key);
             if(r == RES_BOGUS && resB->fHasFallback) {
                 /* TODO: do the fallback */
@@ -1084,6 +1178,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB,
         case URES_STRING:
             return res_getString(&(resB->fResData), resB->fRes, len);
         case URES_TABLE:
+        case URES_TABLE32:
             r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexS, &key);
             if(r == RES_BOGUS && resB->fHasFallback) {
                 /* TODO: do the fallback */
@@ -1120,16 +1215,21 @@ ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status)
   char *packageName = NULL;
   char *pathToResource = NULL;
   char *locale = NULL, *localeEnd = NULL;
+  int32_t length;
+
   if(status == NULL || U_FAILURE(*status)) {
     return result;
   }
-  pathToResource = (char *)uprv_malloc((uprv_strlen(path)+1)*sizeof(char));
+
+  length = uprv_strlen(path)+1;
+  pathToResource = (char *)uprv_malloc(length*sizeof(char));
   /* test for NULL */
   if(pathToResource == NULL) {
     *status = U_MEMORY_ALLOCATION_ERROR;
     return result;
-    }
-  uprv_strcpy(pathToResource, path);
+  }
+  uprv_memcpy(pathToResource, path, length);
+
   locale = pathToResource;
   if(*pathToResource == RES_PATH_SEPARATOR) { /* there is a path specification */
     pathToResource++;
@@ -1143,7 +1243,7 @@ ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status)
     }
   }
 
-  localeEnd = strchr(locale, RES_PATH_SEPARATOR);
+  localeEnd = uprv_strchr(locale, RES_PATH_SEPARATOR);
   if(localeEnd != NULL) {
     *localeEnd = 0;
   }
@@ -1163,11 +1263,10 @@ ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status)
 }
 
 U_CAPI UResourceBundle* U_EXPORT2
-ures_findSubResource(const UResourceBundle *resB, const char* path, UResourceBundle *fillIn, UErrorCode *status) 
+ures_findSubResource(const UResourceBundle *resB, char* path, UResourceBundle *fillIn, UErrorCode *status) 
 {
   Resource res = RES_BOGUS;
   UResourceBundle *result = fillIn;
-  const char *pathToResource = path;
   const char *key;
 
   if(status == NULL || U_FAILURE(*status)) {
@@ -1175,16 +1274,81 @@ ures_findSubResource(const UResourceBundle *resB, const char* path, UResourceBun
   }
 
   /* here we do looping and circular alias checking */
+  /* this loop is here because aliasing is resolved on this level, not on res level */
+  /* so, when we encounter an alias, it is not an aggregate resource, so we return */
+  do {
+    res = res_findResource(&(resB->fResData), resB->fRes, &path, &key); 
+    if(res != RES_BOGUS) {
+        result = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
+        resB = result;
+    } else {
+        *status = U_MISSING_RESOURCE_ERROR;
+        break;
+    }
+  } while(uprv_strlen(path)); /* there is more stuff in the path */
 
-  res = res_findResource(&(resB->fResData), resB->fRes, &pathToResource, &key); 
+  return result;
+}
 
-  if(res != RES_BOGUS) {
-    result = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
-  } else {
-    *status = U_MISSING_RESOURCE_ERROR;
-  }
+U_CAPI UResourceBundle* U_EXPORT2 
+ures_getByKeyWithFallback(const UResourceBundle *resB, 
+                          const char* inKey, 
+                          UResourceBundle *fillIn, 
+                          UErrorCode *status) {
+    Resource res = RES_BOGUS;
+    /*UResourceDataEntry *realData = NULL;*/
+    const char *key = inKey;
+    UResourceBundle *helper = NULL;
 
-  return result;
+    if (status==NULL || U_FAILURE(*status)) {
+        return fillIn;
+    }
+    if(resB == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return fillIn;
+    }
+
+    if(RES_GET_TYPE(resB->fRes) == URES_TABLE || RES_GET_TYPE(resB->fRes) == URES_TABLE32) {
+        int32_t t;
+        res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
+        if(res == RES_BOGUS) {
+            UResourceDataEntry *dataEntry = resB->fData;
+            char path[256];
+            char* myPath = path;
+
+            while(res == RES_BOGUS && dataEntry->fParent != NULL) { /* Otherwise, we'll look in parents */
+                dataEntry = dataEntry->fParent;
+                if(dataEntry->fBogus == U_ZERO_ERROR) {
+                    uprv_strncpy(path, resB->fResPath, resB->fResPathLen);
+                    uprv_strcpy(path+resB->fResPathLen, inKey);
+                    myPath = path;
+                    key = inKey;
+                    do {
+                        res = res_findResource(&(dataEntry->fData), dataEntry->fData.rootRes, &myPath, &key);
+                        if (RES_GET_TYPE(res) == URES_ALIAS && *myPath) {
+                            /* We hit an alias, but we didn't finish following the path. */
+                            helper = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, helper, status);
+                            dataEntry = helper->fData;
+                        }
+                    } while(uprv_strlen(myPath));
+                }
+            }
+            /*const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);*/
+            if(res != RES_BOGUS) {
+              /* check if resB->fResPath gives the right name here */
+                fillIn = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, fillIn, status);
+            } else {
+                *status = U_MISSING_RESOURCE_ERROR;
+            }
+        } else {
+            fillIn = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
+        }
+    } 
+    else {
+        *status = U_RESOURCE_TYPE_MISMATCH;
+    }
+    ures_close(helper);
+    return fillIn;
 }
 
 
@@ -1201,7 +1365,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con
         return fillIn;
     }
 
-    if(RES_GET_TYPE(resB->fRes) == URES_TABLE) {
+    if(RES_GET_TYPE(resB->fRes) == URES_TABLE || RES_GET_TYPE(resB->fRes) == URES_TABLE32) {
         int32_t t;
         res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
         if(res == RES_BOGUS) {
@@ -1253,7 +1417,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c
         return NULL;
     }
 
-    if(RES_GET_TYPE(resB->fRes) == URES_TABLE) {
+    if(RES_GET_TYPE(resB->fRes) == URES_TABLE || RES_GET_TYPE(resB->fRes) == URES_TABLE32) {
         int32_t t=0;
 
         res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
@@ -1266,6 +1430,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c
                     switch (RES_GET_TYPE(res)) {
                     case URES_STRING:
                     case URES_TABLE:
+                    case URES_TABLE32:
                     case URES_ARRAY:
                         return res_getString(rd, res, len);
                     case URES_ALIAS:
@@ -1289,6 +1454,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c
             switch (RES_GET_TYPE(res)) {
             case URES_STRING:
             case URES_TABLE:
+            case URES_TABLE32:
             case URES_ARRAY:
                 return res_getString(&(resB->fResData), res, len);
             case URES_ALIAS:
@@ -1344,6 +1510,35 @@ ures_getLocale(const UResourceBundle* resourceBundle, UErrorCode* status)
     }
 }
 
+U_CAPI const char* U_EXPORT2 
+ures_getLocaleByType(const UResourceBundle* resourceBundle, 
+                     ULocDataLocaleType type, 
+                     UErrorCode* status) {
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if (!resourceBundle) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    } else {
+        switch(type) {
+        case ULOC_ACTUAL_LOCALE:
+            return resourceBundle->fData->fName;
+            break;
+        case ULOC_VALID_LOCALE:
+            return resourceBundle->fTopLevelData->fName;
+            break;
+        case ULOC_REQUESTED_LOCALE:
+            return NULL;
+            break;
+        default:
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return NULL;
+        }
+    }
+}
+
+
 /*
 U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
   if(resB->fResPath == NULL) {
@@ -1388,6 +1583,7 @@ U_CFUNC void ures_freeResPath(UResourceBundle *resB) {
   resB->fResPathLen = 0;
 }
 
+
 U_CFUNC const char* ures_getName(const UResourceBundle* resB) {
   if(resB == NULL) {
     return NULL;
@@ -1442,18 +1638,13 @@ ures_openFillIn(UResourceBundle *r, const char* path,
         r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
         /*r->fParent = RES_BOGUS;*/
         /*r->fResPath = NULL;*/
+        r->fParentRes = NULL;
+        r->fTopLevelData = r->fData;
+
         ures_freeResPath(r);
-        /*
-        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);
-        }
-        */
     }
 }
+
 U_CAPI UResourceBundle*  U_EXPORT2
 ures_open(const char* path,
                     const char* localeID,
@@ -1469,7 +1660,7 @@ ures_open(const char* path,
     }
 
     /* first "canonicalize" the locale ID */
-    length = uloc_getName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
+    length = uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
     if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
         *status = U_ILLEGAL_ARGUMENT_ERROR;
         return NULL;
@@ -1492,6 +1683,8 @@ ures_open(const char* path,
         uprv_free(r);
         return NULL;
     }
+    r->fParentRes = NULL;
+    r->fTopLevelData = r->fData;
 
     hasData = r->fData;
     while(hasData->fBogus != U_ZERO_ERROR) {
@@ -1513,6 +1706,7 @@ ures_open(const char* path,
     /*r->fParent = RES_BOGUS;*/
     r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
     r->fResPath = NULL;
+    r->fResPathLen = 0;
     /*
     if(r->fData->fPath != NULL) {
       ures_setResPath(r, r->fData->fPath);
@@ -1527,31 +1721,6 @@ ures_open(const char* path,
     return r;
 }
 
-U_CAPI UResourceBundle* U_EXPORT2 ures_openU(const UChar* myPath, 
-                  const char* localeID, 
-                  UErrorCode* status)
-{
-    UResourceBundle *r;
-    int32_t pathSize = u_strlen(myPath) + 1;
-    char *path = (char *)uprv_malloc(pathSize);
-    /* test for NULL */
-    if(path == NULL) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return NULL;
-    }
-
-    u_UCharsToChars(myPath, path, pathSize);
-
-    r = ures_open(path, localeID, status);
-    uprv_free(path);
-
-    if (U_FAILURE(*status)) {
-        return NULL;
-    }
-
-    return r;
-}
-
 /**
  *  Opens a resource bundle without "canonicalizing" the locale name. No fallback will be performed 
  *  or sought. However, alias substitution will happen!
@@ -1559,6 +1728,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_openU(const UChar* myPath,
 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;
@@ -1574,12 +1744,13 @@ ures_openDirect(const char* path, const char* localeID, UErrorCode* status) {
     r->fIsTopLevel = TRUE;
     ures_setIsStackObject(r, FALSE);
     r->fIndex = -1;
-    r->fData = entryOpen(path, localeID, status);
-    if(U_FAILURE(*status)) {
+    r->fData = entryOpen(path, localeID, &subStatus);
+    if(U_FAILURE(subStatus)) {
+        *status = subStatus;
         uprv_free(r);
         return NULL;
     }
-    if(*status != U_ZERO_ERROR /*r->fData->fBogus != U_ZERO_ERROR*/) {
+    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);
@@ -1597,36 +1768,11 @@ ures_openDirect(const char* path, const char* localeID, UErrorCode* status) {
     /*r->fParent = RES_BOGUS;*/
     r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
     r->fResPath = NULL;
-    /*
-    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);
-    }
-    */
-    return r;
-}
-
-U_CFUNC void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
-    if(state) {
-        resB->fMagic1 = 0;
-        resB->fMagic2 = 0;
-    } else {
-        resB->fMagic1 = MAGIC1;
-        resB->fMagic2 = MAGIC2;
-    }
-}
-
-U_CFUNC UBool ures_isStackObject(UResourceBundle* resB) {
-  return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE);
-}
-
+    r->fResPathLen = 0;
+    r->fParentRes = NULL;
+    r->fTopLevelData = r->fData;
 
-U_CFUNC void ures_initStackObject(UResourceBundle* resB) {
-  memset(resB, 0, sizeof(UResourceBundle));
-  ures_setIsStackObject(resB, TRUE);
+    return r;
 }
 
 /**
@@ -1640,23 +1786,23 @@ ures_countArrayItems(const UResourceBundle* resourceBundle,
 {
     UResourceBundle resData;
     ures_initStackObject(&resData);
-        if (status==NULL || U_FAILURE(*status)) {
-                return 0;
-        }
-        if(resourceBundle == NULL) {
-                *status = U_ILLEGAL_ARGUMENT_ERROR;
-                return 0;
-        }
+    if (status==NULL || U_FAILURE(*status)) {
+        return 0;
+    }
+    if(resourceBundle == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
     ures_getByKey(resourceBundle, resourceKey, &resData, status);
-
+    
     if(resData.fResData.data != NULL) {
-      int32_t result = res_countArrayItems(&resData.fResData, resData.fRes);
-      ures_close(&resData);
-      return result;
+        int32_t result = res_countArrayItems(&resData.fResData, resData.fRes);
+        ures_close(&resData);
+        return result;
     } else {
-      *status = U_MISSING_RESOURCE_ERROR;
-      ures_close(&resData);
-      return 0;
+        *status = U_MISSING_RESOURCE_ERROR;
+        ures_close(&resData);
+        return 0;
     }
 }
 
@@ -1675,6 +1821,12 @@ ures_close(UResourceBundle*    resB)
         if(ures_isStackObject(resB) == FALSE) {
             uprv_free(resB);
         }
+        else {
+#if 0 /*U_DEBUG*/
+            /* poison the data */
+            uprv_memset(resB, -1, sizeof(UResourceBundle));
+#endif
+        }
     }
 }
 
@@ -1692,7 +1844,7 @@ ures_getVersionNumber(const UResourceBundle*   resourceBundle)
         int32_t len;
 
         const UChar* minor_version = ures_getStringByKey(resourceBundle, kVersionTag, &minor_len, &status);
-    
+        
         /* Determine the length of of the final version string.  This is */
         /* the length of the major part + the length of the separator */
         /* (==1) + the length of the minor part (+ 1 for the zero byte at */
@@ -1705,13 +1857,13 @@ ures_getVersionNumber(const UResourceBundle*   resourceBundle)
 
 
         ((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_malloc(1 + len); 
-    
+       
         if(minor_len > 0) {
             u_UCharsToChars(minor_version, resourceBundle->fVersion , minor_len);
             resourceBundle->fVersion[len] =  '\0';
         }
         else {
-          uprv_strcat(resourceBundle->fVersion, kDefaultMinorVersion);
+          uprv_strcpy(resourceBundle->fVersion, kDefaultMinorVersion);
         }
     }
 
@@ -1724,4 +1876,516 @@ U_CAPI void U_EXPORT2 ures_getVersion(const UResourceBundle* resB, UVersionInfo
     u_versionFromString(versionInfo, ures_getVersionNumber(resB));
 }
 
+/** Tree support functions *******************************/
+#define INDEX_LOCALE_NAME "res_index"
+#define INDEX_TAG         "InstalledLocales"
+#define DEFAULT_TAG       "default"
+
+#if defined(URES_TREE_DEBUG)
+#include <stdio.h>
+#endif
+
+typedef struct ULocalesContext {
+    UResourceBundle installed;
+    UResourceBundle curr;
+} ULocalesContext;
+
+static void U_CALLCONV
+ures_loc_closeLocales(UEnumeration *enumerator) {
+    ULocalesContext *ctx = (ULocalesContext *)enumerator->context;
+    ures_close(&ctx->curr);
+    ures_close(&ctx->installed);
+    uprv_free(ctx);
+    uprv_free(enumerator);
+}
+
+static int32_t U_CALLCONV
+ures_loc_countLocales(UEnumeration *en, UErrorCode *status) {
+    ULocalesContext *ctx = (ULocalesContext *)en->context;
+    return ures_getSize(&ctx->installed);
+}
+
+static const char* U_CALLCONV 
+ures_loc_nextLocale(UEnumeration* en,
+                    int32_t* resultLength,
+                    UErrorCode* status) {
+    ULocalesContext *ctx = (ULocalesContext *)en->context;
+    UResourceBundle *res = &(ctx->installed);
+    UResourceBundle *k = NULL;
+    const char *result = NULL;
+    int32_t len = 0;
+    if(ures_hasNext(res) && (k = ures_getNextResource(res, &ctx->curr, status))) {
+        result = ures_getKey(k);
+        len = uprv_strlen(result);
+    }
+    if (resultLength) {
+        *resultLength = len;
+    }
+    return result;
+}
+
+static void U_CALLCONV 
+ures_loc_resetLocales(UEnumeration* en, 
+                      UErrorCode* status) {
+    UResourceBundle *res = &((ULocalesContext *)en->context)->installed;
+    ures_resetIterator(res);
+}
+
+
+static const UEnumeration gLocalesEnum = {
+    NULL,
+        NULL,
+        ures_loc_closeLocales,
+        ures_loc_countLocales,
+        uenum_unextDefault,
+        ures_loc_nextLocale,
+        ures_loc_resetLocales
+};
+
+
+U_CAPI UEnumeration* U_EXPORT2
+ures_openAvailableLocales(const char *path, UErrorCode *status)
+{
+    UResourceBundle *index = NULL;
+    UEnumeration *en = NULL;
+    ULocalesContext *myContext = NULL;
+    
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+    myContext = uprv_malloc(sizeof(ULocalesContext));
+    en =  (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
+    if(!en || !myContext) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        uprv_free(en);
+        uprv_free(myContext);
+        return NULL;
+    }
+    uprv_memcpy(en, &gLocalesEnum, sizeof(UEnumeration));
+    
+    ures_initStackObject(&myContext->installed);
+    ures_initStackObject(&myContext->curr);
+    index = ures_openDirect(path, INDEX_LOCALE_NAME, status);
+    ures_getByKey(index, INDEX_TAG, &myContext->installed, status);
+    if(U_SUCCESS(*status)) {
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "Got %s::%s::[%s] : %s\n", 
+            path, INDEX_LOCALE_NAME, INDEX_TAG, ures_getKey(&myContext->installed));
+#endif
+        en->context = myContext;
+    } else {
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "%s open failed - %s\n", path, u_errorName(*status));
+#endif
+        ures_close(&myContext->installed);
+        uprv_free(myContext);
+        uprv_free(en);
+        en = NULL;
+    }
+    
+    ures_close(index);
+    
+    return en;
+}
+
+U_CAPI int32_t U_EXPORT2
+ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
+                             const char *path, const char *resName, const char *keyword, const char *locid,
+                             UBool *isAvailable, UBool omitDefault, UErrorCode *status)
+{
+    char kwVal[1024] = ""; /* value of keyword 'keyword' */
+    char defVal[1024] = ""; /* default value for given locale */
+    char defLoc[1024] = ""; /* default value for given locale */
+    char base[1024] = ""; /* base locale */
+    char found[1024];
+    char parent[1024];
+    char full[1024] = "";
+    UResourceBundle bund1, bund2;
+    UResourceBundle *res = NULL;
+    UErrorCode subStatus = U_ZERO_ERROR;
+    int32_t length = 0;
+    if(U_FAILURE(*status)) return 0;
+    if(isAvailable) { 
+        *isAvailable = TRUE;
+    }
+    uloc_getKeywordValue(locid, keyword, kwVal, 1024-1,&subStatus);
+    if(!uprv_strcmp(kwVal, DEFAULT_TAG)) {
+        kwVal[0]=0;
+    }
+    uloc_getBaseName(locid, base, 1024-1,&subStatus);
+#if defined(URES_TREE_DEBUG)
+    fprintf(stderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n", 
+            locid, keyword, kwVal, base, u_errorName(subStatus));
+#endif
+    ures_initStackObject(&bund1);
+    ures_initStackObject(&bund2);
+    
+    
+    uprv_strcpy(parent, base);
+    uprv_strcpy(found, base);
+    
+    if(U_FAILURE(subStatus)) {
+        *status = subStatus;
+        return 0;
+    }
+    
+    do {
+        subStatus = U_ZERO_ERROR;
+        res = ures_open(path, parent, &subStatus);
+        if(((subStatus == U_USING_FALLBACK_WARNING) ||
+            (subStatus == U_USING_DEFAULT_WARNING)) && isAvailable) {
+            *isAvailable = FALSE;
+        }
+        isAvailable = NULL; /* only want to set this the first time around */
+        
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "%s;%s -> %s [%s]\n", path?path:"ICUDATA", parent, u_errorName(subStatus), ures_getLocale(res, &subStatus));
+#endif
+        if(U_FAILURE(subStatus)) {
+            *status = subStatus;
+        } else if(subStatus == U_ZERO_ERROR) {
+            ures_getByKey(res,resName,&bund1, &subStatus);
+            if(subStatus == U_ZERO_ERROR) {
+                const UChar *defUstr;
+                int32_t defLen;
+                /* look for default item */
+#if defined(URES_TREE_DEBUG)
+                fprintf(stderr, "%s;%s : loaded default -> %s\n",
+                    path?path:"ICUDATA", parent, u_errorName(subStatus));
+#endif
+                defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus);
+                if(U_SUCCESS(subStatus) && defLen) {
+                    u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "%s;%s -> default %s=%s,  %s\n", 
+                        path?path:"ICUDATA", parent, keyword, defVal, u_errorName(subStatus));
+#endif
+                    uprv_strcpy(defLoc, parent);
+                    if(kwVal[0]==0) {
+                        uprv_strcpy(kwVal, defVal);
+#if defined(URES_TREE_DEBUG)
+                        fprintf(stderr, "%s;%s -> kwVal =  %s\n", 
+                            path?path:"ICUDATA", parent, keyword, kwVal);
+#endif
+                    }
+                }
+            }
+        }
+        
+        subStatus = U_ZERO_ERROR;
+        
+        uprv_strcpy(found, parent);
+        uloc_getParent(found,parent,1023,&subStatus);
+        ures_close(res);
+    } while(!defVal[0] && *found && U_SUCCESS(*status));
+    
+    /* Now, see if we can find the kwVal collator.. start the search over.. */
+    uprv_strcpy(parent, base);
+    uprv_strcpy(found, base);
+    
+    do {
+        subStatus = U_ZERO_ERROR;
+        res = ures_open(path, parent, &subStatus);
+        if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
+            *isAvailable = FALSE;
+        }
+        isAvailable = NULL; /* only want to set this the first time around */
+        
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "%s;%s -> %s (looking for %s)\n", 
+            path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal);
+#endif
+        if(U_FAILURE(subStatus)) {
+            *status = subStatus;
+        } else if(subStatus == U_ZERO_ERROR) {
+            ures_getByKey(res,resName,&bund1, &subStatus);
+#if defined(URES_TREE_DEBUG)
+/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, resName, u_errorName(subStatus));
+#endif
+            if(subStatus == U_ZERO_ERROR) {
+                ures_getByKey(&bund1, kwVal, &bund2, &subStatus);
+#if defined(URES_TREE_DEBUG)
+/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, kwVal, u_errorName(subStatus));
+#endif
+                if(subStatus == U_ZERO_ERROR) {
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "%s;%s -> full0 %s=%s,  %s\n", 
+                        path?path:"ICUDATA", parent, keyword, kwVal, u_errorName(subStatus));
+#endif
+                    uprv_strcpy(full, parent);
+                    if(*full == 0) {
+                        uprv_strcpy(full, "root");
+                    }
+                        /* now, recalculate default kw if need be */
+                        if(uprv_strlen(defLoc) > uprv_strlen(full)) {
+                          const UChar *defUstr;
+                          int32_t defLen;
+                          /* look for default item */
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> recalculating Default0\n", 
+                                    path?path:"ICUDATA", full);
+#endif
+                          defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus);
+                          if(U_SUCCESS(subStatus) && defLen) {
+                            u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> default0 %s=%s,  %s\n", 
+                                    path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus));
+#endif
+                            uprv_strcpy(defLoc, full);
+                          }
+                        } /* end of recalculate default KW */
+#if defined(URES_TREE_DEBUG)
+                        else {
+                          fprintf(stderr, "No trim0,  %s <= %s\n", defLoc, full);
+                        }
+#endif
+                } else {
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "err=%s in %s looking for %s\n", 
+                        u_errorName(subStatus), parent, kwVal);
+#endif
+                }
+            }
+        }
+        
+        subStatus = U_ZERO_ERROR;
+        
+        uprv_strcpy(found, parent);
+        uloc_getParent(found,parent,1023,&subStatus);
+        ures_close(res);
+    } while(!full[0] && *found && U_SUCCESS(*status));
+    
+    if((full[0]==0) && uprv_strcmp(kwVal, defVal)) {
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "Failed to locate kw %s - try default %s\n", kwVal, defVal);
+#endif
+        uprv_strcpy(kwVal, defVal);
+        uprv_strcpy(parent, base);
+        uprv_strcpy(found, base);
+        
+        do { /* search for 'default' named item */
+            subStatus = U_ZERO_ERROR;
+            res = ures_open(path, parent, &subStatus);
+            if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
+                *isAvailable = FALSE;
+            }
+            isAvailable = NULL; /* only want to set this the first time around */
+            
+#if defined(URES_TREE_DEBUG)
+            fprintf(stderr, "%s;%s -> %s (looking for default %s)\n",
+                path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal);
+#endif
+            if(U_FAILURE(subStatus)) {
+                *status = subStatus;
+            } else if(subStatus == U_ZERO_ERROR) {
+                ures_getByKey(res,resName,&bund1, &subStatus);
+                if(subStatus == U_ZERO_ERROR) {
+                    ures_getByKey(&bund1, kwVal, &bund2, &subStatus);
+                    if(subStatus == U_ZERO_ERROR) {
+#if defined(URES_TREE_DEBUG)
+                        fprintf(stderr, "%s;%s -> full1 %s=%s,  %s\n", path?path:"ICUDATA",
+                            parent, keyword, kwVal, u_errorName(subStatus));
+#endif
+                        uprv_strcpy(full, parent);
+                        if(*full == 0) {
+                            uprv_strcpy(full, "root");
+                        }
+                        
+                        /* now, recalculate default kw if need be */
+                        if(uprv_strlen(defLoc) > uprv_strlen(full)) {
+                          const UChar *defUstr;
+                          int32_t defLen;
+                          /* look for default item */
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> recalculating Default1\n", 
+                                    path?path:"ICUDATA", full);
+#endif
+                          defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus);
+                          if(U_SUCCESS(subStatus) && defLen) {
+                            u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> default %s=%s,  %s\n", 
+                                    path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus));
+#endif
+                            uprv_strcpy(defLoc, full);
+                          }
+                        } /* end of recalculate default KW */
+#if defined(URES_TREE_DEBUG)
+                        else {
+                          fprintf(stderr, "No trim1,  %s <= %s\n", defLoc, full);
+                        }
+#endif
+                    }
+                }
+            }
+            subStatus = U_ZERO_ERROR;
+            
+            uprv_strcpy(found, parent);
+            uloc_getParent(found,parent,1023,&subStatus);
+            ures_close(res);
+        } while(!full[0] && *found && U_SUCCESS(*status));
+    }
+    
+    if(U_SUCCESS(*status)) {
+        if(!full[0]) {
+#if defined(URES_TREE_DEBUG)
+          fprintf(stderr, "Still could not load keyword %s=%s\n", keyword, kwVal);
+#endif
+          *status = U_MISSING_RESOURCE_ERROR;
+        } else if(omitDefault) {
+#if defined(URES_TREE_DEBUG)
+          fprintf(stderr,"Trim? full=%s, defLoc=%s, found=%s\n", full, defLoc, found);
+#endif        
+          if(uprv_strlen(defLoc) <= uprv_strlen(full)) {
+            /* found the keyword in a *child* of where the default tag was present. */
+            if(!uprv_strcmp(kwVal, defVal)) { /* if the requested kw is default, */
+              /* and the default is in or in an ancestor of the current locale */
+#if defined(URES_TREE_DEBUG)
+              fprintf(stderr, "Removing unneeded var %s=%s\n", keyword, kwVal);
+#endif
+              kwVal[0]=0;
+            }
+          }
+        }
+        uprv_strcpy(found, full);
+        if(kwVal[0]) {
+            uprv_strcat(found, "@");
+            uprv_strcat(found, keyword);
+            uprv_strcat(found, "=");
+            uprv_strcat(found, kwVal);
+        } else if(!omitDefault) {
+            uprv_strcat(found, "@");
+            uprv_strcat(found, keyword);
+            uprv_strcat(found, "=");
+            uprv_strcat(found, defVal);
+        }
+    }
+    /* we found the default locale - no need to repeat it.*/
+    
+    ures_close(&bund1);
+    ures_close(&bund2);
+    
+    length = uprv_strlen(found);
+
+    if(U_SUCCESS(*status)) {
+        int32_t copyLength = uprv_min(length, resultCapacity);
+        if(copyLength>0) {
+            uprv_strncpy(result, found, copyLength);
+        }
+        if(length == 0) {
+          *status = U_MISSING_RESOURCE_ERROR; 
+        }
+    } else {
+        length = 0;
+        result[0]=0;
+    }
+    return u_terminateChars(result, resultCapacity, length, status);
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status)
+{
+#define VALUES_BUF_SIZE 2048
+#define VALUES_LIST_SIZE 512
+    
+    char       valuesBuf[VALUES_BUF_SIZE];
+    int32_t    valuesIndex = 0;
+    const char *valuesList[VALUES_LIST_SIZE];
+    int32_t    valuesCount = 0;
+    
+    const char *locale;
+    int32_t     locLen;
+    
+    UEnumeration *locs = NULL;
+    
+    UResourceBundle    item;
+    UResourceBundle    subItem;
+    
+    ures_initStackObject(&item);
+    ures_initStackObject(&subItem);
+    locs = ures_openAvailableLocales(path, status);
+    
+    if(U_FAILURE(*status)) {
+      ures_close(&item);
+      ures_close(&subItem);
+        return NULL;
+    }
+    
+    valuesBuf[0]=0;
+    valuesBuf[1]=0;
+    
+    while((locale = uenum_next(locs, &locLen, status))) {
+        UResourceBundle   *bund = NULL;
+        UResourceBundle   *subPtr = NULL;
+        UErrorCode subStatus = U_ZERO_ERROR; /* don't fail if a bundle is unopenable */
+        bund = ures_openDirect(path, locale, &subStatus);
+        
+#if defined(URES_TREE_DEBUG)
+        if(!bund || U_FAILURE(subStatus)) {
+            fprintf(stderr, "%s-%s values: Can't open %s locale - skipping. (%s)\n", 
+                path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus));
+        }
+#endif
+        
+        ures_getByKey(bund, keyword, &item, &subStatus);
+        
+        if(!bund || U_FAILURE(subStatus)) {
+#if defined(URES_TREE_DEBUG)
+            fprintf(stderr, "%s-%s values: Can't find in %s - skipping. (%s)\n", 
+                path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus));
+#endif
+            ures_close(bund);
+            bund = NULL;
+            continue;
+        }
+        
+        while((subPtr = ures_getNextResource(&item,&subItem,&subStatus))
+            && U_SUCCESS(subStatus)) {
+            const char *k;
+            int32_t i;
+            k = ures_getKey(&subItem);
+            
+#if defined(URES_TREE_DEBUG)
+            /* fprintf(stderr, "%s | %s | %s | %s\n", path?path:"<ICUDATA>", keyword, locale, k); */
+#endif
+            for(i=0;k&&i<valuesCount;i++) {
+                if(!uprv_strcmp(valuesList[i],k)) {
+                    k = NULL; /* found duplicate */
+                }
+            }
+            if(k && *k) {
+                int32_t kLen = uprv_strlen(k);
+                if(!uprv_strcmp(k,DEFAULT_TAG)) {
+                    continue; /* don't need 'default'. */
+                }
+                if((valuesCount >= (VALUES_LIST_SIZE-1)) ||       /* no more space in list .. */
+                    ((valuesIndex+kLen+1+1) >= VALUES_BUF_SIZE)) { /* no more space in buffer (string + 2 nulls) */
+                    *status = U_ILLEGAL_ARGUMENT_ERROR; /* out of space.. */
+                } else {
+                    uprv_strcpy(valuesBuf+valuesIndex, k);
+                    valuesList[valuesCount++] = valuesBuf+valuesIndex;
+                    valuesIndex += kLen;
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "%s | %s | %s | [%s]   (UNIQUE)\n",
+                        path?path:"<ICUDATA>", keyword, locale, k);
+#endif
+                    valuesBuf[valuesIndex++] = 0; /* terminate */
+                }
+            }
+        }
+        ures_close(bund);
+    }
+    valuesBuf[valuesIndex++] = 0; /* terminate */
+    
+    ures_close(&item);
+    ures_close(&subItem);
+    uenum_close(locs);
+#if defined(URES_TREE_DEBUG)
+    fprintf(stderr, "%s:  size %d, #%d\n", u_errorName(*status), 
+        valuesIndex, valuesCount);
+#endif
+    return uloc_openKeywordList(valuesBuf, valuesIndex, status);
+}
+
 /* eof */