LCOV - code coverage report
Current view: top level - intl/icu/source/common - resbund.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 129 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13