]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/uresbund.c
ICU-8.11.2.tar.gz
[apple/icu.git] / icuSources / common / uresbund.c
index d72df6a1f41db54463d70ae2bd2ed3c3da730f5f..1a99a241138cf9e40ee00d71bc2b4cc23ae02d62 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ******************************************************************************
-* Copyright (C) 1997-2003, International Business Machines Corporation and   *
+* Copyright (C) 1997-2006, 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"
 
 
 /*
@@ -40,7 +45,7 @@ static UHashtable *cache = NULL;
 static UMTX resbMutex = NULL;
 
 /* INTERNAL: hashes an entry  */
-static int32_t U_EXPORT2 U_CALLCONV hashEntry(const UHashTok parm) {
+static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
     UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer;
     UHashTok namekey, pathkey;
     namekey.pointer = b->fName;
@@ -49,7 +54,7 @@ static int32_t U_EXPORT2 U_CALLCONV hashEntry(const UHashTok parm) {
 }
 
 /* INTERNAL: compares two entries */
-static UBool U_EXPORT2 U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
+static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
     UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer;
     UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer;
     UHashTok name1, name2, path1, path2;
@@ -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, NULL, 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;
@@ -252,7 +257,7 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
     const char *myPath = NULL;
     char aliasName[100] = { 0 };
     int32_t aliasLen = 0;
-    UBool isAlias = FALSE;
+    /*UBool isAlias = FALSE;*/
     UHashTok hashkey;
 
     if(U_FAILURE(*status)) {
@@ -262,16 +267,14 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
     /* here we try to deduce the right locale name */
     if(localeID == NULL) { /* if localeID is NULL, we're trying to open default locale */
         uprv_strcpy(name, uloc_getDefault());
-    } else if(uprv_strlen(localeID) == 0) { /* if localeID is "" then we try to open root locale */
+    } else if(*localeID == 0) { /* if localeID is "" then we try to open root locale */
         uprv_strcpy(name, kRootLocaleName);
     } else { /* otherwise, we'll open what we're given */
         uprv_strcpy(name, localeID);
     }
 
     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;
@@ -317,12 +320,10 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
 
         r->fHashKey = hashValue;
         r->fParent = NULL;
-        r->fData.data = NULL;
-        r->fData.pRoot = NULL;
-        r->fData.rootRes = 0;
+        uprv_memset(&r->fData, 0, sizeof(ResourceData));
         r->fBogus = U_ZERO_ERROR;
         
-        /* this is the acutal loading - returns bool true/false */
+        /* this is the actual loading - returns bool true/false */
         result = res_load(&(r->fData), r->fPath, r->fName, status);
 
         if (result == FALSE || U_FAILURE(*status)) { 
@@ -335,18 +336,20 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
             /* handle the alias by trying to get out the %%Alias tag.*/
             /* We'll try to get alias string from the bundle */
             Resource aliasres = res_getResource(&(r->fData), "%%ALIAS");
-            const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen);
-            if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */
-                u_UCharsToChars(alias, aliasName, aliasLen+1);
-                isAlias = TRUE;
-                res_unload(&(r->fData));
-                result = res_load(&(r->fData), r->fPath, aliasName, status);
-                if (result == FALSE || U_FAILURE(*status)) { 
-                    /* we couldn't load aliased data - so we have no data */
-                    *status = U_USING_FALLBACK_WARNING;
-                    r->fBogus = U_USING_FALLBACK_WARNING;
+            if (aliasres != RES_BOGUS) {
+                const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen);
+                if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */
+                    u_UCharsToChars(alias, aliasName, aliasLen+1);
+                    /*isAlias = TRUE;*/
+                    res_unload(&(r->fData));
+                    result = res_load(&(r->fData), r->fPath, aliasName, status);
+                    if (result == FALSE || U_FAILURE(*status)) { 
+                        /* we couldn't load aliased data - so we have no data */
+                        *status = U_USING_FALLBACK_WARNING;
+                        r->fBogus = U_USING_FALLBACK_WARNING;
+                    }
+                    setEntryName(r, aliasName, status);
                 }
-                setEntryName(r, aliasName, status);
             }
         }
 
@@ -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;
@@ -435,7 +459,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
       if(r != NULL) { /* if there is one real locale, we can look for parents. */
         t1 = r;
         hasRealData = TRUE;
-        while (hasChopped && !isRoot && t1->fParent == NULL) {
+        while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.noFallback) {
             /* insert regular parents */
             t2 = init_entry(name, r->fPath, &parentStatus);
             t1->fParent = t2;
@@ -477,7 +501,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
         } else { /* we don't even have the root locale */
           *status = U_MISSING_RESOURCE_ERROR;
         }
-      } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL) {
+      } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL && !r->fData.noFallback) {
           /* insert root locale */
           t2 = init_entry(kRootLocaleName, r->fPath, &parentStatus);
           if(!hasRealData) {
@@ -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) {
@@ -555,6 +580,80 @@ static void entryClose(UResourceDataEntry *resB) {
   umtx_unlock(&resbMutex);
 }
 
+/*
+U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
+  if(resB->fResPath == NULL) {
+    resB->fResPath = resB->fResBuf;
+    *(resB->fResPath) = 0;
+  } 
+  resB->fResPathLen = uprv_strlen(toAdd);
+  if(RES_BUFSIZE <= resB->fResPathLen+1) {
+    if(resB->fResPath == resB->fResBuf) {
+      resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
+    } else {
+      resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+    }
+  }
+  uprv_strcpy(resB->fResPath, toAdd);
+}
+*/
+static void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd) {
+  int32_t resPathLenOrig = resB->fResPathLen;
+  if(resB->fResPath == NULL) {
+    resB->fResPath = resB->fResBuf;
+    *(resB->fResPath) = 0;
+    resB->fResPathLen = 0;
+  } 
+  resB->fResPathLen += lenToAdd;
+  if(RES_BUFSIZE <= resB->fResPathLen+1) {
+    if(resB->fResPath == resB->fResBuf) {
+      resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
+      uprv_strcpy(resB->fResPath, resB->fResBuf);
+    } else {
+      resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+    }
+  }
+  uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd);
+}
+
+static void ures_freeResPath(UResourceBundle *resB) {
+    if (resB->fResPath && resB->fResPath != resB->fResBuf) {
+        uprv_free(resB->fResPath);
+    }
+    resB->fResPath = NULL;
+    resB->fResPathLen = 0;
+}
+
+static void
+ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj)
+{
+    if(resB != NULL) {
+        if(resB->fData != NULL) {
+            entryClose(resB->fData);
+        }
+        if(resB->fVersion != NULL) {
+            uprv_free(resB->fVersion);
+        }
+        ures_freeResPath(resB);
+
+        if(ures_isStackObject(resB) == FALSE && freeBundleObj) {
+            uprv_free(resB);
+        }
+#if 0 /*U_DEBUG*/
+        else {
+            /* poison the data */
+            uprv_memset(resB, -1, sizeof(UResourceBundle));
+        }
+#endif
+    }
+}
+
+U_CAPI void  U_EXPORT2
+ures_close(UResourceBundle* resB)
+{
+    ures_closeBundle(resB, TRUE);
+}
+
 static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r, 
                                          const char *key, int32_t index, UResourceDataEntry *realData, 
                                          const UResourceBundle *parent, int32_t noAlias,
@@ -569,35 +668,84 @@ 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 = (int32_t)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++;
-            path = chAlias+1;
-            if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */
-              path = NULL;
-            }
+              /* there is a path included */
+              locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR);
+              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, "LOCALE") == 0) {
+                /* this is an XPath alias, starting with "/LOCALE/" */
+                /* it contains the path to a resource which should be looked up */
+                /* starting in parent */
+                keyPath = locale; 
+                locale = parent->fData->fName; /* this is the parent's name */
+                path = realData->fPath; /* we will be looking in the same package */
+              } else {
+                if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */
+                  path = NULL;
+                }
+                keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
+                if(keyPath) {
+                  *keyPath = 0;
+                  keyPath++;
+                }
+              }
           } else {
             /* no path, start with a locale */
             locale = chAlias;
+            keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
+            if(keyPath) {
+              *keyPath = 0;
+              keyPath++;
+            }
             path = realData->fPath;
           }
-          keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
-          if(keyPath) {
-            *keyPath = 0;
-            keyPath++;
-          }
+
+
           {
             /* got almost everything, let's try to open */
             /* first, open the bundle with real data */
@@ -614,29 +762,46 @@ 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 = (int32_t)(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);
                   }
                 }
                 if(r != RES_BOGUS) {
-                  result = init_resb_result(&(mainRes->fResData), r, key, -1, mainRes->fData, parent, noAlias+1, resB, status);
+                  result = init_resb_result(&(mainRes->fResData), r, temp, -1, mainRes->fData, mainRes, noAlias+1, resB, status);
                 } else {
                   *status = U_MISSING_RESOURCE_ERROR;
                   result = resB;
@@ -649,23 +814,56 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
                  *     anotheralias:alias { "/ICUDATA/sh/CollationElements" }
                  * aliastest resource should finally have the sequence, not collation elements.
                  */
+                UResourceDataEntry *dataEntry = mainRes->fData;
+                char stackPath[URES_MAX_BUFFER_SIZE];
+                char *pathBuf = stackPath, *myPath = pathBuf;
+                if(uprv_strlen(keyPath) > URES_MAX_BUFFER_SIZE) {
+                  pathBuf = (char *)uprv_malloc((uprv_strlen(keyPath)+1)*sizeof(char));
+                  if(pathBuf == NULL) {
+                    *status = U_MEMORY_ALLOCATION_ERROR;
+                    return NULL;
+                  }
+                }
+                uprv_strcpy(pathBuf, keyPath);
                 result = mainRes;
-                while(*keyPath && U_SUCCESS(*status)) {
-                  r = res_findResource(&(result->fResData), result->fRes, (const char**)&keyPath, &temp);
-                  if(r == RES_BOGUS) {
-                    *status = U_MISSING_RESOURCE_ERROR;
-                    result = resB;
-                    break;
+                /* now we have fallback following here */
+                do {
+                  r = dataEntry->fData.rootRes;     
+                  /* this loop handles 'found' resources over several levels */
+                  while(*myPath && U_SUCCESS(*status)) {
+                    r = res_findResource(&(dataEntry->fData), r, &myPath, &temp);
+                    if(r != RES_BOGUS) { /* found a resource, but it might be an indirection */
+                      resB = init_resb_result(&(dataEntry->fData), r, temp, -1, dataEntry, result, noAlias+1, resB, status);
+                      result = resB;
+                      if(result) {
+                        r = result->fRes; /* switch to a new resource, possibly a new tree */
+                        dataEntry = result->fData;
+                      }
+                    } else { /* no resource found, we don't really want to look anymore on this level */
+                      break;
+                    }
                   }
-                  resB = init_resb_result(&(result->fResData), r, key, -1, result->fData, parent, noAlias+1, resB, status);
+                  dataEntry = dataEntry->fParent;
+                  uprv_strcpy(pathBuf, keyPath);
+                  myPath = pathBuf;
+                } while(r == RES_BOGUS && dataEntry != NULL);
+                if(r == RES_BOGUS) {
+                  *status = U_MISSING_RESOURCE_ERROR;
                   result = resB;
                 }
+                if(pathBuf != stackPath) {
+                  uprv_free(pathBuf);
+                }
               }
             } 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 +885,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);
@@ -694,36 +893,55 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
         if(resB->fVersion != NULL) {
             uprv_free(resB->fVersion);
         }
+        /* 
+           weiv: if stack object was passed in, it doesn't really need to be reinited,
+           since the purpose of initing is to remove stack junk. However, at this point 
+           we would not do anything to an allocated object, so stack object should be
+           treated the same
+        */
+        /*
         if(ures_isStackObject(resB) != FALSE) {
             ures_initStackObject(resB);
         }
+        */
+        if(parent != resB) {
+            ures_freeResPath(resB);
+        }
     }
     resB->fData = realData;
     entryIncrease(resB->fData);
     resB->fHasFallback = FALSE;
     resB->fIsTopLevel = FALSE;
     resB->fIndex = -1;
-    resB->fKey = key;
-    ures_freeResPath(resB);
-    if(parent->fResPath) {
-      ures_appendResPath(resB, parent->fResPath, parent->fResPathLen);
+    resB->fKey = key; 
+    resB->fParentRes = parent;
+    resB->fTopLevelData = parent->fTopLevelData;
+    if(parent->fResPath && parent != resB) {
+        ures_appendResPath(resB, parent->fResPath, parent->fResPathLen);
     }
     if(key != NULL) {
-      ures_appendResPath(resB, key, uprv_strlen(key));
-      ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1);
-    } else {
-      char buf[256];
-      int32_t len = T_CString_integerToString(buf, index, 10);
-      ures_appendResPath(resB, buf, len);
-      ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1);
+        ures_appendResPath(resB, key, (int32_t)uprv_strlen(key));
+        if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
+          ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1);
+        }
+    } else if(index >= 0) {
+        char buf[256];
+        int32_t len = T_CString_integerToString(buf, index, 10);
+        ures_appendResPath(resB, buf, len);
+        if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
+          ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1);
+        }
+    }
+    /* Make sure that Purify doesn't complain about uninitialized memory copies. */
+    {
+        int32_t usedLen = ((resB->fResBuf == resB->fResPath) ? resB->fResPathLen : 0);
+        uprv_memset(resB->fResBuf + usedLen, 0, sizeof(resB->fResBuf) - usedLen);
     }
 
     resB->fVersion = NULL;
     resB->fRes = r;
     /*resB->fParent = parent->fRes;*/
-    resB->fResData.data = rdata->data;
-    resB->fResData.pRoot = rdata->pRoot;
-    resB->fResData.rootRes = rdata->rootRes;
+    uprv_memcpy(&resB->fResData, rdata, sizeof(ResourceData));
     resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes);
     return resB;
 }
@@ -744,21 +962,11 @@ UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *origin
             }
         } else {
             isStackObject = ures_isStackObject(r);
-            if(U_FAILURE(*status)) {
-                return r;
-            }
-            ures_close(r);
-            if(isStackObject == FALSE) {
-                r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
-                /* test for NULL */
-                if (r == NULL) {
-                    *status = U_MEMORY_ALLOCATION_ERROR;
-                    return NULL;
-                }
-            }
+            ures_closeBundle(r, FALSE);
         }
         uprv_memcpy(r, original, sizeof(UResourceBundle));
         r->fResPath = NULL;
+        r->fResPathLen = 0;
         if(original->fResPath) {
           ures_appendResPath(r, original->fResPath, original->fResPathLen);
         }
@@ -766,10 +974,8 @@ UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *origin
         if(r->fData != NULL) {
           entryIncrease(r->fData);
         }
-        return r;
-    } else {
-        return r;
     }
+    return r;
 }
 
 /**
@@ -794,6 +1000,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;
     }
@@ -801,6 +1008,78 @@ U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_
     return NULL;
 }
 
+static const char *
+ures_toUTF8String(const UChar *s16, int32_t length16,
+                  char *dest, int32_t *pLength,
+                  UBool forceCopy,
+                  UErrorCode *status) {
+    int32_t capacity;
+
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    if (pLength != NULL) {
+        capacity = *pLength;
+    } else {
+        capacity = 0;
+    }
+    if (capacity < 0 || (capacity > 0 && dest == NULL)) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if (length16 == 0) {
+        /* empty string, return as read-only pointer */
+        if (pLength != NULL) {
+            *pLength = 0;
+        }
+        if (forceCopy) {
+            u_terminateChars(dest, capacity, 0, status);
+            return dest;
+        } else {
+            return "";
+        }
+    } else {
+        /* We need to transform the string to the destination buffer. */
+        if (capacity < length16) {
+            /* No chance for the string to fit. Pure preflighting. */
+            return u_strToUTF8(NULL, 0, pLength, s16, length16, status);
+        }
+        if (!forceCopy && (length16 <= 0x2aaaaaaa)) {
+            /*
+             * We know the string will fit into dest because each UChar turns
+             * into at most three UTF-8 bytes. Fill the latter part of dest
+             * so that callers do not expect to use dest as a string pointer,
+             * hopefully leading to more robust code for when resource bundles
+             * may store UTF-8 natively.
+             * (In which case dest would not be used at all.)
+             *
+             * We do not do this if forceCopy=TRUE because then the caller
+             * expects the string to start exactly at dest.
+             *
+             * The test above for <= 0x2aaaaaaa prevents overflows.
+             * The +1 is for the NUL terminator.
+             */
+            int32_t maxLength = 3 * length16 + 1;
+            if (capacity > maxLength) {
+                dest += capacity - maxLength;
+                capacity = maxLength;
+            }
+        }
+        return u_strToUTF8(dest, capacity, pLength, s16, length16, status);
+    }
+}
+
+U_DRAFT const char * U_EXPORT2
+ures_getUTF8String(const UResourceBundle *resB,
+                   char *dest, int32_t *pLength,
+                   UBool forceCopy,
+                   UErrorCode *status) {
+    int32_t length16;
+    const UChar *s16 = ures_getString(resB, &length16, status);
+    return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
+
 U_CAPI const uint8_t* U_EXPORT2 ures_getBinary(const UResourceBundle* resB, int32_t* len, 
                                                UErrorCode*               status) {
   if (status==NULL || U_FAILURE(*status)) {
@@ -818,6 +1097,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 +1122,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 +1163,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 +1181,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 +1208,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 +1236,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 */
@@ -968,7 +1253,6 @@ U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resB, int32_t*
     case URES_INT_VECTOR:
     default:
       return NULL;
-      break;
     }
   }
 
@@ -1000,6 +1284,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 +1327,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 +1370,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 */
@@ -1108,6 +1395,17 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB,
     return NULL;
 }
 
+U_DRAFT const char * U_EXPORT2
+ures_getUTF8StringByIndex(const UResourceBundle *resB,
+                          int32_t index,
+                          char *dest, int32_t *pLength,
+                          UBool forceCopy,
+                          UErrorCode *status) {
+    int32_t length16;
+    const UChar *s16 = ures_getStringByIndex(resB, index, &length16, status);
+    return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
+
 /*U_CAPI const char *ures_getResPath(UResourceBundle *resB) {
   return resB->fResPath;
 }*/
@@ -1118,18 +1416,23 @@ ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status)
   UResourceBundle *first = NULL; 
   UResourceBundle *result = fillIn;
   char *packageName = NULL;
-  char *pathToResource = NULL;
+  char *pathToResource = NULL, *save = 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 = (int32_t)(uprv_strlen(path)+1);
+  save = 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 +1446,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;
   }
@@ -1158,16 +1461,15 @@ ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status)
     }
     ures_close(first);
   }
-  uprv_free(pathToResource);
+  uprv_free(save);
   return result;
 }
 
 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 +1477,113 @@ 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(*path); /* there is more stuff in the path */
 
-  res = res_findResource(&(resB->fResData), resB->fRes, &pathToResource, &key); 
+  return result;
+}
+U_INTERNAL const UChar* U_EXPORT2 
+ures_getStringByKeyWithFallback(const UResourceBundle *resB, 
+                                const char* inKey, 
+                                int32_t* len,
+                                UErrorCode *status) {
+
+    UResourceBundle stack;
+    const UChar* retVal = NULL;
+    ures_initStackObject(&stack);
+    ures_getByKeyWithFallback(resB, inKey, &stack, status);
+    retVal = ures_getString(&stack, len, status);
+    ures_close(&stack);
+    return retVal;
+}
 
-  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, rootRes = 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;
+            const char* resPath = resB->fResPath;
+            int32_t len = resB->fResPathLen;
+
+            while(res == RES_BOGUS && dataEntry->fParent != NULL) { /* Otherwise, we'll look in parents */
+                dataEntry = dataEntry->fParent;
+                rootRes = dataEntry->fData.rootRes;
+                if(dataEntry->fBogus == U_ZERO_ERROR) {
+                    uprv_strncpy(path, resPath, len);
+                    uprv_strcpy(path+len, inKey);
+                    myPath = path;
+                    key = inKey;
+                    do {
+                        res = res_findResource(&(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, NULL, -1, dataEntry, resB, 0, helper, status); 
+                            /*helper = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, helper, status);*/
+                            if(helper) {
+                              dataEntry = helper->fData;
+                              rootRes = helper->fRes;
+                              resPath = helper->fResPath;
+                              len = helper->fResPathLen;
+
+                            } else {
+                              break;
+                            }
+                        }
+                    } while(*myPath); /* Continue until the whole path is consumed */
+                }
+            }
+            /*const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);*/
+            if(res != RES_BOGUS) {
+              /* check if resB->fResPath gives the right name here */
+                if(uprv_strcmp(dataEntry->fName, uloc_getDefault())==0 || uprv_strcmp(dataEntry->fName, kRootLocaleName)==0) {
+                    *status = U_USING_DEFAULT_WARNING;
+                } else {
+                    *status = U_USING_FALLBACK_WARNING;
+                }
+
+                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 +1600,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 +1652,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 +1665,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 +1689,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:
@@ -1323,6 +1724,16 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c
     return NULL;
 }
 
+U_DRAFT const char * U_EXPORT2
+ures_getUTF8StringByKey(const UResourceBundle *resB,
+                        const char *key,
+                        char *dest, int32_t *pLength,
+                        UBool forceCopy,
+                        UErrorCode *status) {
+    int32_t length16;
+    const UChar *s16 = ures_getStringByKey(resB, key, &length16, status);
+    return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
 
 /* TODO: clean from here down */
 
@@ -1344,48 +1755,29 @@ ures_getLocale(const UResourceBundle* resourceBundle, UErrorCode* status)
     }
 }
 
-/*
-U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
-  if(resB->fResPath == NULL) {
-    resB->fResPath = resB->fResBuf;
-    *(resB->fResPath) = 0;
-  } 
-  resB->fResPathLen = uprv_strlen(toAdd);
-  if(RES_BUFSIZE <= resB->fResPathLen+1) {
-    if(resB->fResPath == resB->fResBuf) {
-      resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
-    } else {
-      resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+U_CAPI const char* U_EXPORT2 
+ures_getLocaleByType(const UResourceBundle* resourceBundle, 
+                     ULocDataLocaleType type, 
+                     UErrorCode* status) {
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
     }
-  }
-  uprv_strcpy(resB->fResPath, toAdd);
-}
-*/
-U_CFUNC void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd) {
-  int32_t resPathLenOrig = resB->fResPathLen;
-  if(resB->fResPath == NULL) {
-    resB->fResPath = resB->fResBuf;
-    *(resB->fResPath) = 0;
-    resB->fResPathLen = 0;
-  } 
-  resB->fResPathLen += lenToAdd;
-  if(RES_BUFSIZE <= resB->fResPathLen+1) {
-    if(resB->fResPath == resB->fResBuf) {
-      resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
-      uprv_strcpy(resB->fResPath, resB->fResBuf);
+    if (!resourceBundle) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
     } else {
-      resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+        switch(type) {
+        case ULOC_ACTUAL_LOCALE:
+            return resourceBundle->fData->fName;
+        case ULOC_VALID_LOCALE:
+            return resourceBundle->fTopLevelData->fName;
+        case ULOC_REQUESTED_LOCALE:
+            return NULL;
+        default:
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return NULL;
+        }
     }
-  }
-  uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd);
-}
-
-U_CFUNC void ures_freeResPath(UResourceBundle *resB) {
-  if (resB->fResPath && resB->fResPath != resB->fResBuf) {
-    uprv_free(resB->fResPath);
-  }
-  resB->fResPath = NULL;
-  resB->fResPathLen = 0;
 }
 
 U_CFUNC const char* ures_getName(const UResourceBundle* resB) {
@@ -1415,45 +1807,34 @@ U_CAPI void  U_EXPORT2
 ures_openFillIn(UResourceBundle *r, const char* path,
                     const char* localeID, UErrorCode* status) {
     if(r == NULL) {
-        *status = U_INTERNAL_PROGRAM_ERROR;
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
     } else {
         UResourceDataEntry *firstData;
+        UBool isStackObject = ures_isStackObject(r);
+
+        ures_closeBundle(r, FALSE);
+        uprv_memset(r, 0, sizeof(UResourceBundle));
+        ures_setIsStackObject(r, isStackObject);
         r->fHasFallback = TRUE;
         r->fIsTopLevel = TRUE;
-        r->fKey = NULL;
-        r->fVersion = NULL;
         r->fIndex = -1;
-        if(r->fData != NULL) {
-            entryClose(r->fData);
-        }
-        if(r->fVersion != NULL) {
-            uprv_free(r->fVersion);
-        }
         r->fData = entryOpen(path, localeID, 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;
         }
-        r->fResData.data = firstData->fData.data;
-        r->fResData.pRoot = firstData->fData.pRoot;
-        r->fResData.rootRes = firstData->fData.rootRes;
+        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->fParent = RES_BOGUS;*/
-        /*r->fResPath = NULL;*/
-        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);
-        }
-        */
+        r->fTopLevelData = r->fData;
     }
 }
+
 U_CAPI UResourceBundle*  U_EXPORT2
 ures_open(const char* path,
                     const char* localeID,
@@ -1462,14 +1843,13 @@ ures_open(const char* path,
     char canonLocaleID[100];
     UResourceDataEntry *hasData = NULL;
     UResourceBundle *r;
-    int32_t length;
 
     if(status == NULL || U_FAILURE(*status)) {
         return NULL;
     }
 
     /* first "canonicalize" the locale ID */
-    length = uloc_getName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
+    uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
     if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
         *status = U_ILLEGAL_ARGUMENT_ERROR;
         return NULL;
@@ -1481,17 +1861,17 @@ ures_open(const char* path,
         return NULL;
     }
 
+    uprv_memset(r, 0, sizeof(UResourceBundle));
     r->fHasFallback = TRUE;
     r->fIsTopLevel = TRUE;
     ures_setIsStackObject(r, FALSE);
-    r->fKey = NULL;
-    r->fVersion = NULL;
     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) {
@@ -1506,13 +1886,10 @@ ures_open(const char* path,
         }
     }
 
-    r->fResData.data = hasData->fData.data;
-    r->fResData.pRoot = hasData->fData.pRoot;
-    r->fResData.rootRes = hasData->fData.rootRes;
+    uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData));
+    r->fHasFallback=(UBool)!r->fResData.noFallback;
     r->fRes = r->fResData.rootRes;
-    /*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);
@@ -1527,31 +1904,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 +1911,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 +1927,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);
@@ -1590,43 +1944,17 @@ ures_openDirect(const char* path, const char* localeID, UErrorCode* status) {
 
     r->fKey = NULL;
     r->fVersion = NULL;
-    r->fResData.data = r->fData->fData.data;
-    r->fResData.pRoot = r->fData->fData.pRoot;
-    r->fResData.rootRes = r->fData->fData.rootRes;
+    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;
-    /*
-    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,41 +1968,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;
-    }
-}
-
-U_CAPI void  U_EXPORT2
-ures_close(UResourceBundle*    resB)
-{
-    if(resB != NULL) {
-        if(resB->fData != NULL) {
-            entryClose(resB->fData);
-        }
-        if(resB->fVersion != NULL) {
-            uprv_free(resB->fVersion);
-        }
-        ures_freeResPath(resB);
-
-        if(ures_isStackObject(resB) == FALSE) {
-            uprv_free(resB);
-        }
+        *status = U_MISSING_RESOURCE_ERROR;
+        ures_close(&resData);
+        return 0;
     }
 }
 
@@ -1692,7 +2002,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 +2015,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 +2034,574 @@ 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 = (int32_t)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 = (int32_t)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(subPtr);
+            
+#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 = (int32_t)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);
+}
+U_INTERNAL UBool U_EXPORT2
+ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
+    if(res1==NULL || res2==NULL){
+        return res1==res2; /* pointer comparision */
+    }
+    if(res1->fKey==NULL||  res2->fKey==NULL){
+        return (res1->fKey==res2->fKey);
+    }else{
+        if(uprv_strcmp(res1->fKey, res2->fKey)!=0){
+            return FALSE;
+        }
+    }
+    if(uprv_strcmp(res1->fData->fName, res2->fData->fName)!=0){
+        return FALSE;
+    }
+    if(res1->fData->fPath == NULL||  res2->fData->fPath==NULL){
+        return (res1->fData->fPath == res2->fData->fPath);
+    }else{
+        if(uprv_strcmp(res1->fData->fPath, res2->fData->fPath)!=0){
+            return FALSE;
+        }
+    }
+    if(uprv_strcmp(res1->fData->fParent->fName, res2->fData->fParent->fName)!=0){
+        return FALSE;
+    }
+    if(uprv_strcmp(res1->fData->fParent->fPath, res2->fData->fParent->fPath)!=0){
+        return FALSE;
+    }
+    if(uprv_strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen)!=0){
+        return FALSE;
+    }
+    if(res1->fRes != res2->fRes){
+        return FALSE;
+    }
+    return TRUE;
+}
+U_INTERNAL UResourceBundle* U_EXPORT2
+ures_clone(const UResourceBundle* res, UErrorCode* status){
+    UResourceBundle* bundle = NULL;
+    UResourceBundle* ret = NULL;
+    if(U_FAILURE(*status) || res == NULL){
+        return NULL;
+    }
+    bundle = ures_open(res->fData->fPath, res->fData->fName, status);
+    if(res->fResPath!=NULL){
+        ret = ures_findSubResource(bundle, res->fResPath, NULL, status);
+        ures_close(bundle);
+    }else{
+        ret = bundle;
+    }
+    return ret;
+}
+U_INTERNAL const UResourceBundle* U_EXPORT2
+ures_getParentBundle(const UResourceBundle* res){
+    if(res==NULL){
+        return NULL;
+    }
+    return res->fParentRes;
+}
 /* eof */