1 // © 2016 and later: Unicode, Inc. and others. 
   2 // License & terms of use: http://www.unicode.org/copyright.html 
   4 ********************************************************************** 
   5 *   Copyright (C) 2000-2016, International Business Machines 
   6 *   Corporation and others.  All Rights Reserved. 
   7 ********************************************************************** 
  13 #include "unicode/ures.h" 
  14 #include "unicode/utypes.h" 
  18 #define kRootLocaleName         "root" 
  19 #define kPoolBundleName         "pool" 
  22  The default minor version and the version separator must be exactly one 
  26 #define kDefaultMinorVersion    "0" 
  27 #define kVersionSeparator       "." 
  28 #define kVersionTag             "Version" 
  30 #define MAGIC1 19700503 
  31 #define MAGIC2 19641227 
  33 #define URES_MAX_ALIAS_LEVEL 256 
  34 #define URES_MAX_BUFFER_SIZE 256 
  36 #define EMPTY_SET 0x2205 
  38 struct UResourceDataEntry
; 
  39 typedef struct UResourceDataEntry UResourceDataEntry
; 
  42  * Note: If we wanted to make this structure smaller, then we could try 
  43  * to use one UResourceDataEntry pointer for fAlias and fPool, with a separate 
  44  * flag to distinguish whether this struct is for a real bundle with a pool, 
  45  * or for an alias entry for which we won't use the pool after loading. 
  47 struct UResourceDataEntry 
{ 
  48     char *fName
; /* name of the locale for bundle - still to decide whether it is original or fallback */ 
  49     char *fPath
; /* path to bundle - used for distinguishing between resources with the same name */ 
  50     UResourceDataEntry 
*fParent
; /*next resource in fallback chain*/ 
  51     UResourceDataEntry 
*fAlias
; 
  52     UResourceDataEntry 
*fPool
; 
  53     ResourceData fData
; /* data for low level access */ 
  54     char fNameBuffer
[3]; /* A small buffer of free space for fName. The free space is due to struct padding. */ 
  55     uint32_t fCountExisting
; /* how much is this resource used */ 
  57     /* int32_t fHashKey;*/ /* for faster access in the hashtable */ 
  60 #define RES_BUFSIZE 64 
  61 #define RES_PATH_SEPARATOR   '/' 
  62 #define RES_PATH_SEPARATOR_S   "/" 
  64 struct UResourceBundle 
{ 
  65     const char *fKey
; /*tag*/ 
  66     UResourceDataEntry 
*fData
; /*for low-level access*/ 
  68     UResourceDataEntry 
*fTopLevelData
; /* for getting the valid locale */ 
  69     char *fResPath
; /* full path to the resource: "zh_TW/CollationElements/Sequence" */ 
  70     // TODO(ICU-20769): Try to change the by-value fResData into a pointer, 
  71     // with the struct in only one place for each bundle. 
  72     // Also replace class ResourceDataValue.resData with a pResData pointer again. 
  73     ResourceData fResData
; 
  74     char fResBuf
[RES_BUFSIZE
]; 
  79     uint32_t fMagic1
;   /* For determining if it's a stack object */ 
  80     uint32_t fMagic2
;   /* For determining if it's a stack object */ 
  84     /*const UResourceBundle *fParentRes;*/ /* needed to get the actual locale for a child resource */ 
  87 U_CAPI 
void U_EXPORT2 
ures_initStackObject(UResourceBundle
* resB
); 
  94  * \class StackUResourceBundle 
  95  * "Smart pointer" like class, closes a UResourceBundle via ures_close(). 
  99  *   StackUResourceBundle bundle; 
 100  *   foo(bundle.getAlias()); 
 102  * Is equivalent to this code: 
 104  *   UResourceBundle bundle; 
 105  *   ures_initStackObject(&bundle); 
 107  *   ures_close(&bundle); 
 109  * @see LocalUResourceBundlePointer 
 112 class U_COMMON_API StackUResourceBundle 
{ 
 114     // No heap allocation. Use only on the stack. 
 115     static void* U_EXPORT2 
operator new(size_t) U_NOEXCEPT 
= delete; 
 116     static void* U_EXPORT2 
operator new[](size_t) U_NOEXCEPT 
= delete; 
 117 #if U_HAVE_PLACEMENT_NEW 
 118     static void* U_EXPORT2 
operator new(size_t, void*) U_NOEXCEPT 
= delete; 
 121     StackUResourceBundle(); 
 122     ~StackUResourceBundle(); 
 124     UResourceBundle
* getAlias() { return &bundle
; } 
 126     UResourceBundle
& ref() { return bundle
; } 
 127     const UResourceBundle
& ref() const { return bundle
; } 
 129     StackUResourceBundle(const StackUResourceBundle
&) = delete; 
 130     StackUResourceBundle
& operator=(const StackUResourceBundle
&) = delete; 
 132     StackUResourceBundle(StackUResourceBundle
&&) = delete; 
 133     StackUResourceBundle
& operator=(StackUResourceBundle
&&) = delete; 
 136     UResourceBundle bundle
; 
 141 #endif  /* __cplusplus */ 
 144  * Opens a resource bundle for the locale; 
 145  * if there is not even a base language bundle, then loads the root bundle; 
 146  * never falls back to the default locale. 
 148  * This is used for algorithms that have good pan-Unicode default behavior, 
 149  * such as case mappings, collation, and segmentation (BreakIterator). 
 151 U_CAPI UResourceBundle
* U_EXPORT2
 
 152 ures_openNoDefault(const char* path
, const char* localeID
, UErrorCode
* status
); 
 154 /* Some getters used by the copy constructor */ 
 155 U_CFUNC 
const char* ures_getName(const UResourceBundle
* resB
); 
 157 U_CFUNC 
const char* ures_getPath(const UResourceBundle
* resB
); 
 159  * If anything was in the RB cache, dump it to the screen. 
 160  * @return TRUE if there was anything into the cache 
 162 U_CAPI UBool U_EXPORT2 
ures_dumpCacheContents(void); 
 164 /*U_CFUNC void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd);*/ 
 165 /*U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd);*/ 
 166 /*U_CFUNC void ures_freeResPath(UResourceBundle *resB);*/ 
 168 /* Candidates for export */ 
 169 U_CFUNC UResourceBundle 
*ures_copyResb(UResourceBundle 
*r
, const UResourceBundle 
*original
, UErrorCode 
*status
); 
 172  * Returns a resource that can be located using the pathToResource argument. One needs optional package, locale 
 173  * and path inside the locale, for example: "/myData/en/zoneStrings/3". Keys and indexes are supported. Keys 
 174  * need to reference data in named structures, while indexes can reference both named and anonymous resources. 
 175  * Features a fill-in parameter.  
 177  * Note, this function does NOT have a syntax for specifying items within a tree.  May want to consider a 
 178  * syntax that delineates between package/tree and resource.   
 180  * @param pathToResource    a path that will lead to the requested resource 
 181  * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. 
 182  *                          Alternatively, you can supply a struct to be filled by this function. 
 183  * @param status            fills in the outgoing error code. 
 184  * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it 
 186 U_CAPI UResourceBundle
* U_EXPORT2
 
 187 ures_findResource(const char* pathToResource
,  
 188                   UResourceBundle 
*fillIn
, UErrorCode 
*status
);  
 191  * Returns a sub resource that can be located using the pathToResource argument. One needs a path inside  
 192  * the supplied resource, for example, if you have "en_US" resource bundle opened, you might ask for 
 193  * "zoneStrings/3". Keys and indexes are supported. Keys 
 194  * need to reference data in named structures, while indexes can reference both  
 195  * named and anonymous resources. 
 196  * Features a fill-in parameter.  
 198  * @param resourceBundle    a resource 
 199  * @param pathToResource    a path that will lead to the requested resource 
 200  * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. 
 201  *                          Alternatively, you can supply a struct to be filled by this function. 
 202  * @param status            fills in the outgoing error code. 
 203  * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it 
 205 U_CAPI UResourceBundle
* U_EXPORT2
 
 206 ures_findSubResource(const UResourceBundle 
*resB
,  
 207                      char* pathToResource
,  
 208                      UResourceBundle 
*fillIn
, UErrorCode 
*status
); 
 211  * Returns a functionally equivalent locale (considering keywords) for the specified keyword. 
 212  * @param result fillin for the equivalent locale 
 213  * @param resultCapacity capacity of the fillin buffer 
 214  * @param path path to the tree, or NULL for ICU data 
 215  * @param resName top level resource. Example: "collations" 
 216  * @param keyword locale keyword. Example: "collation" 
 217  * @param locid The requested locale 
 218  * @param isAvailable If non-null, pointer to fillin parameter that indicates whether the  
 219  * requested locale was available. The locale is defined as 'available' if it physically  
 220  * exists within the specified tree. 
 221  * @param omitDefault if TRUE, omit keyword and value if default. 'de_DE\@collation=standard' -> 'de_DE' 
 222  * @param status error code 
 223  * @return  the actual buffer size needed for the full locale.  If it's greater  
 224  * than resultCapacity, the returned full name will be truncated and an error code will be returned. 
 226 U_CAPI 
int32_t U_EXPORT2
 
 227 ures_getFunctionalEquivalent(char *result
, int32_t resultCapacity
,  
 228                              const char *path
, const char *resName
, const char *keyword
, const char *locid
, 
 229                              UBool 
*isAvailable
, UBool omitDefault
, UErrorCode 
*status
); 
 232  * Given a tree path and keyword, return a string enumeration of all possible values for that keyword. 
 233  * @param path path to the tree, or NULL for ICU data 
 234  * @param keyword a particular keyword to consider, must match a top level resource name  
 236  * @param status error code 
 238 U_CAPI UEnumeration
* U_EXPORT2
 
 239 ures_getKeywordValues(const char *path
, const char *keyword
, UErrorCode 
*status
); 
 243  * Get a resource with multi-level fallback. Normally only the top level resources will 
 244  * fallback to its parent. This performs fallback on subresources. For example, when a table 
 245  * is defined in a resource bundle and a parent resource bundle, normally no fallback occurs 
 246  * on the sub-resources because the table is defined in the current resource bundle, but this 
 247  * function can perform fallback on the sub-resources of the table. 
 248  * @param resB              a resource 
 249  * @param inKey             a key associated with the requested resource 
 250  * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. 
 251  *                          Alternatively, you can supply a struct to be filled by this function. 
 252  * @param status: fills in the outgoing error code 
 253  *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found 
 254  *                could be a non-failing error  
 255  *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT> 
 256  * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it 
 258 U_CAPI UResourceBundle
* U_EXPORT2 
 
 259 ures_getByKeyWithFallback(const UResourceBundle 
*resB
,  
 261                           UResourceBundle 
*fillIn
,  
 266  * Get a String with multi-level fallback. Normally only the top level resources will 
 267  * fallback to its parent. This performs fallback on subresources. For example, when a table 
 268  * is defined in a resource bundle and a parent resource bundle, normally no fallback occurs 
 269  * on the sub-resources because the table is defined in the current resource bundle, but this 
 270  * function can perform fallback on the sub-resources of the table. 
 271  * @param resB              a resource 
 272  * @param inKey             a key associated with the requested resource 
 273  * @param status: fills in the outgoing error code 
 274  *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found 
 275  *                could be a non-failing error  
 276  *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT> 
 277  * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it 
 279 U_CAPI 
const UChar
* U_EXPORT2 
 
 280 ures_getStringByKeyWithFallback(const UResourceBundle 
*resB
,  
 287 U_CAPI 
void U_EXPORT2
 
 288 ures_getValueWithFallback(const UResourceBundle 
*bundle
, const char *path
, 
 289                           UResourceBundle 
*tempFillIn
, 
 290                           icu::ResourceDataValue 
&value
, UErrorCode 
&errorCode
); 
 292 U_CAPI 
void U_EXPORT2
 
 293 ures_getAllItemsWithFallback(const UResourceBundle 
*bundle
, const char *path
, 
 294                              icu::ResourceSink 
&sink
, UErrorCode 
&errorCode
); 
 296 #endif  /* __cplusplus */ 
 299  * Get a version number by key 
 300  * @param resB bundle containing version number 
 301  * @param key the key for the version number 
 302  * @param ver fillin for the version number 
 303  * @param status error code 
 305 U_CAPI 
void U_EXPORT2
 
 306 ures_getVersionByKey(const UResourceBundle 
*resB
, 
 314  * Return the version number associated with this ResourceBundle as a string. 
 316  * @param resourceBundle The resource bundle for which the version is checked. 
 317  * @return  A version number string as specified in the resource bundle or its parent. 
 318  *          The caller does not own this string. 
 319  * @see ures_getVersion 
 321 U_CAPI 
const char* U_EXPORT2 
 
 322 ures_getVersionNumberInternal(const UResourceBundle 
*resourceBundle
); 
 325  * Return the name of the Locale associated with this ResourceBundle. This API allows 
 326  * you to query for the real locale of the resource. For example, if you requested  
 327  * "en_US_CALIFORNIA" and only "en_US" bundle exists, "en_US" will be returned.  
 328  * For subresources, the locale where this resource comes from will be returned. 
 329  * If fallback has occured, getLocale will reflect this. 
 331  * This internal version avoids deprecated-warnings in ICU code. 
 333  * @param resourceBundle resource bundle in question 
 334  * @param status just for catching illegal arguments 
 335  * @return  A Locale name 
 337 U_CAPI 
const char* U_EXPORT2 
 
 338 ures_getLocaleInternal(const UResourceBundle
* resourceBundle
,  
 342  * Same as ures_openDirect() but uses the fill-in parameter instead of allocating a new bundle. 
 344  * @param r The existing UResourceBundle to fill in. If NULL then status will be 
 345  *          set to U_ILLEGAL_ARGUMENT_ERROR. 
 346  * @param packageName   The packageName and locale together point to an ICU udata object, 
 347  *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
 348  *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to 
 349  *                      a package registered with udata_setAppData(). Using a full file or directory 
 350  *                      pathname for packageName is deprecated. If NULL, ICU data will be used. 
 351  * @param locale  specifies the locale for which we want to open the resource 
 352  *                if NULL, the default locale will be used. If strlen(locale) == 0 
 353  *                root locale will be used. 
 354  * @param status The error code. 
 355  * @see ures_openDirect 
 358 U_CAPI 
void U_EXPORT2
 
 359 ures_openDirectFillIn(UResourceBundle 
*r
, 
 360                       const char *packageName
, 
 365  * Same as ures_open(), except that if no resource bundle for the specified package name and locale exists, 
 366  * and the incoming locale specifies a country, this will fall back to the resource bundle for the specified country 
 367  * and the specified country's default language.  For example, if caller asks for fr_JP and no bundle for fr_JP exists, 
 368  * ures_open() will fall back to fr and this function will fall back to ja_JP. 
 369  * @param packageName   The packageName and locale together point to an ICU udata object, 
 370  *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
 371  *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to 
 372  *                      a package registered with udata_setAppData(). Using a full file or directory 
 373  *                      pathname for packageName is deprecated. If NULL, ICU data will be used. 
 374  * @param locale  specifies the locale for which we want to open the resource 
 375  *                if NULL, the default locale will be used. If strlen(locale) == 0 
 376  *                root locale will be used. 
 377  * @param didFallBackByCountry If not NULL, filled in with a Boolean value that indicates whether we actually 
 378  *                            did fall back by country.  If this value is FALSE, the result of calling this function 
 379  *                            is the same as the caller would have gotten from ures_open(). 
 380  * @param status  fills in the outgoing error code. 
 381  * @return      a newly allocated resource bundle. 
 385 U_CAPI UResourceBundle
*  U_EXPORT2
 
 386 ures_openWithCountryFallback(const char*  packageName
, 
 388                              UBool
*       didFallBackByCountry
, 
 392  * If localeID has a parent in parentLocale data, return that. 
 393  * Otherwise return empty string. 
 395  * A more general version of this might then itself call 
 396  * uloc_getParent, but that is not what we want for ualoc usage. 
 398  * Some version of this (perhaps more general) should eventually move 
 399  * (with new name) to ulocimp.h, or perhaps uloc.h. 
 401  * @param localeID Input locale ID string. 
 402  * @param parent   Output string buffer for the parent locale ID. 
 403  * @param parentCapacity Size of the output buffer. 
 404  * @param err A UErrorCode value. 
 405  * @return The length of the parent locale ID. 
 406  * @see uloc_getParent 
 407  * @internal Apple <rdar://problem/63880069> 
 409 U_CAPI 
int32_t U_EXPORT2
 
 410 ures_getLocParent(const char* localeID
, 
 412                  int32_t parentCapacity
,