annotate modules/javafx.web/src/main/native/Source/ThirdParty/icu/source/common/resbund.cpp @ 10550:fee4ef5c87df

8178360: Build and integrate ICU from source Reviewed-by: kcr, arajkumar
author ghb
date Tue, 04 Jul 2017 09:09:49 +0530
parents
children 20a8447c71c6
rev   line source
ghb@10550 1 /*
ghb@10550 2 **********************************************************************
ghb@10550 3 * Copyright (C) 1997-2011, International Business Machines
ghb@10550 4 * Corporation and others. All Rights Reserved.
ghb@10550 5 **********************************************************************
ghb@10550 6 *
ghb@10550 7 * File resbund.cpp
ghb@10550 8 *
ghb@10550 9 * Modification History:
ghb@10550 10 *
ghb@10550 11 * Date Name Description
ghb@10550 12 * 02/05/97 aliu Fixed bug in chopLocale. Added scanForLocaleInFile
ghb@10550 13 * based on code taken from scanForLocale. Added
ghb@10550 14 * constructor which attempts to read resource bundle
ghb@10550 15 * from a specific file, without searching other files.
ghb@10550 16 * 02/11/97 aliu Added UErrorCode return values to constructors. Fixed
ghb@10550 17 * infinite loops in scanForFile and scanForLocale.
ghb@10550 18 * Modified getRawResourceData to not delete storage in
ghb@10550 19 * localeData and resourceData which it doesn't own.
ghb@10550 20 * Added Mac compatibility #ifdefs for tellp() and
ghb@10550 21 * ios::nocreate.
ghb@10550 22 * 03/04/97 aliu Modified to use ExpandingDataSink objects instead of
ghb@10550 23 * the highly inefficient ostrstream objects.
ghb@10550 24 * 03/13/97 aliu Rewrote to load in entire resource bundle and store
ghb@10550 25 * it as a Hashtable of ResourceBundleData objects.
ghb@10550 26 * Added state table to govern parsing of files.
ghb@10550 27 * Modified to load locale index out of new file distinct
ghb@10550 28 * from default.txt.
ghb@10550 29 * 03/25/97 aliu Modified to support 2-d arrays, needed for timezone data.
ghb@10550 30 * Added support for custom file suffixes. Again, needed
ghb@10550 31 * to support timezone data. Improved error handling to
ghb@10550 32 * detect duplicate tags and subtags.
ghb@10550 33 * 04/07/97 aliu Fixed bug in getHashtableForLocale(). Fixed handling
ghb@10550 34 * of failing UErrorCode values on entry to API methods.
ghb@10550 35 * Fixed bugs in getArrayItem() for negative indices.
ghb@10550 36 * 04/29/97 aliu Update to use new Hashtable deletion protocol.
ghb@10550 37 * 05/06/97 aliu Flattened kTransitionTable for HP compiler.
ghb@10550 38 * Fixed usage of CharString.
ghb@10550 39 * 06/11/99 stephen Removed parsing of .txt files.
ghb@10550 40 * Reworked to use new binary format.
ghb@10550 41 * Cleaned up.
ghb@10550 42 * 06/14/99 stephen Removed methods taking a filename suffix.
ghb@10550 43 * 06/22/99 stephen Added missing T_FileStream_close in parse()
ghb@10550 44 * 11/09/99 weiv Added getLocale(), rewritten constructForLocale()
ghb@10550 45 * March 2000 weiv complete overhaul.
ghb@10550 46 ******************************************************************************
ghb@10550 47 */
ghb@10550 48
ghb@10550 49 #include "unicode/utypes.h"
ghb@10550 50 #include "unicode/resbund.h"
ghb@10550 51 #include "umutex.h"
ghb@10550 52
ghb@10550 53 #include "uresimp.h"
ghb@10550 54
ghb@10550 55 U_NAMESPACE_BEGIN
ghb@10550 56
ghb@10550 57 /*-----------------------------------------------------------------------------
ghb@10550 58 * Implementation Notes
ghb@10550 59 *
ghb@10550 60 * Resource bundles are read in once, and thereafter cached.
ghb@10550 61 * ResourceBundle statically keeps track of which files have been
ghb@10550 62 * read, so we are guaranteed that each file is read at most once.
ghb@10550 63 * Resource bundles can be loaded from different data directories and
ghb@10550 64 * will be treated as distinct, even if they are for the same locale.
ghb@10550 65 *
ghb@10550 66 * Resource bundles are lightweight objects, which have pointers to
ghb@10550 67 * one or more shared Hashtable objects containing all the data.
ghb@10550 68 * Copying would be cheap, but there is no copy constructor, since
ghb@10550 69 * there wasn't one in the original API.
ghb@10550 70 *
ghb@10550 71 * The ResourceBundle parsing mechanism is implemented as a transition
ghb@10550 72 * network, for easy maintenance and modification. The network is
ghb@10550 73 * implemented as a matrix (instead of in code) to make this even
ghb@10550 74 * easier. The matrix contains Transition objects. Each Transition
ghb@10550 75 * object describes a destination node and an action to take before
ghb@10550 76 * moving to the destination node. The source node is encoded by the
ghb@10550 77 * index of the object in the array that contains it. The pieces
ghb@10550 78 * needed to understand the transition network are the enums for node
ghb@10550 79 * IDs and actions, the parse() method, which walks through the
ghb@10550 80 * network and implements the actions, and the network itself. The
ghb@10550 81 * network guarantees certain conditions, for example, that a new
ghb@10550 82 * resource will not be closed until one has been opened first; or
ghb@10550 83 * that data will not be stored into a TaggedList until a TaggedList
ghb@10550 84 * has been created. Nonetheless, the code in parse() does some
ghb@10550 85 * consistency checks as it runs the network, and fails with an
ghb@10550 86 * U_INTERNAL_PROGRAM_ERROR if one of these checks fails. If the input
ghb@10550 87 * data has a bad format, an U_INVALID_FORMAT_ERROR is returned. If you
ghb@10550 88 * see an U_INTERNAL_PROGRAM_ERROR the transition matrix has a bug in
ghb@10550 89 * it.
ghb@10550 90 *
ghb@10550 91 * Old functionality of multiple locales in a single file is still
ghb@10550 92 * supported. For this reason, LOCALE names override FILE names. If
ghb@10550 93 * data for en_US is located in the en.txt file, once it is loaded,
ghb@10550 94 * the code will not care where it came from (other than remembering
ghb@10550 95 * which directory it came from). However, if there is an en_US
ghb@10550 96 * resource in en_US.txt, that will take precedence. There is no
ghb@10550 97 * limit to the number or type of resources that can be stored in a
ghb@10550 98 * file, however, files are only searched in a specific way. If
ghb@10550 99 * en_US_CA is requested, then first en_US_CA.txt is searched, then
ghb@10550 100 * en_US.txt, then en.txt, then default.txt. So it only makes sense
ghb@10550 101 * to put certain locales in certain files. In this example, it would
ghb@10550 102 * be logical to put en_US_CA, en_US, and en into the en.txt file,
ghb@10550 103 * since they would be found there if asked for. The extreme example
ghb@10550 104 * is to place all locale resources into default.txt, which should
ghb@10550 105 * also work.
ghb@10550 106 *
ghb@10550 107 * Inheritance is implemented. For example, xx_YY_zz inherits as
ghb@10550 108 * follows: xx_YY_zz, xx_YY, xx, default. Inheritance is implemented
ghb@10550 109 * as an array of hashtables. There will be from 1 to 4 hashtables in
ghb@10550 110 * the array.
ghb@10550 111 *
ghb@10550 112 * Fallback files are implemented. The fallback pattern is Language
ghb@10550 113 * Country Variant (LCV) -> LC -> L. Fallback is first done for the
ghb@10550 114 * requested locale. Then it is done for the default locale, as
ghb@10550 115 * returned by Locale::getDefault(). Then the special file
ghb@10550 116 * default.txt is searched for the default locale. The overall FILE
ghb@10550 117 * fallback path is LCV -> LC -> L -> dLCV -> dLC -> dL -> default.
ghb@10550 118 *
ghb@10550 119 * Note that although file name searching includes the default locale,
ghb@10550 120 * once a ResourceBundle object is constructed, the inheritance path
ghb@10550 121 * no longer includes the default locale. The path is LCV -> LC -> L
ghb@10550 122 * -> default.
ghb@10550 123 *
ghb@10550 124 * File parsing is lazy. Nothing is parsed unless it is called for by
ghb@10550 125 * someone. So when a ResourceBundle for xx_YY_zz is constructed,
ghb@10550 126 * only that locale is parsed (along with anything else in the same
ghb@10550 127 * file). Later, if the FooBar tag is asked for, and if it isn't
ghb@10550 128 * found in xx_YY_zz, then xx_YY.txt will be parsed and checked, and
ghb@10550 129 * so forth, until the chain is exhausted or the tag is found.
ghb@10550 130 *
ghb@10550 131 * Thread-safety is implemented around caches, both the cache that
ghb@10550 132 * stores all the resouce data, and the cache that stores flags
ghb@10550 133 * indicating whether or not a file has been visited. These caches
ghb@10550 134 * delete their storage at static cleanup time, when the process
ghb@10550 135 * quits.
ghb@10550 136 *
ghb@10550 137 * ResourceBundle supports TableCollation as a special case. This
ghb@10550 138 * involves having special ResourceBundle objects which DO own their
ghb@10550 139 * data, since we don't want large collation rule strings in the
ghb@10550 140 * ResourceBundle cache (these are already cached in the
ghb@10550 141 * TableCollation cache). TableCollation files (.ctx files) have the
ghb@10550 142 * same format as normal resource data files, with a different
ghb@10550 143 * interpretation, from the standpoint of ResourceBundle. .ctx files
ghb@10550 144 * are loaded into otherwise ordinary ResourceBundle objects. They
ghb@10550 145 * don't inherit (that's implemented by TableCollation) and they own
ghb@10550 146 * their data (as mentioned above). However, they still support
ghb@10550 147 * possible multiple locales in a single .ctx file. (This is in
ghb@10550 148 * practice a bad idea, since you only want the one locale you're
ghb@10550 149 * looking for, and only one tag will be present
ghb@10550 150 * ("CollationElements"), so you don't need an inheritance chain of
ghb@10550 151 * multiple locales.) Up to 4 locale resources will be loaded from a
ghb@10550 152 * .ctx file; everything after the first 4 is ignored (parsed and
ghb@10550 153 * deleted). (Normal .txt files have no limit.) Instead of being
ghb@10550 154 * loaded into the cache, and then looked up as needed, the locale
ghb@10550 155 * resources are read straight into the ResourceBundle object.
ghb@10550 156 *
ghb@10550 157 * The Index, which used to reside in default.txt, has been moved to a
ghb@10550 158 * new file, index.txt. This file contains a slightly modified format
ghb@10550 159 * with the addition of the "InstalledLocales" tag; it looks like:
ghb@10550 160 *
ghb@10550 161 * Index {
ghb@10550 162 * InstalledLocales {
ghb@10550 163 * ar
ghb@10550 164 * ..
ghb@10550 165 * zh_TW
ghb@10550 166 * }
ghb@10550 167 * }
ghb@10550 168 */
ghb@10550 169 //-----------------------------------------------------------------------------
ghb@10550 170
ghb@10550 171 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ResourceBundle)
ghb@10550 172
ghb@10550 173 ResourceBundle::ResourceBundle(UErrorCode &err)
ghb@10550 174 :UObject(), fLocale(NULL)
ghb@10550 175 {
ghb@10550 176 fResource = ures_open(0, Locale::getDefault().getName(), &err);
ghb@10550 177 }
ghb@10550 178
ghb@10550 179 ResourceBundle::ResourceBundle(const ResourceBundle &other)
ghb@10550 180 :UObject(other), fLocale(NULL)
ghb@10550 181 {
ghb@10550 182 UErrorCode status = U_ZERO_ERROR;
ghb@10550 183
ghb@10550 184 if (other.fResource) {
ghb@10550 185 fResource = ures_copyResb(0, other.fResource, &status);
ghb@10550 186 } else {
ghb@10550 187 /* Copying a bad resource bundle */
ghb@10550 188 fResource = NULL;
ghb@10550 189 }
ghb@10550 190 }
ghb@10550 191
ghb@10550 192 ResourceBundle::ResourceBundle(UResourceBundle *res, UErrorCode& err)
ghb@10550 193 :UObject(), fLocale(NULL)
ghb@10550 194 {
ghb@10550 195 if (res) {
ghb@10550 196 fResource = ures_copyResb(0, res, &err);
ghb@10550 197 } else {
ghb@10550 198 /* Copying a bad resource bundle */
ghb@10550 199 fResource = NULL;
ghb@10550 200 }
ghb@10550 201 }
ghb@10550 202
ghb@10550 203 ResourceBundle::ResourceBundle(const char* path, const Locale& locale, UErrorCode& err)
ghb@10550 204 :UObject(), fLocale(NULL)
ghb@10550 205 {
ghb@10550 206 fResource = ures_open(path, locale.getName(), &err);
ghb@10550 207 }
ghb@10550 208
ghb@10550 209
ghb@10550 210 ResourceBundle& ResourceBundle::operator=(const ResourceBundle& other)
ghb@10550 211 {
ghb@10550 212 if(this == &other) {
ghb@10550 213 return *this;
ghb@10550 214 }
ghb@10550 215 if(fResource != 0) {
ghb@10550 216 ures_close(fResource);
ghb@10550 217 fResource = NULL;
ghb@10550 218 }
ghb@10550 219 UErrorCode status = U_ZERO_ERROR;
ghb@10550 220 if (other.fResource) {
ghb@10550 221 fResource = ures_copyResb(0, other.fResource, &status);
ghb@10550 222 } else {
ghb@10550 223 /* Copying a bad resource bundle */
ghb@10550 224 fResource = NULL;
ghb@10550 225 }
ghb@10550 226 return *this;
ghb@10550 227 }
ghb@10550 228
ghb@10550 229 ResourceBundle::~ResourceBundle()
ghb@10550 230 {
ghb@10550 231 if(fResource != 0) {
ghb@10550 232 ures_close(fResource);
ghb@10550 233 }
ghb@10550 234 if(fLocale != NULL) {
ghb@10550 235 delete(fLocale);
ghb@10550 236 }
ghb@10550 237 }
ghb@10550 238
ghb@10550 239 ResourceBundle *
ghb@10550 240 ResourceBundle::clone() const {
ghb@10550 241 return new ResourceBundle(*this);
ghb@10550 242 }
ghb@10550 243
ghb@10550 244 UnicodeString ResourceBundle::getString(UErrorCode& status) const {
ghb@10550 245 int32_t len = 0;
ghb@10550 246 const UChar *r = ures_getString(fResource, &len, &status);
ghb@10550 247 return UnicodeString(TRUE, r, len);
ghb@10550 248 }
ghb@10550 249
ghb@10550 250 const uint8_t *ResourceBundle::getBinary(int32_t& len, UErrorCode& status) const {
ghb@10550 251 return ures_getBinary(fResource, &len, &status);
ghb@10550 252 }
ghb@10550 253
ghb@10550 254 const int32_t *ResourceBundle::getIntVector(int32_t& len, UErrorCode& status) const {
ghb@10550 255 return ures_getIntVector(fResource, &len, &status);
ghb@10550 256 }
ghb@10550 257
ghb@10550 258 uint32_t ResourceBundle::getUInt(UErrorCode& status) const {
ghb@10550 259 return ures_getUInt(fResource, &status);
ghb@10550 260 }
ghb@10550 261
ghb@10550 262 int32_t ResourceBundle::getInt(UErrorCode& status) const {
ghb@10550 263 return ures_getInt(fResource, &status);
ghb@10550 264 }
ghb@10550 265
ghb@10550 266 const char *ResourceBundle::getName(void) const {
ghb@10550 267 return ures_getName(fResource);
ghb@10550 268 }
ghb@10550 269
ghb@10550 270 const char *ResourceBundle::getKey(void) const {
ghb@10550 271 return ures_getKey(fResource);
ghb@10550 272 }
ghb@10550 273
ghb@10550 274 UResType ResourceBundle::getType(void) const {
ghb@10550 275 return ures_getType(fResource);
ghb@10550 276 }
ghb@10550 277
ghb@10550 278 int32_t ResourceBundle::getSize(void) const {
ghb@10550 279 return ures_getSize(fResource);
ghb@10550 280 }
ghb@10550 281
ghb@10550 282 UBool ResourceBundle::hasNext(void) const {
ghb@10550 283 return ures_hasNext(fResource);
ghb@10550 284 }
ghb@10550 285
ghb@10550 286 void ResourceBundle::resetIterator(void) {
ghb@10550 287 ures_resetIterator(fResource);
ghb@10550 288 }
ghb@10550 289
ghb@10550 290 ResourceBundle ResourceBundle::getNext(UErrorCode& status) {
ghb@10550 291 UResourceBundle r;
ghb@10550 292
ghb@10550 293 ures_initStackObject(&r);
ghb@10550 294 ures_getNextResource(fResource, &r, &status);
ghb@10550 295 ResourceBundle res(&r, status);
ghb@10550 296 if (U_SUCCESS(status)) {
ghb@10550 297 ures_close(&r);
ghb@10550 298 }
ghb@10550 299 return res;
ghb@10550 300 }
ghb@10550 301
ghb@10550 302 UnicodeString ResourceBundle::getNextString(UErrorCode& status) {
ghb@10550 303 int32_t len = 0;
ghb@10550 304 const UChar* r = ures_getNextString(fResource, &len, 0, &status);
ghb@10550 305 return UnicodeString(TRUE, r, len);
ghb@10550 306 }
ghb@10550 307
ghb@10550 308 UnicodeString ResourceBundle::getNextString(const char ** key, UErrorCode& status) {
ghb@10550 309 int32_t len = 0;
ghb@10550 310 const UChar* r = ures_getNextString(fResource, &len, key, &status);
ghb@10550 311 return UnicodeString(TRUE, r, len);
ghb@10550 312 }
ghb@10550 313
ghb@10550 314 ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const {
ghb@10550 315 UResourceBundle r;
ghb@10550 316
ghb@10550 317 ures_initStackObject(&r);
ghb@10550 318 ures_getByIndex(fResource, indexR, &r, &status);
ghb@10550 319 ResourceBundle res(&r, status);
ghb@10550 320 if (U_SUCCESS(status)) {
ghb@10550 321 ures_close(&r);
ghb@10550 322 }
ghb@10550 323 return res;
ghb@10550 324 }
ghb@10550 325
ghb@10550 326 UnicodeString ResourceBundle::getStringEx(int32_t indexS, UErrorCode& status) const {
ghb@10550 327 int32_t len = 0;
ghb@10550 328 const UChar* r = ures_getStringByIndex(fResource, indexS, &len, &status);
ghb@10550 329 return UnicodeString(TRUE, r, len);
ghb@10550 330 }
ghb@10550 331
ghb@10550 332 ResourceBundle ResourceBundle::get(const char* key, UErrorCode& status) const {
ghb@10550 333 UResourceBundle r;
ghb@10550 334
ghb@10550 335 ures_initStackObject(&r);
ghb@10550 336 ures_getByKey(fResource, key, &r, &status);
ghb@10550 337 ResourceBundle res(&r, status);
ghb@10550 338 if (U_SUCCESS(status)) {
ghb@10550 339 ures_close(&r);
ghb@10550 340 }
ghb@10550 341 return res;
ghb@10550 342 }
ghb@10550 343
ghb@10550 344 ResourceBundle ResourceBundle::getWithFallback(const char* key, UErrorCode& status){
ghb@10550 345 UResourceBundle r;
ghb@10550 346 ures_initStackObject(&r);
ghb@10550 347 ures_getByKeyWithFallback(fResource, key, &r, &status);
ghb@10550 348 ResourceBundle res(&r, status);
ghb@10550 349 if(U_SUCCESS(status)){
ghb@10550 350 ures_close(&r);
ghb@10550 351 }
ghb@10550 352 return res;
ghb@10550 353 }
ghb@10550 354 UnicodeString ResourceBundle::getStringEx(const char* key, UErrorCode& status) const {
ghb@10550 355 int32_t len = 0;
ghb@10550 356 const UChar* r = ures_getStringByKey(fResource, key, &len, &status);
ghb@10550 357 return UnicodeString(TRUE, r, len);
ghb@10550 358 }
ghb@10550 359
ghb@10550 360 const char*
ghb@10550 361 ResourceBundle::getVersionNumber() const
ghb@10550 362 {
ghb@10550 363 return ures_getVersionNumberInternal(fResource);
ghb@10550 364 }
ghb@10550 365
ghb@10550 366 void ResourceBundle::getVersion(UVersionInfo versionInfo) const {
ghb@10550 367 ures_getVersion(fResource, versionInfo);
ghb@10550 368 }
ghb@10550 369
ghb@10550 370 const Locale &ResourceBundle::getLocale(void) const
ghb@10550 371 {
ghb@10550 372 UBool needInit;
ghb@10550 373 UMTX_CHECK(NULL, (fLocale == NULL), needInit);
ghb@10550 374 if(needInit) {
ghb@10550 375 UErrorCode status = U_ZERO_ERROR;
ghb@10550 376 const char *localeName = ures_getLocaleInternal(fResource, &status);
ghb@10550 377 Locale *tLocale = new Locale(localeName);
ghb@10550 378 // Null pointer check
ghb@10550 379 if (tLocale == NULL) {
ghb@10550 380 return Locale::getDefault(); // Return default locale if one could not be created.
ghb@10550 381 }
ghb@10550 382 umtx_lock(NULL);
ghb@10550 383 ResourceBundle *me = (ResourceBundle *)this; // semantically const
ghb@10550 384 if (me->fLocale == NULL) {
ghb@10550 385 me->fLocale = tLocale;
ghb@10550 386 tLocale = NULL;
ghb@10550 387 }
ghb@10550 388 umtx_unlock(NULL);
ghb@10550 389 delete tLocale;
ghb@10550 390 }
ghb@10550 391 return *fLocale;
ghb@10550 392 }
ghb@10550 393
ghb@10550 394 const Locale ResourceBundle::getLocale(ULocDataLocaleType type, UErrorCode &status) const
ghb@10550 395 {
ghb@10550 396 return ures_getLocaleByType(fResource, type, &status);
ghb@10550 397 }
ghb@10550 398
ghb@10550 399 //eof
ghb@10550 400 U_NAMESPACE_END