1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/resbund.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,396 @@ 1.4 +/* 1.5 +********************************************************************** 1.6 +* Copyright (C) 1997-2013, International Business Machines 1.7 +* Corporation and others. All Rights Reserved. 1.8 +********************************************************************** 1.9 +* 1.10 +* File resbund.cpp 1.11 +* 1.12 +* Modification History: 1.13 +* 1.14 +* Date Name Description 1.15 +* 02/05/97 aliu Fixed bug in chopLocale. Added scanForLocaleInFile 1.16 +* based on code taken from scanForLocale. Added 1.17 +* constructor which attempts to read resource bundle 1.18 +* from a specific file, without searching other files. 1.19 +* 02/11/97 aliu Added UErrorCode return values to constructors. Fixed 1.20 +* infinite loops in scanForFile and scanForLocale. 1.21 +* Modified getRawResourceData to not delete storage in 1.22 +* localeData and resourceData which it doesn't own. 1.23 +* Added Mac compatibility #ifdefs for tellp() and 1.24 +* ios::nocreate. 1.25 +* 03/04/97 aliu Modified to use ExpandingDataSink objects instead of 1.26 +* the highly inefficient ostrstream objects. 1.27 +* 03/13/97 aliu Rewrote to load in entire resource bundle and store 1.28 +* it as a Hashtable of ResourceBundleData objects. 1.29 +* Added state table to govern parsing of files. 1.30 +* Modified to load locale index out of new file distinct 1.31 +* from default.txt. 1.32 +* 03/25/97 aliu Modified to support 2-d arrays, needed for timezone data. 1.33 +* Added support for custom file suffixes. Again, needed 1.34 +* to support timezone data. Improved error handling to 1.35 +* detect duplicate tags and subtags. 1.36 +* 04/07/97 aliu Fixed bug in getHashtableForLocale(). Fixed handling 1.37 +* of failing UErrorCode values on entry to API methods. 1.38 +* Fixed bugs in getArrayItem() for negative indices. 1.39 +* 04/29/97 aliu Update to use new Hashtable deletion protocol. 1.40 +* 05/06/97 aliu Flattened kTransitionTable for HP compiler. 1.41 +* Fixed usage of CharString. 1.42 +* 06/11/99 stephen Removed parsing of .txt files. 1.43 +* Reworked to use new binary format. 1.44 +* Cleaned up. 1.45 +* 06/14/99 stephen Removed methods taking a filename suffix. 1.46 +* 06/22/99 stephen Added missing T_FileStream_close in parse() 1.47 +* 11/09/99 weiv Added getLocale(), rewritten constructForLocale() 1.48 +* March 2000 weiv complete overhaul. 1.49 +****************************************************************************** 1.50 +*/ 1.51 + 1.52 +#include "unicode/utypes.h" 1.53 +#include "unicode/resbund.h" 1.54 + 1.55 +#include "mutex.h" 1.56 +#include "uassert.h" 1.57 +#include "umutex.h" 1.58 + 1.59 +#include "uresimp.h" 1.60 + 1.61 +U_NAMESPACE_BEGIN 1.62 + 1.63 +/*----------------------------------------------------------------------------- 1.64 + * Implementation Notes 1.65 + * 1.66 + * Resource bundles are read in once, and thereafter cached. 1.67 + * ResourceBundle statically keeps track of which files have been 1.68 + * read, so we are guaranteed that each file is read at most once. 1.69 + * Resource bundles can be loaded from different data directories and 1.70 + * will be treated as distinct, even if they are for the same locale. 1.71 + * 1.72 + * Resource bundles are lightweight objects, which have pointers to 1.73 + * one or more shared Hashtable objects containing all the data. 1.74 + * Copying would be cheap, but there is no copy constructor, since 1.75 + * there wasn't one in the original API. 1.76 + * 1.77 + * The ResourceBundle parsing mechanism is implemented as a transition 1.78 + * network, for easy maintenance and modification. The network is 1.79 + * implemented as a matrix (instead of in code) to make this even 1.80 + * easier. The matrix contains Transition objects. Each Transition 1.81 + * object describes a destination node and an action to take before 1.82 + * moving to the destination node. The source node is encoded by the 1.83 + * index of the object in the array that contains it. The pieces 1.84 + * needed to understand the transition network are the enums for node 1.85 + * IDs and actions, the parse() method, which walks through the 1.86 + * network and implements the actions, and the network itself. The 1.87 + * network guarantees certain conditions, for example, that a new 1.88 + * resource will not be closed until one has been opened first; or 1.89 + * that data will not be stored into a TaggedList until a TaggedList 1.90 + * has been created. Nonetheless, the code in parse() does some 1.91 + * consistency checks as it runs the network, and fails with an 1.92 + * U_INTERNAL_PROGRAM_ERROR if one of these checks fails. If the input 1.93 + * data has a bad format, an U_INVALID_FORMAT_ERROR is returned. If you 1.94 + * see an U_INTERNAL_PROGRAM_ERROR the transition matrix has a bug in 1.95 + * it. 1.96 + * 1.97 + * Old functionality of multiple locales in a single file is still 1.98 + * supported. For this reason, LOCALE names override FILE names. If 1.99 + * data for en_US is located in the en.txt file, once it is loaded, 1.100 + * the code will not care where it came from (other than remembering 1.101 + * which directory it came from). However, if there is an en_US 1.102 + * resource in en_US.txt, that will take precedence. There is no 1.103 + * limit to the number or type of resources that can be stored in a 1.104 + * file, however, files are only searched in a specific way. If 1.105 + * en_US_CA is requested, then first en_US_CA.txt is searched, then 1.106 + * en_US.txt, then en.txt, then default.txt. So it only makes sense 1.107 + * to put certain locales in certain files. In this example, it would 1.108 + * be logical to put en_US_CA, en_US, and en into the en.txt file, 1.109 + * since they would be found there if asked for. The extreme example 1.110 + * is to place all locale resources into default.txt, which should 1.111 + * also work. 1.112 + * 1.113 + * Inheritance is implemented. For example, xx_YY_zz inherits as 1.114 + * follows: xx_YY_zz, xx_YY, xx, default. Inheritance is implemented 1.115 + * as an array of hashtables. There will be from 1 to 4 hashtables in 1.116 + * the array. 1.117 + * 1.118 + * Fallback files are implemented. The fallback pattern is Language 1.119 + * Country Variant (LCV) -> LC -> L. Fallback is first done for the 1.120 + * requested locale. Then it is done for the default locale, as 1.121 + * returned by Locale::getDefault(). Then the special file 1.122 + * default.txt is searched for the default locale. The overall FILE 1.123 + * fallback path is LCV -> LC -> L -> dLCV -> dLC -> dL -> default. 1.124 + * 1.125 + * Note that although file name searching includes the default locale, 1.126 + * once a ResourceBundle object is constructed, the inheritance path 1.127 + * no longer includes the default locale. The path is LCV -> LC -> L 1.128 + * -> default. 1.129 + * 1.130 + * File parsing is lazy. Nothing is parsed unless it is called for by 1.131 + * someone. So when a ResourceBundle for xx_YY_zz is constructed, 1.132 + * only that locale is parsed (along with anything else in the same 1.133 + * file). Later, if the FooBar tag is asked for, and if it isn't 1.134 + * found in xx_YY_zz, then xx_YY.txt will be parsed and checked, and 1.135 + * so forth, until the chain is exhausted or the tag is found. 1.136 + * 1.137 + * Thread-safety is implemented around caches, both the cache that 1.138 + * stores all the resouce data, and the cache that stores flags 1.139 + * indicating whether or not a file has been visited. These caches 1.140 + * delete their storage at static cleanup time, when the process 1.141 + * quits. 1.142 + * 1.143 + * ResourceBundle supports TableCollation as a special case. This 1.144 + * involves having special ResourceBundle objects which DO own their 1.145 + * data, since we don't want large collation rule strings in the 1.146 + * ResourceBundle cache (these are already cached in the 1.147 + * TableCollation cache). TableCollation files (.ctx files) have the 1.148 + * same format as normal resource data files, with a different 1.149 + * interpretation, from the standpoint of ResourceBundle. .ctx files 1.150 + * are loaded into otherwise ordinary ResourceBundle objects. They 1.151 + * don't inherit (that's implemented by TableCollation) and they own 1.152 + * their data (as mentioned above). However, they still support 1.153 + * possible multiple locales in a single .ctx file. (This is in 1.154 + * practice a bad idea, since you only want the one locale you're 1.155 + * looking for, and only one tag will be present 1.156 + * ("CollationElements"), so you don't need an inheritance chain of 1.157 + * multiple locales.) Up to 4 locale resources will be loaded from a 1.158 + * .ctx file; everything after the first 4 is ignored (parsed and 1.159 + * deleted). (Normal .txt files have no limit.) Instead of being 1.160 + * loaded into the cache, and then looked up as needed, the locale 1.161 + * resources are read straight into the ResourceBundle object. 1.162 + * 1.163 + * The Index, which used to reside in default.txt, has been moved to a 1.164 + * new file, index.txt. This file contains a slightly modified format 1.165 + * with the addition of the "InstalledLocales" tag; it looks like: 1.166 + * 1.167 + * Index { 1.168 + * InstalledLocales { 1.169 + * ar 1.170 + * .. 1.171 + * zh_TW 1.172 + * } 1.173 + * } 1.174 + */ 1.175 +//----------------------------------------------------------------------------- 1.176 + 1.177 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ResourceBundle) 1.178 + 1.179 +ResourceBundle::ResourceBundle(UErrorCode &err) 1.180 + :UObject(), fLocale(NULL) 1.181 +{ 1.182 + fResource = ures_open(0, Locale::getDefault().getName(), &err); 1.183 +} 1.184 + 1.185 +ResourceBundle::ResourceBundle(const ResourceBundle &other) 1.186 + :UObject(other), fLocale(NULL) 1.187 +{ 1.188 + UErrorCode status = U_ZERO_ERROR; 1.189 + 1.190 + if (other.fResource) { 1.191 + fResource = ures_copyResb(0, other.fResource, &status); 1.192 + } else { 1.193 + /* Copying a bad resource bundle */ 1.194 + fResource = NULL; 1.195 + } 1.196 +} 1.197 + 1.198 +ResourceBundle::ResourceBundle(UResourceBundle *res, UErrorCode& err) 1.199 + :UObject(), fLocale(NULL) 1.200 +{ 1.201 + if (res) { 1.202 + fResource = ures_copyResb(0, res, &err); 1.203 + } else { 1.204 + /* Copying a bad resource bundle */ 1.205 + fResource = NULL; 1.206 + } 1.207 +} 1.208 + 1.209 +ResourceBundle::ResourceBundle(const char* path, const Locale& locale, UErrorCode& err) 1.210 + :UObject(), fLocale(NULL) 1.211 +{ 1.212 + fResource = ures_open(path, locale.getName(), &err); 1.213 +} 1.214 + 1.215 + 1.216 +ResourceBundle& ResourceBundle::operator=(const ResourceBundle& other) 1.217 +{ 1.218 + if(this == &other) { 1.219 + return *this; 1.220 + } 1.221 + if(fResource != 0) { 1.222 + ures_close(fResource); 1.223 + fResource = NULL; 1.224 + } 1.225 + if (fLocale != NULL) { 1.226 + delete fLocale; 1.227 + fLocale = NULL; 1.228 + } 1.229 + UErrorCode status = U_ZERO_ERROR; 1.230 + if (other.fResource) { 1.231 + fResource = ures_copyResb(0, other.fResource, &status); 1.232 + } else { 1.233 + /* Copying a bad resource bundle */ 1.234 + fResource = NULL; 1.235 + } 1.236 + return *this; 1.237 +} 1.238 + 1.239 +ResourceBundle::~ResourceBundle() 1.240 +{ 1.241 + if(fResource != 0) { 1.242 + ures_close(fResource); 1.243 + } 1.244 + if(fLocale != NULL) { 1.245 + delete(fLocale); 1.246 + } 1.247 +} 1.248 + 1.249 +ResourceBundle * 1.250 +ResourceBundle::clone() const { 1.251 + return new ResourceBundle(*this); 1.252 +} 1.253 + 1.254 +UnicodeString ResourceBundle::getString(UErrorCode& status) const { 1.255 + int32_t len = 0; 1.256 + const UChar *r = ures_getString(fResource, &len, &status); 1.257 + return UnicodeString(TRUE, r, len); 1.258 +} 1.259 + 1.260 +const uint8_t *ResourceBundle::getBinary(int32_t& len, UErrorCode& status) const { 1.261 + return ures_getBinary(fResource, &len, &status); 1.262 +} 1.263 + 1.264 +const int32_t *ResourceBundle::getIntVector(int32_t& len, UErrorCode& status) const { 1.265 + return ures_getIntVector(fResource, &len, &status); 1.266 +} 1.267 + 1.268 +uint32_t ResourceBundle::getUInt(UErrorCode& status) const { 1.269 + return ures_getUInt(fResource, &status); 1.270 +} 1.271 + 1.272 +int32_t ResourceBundle::getInt(UErrorCode& status) const { 1.273 + return ures_getInt(fResource, &status); 1.274 +} 1.275 + 1.276 +const char *ResourceBundle::getName(void) const { 1.277 + return ures_getName(fResource); 1.278 +} 1.279 + 1.280 +const char *ResourceBundle::getKey(void) const { 1.281 + return ures_getKey(fResource); 1.282 +} 1.283 + 1.284 +UResType ResourceBundle::getType(void) const { 1.285 + return ures_getType(fResource); 1.286 +} 1.287 + 1.288 +int32_t ResourceBundle::getSize(void) const { 1.289 + return ures_getSize(fResource); 1.290 +} 1.291 + 1.292 +UBool ResourceBundle::hasNext(void) const { 1.293 + return ures_hasNext(fResource); 1.294 +} 1.295 + 1.296 +void ResourceBundle::resetIterator(void) { 1.297 + ures_resetIterator(fResource); 1.298 +} 1.299 + 1.300 +ResourceBundle ResourceBundle::getNext(UErrorCode& status) { 1.301 + UResourceBundle r; 1.302 + 1.303 + ures_initStackObject(&r); 1.304 + ures_getNextResource(fResource, &r, &status); 1.305 + ResourceBundle res(&r, status); 1.306 + if (U_SUCCESS(status)) { 1.307 + ures_close(&r); 1.308 + } 1.309 + return res; 1.310 +} 1.311 + 1.312 +UnicodeString ResourceBundle::getNextString(UErrorCode& status) { 1.313 + int32_t len = 0; 1.314 + const UChar* r = ures_getNextString(fResource, &len, 0, &status); 1.315 + return UnicodeString(TRUE, r, len); 1.316 +} 1.317 + 1.318 +UnicodeString ResourceBundle::getNextString(const char ** key, UErrorCode& status) { 1.319 + int32_t len = 0; 1.320 + const UChar* r = ures_getNextString(fResource, &len, key, &status); 1.321 + return UnicodeString(TRUE, r, len); 1.322 +} 1.323 + 1.324 +ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const { 1.325 + UResourceBundle r; 1.326 + 1.327 + ures_initStackObject(&r); 1.328 + ures_getByIndex(fResource, indexR, &r, &status); 1.329 + ResourceBundle res(&r, status); 1.330 + if (U_SUCCESS(status)) { 1.331 + ures_close(&r); 1.332 + } 1.333 + return res; 1.334 +} 1.335 + 1.336 +UnicodeString ResourceBundle::getStringEx(int32_t indexS, UErrorCode& status) const { 1.337 + int32_t len = 0; 1.338 + const UChar* r = ures_getStringByIndex(fResource, indexS, &len, &status); 1.339 + return UnicodeString(TRUE, r, len); 1.340 +} 1.341 + 1.342 +ResourceBundle ResourceBundle::get(const char* key, UErrorCode& status) const { 1.343 + UResourceBundle r; 1.344 + 1.345 + ures_initStackObject(&r); 1.346 + ures_getByKey(fResource, key, &r, &status); 1.347 + ResourceBundle res(&r, status); 1.348 + if (U_SUCCESS(status)) { 1.349 + ures_close(&r); 1.350 + } 1.351 + return res; 1.352 +} 1.353 + 1.354 +ResourceBundle ResourceBundle::getWithFallback(const char* key, UErrorCode& status){ 1.355 + UResourceBundle r; 1.356 + ures_initStackObject(&r); 1.357 + ures_getByKeyWithFallback(fResource, key, &r, &status); 1.358 + ResourceBundle res(&r, status); 1.359 + if(U_SUCCESS(status)){ 1.360 + ures_close(&r); 1.361 + } 1.362 + return res; 1.363 +} 1.364 +UnicodeString ResourceBundle::getStringEx(const char* key, UErrorCode& status) const { 1.365 + int32_t len = 0; 1.366 + const UChar* r = ures_getStringByKey(fResource, key, &len, &status); 1.367 + return UnicodeString(TRUE, r, len); 1.368 +} 1.369 + 1.370 +const char* 1.371 +ResourceBundle::getVersionNumber() const 1.372 +{ 1.373 + return ures_getVersionNumberInternal(fResource); 1.374 +} 1.375 + 1.376 +void ResourceBundle::getVersion(UVersionInfo versionInfo) const { 1.377 + ures_getVersion(fResource, versionInfo); 1.378 +} 1.379 + 1.380 +static UMutex gLocaleLock = U_MUTEX_INITIALIZER; 1.381 +const Locale &ResourceBundle::getLocale(void) const { 1.382 + Mutex lock(&gLocaleLock); 1.383 + if (fLocale != NULL) { 1.384 + return *fLocale; 1.385 + } 1.386 + UErrorCode status = U_ZERO_ERROR; 1.387 + const char *localeName = ures_getLocaleInternal(fResource, &status); 1.388 + ResourceBundle *ncThis = const_cast<ResourceBundle *>(this); 1.389 + ncThis->fLocale = new Locale(localeName); 1.390 + return ncThis->fLocale != NULL ? *ncThis->fLocale : Locale::getDefault(); 1.391 +} 1.392 + 1.393 +const Locale ResourceBundle::getLocale(ULocDataLocaleType type, UErrorCode &status) const 1.394 +{ 1.395 + return ures_getLocaleByType(fResource, type, &status); 1.396 +} 1.397 + 1.398 +U_NAMESPACE_END 1.399 +//eof