~ubuntu-branches/ubuntu/quantal/icu/quantal

« back to all changes in this revision

Viewing changes to source/common/resbund.cpp

  • Committer: Package Import Robot
  • Author(s): Yves Arrouye
  • Date: 2002-03-03 15:31:13 UTC
  • Revision ID: package-import@ubuntu.com-20020303153113-3ssceqlq45xbmbnc
Tags: upstream-2.0-2.1pre20020303
ImportĀ upstreamĀ versionĀ 2.0-2.1pre20020303

Show diffs side-by-side

added added

removed removed

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