1/*
2*******************************************************************************
3* Copyright (C) 1997-2011, International Business Machines Corporation and    *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*
7* File DTFMTSYM.CPP
8*
9* Modification History:
10*
11*   Date        Name        Description
12*   02/19/97    aliu        Converted from java.
13*   07/21/98    stephen     Added getZoneIndex
14*                            Changed weekdays/short weekdays to be one-based
15*   06/14/99    stephen     Removed SimpleDateFormat::fgTimeZoneDataSuffix
16*   11/16/99    weiv        Added 'Y' and 'e' to fgPatternChars
17*   03/27/00    weiv        Keeping resource bundle around!
18*   06/30/05    emmons      Added eraNames, narrow month/day, standalone context
19*   10/12/05    emmons      Added setters for eraNames, month/day by width/context
20*******************************************************************************
21*/
22#include "unicode/utypes.h"
23
24#if !UCONFIG_NO_FORMATTING
25#include "unicode/ustring.h"
26#include "unicode/dtfmtsym.h"
27#include "unicode/smpdtfmt.h"
28#include "unicode/msgfmt.h"
29#include "cpputils.h"
30#include "ucln_in.h"
31#include "umutex.h"
32#include "cmemory.h"
33#include "cstring.h"
34#include "locbased.h"
35#include "gregoimp.h"
36#include "hash.h"
37#include "uresimp.h"
38#include "ureslocs.h"
39#include "tznames.h"
40
41// *****************************************************************************
42// class DateFormatSymbols
43// *****************************************************************************
44
45/**
46 * These are static arrays we use only in the case where we have no
47 * resource data.
48 */
49
50#define PATTERN_CHARS_LEN 30
51
52/**
53 * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
54 * locales use the same these unlocalized pattern characters.
55 */
56static const UChar gPatternChars[] = {
57    // GyMdkHmsSEDFwWahKzYeugAZvcLQqV
58    0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
59    0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
60    0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56, 0
61};
62
63/* length of an array */
64#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
65
66//------------------------------------------------------
67// Strings of last resort.  These are only used if we have no resource
68// files.  They aren't designed for actual use, just for backup.
69
70// These are the month names and abbreviations of last resort.
71static const UChar gLastResortMonthNames[13][3] =
72{
73    {0x0030, 0x0031, 0x0000}, /* "01" */
74    {0x0030, 0x0032, 0x0000}, /* "02" */
75    {0x0030, 0x0033, 0x0000}, /* "03" */
76    {0x0030, 0x0034, 0x0000}, /* "04" */
77    {0x0030, 0x0035, 0x0000}, /* "05" */
78    {0x0030, 0x0036, 0x0000}, /* "06" */
79    {0x0030, 0x0037, 0x0000}, /* "07" */
80    {0x0030, 0x0038, 0x0000}, /* "08" */
81    {0x0030, 0x0039, 0x0000}, /* "09" */
82    {0x0031, 0x0030, 0x0000}, /* "10" */
83    {0x0031, 0x0031, 0x0000}, /* "11" */
84    {0x0031, 0x0032, 0x0000}, /* "12" */
85    {0x0031, 0x0033, 0x0000}  /* "13" */
86};
87
88// These are the weekday names and abbreviations of last resort.
89static const UChar gLastResortDayNames[8][2] =
90{
91    {0x0030, 0x0000}, /* "0" */
92    {0x0031, 0x0000}, /* "1" */
93    {0x0032, 0x0000}, /* "2" */
94    {0x0033, 0x0000}, /* "3" */
95    {0x0034, 0x0000}, /* "4" */
96    {0x0035, 0x0000}, /* "5" */
97    {0x0036, 0x0000}, /* "6" */
98    {0x0037, 0x0000}  /* "7" */
99};
100
101// These are the quarter names and abbreviations of last resort.
102static const UChar gLastResortQuarters[4][2] =
103{
104    {0x0031, 0x0000}, /* "1" */
105    {0x0032, 0x0000}, /* "2" */
106    {0x0033, 0x0000}, /* "3" */
107    {0x0034, 0x0000}, /* "4" */
108};
109
110// These are the am/pm and BC/AD markers of last resort.
111static const UChar gLastResortAmPmMarkers[2][3] =
112{
113    {0x0041, 0x004D, 0x0000}, /* "AM" */
114    {0x0050, 0x004D, 0x0000}  /* "PM" */
115};
116
117static const UChar gLastResortEras[2][3] =
118{
119    {0x0042, 0x0043, 0x0000}, /* "BC" */
120    {0x0041, 0x0044, 0x0000}  /* "AD" */
121};
122
123// Not used now
124//// These are the zone strings of last resort.
125//static const UChar gLastResortZoneStrings[5][4] =
126//{
127//    {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
128//    {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
129//    {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
130//    {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
131//    {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
132//};
133
134static const UChar gLastResortGmtZero[] =
135    {0x0047, 0x004D, 0x0054, 0x0000}; /* GMT */
136
137static const UChar gLastResortGmtFormat[] =
138    {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
139
140static const UChar gLastResortGmtHourFormats[4][10] =
141{
142    {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* -HH:mm:ss */
143    {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000}, /* -HH:mm */
144    {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* +HH:mm:ss */
145    {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000}  /* +HH:mm */
146};
147
148/* Sizes for the last resort string arrays */
149typedef enum LastResortSize {
150    kMonthNum = 13,
151    kMonthLen = 3,
152
153    kDayNum = 8,
154    kDayLen = 2,
155
156    kAmPmNum = 2,
157    kAmPmLen = 3,
158
159    kQuarterNum = 4,
160    kQuarterLen = 2,
161
162    kEraNum = 2,
163    kEraLen = 3,
164
165    kZoneNum = 5,
166    kZoneLen = 4,
167
168    kGmtHourNum = 4,
169    kGmtHourLen = 10
170} LastResortSize;
171
172U_NAMESPACE_BEGIN
173
174UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)
175
176#define kSUPPLEMENTAL "supplementalData"
177
178/**
179 * These are the tags we expect to see in normal resource bundle files associated
180 * with a locale and calendar
181 */
182static const char gErasTag[]="eras";
183static const char gMonthNamesTag[]="monthNames";
184static const char gDayNamesTag[]="dayNames";
185static const char gNamesWideTag[]="wide";
186static const char gNamesAbbrTag[]="abbreviated";
187static const char gNamesNarrowTag[]="narrow";
188static const char gNamesStandaloneTag[]="stand-alone";
189static const char gAmPmMarkersTag[]="AmPmMarkers";
190static const char gQuartersTag[]="quarters";
191
192static const char gZoneStringsTag[]="zoneStrings";
193static const char gGmtZeroFormatTag[] = "gmtZeroFormat";
194static const char gGmtFormatTag[]="gmtFormat";
195static const char gHourFormatTag[]="hourFormat";
196
197static const char gLocalPatternCharsTag[]="localPatternChars";
198
199static UMTX LOCK;
200
201/**
202 * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly.
203 * Work around this.
204 */
205static inline UnicodeString* newUnicodeStringArray(size_t count) {
206    return new UnicodeString[count ? count : 1];
207}
208
209//------------------------------------------------------
210
211DateFormatSymbols::DateFormatSymbols(const Locale& locale,
212                                     UErrorCode& status)
213    : UObject()
214{
215  initializeData(locale, NULL,  status);
216}
217
218DateFormatSymbols::DateFormatSymbols(UErrorCode& status)
219    : UObject()
220{
221  initializeData(Locale::getDefault(), NULL, status, TRUE);
222}
223
224
225DateFormatSymbols::DateFormatSymbols(const Locale& locale,
226                                     const char *type,
227                                     UErrorCode& status)
228    : UObject()
229{
230  initializeData(locale, type,  status);
231}
232
233DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status)
234    : UObject()
235{
236  initializeData(Locale::getDefault(), type, status, TRUE);
237}
238
239DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other)
240    : UObject(other)
241{
242    copyData(other);
243}
244
245void
246DateFormatSymbols::assignArray(UnicodeString*& dstArray,
247                               int32_t& dstCount,
248                               const UnicodeString* srcArray,
249                               int32_t srcCount)
250{
251    // assignArray() is only called by copyData(), which in turn implements the
252    // copy constructor and the assignment operator.
253    // All strings in a DateFormatSymbols object are created in one of the following
254    // three ways that all allow to safely use UnicodeString::fastCopyFrom():
255    // - readonly-aliases from resource bundles
256    // - readonly-aliases or allocated strings from constants
257    // - safely cloned strings (with owned buffers) from setXYZ() functions
258    //
259    // Note that this is true for as long as DateFormatSymbols can be constructed
260    // only from a locale bundle or set via the cloning API,
261    // *and* for as long as all the strings are in *private* fields, preventing
262    // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()).
263    dstCount = srcCount;
264    dstArray = newUnicodeStringArray(srcCount);
265    if(dstArray != NULL) {
266        int32_t i;
267        for(i=0; i<srcCount; ++i) {
268            dstArray[i].fastCopyFrom(srcArray[i]);
269        }
270    }
271}
272
273/**
274 * Create a copy, in fZoneStrings, of the given zone strings array.  The
275 * member variables fZoneStringsRowCount and fZoneStringsColCount should
276 * be set already by the caller.
277 */
278void
279DateFormatSymbols::createZoneStrings(const UnicodeString *const * otherStrings)
280{
281    int32_t row, col;
282    UBool failed = FALSE;
283
284    fZoneStrings = (UnicodeString **)uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString *));
285    if (fZoneStrings != NULL) {
286        for (row=0; row<fZoneStringsRowCount; ++row)
287        {
288            fZoneStrings[row] = newUnicodeStringArray(fZoneStringsColCount);
289            if (fZoneStrings[row] == NULL) {
290                failed = TRUE;
291                break;
292            }
293            for (col=0; col<fZoneStringsColCount; ++col) {
294                // fastCopyFrom() - see assignArray comments
295                fZoneStrings[row][col].fastCopyFrom(otherStrings[row][col]);
296            }
297        }
298    }
299    // If memory allocation failed, roll back and delete fZoneStrings
300    if (failed) {
301        for (int i = row; i >= 0; i--) {
302            delete[] fZoneStrings[i];
303        }
304        uprv_free(fZoneStrings);
305        fZoneStrings = NULL;
306    }
307}
308
309/**
310 * Copy all of the other's data to this.
311 */
312void
313DateFormatSymbols::copyData(const DateFormatSymbols& other) {
314    assignArray(fEras, fErasCount, other.fEras, other.fErasCount);
315    assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount);
316    assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount);
317    assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount);
318    assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount);
319    assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount);
320    assignArray(fStandaloneMonths, fStandaloneMonthsCount, other.fStandaloneMonths, other.fStandaloneMonthsCount);
321    assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, other.fStandaloneShortMonths, other.fStandaloneShortMonthsCount);
322    assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, other.fStandaloneNarrowMonths, other.fStandaloneNarrowMonthsCount);
323    assignArray(fWeekdays, fWeekdaysCount, other.fWeekdays, other.fWeekdaysCount);
324    assignArray(fShortWeekdays, fShortWeekdaysCount, other.fShortWeekdays, other.fShortWeekdaysCount);
325    assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount);
326    assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, other.fStandaloneWeekdays, other.fStandaloneWeekdaysCount);
327    assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, other.fStandaloneShortWeekdays, other.fStandaloneShortWeekdaysCount);
328    assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount);
329    assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount);
330    assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount);
331    assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
332    assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
333    assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
334    fGmtZero = other.fGmtZero;
335    fGmtFormat = other.fGmtFormat;
336    assignArray(fGmtHourFormats, fGmtHourFormatsCount, other.fGmtHourFormats, other.fGmtHourFormatsCount);
337
338    if (other.fZoneStrings != NULL) {
339        fZoneStringsColCount = other.fZoneStringsColCount;
340        fZoneStringsRowCount = other.fZoneStringsRowCount;
341        createZoneStrings((const UnicodeString**)other.fZoneStrings);
342
343    } else {
344        fZoneStrings = NULL;
345        fZoneStringsColCount = 0;
346        fZoneStringsRowCount = 0;
347    }
348    fZSFLocale = other.fZSFLocale;
349    // Other zone strings data is created on demand
350    fLocaleZoneStrings = NULL;
351
352    // fastCopyFrom() - see assignArray comments
353    fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
354}
355
356/**
357 * Assignment operator.
358 */
359DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
360{
361    dispose();
362    copyData(other);
363
364    return *this;
365}
366
367DateFormatSymbols::~DateFormatSymbols()
368{
369    dispose();
370}
371
372void DateFormatSymbols::dispose()
373{
374    if (fEras)                     delete[] fEras;
375    if (fEraNames)                 delete[] fEraNames;
376    if (fNarrowEras)               delete[] fNarrowEras;
377    if (fMonths)                   delete[] fMonths;
378    if (fShortMonths)              delete[] fShortMonths;
379    if (fNarrowMonths)             delete[] fNarrowMonths;
380    if (fStandaloneMonths)         delete[] fStandaloneMonths;
381    if (fStandaloneShortMonths)    delete[] fStandaloneShortMonths;
382    if (fStandaloneNarrowMonths)   delete[] fStandaloneNarrowMonths;
383    if (fWeekdays)                 delete[] fWeekdays;
384    if (fShortWeekdays)            delete[] fShortWeekdays;
385    if (fNarrowWeekdays)           delete[] fNarrowWeekdays;
386    if (fStandaloneWeekdays)       delete[] fStandaloneWeekdays;
387    if (fStandaloneShortWeekdays)  delete[] fStandaloneShortWeekdays;
388    if (fStandaloneNarrowWeekdays) delete[] fStandaloneNarrowWeekdays;
389    if (fAmPms)                    delete[] fAmPms;
390    if (fQuarters)                 delete[] fQuarters;
391    if (fShortQuarters)            delete[] fShortQuarters;
392    if (fStandaloneQuarters)       delete[] fStandaloneQuarters;
393    if (fStandaloneShortQuarters)  delete[] fStandaloneShortQuarters;
394    if (fGmtHourFormats)           delete[] fGmtHourFormats;
395
396    disposeZoneStrings();
397}
398
399void DateFormatSymbols::disposeZoneStrings()
400{
401    if (fZoneStrings) {
402        for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
403            delete[] fZoneStrings[row];
404        }
405        uprv_free(fZoneStrings);
406    }
407    if (fLocaleZoneStrings) {
408        for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
409            delete[] fLocaleZoneStrings[row];
410        }
411        uprv_free(fLocaleZoneStrings);
412    }
413
414    fZoneStrings = NULL;
415    fLocaleZoneStrings = NULL;
416    fZoneStringsRowCount = 0;
417    fZoneStringsColCount = 0;
418}
419
420UBool
421DateFormatSymbols::arrayCompare(const UnicodeString* array1,
422                                const UnicodeString* array2,
423                                int32_t count)
424{
425    if (array1 == array2) return TRUE;
426    while (count>0)
427    {
428        --count;
429        if (array1[count] != array2[count]) return FALSE;
430    }
431    return TRUE;
432}
433
434UBool
435DateFormatSymbols::operator==(const DateFormatSymbols& other) const
436{
437    // First do cheap comparisons
438    if (this == &other) {
439        return TRUE;
440    }
441    if (fErasCount == other.fErasCount &&
442        fEraNamesCount == other.fEraNamesCount &&
443        fNarrowErasCount == other.fNarrowErasCount &&
444        fMonthsCount == other.fMonthsCount &&
445        fShortMonthsCount == other.fShortMonthsCount &&
446        fNarrowMonthsCount == other.fNarrowMonthsCount &&
447        fStandaloneMonthsCount == other.fStandaloneMonthsCount &&
448        fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount &&
449        fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount &&
450        fWeekdaysCount == other.fWeekdaysCount &&
451        fShortWeekdaysCount == other.fShortWeekdaysCount &&
452        fNarrowWeekdaysCount == other.fNarrowWeekdaysCount &&
453        fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount &&
454        fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount &&
455        fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount &&
456        fAmPmsCount == other.fAmPmsCount &&
457        fQuartersCount == other.fQuartersCount &&
458        fShortQuartersCount == other.fShortQuartersCount &&
459        fStandaloneQuartersCount == other.fStandaloneQuartersCount &&
460        fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount &&
461        fGmtHourFormatsCount == other.fGmtHourFormatsCount &&
462        fGmtZero == other.fGmtZero &&
463        fGmtFormat == other.fGmtFormat)
464    {
465        // Now compare the arrays themselves
466        if (arrayCompare(fEras, other.fEras, fErasCount) &&
467            arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) &&
468            arrayCompare(fNarrowEras, other.fNarrowEras, fNarrowErasCount) &&
469            arrayCompare(fMonths, other.fMonths, fMonthsCount) &&
470            arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) &&
471            arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) &&
472            arrayCompare(fStandaloneMonths, other.fStandaloneMonths, fStandaloneMonthsCount) &&
473            arrayCompare(fStandaloneShortMonths, other.fStandaloneShortMonths, fStandaloneShortMonthsCount) &&
474            arrayCompare(fStandaloneNarrowMonths, other.fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount) &&
475            arrayCompare(fWeekdays, other.fWeekdays, fWeekdaysCount) &&
476            arrayCompare(fShortWeekdays, other.fShortWeekdays, fShortWeekdaysCount) &&
477            arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) &&
478            arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) &&
479            arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) &&
480            arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) &&
481            arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) &&
482            arrayCompare(fQuarters, other.fQuarters, fQuartersCount) &&
483            arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) &&
484            arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
485            arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) &&
486            arrayCompare(fGmtHourFormats, other.fGmtHourFormats, fGmtHourFormatsCount))
487        {
488            // Compare the contents of fZoneStrings
489            if (fZoneStrings == NULL && other.fZoneStrings == NULL) {
490                if (fZSFLocale == other.fZSFLocale) {
491                    return TRUE;
492                }
493            } else if (fZoneStrings != NULL && other.fZoneStrings != NULL) {
494                if (fZoneStringsRowCount == other.fZoneStringsRowCount
495                    && fZoneStringsColCount == other.fZoneStringsColCount) {
496                    UBool cmpres = TRUE;
497                    for (int32_t i = 0; (i < fZoneStringsRowCount) && cmpres; i++) {
498                        cmpres = arrayCompare(fZoneStrings[i], other.fZoneStrings[i], fZoneStringsColCount);
499                    }
500                    return cmpres;
501                }
502            }
503            return FALSE;
504        }
505    }
506    return FALSE;
507}
508
509//------------------------------------------------------
510
511const UnicodeString*
512DateFormatSymbols::getEras(int32_t &count) const
513{
514    count = fErasCount;
515    return fEras;
516}
517
518const UnicodeString*
519DateFormatSymbols::getEraNames(int32_t &count) const
520{
521    count = fEraNamesCount;
522    return fEraNames;
523}
524
525const UnicodeString*
526DateFormatSymbols::getNarrowEras(int32_t &count) const
527{
528    count = fNarrowErasCount;
529    return fNarrowEras;
530}
531
532const UnicodeString*
533DateFormatSymbols::getMonths(int32_t &count) const
534{
535    count = fMonthsCount;
536    return fMonths;
537}
538
539const UnicodeString*
540DateFormatSymbols::getShortMonths(int32_t &count) const
541{
542    count = fShortMonthsCount;
543    return fShortMonths;
544}
545
546const UnicodeString*
547DateFormatSymbols::getMonths(int32_t &count, DtContextType context, DtWidthType width ) const
548{
549    UnicodeString *returnValue = NULL;
550
551    switch (context) {
552    case FORMAT :
553        switch(width) {
554        case WIDE :
555            count = fMonthsCount;
556            returnValue = fMonths;
557            break;
558        case ABBREVIATED :
559            count = fShortMonthsCount;
560            returnValue = fShortMonths;
561            break;
562        case NARROW :
563            count = fNarrowMonthsCount;
564            returnValue = fNarrowMonths;
565            break;
566        case DT_WIDTH_COUNT :
567            break;
568        }
569        break;
570    case STANDALONE :
571        switch(width) {
572        case WIDE :
573            count = fStandaloneMonthsCount;
574            returnValue = fStandaloneMonths;
575            break;
576        case ABBREVIATED :
577            count = fStandaloneShortMonthsCount;
578            returnValue = fStandaloneShortMonths;
579            break;
580        case NARROW :
581            count = fStandaloneNarrowMonthsCount;
582            returnValue = fStandaloneNarrowMonths;
583            break;
584        case DT_WIDTH_COUNT :
585            break;
586        }
587        break;
588    case DT_CONTEXT_COUNT :
589        break;
590    }
591    return returnValue;
592}
593
594const UnicodeString*
595DateFormatSymbols::getWeekdays(int32_t &count) const
596{
597    count = fWeekdaysCount;
598    return fWeekdays;
599}
600
601const UnicodeString*
602DateFormatSymbols::getShortWeekdays(int32_t &count) const
603{
604    count = fShortWeekdaysCount;
605    return fShortWeekdays;
606}
607
608const UnicodeString*
609DateFormatSymbols::getWeekdays(int32_t &count, DtContextType context, DtWidthType width) const
610{
611    UnicodeString *returnValue = NULL;
612    switch (context) {
613    case FORMAT :
614        switch(width) {
615            case WIDE :
616                count = fWeekdaysCount;
617                returnValue = fWeekdays;
618                break;
619            case ABBREVIATED :
620                count = fShortWeekdaysCount;
621                returnValue = fShortWeekdays;
622                break;
623            case NARROW :
624                count = fNarrowWeekdaysCount;
625                returnValue = fNarrowWeekdays;
626                break;
627            case DT_WIDTH_COUNT :
628                break;
629        }
630        break;
631    case STANDALONE :
632        switch(width) {
633            case WIDE :
634                count = fStandaloneWeekdaysCount;
635                returnValue = fStandaloneWeekdays;
636                break;
637            case ABBREVIATED :
638                count = fStandaloneShortWeekdaysCount;
639                returnValue = fStandaloneShortWeekdays;
640                break;
641            case NARROW :
642                count = fStandaloneNarrowWeekdaysCount;
643                returnValue = fStandaloneNarrowWeekdays;
644                break;
645            case DT_WIDTH_COUNT :
646                break;
647        }
648        break;
649    case DT_CONTEXT_COUNT :
650        break;
651    }
652    return returnValue;
653}
654
655const UnicodeString*
656DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthType width ) const
657{
658    UnicodeString *returnValue = NULL;
659
660    switch (context) {
661    case FORMAT :
662        switch(width) {
663        case WIDE :
664            count = fQuartersCount;
665            returnValue = fQuarters;
666            break;
667        case ABBREVIATED :
668            count = fShortQuartersCount;
669            returnValue = fShortQuarters;
670            break;
671        case NARROW :
672            count = 0;
673            returnValue = NULL;
674            break;
675        case DT_WIDTH_COUNT :
676            break;
677        }
678        break;
679    case STANDALONE :
680        switch(width) {
681        case WIDE :
682            count = fStandaloneQuartersCount;
683            returnValue = fStandaloneQuarters;
684            break;
685        case ABBREVIATED :
686            count = fStandaloneShortQuartersCount;
687            returnValue = fStandaloneShortQuarters;
688            break;
689        case NARROW :
690            count = 0;
691            returnValue = NULL;
692            break;
693        case DT_WIDTH_COUNT :
694            break;
695        }
696        break;
697    case DT_CONTEXT_COUNT :
698        break;
699    }
700    return returnValue;
701}
702
703const UnicodeString*
704DateFormatSymbols::getAmPmStrings(int32_t &count) const
705{
706    count = fAmPmsCount;
707    return fAmPms;
708}
709
710//------------------------------------------------------
711
712void
713DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count)
714{
715    // delete the old list if we own it
716    if (fEras)
717        delete[] fEras;
718
719    // we always own the new list, which we create here (we duplicate rather
720    // than adopting the list passed in)
721    fEras = newUnicodeStringArray(count);
722    uprv_arrayCopy(erasArray,fEras,  count);
723    fErasCount = count;
724}
725
726void
727DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count)
728{
729    // delete the old list if we own it
730    if (fEraNames)
731        delete[] fEraNames;
732
733    // we always own the new list, which we create here (we duplicate rather
734    // than adopting the list passed in)
735    fEraNames = newUnicodeStringArray(count);
736    uprv_arrayCopy(eraNamesArray,fEraNames,  count);
737    fEraNamesCount = count;
738}
739
740void
741DateFormatSymbols::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count)
742{
743    // delete the old list if we own it
744    if (fNarrowEras)
745        delete[] fNarrowEras;
746
747    // we always own the new list, which we create here (we duplicate rather
748    // than adopting the list passed in)
749    fNarrowEras = newUnicodeStringArray(count);
750    uprv_arrayCopy(narrowErasArray,fNarrowEras,  count);
751    fNarrowErasCount = count;
752}
753
754void
755DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count)
756{
757    // delete the old list if we own it
758    if (fMonths)
759        delete[] fMonths;
760
761    // we always own the new list, which we create here (we duplicate rather
762    // than adopting the list passed in)
763    fMonths = newUnicodeStringArray(count);
764    uprv_arrayCopy( monthsArray,fMonths,count);
765    fMonthsCount = count;
766}
767
768void
769DateFormatSymbols::setShortMonths(const UnicodeString* shortMonthsArray, int32_t count)
770{
771    // delete the old list if we own it
772    if (fShortMonths)
773        delete[] fShortMonths;
774
775    // we always own the new list, which we create here (we duplicate rather
776    // than adopting the list passed in)
777    fShortMonths = newUnicodeStringArray(count);
778    uprv_arrayCopy(shortMonthsArray,fShortMonths,  count);
779    fShortMonthsCount = count;
780}
781
782void
783DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, DtContextType context, DtWidthType width)
784{
785    // delete the old list if we own it
786    // we always own the new list, which we create here (we duplicate rather
787    // than adopting the list passed in)
788
789    switch (context) {
790    case FORMAT :
791        switch (width) {
792        case WIDE :
793            if (fMonths)
794                delete[] fMonths;
795            fMonths = newUnicodeStringArray(count);
796            uprv_arrayCopy( monthsArray,fMonths,count);
797            fMonthsCount = count;
798            break;
799        case ABBREVIATED :
800            if (fShortMonths)
801                delete[] fShortMonths;
802            fShortMonths = newUnicodeStringArray(count);
803            uprv_arrayCopy( monthsArray,fShortMonths,count);
804            fShortMonthsCount = count;
805            break;
806        case NARROW :
807            if (fNarrowMonths)
808                delete[] fNarrowMonths;
809            fNarrowMonths = newUnicodeStringArray(count);
810            uprv_arrayCopy( monthsArray,fNarrowMonths,count);
811            fNarrowMonthsCount = count;
812            break;
813        case DT_WIDTH_COUNT :
814            break;
815        }
816        break;
817    case STANDALONE :
818        switch (width) {
819        case WIDE :
820            if (fStandaloneMonths)
821                delete[] fStandaloneMonths;
822            fStandaloneMonths = newUnicodeStringArray(count);
823            uprv_arrayCopy( monthsArray,fStandaloneMonths,count);
824            fStandaloneMonthsCount = count;
825            break;
826        case ABBREVIATED :
827            if (fStandaloneShortMonths)
828                delete[] fStandaloneShortMonths;
829            fStandaloneShortMonths = newUnicodeStringArray(count);
830            uprv_arrayCopy( monthsArray,fStandaloneShortMonths,count);
831            fStandaloneShortMonthsCount = count;
832            break;
833        case NARROW :
834           if (fStandaloneNarrowMonths)
835                delete[] fStandaloneNarrowMonths;
836            fStandaloneNarrowMonths = newUnicodeStringArray(count);
837            uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count);
838            fStandaloneNarrowMonthsCount = count;
839            break;
840        case DT_WIDTH_COUNT :
841            break;
842        }
843        break;
844    case DT_CONTEXT_COUNT :
845        break;
846    }
847}
848
849void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count)
850{
851    // delete the old list if we own it
852    if (fWeekdays)
853        delete[] fWeekdays;
854
855    // we always own the new list, which we create here (we duplicate rather
856    // than adopting the list passed in)
857    fWeekdays = newUnicodeStringArray(count);
858    uprv_arrayCopy(weekdaysArray,fWeekdays,count);
859    fWeekdaysCount = count;
860}
861
862void
863DateFormatSymbols::setShortWeekdays(const UnicodeString* shortWeekdaysArray, int32_t count)
864{
865    // delete the old list if we own it
866    if (fShortWeekdays)
867        delete[] fShortWeekdays;
868
869    // we always own the new list, which we create here (we duplicate rather
870    // than adopting the list passed in)
871    fShortWeekdays = newUnicodeStringArray(count);
872    uprv_arrayCopy(shortWeekdaysArray, fShortWeekdays, count);
873    fShortWeekdaysCount = count;
874}
875
876void
877DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count, DtContextType context, DtWidthType width)
878{
879    // delete the old list if we own it
880    // we always own the new list, which we create here (we duplicate rather
881    // than adopting the list passed in)
882
883    switch (context) {
884    case FORMAT :
885        switch (width) {
886        case WIDE :
887            if (fWeekdays)
888                delete[] fWeekdays;
889            fWeekdays = newUnicodeStringArray(count);
890            uprv_arrayCopy(weekdaysArray, fWeekdays, count);
891            fWeekdaysCount = count;
892            break;
893        case ABBREVIATED :
894            if (fShortWeekdays)
895                delete[] fShortWeekdays;
896            fShortWeekdays = newUnicodeStringArray(count);
897            uprv_arrayCopy(weekdaysArray, fShortWeekdays, count);
898            fShortWeekdaysCount = count;
899            break;
900        case NARROW :
901            if (fNarrowWeekdays)
902                delete[] fNarrowWeekdays;
903            fNarrowWeekdays = newUnicodeStringArray(count);
904            uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count);
905            fNarrowWeekdaysCount = count;
906            break;
907        case DT_WIDTH_COUNT :
908            break;
909        }
910        break;
911    case STANDALONE :
912        switch (width) {
913        case WIDE :
914            if (fStandaloneWeekdays)
915                delete[] fStandaloneWeekdays;
916            fStandaloneWeekdays = newUnicodeStringArray(count);
917            uprv_arrayCopy(weekdaysArray, fStandaloneWeekdays, count);
918            fStandaloneWeekdaysCount = count;
919            break;
920        case ABBREVIATED :
921            if (fStandaloneShortWeekdays)
922                delete[] fStandaloneShortWeekdays;
923            fStandaloneShortWeekdays = newUnicodeStringArray(count);
924            uprv_arrayCopy(weekdaysArray, fStandaloneShortWeekdays, count);
925            fStandaloneShortWeekdaysCount = count;
926            break;
927        case NARROW :
928            if (fStandaloneNarrowWeekdays)
929                delete[] fStandaloneNarrowWeekdays;
930            fStandaloneNarrowWeekdays = newUnicodeStringArray(count);
931            uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count);
932            fStandaloneNarrowWeekdaysCount = count;
933            break;
934        case DT_WIDTH_COUNT :
935            break;
936        }
937        break;
938    case DT_CONTEXT_COUNT :
939        break;
940    }
941}
942
943void
944DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count, DtContextType context, DtWidthType width)
945{
946    // delete the old list if we own it
947    // we always own the new list, which we create here (we duplicate rather
948    // than adopting the list passed in)
949
950    switch (context) {
951    case FORMAT :
952        switch (width) {
953        case WIDE :
954            if (fQuarters)
955                delete[] fQuarters;
956            fQuarters = newUnicodeStringArray(count);
957            uprv_arrayCopy( quartersArray,fQuarters,count);
958            fQuartersCount = count;
959            break;
960        case ABBREVIATED :
961            if (fShortQuarters)
962                delete[] fShortQuarters;
963            fShortQuarters = newUnicodeStringArray(count);
964            uprv_arrayCopy( quartersArray,fShortQuarters,count);
965            fShortQuartersCount = count;
966            break;
967        case NARROW :
968        /*
969            if (fNarrowQuarters)
970                delete[] fNarrowQuarters;
971            fNarrowQuarters = newUnicodeStringArray(count);
972            uprv_arrayCopy( quartersArray,fNarrowQuarters,count);
973            fNarrowQuartersCount = count;
974        */
975            break;
976        case DT_WIDTH_COUNT :
977            break;
978        }
979        break;
980    case STANDALONE :
981        switch (width) {
982        case WIDE :
983            if (fStandaloneQuarters)
984                delete[] fStandaloneQuarters;
985            fStandaloneQuarters = newUnicodeStringArray(count);
986            uprv_arrayCopy( quartersArray,fStandaloneQuarters,count);
987            fStandaloneQuartersCount = count;
988            break;
989        case ABBREVIATED :
990            if (fStandaloneShortQuarters)
991                delete[] fStandaloneShortQuarters;
992            fStandaloneShortQuarters = newUnicodeStringArray(count);
993            uprv_arrayCopy( quartersArray,fStandaloneShortQuarters,count);
994            fStandaloneShortQuartersCount = count;
995            break;
996        case NARROW :
997        /*
998           if (fStandaloneNarrowQuarters)
999                delete[] fStandaloneNarrowQuarters;
1000            fStandaloneNarrowQuarters = newUnicodeStringArray(count);
1001            uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count);
1002            fStandaloneNarrowQuartersCount = count;
1003        */
1004            break;
1005        case DT_WIDTH_COUNT :
1006            break;
1007        }
1008        break;
1009    case DT_CONTEXT_COUNT :
1010        break;
1011    }
1012}
1013
1014void
1015DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count)
1016{
1017    // delete the old list if we own it
1018    if (fAmPms) delete[] fAmPms;
1019
1020    // we always own the new list, which we create here (we duplicate rather
1021    // than adopting the list passed in)
1022    fAmPms = newUnicodeStringArray(count);
1023    uprv_arrayCopy(amPmsArray,fAmPms,count);
1024    fAmPmsCount = count;
1025}
1026
1027const UnicodeString**
1028DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
1029{
1030    const UnicodeString **result = NULL;
1031
1032    umtx_lock(&LOCK);
1033    if (fZoneStrings == NULL) {
1034        if (fLocaleZoneStrings == NULL) {
1035            ((DateFormatSymbols*)this)->initZoneStringsArray();
1036        }
1037        result = (const UnicodeString**)fLocaleZoneStrings;
1038    } else {
1039        result = (const UnicodeString**)fZoneStrings;
1040    }
1041    rowCount = fZoneStringsRowCount;
1042    columnCount = fZoneStringsColCount;
1043    umtx_unlock(&LOCK);
1044
1045    return result;
1046}
1047
1048// For now, we include all zones
1049#define ZONE_SET UCAL_ZONE_TYPE_ANY
1050
1051// This code must be called within a synchronized block
1052void
1053DateFormatSymbols::initZoneStringsArray(void) {
1054    if (fZoneStrings != NULL || fLocaleZoneStrings != NULL) {
1055        return;
1056    }
1057
1058    UErrorCode status = U_ZERO_ERROR;
1059
1060    StringEnumeration *tzids = NULL;
1061    UnicodeString ** zarray = NULL;
1062    TimeZoneNames *tzNames = NULL;
1063    int32_t rows = 0;
1064
1065    do { // dummy do-while
1066
1067        tzids = TimeZone::createTimeZoneIDEnumeration(ZONE_SET, NULL, NULL, status);
1068        rows = tzids->count(status);
1069        if (U_FAILURE(status)) {
1070            break;
1071        }
1072
1073        // Allocate array
1074        int32_t size = rows * sizeof(UnicodeString*);
1075        zarray = (UnicodeString**)uprv_malloc(size);
1076        if (zarray == NULL) {
1077            status = U_MEMORY_ALLOCATION_ERROR;
1078            break;
1079        }
1080        uprv_memset(zarray, 0, size);
1081
1082        tzNames = TimeZoneNames::createInstance(fZSFLocale, status);
1083
1084        const UnicodeString *tzid;
1085        int32_t i = 0;
1086        UDate now = Calendar::getNow();
1087        UnicodeString tzDispName;
1088
1089        while ((tzid = tzids->snext(status))) {
1090            if (U_FAILURE(status)) {
1091                break;
1092            }
1093
1094            zarray[i] = new UnicodeString[5];
1095            if (zarray[i] == NULL) {
1096                status = U_MEMORY_ALLOCATION_ERROR;
1097                break;
1098            }
1099
1100            zarray[i][0].setTo(*tzid);
1101            zarray[i][1].setTo(tzNames->getDisplayName(*tzid, UTZNM_LONG_STANDARD, now, tzDispName));
1102            zarray[i][2].setTo(tzNames->getDisplayName(*tzid, UTZNM_SHORT_STANDARD, now, tzDispName));
1103            zarray[i][3].setTo(tzNames->getDisplayName(*tzid, UTZNM_LONG_DAYLIGHT, now, tzDispName));
1104            zarray[i][4].setTo(tzNames->getDisplayName(*tzid, UTZNM_SHORT_DAYLIGHT, now, tzDispName));
1105            i++;
1106        }
1107
1108    } while (FALSE);
1109
1110    if (U_FAILURE(status)) {
1111        if (zarray) {
1112            for (int32_t i = 0; i < rows; i++) {
1113                if (zarray[i]) {
1114                    delete[] zarray[i];
1115                }
1116            }
1117            uprv_free(zarray);
1118        }
1119    }
1120
1121    if (tzNames) {
1122        delete tzNames;
1123    }
1124    if (tzids) {
1125        delete tzids;
1126    }
1127
1128    fLocaleZoneStrings = zarray;
1129    fZoneStringsRowCount = rows;
1130    fZoneStringsColCount = 5;
1131}
1132
1133void
1134DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount)
1135{
1136    // since deleting a 2-d array is a pain in the butt, we offload that task to
1137    // a separate function
1138    disposeZoneStrings();
1139    // we always own the new list, which we create here (we duplicate rather
1140    // than adopting the list passed in)
1141    fZoneStringsRowCount = rowCount;
1142    fZoneStringsColCount = columnCount;
1143    createZoneStrings((const UnicodeString**)strings);
1144}
1145
1146//------------------------------------------------------
1147
1148const UChar * U_EXPORT2
1149DateFormatSymbols::getPatternUChars(void)
1150{
1151    return gPatternChars;
1152}
1153
1154//------------------------------------------------------
1155
1156UnicodeString&
1157DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const
1158{
1159    // fastCopyFrom() - see assignArray comments
1160    return result.fastCopyFrom(fLocalPatternChars);
1161}
1162
1163//------------------------------------------------------
1164
1165void
1166DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars)
1167{
1168    fLocalPatternChars = newLocalPatternChars;
1169}
1170
1171//------------------------------------------------------
1172
1173static void
1174initField(UnicodeString **field, int32_t& length, const UResourceBundle *data, UErrorCode &status) {
1175    if (U_SUCCESS(status)) {
1176        int32_t strLen = 0;
1177        length = ures_getSize(data);
1178        *field = newUnicodeStringArray(length);
1179        if (*field) {
1180            for(int32_t i = 0; i<length; i++) {
1181                const UChar *resStr = ures_getStringByIndex(data, i, &strLen, &status);
1182                // setTo() - see assignArray comments
1183                (*(field)+i)->setTo(TRUE, resStr, strLen);
1184            }
1185        }
1186        else {
1187            length = 0;
1188            status = U_MEMORY_ALLOCATION_ERROR;
1189        }
1190    }
1191}
1192
1193static void
1194initField(UnicodeString **field, int32_t& length, const UChar *data, LastResortSize numStr, LastResortSize strLen, UErrorCode &status) {
1195    if (U_SUCCESS(status)) {
1196        length = numStr;
1197        *field = newUnicodeStringArray((size_t)numStr);
1198        if (*field) {
1199            for(int32_t i = 0; i<length; i++) {
1200                // readonly aliases - all "data" strings are constant
1201                // -1 as length for variable-length strings (gLastResortDayNames[0] is empty)
1202                (*(field)+i)->setTo(TRUE, data+(i*((int32_t)strLen)), -1);
1203            }
1204        }
1205        else {
1206            length = 0;
1207            status = U_MEMORY_ALLOCATION_ERROR;
1208        }
1209    }
1210}
1211
1212void
1213DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData)
1214{
1215    int32_t i;
1216    int32_t len = 0;
1217    const UChar *resStr;
1218    /* In case something goes wrong, initialize all of the data to NULL. */
1219    fEras = NULL;
1220    fErasCount = 0;
1221    fEraNames = NULL;
1222    fEraNamesCount = 0;
1223    fNarrowEras = NULL;
1224    fNarrowErasCount = 0;
1225    fMonths = NULL;
1226    fMonthsCount=0;
1227    fShortMonths = NULL;
1228    fShortMonthsCount=0;
1229    fNarrowMonths = NULL;
1230    fNarrowMonthsCount=0;
1231    fStandaloneMonths = NULL;
1232    fStandaloneMonthsCount=0;
1233    fStandaloneShortMonths = NULL;
1234    fStandaloneShortMonthsCount=0;
1235    fStandaloneNarrowMonths = NULL;
1236    fStandaloneNarrowMonthsCount=0;
1237    fWeekdays = NULL;
1238    fWeekdaysCount=0;
1239    fShortWeekdays = NULL;
1240    fShortWeekdaysCount=0;
1241    fNarrowWeekdays = NULL;
1242    fNarrowWeekdaysCount=0;
1243    fStandaloneWeekdays = NULL;
1244    fStandaloneWeekdaysCount=0;
1245    fStandaloneShortWeekdays = NULL;
1246    fStandaloneShortWeekdaysCount=0;
1247    fStandaloneNarrowWeekdays = NULL;
1248    fStandaloneNarrowWeekdaysCount=0;
1249    fAmPms = NULL;
1250    fAmPmsCount=0;
1251    fQuarters = NULL;
1252    fQuartersCount = 0;
1253    fShortQuarters = NULL;
1254    fShortQuartersCount = 0;
1255    fStandaloneQuarters = NULL;
1256    fStandaloneQuartersCount = 0;
1257    fStandaloneShortQuarters = NULL;
1258    fStandaloneShortQuartersCount = 0;
1259    fGmtHourFormats = NULL;
1260    fGmtHourFormatsCount = 0;
1261    fZoneStringsRowCount = 0;
1262    fZoneStringsColCount = 0;
1263    fZoneStrings = NULL;
1264    fLocaleZoneStrings = NULL;
1265
1266    // We need to preserve the requested locale for
1267    // lazy ZoneStringFormat instantiation.  ZoneStringFormat
1268    // is region sensitive, thus, bundle locale bundle's locale
1269    // is not sufficient.
1270    fZSFLocale = locale;
1271
1272    if (U_FAILURE(status)) return;
1273
1274    /**
1275     * Retrieve the string arrays we need from the resource bundle file.
1276     * We cast away const here, but that's okay; we won't delete any of
1277     * these.
1278     */
1279    CalendarData calData(locale, type, status);
1280
1281    /**
1282     * Use the localeBundle for getting zone GMT formatting patterns
1283     */
1284    UResourceBundle *zoneBundle = ures_open(U_ICUDATA_ZONE, locale.getName(), &status);
1285    UResourceBundle *zoneStringsArray = ures_getByKeyWithFallback(zoneBundle, gZoneStringsTag, NULL, &status);
1286
1287    // load the first data item
1288    UResourceBundle *erasMain = calData.getByKey(gErasTag, status);
1289    UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, NULL, &status);
1290    UErrorCode oldStatus = status;
1291    UResourceBundle *eraNames = ures_getByKeyWithFallback(erasMain, gNamesWideTag, NULL, &status);
1292    if ( status == U_MISSING_RESOURCE_ERROR ) { // Workaround because eras/wide was omitted from CLDR 1.3
1293       status = oldStatus;
1294       eraNames = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, NULL, &status);
1295    }
1296	// current ICU4J falls back to abbreviated if narrow eras are missing, so we will too
1297    oldStatus = status;
1298    UResourceBundle *narrowEras = ures_getByKeyWithFallback(erasMain, gNamesNarrowTag, NULL, &status);
1299    if ( status == U_MISSING_RESOURCE_ERROR ) {
1300       status = oldStatus;
1301       narrowEras = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, NULL, &status);
1302    }
1303
1304    UResourceBundle *lsweekdaysData = NULL; // Data closed by calData
1305    UResourceBundle *weekdaysData = NULL; // Data closed by calData
1306    UResourceBundle *narrowWeekdaysData = NULL; // Data closed by calData
1307    UResourceBundle *standaloneWeekdaysData = NULL; // Data closed by calData
1308    UResourceBundle *standaloneShortWeekdaysData = NULL; // Data closed by calData
1309    UResourceBundle *standaloneNarrowWeekdaysData = NULL; // Data closed by calData
1310
1311    U_LOCALE_BASED(locBased, *this);
1312    if (U_FAILURE(status))
1313    {
1314        if (useLastResortData)
1315        {
1316            // Handle the case in which there is no resource data present.
1317            // We don't have to generate usable patterns in this situation;
1318            // we just need to produce something that will be semi-intelligible
1319            // in most locales.
1320
1321            status = U_USING_FALLBACK_WARNING;
1322
1323            initField(&fEras, fErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status);
1324            initField(&fEraNames, fEraNamesCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status);
1325            initField(&fNarrowEras, fNarrowErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status);
1326            initField(&fMonths, fMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen,  status);
1327            initField(&fShortMonths, fShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
1328            initField(&fNarrowMonths, fNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
1329            initField(&fStandaloneMonths, fStandaloneMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen,  status);
1330            initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
1331            initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
1332            initField(&fWeekdays, fWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
1333            initField(&fShortWeekdays, fShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
1334            initField(&fNarrowWeekdays, fNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
1335            initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
1336            initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
1337            initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
1338            initField(&fAmPms, fAmPmsCount, (const UChar *)gLastResortAmPmMarkers, kAmPmNum, kAmPmLen, status);
1339            initField(&fQuarters, fQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
1340            initField(&fShortQuarters, fShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
1341            initField(&fStandaloneQuarters, fStandaloneQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
1342            initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
1343            initField(&fGmtHourFormats, fGmtHourFormatsCount, (const UChar *)gLastResortGmtHourFormats, kGmtHourNum, kGmtHourLen, status);
1344            fGmtZero.setTo(TRUE, gLastResortGmtZero, -1);
1345            fGmtFormat.setTo(TRUE, gLastResortGmtFormat, -1);
1346            fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN);
1347        }
1348        goto cleanup;
1349    }
1350
1351    // if we make it to here, the resource data is cool, and we can get everything out
1352    // of it that we need except for the time-zone and localized-pattern data, which
1353    // are stored in a separate file
1354    locBased.setLocaleIDs(ures_getLocaleByType(eras, ULOC_VALID_LOCALE, &status),
1355                          ures_getLocaleByType(eras, ULOC_ACTUAL_LOCALE, &status));
1356
1357    initField(&fEras, fErasCount, eras, status);
1358    initField(&fEraNames, fEraNamesCount, eraNames, status);
1359    initField(&fNarrowEras, fNarrowErasCount, narrowEras, status);
1360
1361    initField(&fMonths, fMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status);
1362    initField(&fShortMonths, fShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
1363
1364    initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status);
1365    if(status == U_MISSING_RESOURCE_ERROR) {
1366        status = U_ZERO_ERROR;
1367        initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
1368    }
1369    if ( status == U_MISSING_RESOURCE_ERROR ) { /* If format/narrow not available, use format/abbreviated */
1370       status = U_ZERO_ERROR;
1371       initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
1372    }
1373
1374    initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status);
1375    if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/wide not available, use format/wide */
1376       status = U_ZERO_ERROR;
1377       initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status);
1378    }
1379    initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
1380    if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/abbreviated not available, use format/abbreviated */
1381       status = U_ZERO_ERROR;
1382       initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
1383    }
1384    initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
1385    if ( status == U_MISSING_RESOURCE_ERROR ) { /* if standalone/narrow not availabe, try format/narrow */
1386       status = U_ZERO_ERROR;
1387       initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status);
1388       if ( status == U_MISSING_RESOURCE_ERROR ) { /* if still not there, use format/abbreviated */
1389          status = U_ZERO_ERROR;
1390          initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
1391       }
1392    }
1393    initField(&fAmPms, fAmPmsCount, calData.getByKey(gAmPmMarkersTag, status), status);
1394
1395    initField(&fQuarters, fQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status);
1396    initField(&fShortQuarters, fShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status);
1397
1398    initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status);
1399    if(status == U_MISSING_RESOURCE_ERROR) {
1400        status = U_ZERO_ERROR;
1401        initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status);
1402    }
1403
1404    initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
1405    if(status == U_MISSING_RESOURCE_ERROR) {
1406        status = U_ZERO_ERROR;
1407        initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status);
1408    }
1409
1410    // GMT zero
1411    resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gGmtZeroFormatTag, &len, &status);
1412    if (len > 0) {
1413        fGmtZero.setTo(TRUE, resStr, len);
1414    }
1415
1416    // GMT format patterns
1417    resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gGmtFormatTag, &len, &status);
1418    if (len > 0) {
1419        fGmtFormat.setTo(TRUE, resStr, len);
1420    }
1421
1422    resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gHourFormatTag, &len, &status);
1423    if (len > 0) {
1424        UChar *sep = u_strchr(resStr, (UChar)0x003B /* ';' */);
1425        if (sep != NULL) {
1426            fGmtHourFormats = newUnicodeStringArray(GMT_HOUR_COUNT);
1427            if (fGmtHourFormats == NULL) {
1428                status = U_MEMORY_ALLOCATION_ERROR;
1429            } else {
1430                fGmtHourFormatsCount = GMT_HOUR_COUNT;
1431                fGmtHourFormats[GMT_NEGATIVE_HM].setTo(TRUE, sep + 1, -1);
1432                fGmtHourFormats[GMT_POSITIVE_HM].setTo(FALSE, resStr, (int32_t)(sep - resStr));
1433
1434                // CLDR 1.5 does not have GMT offset pattern including second field.
1435                // For now, append "ss" to the end.
1436                if (fGmtHourFormats[GMT_NEGATIVE_HM].indexOf((UChar)0x003A /* ':' */) != -1) {
1437                    fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE(":ss");
1438                } else if (fGmtHourFormats[GMT_NEGATIVE_HM].indexOf((UChar)0x002E /* '.' */) != -1) {
1439                    fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE(".ss");
1440                } else {
1441                    fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + UNICODE_STRING_SIMPLE("ss");
1442                }
1443                if (fGmtHourFormats[GMT_POSITIVE_HM].indexOf((UChar)0x003A /* ':' */) != -1) {
1444                    fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE(":ss");
1445                } else if (fGmtHourFormats[GMT_POSITIVE_HM].indexOf((UChar)0x002E /* '.' */) != -1) {
1446                    fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE(".ss");
1447                } else {
1448                    fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + UNICODE_STRING_SIMPLE("ss");
1449                }
1450            }
1451        }
1452    }
1453
1454    // ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597)
1455    /*
1456    // fastCopyFrom()/setTo() - see assignArray comments
1457    resStr = ures_getStringByKey(fResourceBundle, gLocalPatternCharsTag, &len, &status);
1458    fLocalPatternChars.setTo(TRUE, resStr, len);
1459    // If the locale data does not include new pattern chars, use the defaults
1460    // TODO: Consider making this an error, since this may add conflicting characters.
1461    if (len < PATTERN_CHARS_LEN) {
1462        fLocalPatternChars.append(UnicodeString(TRUE, &gPatternChars[len], PATTERN_CHARS_LEN-len));
1463    }
1464    */
1465    fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN);
1466
1467    // {sfb} fixed to handle 1-based weekdays
1468    weekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status);
1469    fWeekdaysCount = ures_getSize(weekdaysData);
1470    fWeekdays = new UnicodeString[fWeekdaysCount+1];
1471    /* pin the blame on system. If we cannot get a chunk of memory .. the system is dying!*/
1472    if (fWeekdays == NULL) {
1473        status = U_MEMORY_ALLOCATION_ERROR;
1474        goto cleanup;
1475    }
1476    // leave fWeekdays[0] empty
1477    for(i = 0; i<fWeekdaysCount; i++) {
1478        resStr = ures_getStringByIndex(weekdaysData, i, &len, &status);
1479        // setTo() - see assignArray comments
1480        fWeekdays[i+1].setTo(TRUE, resStr, len);
1481    }
1482    fWeekdaysCount++;
1483
1484    lsweekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
1485    fShortWeekdaysCount = ures_getSize(lsweekdaysData);
1486    fShortWeekdays = new UnicodeString[fShortWeekdaysCount+1];
1487    /* test for NULL */
1488    if (fShortWeekdays == 0) {
1489        status = U_MEMORY_ALLOCATION_ERROR;
1490        goto cleanup;
1491    }
1492    // leave fShortWeekdays[0] empty
1493    for(i = 0; i<fShortWeekdaysCount; i++) {
1494        resStr = ures_getStringByIndex(lsweekdaysData, i, &len, &status);
1495        // setTo() - see assignArray comments
1496        fShortWeekdays[i+1].setTo(TRUE, resStr, len);
1497    }
1498    fShortWeekdaysCount++;
1499
1500    narrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesNarrowTag, status);
1501    if(status == U_MISSING_RESOURCE_ERROR) {
1502        status = U_ZERO_ERROR;
1503        narrowWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status);
1504    }
1505    if ( status == U_MISSING_RESOURCE_ERROR ) {
1506       status = U_ZERO_ERROR;
1507       narrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
1508    }
1509    fNarrowWeekdaysCount = ures_getSize(narrowWeekdaysData);
1510    fNarrowWeekdays = new UnicodeString[fNarrowWeekdaysCount+1];
1511    /* test for NULL */
1512    if (fNarrowWeekdays == 0) {
1513        status = U_MEMORY_ALLOCATION_ERROR;
1514        goto cleanup;
1515    }
1516    // leave fNarrowWeekdays[0] empty
1517    for(i = 0; i<fNarrowWeekdaysCount; i++) {
1518        resStr = ures_getStringByIndex(narrowWeekdaysData, i, &len, &status);
1519        // setTo() - see assignArray comments
1520        fNarrowWeekdays[i+1].setTo(TRUE, resStr, len);
1521    }
1522    fNarrowWeekdaysCount++;
1523
1524    standaloneWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status);
1525    if ( status == U_MISSING_RESOURCE_ERROR ) {
1526       status = U_ZERO_ERROR;
1527       standaloneWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status);
1528    }
1529    fStandaloneWeekdaysCount = ures_getSize(standaloneWeekdaysData);
1530    fStandaloneWeekdays = new UnicodeString[fStandaloneWeekdaysCount+1];
1531    /* test for NULL */
1532    if (fStandaloneWeekdays == 0) {
1533        status = U_MEMORY_ALLOCATION_ERROR;
1534        goto cleanup;
1535    }
1536    // leave fStandaloneWeekdays[0] empty
1537    for(i = 0; i<fStandaloneWeekdaysCount; i++) {
1538        resStr = ures_getStringByIndex(standaloneWeekdaysData, i, &len, &status);
1539        // setTo() - see assignArray comments
1540        fStandaloneWeekdays[i+1].setTo(TRUE, resStr, len);
1541    }
1542    fStandaloneWeekdaysCount++;
1543
1544    standaloneShortWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status);
1545    if ( status == U_MISSING_RESOURCE_ERROR ) {
1546       status = U_ZERO_ERROR;
1547       standaloneShortWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
1548    }
1549    fStandaloneShortWeekdaysCount = ures_getSize(standaloneShortWeekdaysData);
1550    fStandaloneShortWeekdays = new UnicodeString[fStandaloneShortWeekdaysCount+1];
1551    /* test for NULL */
1552    if (fStandaloneShortWeekdays == 0) {
1553        status = U_MEMORY_ALLOCATION_ERROR;
1554        goto cleanup;
1555    }
1556    // leave fStandaloneShortWeekdays[0] empty
1557    for(i = 0; i<fStandaloneShortWeekdaysCount; i++) {
1558        resStr = ures_getStringByIndex(standaloneShortWeekdaysData, i, &len, &status);
1559        // setTo() - see assignArray comments
1560        fStandaloneShortWeekdays[i+1].setTo(TRUE, resStr, len);
1561    }
1562    fStandaloneShortWeekdaysCount++;
1563
1564    standaloneNarrowWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status);
1565    if ( status == U_MISSING_RESOURCE_ERROR ) {
1566       status = U_ZERO_ERROR;
1567       standaloneNarrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesNarrowTag, status);
1568       if ( status == U_MISSING_RESOURCE_ERROR ) {
1569          status = U_ZERO_ERROR;
1570          standaloneNarrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
1571       }
1572    }
1573    fStandaloneNarrowWeekdaysCount = ures_getSize(standaloneNarrowWeekdaysData);
1574    fStandaloneNarrowWeekdays = new UnicodeString[fStandaloneNarrowWeekdaysCount+1];
1575    /* test for NULL */
1576    if (fStandaloneNarrowWeekdays == 0) {
1577        status = U_MEMORY_ALLOCATION_ERROR;
1578        goto cleanup;
1579    }
1580    // leave fStandaloneNarrowWeekdays[0] empty
1581    for(i = 0; i<fStandaloneNarrowWeekdaysCount; i++) {
1582        resStr = ures_getStringByIndex(standaloneNarrowWeekdaysData, i, &len, &status);
1583        // setTo() - see assignArray comments
1584        fStandaloneNarrowWeekdays[i+1].setTo(TRUE, resStr, len);
1585    }
1586    fStandaloneNarrowWeekdaysCount++;
1587
1588cleanup:
1589    ures_close(eras);
1590    ures_close(eraNames);
1591    ures_close(narrowEras);
1592    ures_close(zoneStringsArray);
1593    ures_close(zoneBundle);
1594}
1595
1596Locale
1597DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
1598    U_LOCALE_BASED(locBased, *this);
1599    return locBased.getLocale(type, status);
1600}
1601
1602U_NAMESPACE_END
1603
1604#endif /* #if !UCONFIG_NO_FORMATTING */
1605
1606//eof
1607