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