Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

uresbund.c

00001 /*
00002 *******************************************************************************
00003 * Copyright (C) 1997-1999, International Business Machines Corporation and    *
00004 * others. All Rights Reserved.                                                *
00005 *******************************************************************************
00006 *
00007 * File URESBUND.C
00008 *
00009 * Modification History:
00010 *
00011 *   Date        Name        Description
00012 *   04/01/97    aliu        Creation.
00013 *   06/14/99    stephen     Removed functions taking a filename suffix.
00014 *   07/20/99    stephen     Changed for UResourceBundle typedef'd to void*
00015 *   11/09/99    weiv            Added ures_getLocale()
00016 *   March 2000  weiv        Total overhaul - using data in DLLs
00017 *   06/20/2000  helena      OS/400 port changes; mostly typecast.
00018 *******************************************************************************
00019 */
00020 
00021 #include "uresimp.h"
00022 #include <stdio.h>
00023 
00024 /* this is just for internal purposes. DO NOT USE! */
00025 static void entryCloseInt(UResourceDataEntry *resB);
00026 void entryClose(UResourceDataEntry *resB);
00027 
00028 
00029 /* Static cache for already opened resource bundles - mostly for keeping fallback info */
00030 static UHashtable *cache = NULL;
00031 static UBool isMutexInited = FALSE;
00032 static UMTX resbMutex = NULL;
00033 
00034 /* INTERNAL: hashes an entry  */
00035 static int32_t hashEntry(const void *parm) {
00036     UResourceDataEntry *b = (UResourceDataEntry *)parm;
00037     return uhash_hashChars(b->fName)+37*uhash_hashChars(b->fPath);
00038 }
00039 
00040 /* INTERNAL: compares two entries */
00041 static UBool compareEntries(const void *p1, const void *p2) {
00042     UResourceDataEntry *b1 = (UResourceDataEntry *)p1;
00043     UResourceDataEntry *b2 = (UResourceDataEntry *)p2;
00044 
00045     return (UBool)(uhash_compareChars(b1->fName, b2->fName) & 
00046         uhash_compareChars(b1->fPath, b2->fPath));
00047 }
00048 
00049 
00054 static UBool chopLocale(char *name) {
00055     char *i = uprv_strrchr(name, '_');
00056 
00057     if(i != NULL) {
00058         *i = '\0';
00059         return TRUE;
00060     }
00061 
00062     return FALSE;
00063 }
00064 
00068 static void entryIncrease(UResourceDataEntry *entry) {
00069     umtx_lock(&resbMutex);
00070     entry->fCountExisting++;
00071     while(entry->fParent != NULL) {
00072       entry = entry->fParent;
00073       entry->fCountExisting++;
00074     }
00075     umtx_unlock(&resbMutex);
00076 }
00077 
00082 const ResourceData *getFallbackData(const UResourceBundle* resBundle, const char* * resTag, UResourceDataEntry* *realData, Resource *res, UErrorCode *status) {
00083     UResourceDataEntry *resB = resBundle->fData;
00084     int32_t indexR = -1;
00085     int32_t i = 0;
00086     *res = RES_BOGUS;
00087     if(resB != NULL) {
00088         if(resB->fBogus == U_ZERO_ERROR) { /* if this resource is real, */
00089             *res = res_getTableItemByKey(&(resB->fData), resB->fData.rootRes, &indexR, resTag); /* try to get data from there */
00090             i++;
00091         }
00092         if(resBundle->fHasFallback == TRUE) {
00093             while(*res == RES_BOGUS && resB->fParent != NULL) { /* Otherwise, we'll look in parents */
00094                 resB = resB->fParent;
00095                 if(resB->fBogus == U_ZERO_ERROR) {
00096                     i++;
00097                     *res = res_getTableItemByKey(&(resB->fData), resB->fData.rootRes, &indexR, resTag);
00098                 }
00099             }
00100         }
00101 
00102         if(*res != RES_BOGUS) { /* If the resource is found in parents, we need to adjust the error */
00103             if(i>1) {
00104                 if(uprv_strcmp(resB->fName, uloc_getDefault())==0 || uprv_strcmp(resB->fName, kRootLocaleName)==0) {
00105                     *status = U_USING_DEFAULT_ERROR;
00106                 } else {
00107                     *status = U_USING_FALLBACK_ERROR;
00108                 }
00109             }
00110             *realData = resB;
00111             return (&(resB->fData));
00112         } else { /* If resource is not found, we need to give an error */
00113             *status = U_MISSING_RESOURCE_ERROR;
00114             return NULL;
00115         }
00116     } else {
00117             *status = U_MISSING_RESOURCE_ERROR;
00118             return NULL;
00119     }
00120 }
00121 
00123 static void initCache(UErrorCode *status) {
00124     if(isMutexInited == FALSE) {
00125         umtx_lock(NULL);
00126         if(isMutexInited == FALSE) {
00127           umtx_init(&resbMutex);
00128           isMutexInited = TRUE;
00129         }
00130         umtx_unlock(NULL);
00131     }
00132     if(cache == NULL) {
00133         UHashtable *newCache = uhash_open(hashEntry, compareEntries, status);
00134         if (U_FAILURE(*status)) {
00135             return;
00136         }
00137         umtx_lock(&resbMutex);
00138         if(cache == NULL) {
00139             cache = newCache;
00140             newCache = NULL;
00141         }
00142         umtx_unlock(&resbMutex);
00143         if(newCache != NULL) {
00144             uhash_close(newCache);
00145         }
00146     }
00147 }
00148 
00151 static void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status) {
00152     if(res->fName != NULL) {
00153         uprv_free(res->fName);
00154     }
00155     res->fName = (char *)uprv_malloc(sizeof(char)*uprv_strlen(name)+1);
00156     if(res->fName == NULL) {
00157         *status = U_MEMORY_ALLOCATION_ERROR;
00158     } else {
00159         uprv_strcpy(res->fName, name);
00160     }
00161 }
00162 
00166 static UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) {
00167     UResourceDataEntry *r = NULL;
00168     UResourceDataEntry find;
00169     int32_t hashValue;
00170     char name[96];
00171     const char *myPath = NULL;
00172 
00173     if(U_FAILURE(*status)) {
00174         return NULL;
00175     }
00176 
00177     /* here we try to deduce the right locale name */
00178     if(localeID == NULL) { /* if localeID is NULL, we're trying to open default locale */
00179         uprv_strcpy(name, uloc_getDefault());
00180     } else if(uprv_strlen(localeID) == 0) { /* if localeID is "" then we try to open root locale */
00181         uprv_strcpy(name, kRootLocaleName);
00182     } else { /* otherwise, we'll open what we're given */
00183         uprv_strcpy(name, localeID);
00184     }
00185 
00186     if(path != NULL) { /* if we actually have path, we'll use it */
00187         if(uprv_strcmp(path, u_getDataDirectory()) != 0) { /* unless it is system default path */
00188             myPath = path;
00189         }
00190     }
00191 
00192     find.fName = name;
00193     find.fPath = (char *)myPath;
00194 
00195     /* calculate the hash value of the entry */
00196     hashValue = hashEntry((const void *)&find);
00197 
00198     /* check to see if we already have this entry */
00199     r = (UResourceDataEntry *)uhash_get(cache, &find);
00200 
00201     if(r != NULL) { /* if the entry is already in the hash table */
00202         r->fCountExisting++; /* we just increase it's reference count */
00203         *status = r->fBogus; /* and set returning status */
00204     } else { /* otherwise, we'll try to construct a new entry */
00205         UBool result = FALSE;
00206 
00207         r = (UResourceDataEntry *) uprv_malloc(sizeof(UResourceDataEntry));
00208 
00209         if(r == NULL) {
00210             *status = U_MEMORY_ALLOCATION_ERROR;
00211             return NULL;
00212         }
00213         r->fCountExisting = 1;
00214 
00215         r->fName = NULL;
00216         setEntryName(r, name, status);
00217 
00218         r->fPath = NULL;
00219         if(myPath != NULL && !U_FAILURE(*status)) {
00220             r->fPath = (char *)uprv_malloc(sizeof(char)*uprv_strlen(myPath)+1);
00221             if(r->fPath == NULL) {
00222                 *status = U_MEMORY_ALLOCATION_ERROR;
00223             } else {
00224                 uprv_strcpy(r->fPath, myPath);
00225             }
00226         }
00227 
00228         r->fHashKey = hashValue;
00229         r->fParent = NULL;
00230         r->fData.data = NULL;
00231         r->fData.pRoot = NULL;
00232         r->fData.rootRes = 0;
00233         r->fBogus = U_ZERO_ERROR;
00234         
00235         /* this is the acutal loading - returns bool true/false */
00236         result = res_load(&(r->fData), r->fPath, r->fName, status);
00237 
00238         if (result == FALSE || U_FAILURE(*status)) { 
00239             /* we have no such entry in dll, so it will always use fallback */
00240             *status = U_USING_FALLBACK_ERROR;
00241             r->fBogus = U_USING_FALLBACK_ERROR;
00242         } else { /* if we have a regular entry */
00243             /* handle the alias by trying to get out the %%Alias tag.*/
00244             char aliasName[100];
00245             int32_t aliasLen;
00246             /* We'll try to get alias string from the bundle */
00247             Resource aliasres = res_getResource(&(r->fData), "%%ALIAS");
00248             const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen);
00249             if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */
00250                 u_UCharsToChars(alias, aliasName, u_strlen(alias)+1);
00251                 res_unload(&(r->fData));
00252                 result = res_load(&(r->fData), r->fPath, aliasName, status);
00253                 if (result == FALSE || U_FAILURE(*status)) { 
00254                     /* we couldn't load aliased data - so we have no data */
00255                     *status = U_USING_FALLBACK_ERROR;
00256                     r->fBogus = U_USING_FALLBACK_ERROR;
00257                 }
00258             }
00259         }
00260 
00261         {
00262             UResourceDataEntry *oldR = NULL;
00263             if((oldR = (UResourceDataEntry *)uhash_get(cache, r)) == NULL) { /* if the data is not cached */
00264               /* just insert it in the cache */
00265                 uhash_put(cache, (void *)r, r, status);
00266             } else {
00267               /* somebody have already inserted it while we were working, discard newly opened data */
00268               /* this part is probably obsolete since we check cache in locked state */
00269                 uprv_free(r->fName);
00270                 if(r->fPath != NULL) {
00271                     uprv_free(r->fPath);
00272                 }
00273                 uprv_free(r);
00274                 r = oldR;
00275                 r->fCountExisting++;
00276             }
00277         }
00278     }
00279     return r;
00280 }
00281 
00282 /* INTERNAL: */
00283 static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UErrorCode* status) {
00284     UErrorCode initstatus = U_ZERO_ERROR;
00285     UResourceDataEntry *r = NULL;
00286     UResourceDataEntry *t1 = NULL;
00287     UResourceDataEntry *t2 = NULL;
00288     UBool isDefault = FALSE;
00289     UBool isRoot = FALSE;
00290     UBool hasRealData = FALSE;
00291     UBool hasChopped = FALSE;
00292     char name[96];
00293 
00294     if(U_FAILURE(*status)) {
00295       return NULL;
00296     }
00297 
00298     initCache(status);
00299 
00300     umtx_lock(&resbMutex);
00301     r = init_entry(localeID, path, &initstatus);
00302     uprv_strcpy(name, r->fName);
00303     isDefault = (UBool)(uprv_strncmp(name, uloc_getDefault(), uprv_strlen(name)) == 0);
00304     hasRealData = (UBool)(r->fBogus == U_ZERO_ERROR);
00305 
00306     isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName) == 0);
00307 
00308     /*Fallback data stuff*/
00309     hasChopped = chopLocale(name);
00310     t1 = r;
00311 
00312     while (hasChopped && !isRoot && t1->fParent == NULL) {
00313         /* insert regular parents */
00314         t2 = init_entry(name, r->fPath, status);
00315         hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) | hasRealData);
00316         t1->fParent = t2;
00317         t1 = t2;
00318         hasChopped = chopLocale(name);
00319     }
00320 
00321     if(!hasRealData && !isDefault && !isRoot && t1->fParent == NULL) {
00322         /* insert default locale */
00323         uprv_strcpy(name, uloc_getDefault());
00324         t2 = init_entry(name, r->fPath, status);
00325         hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) | hasRealData);
00326         r->fBogus = U_USING_DEFAULT_ERROR;
00327         isDefault = TRUE;
00328         t1->fParent = t2;
00329         t1 = t2;
00330         hasChopped = chopLocale(name);
00331         while (hasChopped && t1->fParent == NULL) {
00332             /* insert chopped defaults */
00333             t2 = init_entry(name, r->fPath, status);
00334             hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) | hasRealData);
00335             t1->fParent = t2;
00336             t1 = t2;
00337             hasChopped = chopLocale(name);
00338         }
00339     }
00340 
00341     if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL) {
00342         /* insert root locale */
00343         t2 = init_entry(kRootLocaleName, r->fPath, status);
00344         if(!hasRealData) {
00345           r->fBogus = U_USING_DEFAULT_ERROR;
00346         }
00347         hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) | hasRealData);
00348         t1->fParent = t2;
00349         t1 = t2;
00350     }
00351 
00352     while(!isRoot && t1->fParent != NULL) {
00353         t1->fParent->fCountExisting++;
00354         t1 = t1->fParent;
00355         hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) | hasRealData);
00356     }
00357 
00358     if(!hasRealData) {
00359         entryCloseInt(r);
00360         *status = U_MISSING_RESOURCE_ERROR;
00361     }
00362 
00363     umtx_unlock(&resbMutex);
00364 
00365     if(U_SUCCESS(*status)) {
00366       *status = r->fBogus;
00367       return r;
00368     } else {
00369       return NULL;
00370     }
00371 }
00372 
00373 
00383 U_CFUNC UResourceBundle* ures_openNoFallback(const char* path, const char* localeID, UErrorCode* status) {
00384     UResourceBundle *r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
00385     if(r == NULL) {
00386         *status = U_MEMORY_ALLOCATION_ERROR;
00387         return NULL;
00388     }
00389 
00390     r->fHasFallback = FALSE;
00391     r->fIsTopLevel = TRUE;
00392     ures_setIsStackObject(r, FALSE);
00393     r->fIndex = -1;
00394     r->fData = entryOpen(path, localeID, status);
00395     if(U_FAILURE(*status)) {
00396         uprv_free(r);
00397         return NULL;
00398     }
00399     if(r->fData->fBogus != U_ZERO_ERROR) {
00400         entryClose(r->fData);
00401         uprv_free(r);
00402         *status = U_MISSING_RESOURCE_ERROR;
00403         return NULL;
00404     }
00405 
00406     r->fKey = NULL;
00407     r->fVersion = NULL;
00408     r->fResData.data = r->fData->fData.data;
00409     r->fResData.pRoot = r->fData->fData.pRoot;
00410     r->fResData.rootRes = r->fData->fData.rootRes;
00411     r->fRes = r->fResData.rootRes;
00412     r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
00413     return r;
00414 }
00415 
00416 /* INTERNAL: */
00417 static UResourceBundle *init_resb_result(const ResourceData *rdata, const Resource r, const char *key, UResourceDataEntry *realData, UResourceBundle *resB, UErrorCode *status) {
00418     if(status == NULL || U_FAILURE(*status)) {
00419         return resB;
00420     }
00421     if(resB == NULL) {
00422         resB = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
00423         ures_setIsStackObject(resB, FALSE);
00424     } else {
00425         if(ures_isStackObject(resB, status) != FALSE) {
00426             ures_setIsStackObject(resB, TRUE);
00427         }
00428     }
00429     resB->fData = realData;
00430     entryIncrease(resB->fData);
00431     resB->fHasFallback = FALSE;
00432     resB->fIsTopLevel = FALSE;
00433     resB->fIndex = -1;
00434     resB->fKey = key;
00435     resB->fVersion = NULL;
00436     resB->fRes = r;
00437     resB->fResData.data = rdata->data;
00438     resB->fResData.pRoot = rdata->pRoot;
00439     resB->fResData.rootRes = rdata->rootRes;
00440     resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes);
00441     return resB;
00442 }
00443 
00444 UResourceBundle *copyResb(UResourceBundle *r, const UResourceBundle *original, UErrorCode *status) {
00445     UBool isStackObject;
00446     if(U_FAILURE(*status) || r == original) {
00447         return r;
00448     }
00449     if(original != NULL) {
00450         if(r == NULL) {
00451             isStackObject = FALSE;
00452             r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
00453         } else {
00454             isStackObject = ures_isStackObject(r, status);
00455             if(U_FAILURE(*status)) {
00456                 return r;
00457             }
00458             if(isStackObject == FALSE) {
00459                 ures_close(r);
00460                 r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
00461             }
00462         }
00463         uprv_memcpy(r, original, sizeof(UResourceBundle));
00464         ures_setIsStackObject(r, isStackObject);
00465         if(r->fData != NULL) {
00466           entryIncrease(r->fData);
00467         }
00468         return r;
00469     } else {
00470         return r;
00471     }
00472 }
00473 
00478 U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_t* len, UErrorCode* status) {
00479 
00480     if (status==NULL || U_FAILURE(*status)) {
00481         return NULL;
00482     }
00483     if(resB == NULL) {
00484         *status = U_ILLEGAL_ARGUMENT_ERROR;
00485         return NULL;
00486     }
00487 
00488     switch(RES_GET_TYPE(resB->fRes)) {
00489         case RES_STRING:
00490             return res_getString(&(resB->fResData), resB->fRes, len);
00491         case RES_INT:
00492         case RES_INT_VECTOR:
00493         case RES_BINARY:
00494         case RES_ARRAY:
00495         case RES_TABLE:
00496         default:
00497             *status = U_RESOURCE_TYPE_MISMATCH;
00498     }
00499 
00500     return NULL;
00501 }
00502 
00503 U_CAPI const uint8_t* U_EXPORT2 ures_getBinary(const UResourceBundle* resB, int32_t* len, 
00504                                                UErrorCode*               status) {
00505 
00506   if (status==NULL || U_FAILURE(*status)) {
00507     return NULL;
00508   }
00509   if(resB == NULL) {
00510     *status = U_ILLEGAL_ARGUMENT_ERROR;
00511     return NULL;
00512   }
00513   switch(RES_GET_TYPE(resB->fRes)) {
00514   case RES_BINARY:
00515     return res_getBinary(&(resB->fResData), resB->fRes, len);
00516   case RES_INT:
00517   case RES_STRING:
00518   case RES_INT_VECTOR:
00519   case RES_ARRAY:
00520   case RES_TABLE:
00521   default:
00522     *status = U_RESOURCE_TYPE_MISMATCH;
00523   }
00524 
00525   return NULL;
00526 }
00527 
00528 U_CAPI uint32_t U_EXPORT2 ures_getInt(const UResourceBundle* resB, UErrorCode *status) {
00529   
00530   if (status==NULL || U_FAILURE(*status)) {
00531     return 0xffffffff;
00532   }
00533   if(resB == NULL) {
00534     *status = U_ILLEGAL_ARGUMENT_ERROR;
00535     return 0xffffffff;
00536   }
00537   return RES_GET_UINT(resB->fRes);
00538 }
00539 
00540 
00541 U_CAPI UResType U_EXPORT2 ures_getType(UResourceBundle *resB) {
00542   if(resB == NULL) {
00543     return RES_NONE;
00544   }
00545   return (UResType) (RES_GET_TYPE(resB->fRes));
00546 }
00547 
00548 U_CAPI const char * U_EXPORT2 ures_getKey(UResourceBundle *resB) {
00549   if(resB == NULL) {
00550     return NULL;
00551   }
00552   
00553   return(resB->fKey);
00554 }
00555 
00556 U_CAPI int32_t U_EXPORT2 ures_getSize(UResourceBundle *resB) {
00557   if(resB == NULL) {
00558     return 0;
00559   }
00560   
00561   return resB->fSize;
00562 }
00563 
00564 U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resB){
00565   if(resB == NULL) {
00566     return;
00567   }
00568   resB->fIndex = -1;
00569 }
00570 
00571 U_CAPI UBool U_EXPORT2 ures_hasNext(UResourceBundle *resB) {
00572   if(resB == NULL) {
00573     return FALSE;
00574   }
00575   return (UBool)(resB->fIndex < resB->fSize-1);
00576 }
00577 
00578 U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resB, int32_t* len, const char ** key, UErrorCode *status) {
00579   Resource r = RES_BOGUS;
00580   
00581   if (status==NULL || U_FAILURE(*status)) {
00582     return NULL;
00583   }
00584   if(resB == NULL) {
00585     *status = U_ILLEGAL_ARGUMENT_ERROR;
00586     return NULL;
00587   }
00588   
00589   if(resB->fIndex == resB->fSize-1) {
00590     *status = U_INDEX_OUTOFBOUNDS_ERROR;
00591   } else {
00592     resB->fIndex++;
00593     switch(RES_GET_TYPE(resB->fRes)) {
00594     case RES_INT:
00595     case RES_BINARY:
00596     case RES_STRING:
00597       return res_getString(&(resB->fResData), resB->fRes, len); 
00598     case RES_TABLE:
00599       r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, key);
00600       if(r == RES_BOGUS && resB->fHasFallback) {
00601         /* TODO: do the fallback */
00602       }
00603       return res_getString(&(resB->fResData), r, len); 
00604     case RES_ARRAY:
00605       r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
00606       if(r == RES_BOGUS && resB->fHasFallback) {
00607         /* TODO: do the fallback */
00608       }
00609       return res_getString(&(resB->fResData), r, len);
00610     case RES_INT_VECTOR:
00611     default:
00612       return NULL;
00613       break;
00614     }
00615   }
00616 
00617   return NULL;
00618 }
00619 
00620 U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resB, UResourceBundle *fillIn, UErrorCode *status) {
00621     const char *key = NULL;
00622     Resource r = RES_BOGUS;
00623 
00624     if (status==NULL || U_FAILURE(*status)) {
00625             /*return NULL;*/
00626             return fillIn;
00627     }
00628     if(resB == NULL) {
00629             *status = U_ILLEGAL_ARGUMENT_ERROR;
00630             /*return NULL;*/
00631             return fillIn;
00632     }
00633 
00634     if(resB->fIndex == resB->fSize-1) {
00635       *status = U_INDEX_OUTOFBOUNDS_ERROR;
00636       /*return NULL;*/
00637     } else {
00638         resB->fIndex++;
00639         switch(RES_GET_TYPE(resB->fRes)) {
00640         case RES_INT:
00641         case RES_BINARY:
00642         case RES_STRING:
00643             return copyResb(fillIn, resB, status);
00644         case RES_TABLE:
00645             r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, &key);
00646             if(r == RES_BOGUS && resB->fHasFallback) {
00647                 /* TODO: do the fallback */
00648             }
00649             return init_resb_result(&(resB->fResData), r, key, resB->fData, fillIn, status);
00650         case RES_ARRAY:
00651             r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
00652             if(r == RES_BOGUS && resB->fHasFallback) {
00653                 /* TODO: do the fallback */
00654             }
00655             return init_resb_result(&(resB->fResData), r, key, resB->fData, fillIn, status);
00656         case RES_INT_VECTOR:
00657         default:
00658             /*return NULL;*/
00659             return fillIn;
00660         }
00661     }
00662     /*return NULL;*/
00663     return fillIn;
00664 }
00665 
00666 U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resB, int32_t indexR, UResourceBundle *fillIn, UErrorCode *status) {
00667     const char* key = NULL;
00668     Resource r = RES_BOGUS;
00669 
00670     if (status==NULL || U_FAILURE(*status)) {
00671         /*return NULL;*/
00672         return fillIn;
00673     }
00674     if(resB == NULL) {
00675         *status = U_ILLEGAL_ARGUMENT_ERROR;
00676         /*return NULL;*/
00677         return fillIn;
00678     }
00679 
00680     if(indexR >= 0 && resB->fSize > indexR) {
00681         switch(RES_GET_TYPE(resB->fRes)) {
00682         case RES_INT:
00683         case RES_BINARY:
00684         case RES_STRING:
00685             return copyResb(fillIn, resB, status);
00686         case RES_TABLE:
00687             r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexR, &key);
00688             if(r == RES_BOGUS && resB->fHasFallback) {
00689                 /* TODO: do the fallback */
00690             }
00691             return init_resb_result(&(resB->fResData), r, key, resB->fData, fillIn, status);
00692         case RES_ARRAY:
00693             r = res_getArrayItem(&(resB->fResData), resB->fRes, indexR);
00694             if(r == RES_BOGUS && resB->fHasFallback) {
00695                 /* TODO: do the fallback */
00696             }
00697             return init_resb_result(&(resB->fResData), r, key, resB->fData, fillIn, status);
00698         case RES_INT_VECTOR:
00699         default:
00700             /*return NULL;*/
00701             return fillIn;
00702         }
00703     } else {
00704         *status = U_MISSING_RESOURCE_ERROR;
00705     }
00706     /*return NULL;*/
00707     return fillIn;
00708 }
00709 
00710 U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status) {
00711     const char* key = NULL;
00712     Resource r = RES_BOGUS;
00713 
00714     if (status==NULL || U_FAILURE(*status)) {
00715         return NULL;
00716     }
00717     if(resB == NULL) {
00718         *status = U_ILLEGAL_ARGUMENT_ERROR;
00719         return NULL;
00720     }
00721 
00722     if(indexS >= 0 && resB->fSize > indexS) {
00723         switch(RES_GET_TYPE(resB->fRes)) {
00724         case RES_INT:
00725         case RES_BINARY:
00726         case RES_STRING:
00727             return res_getString(&(resB->fResData), resB->fRes, len);
00728         case RES_TABLE:
00729             r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexS, &key);
00730             if(r == RES_BOGUS && resB->fHasFallback) {
00731                 /* TODO: do the fallback */
00732             }
00733             return res_getString(&(resB->fResData), r, len);
00734         case RES_ARRAY:
00735             r = res_getArrayItem(&(resB->fResData), resB->fRes, indexS);
00736             if(r == RES_BOGUS && resB->fHasFallback) {
00737                 /* TODO: do the fallback */
00738             }
00739             return res_getString(&(resB->fResData), r, len);
00740         case RES_INT_VECTOR:
00741         default:
00742             return NULL;
00743         }
00744     } else {
00745         *status = U_MISSING_RESOURCE_ERROR;
00746     }
00747     return NULL;
00748 }
00749 
00750 U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) {
00751     Resource res = RES_BOGUS;
00752     UResourceDataEntry *realData = NULL;
00753     const char *key = inKey;
00754 
00755     if (status==NULL || U_FAILURE(*status)) {
00756         /*return NULL;*/
00757         return fillIn;
00758     }
00759     if(resB == NULL) {
00760         *status = U_ILLEGAL_ARGUMENT_ERROR;
00761         /*return NULL;*/
00762         return fillIn;
00763     }
00764 
00765     if(RES_GET_TYPE(resB->fRes) == RES_TABLE) {
00766         int32_t t;
00767         res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
00768         if(res == RES_BOGUS) {
00769             key = inKey;
00770             if(resB->fHasFallback == TRUE) {
00771                 const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
00772                 if(U_SUCCESS(*status)) {
00773                     return init_resb_result(rd, res, key, realData, fillIn, status);
00774                 } else {
00775                     *status = U_MISSING_RESOURCE_ERROR;
00776                 }
00777             } else {
00778                 *status = U_MISSING_RESOURCE_ERROR;
00779             }
00780         } else {
00781             return init_resb_result(&(resB->fResData), res, key, resB->fData, fillIn, status);
00782         }
00783     } else if(RES_GET_TYPE(resB->fRes) == RES_ARRAY && resB->fHasFallback == TRUE) {
00784         /* here should go a first attempt to locate the key using index table */
00785         const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
00786         if(U_SUCCESS(*status)) {
00787             return init_resb_result(rd, res, key, realData, fillIn, status);
00788         } else {
00789             *status = U_MISSING_RESOURCE_ERROR;
00790         }
00791     } else {
00792         *status = U_RESOURCE_TYPE_MISMATCH;
00793     }
00794     /*return NULL;*/
00795     return fillIn;
00796 }
00797 
00798 U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, const char* inKey, int32_t* len, UErrorCode *status) {
00799     Resource res = RES_BOGUS;
00800     UResourceDataEntry *realData = NULL;
00801     const char* key = inKey;
00802 
00803     if (status==NULL || U_FAILURE(*status)) {
00804         return NULL;
00805     }
00806     if(resB == NULL) {
00807         *status = U_ILLEGAL_ARGUMENT_ERROR;
00808         return NULL;
00809     }
00810 
00811     if(RES_GET_TYPE(resB->fRes) == RES_TABLE) {
00812         int32_t t=0;
00813         res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
00814         if(res == RES_BOGUS) {
00815             key = inKey;
00816             if(resB->fHasFallback == TRUE) {
00817                 const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
00818                 if(U_SUCCESS(*status)) {
00819                     return res_getString(rd, res, len);
00820                 } else {
00821                     *status = U_MISSING_RESOURCE_ERROR;
00822                 }
00823             } else {
00824                 *status = U_MISSING_RESOURCE_ERROR;
00825             }
00826         } else {
00827             return res_getString(&(resB->fResData), res, len);
00828         }
00829     } else if(RES_GET_TYPE(resB->fRes) == RES_ARRAY && resB->fHasFallback == TRUE) {
00830         /* here should go a first attempt to locate the key using index table */
00831         const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
00832         if(U_SUCCESS(*status)) {
00833             return res_getString(rd, res, len);
00834         } else {
00835             *status = U_MISSING_RESOURCE_ERROR;
00836         }
00837     } else {
00838         *status = U_RESOURCE_TYPE_MISMATCH;
00839     }
00840     return NULL;
00841 }
00842 
00843 
00844 /* TODO: clean from here down */
00845 
00850 U_CFUNC const char* ures_getRealLocale(const UResourceBundle* resourceBundle, UErrorCode* status)
00851 {
00852     const UResourceDataEntry *resB = resourceBundle->fData;
00853     if (status==NULL || U_FAILURE(*status)) {
00854         return NULL;
00855     }
00856     if (!resourceBundle) {
00857         *status = U_ILLEGAL_ARGUMENT_ERROR;
00858         return NULL;
00859     }
00860 
00861     while(resB->fBogus != U_ZERO_ERROR && resB->fParent != NULL) {
00862         resB = resB->fParent;
00863     }
00864     if(resB->fBogus == U_ZERO_ERROR) {
00865         return resB->fName;
00866     } else {
00867         *status = U_INTERNAL_PROGRAM_ERROR;
00868     }
00869     return NULL;
00870 }
00871 
00872 static void entryCloseInt(UResourceDataEntry *resB) {
00873     UResourceDataEntry *p = resB;
00874 
00875     while(resB != NULL) {
00876         p = resB->fParent;
00877         resB->fCountExisting--;
00878 
00879         if(resB->fCountExisting <= 0) {
00880 
00881           /* Entries are left in the cache. TODO: add ures_cacheFlush() to force a flush
00882              of the cache. */
00883 /*
00884             uhash_remove(cache, resB);
00885             if(resB->fBogus == U_ZERO_ERROR) {
00886                 res_unload(&(resB->fData));
00887             }
00888             if(resB->fName != NULL) {
00889                 uprv_free(resB->fName);
00890             }
00891             if(resB->fPath != NULL) {
00892                 uprv_free(resB->fPath);
00893             }
00894             uprv_free(resB);
00895 */
00896         }
00897 
00898         resB = p;
00899     }
00900 }
00901 
00906 void entryClose(UResourceDataEntry *resB) {
00907   umtx_lock(&resbMutex);
00908   entryCloseInt(resB);
00909   umtx_unlock(&resbMutex);
00910 }
00911 
00912 
00913 U_CFUNC const char* ures_getName(const UResourceBundle* resB) {
00914     return resB->fData->fName;
00915 }
00916 U_CFUNC const char* ures_getPath(const UResourceBundle* resB) {
00917     return resB->fData->fPath;
00918 }
00919 U_CFUNC const char* ures_getTag(const UResourceBundle* resB) {
00920     return resB->fKey;
00921 }
00922 U_CFUNC const ResourceData * ures_getResData(const UResourceBundle* resB) {
00923     return &(resB->fData->fData);
00924 }
00925 
00926 /* OLD API implementation */
00927 
00933 U_CAPI void ures_openFillIn(UResourceBundle *r, const char* path,
00934                     const char* localeID, UErrorCode* status) {
00935     if(r == NULL) {
00936         *status = U_INTERNAL_PROGRAM_ERROR;
00937     } else {
00938         UResourceDataEntry *firstData;
00939         r->fHasFallback = TRUE;
00940         r->fIsTopLevel = TRUE;
00941         r->fKey = NULL;
00942         r->fVersion = NULL;
00943         r->fIndex = -1;
00944         r->fData = entryOpen(path, localeID, status);
00945         /* this is a quick fix to get regular data in bundle - until construction is cleaned up */
00946         firstData = r->fData;
00947         while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) {
00948             firstData = firstData->fParent;
00949         }
00950         r->fResData.data = firstData->fData.data;
00951         r->fResData.pRoot = firstData->fData.pRoot;
00952         r->fResData.rootRes = firstData->fData.rootRes;
00953         r->fRes = r->fResData.rootRes;
00954         r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
00955     }
00956 }
00957 U_CAPI UResourceBundle* ures_open(const char* path,
00958                     const char* localeID,
00959                     UErrorCode* status)
00960 {
00961     UResourceDataEntry *hasData = NULL;
00962     UResourceBundle *r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
00963     if(r == NULL) {
00964         *status = U_MEMORY_ALLOCATION_ERROR;
00965         return NULL;
00966     }
00967 
00968     r->fHasFallback = TRUE;
00969     r->fIsTopLevel = TRUE;
00970     ures_setIsStackObject(r, FALSE);
00971     r->fKey = NULL;
00972     r->fVersion = NULL;
00973     r->fIndex = -1;
00974     r->fData = entryOpen(path, localeID, status);
00975     if(U_FAILURE(*status)) {
00976         uprv_free(r);
00977         return NULL;
00978     }
00979 
00980     hasData = r->fData;
00981     while(hasData->fBogus != U_ZERO_ERROR) {
00982         hasData = hasData->fParent;
00983         if(hasData == NULL) {
00984             entryClose(r->fData);
00985             uprv_free(r);
00986             *status = U_MISSING_RESOURCE_ERROR;
00987             return NULL;
00988         }
00989     }
00990 
00991     r->fResData.data = hasData->fData.data;
00992     r->fResData.pRoot = hasData->fData.pRoot;
00993     r->fResData.rootRes = hasData->fData.rootRes;
00994     r->fRes = r->fResData.rootRes;
00995     r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
00996 
00997     return r;
00998 }
00999 
01000 U_CAPI UResourceBundle* ures_openW(const wchar_t* myPath,
01001                     const char* localeID,
01002                     UErrorCode* status)
01003 {
01004     char path[100];
01005     UResourceBundle *r;
01006     size_t tempSize = uprv_wcstombs(NULL, myPath, ((size_t)-1) >> 1);
01007     /*char *temp = new char[tempSize + 1];*/
01008 
01009     tempSize = uprv_wcstombs(path, myPath, tempSize);
01010     path[tempSize] = 0;
01011 
01012     /*u_UCharsToChars(myPath, path, uprv_wcslen(myPath)+1);*/
01013 
01014     r = ures_open(path, localeID, status);
01015 
01016     if (r == FALSE || U_FAILURE(*status)) {
01017         return NULL;
01018     }
01019 
01020     return r;
01021 }
01022 
01023 
01024 U_CAPI UResourceBundle* U_EXPORT2 ures_openU(const UChar* myPath, 
01025                   const char* localeID, 
01026                   UErrorCode* status)
01027 {
01028     char path[100];
01029     UResourceBundle *r;
01030     int32_t pathlen = u_strlen(myPath);
01031 
01032 
01033     u_UCharsToChars(myPath, path, pathlen);
01034     path[pathlen] = 0;
01035 
01036     r = ures_open(path, localeID, status);
01037 
01038     if (r == FALSE || U_FAILURE(*status)) {
01039         return NULL;
01040     }
01041 
01042     return r;
01043 }
01044 
01045 U_CAPI void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
01046     if(state == TRUE) {
01047         resB->fMagic1 = 0;
01048         resB->fMagic2 = 0;
01049     } else {
01050         resB->fMagic1 = MAGIC1;
01051         resB->fMagic2 = MAGIC2;
01052     }
01053 }
01054 
01055 U_CAPI UBool ures_isStackObject( UResourceBundle* resB, UErrorCode *status) {
01056     if(status == NULL || U_FAILURE(*status)) {
01057         return FALSE;
01058     }
01059     if(resB == NULL) {
01060         *status = U_ILLEGAL_ARGUMENT_ERROR;
01061         return TRUE;
01062     }
01063     if(resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2) {
01064         return FALSE;
01065     } else {
01066         return TRUE;
01067     }
01068 }
01069 
01070 
01071 U_CAPI const UChar* ures_get(    const UResourceBundle*    resB,
01072                 const char*              resourceTag,
01073                 UErrorCode*               status) 
01074 {
01075     int32_t len = 0;
01076         if(resB == NULL || U_FAILURE(*status)) {
01077                 *status = U_ILLEGAL_ARGUMENT_ERROR;
01078                 return NULL;
01079         }
01080     return ures_getStringByKey(resB, resourceTag, &len, status);
01081 }
01082 
01083 U_CAPI const UChar* ures_getArrayItem(const UResourceBundle*     resB,
01084                     const char*               resourceTag,
01085                     int32_t                   resourceIndex,
01086                     UErrorCode*                status)
01087 {
01088     UResourceBundle res;
01089     ures_setIsStackObject(&res, TRUE);
01090         if (status==NULL || U_FAILURE(*status)) {
01091                 return NULL;
01092         }
01093         if(resB == NULL) {
01094                 *status = U_ILLEGAL_ARGUMENT_ERROR;
01095                 return NULL;
01096         }
01097     ures_getByKey(resB, resourceTag, &res, status);
01098     if(U_SUCCESS(*status)) {
01099         int32_t len = 0;
01100         const UChar *r = ures_getStringByIndex(&res, resourceIndex, &len, status);
01101         ures_close(&res);
01102         return r;
01103     } else {
01104         return NULL;
01105     }
01106 }
01107 
01108 U_CAPI const UChar* ures_get2dArrayItem(const UResourceBundle*   resB,
01109                       const char*             resourceTag,
01110                       int32_t                 rowIndex,
01111                       int32_t                 columnIndex,
01112                       UErrorCode*              status)
01113 {
01114     UResourceBundle res;
01115     ures_setIsStackObject(&res, TRUE);
01116         if (status==NULL || U_FAILURE(*status)) {
01117                 return NULL;
01118         }
01119         if(resB == NULL) {
01120                 *status = U_ILLEGAL_ARGUMENT_ERROR;
01121                 return NULL;
01122         }
01123     ures_getByKey(resB, resourceTag, &res, status);
01124     if(U_SUCCESS(*status)) {
01125         UResourceBundle res2;
01126         ures_setIsStackObject(&res2, TRUE);
01127         ures_getByIndex(&res, rowIndex, &res2, status);
01128         ures_close(&res);
01129         if(U_SUCCESS(*status)) {
01130             int32_t len = 0;
01131             const UChar *r = ures_getStringByIndex(&res2, columnIndex, &len, status);
01132             ures_close(&res2);
01133             return r;
01134         } else {
01135             return NULL;
01136         }
01137     } else {
01138         return NULL;
01139     }
01140 }
01141 
01142 U_CAPI const UChar* ures_getTaggedArrayItem(const UResourceBundle*   resB,
01143                       const char*             resourceTag,
01144                       const char*             itemTag,
01145                       UErrorCode*              status)
01146 {
01147     UResourceBundle res;
01148     ures_setIsStackObject(&res, TRUE);
01149         if (status==NULL || U_FAILURE(*status)) {
01150                 return NULL;
01151         }
01152         if(resB == NULL) {
01153                 *status = U_ILLEGAL_ARGUMENT_ERROR;
01154                 return NULL;
01155         }
01156     ures_getByKey(resB, resourceTag, &res, status);
01157     if(U_SUCCESS(*status)) {
01158         int32_t len = 0;
01159         const UChar *r = ures_getStringByKey(&res, itemTag, &len, status);
01160         ures_close(&res);
01161         return r;
01162     } else {
01163         return NULL;
01164     }
01165 }
01166 
01171 U_CAPI int32_t ures_countArrayItems(const UResourceBundle* resourceBundle,
01172                   const char* resourceKey,
01173                   UErrorCode* status)
01174 {
01175     UResourceBundle resData;
01176     ures_setIsStackObject(&resData, TRUE);
01177         if (status==NULL || U_FAILURE(*status)) {
01178                 return 0;
01179         }
01180         if(resourceBundle == NULL) {
01181                 *status = U_ILLEGAL_ARGUMENT_ERROR;
01182                 return 0;
01183         }
01184     ures_getByKey(resourceBundle, resourceKey, &resData, status);
01185 
01186     if(resData.fResData.data != NULL) {
01187       int32_t result = res_countArrayItems(&resData.fResData, resData.fRes);
01188       ures_close(&resData);
01189       return result;
01190     } else {
01191       *status = U_MISSING_RESOURCE_ERROR;
01192       ures_close(&resData);
01193       return 0;
01194     }
01195 }
01196 
01197 U_CAPI void ures_close(UResourceBundle*    resB)
01198 {
01199     UErrorCode status = U_ZERO_ERROR;
01200     if(resB != NULL) {
01201         if(resB->fData != NULL) {
01202             entryClose(resB->fData);
01203         }
01204         /*
01205         if(resB->fKey != NULL) {
01206             uprv_free(resB->fKey);
01207         }
01208         */
01209         if(resB->fVersion != NULL) {
01210             uprv_free(resB->fVersion);
01211         }
01212 
01213         if(ures_isStackObject(resB, &status) == FALSE) {
01214             uprv_free(resB);
01215         }
01216     }
01217 }
01218 
01219 U_CAPI const char* ures_getVersionNumber(const UResourceBundle*   resourceBundle)
01220 {
01221     if (!resourceBundle) return NULL;
01222 
01223     if(resourceBundle->fVersion == NULL) {
01224 
01225         /* If the version ID has not been built yet, then do so.  Retrieve */
01226         /* the minor version from the file. */
01227         UErrorCode status = U_ZERO_ERROR;
01228         int32_t minor_len = 0;
01229         int32_t len;
01230 
01231         const UChar* minor_version = ures_getStringByKey(resourceBundle, kVersionTag, &minor_len, &status);
01232     
01233         /* Determine the length of of the final version string.  This is */
01234         /* the length of the major part + the length of the separator */
01235         /* (==1) + the length of the minor part (+ 1 for the zero byte at */
01236         /* the end). */
01237 
01238         len = (minor_len > 0) ? minor_len : 1;
01239     
01240         /* Allocate the string, and build it up. */
01241         /* + 1 for zero byte */
01242 
01243 
01244         ((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_malloc(1 + len); 
01245     
01246         if(minor_len > 0) {
01247             u_UCharsToChars(minor_version, resourceBundle->fVersion , minor_len);
01248             resourceBundle->fVersion[len] =  '\0';
01249         }
01250         else {
01251           uprv_strcat(resourceBundle->fVersion, kDefaultMinorVersion);
01252         }
01253     }
01254 
01255     return resourceBundle->fVersion;
01256 }
01257 
01258 U_CAPI void U_EXPORT2 ures_getVersion(const UResourceBundle* resB, UVersionInfo versionInfo) {
01259     if (!resB) return;
01260 
01261     u_versionFromString(versionInfo, ures_getVersionNumber(resB));
01262 }
01263 
01269 U_CAPI const char* ures_getLocale(const UResourceBundle* resourceBundle, UErrorCode* status)
01270 {
01271         if (status==NULL || U_FAILURE(*status)) {
01272                 return NULL;
01273         }
01274   if (!resourceBundle)
01275     {
01276       *status = U_ILLEGAL_ARGUMENT_ERROR;
01277       return NULL;
01278     }
01279   return ures_getName(resourceBundle);
01280 }
01281 
01282 
01283 /* eof */

Generated at Tue Dec 5 10:48:11 2000 for ICU by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000