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