tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

resbund.cpp (15242B)


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