/src/icu/source/i18n/smpdtfmt.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // © 2016 and later: Unicode, Inc. and others.  | 
2  |  | // License & terms of use: http://www.unicode.org/copyright.html  | 
3  |  | /*  | 
4  |  | *******************************************************************************  | 
5  |  | * Copyright (C) 1997-2016, International Business Machines Corporation and    *  | 
6  |  | * others. All Rights Reserved.                                                *  | 
7  |  | *******************************************************************************  | 
8  |  | *  | 
9  |  | * File SMPDTFMT.CPP  | 
10  |  | *  | 
11  |  | * Modification History:  | 
12  |  | *  | 
13  |  | *   Date        Name        Description  | 
14  |  | *   02/19/97    aliu        Converted from java.  | 
15  |  | *   03/31/97    aliu        Modified extensively to work with 50 locales.  | 
16  |  | *   04/01/97    aliu        Added support for centuries.  | 
17  |  | *   07/09/97    helena      Made ParsePosition into a class.  | 
18  |  | *   07/21/98    stephen     Added initializeDefaultCentury.  | 
19  |  | *                             Removed getZoneIndex (added in DateFormatSymbols)  | 
20  |  | *                             Removed subParseLong  | 
21  |  | *                             Removed chk  | 
22  |  | *   02/22/99    stephen     Removed character literals for EBCDIC safety  | 
23  |  | *   10/14/99    aliu        Updated 2-digit year parsing so that only "00" thru  | 
24  |  | *                           "99" are recognized. {j28 4182066} | 
25  |  | *   11/15/99    weiv        Added support for week of year/day of week format  | 
26  |  | ********************************************************************************  | 
27  |  | */  | 
28  |  |  | 
29  |  | #define ZID_KEY_MAX 128  | 
30  |  |  | 
31  |  | #include "unicode/utypes.h"  | 
32  |  |  | 
33  |  | #if !UCONFIG_NO_FORMATTING  | 
34  |  | #include "unicode/smpdtfmt.h"  | 
35  |  | #include "unicode/dtfmtsym.h"  | 
36  |  | #include "unicode/ures.h"  | 
37  |  | #include "unicode/msgfmt.h"  | 
38  |  | #include "unicode/calendar.h"  | 
39  |  | #include "unicode/gregocal.h"  | 
40  |  | #include "unicode/timezone.h"  | 
41  |  | #include "unicode/decimfmt.h"  | 
42  |  | #include "unicode/dcfmtsym.h"  | 
43  |  | #include "unicode/uchar.h"  | 
44  |  | #include "unicode/uniset.h"  | 
45  |  | #include "unicode/ustring.h"  | 
46  |  | #include "unicode/basictz.h"  | 
47  |  | #include "unicode/simpleformatter.h"  | 
48  |  | #include "unicode/simpletz.h"  | 
49  |  | #include "unicode/rbtz.h"  | 
50  |  | #include "unicode/tzfmt.h"  | 
51  |  | #include "unicode/ucasemap.h"  | 
52  |  | #include "unicode/utf16.h"  | 
53  |  | #include "unicode/vtzone.h"  | 
54  |  | #include "unicode/udisplaycontext.h"  | 
55  |  | #include "unicode/brkiter.h"  | 
56  |  | #include "unicode/rbnf.h"  | 
57  |  | #include "unicode/dtptngen.h"  | 
58  |  | #include "uresimp.h"  | 
59  |  | #include "olsontz.h"  | 
60  |  | #include "patternprops.h"  | 
61  |  | #include "fphdlimp.h"  | 
62  |  | #include "hebrwcal.h"  | 
63  |  | #include "cstring.h"  | 
64  |  | #include "uassert.h"  | 
65  |  | #include "cmemory.h"  | 
66  |  | #include "umutex.h"  | 
67  |  | #include "mutex.h"  | 
68  |  | #include <float.h>  | 
69  |  | #include "smpdtfst.h"  | 
70  |  | #include "sharednumberformat.h"  | 
71  |  | #include "ucasemap_imp.h"  | 
72  |  | #include "ustr_imp.h"  | 
73  |  | #include "charstr.h"  | 
74  |  | #include "uvector.h"  | 
75  |  | #include "cstr.h"  | 
76  |  | #include "dayperiodrules.h"  | 
77  |  | #include "tznames_impl.h"   // ZONE_NAME_U16_MAX  | 
78  |  | #include "number_utypes.h"  | 
79  |  |  | 
80  |  | #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)  | 
81  |  | #include <stdio.h>  | 
82  |  | #endif  | 
83  |  |  | 
84  |  | // *****************************************************************************  | 
85  |  | // class SimpleDateFormat  | 
86  |  | // *****************************************************************************  | 
87  |  |  | 
88  |  | U_NAMESPACE_BEGIN  | 
89  |  |  | 
90  |  | /**  | 
91  |  |  * Last-resort string to use for "GMT" when constructing time zone strings.  | 
92  |  |  */  | 
93  |  | // For time zones that have no names, use strings GMT+minutes and  | 
94  |  | // GMT-minutes. For instance, in France the time zone is GMT+60.  | 
95  |  | // Also accepted are GMT+H:MM or GMT-H:MM.  | 
96  |  | // Currently not being used  | 
97  |  | //static const UChar gGmt[]      = {0x0047, 0x004D, 0x0054, 0x0000};         // "GMT" | 
98  |  | //static const UChar gGmtPlus[]  = {0x0047, 0x004D, 0x0054, 0x002B, 0x0000}; // "GMT+" | 
99  |  | //static const UChar gGmtMinus[] = {0x0047, 0x004D, 0x0054, 0x002D, 0x0000}; // "GMT-" | 
100  |  | //static const UChar gDefGmtPat[]       = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */ | 
101  |  | //static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* -HH:mm:ss */ | 
102  |  | //static const UChar gDefGmtNegHmPat[]  = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */ | 
103  |  | //static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */ | 
104  |  | //static const UChar gDefGmtPosHmPat[]  = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */ | 
105  |  | //static const UChar gUt[]       = {0x0055, 0x0054, 0x0000};  // "UT" | 
106  |  | //static const UChar gUtc[]      = {0x0055, 0x0054, 0x0043, 0x0000};  // "UT" | 
107  |  |  | 
108  |  | typedef enum GmtPatSize { | 
109  |  |     kGmtLen = 3,  | 
110  |  |     kGmtPatLen = 6,  | 
111  |  |     kNegHmsLen = 9,  | 
112  |  |     kNegHmLen = 6,  | 
113  |  |     kPosHmsLen = 9,  | 
114  |  |     kPosHmLen = 6,  | 
115  |  |     kUtLen = 2,  | 
116  |  |     kUtcLen = 3  | 
117  |  | } GmtPatSize;  | 
118  |  |  | 
119  |  | // Stuff needed for numbering system overrides  | 
120  |  |  | 
121  |  | typedef enum OvrStrType { | 
122  |  |     kOvrStrDate = 0,  | 
123  |  |     kOvrStrTime = 1,  | 
124  |  |     kOvrStrBoth = 2  | 
125  |  | } OvrStrType;  | 
126  |  |  | 
127  |  | static const UDateFormatField kDateFields[] = { | 
128  |  |     UDAT_YEAR_FIELD,  | 
129  |  |     UDAT_MONTH_FIELD,  | 
130  |  |     UDAT_DATE_FIELD,  | 
131  |  |     UDAT_DAY_OF_YEAR_FIELD,  | 
132  |  |     UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,  | 
133  |  |     UDAT_WEEK_OF_YEAR_FIELD,  | 
134  |  |     UDAT_WEEK_OF_MONTH_FIELD,  | 
135  |  |     UDAT_YEAR_WOY_FIELD,  | 
136  |  |     UDAT_EXTENDED_YEAR_FIELD,  | 
137  |  |     UDAT_JULIAN_DAY_FIELD,  | 
138  |  |     UDAT_STANDALONE_DAY_FIELD,  | 
139  |  |     UDAT_STANDALONE_MONTH_FIELD,  | 
140  |  |     UDAT_QUARTER_FIELD,  | 
141  |  |     UDAT_STANDALONE_QUARTER_FIELD,  | 
142  |  |     UDAT_YEAR_NAME_FIELD,  | 
143  |  |     UDAT_RELATED_YEAR_FIELD };  | 
144  |  | static const int8_t kDateFieldsCount = 16;  | 
145  |  |  | 
146  |  | static const UDateFormatField kTimeFields[] = { | 
147  |  |     UDAT_HOUR_OF_DAY1_FIELD,  | 
148  |  |     UDAT_HOUR_OF_DAY0_FIELD,  | 
149  |  |     UDAT_MINUTE_FIELD,  | 
150  |  |     UDAT_SECOND_FIELD,  | 
151  |  |     UDAT_FRACTIONAL_SECOND_FIELD,  | 
152  |  |     UDAT_HOUR1_FIELD,  | 
153  |  |     UDAT_HOUR0_FIELD,  | 
154  |  |     UDAT_MILLISECONDS_IN_DAY_FIELD,  | 
155  |  |     UDAT_TIMEZONE_RFC_FIELD,  | 
156  |  |     UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD };  | 
157  |  | static const int8_t kTimeFieldsCount = 10;  | 
158  |  |  | 
159  |  |  | 
160  |  | // This is a pattern-of-last-resort used when we can't load a usable pattern out  | 
161  |  | // of a resource.  | 
162  |  | static const UChar gDefaultPattern[] =  | 
163  |  | { | 
164  |  |     0x79, 0x79, 0x79, 0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0  | 
165  |  | };  /* "yyyyMMdd hh:mm a" */  | 
166  |  |  | 
167  |  | // This prefix is designed to NEVER MATCH real text, in order to  | 
168  |  | // suppress the parsing of negative numbers.  Adjust as needed (if  | 
169  |  | // this becomes valid Unicode).  | 
170  |  | static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0}; | 
171  |  |  | 
172  |  | /**  | 
173  |  |  * These are the tags we expect to see in normal resource bundle files associated  | 
174  |  |  * with a locale.  | 
175  |  |  */  | 
176  |  | static const UChar QUOTE = 0x27; // Single quote  | 
177  |  |  | 
178  |  | /*  | 
179  |  |  * The field range check bias for each UDateFormatField.  | 
180  |  |  * The bias is added to the minimum and maximum values  | 
181  |  |  * before they are compared to the parsed number.  | 
182  |  |  * For example, the calendar stores zero-based month numbers  | 
183  |  |  * but the parsed month numbers start at 1, so the bias is 1.  | 
184  |  |  *  | 
185  |  |  * A value of -1 means that the value is not checked.  | 
186  |  |  */  | 
187  |  | static const int32_t gFieldRangeBias[] = { | 
188  |  |     -1,  // 'G' - UDAT_ERA_FIELD  | 
189  |  |     -1,  // 'y' - UDAT_YEAR_FIELD  | 
190  |  |      1,  // 'M' - UDAT_MONTH_FIELD  | 
191  |  |      0,  // 'd' - UDAT_DATE_FIELD  | 
192  |  |     -1,  // 'k' - UDAT_HOUR_OF_DAY1_FIELD  | 
193  |  |     -1,  // 'H' - UDAT_HOUR_OF_DAY0_FIELD  | 
194  |  |      0,  // 'm' - UDAT_MINUTE_FIELD  | 
195  |  |      0,  // 's' - UDAT_SECOND_FIELD  | 
196  |  |     -1,  // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)  | 
197  |  |     -1,  // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)  | 
198  |  |     -1,  // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)  | 
199  |  |     -1,  // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?)  | 
200  |  |     -1,  // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?)  | 
201  |  |     -1,  // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?)  | 
202  |  |     -1,  // 'a' - UDAT_AM_PM_FIELD  | 
203  |  |     -1,  // 'h' - UDAT_HOUR1_FIELD  | 
204  |  |     -1,  // 'K' - UDAT_HOUR0_FIELD  | 
205  |  |     -1,  // 'z' - UDAT_TIMEZONE_FIELD  | 
206  |  |     -1,  // 'Y' - UDAT_YEAR_WOY_FIELD  | 
207  |  |     -1,  // 'e' - UDAT_DOW_LOCAL_FIELD  | 
208  |  |     -1,  // 'u' - UDAT_EXTENDED_YEAR_FIELD  | 
209  |  |     -1,  // 'g' - UDAT_JULIAN_DAY_FIELD  | 
210  |  |     -1,  // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD  | 
211  |  |     -1,  // 'Z' - UDAT_TIMEZONE_RFC_FIELD  | 
212  |  |     -1,  // 'v' - UDAT_TIMEZONE_GENERIC_FIELD  | 
213  |  |      0,  // 'c' - UDAT_STANDALONE_DAY_FIELD  | 
214  |  |      1,  // 'L' - UDAT_STANDALONE_MONTH_FIELD  | 
215  |  |     -1,  // 'Q' - UDAT_QUARTER_FIELD (1-4?)  | 
216  |  |     -1,  // 'q' - UDAT_STANDALONE_QUARTER_FIELD  | 
217  |  |     -1,  // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD  | 
218  |  |     -1,  // 'U' - UDAT_YEAR_NAME_FIELD  | 
219  |  |     -1,  // 'O' - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD  | 
220  |  |     -1,  // 'X' - UDAT_TIMEZONE_ISO_FIELD  | 
221  |  |     -1,  // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD  | 
222  |  |     -1,  // 'r' - UDAT_RELATED_YEAR_FIELD  | 
223  |  | #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR  | 
224  |  |     -1,  // ':' - UDAT_TIME_SEPARATOR_FIELD  | 
225  |  | #else  | 
226  |  |     -1,  // (no pattern character currently) - UDAT_TIME_SEPARATOR_FIELD  | 
227  |  | #endif  | 
228  |  | };  | 
229  |  |  | 
230  |  | // When calendar uses hebr numbering (i.e. he@calendar=hebrew),  | 
231  |  | // offset the years within the current millennium down to 1-999  | 
232  |  | static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;  | 
233  |  | static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;  | 
234  |  |  | 
235  |  | /**  | 
236  |  |  * Maximum range for detecting daylight offset of a time zone when parsed time zone  | 
237  |  |  * string indicates it's daylight saving time, but the detected time zone does not  | 
238  |  |  * observe daylight saving time at the parsed date.  | 
239  |  |  */  | 
240  |  | static const double MAX_DAYLIGHT_DETECTION_RANGE = 30*365*24*60*60*1000.0;  | 
241  |  |  | 
242  |  | static UMutex LOCK;  | 
243  |  |  | 
244  |  | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)  | 
245  |  |  | 
246  | 0  | SimpleDateFormat::NSOverride::~NSOverride() { | 
247  | 0  |     if (snf != NULL) { | 
248  | 0  |         snf->removeRef();  | 
249  | 0  |     }  | 
250  | 0  | }  | 
251  |  |  | 
252  |  |  | 
253  | 0  | void SimpleDateFormat::NSOverride::free() { | 
254  | 0  |     NSOverride *cur = this;  | 
255  | 0  |     while (cur) { | 
256  | 0  |         NSOverride *next_temp = cur->next;  | 
257  | 0  |         delete cur;  | 
258  | 0  |         cur = next_temp;  | 
259  | 0  |     }  | 
260  | 0  | }  | 
261  |  |  | 
262  |  | // no matter what the locale's default number format looked like, we want  | 
263  |  | // to modify it so that it doesn't use thousands separators, doesn't always  | 
264  |  | // show the decimal point, and recognizes integers only when parsing  | 
265  | 0  | static void fixNumberFormatForDates(NumberFormat &nf) { | 
266  | 0  |     nf.setGroupingUsed(FALSE);  | 
267  | 0  |     DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(&nf);  | 
268  | 0  |     if (decfmt != NULL) { | 
269  | 0  |         decfmt->setDecimalSeparatorAlwaysShown(FALSE);  | 
270  | 0  |     }  | 
271  | 0  |     nf.setParseIntegerOnly(TRUE);  | 
272  | 0  |     nf.setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"  | 
273  | 0  | }  | 
274  |  |  | 
275  |  | static const SharedNumberFormat *createSharedNumberFormat(  | 
276  | 0  |         NumberFormat *nfToAdopt) { | 
277  | 0  |     fixNumberFormatForDates(*nfToAdopt);  | 
278  | 0  |     const SharedNumberFormat *result = new SharedNumberFormat(nfToAdopt);  | 
279  | 0  |     if (result == NULL) { | 
280  | 0  |         delete nfToAdopt;  | 
281  | 0  |     }  | 
282  | 0  |     return result;  | 
283  | 0  | }  | 
284  |  |  | 
285  |  | static const SharedNumberFormat *createSharedNumberFormat(  | 
286  | 0  |         const Locale &loc, UErrorCode &status) { | 
287  | 0  |     NumberFormat *nf = NumberFormat::createInstance(loc, status);  | 
288  | 0  |     if (U_FAILURE(status)) { | 
289  | 0  |         return NULL;  | 
290  | 0  |     }  | 
291  | 0  |     const SharedNumberFormat *result = createSharedNumberFormat(nf);  | 
292  | 0  |     if (result == NULL) { | 
293  | 0  |         status = U_MEMORY_ALLOCATION_ERROR;  | 
294  | 0  |     }  | 
295  | 0  |     return result;  | 
296  | 0  | }  | 
297  |  |  | 
298  | 0  | static const SharedNumberFormat **allocSharedNumberFormatters() { | 
299  | 0  |     const SharedNumberFormat **result = (const SharedNumberFormat**)  | 
300  | 0  |             uprv_malloc(UDAT_FIELD_COUNT * sizeof(const SharedNumberFormat*));  | 
301  | 0  |     if (result == NULL) { | 
302  | 0  |         return NULL;  | 
303  | 0  |     }  | 
304  | 0  |     for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) { | 
305  | 0  |         result[i] = NULL;  | 
306  | 0  |     }  | 
307  | 0  |     return result;  | 
308  | 0  | }  | 
309  |  |  | 
310  | 0  | static void freeSharedNumberFormatters(const SharedNumberFormat ** list) { | 
311  | 0  |     for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) { | 
312  | 0  |         SharedObject::clearPtr(list[i]);  | 
313  | 0  |     }  | 
314  | 0  |     uprv_free(list);  | 
315  | 0  | }  | 
316  |  |  | 
317  |  | const NumberFormat *SimpleDateFormat::getNumberFormatByIndex(  | 
318  | 0  |         UDateFormatField index) const { | 
319  | 0  |     if (fSharedNumberFormatters == NULL ||  | 
320  | 0  |         fSharedNumberFormatters[index] == NULL) { | 
321  | 0  |         return fNumberFormat;  | 
322  | 0  |     }  | 
323  | 0  |     return &(**fSharedNumberFormatters[index]);  | 
324  | 0  | }  | 
325  |  |  | 
326  |  | //----------------------------------------------------------------------  | 
327  |  |  | 
328  |  | SimpleDateFormat::~SimpleDateFormat()  | 
329  | 0  | { | 
330  | 0  |     delete fSymbols;  | 
331  | 0  |     if (fSharedNumberFormatters) { | 
332  | 0  |         freeSharedNumberFormatters(fSharedNumberFormatters);  | 
333  | 0  |     }  | 
334  | 0  |     if (fTimeZoneFormat) { | 
335  | 0  |         delete fTimeZoneFormat;  | 
336  | 0  |     }  | 
337  | 0  |     freeFastNumberFormatters();  | 
338  |  | 
  | 
339  | 0  | #if !UCONFIG_NO_BREAK_ITERATION  | 
340  | 0  |     delete fCapitalizationBrkIter;  | 
341  | 0  | #endif  | 
342  | 0  | }  | 
343  |  |  | 
344  |  | //----------------------------------------------------------------------  | 
345  |  |  | 
346  |  | SimpleDateFormat::SimpleDateFormat(UErrorCode& status)  | 
347  | 0  |   :   fLocale(Locale::getDefault()),  | 
348  |  |       fSymbols(NULL),  | 
349  |  |       fTimeZoneFormat(NULL),  | 
350  |  |       fSharedNumberFormatters(NULL),  | 
351  |  |       fCapitalizationBrkIter(NULL)  | 
352  | 0  | { | 
353  | 0  |     initializeBooleanAttributes();  | 
354  | 0  |     construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);  | 
355  | 0  |     initializeDefaultCentury();  | 
356  | 0  | }  | 
357  |  |  | 
358  |  | //----------------------------------------------------------------------  | 
359  |  |  | 
360  |  | SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,  | 
361  |  |                                    UErrorCode &status)  | 
362  | 0  | :   fPattern(pattern),  | 
363  | 0  |     fLocale(Locale::getDefault()),  | 
364  |  |     fSymbols(NULL),  | 
365  |  |     fTimeZoneFormat(NULL),  | 
366  |  |     fSharedNumberFormatters(NULL),  | 
367  |  |     fCapitalizationBrkIter(NULL)  | 
368  | 0  | { | 
369  | 0  |     fDateOverride.setToBogus();  | 
370  | 0  |     fTimeOverride.setToBogus();  | 
371  | 0  |     initializeBooleanAttributes();  | 
372  | 0  |     initializeCalendar(NULL,fLocale,status);  | 
373  | 0  |     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);  | 
374  | 0  |     initialize(fLocale, status);  | 
375  | 0  |     initializeDefaultCentury();  | 
376  |  | 
  | 
377  | 0  | }  | 
378  |  | //----------------------------------------------------------------------  | 
379  |  |  | 
380  |  | SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,  | 
381  |  |                                    const UnicodeString& override,  | 
382  |  |                                    UErrorCode &status)  | 
383  | 0  | :   fPattern(pattern),  | 
384  | 0  |     fLocale(Locale::getDefault()),  | 
385  |  |     fSymbols(NULL),  | 
386  |  |     fTimeZoneFormat(NULL),  | 
387  |  |     fSharedNumberFormatters(NULL),  | 
388  |  |     fCapitalizationBrkIter(NULL)  | 
389  | 0  | { | 
390  | 0  |     fDateOverride.setTo(override);  | 
391  | 0  |     fTimeOverride.setToBogus();  | 
392  | 0  |     initializeBooleanAttributes();  | 
393  | 0  |     initializeCalendar(NULL,fLocale,status);  | 
394  | 0  |     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);  | 
395  | 0  |     initialize(fLocale, status);  | 
396  | 0  |     initializeDefaultCentury();  | 
397  |  | 
  | 
398  | 0  |     processOverrideString(fLocale,override,kOvrStrBoth,status);  | 
399  |  | 
  | 
400  | 0  | }  | 
401  |  |  | 
402  |  | //----------------------------------------------------------------------  | 
403  |  |  | 
404  |  | SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,  | 
405  |  |                                    const Locale& locale,  | 
406  |  |                                    UErrorCode& status)  | 
407  | 0  | :   fPattern(pattern),  | 
408  | 0  |     fLocale(locale),  | 
409  |  |     fTimeZoneFormat(NULL),  | 
410  |  |     fSharedNumberFormatters(NULL),  | 
411  |  |     fCapitalizationBrkIter(NULL)  | 
412  | 0  | { | 
413  |  | 
  | 
414  | 0  |     fDateOverride.setToBogus();  | 
415  | 0  |     fTimeOverride.setToBogus();  | 
416  | 0  |     initializeBooleanAttributes();  | 
417  |  | 
  | 
418  | 0  |     initializeCalendar(NULL,fLocale,status);  | 
419  | 0  |     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);  | 
420  | 0  |     initialize(fLocale, status);  | 
421  | 0  |     initializeDefaultCentury();  | 
422  | 0  | }  | 
423  |  |  | 
424  |  | //----------------------------------------------------------------------  | 
425  |  |  | 
426  |  | SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,  | 
427  |  |                                    const UnicodeString& override,  | 
428  |  |                                    const Locale& locale,  | 
429  |  |                                    UErrorCode& status)  | 
430  | 0  | :   fPattern(pattern),  | 
431  | 0  |     fLocale(locale),  | 
432  |  |     fTimeZoneFormat(NULL),  | 
433  |  |     fSharedNumberFormatters(NULL),  | 
434  |  |     fCapitalizationBrkIter(NULL)  | 
435  | 0  | { | 
436  |  | 
  | 
437  | 0  |     fDateOverride.setTo(override);  | 
438  | 0  |     fTimeOverride.setToBogus();  | 
439  | 0  |     initializeBooleanAttributes();  | 
440  |  | 
  | 
441  | 0  |     initializeCalendar(NULL,fLocale,status);  | 
442  | 0  |     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);  | 
443  | 0  |     initialize(fLocale, status);  | 
444  | 0  |     initializeDefaultCentury();  | 
445  |  | 
  | 
446  | 0  |     processOverrideString(locale,override,kOvrStrBoth,status);  | 
447  |  | 
  | 
448  | 0  | }  | 
449  |  |  | 
450  |  | //----------------------------------------------------------------------  | 
451  |  |  | 
452  |  | SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,  | 
453  |  |                                    DateFormatSymbols* symbolsToAdopt,  | 
454  |  |                                    UErrorCode& status)  | 
455  | 0  | :   fPattern(pattern),  | 
456  | 0  |     fLocale(Locale::getDefault()),  | 
457  | 0  |     fSymbols(symbolsToAdopt),  | 
458  |  |     fTimeZoneFormat(NULL),  | 
459  |  |     fSharedNumberFormatters(NULL),  | 
460  |  |     fCapitalizationBrkIter(NULL)  | 
461  | 0  | { | 
462  |  | 
  | 
463  | 0  |     fDateOverride.setToBogus();  | 
464  | 0  |     fTimeOverride.setToBogus();  | 
465  | 0  |     initializeBooleanAttributes();  | 
466  |  | 
  | 
467  | 0  |     initializeCalendar(NULL,fLocale,status);  | 
468  | 0  |     initialize(fLocale, status);  | 
469  | 0  |     initializeDefaultCentury();  | 
470  | 0  | }  | 
471  |  |  | 
472  |  | //----------------------------------------------------------------------  | 
473  |  |  | 
474  |  | SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,  | 
475  |  |                                    const DateFormatSymbols& symbols,  | 
476  |  |                                    UErrorCode& status)  | 
477  | 0  | :   fPattern(pattern),  | 
478  | 0  |     fLocale(Locale::getDefault()),  | 
479  | 0  |     fSymbols(new DateFormatSymbols(symbols)),  | 
480  |  |     fTimeZoneFormat(NULL),  | 
481  |  |     fSharedNumberFormatters(NULL),  | 
482  |  |     fCapitalizationBrkIter(NULL)  | 
483  | 0  | { | 
484  |  | 
  | 
485  | 0  |     fDateOverride.setToBogus();  | 
486  | 0  |     fTimeOverride.setToBogus();  | 
487  | 0  |     initializeBooleanAttributes();  | 
488  |  | 
  | 
489  | 0  |     initializeCalendar(NULL, fLocale, status);  | 
490  | 0  |     initialize(fLocale, status);  | 
491  | 0  |     initializeDefaultCentury();  | 
492  | 0  | }  | 
493  |  |  | 
494  |  | //----------------------------------------------------------------------  | 
495  |  |  | 
496  |  | // Not for public consumption; used by DateFormat  | 
497  |  | SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,  | 
498  |  |                                    EStyle dateStyle,  | 
499  |  |                                    const Locale& locale,  | 
500  |  |                                    UErrorCode& status)  | 
501  | 0  | :   fLocale(locale),  | 
502  |  |     fSymbols(NULL),  | 
503  |  |     fTimeZoneFormat(NULL),  | 
504  |  |     fSharedNumberFormatters(NULL),  | 
505  |  |     fCapitalizationBrkIter(NULL)  | 
506  | 0  | { | 
507  | 0  |     initializeBooleanAttributes();  | 
508  | 0  |     construct(timeStyle, dateStyle, fLocale, status);  | 
509  | 0  |     if(U_SUCCESS(status)) { | 
510  | 0  |       initializeDefaultCentury();  | 
511  | 0  |     }  | 
512  | 0  | }  | 
513  |  |  | 
514  |  | //----------------------------------------------------------------------  | 
515  |  |  | 
516  |  | /**  | 
517  |  |  * Not for public consumption; used by DateFormat.  This constructor  | 
518  |  |  * never fails.  If the resource data is not available, it uses the  | 
519  |  |  * the last resort symbols.  | 
520  |  |  */  | 
521  |  | SimpleDateFormat::SimpleDateFormat(const Locale& locale,  | 
522  |  |                                    UErrorCode& status)  | 
523  | 0  | :   fPattern(gDefaultPattern),  | 
524  | 0  |     fLocale(locale),  | 
525  |  |     fSymbols(NULL),  | 
526  |  |     fTimeZoneFormat(NULL),  | 
527  |  |     fSharedNumberFormatters(NULL),  | 
528  |  |     fCapitalizationBrkIter(NULL)  | 
529  | 0  | { | 
530  | 0  |     if (U_FAILURE(status)) return;  | 
531  | 0  |     initializeBooleanAttributes();  | 
532  | 0  |     initializeCalendar(NULL, fLocale, status);  | 
533  | 0  |     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);  | 
534  | 0  |     if (U_FAILURE(status))  | 
535  | 0  |     { | 
536  | 0  |         status = U_ZERO_ERROR;  | 
537  | 0  |         delete fSymbols;  | 
538  |  |         // This constructor doesn't fail; it uses last resort data  | 
539  | 0  |         fSymbols = new DateFormatSymbols(status);  | 
540  |  |         /* test for NULL */  | 
541  | 0  |         if (fSymbols == 0) { | 
542  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
543  | 0  |             return;  | 
544  | 0  |         }  | 
545  | 0  |     }  | 
546  |  |  | 
547  | 0  |     fDateOverride.setToBogus();  | 
548  | 0  |     fTimeOverride.setToBogus();  | 
549  |  | 
  | 
550  | 0  |     initialize(fLocale, status);  | 
551  | 0  |     if(U_SUCCESS(status)) { | 
552  | 0  |       initializeDefaultCentury();  | 
553  | 0  |     }  | 
554  | 0  | }  | 
555  |  |  | 
556  |  | //----------------------------------------------------------------------  | 
557  |  |  | 
558  |  | SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)  | 
559  | 0  | :   DateFormat(other),  | 
560  | 0  |     fLocale(other.fLocale),  | 
561  |  |     fSymbols(NULL),  | 
562  |  |     fTimeZoneFormat(NULL),  | 
563  |  |     fSharedNumberFormatters(NULL),  | 
564  |  |     fCapitalizationBrkIter(NULL)  | 
565  | 0  | { | 
566  | 0  |     initializeBooleanAttributes();  | 
567  | 0  |     *this = other;  | 
568  | 0  | }  | 
569  |  |  | 
570  |  | //----------------------------------------------------------------------  | 
571  |  |  | 
572  |  | SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)  | 
573  | 0  | { | 
574  | 0  |     if (this == &other) { | 
575  | 0  |         return *this;  | 
576  | 0  |     }  | 
577  | 0  |     DateFormat::operator=(other);  | 
578  | 0  |     fDateOverride = other.fDateOverride;  | 
579  | 0  |     fTimeOverride = other.fTimeOverride;  | 
580  |  | 
  | 
581  | 0  |     delete fSymbols;  | 
582  | 0  |     fSymbols = NULL;  | 
583  |  | 
  | 
584  | 0  |     if (other.fSymbols)  | 
585  | 0  |         fSymbols = new DateFormatSymbols(*other.fSymbols);  | 
586  |  | 
  | 
587  | 0  |     fDefaultCenturyStart         = other.fDefaultCenturyStart;  | 
588  | 0  |     fDefaultCenturyStartYear     = other.fDefaultCenturyStartYear;  | 
589  | 0  |     fHaveDefaultCentury          = other.fHaveDefaultCentury;  | 
590  |  | 
  | 
591  | 0  |     fPattern = other.fPattern;  | 
592  | 0  |     fHasMinute = other.fHasMinute;  | 
593  | 0  |     fHasSecond = other.fHasSecond;  | 
594  |  | 
  | 
595  | 0  |     fLocale = other.fLocale;  | 
596  |  |  | 
597  |  |     // TimeZoneFormat can now be set independently via setter.  | 
598  |  |     // If it is NULL, it will be lazily initialized from locale.  | 
599  | 0  |     delete fTimeZoneFormat;  | 
600  | 0  |     fTimeZoneFormat = nullptr;  | 
601  | 0  |     TimeZoneFormat *otherTZFormat;  | 
602  | 0  |     { | 
603  |  |         // Synchronization is required here, when accessing other.fTimeZoneFormat,  | 
604  |  |         // because another thread may be concurrently executing other.tzFormat(),  | 
605  |  |         // a logically const function that lazily creates other.fTimeZoneFormat.  | 
606  |  |         //  | 
607  |  |         // Without synchronization, reordered memory writes could allow us  | 
608  |  |         // to see a non-null fTimeZoneFormat before the object itself was  | 
609  |  |         // fully initialized. In case of a race, it doesn't matter whether  | 
610  |  |         // we see a null or a fully initialized other.fTimeZoneFormat,  | 
611  |  |         // only that we avoid seeing a partially initialized object.  | 
612  |  |         //  | 
613  |  |         // Once initialized, no const function can modify fTimeZoneFormat,  | 
614  |  |         // meaning that once we have safely grabbed the other.fTimeZoneFormat  | 
615  |  |         // pointer, continued synchronization is not required to use it.  | 
616  | 0  |         Mutex m(&LOCK);  | 
617  | 0  |         otherTZFormat = other.fTimeZoneFormat;  | 
618  | 0  |     }  | 
619  | 0  |     if (otherTZFormat) { | 
620  | 0  |         fTimeZoneFormat = new TimeZoneFormat(*otherTZFormat);  | 
621  | 0  |     }  | 
622  |  | 
  | 
623  | 0  | #if !UCONFIG_NO_BREAK_ITERATION  | 
624  | 0  |     if (other.fCapitalizationBrkIter != NULL) { | 
625  | 0  |         fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();  | 
626  | 0  |     }  | 
627  | 0  | #endif  | 
628  |  | 
  | 
629  | 0  |     if (fSharedNumberFormatters != NULL) { | 
630  | 0  |         freeSharedNumberFormatters(fSharedNumberFormatters);  | 
631  | 0  |         fSharedNumberFormatters = NULL;  | 
632  | 0  |     }  | 
633  | 0  |     if (other.fSharedNumberFormatters != NULL) { | 
634  | 0  |         fSharedNumberFormatters = allocSharedNumberFormatters();  | 
635  | 0  |         if (fSharedNumberFormatters) { | 
636  | 0  |             for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) { | 
637  | 0  |                 SharedObject::copyPtr(  | 
638  | 0  |                         other.fSharedNumberFormatters[i],  | 
639  | 0  |                         fSharedNumberFormatters[i]);  | 
640  | 0  |             }  | 
641  | 0  |         }  | 
642  | 0  |     }  | 
643  |  | 
  | 
644  | 0  |     UErrorCode localStatus = U_ZERO_ERROR;  | 
645  | 0  |     freeFastNumberFormatters();  | 
646  | 0  |     initFastNumberFormatters(localStatus);  | 
647  |  | 
  | 
648  | 0  |     return *this;  | 
649  | 0  | }  | 
650  |  |  | 
651  |  | //----------------------------------------------------------------------  | 
652  |  |  | 
653  |  | SimpleDateFormat*  | 
654  |  | SimpleDateFormat::clone() const  | 
655  | 0  | { | 
656  | 0  |     return new SimpleDateFormat(*this);  | 
657  | 0  | }  | 
658  |  |  | 
659  |  | //----------------------------------------------------------------------  | 
660  |  |  | 
661  |  | bool  | 
662  |  | SimpleDateFormat::operator==(const Format& other) const  | 
663  | 0  | { | 
664  | 0  |     if (DateFormat::operator==(other)) { | 
665  |  |         // The DateFormat::operator== check for fCapitalizationContext equality above  | 
666  |  |         //   is sufficient to check equality of all derived context-related data.  | 
667  |  |         // DateFormat::operator== guarantees following cast is safe  | 
668  | 0  |         SimpleDateFormat* that = (SimpleDateFormat*)&other;  | 
669  | 0  |         return (fPattern             == that->fPattern &&  | 
670  | 0  |                 fSymbols             != NULL && // Check for pathological object  | 
671  | 0  |                 that->fSymbols       != NULL && // Check for pathological object  | 
672  | 0  |                 *fSymbols            == *that->fSymbols &&  | 
673  | 0  |                 fHaveDefaultCentury  == that->fHaveDefaultCentury &&  | 
674  | 0  |                 fDefaultCenturyStart == that->fDefaultCenturyStart);  | 
675  | 0  |     }  | 
676  | 0  |     return FALSE;  | 
677  | 0  | }  | 
678  |  |  | 
679  |  | //----------------------------------------------------------------------  | 
680  |  | static const UChar* timeSkeletons[4] = { | 
681  |  |     u"jmmsszzzz",   // kFull  | 
682  |  |     u"jmmssz",      // kLong  | 
683  |  |     u"jmmss",       // kMedium  | 
684  |  |     u"jmm",         // kShort  | 
685  |  | };  | 
686  |  |  | 
687  |  | void SimpleDateFormat::construct(EStyle timeStyle,  | 
688  |  |                                  EStyle dateStyle,  | 
689  |  |                                  const Locale& locale,  | 
690  |  |                                  UErrorCode& status)  | 
691  | 0  | { | 
692  |  |     // called by several constructors to load pattern data from the resources  | 
693  | 0  |     if (U_FAILURE(status)) return;  | 
694  |  |  | 
695  |  |     // We will need the calendar to know what type of symbols to load.  | 
696  | 0  |     initializeCalendar(NULL, locale, status);  | 
697  | 0  |     if (U_FAILURE(status)) return;  | 
698  |  |  | 
699  |  |     // Load date time patterns directly from resources.  | 
700  | 0  |     const char* cType = fCalendar ? fCalendar->getType() : NULL;  | 
701  | 0  |     LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getBaseName(), &status));  | 
702  | 0  |     if (U_FAILURE(status)) return;  | 
703  |  |  | 
704  | 0  |     UBool cTypeIsGregorian = TRUE;  | 
705  | 0  |     LocalUResourceBundlePointer dateTimePatterns;  | 
706  | 0  |     if (cType != NULL && uprv_strcmp(cType, "gregorian") != 0) { | 
707  | 0  |         CharString resourcePath("calendar/", status); | 
708  | 0  |         resourcePath.append(cType, status).append("/DateTimePatterns", status); | 
709  | 0  |         dateTimePatterns.adoptInstead(  | 
710  | 0  |             ures_getByKeyWithFallback(bundle.getAlias(), resourcePath.data(),  | 
711  | 0  |                                       (UResourceBundle*)NULL, &status));  | 
712  | 0  |         cTypeIsGregorian = FALSE;  | 
713  | 0  |     }  | 
714  |  |  | 
715  |  |     // Check for "gregorian" fallback.  | 
716  | 0  |     if (cTypeIsGregorian || status == U_MISSING_RESOURCE_ERROR) { | 
717  | 0  |         status = U_ZERO_ERROR;  | 
718  | 0  |         dateTimePatterns.adoptInstead(  | 
719  | 0  |             ures_getByKeyWithFallback(bundle.getAlias(),  | 
720  | 0  |                                       "calendar/gregorian/DateTimePatterns",  | 
721  | 0  |                                       (UResourceBundle*)NULL, &status));  | 
722  | 0  |     }  | 
723  | 0  |     if (U_FAILURE(status)) return;  | 
724  |  |  | 
725  | 0  |     LocalUResourceBundlePointer currentBundle;  | 
726  |  | 
  | 
727  | 0  |     if (ures_getSize(dateTimePatterns.getAlias()) <= kDateTime)  | 
728  | 0  |     { | 
729  | 0  |         status = U_INVALID_FORMAT_ERROR;  | 
730  | 0  |         return;  | 
731  | 0  |     }  | 
732  |  |  | 
733  | 0  |     setLocaleIDs(ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_VALID_LOCALE, &status),  | 
734  | 0  |                  ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_ACTUAL_LOCALE, &status));  | 
735  |  |  | 
736  |  |     // create a symbols object from the locale  | 
737  | 0  |     fSymbols = DateFormatSymbols::createForLocale(locale, status);  | 
738  | 0  |     if (U_FAILURE(status)) return;  | 
739  |  |     /* test for NULL */  | 
740  | 0  |     if (fSymbols == 0) { | 
741  | 0  |         status = U_MEMORY_ALLOCATION_ERROR;  | 
742  | 0  |         return;  | 
743  | 0  |     }  | 
744  |  |  | 
745  | 0  |     const UChar *resStr,*ovrStr;  | 
746  | 0  |     int32_t resStrLen,ovrStrLen = 0;  | 
747  | 0  |     fDateOverride.setToBogus();  | 
748  | 0  |     fTimeOverride.setToBogus();  | 
749  |  | 
  | 
750  | 0  |     UnicodeString timePattern;  | 
751  | 0  |     if (timeStyle >= kFull && timeStyle <= kShort) { | 
752  | 0  |         const char* baseLocID = locale.getBaseName();  | 
753  | 0  |         if (baseLocID[0]!=0 && uprv_strcmp(baseLocID,"und")!=0) { | 
754  | 0  |             UErrorCode useStatus = U_ZERO_ERROR;  | 
755  | 0  |             Locale baseLoc(baseLocID);  | 
756  | 0  |             Locale validLoc(getLocale(ULOC_VALID_LOCALE, useStatus));  | 
757  | 0  |             if (U_SUCCESS(useStatus) && validLoc!=baseLoc) { | 
758  | 0  |                 bool useDTPG = false;  | 
759  | 0  |                 const char* baseReg = baseLoc.getCountry(); // empty string if no region  | 
760  | 0  |                 if ((baseReg[0]!=0 && uprv_strncmp(baseReg,validLoc.getCountry(),ULOC_COUNTRY_CAPACITY)!=0)  | 
761  | 0  |                         || uprv_strncmp(baseLoc.getLanguage(),validLoc.getLanguage(),ULOC_LANG_CAPACITY)!=0) { | 
762  |  |                     // use DTPG if  | 
763  |  |                     // * baseLoc has a region and validLoc does not have the same one (or has none), OR  | 
764  |  |                     // * validLoc has a different language code than baseLoc  | 
765  | 0  |                     useDTPG = true;  | 
766  | 0  |                 }  | 
767  | 0  |                 if (useDTPG) { | 
768  |  |                     // The standard time formats may have the wrong time cycle, because:  | 
769  |  |                     // the valid locale differs in important ways (region, language) from  | 
770  |  |                     // the base locale.  | 
771  |  |                     // We could *also* check whether they do actually have a mismatch with  | 
772  |  |                     // the time cycle preferences for the region, but that is a lot more  | 
773  |  |                     // work for little or no additional benefit, since just going ahead  | 
774  |  |                     // and always synthesizing the time format as per the following should  | 
775  |  |                     // create a locale-appropriate pattern with cycle that matches the  | 
776  |  |                     // region preferences anyway.  | 
777  | 0  |                     LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstanceNoStdPat(locale, useStatus));  | 
778  | 0  |                     if (U_SUCCESS(useStatus)) { | 
779  | 0  |                         UnicodeString timeSkeleton(TRUE, timeSkeletons[timeStyle], -1);  | 
780  | 0  |                         timePattern = dtpg->getBestPattern(timeSkeleton, useStatus);  | 
781  | 0  |                     }  | 
782  | 0  |                 }  | 
783  | 0  |             }  | 
784  | 0  |         }  | 
785  | 0  |     }  | 
786  |  |  | 
787  |  |     // if the pattern should include both date and time information, use the date/time  | 
788  |  |     // pattern string as a guide to tell use how to glue together the appropriate date  | 
789  |  |     // and time pattern strings.  | 
790  | 0  |     if ((timeStyle != kNone) && (dateStyle != kNone))  | 
791  | 0  |     { | 
792  | 0  |         UnicodeString tempus1(timePattern);  | 
793  | 0  |         if (tempus1.length() == 0) { | 
794  | 0  |             currentBundle.adoptInstead(  | 
795  | 0  |                     ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));  | 
796  | 0  |             if (U_FAILURE(status)) { | 
797  | 0  |                status = U_INVALID_FORMAT_ERROR;  | 
798  | 0  |                return;  | 
799  | 0  |             }  | 
800  | 0  |             switch (ures_getType(currentBundle.getAlias())) { | 
801  | 0  |                 case URES_STRING: { | 
802  | 0  |                    resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);  | 
803  | 0  |                    break;  | 
804  | 0  |                 }  | 
805  | 0  |                 case URES_ARRAY: { | 
806  | 0  |                    resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);  | 
807  | 0  |                    ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);  | 
808  | 0  |                    fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen);  | 
809  | 0  |                    break;  | 
810  | 0  |                 }  | 
811  | 0  |                 default: { | 
812  | 0  |                    status = U_INVALID_FORMAT_ERROR;  | 
813  | 0  |                    return;  | 
814  | 0  |                 }  | 
815  | 0  |             }  | 
816  |  |  | 
817  | 0  |             tempus1.setTo(TRUE, resStr, resStrLen);  | 
818  | 0  |         }  | 
819  |  |  | 
820  | 0  |         currentBundle.adoptInstead(  | 
821  | 0  |                 ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));  | 
822  | 0  |         if (U_FAILURE(status)) { | 
823  | 0  |            status = U_INVALID_FORMAT_ERROR;  | 
824  | 0  |            return;  | 
825  | 0  |         }  | 
826  | 0  |         switch (ures_getType(currentBundle.getAlias())) { | 
827  | 0  |             case URES_STRING: { | 
828  | 0  |                resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);  | 
829  | 0  |                break;  | 
830  | 0  |             }  | 
831  | 0  |             case URES_ARRAY: { | 
832  | 0  |                resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);  | 
833  | 0  |                ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);  | 
834  | 0  |                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);  | 
835  | 0  |                break;  | 
836  | 0  |             }  | 
837  | 0  |             default: { | 
838  | 0  |                status = U_INVALID_FORMAT_ERROR;  | 
839  | 0  |                return;  | 
840  | 0  |             }  | 
841  | 0  |         }  | 
842  |  |  | 
843  | 0  |         UnicodeString tempus2(TRUE, resStr, resStrLen);  | 
844  |  | 
  | 
845  | 0  |         int32_t glueIndex = kDateTime;  | 
846  | 0  |         int32_t patternsSize = ures_getSize(dateTimePatterns.getAlias());  | 
847  | 0  |         if (patternsSize >= (kDateTimeOffset + kShort + 1)) { | 
848  |  |             // Get proper date time format  | 
849  | 0  |             glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));  | 
850  | 0  |         }  | 
851  |  | 
  | 
852  | 0  |         resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), glueIndex, &resStrLen, &status);  | 
853  | 0  |         SimpleFormatter(UnicodeString(TRUE, resStr, resStrLen), 2, 2, status).  | 
854  | 0  |                 format(tempus1, tempus2, fPattern, status);  | 
855  | 0  |     }  | 
856  |  |     // if the pattern includes just time data or just date date, load the appropriate  | 
857  |  |     // pattern string from the resources  | 
858  |  |     // setTo() - see DateFormatSymbols::assignArray comments  | 
859  | 0  |     else if (timeStyle != kNone) { | 
860  | 0  |         fPattern.setTo(timePattern);  | 
861  | 0  |         if (fPattern.length() == 0) { | 
862  | 0  |             currentBundle.adoptInstead(  | 
863  | 0  |                     ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));  | 
864  | 0  |             if (U_FAILURE(status)) { | 
865  | 0  |                status = U_INVALID_FORMAT_ERROR;  | 
866  | 0  |                return;  | 
867  | 0  |             }  | 
868  | 0  |             switch (ures_getType(currentBundle.getAlias())) { | 
869  | 0  |                 case URES_STRING: { | 
870  | 0  |                    resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);  | 
871  | 0  |                    break;  | 
872  | 0  |                 }  | 
873  | 0  |                 case URES_ARRAY: { | 
874  | 0  |                    resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);  | 
875  | 0  |                    ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);  | 
876  | 0  |                    fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);  | 
877  | 0  |                    break;  | 
878  | 0  |                 }  | 
879  | 0  |                 default: { | 
880  | 0  |                    status = U_INVALID_FORMAT_ERROR;  | 
881  | 0  |                    return;  | 
882  | 0  |                 }  | 
883  | 0  |             }  | 
884  | 0  |             fPattern.setTo(TRUE, resStr, resStrLen);  | 
885  | 0  |         }  | 
886  | 0  |     }  | 
887  | 0  |     else if (dateStyle != kNone) { | 
888  | 0  |         currentBundle.adoptInstead(  | 
889  | 0  |                 ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));  | 
890  | 0  |         if (U_FAILURE(status)) { | 
891  | 0  |            status = U_INVALID_FORMAT_ERROR;  | 
892  | 0  |            return;  | 
893  | 0  |         }  | 
894  | 0  |         switch (ures_getType(currentBundle.getAlias())) { | 
895  | 0  |             case URES_STRING: { | 
896  | 0  |                resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);  | 
897  | 0  |                break;  | 
898  | 0  |             }  | 
899  | 0  |             case URES_ARRAY: { | 
900  | 0  |                resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);  | 
901  | 0  |                ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);  | 
902  | 0  |                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);  | 
903  | 0  |                break;  | 
904  | 0  |             }  | 
905  | 0  |             default: { | 
906  | 0  |                status = U_INVALID_FORMAT_ERROR;  | 
907  | 0  |                return;  | 
908  | 0  |             }  | 
909  | 0  |         }  | 
910  | 0  |         fPattern.setTo(TRUE, resStr, resStrLen);  | 
911  | 0  |     }  | 
912  |  |  | 
913  |  |     // and if it includes _neither_, that's an error  | 
914  | 0  |     else  | 
915  | 0  |         status = U_INVALID_FORMAT_ERROR;  | 
916  |  |  | 
917  |  |     // finally, finish initializing by creating a Calendar and a NumberFormat  | 
918  | 0  |     initialize(locale, status);  | 
919  | 0  | }  | 
920  |  |  | 
921  |  | //----------------------------------------------------------------------  | 
922  |  |  | 
923  |  | Calendar*  | 
924  |  | SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)  | 
925  | 0  | { | 
926  | 0  |     if(!U_FAILURE(status)) { | 
927  | 0  |         fCalendar = Calendar::createInstance(  | 
928  | 0  |             adoptZone ? adoptZone : TimeZone::forLocaleOrDefault(locale), locale, status);  | 
929  | 0  |     }  | 
930  | 0  |     return fCalendar;  | 
931  | 0  | }  | 
932  |  |  | 
933  |  | void  | 
934  |  | SimpleDateFormat::initialize(const Locale& locale,  | 
935  |  |                              UErrorCode& status)  | 
936  | 0  | { | 
937  | 0  |     if (U_FAILURE(status)) return;  | 
938  |  |  | 
939  | 0  |     parsePattern(); // Need this before initNumberFormatters(), to set fHasHanYearChar  | 
940  |  |  | 
941  |  |     // Simple-minded hack to force Gannen year numbering for ja@calendar=japanese  | 
942  |  |     // if format is non-numeric (includes 年) and fDateOverride is not already specified.  | 
943  |  |     // Now this does get updated if applyPattern subsequently changes the pattern type.  | 
944  | 0  |     if (fDateOverride.isBogus() && fHasHanYearChar &&  | 
945  | 0  |             fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&  | 
946  | 0  |             uprv_strcmp(fLocale.getLanguage(),"ja") == 0) { | 
947  | 0  |         fDateOverride.setTo(u"y=jpanyear", -1);  | 
948  | 0  |     }  | 
949  |  |  | 
950  |  |     // We don't need to check that the row count is >= 1, since all 2d arrays have at  | 
951  |  |     // least one row  | 
952  | 0  |     fNumberFormat = NumberFormat::createInstance(locale, status);  | 
953  | 0  |     if (fNumberFormat != NULL && U_SUCCESS(status))  | 
954  | 0  |     { | 
955  | 0  |         fixNumberFormatForDates(*fNumberFormat);  | 
956  |  |         //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse  | 
957  |  | 
  | 
958  | 0  |         initNumberFormatters(locale, status);  | 
959  | 0  |         initFastNumberFormatters(status);  | 
960  |  | 
  | 
961  | 0  |     }  | 
962  | 0  |     else if (U_SUCCESS(status))  | 
963  | 0  |     { | 
964  | 0  |         status = U_MISSING_RESOURCE_ERROR;  | 
965  | 0  |     }  | 
966  | 0  | }  | 
967  |  |  | 
968  |  | /* Initialize the fields we use to disambiguate ambiguous years. Separate  | 
969  |  |  * so we can call it from readObject().  | 
970  |  |  */  | 
971  |  | void SimpleDateFormat::initializeDefaultCentury()  | 
972  | 0  | { | 
973  | 0  |   if(fCalendar) { | 
974  | 0  |     fHaveDefaultCentury = fCalendar->haveDefaultCentury();  | 
975  | 0  |     if(fHaveDefaultCentury) { | 
976  | 0  |       fDefaultCenturyStart = fCalendar->defaultCenturyStart();  | 
977  | 0  |       fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();  | 
978  | 0  |     } else { | 
979  | 0  |       fDefaultCenturyStart = DBL_MIN;  | 
980  | 0  |       fDefaultCenturyStartYear = -1;  | 
981  | 0  |     }  | 
982  | 0  |   }  | 
983  | 0  | }  | 
984  |  |  | 
985  |  | /*  | 
986  |  |  * Initialize the boolean attributes. Separate so we can call it from all constructors.  | 
987  |  |  */  | 
988  |  | void SimpleDateFormat::initializeBooleanAttributes()  | 
989  | 0  | { | 
990  | 0  |     UErrorCode status = U_ZERO_ERROR;  | 
991  |  | 
  | 
992  | 0  |     setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status);  | 
993  | 0  |     setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status);  | 
994  | 0  |     setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, true, status);  | 
995  | 0  |     setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, true, status);  | 
996  | 0  | }  | 
997  |  |  | 
998  |  | /* Define one-century window into which to disambiguate dates using  | 
999  |  |  * two-digit years. Make public in JDK 1.2.  | 
1000  |  |  */  | 
1001  |  | void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)  | 
1002  | 0  | { | 
1003  | 0  |     if(U_FAILURE(status)) { | 
1004  | 0  |         return;  | 
1005  | 0  |     }  | 
1006  | 0  |     if(!fCalendar) { | 
1007  | 0  |       status = U_ILLEGAL_ARGUMENT_ERROR;  | 
1008  | 0  |       return;  | 
1009  | 0  |     }  | 
1010  |  |  | 
1011  | 0  |     fCalendar->setTime(startDate, status);  | 
1012  | 0  |     if(U_SUCCESS(status)) { | 
1013  | 0  |         fHaveDefaultCentury = TRUE;  | 
1014  | 0  |         fDefaultCenturyStart = startDate;  | 
1015  | 0  |         fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);  | 
1016  | 0  |     }  | 
1017  | 0  | }  | 
1018  |  |  | 
1019  |  | //----------------------------------------------------------------------  | 
1020  |  |  | 
1021  |  | UnicodeString&  | 
1022  |  | SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const  | 
1023  | 0  | { | 
1024  | 0  |   UErrorCode status = U_ZERO_ERROR;  | 
1025  | 0  |   FieldPositionOnlyHandler handler(pos);  | 
1026  | 0  |   return _format(cal, appendTo, handler, status);  | 
1027  | 0  | }  | 
1028  |  |  | 
1029  |  | //----------------------------------------------------------------------  | 
1030  |  |  | 
1031  |  | UnicodeString&  | 
1032  |  | SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,  | 
1033  |  |                          FieldPositionIterator* posIter, UErrorCode& status) const  | 
1034  | 0  | { | 
1035  | 0  |   FieldPositionIteratorHandler handler(posIter, status);  | 
1036  | 0  |   return _format(cal, appendTo, handler, status);  | 
1037  | 0  | }  | 
1038  |  |  | 
1039  |  | //----------------------------------------------------------------------  | 
1040  |  |  | 
1041  |  | UnicodeString&  | 
1042  |  | SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,  | 
1043  |  |                             FieldPositionHandler& handler, UErrorCode& status) const  | 
1044  | 0  | { | 
1045  | 0  |     if ( U_FAILURE(status) ) { | 
1046  | 0  |        return appendTo;  | 
1047  | 0  |     }  | 
1048  | 0  |     Calendar* workCal = &cal;  | 
1049  | 0  |     Calendar* calClone = NULL;  | 
1050  | 0  |     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) { | 
1051  |  |         // Different calendar type  | 
1052  |  |         // We use the time and time zone from the input calendar, but  | 
1053  |  |         // do not use the input calendar for field calculation.  | 
1054  | 0  |         calClone = fCalendar->clone();  | 
1055  | 0  |         if (calClone != NULL) { | 
1056  | 0  |             UDate t = cal.getTime(status);  | 
1057  | 0  |             calClone->setTime(t, status);  | 
1058  | 0  |             calClone->setTimeZone(cal.getTimeZone());  | 
1059  | 0  |             workCal = calClone;  | 
1060  | 0  |         } else { | 
1061  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
1062  | 0  |             return appendTo;  | 
1063  | 0  |         }  | 
1064  | 0  |     }  | 
1065  |  |  | 
1066  | 0  |     UBool inQuote = FALSE;  | 
1067  | 0  |     UChar prevCh = 0;  | 
1068  | 0  |     int32_t count = 0;  | 
1069  | 0  |     int32_t fieldNum = 0;  | 
1070  | 0  |     UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);  | 
1071  |  |  | 
1072  |  |     // loop through the pattern string character by character  | 
1073  | 0  |     for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) { | 
1074  | 0  |         UChar ch = fPattern[i];  | 
1075  |  |  | 
1076  |  |         // Use subFormat() to format a repeated pattern character  | 
1077  |  |         // when a different pattern or non-pattern character is seen  | 
1078  | 0  |         if (ch != prevCh && count > 0) { | 
1079  | 0  |             subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,  | 
1080  | 0  |                       prevCh, handler, *workCal, status);  | 
1081  | 0  |             count = 0;  | 
1082  | 0  |         }  | 
1083  | 0  |         if (ch == QUOTE) { | 
1084  |  |             // Consecutive single quotes are a single quote literal,  | 
1085  |  |             // either outside of quotes or between quotes  | 
1086  | 0  |             if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) { | 
1087  | 0  |                 appendTo += (UChar)QUOTE;  | 
1088  | 0  |                 ++i;  | 
1089  | 0  |             } else { | 
1090  | 0  |                 inQuote = ! inQuote;  | 
1091  | 0  |             }  | 
1092  | 0  |         }  | 
1093  | 0  |         else if (!inQuote && isSyntaxChar(ch)) { | 
1094  |  |             // ch is a date-time pattern character to be interpreted  | 
1095  |  |             // by subFormat(); count the number of times it is repeated  | 
1096  | 0  |             prevCh = ch;  | 
1097  | 0  |             ++count;  | 
1098  | 0  |         }  | 
1099  | 0  |         else { | 
1100  |  |             // Append quoted characters and unquoted non-pattern characters  | 
1101  | 0  |             appendTo += ch;  | 
1102  | 0  |         }  | 
1103  | 0  |     }  | 
1104  |  |  | 
1105  |  |     // Format the last item in the pattern, if any  | 
1106  | 0  |     if (count > 0) { | 
1107  | 0  |         subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,  | 
1108  | 0  |                   prevCh, handler, *workCal, status);  | 
1109  | 0  |     }  | 
1110  |  | 
  | 
1111  | 0  |     if (calClone != NULL) { | 
1112  | 0  |         delete calClone;  | 
1113  | 0  |     }  | 
1114  |  | 
  | 
1115  | 0  |     return appendTo;  | 
1116  | 0  | }  | 
1117  |  |  | 
1118  |  | //----------------------------------------------------------------------  | 
1119  |  |  | 
1120  |  | /* Map calendar field into calendar field level.  | 
1121  |  |  * the larger the level, the smaller the field unit.  | 
1122  |  |  * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10,  | 
1123  |  |  * UCAL_MONTH level is 20.  | 
1124  |  |  * NOTE: if new fields adds in, the table needs to update.  | 
1125  |  |  */  | 
1126  |  | const int32_t  | 
1127  |  | SimpleDateFormat::fgCalendarFieldToLevel[] =  | 
1128  |  | { | 
1129  |  |     /*GyM*/ 0, 10, 20,  | 
1130  |  |     /*wW*/ 20, 30,  | 
1131  |  |     /*dDEF*/ 30, 20, 30, 30,  | 
1132  |  |     /*ahHm*/ 40, 50, 50, 60,  | 
1133  |  |     /*sS*/ 70, 80,  | 
1134  |  |     /*z?Y*/ 0, 0, 10,  | 
1135  |  |     /*eug*/ 30, 10, 0,  | 
1136  |  |     /*A?.*/ 40, 0, 0  | 
1137  |  | };  | 
1138  |  |  | 
1139  | 0  | int32_t SimpleDateFormat::getLevelFromChar(UChar ch) { | 
1140  |  |     // Map date field LETTER into calendar field level.  | 
1141  |  |     // the larger the level, the smaller the field unit.  | 
1142  |  |     // NOTE: if new fields adds in, the table needs to update.  | 
1143  | 0  |     static const int32_t mapCharToLevel[] = { | 
1144  | 0  |             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  | 
1145  |  |         //  | 
1146  | 0  |             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  | 
1147  |  |         //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /  | 
1148  | 0  |             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  | 
1149  |  | #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR  | 
1150  |  |         //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?  | 
1151  |  |             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1, -1, -1,  | 
1152  |  | #else  | 
1153  |  |         //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?  | 
1154  | 0  |             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  | 
1155  | 0  | #endif  | 
1156  |  |         //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O  | 
1157  | 0  |             -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1,  0,  | 
1158  |  |         //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _  | 
1159  | 0  |             -1, 20, -1, 80, -1, 10,  0, 30,  0, 10,  0, -1, -1, -1, -1, -1,  | 
1160  |  |         //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o  | 
1161  | 0  |             -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50,  0, 60, -1, -1,  | 
1162  |  |         //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~ | 
1163  | 0  |             -1, 20, 10, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1  | 
1164  | 0  |     };  | 
1165  |  | 
  | 
1166  | 0  |     return ch < UPRV_LENGTHOF(mapCharToLevel) ? mapCharToLevel[ch] : -1;  | 
1167  | 0  | }  | 
1168  |  |  | 
1169  | 0  | UBool SimpleDateFormat::isSyntaxChar(UChar ch) { | 
1170  | 0  |     static const UBool mapCharToIsSyntax[] = { | 
1171  |  |         //  | 
1172  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1173  |  |         //  | 
1174  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1175  |  |         //  | 
1176  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1177  |  |         //  | 
1178  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1179  |  |         //         !      "      #      $      %      &      '  | 
1180  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1181  |  |         //  (      )      *      +      ,      -      .      /  | 
1182  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1183  |  |         //  0      1      2      3      4      5      6      7  | 
1184  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1185  |  | #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR  | 
1186  |  |         //  8      9      :      ;      <      =      >      ?  | 
1187  |  |         FALSE, FALSE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1188  |  | #else  | 
1189  |  |         //  8      9      :      ;      <      =      >      ?  | 
1190  | 0  |         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1191  | 0  | #endif  | 
1192  |  |         //  @      A      B      C      D      E      F      G  | 
1193  | 0  |         FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  | 
1194  |  |         //  H      I      J      K      L      M      N      O  | 
1195  | 0  |          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  | 
1196  |  |         //  P      Q      R      S      T      U      V      W  | 
1197  | 0  |          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  | 
1198  |  |         //  X      Y      Z      [      \      ]      ^      _  | 
1199  | 0  |          TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,  | 
1200  |  |         //  `      a      b      c      d      e      f      g  | 
1201  | 0  |         FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  | 
1202  |  |         //  h      i      j      k      l      m      n      o  | 
1203  | 0  |          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  | 
1204  |  |         //  p      q      r      s      t      u      v      w  | 
1205  | 0  |          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  | 
1206  |  |         //  x      y      z      {      |      }      ~ | 
1207  | 0  |          TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE  | 
1208  | 0  |     };  | 
1209  |  | 
  | 
1210  | 0  |     return ch < UPRV_LENGTHOF(mapCharToIsSyntax) ? mapCharToIsSyntax[ch] : FALSE;  | 
1211  | 0  | }  | 
1212  |  |  | 
1213  |  | // Map index into pattern character string to Calendar field number.  | 
1214  |  | const UCalendarDateFields  | 
1215  |  | SimpleDateFormat::fgPatternIndexToCalendarField[] =  | 
1216  |  | { | 
1217  |  |     /*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH,  | 
1218  |  |     /*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY,  | 
1219  |  |     /*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND,  | 
1220  |  |     /*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,  | 
1221  |  |     /*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM,  | 
1222  |  |     /*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,  | 
1223  |  |     /*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR,  | 
1224  |  |     /*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET,  | 
1225  |  |     /*v*/   UCAL_ZONE_OFFSET,  | 
1226  |  |     /*c*/   UCAL_DOW_LOCAL,  | 
1227  |  |     /*L*/   UCAL_MONTH,  | 
1228  |  |     /*Q*/   UCAL_MONTH,  | 
1229  |  |     /*q*/   UCAL_MONTH,  | 
1230  |  |     /*V*/   UCAL_ZONE_OFFSET,  | 
1231  |  |     /*U*/   UCAL_YEAR,  | 
1232  |  |     /*O*/   UCAL_ZONE_OFFSET,  | 
1233  |  |     /*Xx*/  UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,  | 
1234  |  |     /*r*/   UCAL_EXTENDED_YEAR,  | 
1235  |  |     /*bB*/   UCAL_FIELD_COUNT, UCAL_FIELD_COUNT,  // no mappings to calendar fields  | 
1236  |  | #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR  | 
1237  |  |     /*:*/   UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */  | 
1238  |  | #else  | 
1239  |  |     /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/   UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */  | 
1240  |  | #endif  | 
1241  |  | };  | 
1242  |  |  | 
1243  |  | // Map index into pattern character string to DateFormat field number  | 
1244  |  | const UDateFormatField  | 
1245  |  | SimpleDateFormat::fgPatternIndexToDateFormatField[] = { | 
1246  |  |     /*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD,  | 
1247  |  |     /*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD,  | 
1248  |  |     /*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD,  | 
1249  |  |     /*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,  | 
1250  |  |     /*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD,  | 
1251  |  |     /*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD,  | 
1252  |  |     /*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD,  | 
1253  |  |     /*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD,  | 
1254  |  |     /*v*/   UDAT_TIMEZONE_GENERIC_FIELD,  | 
1255  |  |     /*c*/   UDAT_STANDALONE_DAY_FIELD,  | 
1256  |  |     /*L*/   UDAT_STANDALONE_MONTH_FIELD,  | 
1257  |  |     /*Q*/   UDAT_QUARTER_FIELD,  | 
1258  |  |     /*q*/   UDAT_STANDALONE_QUARTER_FIELD,  | 
1259  |  |     /*V*/   UDAT_TIMEZONE_SPECIAL_FIELD,  | 
1260  |  |     /*U*/   UDAT_YEAR_NAME_FIELD,  | 
1261  |  |     /*O*/   UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,  | 
1262  |  |     /*Xx*/  UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,  | 
1263  |  |     /*r*/   UDAT_RELATED_YEAR_FIELD,  | 
1264  |  |     /*bB*/  UDAT_AM_PM_MIDNIGHT_NOON_FIELD, UDAT_FLEXIBLE_DAY_PERIOD_FIELD,  | 
1265  |  | #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR  | 
1266  |  |     /*:*/   UDAT_TIME_SEPARATOR_FIELD,  | 
1267  |  | #else  | 
1268  |  |     /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/   UDAT_TIME_SEPARATOR_FIELD,  | 
1269  |  | #endif  | 
1270  |  | };  | 
1271  |  |  | 
1272  |  | //----------------------------------------------------------------------  | 
1273  |  |  | 
1274  |  | /**  | 
1275  |  |  * Append symbols[value] to dst.  Make sure the array index is not out  | 
1276  |  |  * of bounds.  | 
1277  |  |  */  | 
1278  |  | static inline void  | 
1279  |  | _appendSymbol(UnicodeString& dst,  | 
1280  |  |               int32_t value,  | 
1281  |  |               const UnicodeString* symbols,  | 
1282  | 0  |               int32_t symbolsCount) { | 
1283  | 0  |     U_ASSERT(0 <= value && value < symbolsCount);  | 
1284  | 0  |     if (0 <= value && value < symbolsCount) { | 
1285  | 0  |         dst += symbols[value];  | 
1286  | 0  |     }  | 
1287  | 0  | }  | 
1288  |  |  | 
1289  |  | static inline void  | 
1290  |  | _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount,  | 
1291  | 0  |               const UnicodeString* monthPattern, UErrorCode& status) { | 
1292  | 0  |     U_ASSERT(0 <= value && value < symbolsCount);  | 
1293  | 0  |     if (0 <= value && value < symbolsCount) { | 
1294  | 0  |         if (monthPattern == NULL) { | 
1295  | 0  |             dst += symbols[value];  | 
1296  | 0  |         } else { | 
1297  | 0  |             SimpleFormatter(*monthPattern, 1, 1, status).format(symbols[value], dst, status);  | 
1298  | 0  |         }  | 
1299  | 0  |     }  | 
1300  | 0  | }  | 
1301  |  |  | 
1302  |  | //----------------------------------------------------------------------  | 
1303  |  |  | 
1304  |  | static number::LocalizedNumberFormatter*  | 
1305  | 0  | createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt, UErrorCode& status) { | 
1306  | 0  |     const number::LocalizedNumberFormatter* lnfBase = df->toNumberFormatter(status);  | 
1307  | 0  |     if (U_FAILURE(status)) { | 
1308  | 0  |         return nullptr;  | 
1309  | 0  |     }  | 
1310  | 0  |     return lnfBase->integerWidth(  | 
1311  | 0  |         number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)  | 
1312  | 0  |     ).clone().orphan();  | 
1313  | 0  | }  | 
1314  |  |  | 
1315  | 0  | void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) { | 
1316  | 0  |     if (U_FAILURE(status)) { | 
1317  | 0  |         return;  | 
1318  | 0  |     }  | 
1319  | 0  |     auto* df = dynamic_cast<const DecimalFormat*>(fNumberFormat);  | 
1320  | 0  |     if (df == nullptr) { | 
1321  | 0  |         return;  | 
1322  | 0  |     }  | 
1323  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10, status);  | 
1324  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10, status);  | 
1325  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10, status);  | 
1326  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10, status);  | 
1327  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2, status);  | 
1328  | 0  | }  | 
1329  |  |  | 
1330  | 0  | void SimpleDateFormat::freeFastNumberFormatters() { | 
1331  | 0  |     delete fFastNumberFormatters[SMPDTFMT_NF_1x10];  | 
1332  | 0  |     delete fFastNumberFormatters[SMPDTFMT_NF_2x10];  | 
1333  | 0  |     delete fFastNumberFormatters[SMPDTFMT_NF_3x10];  | 
1334  | 0  |     delete fFastNumberFormatters[SMPDTFMT_NF_4x10];  | 
1335  | 0  |     delete fFastNumberFormatters[SMPDTFMT_NF_2x2];  | 
1336  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_1x10] = nullptr;  | 
1337  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_2x10] = nullptr;  | 
1338  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_3x10] = nullptr;  | 
1339  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_4x10] = nullptr;  | 
1340  | 0  |     fFastNumberFormatters[SMPDTFMT_NF_2x2] = nullptr;  | 
1341  | 0  | }  | 
1342  |  |  | 
1343  |  |  | 
1344  |  | void  | 
1345  | 0  | SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) { | 
1346  | 0  |     if (U_FAILURE(status)) { | 
1347  | 0  |         return;  | 
1348  | 0  |     }  | 
1349  | 0  |     if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) { | 
1350  | 0  |         return;  | 
1351  | 0  |     }  | 
1352  | 0  |     umtx_lock(&LOCK);  | 
1353  | 0  |     if (fSharedNumberFormatters == NULL) { | 
1354  | 0  |         fSharedNumberFormatters = allocSharedNumberFormatters();  | 
1355  | 0  |         if (fSharedNumberFormatters == NULL) { | 
1356  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
1357  | 0  |         }  | 
1358  | 0  |     }  | 
1359  | 0  |     umtx_unlock(&LOCK);  | 
1360  |  | 
  | 
1361  | 0  |     if (U_FAILURE(status)) { | 
1362  | 0  |         return;  | 
1363  | 0  |     }  | 
1364  |  |  | 
1365  | 0  |     processOverrideString(locale,fDateOverride,kOvrStrDate,status);  | 
1366  | 0  |     processOverrideString(locale,fTimeOverride,kOvrStrTime,status);  | 
1367  | 0  | }  | 
1368  |  |  | 
1369  |  | void  | 
1370  | 0  | SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) { | 
1371  | 0  |     if (str.isBogus() || U_FAILURE(status)) { | 
1372  | 0  |         return;  | 
1373  | 0  |     }  | 
1374  |  |  | 
1375  | 0  |     int32_t start = 0;  | 
1376  | 0  |     int32_t len;  | 
1377  | 0  |     UnicodeString nsName;  | 
1378  | 0  |     UnicodeString ovrField;  | 
1379  | 0  |     UBool moreToProcess = TRUE;  | 
1380  | 0  |     NSOverride *overrideList = NULL;  | 
1381  |  | 
  | 
1382  | 0  |     while (moreToProcess) { | 
1383  | 0  |         int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);  | 
1384  | 0  |         if (delimiterPosition == -1) { | 
1385  | 0  |             moreToProcess = FALSE;  | 
1386  | 0  |             len = str.length() - start;  | 
1387  | 0  |         } else { | 
1388  | 0  |             len = delimiterPosition - start;  | 
1389  | 0  |         }  | 
1390  | 0  |         UnicodeString currentString(str,start,len);  | 
1391  | 0  |         int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0);  | 
1392  | 0  |         if (equalSignPosition == -1) { // Simple override string such as "hebrew" | 
1393  | 0  |             nsName.setTo(currentString);  | 
1394  | 0  |             ovrField.setToBogus();  | 
1395  | 0  |         } else { // Field specific override string such as "y=hebrew" | 
1396  | 0  |             nsName.setTo(currentString,equalSignPosition+1);  | 
1397  | 0  |             ovrField.setTo(currentString,0,1); // We just need the first character.  | 
1398  | 0  |         }  | 
1399  |  | 
  | 
1400  | 0  |         int32_t nsNameHash = nsName.hashCode();  | 
1401  |  |         // See if the numbering system is in the override list, if not, then add it.  | 
1402  | 0  |         NSOverride *curr = overrideList;  | 
1403  | 0  |         const SharedNumberFormat *snf = NULL;  | 
1404  | 0  |         UBool found = FALSE;  | 
1405  | 0  |         while ( curr && !found ) { | 
1406  | 0  |             if ( curr->hash == nsNameHash ) { | 
1407  | 0  |                 snf = curr->snf;  | 
1408  | 0  |                 found = TRUE;  | 
1409  | 0  |             }  | 
1410  | 0  |             curr = curr->next;  | 
1411  | 0  |         }  | 
1412  |  | 
  | 
1413  | 0  |         if (!found) { | 
1414  | 0  |            LocalPointer<NSOverride> cur(new NSOverride);  | 
1415  | 0  |            if (!cur.isNull()) { | 
1416  | 0  |                char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];  | 
1417  | 0  |                uprv_strcpy(kw,"numbers=");  | 
1418  | 0  |                nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);  | 
1419  |  | 
  | 
1420  | 0  |                Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);  | 
1421  | 0  |                cur->hash = nsNameHash;  | 
1422  | 0  |                cur->next = overrideList;  | 
1423  | 0  |                SharedObject::copyPtr(  | 
1424  | 0  |                        createSharedNumberFormat(ovrLoc, status), cur->snf);  | 
1425  | 0  |                if (U_FAILURE(status)) { | 
1426  | 0  |                    if (overrideList) { | 
1427  | 0  |                        overrideList->free();  | 
1428  | 0  |                    }  | 
1429  | 0  |                    return;  | 
1430  | 0  |                }  | 
1431  | 0  |                snf = cur->snf;  | 
1432  | 0  |                overrideList = cur.orphan();  | 
1433  | 0  |            } else { | 
1434  | 0  |                status = U_MEMORY_ALLOCATION_ERROR;  | 
1435  | 0  |                if (overrideList) { | 
1436  | 0  |                    overrideList->free();  | 
1437  | 0  |                }  | 
1438  | 0  |                return;  | 
1439  | 0  |            }  | 
1440  | 0  |         }  | 
1441  |  |  | 
1442  |  |         // Now that we have an appropriate number formatter, fill in the appropriate spaces in the  | 
1443  |  |         // number formatters table.  | 
1444  | 0  |         if (ovrField.isBogus()) { | 
1445  | 0  |             switch (type) { | 
1446  | 0  |                 case kOvrStrDate:  | 
1447  | 0  |                 case kOvrStrBoth: { | 
1448  | 0  |                     for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) { | 
1449  | 0  |                         SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]);  | 
1450  | 0  |                     }  | 
1451  | 0  |                     if (type==kOvrStrDate) { | 
1452  | 0  |                         break;  | 
1453  | 0  |                     }  | 
1454  | 0  |                     U_FALLTHROUGH;  | 
1455  | 0  |                 }  | 
1456  | 0  |                 case kOvrStrTime : { | 
1457  | 0  |                     for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) { | 
1458  | 0  |                         SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]);  | 
1459  | 0  |                     }  | 
1460  | 0  |                     break;  | 
1461  | 0  |                 }  | 
1462  | 0  |             }  | 
1463  | 0  |         } else { | 
1464  |  |            // if the pattern character is unrecognized, signal an error and bail out  | 
1465  | 0  |            UDateFormatField patternCharIndex =  | 
1466  | 0  |               DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0));  | 
1467  | 0  |            if (patternCharIndex == UDAT_FIELD_COUNT) { | 
1468  | 0  |                status = U_INVALID_FORMAT_ERROR;  | 
1469  | 0  |                if (overrideList) { | 
1470  | 0  |                    overrideList->free();  | 
1471  | 0  |                }  | 
1472  | 0  |                return;  | 
1473  | 0  |            }  | 
1474  | 0  |            SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);  | 
1475  | 0  |         }  | 
1476  |  |  | 
1477  | 0  |         start = delimiterPosition + 1;  | 
1478  | 0  |     }  | 
1479  | 0  |     if (overrideList) { | 
1480  | 0  |         overrideList->free();  | 
1481  | 0  |     }  | 
1482  | 0  | }  | 
1483  |  |  | 
1484  |  | //---------------------------------------------------------------------  | 
1485  |  | void  | 
1486  |  | SimpleDateFormat::subFormat(UnicodeString &appendTo,  | 
1487  |  |                             char16_t ch,  | 
1488  |  |                             int32_t count,  | 
1489  |  |                             UDisplayContext capitalizationContext,  | 
1490  |  |                             int32_t fieldNum,  | 
1491  |  |                             char16_t fieldToOutput,  | 
1492  |  |                             FieldPositionHandler& handler,  | 
1493  |  |                             Calendar& cal,  | 
1494  |  |                             UErrorCode& status) const  | 
1495  | 0  | { | 
1496  | 0  |     if (U_FAILURE(status)) { | 
1497  | 0  |         return;  | 
1498  | 0  |     }  | 
1499  |  |  | 
1500  |  |     // this function gets called by format() to produce the appropriate substitution  | 
1501  |  |     // text for an individual pattern symbol (e.g., "HH" or "yyyy")  | 
1502  |  |  | 
1503  | 0  |     UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);  | 
1504  | 0  |     const int32_t maxIntCount = 10;  | 
1505  | 0  |     int32_t beginOffset = appendTo.length();  | 
1506  | 0  |     const NumberFormat *currentNumberFormat;  | 
1507  | 0  |     DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;  | 
1508  |  | 
  | 
1509  | 0  |     UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);  | 
1510  | 0  |     UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);  | 
1511  |  |  | 
1512  |  |     // if the pattern character is unrecognized, signal an error and dump out  | 
1513  | 0  |     if (patternCharIndex == UDAT_FIELD_COUNT)  | 
1514  | 0  |     { | 
1515  | 0  |         if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored | 
1516  | 0  |             status = U_INVALID_FORMAT_ERROR;  | 
1517  | 0  |         }  | 
1518  | 0  |         return;  | 
1519  | 0  |     }  | 
1520  |  |  | 
1521  | 0  |     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];  | 
1522  | 0  |     int32_t value = 0;  | 
1523  |  |     // Don't get value unless it is useful  | 
1524  | 0  |     if (field < UCAL_FIELD_COUNT) { | 
1525  | 0  |         value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status);  | 
1526  | 0  |     }  | 
1527  | 0  |     if (U_FAILURE(status)) { | 
1528  | 0  |         return;  | 
1529  | 0  |     }  | 
1530  |  |  | 
1531  | 0  |     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);  | 
1532  | 0  |     if (currentNumberFormat == NULL) { | 
1533  | 0  |         status = U_INTERNAL_PROGRAM_ERROR;  | 
1534  | 0  |         return;  | 
1535  | 0  |     }  | 
1536  | 0  |     UnicodeString hebr("hebr", 4, US_INV); | 
1537  |  | 
  | 
1538  | 0  |     switch (patternCharIndex) { | 
1539  |  |  | 
1540  |  |     // for any "G" symbol, write out the appropriate era string  | 
1541  |  |     // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name  | 
1542  | 0  |     case UDAT_ERA_FIELD:  | 
1543  | 0  |         if (isChineseCalendar) { | 
1544  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J  | 
1545  | 0  |         } else { | 
1546  | 0  |             if (count == 5) { | 
1547  | 0  |                 _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);  | 
1548  | 0  |                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow;  | 
1549  | 0  |             } else if (count == 4) { | 
1550  | 0  |                 _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);  | 
1551  | 0  |                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;  | 
1552  | 0  |             } else { | 
1553  | 0  |                 _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);  | 
1554  | 0  |                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;  | 
1555  | 0  |             }  | 
1556  | 0  |         }  | 
1557  | 0  |         break;  | 
1558  |  |  | 
1559  | 0  |      case UDAT_YEAR_NAME_FIELD:  | 
1560  | 0  |         if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) { | 
1561  |  |             // the Calendar YEAR field runs 1 through 60 for cyclic years  | 
1562  | 0  |             _appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount);  | 
1563  | 0  |             break;  | 
1564  | 0  |         }  | 
1565  |  |         // else fall through to numeric year handling, do not break here  | 
1566  | 0  |         U_FALLTHROUGH;  | 
1567  |  |  | 
1568  |  |    // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits  | 
1569  |  |     // NEW: UTS#35:  | 
1570  |  | //Year         y     yy     yyy     yyyy     yyyyy  | 
1571  |  | //AD 1         1     01     001     0001     00001  | 
1572  |  | //AD 12       12     12     012     0012     00012  | 
1573  |  | //AD 123     123     23     123     0123     00123  | 
1574  |  | //AD 1234   1234     34    1234     1234     01234  | 
1575  |  | //AD 12345 12345     45   12345    12345     12345  | 
1576  | 0  |     case UDAT_YEAR_FIELD:  | 
1577  | 0  |     case UDAT_YEAR_WOY_FIELD:  | 
1578  | 0  |         if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) { | 
1579  | 0  |             value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR;  | 
1580  | 0  |         }  | 
1581  | 0  |         if(count == 2)  | 
1582  | 0  |             zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);  | 
1583  | 0  |         else  | 
1584  | 0  |             zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);  | 
1585  | 0  |         break;  | 
1586  |  |  | 
1587  |  |     // for "MMMM"/"LLLL", write out the whole month name, for "MMM"/"LLL", write out the month  | 
1588  |  |     // abbreviation, for "M"/"L" or "MM"/"LL", write out the month as a number with the  | 
1589  |  |     // appropriate number of digits  | 
1590  |  |     // for "MMMMM"/"LLLLL", use the narrow form  | 
1591  | 0  |     case UDAT_MONTH_FIELD:  | 
1592  | 0  |     case UDAT_STANDALONE_MONTH_FIELD:  | 
1593  | 0  |         if ( isHebrewCalendar ) { | 
1594  | 0  |            HebrewCalendar *hc = (HebrewCalendar*)&cal;  | 
1595  | 0  |            if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )  | 
1596  | 0  |                value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.  | 
1597  | 0  |            if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )  | 
1598  | 0  |                value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.  | 
1599  | 0  |         }  | 
1600  | 0  |         { | 
1601  | 0  |             int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)?  | 
1602  | 0  |                         cal.get(UCAL_IS_LEAP_MONTH, status): 0;  | 
1603  |  |             // should consolidate the next section by using arrays of pointers & counts for the right symbols...  | 
1604  | 0  |             if (count == 5) { | 
1605  | 0  |                 if (patternCharIndex == UDAT_MONTH_FIELD) { | 
1606  | 0  |                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount,  | 
1607  | 0  |                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status);  | 
1608  | 0  |                 } else { | 
1609  | 0  |                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount,  | 
1610  | 0  |                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status);  | 
1611  | 0  |                 }  | 
1612  | 0  |                 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;  | 
1613  | 0  |             } else if (count == 4) { | 
1614  | 0  |                 if (patternCharIndex == UDAT_MONTH_FIELD) { | 
1615  | 0  |                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount,  | 
1616  | 0  |                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status);  | 
1617  | 0  |                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;  | 
1618  | 0  |                 } else { | 
1619  | 0  |                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount,  | 
1620  | 0  |                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status);  | 
1621  | 0  |                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;  | 
1622  | 0  |                 }  | 
1623  | 0  |             } else if (count == 3) { | 
1624  | 0  |                 if (patternCharIndex == UDAT_MONTH_FIELD) { | 
1625  | 0  |                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount,  | 
1626  | 0  |                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status);  | 
1627  | 0  |                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;  | 
1628  | 0  |                 } else { | 
1629  | 0  |                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount,  | 
1630  | 0  |                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status);  | 
1631  | 0  |                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;  | 
1632  | 0  |                 }  | 
1633  | 0  |             } else { | 
1634  | 0  |                 UnicodeString monthNumber;  | 
1635  | 0  |                 zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount);  | 
1636  | 0  |                 _appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1,  | 
1637  | 0  |                         (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status);  | 
1638  | 0  |             }  | 
1639  | 0  |         }  | 
1640  | 0  |         break;  | 
1641  |  |  | 
1642  |  |     // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"  | 
1643  | 0  |     case UDAT_HOUR_OF_DAY1_FIELD:  | 
1644  | 0  |         if (value == 0)  | 
1645  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);  | 
1646  | 0  |         else  | 
1647  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);  | 
1648  | 0  |         break;  | 
1649  |  |  | 
1650  | 0  |     case UDAT_FRACTIONAL_SECOND_FIELD:  | 
1651  |  |         // Fractional seconds left-justify  | 
1652  | 0  |         { | 
1653  | 0  |             int32_t minDigits = (count > 3) ? 3 : count;  | 
1654  | 0  |             if (count == 1) { | 
1655  | 0  |                 value /= 100;  | 
1656  | 0  |             } else if (count == 2) { | 
1657  | 0  |                 value /= 10;  | 
1658  | 0  |             }  | 
1659  | 0  |             zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount);  | 
1660  | 0  |             if (count > 3) { | 
1661  | 0  |                 zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount);  | 
1662  | 0  |             }  | 
1663  | 0  |         }  | 
1664  | 0  |         break;  | 
1665  |  |  | 
1666  |  |     // for "ee" or "e", use local numeric day-of-the-week  | 
1667  |  |     // for "EEEEEE" or "eeeeee", write out the short day-of-the-week name  | 
1668  |  |     // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name  | 
1669  |  |     // for "EEEE" or "eeee", write out the wide day-of-the-week name  | 
1670  |  |     // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name  | 
1671  | 0  |     case UDAT_DOW_LOCAL_FIELD:  | 
1672  | 0  |         if ( count < 3 ) { | 
1673  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);  | 
1674  | 0  |             break;  | 
1675  | 0  |         }  | 
1676  |  |         // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week,  | 
1677  |  |         // we want standard day-of-week, so first fix value to work for EEEEE-EEE.  | 
1678  | 0  |         value = cal.get(UCAL_DAY_OF_WEEK, status);  | 
1679  | 0  |         if (U_FAILURE(status)) { | 
1680  | 0  |             return;  | 
1681  | 0  |         }  | 
1682  |  |         // fall through, do not break here  | 
1683  | 0  |         U_FALLTHROUGH;  | 
1684  | 0  |     case UDAT_DAY_OF_WEEK_FIELD:  | 
1685  | 0  |         if (count == 5) { | 
1686  | 0  |             _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,  | 
1687  | 0  |                           fSymbols->fNarrowWeekdaysCount);  | 
1688  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;  | 
1689  | 0  |         } else if (count == 4) { | 
1690  | 0  |             _appendSymbol(appendTo, value, fSymbols->fWeekdays,  | 
1691  | 0  |                           fSymbols->fWeekdaysCount);  | 
1692  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;  | 
1693  | 0  |         } else if (count == 6) { | 
1694  | 0  |             _appendSymbol(appendTo, value, fSymbols->fShorterWeekdays,  | 
1695  | 0  |                           fSymbols->fShorterWeekdaysCount);  | 
1696  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;  | 
1697  | 0  |         } else { | 
1698  | 0  |             _appendSymbol(appendTo, value, fSymbols->fShortWeekdays,  | 
1699  | 0  |                           fSymbols->fShortWeekdaysCount);  | 
1700  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;  | 
1701  | 0  |         }  | 
1702  | 0  |         break;  | 
1703  |  |  | 
1704  |  |     // for "ccc", write out the abbreviated day-of-the-week name  | 
1705  |  |     // for "cccc", write out the wide day-of-the-week name  | 
1706  |  |     // for "ccccc", use the narrow day-of-the-week name  | 
1707  |  |     // for "ccccc", use the short day-of-the-week name  | 
1708  | 0  |     case UDAT_STANDALONE_DAY_FIELD:  | 
1709  | 0  |         if ( count < 3 ) { | 
1710  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);  | 
1711  | 0  |             break;  | 
1712  | 0  |         }  | 
1713  |  |         // fall through to alpha DOW handling, but for that we don't want local day-of-week,  | 
1714  |  |         // we want standard day-of-week, so first fix value.  | 
1715  | 0  |         value = cal.get(UCAL_DAY_OF_WEEK, status);  | 
1716  | 0  |         if (U_FAILURE(status)) { | 
1717  | 0  |             return;  | 
1718  | 0  |         }  | 
1719  | 0  |         if (count == 5) { | 
1720  | 0  |             _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,  | 
1721  | 0  |                           fSymbols->fStandaloneNarrowWeekdaysCount);  | 
1722  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;  | 
1723  | 0  |         } else if (count == 4) { | 
1724  | 0  |             _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,  | 
1725  | 0  |                           fSymbols->fStandaloneWeekdaysCount);  | 
1726  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;  | 
1727  | 0  |         } else if (count == 6) { | 
1728  | 0  |             _appendSymbol(appendTo, value, fSymbols->fStandaloneShorterWeekdays,  | 
1729  | 0  |                           fSymbols->fStandaloneShorterWeekdaysCount);  | 
1730  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;  | 
1731  | 0  |         } else { // count == 3 | 
1732  | 0  |             _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,  | 
1733  | 0  |                           fSymbols->fStandaloneShortWeekdaysCount);  | 
1734  | 0  |             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;  | 
1735  | 0  |         }  | 
1736  | 0  |         break;  | 
1737  |  |  | 
1738  |  |     // for "a" symbol, write out the whole AM/PM string  | 
1739  | 0  |     case UDAT_AM_PM_FIELD:  | 
1740  | 0  |         if (count < 5) { | 
1741  | 0  |             _appendSymbol(appendTo, value, fSymbols->fAmPms,  | 
1742  | 0  |                           fSymbols->fAmPmsCount);  | 
1743  | 0  |         } else { | 
1744  | 0  |             _appendSymbol(appendTo, value, fSymbols->fNarrowAmPms,  | 
1745  | 0  |                           fSymbols->fNarrowAmPmsCount);  | 
1746  | 0  |         }  | 
1747  | 0  |         break;  | 
1748  |  |  | 
1749  |  |     // if we see pattern character for UDAT_TIME_SEPARATOR_FIELD (none currently defined),  | 
1750  |  |     // write out the time separator string. Leave support in for future definition.  | 
1751  | 0  |     case UDAT_TIME_SEPARATOR_FIELD:  | 
1752  | 0  |         { | 
1753  | 0  |             UnicodeString separator;  | 
1754  | 0  |             appendTo += fSymbols->getTimeSeparatorString(separator);  | 
1755  | 0  |         }  | 
1756  | 0  |         break;  | 
1757  |  |  | 
1758  |  |     // for "h" and "hh", write out the hour, adjusting noon and midnight to show up  | 
1759  |  |     // as "12"  | 
1760  | 0  |     case UDAT_HOUR1_FIELD:  | 
1761  | 0  |         if (value == 0)  | 
1762  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);  | 
1763  | 0  |         else  | 
1764  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);  | 
1765  | 0  |         break;  | 
1766  |  |  | 
1767  | 0  |     case UDAT_TIMEZONE_FIELD: // 'z'  | 
1768  | 0  |     case UDAT_TIMEZONE_RFC_FIELD: // 'Z'  | 
1769  | 0  |     case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'  | 
1770  | 0  |     case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'  | 
1771  | 0  |     case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'  | 
1772  | 0  |     case UDAT_TIMEZONE_ISO_FIELD: // 'X'  | 
1773  | 0  |     case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'  | 
1774  | 0  |         { | 
1775  | 0  |             UChar zsbuf[ZONE_NAME_U16_MAX];  | 
1776  | 0  |             UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));  | 
1777  | 0  |             const TimeZone& tz = cal.getTimeZone();  | 
1778  | 0  |             UDate date = cal.getTime(status);  | 
1779  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
1780  | 0  |             if (U_SUCCESS(status)) { | 
1781  | 0  |                 if (patternCharIndex == UDAT_TIMEZONE_FIELD) { | 
1782  | 0  |                     if (count < 4) { | 
1783  |  |                         // "z", "zz", "zzz"  | 
1784  | 0  |                         tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);  | 
1785  | 0  |                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;  | 
1786  | 0  |                     } else { | 
1787  |  |                         // "zzzz" or longer  | 
1788  | 0  |                         tzfmt->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);  | 
1789  | 0  |                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;  | 
1790  | 0  |                     }  | 
1791  | 0  |                 }  | 
1792  | 0  |                 else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) { | 
1793  | 0  |                     if (count < 4) { | 
1794  |  |                         // "Z"  | 
1795  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);  | 
1796  | 0  |                     } else if (count == 5) { | 
1797  |  |                         // "ZZZZZ"  | 
1798  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);  | 
1799  | 0  |                     } else { | 
1800  |  |                         // "ZZ", "ZZZ", "ZZZZ"  | 
1801  | 0  |                         tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);  | 
1802  | 0  |                     }  | 
1803  | 0  |                 }  | 
1804  | 0  |                 else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) { | 
1805  | 0  |                     if (count == 1) { | 
1806  |  |                         // "v"  | 
1807  | 0  |                         tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);  | 
1808  | 0  |                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;  | 
1809  | 0  |                     } else if (count == 4) { | 
1810  |  |                         // "vvvv"  | 
1811  | 0  |                         tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);  | 
1812  | 0  |                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;  | 
1813  | 0  |                     }  | 
1814  | 0  |                 }  | 
1815  | 0  |                 else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) { | 
1816  | 0  |                     if (count == 1) { | 
1817  |  |                         // "V"  | 
1818  | 0  |                         tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);  | 
1819  | 0  |                     } else if (count == 2) { | 
1820  |  |                         // "VV"  | 
1821  | 0  |                         tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);  | 
1822  | 0  |                     } else if (count == 3) { | 
1823  |  |                         // "VVV"  | 
1824  | 0  |                         tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);  | 
1825  | 0  |                     } else if (count == 4) { | 
1826  |  |                         // "VVVV"  | 
1827  | 0  |                         tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);  | 
1828  | 0  |                         capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;  | 
1829  | 0  |                     }  | 
1830  | 0  |                 }  | 
1831  | 0  |                 else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) { | 
1832  | 0  |                     if (count == 1) { | 
1833  |  |                         // "O"  | 
1834  | 0  |                         tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);  | 
1835  | 0  |                     } else if (count == 4) { | 
1836  |  |                         // "OOOO"  | 
1837  | 0  |                         tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);  | 
1838  | 0  |                     }  | 
1839  | 0  |                 }  | 
1840  | 0  |                 else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) { | 
1841  | 0  |                     if (count == 1) { | 
1842  |  |                         // "X"  | 
1843  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);  | 
1844  | 0  |                     } else if (count == 2) { | 
1845  |  |                         // "XX"  | 
1846  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);  | 
1847  | 0  |                     } else if (count == 3) { | 
1848  |  |                         // "XXX"  | 
1849  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);  | 
1850  | 0  |                     } else if (count == 4) { | 
1851  |  |                         // "XXXX"  | 
1852  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);  | 
1853  | 0  |                     } else if (count == 5) { | 
1854  |  |                         // "XXXXX"  | 
1855  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);  | 
1856  | 0  |                     }  | 
1857  | 0  |                 }  | 
1858  | 0  |                 else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) { | 
1859  | 0  |                     if (count == 1) { | 
1860  |  |                         // "x"  | 
1861  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);  | 
1862  | 0  |                     } else if (count == 2) { | 
1863  |  |                         // "xx"  | 
1864  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);  | 
1865  | 0  |                     } else if (count == 3) { | 
1866  |  |                         // "xxx"  | 
1867  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);  | 
1868  | 0  |                     } else if (count == 4) { | 
1869  |  |                         // "xxxx"  | 
1870  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);  | 
1871  | 0  |                     } else if (count == 5) { | 
1872  |  |                         // "xxxxx"  | 
1873  | 0  |                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);  | 
1874  | 0  |                     }  | 
1875  | 0  |                 }  | 
1876  | 0  |                 else { | 
1877  | 0  |                     UPRV_UNREACHABLE;  | 
1878  | 0  |                 }  | 
1879  | 0  |             }  | 
1880  | 0  |             appendTo += zoneString;  | 
1881  | 0  |         }  | 
1882  | 0  |         break;  | 
1883  |  |  | 
1884  | 0  |     case UDAT_QUARTER_FIELD:  | 
1885  | 0  |         if (count >= 5)  | 
1886  | 0  |             _appendSymbol(appendTo, value/3, fSymbols->fNarrowQuarters,  | 
1887  | 0  |                           fSymbols->fNarrowQuartersCount);  | 
1888  | 0  |          else if (count == 4)  | 
1889  | 0  |             _appendSymbol(appendTo, value/3, fSymbols->fQuarters,  | 
1890  | 0  |                           fSymbols->fQuartersCount);  | 
1891  | 0  |         else if (count == 3)  | 
1892  | 0  |             _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,  | 
1893  | 0  |                           fSymbols->fShortQuartersCount);  | 
1894  | 0  |         else  | 
1895  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);  | 
1896  | 0  |         break;  | 
1897  |  |  | 
1898  | 0  |     case UDAT_STANDALONE_QUARTER_FIELD:  | 
1899  | 0  |         if (count >= 5)  | 
1900  | 0  |             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneNarrowQuarters,  | 
1901  | 0  |                           fSymbols->fStandaloneNarrowQuartersCount);  | 
1902  | 0  |         else if (count == 4)  | 
1903  | 0  |             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,  | 
1904  | 0  |                           fSymbols->fStandaloneQuartersCount);  | 
1905  | 0  |         else if (count == 3)  | 
1906  | 0  |             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,  | 
1907  | 0  |                           fSymbols->fStandaloneShortQuartersCount);  | 
1908  | 0  |         else  | 
1909  | 0  |             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);  | 
1910  | 0  |         break;  | 
1911  |  |  | 
1912  | 0  |     case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:  | 
1913  | 0  |     { | 
1914  | 0  |         const UnicodeString *toAppend = NULL;  | 
1915  | 0  |         int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);  | 
1916  |  |  | 
1917  |  |         // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.  | 
1918  |  |         // For ICU 57 output of "midnight" is temporarily suppressed.  | 
1919  |  |  | 
1920  |  |         // For "midnight" and "noon":  | 
1921  |  |         // Time, as displayed, must be exactly noon or midnight.  | 
1922  |  |         // This means minutes and seconds, if present, must be zero.  | 
1923  | 0  |         if ((/*hour == 0 ||*/ hour == 12) &&  | 
1924  | 0  |                 (!fHasMinute || cal.get(UCAL_MINUTE, status) == 0) &&  | 
1925  | 0  |                 (!fHasSecond || cal.get(UCAL_SECOND, status) == 0)) { | 
1926  |  |             // Stealing am/pm value to use as our array index.  | 
1927  |  |             // It works out: am/midnight are both 0, pm/noon are both 1,  | 
1928  |  |             // 12 am is 12 midnight, and 12 pm is 12 noon.  | 
1929  | 0  |             int32_t val = cal.get(UCAL_AM_PM, status);  | 
1930  |  | 
  | 
1931  | 0  |             if (count <= 3) { | 
1932  | 0  |                 toAppend = &fSymbols->fAbbreviatedDayPeriods[val];  | 
1933  | 0  |             } else if (count == 4 || count > 5) { | 
1934  | 0  |                 toAppend = &fSymbols->fWideDayPeriods[val];  | 
1935  | 0  |             } else { // count == 5 | 
1936  | 0  |                 toAppend = &fSymbols->fNarrowDayPeriods[val];  | 
1937  | 0  |             }  | 
1938  | 0  |         }  | 
1939  |  |  | 
1940  |  |         // toAppend is NULL if time isn't exactly midnight or noon (as displayed).  | 
1941  |  |         // toAppend is bogus if time is midnight or noon, but no localized string exists.  | 
1942  |  |         // In either case, fall back to am/pm.  | 
1943  | 0  |         if (toAppend == NULL || toAppend->isBogus()) { | 
1944  |  |             // Reformat with identical arguments except ch, now changed to 'a'.  | 
1945  |  |             // We are passing a different fieldToOutput because we want to add  | 
1946  |  |             // 'b' to field position. This makes this fallback stable when  | 
1947  |  |             // there is a data change on locales.  | 
1948  | 0  |             subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'b', handler, cal, status);  | 
1949  | 0  |             return;  | 
1950  | 0  |         } else { | 
1951  | 0  |             appendTo += *toAppend;  | 
1952  | 0  |         }  | 
1953  |  |  | 
1954  | 0  |         break;  | 
1955  | 0  |     }  | 
1956  |  |  | 
1957  | 0  |     case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:  | 
1958  | 0  |     { | 
1959  |  |         // TODO: Maybe fetch the DayperiodRules during initialization (instead of at the first  | 
1960  |  |         // loading of an instance) if a relevant pattern character (b or B) is used.  | 
1961  | 0  |         const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);  | 
1962  | 0  |         if (U_FAILURE(status)) { | 
1963  |  |             // Data doesn't conform to spec, therefore loading failed.  | 
1964  | 0  |             break;  | 
1965  | 0  |         }  | 
1966  | 0  |         if (ruleSet == NULL) { | 
1967  |  |             // Data doesn't exist for the locale we're looking for.  | 
1968  |  |             // Falling back to am/pm.  | 
1969  |  |             // We are passing a different fieldToOutput because we want to add  | 
1970  |  |             // 'B' to field position. This makes this fallback stable when  | 
1971  |  |             // there is a data change on locales.  | 
1972  | 0  |             subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);  | 
1973  | 0  |             return;  | 
1974  | 0  |         }  | 
1975  |  |  | 
1976  |  |         // Get current display time.  | 
1977  | 0  |         int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);  | 
1978  | 0  |         int32_t minute = 0;  | 
1979  | 0  |         if (fHasMinute) { | 
1980  | 0  |             minute = cal.get(UCAL_MINUTE, status);  | 
1981  | 0  |         }  | 
1982  | 0  |         int32_t second = 0;  | 
1983  | 0  |         if (fHasSecond) { | 
1984  | 0  |             second = cal.get(UCAL_SECOND, status);  | 
1985  | 0  |         }  | 
1986  |  |  | 
1987  |  |         // Determine day period.  | 
1988  | 0  |         DayPeriodRules::DayPeriod periodType;  | 
1989  | 0  |         if (hour == 0 && minute == 0 && second == 0 && ruleSet->hasMidnight()) { | 
1990  | 0  |             periodType = DayPeriodRules::DAYPERIOD_MIDNIGHT;  | 
1991  | 0  |         } else if (hour == 12 && minute == 0 && second == 0 && ruleSet->hasNoon()) { | 
1992  | 0  |             periodType = DayPeriodRules::DAYPERIOD_NOON;  | 
1993  | 0  |         } else { | 
1994  | 0  |             periodType = ruleSet->getDayPeriodForHour(hour);  | 
1995  | 0  |         }  | 
1996  |  |  | 
1997  |  |         // Rule set exists, therefore periodType can't be UNKNOWN.  | 
1998  |  |         // Get localized string.  | 
1999  | 0  |         U_ASSERT(periodType != DayPeriodRules::DAYPERIOD_UNKNOWN);  | 
2000  | 0  |         UnicodeString *toAppend = NULL;  | 
2001  | 0  |         int32_t index;  | 
2002  |  |  | 
2003  |  |         // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.  | 
2004  |  |         // For ICU 57 output of "midnight" is temporarily suppressed.  | 
2005  |  | 
  | 
2006  | 0  |         if (periodType != DayPeriodRules::DAYPERIOD_AM &&  | 
2007  | 0  |                 periodType != DayPeriodRules::DAYPERIOD_PM &&  | 
2008  | 0  |                 periodType != DayPeriodRules::DAYPERIOD_MIDNIGHT) { | 
2009  | 0  |             index = (int32_t)periodType;  | 
2010  | 0  |             if (count <= 3) { | 
2011  | 0  |                 toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short  | 
2012  | 0  |             } else if (count == 4 || count > 5) { | 
2013  | 0  |                 toAppend = &fSymbols->fWideDayPeriods[index];  | 
2014  | 0  |             } else {  // count == 5 | 
2015  | 0  |                 toAppend = &fSymbols->fNarrowDayPeriods[index];  | 
2016  | 0  |             }  | 
2017  | 0  |         }  | 
2018  |  |  | 
2019  |  |         // Fallback schedule:  | 
2020  |  |         // Midnight/Noon -> General Periods -> AM/PM.  | 
2021  |  |  | 
2022  |  |         // Midnight/Noon -> General Periods.  | 
2023  | 0  |         if ((toAppend == NULL || toAppend->isBogus()) &&  | 
2024  | 0  |                 (periodType == DayPeriodRules::DAYPERIOD_MIDNIGHT ||  | 
2025  | 0  |                  periodType == DayPeriodRules::DAYPERIOD_NOON)) { | 
2026  | 0  |             periodType = ruleSet->getDayPeriodForHour(hour);  | 
2027  | 0  |             index = (int32_t)periodType;  | 
2028  |  | 
  | 
2029  | 0  |             if (count <= 3) { | 
2030  | 0  |                 toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short  | 
2031  | 0  |             } else if (count == 4 || count > 5) { | 
2032  | 0  |                 toAppend = &fSymbols->fWideDayPeriods[index];  | 
2033  | 0  |             } else {  // count == 5 | 
2034  | 0  |                 toAppend = &fSymbols->fNarrowDayPeriods[index];  | 
2035  | 0  |             }  | 
2036  | 0  |         }  | 
2037  |  |  | 
2038  |  |         // General Periods -> AM/PM.  | 
2039  | 0  |         if (periodType == DayPeriodRules::DAYPERIOD_AM ||  | 
2040  | 0  |             periodType == DayPeriodRules::DAYPERIOD_PM ||  | 
2041  | 0  |             toAppend->isBogus()) { | 
2042  |  |             // We are passing a different fieldToOutput because we want to add  | 
2043  |  |             // 'B' to field position iterator. This makes this fallback stable when  | 
2044  |  |             // there is a data change on locales.  | 
2045  | 0  |             subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);  | 
2046  | 0  |             return;  | 
2047  | 0  |         }  | 
2048  | 0  |         else { | 
2049  | 0  |             appendTo += *toAppend;  | 
2050  | 0  |         }  | 
2051  |  |  | 
2052  | 0  |         break;  | 
2053  | 0  |     }  | 
2054  |  |  | 
2055  |  |     // all of the other pattern symbols can be formatted as simple numbers with  | 
2056  |  |     // appropriate zero padding  | 
2057  | 0  |     default:  | 
2058  | 0  |         zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);  | 
2059  | 0  |         break;  | 
2060  | 0  |     }  | 
2061  | 0  | #if !UCONFIG_NO_BREAK_ITERATION  | 
2062  |  |     // if first field, check to see whether we need to and are able to titlecase it  | 
2063  | 0  |     if (fieldNum == 0 && fCapitalizationBrkIter != NULL && appendTo.length() > beginOffset &&  | 
2064  | 0  |             u_islower(appendTo.char32At(beginOffset))) { | 
2065  | 0  |         UBool titlecase = FALSE;  | 
2066  | 0  |         switch (capitalizationContext) { | 
2067  | 0  |             case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:  | 
2068  | 0  |                 titlecase = TRUE;  | 
2069  | 0  |                 break;  | 
2070  | 0  |             case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:  | 
2071  | 0  |                 titlecase = fSymbols->fCapitalization[capContextUsageType][0];  | 
2072  | 0  |                 break;  | 
2073  | 0  |             case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:  | 
2074  | 0  |                 titlecase = fSymbols->fCapitalization[capContextUsageType][1];  | 
2075  | 0  |                 break;  | 
2076  | 0  |             default:  | 
2077  |  |                 // titlecase = FALSE;  | 
2078  | 0  |                 break;  | 
2079  | 0  |         }  | 
2080  | 0  |         if (titlecase) { | 
2081  | 0  |             BreakIterator* const mutableCapitalizationBrkIter = fCapitalizationBrkIter->clone();  | 
2082  | 0  |             UnicodeString firstField(appendTo, beginOffset);  | 
2083  | 0  |             firstField.toTitle(mutableCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);  | 
2084  | 0  |             appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);  | 
2085  | 0  |             delete mutableCapitalizationBrkIter;  | 
2086  | 0  |         }  | 
2087  | 0  |     }  | 
2088  | 0  | #endif  | 
2089  |  |  | 
2090  | 0  |     handler.addAttribute(DateFormatSymbols::getPatternCharIndex(fieldToOutput), beginOffset, appendTo.length());  | 
2091  | 0  | }  | 
2092  |  |  | 
2093  |  | //----------------------------------------------------------------------  | 
2094  |  |  | 
2095  | 0  | void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) { | 
2096  | 0  |     fixNumberFormatForDates(*formatToAdopt);  | 
2097  | 0  |     delete fNumberFormat;  | 
2098  | 0  |     fNumberFormat = formatToAdopt;  | 
2099  |  |  | 
2100  |  |     // We successfully set the default number format. Now delete the overrides  | 
2101  |  |     // (can't fail).  | 
2102  | 0  |     if (fSharedNumberFormatters) { | 
2103  | 0  |         freeSharedNumberFormatters(fSharedNumberFormatters);  | 
2104  | 0  |         fSharedNumberFormatters = NULL;  | 
2105  | 0  |     }  | 
2106  |  |  | 
2107  |  |     // Also re-compute the fast formatters.  | 
2108  | 0  |     UErrorCode localStatus = U_ZERO_ERROR;  | 
2109  | 0  |     freeFastNumberFormatters();  | 
2110  | 0  |     initFastNumberFormatters(localStatus);  | 
2111  | 0  | }  | 
2112  |  |  | 
2113  | 0  | void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){ | 
2114  | 0  |     fixNumberFormatForDates(*formatToAdopt);  | 
2115  | 0  |     LocalPointer<NumberFormat> fmt(formatToAdopt);  | 
2116  | 0  |     if (U_FAILURE(status)) { | 
2117  | 0  |         return;  | 
2118  | 0  |     }  | 
2119  |  |  | 
2120  |  |     // We must ensure fSharedNumberFormatters is allocated.  | 
2121  | 0  |     if (fSharedNumberFormatters == NULL) { | 
2122  | 0  |         fSharedNumberFormatters = allocSharedNumberFormatters();  | 
2123  | 0  |         if (fSharedNumberFormatters == NULL) { | 
2124  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
2125  | 0  |             return;  | 
2126  | 0  |         }  | 
2127  | 0  |     }  | 
2128  | 0  |     const SharedNumberFormat *newFormat = createSharedNumberFormat(fmt.orphan());  | 
2129  | 0  |     if (newFormat == NULL) { | 
2130  | 0  |         status = U_MEMORY_ALLOCATION_ERROR;  | 
2131  | 0  |         return;  | 
2132  | 0  |     }  | 
2133  | 0  |     for (int i=0; i<fields.length(); i++) { | 
2134  | 0  |         UChar field = fields.charAt(i);  | 
2135  |  |         // if the pattern character is unrecognized, signal an error and bail out  | 
2136  | 0  |         UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(field);  | 
2137  | 0  |         if (patternCharIndex == UDAT_FIELD_COUNT) { | 
2138  | 0  |             status = U_INVALID_FORMAT_ERROR;  | 
2139  | 0  |             newFormat->deleteIfZeroRefCount();  | 
2140  | 0  |             return;  | 
2141  | 0  |         }  | 
2142  |  |  | 
2143  |  |         // Set the number formatter in the table  | 
2144  | 0  |         SharedObject::copyPtr(  | 
2145  | 0  |                 newFormat, fSharedNumberFormatters[patternCharIndex]);  | 
2146  | 0  |     }  | 
2147  | 0  |     newFormat->deleteIfZeroRefCount();  | 
2148  | 0  | }  | 
2149  |  |  | 
2150  |  | const NumberFormat *  | 
2151  | 0  | SimpleDateFormat::getNumberFormatForField(UChar field) const { | 
2152  | 0  |     UDateFormatField index = DateFormatSymbols::getPatternCharIndex(field);  | 
2153  | 0  |     if (index == UDAT_FIELD_COUNT) { | 
2154  | 0  |         return NULL;  | 
2155  | 0  |     }  | 
2156  | 0  |     return getNumberFormatByIndex(index);  | 
2157  | 0  | }  | 
2158  |  |  | 
2159  |  | //----------------------------------------------------------------------  | 
2160  |  | void  | 
2161  |  | SimpleDateFormat::zeroPaddingNumber(  | 
2162  |  |         const NumberFormat *currentNumberFormat,  | 
2163  |  |         UnicodeString &appendTo,  | 
2164  |  |         int32_t value, int32_t minDigits, int32_t maxDigits) const  | 
2165  | 0  | { | 
2166  | 0  |     const number::LocalizedNumberFormatter* fastFormatter = nullptr;  | 
2167  |  |     // NOTE: This uses the heuristic that these five min/max int settings account for the vast majority  | 
2168  |  |     // of SimpleDateFormat number formatting cases at the time of writing (ICU 62).  | 
2169  | 0  |     if (currentNumberFormat == fNumberFormat) { | 
2170  | 0  |         if (maxDigits == 10) { | 
2171  | 0  |             if (minDigits == 1) { | 
2172  | 0  |                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_1x10];  | 
2173  | 0  |             } else if (minDigits == 2) { | 
2174  | 0  |                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x10];  | 
2175  | 0  |             } else if (minDigits == 3) { | 
2176  | 0  |                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_3x10];  | 
2177  | 0  |             } else if (minDigits == 4) { | 
2178  | 0  |                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_4x10];  | 
2179  | 0  |             }  | 
2180  | 0  |         } else if (maxDigits == 2) { | 
2181  | 0  |             if (minDigits == 2) { | 
2182  | 0  |                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x2];  | 
2183  | 0  |             }  | 
2184  | 0  |         }  | 
2185  | 0  |     }  | 
2186  | 0  |     if (fastFormatter != nullptr) { | 
2187  |  |         // Can use fast path  | 
2188  | 0  |         number::impl::UFormattedNumberData result;  | 
2189  | 0  |         result.quantity.setToInt(value);  | 
2190  | 0  |         UErrorCode localStatus = U_ZERO_ERROR;  | 
2191  | 0  |         fastFormatter->formatImpl(&result, localStatus);  | 
2192  | 0  |         if (U_FAILURE(localStatus)) { | 
2193  | 0  |             return;  | 
2194  | 0  |         }  | 
2195  | 0  |         appendTo.append(result.getStringRef().toTempUnicodeString());  | 
2196  | 0  |         return;  | 
2197  | 0  |     }  | 
2198  |  |  | 
2199  |  |     // Check for RBNF (no clone necessary)  | 
2200  | 0  |     auto* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(currentNumberFormat);  | 
2201  | 0  |     if (rbnf != nullptr) { | 
2202  | 0  |         FieldPosition pos(FieldPosition::DONT_CARE);  | 
2203  | 0  |         rbnf->format(value, appendTo, pos);  // 3rd arg is there to speed up processing  | 
2204  | 0  |         return;  | 
2205  | 0  |     }  | 
2206  |  |  | 
2207  |  |     // Fall back to slow path (clone and mutate the NumberFormat)  | 
2208  | 0  |     if (currentNumberFormat != nullptr) { | 
2209  | 0  |         FieldPosition pos(FieldPosition::DONT_CARE);  | 
2210  | 0  |         LocalPointer<NumberFormat> nf(currentNumberFormat->clone());  | 
2211  | 0  |         nf->setMinimumIntegerDigits(minDigits);  | 
2212  | 0  |         nf->setMaximumIntegerDigits(maxDigits);  | 
2213  | 0  |         nf->format(value, appendTo, pos);  // 3rd arg is there to speed up processing  | 
2214  | 0  |     }  | 
2215  | 0  | }  | 
2216  |  |  | 
2217  |  | //----------------------------------------------------------------------  | 
2218  |  |  | 
2219  |  | /**  | 
2220  |  |  * Return true if the given format character, occurring count  | 
2221  |  |  * times, represents a numeric field.  | 
2222  |  |  */  | 
2223  | 0  | UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) { | 
2224  | 0  |     return DateFormatSymbols::isNumericPatternChar(formatChar, count);  | 
2225  | 0  | }  | 
2226  |  |  | 
2227  |  | UBool  | 
2228  | 0  | SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) { | 
2229  | 0  |     if (patternOffset >= pattern.length()) { | 
2230  |  |         // not at any field  | 
2231  | 0  |         return FALSE;  | 
2232  | 0  |     }  | 
2233  | 0  |     UChar ch = pattern.charAt(patternOffset);  | 
2234  | 0  |     UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);  | 
2235  | 0  |     if (f == UDAT_FIELD_COUNT) { | 
2236  |  |         // not at any field  | 
2237  | 0  |         return FALSE;  | 
2238  | 0  |     }  | 
2239  | 0  |     int32_t i = patternOffset;  | 
2240  | 0  |     while (pattern.charAt(++i) == ch) {} | 
2241  | 0  |     return DateFormatSymbols::isNumericField(f, i - patternOffset);  | 
2242  | 0  | }  | 
2243  |  |  | 
2244  |  | UBool  | 
2245  | 0  | SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) { | 
2246  | 0  |     if (patternOffset <= 0) { | 
2247  |  |         // not after any field  | 
2248  | 0  |         return FALSE;  | 
2249  | 0  |     }  | 
2250  | 0  |     UChar ch = pattern.charAt(--patternOffset);  | 
2251  | 0  |     UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);  | 
2252  | 0  |     if (f == UDAT_FIELD_COUNT) { | 
2253  |  |         // not after any field  | 
2254  | 0  |         return FALSE;  | 
2255  | 0  |     }  | 
2256  | 0  |     int32_t i = patternOffset;  | 
2257  | 0  |     while (pattern.charAt(--i) == ch) {} | 
2258  | 0  |     return !DateFormatSymbols::isNumericField(f, patternOffset - i);  | 
2259  | 0  | }  | 
2260  |  |  | 
2261  |  | void  | 
2262  |  | SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const  | 
2263  | 0  | { | 
2264  | 0  |     UErrorCode status = U_ZERO_ERROR;  | 
2265  | 0  |     int32_t pos = parsePos.getIndex();  | 
2266  | 0  |     if(parsePos.getIndex() < 0) { | 
2267  | 0  |         parsePos.setErrorIndex(0);  | 
2268  | 0  |         return;  | 
2269  | 0  |     }  | 
2270  | 0  |     int32_t start = pos;  | 
2271  |  |  | 
2272  |  |     // Hold the day period until everything else is parsed, because we need  | 
2273  |  |     // the hour to interpret time correctly.  | 
2274  | 0  |     int32_t dayPeriodInt = -1;  | 
2275  |  | 
  | 
2276  | 0  |     UBool ambiguousYear[] = { FALSE }; | 
2277  | 0  |     int32_t saveHebrewMonth = -1;  | 
2278  | 0  |     int32_t count = 0;  | 
2279  | 0  |     UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;  | 
2280  |  |  | 
2281  |  |     // For parsing abutting numeric fields. 'abutPat' is the  | 
2282  |  |     // offset into 'pattern' of the first of 2 or more abutting  | 
2283  |  |     // numeric fields.  'abutStart' is the offset into 'text'  | 
2284  |  |     // where parsing the fields begins. 'abutPass' starts off as 0  | 
2285  |  |     // and increments each time we try to parse the fields.  | 
2286  | 0  |     int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields  | 
2287  | 0  |     int32_t abutStart = 0;  | 
2288  | 0  |     int32_t abutPass = 0;  | 
2289  | 0  |     UBool inQuote = FALSE;  | 
2290  |  | 
  | 
2291  | 0  |     MessageFormat * numericLeapMonthFormatter = NULL;  | 
2292  |  | 
  | 
2293  | 0  |     Calendar* calClone = NULL;  | 
2294  | 0  |     Calendar *workCal = &cal;  | 
2295  | 0  |     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) { | 
2296  |  |         // Different calendar type  | 
2297  |  |         // We use the time/zone from the input calendar, but  | 
2298  |  |         // do not use the input calendar for field calculation.  | 
2299  | 0  |         calClone = fCalendar->clone();  | 
2300  | 0  |         if (calClone != NULL) { | 
2301  | 0  |             calClone->setTime(cal.getTime(status),status);  | 
2302  | 0  |             if (U_FAILURE(status)) { | 
2303  | 0  |                 goto ExitParse;  | 
2304  | 0  |             }  | 
2305  | 0  |             calClone->setTimeZone(cal.getTimeZone());  | 
2306  | 0  |             workCal = calClone;  | 
2307  | 0  |         } else { | 
2308  | 0  |             status = U_MEMORY_ALLOCATION_ERROR;  | 
2309  | 0  |             goto ExitParse;  | 
2310  | 0  |         }  | 
2311  | 0  |     }  | 
2312  |  |  | 
2313  | 0  |     if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) { | 
2314  | 0  |         numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);  | 
2315  | 0  |         if (numericLeapMonthFormatter == NULL) { | 
2316  | 0  |              status = U_MEMORY_ALLOCATION_ERROR;  | 
2317  | 0  |              goto ExitParse;  | 
2318  | 0  |         } else if (U_FAILURE(status)) { | 
2319  | 0  |              goto ExitParse; // this will delete numericLeapMonthFormatter  | 
2320  | 0  |         }  | 
2321  | 0  |     }  | 
2322  |  |  | 
2323  | 0  |     for (int32_t i=0; i<fPattern.length(); ++i) { | 
2324  | 0  |         UChar ch = fPattern.charAt(i);  | 
2325  |  |  | 
2326  |  |         // Handle alphabetic field characters.  | 
2327  | 0  |         if (!inQuote && isSyntaxChar(ch)) { | 
2328  | 0  |             int32_t fieldPat = i;  | 
2329  |  |  | 
2330  |  |             // Count the length of this field specifier  | 
2331  | 0  |             count = 1;  | 
2332  | 0  |             while ((i+1)<fPattern.length() &&  | 
2333  | 0  |                    fPattern.charAt(i+1) == ch) { | 
2334  | 0  |                 ++count;  | 
2335  | 0  |                 ++i;  | 
2336  | 0  |             }  | 
2337  |  | 
  | 
2338  | 0  |             if (isNumeric(ch, count)) { | 
2339  | 0  |                 if (abutPat < 0) { | 
2340  |  |                     // Determine if there is an abutting numeric field.  | 
2341  |  |                     // Record the start of a set of abutting numeric fields.  | 
2342  | 0  |                     if (isAtNumericField(fPattern, i + 1)) { | 
2343  | 0  |                         abutPat = fieldPat;  | 
2344  | 0  |                         abutStart = pos;  | 
2345  | 0  |                         abutPass = 0;  | 
2346  | 0  |                     }  | 
2347  | 0  |                 }  | 
2348  | 0  |             } else { | 
2349  | 0  |                 abutPat = -1; // End of any abutting fields  | 
2350  | 0  |             }  | 
2351  |  |  | 
2352  |  |             // Handle fields within a run of abutting numeric fields.  Take  | 
2353  |  |             // the pattern "HHmmss" as an example. We will try to parse  | 
2354  |  |             // 2/2/2 characters of the input text, then if that fails,  | 
2355  |  |             // 1/2/2.  We only adjust the width of the leftmost field; the  | 
2356  |  |             // others remain fixed.  This allows "123456" => 12:34:56, but  | 
2357  |  |             // "12345" => 1:23:45.  Likewise, for the pattern "yyyyMMdd" we  | 
2358  |  |             // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2.  | 
2359  | 0  |             if (abutPat >= 0) { | 
2360  |  |                 // If we are at the start of a run of abutting fields, then  | 
2361  |  |                 // shorten this field in each pass.  If we can't shorten  | 
2362  |  |                 // this field any more, then the parse of this set of  | 
2363  |  |                 // abutting numeric fields has failed.  | 
2364  | 0  |                 if (fieldPat == abutPat) { | 
2365  | 0  |                     count -= abutPass++;  | 
2366  | 0  |                     if (count == 0) { | 
2367  | 0  |                         status = U_PARSE_ERROR;  | 
2368  | 0  |                         goto ExitParse;  | 
2369  | 0  |                     }  | 
2370  | 0  |                 }  | 
2371  |  |  | 
2372  | 0  |                 pos = subParse(text, pos, ch, count,  | 
2373  | 0  |                                TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType);  | 
2374  |  |  | 
2375  |  |                 // If the parse fails anywhere in the run, back up to the  | 
2376  |  |                 // start of the run and retry.  | 
2377  | 0  |                 if (pos < 0) { | 
2378  | 0  |                     i = abutPat - 1;  | 
2379  | 0  |                     pos = abutStart;  | 
2380  | 0  |                     continue;  | 
2381  | 0  |                 }  | 
2382  | 0  |             }  | 
2383  |  |  | 
2384  |  |             // Handle non-numeric fields and non-abutting numeric  | 
2385  |  |             // fields.  | 
2386  | 0  |             else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored | 
2387  | 0  |                 int32_t s = subParse(text, pos, ch, count,  | 
2388  | 0  |                                FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, &dayPeriodInt);  | 
2389  |  | 
  | 
2390  | 0  |                 if (s == -pos-1) { | 
2391  |  |                     // era not present, in special cases allow this to continue  | 
2392  |  |                     // from the position where the era was expected  | 
2393  | 0  |                     s = pos;  | 
2394  |  | 
  | 
2395  | 0  |                     if (i+1 < fPattern.length()) { | 
2396  |  |                         // move to next pattern character  | 
2397  | 0  |                         UChar c = fPattern.charAt(i+1);  | 
2398  |  |  | 
2399  |  |                         // check for whitespace  | 
2400  | 0  |                         if (PatternProps::isWhiteSpace(c)) { | 
2401  | 0  |                             i++;  | 
2402  |  |                             // Advance over run in pattern  | 
2403  | 0  |                             while ((i+1)<fPattern.length() &&  | 
2404  | 0  |                                    PatternProps::isWhiteSpace(fPattern.charAt(i+1))) { | 
2405  | 0  |                                 ++i;  | 
2406  | 0  |                             }  | 
2407  | 0  |                         }  | 
2408  | 0  |                     }  | 
2409  | 0  |                 }  | 
2410  | 0  |                 else if (s <= 0) { | 
2411  | 0  |                     status = U_PARSE_ERROR;  | 
2412  | 0  |                     goto ExitParse;  | 
2413  | 0  |                 }  | 
2414  | 0  |                 pos = s;  | 
2415  | 0  |             }  | 
2416  | 0  |         }  | 
2417  |  |  | 
2418  |  |         // Handle literal pattern characters.  These are any  | 
2419  |  |         // quoted characters and non-alphabetic unquoted  | 
2420  |  |         // characters.  | 
2421  | 0  |         else { | 
2422  |  | 
  | 
2423  | 0  |             abutPat = -1; // End of any abutting fields  | 
2424  |  | 
  | 
2425  | 0  |             if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status), isLenient())) { | 
2426  | 0  |                 status = U_PARSE_ERROR;  | 
2427  | 0  |                 goto ExitParse;  | 
2428  | 0  |             }  | 
2429  | 0  |         }  | 
2430  | 0  |     }  | 
2431  |  |  | 
2432  |  |     // Special hack for trailing "." after non-numeric field.  | 
2433  | 0  |     if (text.charAt(pos) == 0x2e && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) { | 
2434  |  |         // only do if the last field is not numeric  | 
2435  | 0  |         if (isAfterNonNumericField(fPattern, fPattern.length())) { | 
2436  | 0  |             pos++; // skip the extra "."  | 
2437  | 0  |         }  | 
2438  | 0  |     }  | 
2439  |  |  | 
2440  |  |     // If dayPeriod is set, use it in conjunction with hour-of-day to determine am/pm.  | 
2441  | 0  |     if (dayPeriodInt >= 0) { | 
2442  | 0  |         DayPeriodRules::DayPeriod dayPeriod = (DayPeriodRules::DayPeriod)dayPeriodInt;  | 
2443  | 0  |         const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);  | 
2444  |  | 
  | 
2445  | 0  |         if (!cal.isSet(UCAL_HOUR) && !cal.isSet(UCAL_HOUR_OF_DAY)) { | 
2446  |  |             // If hour is not set, set time to the midpoint of current day period, overwriting  | 
2447  |  |             // minutes if it's set.  | 
2448  | 0  |             double midPoint = ruleSet->getMidPointForDayPeriod(dayPeriod, status);  | 
2449  |  |  | 
2450  |  |             // If we can't get midPoint we do nothing.  | 
2451  | 0  |             if (U_SUCCESS(status)) { | 
2452  |  |                 // Truncate midPoint toward zero to get the hour.  | 
2453  |  |                 // Any leftover means it was a half-hour.  | 
2454  | 0  |                 int32_t midPointHour = (int32_t) midPoint;  | 
2455  | 0  |                 int32_t midPointMinute = (midPoint - midPointHour) > 0 ? 30 : 0;  | 
2456  |  |  | 
2457  |  |                 // No need to set am/pm because hour-of-day is set last therefore takes precedence.  | 
2458  | 0  |                 cal.set(UCAL_HOUR_OF_DAY, midPointHour);  | 
2459  | 0  |                 cal.set(UCAL_MINUTE, midPointMinute);  | 
2460  | 0  |             }  | 
2461  | 0  |         } else { | 
2462  | 0  |             int hourOfDay;  | 
2463  |  | 
  | 
2464  | 0  |             if (cal.isSet(UCAL_HOUR_OF_DAY)) {  // Hour is parsed in 24-hour format. | 
2465  | 0  |                 hourOfDay = cal.get(UCAL_HOUR_OF_DAY, status);  | 
2466  | 0  |             } else {  // Hour is parsed in 12-hour format. | 
2467  | 0  |                 hourOfDay = cal.get(UCAL_HOUR, status);  | 
2468  |  |                 // cal.get() turns 12 to 0 for 12-hour time; change 0 to 12  | 
2469  |  |                 // so 0 unambiguously means a 24-hour time from above.  | 
2470  | 0  |                 if (hourOfDay == 0) { hourOfDay = 12; } | 
2471  | 0  |             }  | 
2472  | 0  |             U_ASSERT(0 <= hourOfDay && hourOfDay <= 23);  | 
2473  |  |  | 
2474  |  |  | 
2475  |  |             // If hour-of-day is 0 or 13 thru 23 then input time in unambiguously in 24-hour format.  | 
2476  | 0  |             if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) { | 
2477  |  |                 // Make hour-of-day take precedence over (hour + am/pm) by setting it again.  | 
2478  | 0  |                 cal.set(UCAL_HOUR_OF_DAY, hourOfDay);  | 
2479  | 0  |             } else { | 
2480  |  |                 // We have a 12-hour time and need to choose between am and pm.  | 
2481  |  |                 // Behave as if dayPeriod spanned 6 hours each way from its center point.  | 
2482  |  |                 // This will parse correctly for consistent time + period (e.g. 10 at night) as  | 
2483  |  |                 // well as provide a reasonable recovery for inconsistent time + period (e.g.  | 
2484  |  |                 // 9 in the afternoon).  | 
2485  |  |  | 
2486  |  |                 // Assume current time is in the AM.  | 
2487  |  |                 // - Change 12 back to 0 for easier handling of 12am.  | 
2488  |  |                 // - Append minutes as fractional hours because e.g. 8:15 and 8:45 could be parsed  | 
2489  |  |                 // into different half-days if center of dayPeriod is at 14:30.  | 
2490  |  |                 // - cal.get(MINUTE) will return 0 if MINUTE is unset, which works.  | 
2491  | 0  |                 if (hourOfDay == 12) { hourOfDay = 0; } | 
2492  | 0  |                 double currentHour = hourOfDay + (cal.get(UCAL_MINUTE, status)) / 60.0;  | 
2493  | 0  |                 double midPointHour = ruleSet->getMidPointForDayPeriod(dayPeriod, status);  | 
2494  |  | 
  | 
2495  | 0  |                 if (U_SUCCESS(status)) { | 
2496  | 0  |                     double hoursAheadMidPoint = currentHour - midPointHour;  | 
2497  |  |  | 
2498  |  |                     // Assume current time is in the AM.  | 
2499  | 0  |                     if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) { | 
2500  |  |                         // Assumption holds; set time as such.  | 
2501  | 0  |                         cal.set(UCAL_AM_PM, 0);  | 
2502  | 0  |                     } else { | 
2503  | 0  |                         cal.set(UCAL_AM_PM, 1);  | 
2504  | 0  |                     }  | 
2505  | 0  |                 }  | 
2506  | 0  |             }  | 
2507  | 0  |         }  | 
2508  | 0  |     }  | 
2509  |  |  | 
2510  |  |     // At this point the fields of Calendar have been set.  Calendar  | 
2511  |  |     // will fill in default values for missing fields when the time  | 
2512  |  |     // is computed.  | 
2513  |  | 
  | 
2514  | 0  |     parsePos.setIndex(pos);  | 
2515  |  |  | 
2516  |  |     // This part is a problem:  When we call parsedDate.after, we compute the time.  | 
2517  |  |     // Take the date April 3 2004 at 2:30 am.  When this is first set up, the year  | 
2518  |  |     // will be wrong if we're parsing a 2-digit year pattern.  It will be 1904.  | 
2519  |  |     // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day.  2:30 am  | 
2520  |  |     // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am  | 
2521  |  |     // on that day.  It is therefore parsed out to fields as 3:30 am.  Then we  | 
2522  |  |     // add 100 years, and get April 3 2004 at 3:30 am.  Note that April 3 2004 is  | 
2523  |  |     // a Saturday, so it can have a 2:30 am -- and it should. [LIU]  | 
2524  |  |     /*  | 
2525  |  |         UDate parsedDate = calendar.getTime();  | 
2526  |  |         if( ambiguousYear[0] && !parsedDate.after(fDefaultCenturyStart) ) { | 
2527  |  |             calendar.add(Calendar.YEAR, 100);  | 
2528  |  |             parsedDate = calendar.getTime();  | 
2529  |  |         }  | 
2530  |  |     */  | 
2531  |  |     // Because of the above condition, save off the fields in case we need to readjust.  | 
2532  |  |     // The procedure we use here is not particularly efficient, but there is no other  | 
2533  |  |     // way to do this given the API restrictions present in Calendar.  We minimize  | 
2534  |  |     // inefficiency by only performing this computation when it might apply, that is,  | 
2535  |  |     // when the two-digit year is equal to the start year, and thus might fall at the  | 
2536  |  |     // front or the back of the default century.  This only works because we adjust  | 
2537  |  |     // the year correctly to start with in other cases -- see subParse().  | 
2538  | 0  |     if (ambiguousYear[0] || tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year  | 
2539  | 0  |     { | 
2540  |  |         // We need a copy of the fields, and we need to avoid triggering a call to  | 
2541  |  |         // complete(), which will recalculate the fields.  Since we can't access  | 
2542  |  |         // the fields[] array in Calendar, we clone the entire object.  This will  | 
2543  |  |         // stop working if Calendar.clone() is ever rewritten to call complete().  | 
2544  | 0  |         Calendar *copy;  | 
2545  | 0  |         if (ambiguousYear[0]) { | 
2546  | 0  |             copy = cal.clone();  | 
2547  |  |             // Check for failed cloning.  | 
2548  | 0  |             if (copy == NULL) { | 
2549  | 0  |                 status = U_MEMORY_ALLOCATION_ERROR;  | 
2550  | 0  |                 goto ExitParse;  | 
2551  | 0  |             }  | 
2552  | 0  |             UDate parsedDate = copy->getTime(status);  | 
2553  |  |             // {sfb} check internalGetDefaultCenturyStart | 
2554  | 0  |             if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) { | 
2555  |  |                 // We can't use add here because that does a complete() first.  | 
2556  | 0  |                 cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100);  | 
2557  | 0  |             }  | 
2558  | 0  |             delete copy;  | 
2559  | 0  |         }  | 
2560  |  |  | 
2561  | 0  |         if (tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) { | 
2562  | 0  |             copy = cal.clone();  | 
2563  |  |             // Check for failed cloning.  | 
2564  | 0  |             if (copy == NULL) { | 
2565  | 0  |                 status = U_MEMORY_ALLOCATION_ERROR;  | 
2566  | 0  |                 goto ExitParse;  | 
2567  | 0  |             }  | 
2568  | 0  |             const TimeZone & tz = cal.getTimeZone();  | 
2569  | 0  |             BasicTimeZone *btz = NULL;  | 
2570  |  | 
  | 
2571  | 0  |             if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL  | 
2572  | 0  |                 || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL  | 
2573  | 0  |                 || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL  | 
2574  | 0  |                 || dynamic_cast<const VTimeZone *>(&tz) != NULL) { | 
2575  | 0  |                 btz = (BasicTimeZone*)&tz;  | 
2576  | 0  |             }  | 
2577  |  |  | 
2578  |  |             // Get local millis  | 
2579  | 0  |             copy->set(UCAL_ZONE_OFFSET, 0);  | 
2580  | 0  |             copy->set(UCAL_DST_OFFSET, 0);  | 
2581  | 0  |             UDate localMillis = copy->getTime(status);  | 
2582  |  |  | 
2583  |  |             // Make sure parsed time zone type (Standard or Daylight)  | 
2584  |  |             // matches the rule used by the parsed time zone.  | 
2585  | 0  |             int32_t raw, dst;  | 
2586  | 0  |             if (btz != NULL) { | 
2587  | 0  |                 if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) { | 
2588  | 0  |                     btz->getOffsetFromLocal(localMillis,  | 
2589  | 0  |                         UCAL_TZ_LOCAL_STANDARD_FORMER, UCAL_TZ_LOCAL_STANDARD_LATTER, raw, dst, status);  | 
2590  | 0  |                 } else { | 
2591  | 0  |                     btz->getOffsetFromLocal(localMillis,  | 
2592  | 0  |                         UCAL_TZ_LOCAL_DAYLIGHT_FORMER, UCAL_TZ_LOCAL_DAYLIGHT_LATTER, raw, dst, status);  | 
2593  | 0  |                 }  | 
2594  | 0  |             } else { | 
2595  |  |                 // No good way to resolve ambiguous time at transition,  | 
2596  |  |                 // but following code work in most case.  | 
2597  | 0  |                 tz.getOffset(localMillis, TRUE, raw, dst, status);  | 
2598  | 0  |             }  | 
2599  |  |  | 
2600  |  |             // Now, compare the results with parsed type, either standard or daylight saving time  | 
2601  | 0  |             int32_t resolvedSavings = dst;  | 
2602  | 0  |             if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) { | 
2603  | 0  |                 if (dst != 0) { | 
2604  |  |                     // Override DST_OFFSET = 0 in the result calendar  | 
2605  | 0  |                     resolvedSavings = 0;  | 
2606  | 0  |                 }  | 
2607  | 0  |             } else { // tztype == TZTYPE_DST | 
2608  | 0  |                 if (dst == 0) { | 
2609  | 0  |                     if (btz != NULL) { | 
2610  |  |                         // This implementation resolves daylight saving time offset  | 
2611  |  |                         // closest rule after the given time.  | 
2612  | 0  |                         UDate baseTime = localMillis + raw;  | 
2613  | 0  |                         UDate time = baseTime;  | 
2614  | 0  |                         UDate limit = baseTime + MAX_DAYLIGHT_DETECTION_RANGE;  | 
2615  | 0  |                         TimeZoneTransition trs;  | 
2616  | 0  |                         UBool trsAvail;  | 
2617  |  |  | 
2618  |  |                         // Search for DST rule after the given time  | 
2619  | 0  |                         while (time < limit) { | 
2620  | 0  |                             trsAvail = btz->getNextTransition(time, FALSE, trs);  | 
2621  | 0  |                             if (!trsAvail) { | 
2622  | 0  |                                 break;  | 
2623  | 0  |                             }  | 
2624  | 0  |                             resolvedSavings = trs.getTo()->getDSTSavings();  | 
2625  | 0  |                             if (resolvedSavings != 0) { | 
2626  | 0  |                                 break;  | 
2627  | 0  |                             }  | 
2628  | 0  |                             time = trs.getTime();  | 
2629  | 0  |                         }  | 
2630  |  | 
  | 
2631  | 0  |                         if (resolvedSavings == 0) { | 
2632  |  |                             // If no DST rule after the given time was found, search for  | 
2633  |  |                             // DST rule before.  | 
2634  | 0  |                             time = baseTime;  | 
2635  | 0  |                             limit = baseTime - MAX_DAYLIGHT_DETECTION_RANGE;  | 
2636  | 0  |                             while (time > limit) { | 
2637  | 0  |                                 trsAvail = btz->getPreviousTransition(time, TRUE, trs);  | 
2638  | 0  |                                 if (!trsAvail) { | 
2639  | 0  |                                     break;  | 
2640  | 0  |                                 }  | 
2641  | 0  |                                 resolvedSavings = trs.getFrom()->getDSTSavings();  | 
2642  | 0  |                                 if (resolvedSavings != 0) { | 
2643  | 0  |                                     break;  | 
2644  | 0  |                                 }  | 
2645  | 0  |                                 time = trs.getTime() - 1;  | 
2646  | 0  |                             }  | 
2647  |  | 
  | 
2648  | 0  |                             if (resolvedSavings == 0) { | 
2649  | 0  |                                 resolvedSavings = btz->getDSTSavings();  | 
2650  | 0  |                             }  | 
2651  | 0  |                         }  | 
2652  | 0  |                     } else { | 
2653  | 0  |                         resolvedSavings = tz.getDSTSavings();  | 
2654  | 0  |                     }  | 
2655  | 0  |                     if (resolvedSavings == 0) { | 
2656  |  |                         // final fallback  | 
2657  | 0  |                         resolvedSavings = U_MILLIS_PER_HOUR;  | 
2658  | 0  |                     }  | 
2659  | 0  |                 }  | 
2660  | 0  |             }  | 
2661  | 0  |             cal.set(UCAL_ZONE_OFFSET, raw);  | 
2662  | 0  |             cal.set(UCAL_DST_OFFSET, resolvedSavings);  | 
2663  | 0  |             delete copy;  | 
2664  | 0  |         }  | 
2665  | 0  |     }  | 
2666  | 0  | ExitParse:  | 
2667  |  |     // Set the parsed result if local calendar is used  | 
2668  |  |     // instead of the input calendar  | 
2669  | 0  |     if (U_SUCCESS(status) && workCal != &cal) { | 
2670  | 0  |         cal.setTimeZone(workCal->getTimeZone());  | 
2671  | 0  |         cal.setTime(workCal->getTime(status), status);  | 
2672  | 0  |     }  | 
2673  |  | 
  | 
2674  | 0  |     if (numericLeapMonthFormatter != NULL) { | 
2675  | 0  |         delete numericLeapMonthFormatter;  | 
2676  | 0  |     }  | 
2677  | 0  |     if (calClone != NULL) { | 
2678  | 0  |         delete calClone;  | 
2679  | 0  |     }  | 
2680  |  |  | 
2681  |  |     // If any Calendar calls failed, we pretend that we  | 
2682  |  |     // couldn't parse the string, when in reality this isn't quite accurate--  | 
2683  |  |     // we did parse it; the Calendar calls just failed.  | 
2684  | 0  |     if (U_FAILURE(status)) { | 
2685  | 0  |         parsePos.setErrorIndex(pos);  | 
2686  | 0  |         parsePos.setIndex(start);  | 
2687  | 0  |     }  | 
2688  | 0  | }  | 
2689  |  |  | 
2690  |  | //----------------------------------------------------------------------  | 
2691  |  |  | 
2692  |  | static int32_t  | 
2693  |  | matchStringWithOptionalDot(const UnicodeString &text,  | 
2694  |  |                             int32_t index,  | 
2695  |  |                             const UnicodeString &data);  | 
2696  |  |  | 
2697  |  | int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,  | 
2698  |  |                               int32_t start,  | 
2699  |  |                               UCalendarDateFields field,  | 
2700  |  |                               const UnicodeString* data,  | 
2701  |  |                               int32_t dataCount,  | 
2702  |  |                               Calendar& cal) const  | 
2703  | 0  | { | 
2704  | 0  |     int32_t i = 0;  | 
2705  | 0  |     int32_t count = dataCount;  | 
2706  |  |  | 
2707  |  |     // There may be multiple strings in the data[] array which begin with  | 
2708  |  |     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).  | 
2709  |  |     // We keep track of the longest match, and return that.  Note that this  | 
2710  |  |     // unfortunately requires us to test all array elements.  | 
2711  | 0  |     int32_t bestMatchLength = 0, bestMatch = -1;  | 
2712  | 0  |     UnicodeString bestMatchName;  | 
2713  |  | 
  | 
2714  | 0  |     for (; i < count; ++i) { | 
2715  | 0  |         int32_t matchLength = 0;  | 
2716  | 0  |         if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) { | 
2717  | 0  |             bestMatchLength = matchLength;  | 
2718  | 0  |             bestMatch = i;  | 
2719  | 0  |         }  | 
2720  | 0  |     }  | 
2721  |  | 
  | 
2722  | 0  |     if (bestMatch >= 0) { | 
2723  | 0  |         cal.set(field, bestMatch * 3);  | 
2724  | 0  |         return start + bestMatchLength;  | 
2725  | 0  |     }  | 
2726  |  |  | 
2727  | 0  |     return -start;  | 
2728  | 0  | }  | 
2729  |  |  | 
2730  |  | int32_t SimpleDateFormat::matchDayPeriodStrings(const UnicodeString& text, int32_t start,  | 
2731  |  |                               const UnicodeString* data, int32_t dataCount,  | 
2732  |  |                               int32_t &dayPeriod) const  | 
2733  | 0  | { | 
2734  |  | 
  | 
2735  | 0  |     int32_t bestMatchLength = 0, bestMatch = -1;  | 
2736  |  | 
  | 
2737  | 0  |     for (int32_t i = 0; i < dataCount; ++i) { | 
2738  | 0  |         int32_t matchLength = 0;  | 
2739  | 0  |         if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) { | 
2740  | 0  |             bestMatchLength = matchLength;  | 
2741  | 0  |             bestMatch = i;  | 
2742  | 0  |         }  | 
2743  | 0  |     }  | 
2744  |  | 
  | 
2745  | 0  |     if (bestMatch >= 0) { | 
2746  | 0  |         dayPeriod = bestMatch;  | 
2747  | 0  |         return start + bestMatchLength;  | 
2748  | 0  |     }  | 
2749  |  |  | 
2750  | 0  |     return -start;  | 
2751  | 0  | }  | 
2752  |  |  | 
2753  |  | //----------------------------------------------------------------------  | 
2754  |  | UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,  | 
2755  |  |                                       int32_t &patternOffset,  | 
2756  |  |                                       const UnicodeString &text,  | 
2757  |  |                                       int32_t &textOffset,  | 
2758  |  |                                       UBool whitespaceLenient,  | 
2759  |  |                                       UBool partialMatchLenient,  | 
2760  |  |                                       UBool oldLeniency)  | 
2761  | 0  | { | 
2762  | 0  |     UBool inQuote = FALSE;  | 
2763  | 0  |     UnicodeString literal;  | 
2764  | 0  |     int32_t i = patternOffset;  | 
2765  |  |  | 
2766  |  |     // scan pattern looking for contiguous literal characters  | 
2767  | 0  |     for ( ; i < pattern.length(); i += 1) { | 
2768  | 0  |         UChar ch = pattern.charAt(i);  | 
2769  |  | 
  | 
2770  | 0  |         if (!inQuote && isSyntaxChar(ch)) { | 
2771  | 0  |             break;  | 
2772  | 0  |         }  | 
2773  |  |  | 
2774  | 0  |         if (ch == QUOTE) { | 
2775  |  |             // Match a quote literal ('') inside OR outside of quotes | 
2776  | 0  |             if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) { | 
2777  | 0  |                 i += 1;  | 
2778  | 0  |             } else { | 
2779  | 0  |                 inQuote = !inQuote;  | 
2780  | 0  |                 continue;  | 
2781  | 0  |             }  | 
2782  | 0  |         }  | 
2783  |  |  | 
2784  | 0  |         literal += ch;  | 
2785  | 0  |     }  | 
2786  |  |  | 
2787  |  |     // at this point, literal contains the literal text  | 
2788  |  |     // and i is the index of the next non-literal pattern character.  | 
2789  | 0  |     int32_t p;  | 
2790  | 0  |     int32_t t = textOffset;  | 
2791  |  | 
  | 
2792  | 0  |     if (whitespaceLenient) { | 
2793  |  |         // trim leading, trailing whitespace from  | 
2794  |  |         // the literal text  | 
2795  | 0  |         literal.trim();  | 
2796  |  |  | 
2797  |  |         // ignore any leading whitespace in the text  | 
2798  | 0  |         while (t < text.length() && u_isWhitespace(text.charAt(t))) { | 
2799  | 0  |             t += 1;  | 
2800  | 0  |         }  | 
2801  | 0  |     }  | 
2802  |  | 
  | 
2803  | 0  |     for (p = 0; p < literal.length() && t < text.length();) { | 
2804  | 0  |         UBool needWhitespace = FALSE;  | 
2805  |  | 
  | 
2806  | 0  |         while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) { | 
2807  | 0  |             needWhitespace = TRUE;  | 
2808  | 0  |             p += 1;  | 
2809  | 0  |         }  | 
2810  |  | 
  | 
2811  | 0  |         if (needWhitespace) { | 
2812  | 0  |             int32_t tStart = t;  | 
2813  |  | 
  | 
2814  | 0  |             while (t < text.length()) { | 
2815  | 0  |                 UChar tch = text.charAt(t);  | 
2816  |  | 
  | 
2817  | 0  |                 if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) { | 
2818  | 0  |                     break;  | 
2819  | 0  |                 }  | 
2820  |  |  | 
2821  | 0  |                 t += 1;  | 
2822  | 0  |             }  | 
2823  |  |  | 
2824  |  |             // TODO: should we require internal spaces  | 
2825  |  |             // in lenient mode? (There won't be any  | 
2826  |  |             // leading or trailing spaces)  | 
2827  | 0  |             if (!whitespaceLenient && t == tStart) { | 
2828  |  |                 // didn't find matching whitespace:  | 
2829  |  |                 // an error in strict mode  | 
2830  | 0  |                 return FALSE;  | 
2831  | 0  |             }  | 
2832  |  |  | 
2833  |  |             // In strict mode, this run of whitespace  | 
2834  |  |             // may have been at the end.  | 
2835  | 0  |             if (p >= literal.length()) { | 
2836  | 0  |                 break;  | 
2837  | 0  |             }  | 
2838  | 0  |         }  | 
2839  | 0  |         if (t >= text.length() || literal.charAt(p) != text.charAt(t)) { | 
2840  |  |             // Ran out of text, or found a non-matching character:  | 
2841  |  |             // OK in lenient mode, an error in strict mode.  | 
2842  | 0  |             if (whitespaceLenient) { | 
2843  | 0  |                 if (t == textOffset && text.charAt(t) == 0x2e &&  | 
2844  | 0  |                         isAfterNonNumericField(pattern, patternOffset)) { | 
2845  |  |                     // Lenient mode and the literal input text begins with a "." and  | 
2846  |  |                     // we are after a non-numeric field: We skip the "."  | 
2847  | 0  |                     ++t;  | 
2848  | 0  |                     continue;  // Do not update p.  | 
2849  | 0  |                 }  | 
2850  |  |                 // if it is actual whitespace and we're whitespace lenient it's OK  | 
2851  |  |  | 
2852  | 0  |                 UChar wsc = text.charAt(t);  | 
2853  | 0  |                 if(PatternProps::isWhiteSpace(wsc)) { | 
2854  |  |                     // Lenient mode and it's just whitespace we skip it  | 
2855  | 0  |                     ++t;  | 
2856  | 0  |                     continue;  // Do not update p.  | 
2857  | 0  |                 }  | 
2858  | 0  |             }  | 
2859  |  |             // hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for partial matches  | 
2860  | 0  |             if(partialMatchLenient && oldLeniency) { | 
2861  | 0  |                 break;  | 
2862  | 0  |             }  | 
2863  |  |  | 
2864  | 0  |             return FALSE;  | 
2865  | 0  |         }  | 
2866  | 0  |         ++p;  | 
2867  | 0  |         ++t;  | 
2868  | 0  |     }  | 
2869  |  |  | 
2870  |  |     // At this point if we're in strict mode we have a complete match.  | 
2871  |  |     // If we're in lenient mode we may have a partial match, or no  | 
2872  |  |     // match at all.  | 
2873  | 0  |     if (p <= 0) { | 
2874  |  |         // no match. Pretend it matched a run of whitespace  | 
2875  |  |         // and ignorables in the text.  | 
2876  | 0  |         const  UnicodeSet *ignorables = NULL;  | 
2877  | 0  |         UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i));  | 
2878  | 0  |         if (patternCharIndex != UDAT_FIELD_COUNT) { | 
2879  | 0  |             ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);  | 
2880  | 0  |         }  | 
2881  |  | 
  | 
2882  | 0  |         for (t = textOffset; t < text.length(); t += 1) { | 
2883  | 0  |             UChar ch = text.charAt(t);  | 
2884  |  | 
  | 
2885  | 0  |             if (ignorables == NULL || !ignorables->contains(ch)) { | 
2886  | 0  |                 break;  | 
2887  | 0  |             }  | 
2888  | 0  |         }  | 
2889  | 0  |     }  | 
2890  |  |  | 
2891  |  |     // if we get here, we've got a complete match.  | 
2892  | 0  |     patternOffset = i - 1;  | 
2893  | 0  |     textOffset = t;  | 
2894  |  | 
  | 
2895  | 0  |     return TRUE;  | 
2896  | 0  | }  | 
2897  |  |  | 
2898  |  | //----------------------------------------------------------------------  | 
2899  |  |  | 
2900  |  | int32_t SimpleDateFormat::matchString(const UnicodeString& text,  | 
2901  |  |                               int32_t start,  | 
2902  |  |                               UCalendarDateFields field,  | 
2903  |  |                               const UnicodeString* data,  | 
2904  |  |                               int32_t dataCount,  | 
2905  |  |                               const UnicodeString* monthPattern,  | 
2906  |  |                               Calendar& cal) const  | 
2907  | 0  | { | 
2908  | 0  |     int32_t i = 0;  | 
2909  | 0  |     int32_t count = dataCount;  | 
2910  |  | 
  | 
2911  | 0  |     if (field == UCAL_DAY_OF_WEEK) i = 1;  | 
2912  |  |  | 
2913  |  |     // There may be multiple strings in the data[] array which begin with  | 
2914  |  |     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).  | 
2915  |  |     // We keep track of the longest match, and return that.  Note that this  | 
2916  |  |     // unfortunately requires us to test all array elements.  | 
2917  | 0  |     int32_t bestMatchLength = 0, bestMatch = -1;  | 
2918  | 0  |     UnicodeString bestMatchName;  | 
2919  | 0  |     int32_t isLeapMonth = 0;  | 
2920  |  | 
  | 
2921  | 0  |     for (; i < count; ++i) { | 
2922  | 0  |         int32_t matchLen = 0;  | 
2923  | 0  |         if ((matchLen = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) { | 
2924  | 0  |             bestMatch = i;  | 
2925  | 0  |             bestMatchLength = matchLen;  | 
2926  | 0  |         }  | 
2927  |  | 
  | 
2928  | 0  |         if (monthPattern != NULL) { | 
2929  | 0  |             UErrorCode status = U_ZERO_ERROR;  | 
2930  | 0  |             UnicodeString leapMonthName;  | 
2931  | 0  |             SimpleFormatter(*monthPattern, 1, 1, status).format(data[i], leapMonthName, status);  | 
2932  | 0  |             if (U_SUCCESS(status)) { | 
2933  | 0  |                 if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) { | 
2934  | 0  |                     bestMatch = i;  | 
2935  | 0  |                     bestMatchLength = matchLen;  | 
2936  | 0  |                     isLeapMonth = 1;  | 
2937  | 0  |                 }  | 
2938  | 0  |             }  | 
2939  | 0  |         }  | 
2940  | 0  |     }  | 
2941  |  | 
  | 
2942  | 0  |     if (bestMatch >= 0) { | 
2943  | 0  |         if (field < UCAL_FIELD_COUNT) { | 
2944  |  |             // Adjustment for Hebrew Calendar month Adar II  | 
2945  | 0  |             if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) { | 
2946  | 0  |                 cal.set(field,6);  | 
2947  | 0  |             } else { | 
2948  | 0  |                 if (field == UCAL_YEAR) { | 
2949  | 0  |                     bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60  | 
2950  | 0  |                 }  | 
2951  | 0  |                 cal.set(field, bestMatch);  | 
2952  | 0  |             }  | 
2953  | 0  |             if (monthPattern != NULL) { | 
2954  | 0  |                 cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);  | 
2955  | 0  |             }  | 
2956  | 0  |         }  | 
2957  |  | 
  | 
2958  | 0  |         return start + bestMatchLength;  | 
2959  | 0  |     }  | 
2960  |  |  | 
2961  | 0  |     return -start;  | 
2962  | 0  | }  | 
2963  |  |  | 
2964  |  | static int32_t  | 
2965  |  | matchStringWithOptionalDot(const UnicodeString &text,  | 
2966  |  |                             int32_t index,  | 
2967  | 0  |                             const UnicodeString &data) { | 
2968  | 0  |     UErrorCode sts = U_ZERO_ERROR;  | 
2969  | 0  |     int32_t matchLenText = 0;  | 
2970  | 0  |     int32_t matchLenData = 0;  | 
2971  |  | 
  | 
2972  | 0  |     u_caseInsensitivePrefixMatch(text.getBuffer() + index, text.length() - index,  | 
2973  | 0  |                                  data.getBuffer(), data.length(),  | 
2974  | 0  |                                  0 /* default case option */,  | 
2975  | 0  |                                  &matchLenText, &matchLenData,  | 
2976  | 0  |                                  &sts);  | 
2977  | 0  |     U_ASSERT (U_SUCCESS(sts));  | 
2978  |  | 
  | 
2979  | 0  |     if (matchLenData == data.length() /* normal match */  | 
2980  | 0  |         || (data.charAt(data.length() - 1) == 0x2e  | 
2981  | 0  |             && matchLenData == data.length() - 1 /* match without trailing dot */)) { | 
2982  | 0  |         return matchLenText;  | 
2983  | 0  |     }  | 
2984  |  |  | 
2985  | 0  |     return 0;  | 
2986  | 0  | }  | 
2987  |  |  | 
2988  |  | //----------------------------------------------------------------------  | 
2989  |  |  | 
2990  |  | void  | 
2991  |  | SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)  | 
2992  | 0  | { | 
2993  | 0  |     parseAmbiguousDatesAsAfter(d, status);  | 
2994  | 0  | }  | 
2995  |  |  | 
2996  |  | /**  | 
2997  |  |  * Private member function that converts the parsed date strings into  | 
2998  |  |  * timeFields. Returns -start (for ParsePosition) if failed.  | 
2999  |  |  */  | 
3000  |  | int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,  | 
3001  |  |                            UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,  | 
3002  |  |                            int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType,  | 
3003  |  |                            int32_t *dayPeriod) const  | 
3004  | 0  | { | 
3005  | 0  |     Formattable number;  | 
3006  | 0  |     int32_t value = 0;  | 
3007  | 0  |     int32_t i;  | 
3008  | 0  |     int32_t ps = 0;  | 
3009  | 0  |     UErrorCode status = U_ZERO_ERROR;  | 
3010  | 0  |     ParsePosition pos(0);  | 
3011  | 0  |     UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);  | 
3012  | 0  |     const NumberFormat *currentNumberFormat;  | 
3013  | 0  |     UnicodeString temp;  | 
3014  | 0  |     UBool gotNumber = FALSE;  | 
3015  |  | 
  | 
3016  |  | #if defined (U_DEBUG_CAL)  | 
3017  |  |     //fprintf(stderr, "%s:%d - [%c]  st=%d \n", __FILE__, __LINE__, (char) ch, start);  | 
3018  |  | #endif  | 
3019  |  | 
  | 
3020  | 0  |     if (patternCharIndex == UDAT_FIELD_COUNT) { | 
3021  | 0  |         return -start;  | 
3022  | 0  |     }  | 
3023  |  |  | 
3024  | 0  |     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);  | 
3025  | 0  |     if (currentNumberFormat == NULL) { | 
3026  | 0  |         return -start;  | 
3027  | 0  |     }  | 
3028  | 0  |     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; // UCAL_FIELD_COUNT if irrelevant  | 
3029  | 0  |     UnicodeString hebr("hebr", 4, US_INV); | 
3030  |  | 
  | 
3031  | 0  |     if (numericLeapMonthFormatter != NULL) { | 
3032  | 0  |         numericLeapMonthFormatter->setFormats((const Format **)¤tNumberFormat, 1);  | 
3033  | 0  |     }  | 
3034  | 0  |     UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);  | 
3035  |  |  | 
3036  |  |     // If there are any spaces here, skip over them.  If we hit the end  | 
3037  |  |     // of the string, then fail.  | 
3038  | 0  |     for (;;) { | 
3039  | 0  |         if (start >= text.length()) { | 
3040  | 0  |             return -start;  | 
3041  | 0  |         }  | 
3042  | 0  |         UChar32 c = text.char32At(start);  | 
3043  | 0  |         if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) { | 
3044  | 0  |             break;  | 
3045  | 0  |         }  | 
3046  | 0  |         start += U16_LENGTH(c);  | 
3047  | 0  |     }  | 
3048  | 0  |     pos.setIndex(start);  | 
3049  |  |  | 
3050  |  |     // We handle a few special cases here where we need to parse  | 
3051  |  |     // a number value.  We handle further, more generic cases below.  We need  | 
3052  |  |     // to handle some of them here because some fields require extra processing on  | 
3053  |  |     // the parsed value.  | 
3054  | 0  |     if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||                       // k  | 
3055  | 0  |         patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD ||                       // H  | 
3056  | 0  |         patternCharIndex == UDAT_HOUR1_FIELD ||                              // h  | 
3057  | 0  |         patternCharIndex == UDAT_HOUR0_FIELD ||                              // K  | 
3058  | 0  |         (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) ||          // e  | 
3059  | 0  |         (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) ||     // c  | 
3060  | 0  |         (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||              // M  | 
3061  | 0  |         (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||   // L  | 
3062  | 0  |         (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||            // Q  | 
3063  | 0  |         (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q  | 
3064  | 0  |         patternCharIndex == UDAT_YEAR_FIELD ||                               // y  | 
3065  | 0  |         patternCharIndex == UDAT_YEAR_WOY_FIELD ||                           // Y  | 
3066  | 0  |         patternCharIndex == UDAT_YEAR_NAME_FIELD ||                          // U (falls back to numeric)  | 
3067  | 0  |         (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) ||         // G  | 
3068  | 0  |         patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)                    // S  | 
3069  | 0  |     { | 
3070  | 0  |         int32_t parseStart = pos.getIndex();  | 
3071  |  |         // It would be good to unify this with the obeyCount logic below,  | 
3072  |  |         // but that's going to be difficult.  | 
3073  | 0  |         const UnicodeString* src;  | 
3074  |  | 
  | 
3075  | 0  |         UBool parsedNumericLeapMonth = FALSE;  | 
3076  | 0  |         if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) { | 
3077  | 0  |             int32_t argCount;  | 
3078  | 0  |             Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount);  | 
3079  | 0  |             if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) { | 
3080  | 0  |                 parsedNumericLeapMonth = TRUE;  | 
3081  | 0  |                 number.setLong(args[0].getLong());  | 
3082  | 0  |                 cal.set(UCAL_IS_LEAP_MONTH, 1);  | 
3083  | 0  |                 delete[] args;  | 
3084  | 0  |             } else { | 
3085  | 0  |                 pos.setIndex(parseStart);  | 
3086  | 0  |                 cal.set(UCAL_IS_LEAP_MONTH, 0);  | 
3087  | 0  |             }  | 
3088  | 0  |         }  | 
3089  |  | 
  | 
3090  | 0  |         if (!parsedNumericLeapMonth) { | 
3091  | 0  |             if (obeyCount) { | 
3092  | 0  |                 if ((start+count) > text.length()) { | 
3093  | 0  |                     return -start;  | 
3094  | 0  |                 }  | 
3095  |  |  | 
3096  | 0  |                 text.extractBetween(0, start + count, temp);  | 
3097  | 0  |                 src = &temp;  | 
3098  | 0  |             } else { | 
3099  | 0  |                 src = &text;  | 
3100  | 0  |             }  | 
3101  |  |  | 
3102  | 0  |             parseInt(*src, number, pos, allowNegative,currentNumberFormat);  | 
3103  | 0  |         }  | 
3104  |  |  | 
3105  | 0  |         int32_t txtLoc = pos.getIndex();  | 
3106  |  | 
  | 
3107  | 0  |         if (txtLoc > parseStart) { | 
3108  | 0  |             value = number.getLong();  | 
3109  | 0  |             gotNumber = TRUE;  | 
3110  |  |  | 
3111  |  |             // suffix processing  | 
3112  | 0  |             if (value < 0 ) { | 
3113  | 0  |                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);  | 
3114  | 0  |                 if (txtLoc != pos.getIndex()) { | 
3115  | 0  |                     value *= -1;  | 
3116  | 0  |                 }  | 
3117  | 0  |             }  | 
3118  | 0  |             else { | 
3119  | 0  |                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);  | 
3120  | 0  |             }  | 
3121  |  | 
  | 
3122  | 0  |             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) { | 
3123  |  |                 // Check the range of the value  | 
3124  | 0  |                 int32_t bias = gFieldRangeBias[patternCharIndex];  | 
3125  | 0  |                 if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) { | 
3126  | 0  |                     return -start;  | 
3127  | 0  |                 }  | 
3128  | 0  |             }  | 
3129  |  |  | 
3130  | 0  |             pos.setIndex(txtLoc);  | 
3131  | 0  |         }  | 
3132  | 0  |     }  | 
3133  |  |  | 
3134  |  |     // Make sure that we got a number if  | 
3135  |  |     // we want one, and didn't get one  | 
3136  |  |     // if we don't want one.  | 
3137  | 0  |     switch (patternCharIndex) { | 
3138  | 0  |         case UDAT_HOUR_OF_DAY1_FIELD:  | 
3139  | 0  |         case UDAT_HOUR_OF_DAY0_FIELD:  | 
3140  | 0  |         case UDAT_HOUR1_FIELD:  | 
3141  | 0  |         case UDAT_HOUR0_FIELD:  | 
3142  |  |             // special range check for hours:  | 
3143  | 0  |             if (value < 0 || value > 24) { | 
3144  | 0  |                 return -start;  | 
3145  | 0  |             }  | 
3146  |  |  | 
3147  |  |             // fall through to gotNumber check  | 
3148  | 0  |             U_FALLTHROUGH;  | 
3149  | 0  |         case UDAT_YEAR_FIELD:  | 
3150  | 0  |         case UDAT_YEAR_WOY_FIELD:  | 
3151  | 0  |         case UDAT_FRACTIONAL_SECOND_FIELD:  | 
3152  |  |             // these must be a number  | 
3153  | 0  |             if (! gotNumber) { | 
3154  | 0  |                 return -start;  | 
3155  | 0  |             }  | 
3156  |  |  | 
3157  | 0  |             break;  | 
3158  |  |  | 
3159  | 0  |         default:  | 
3160  |  |             // we check the rest of the fields below.  | 
3161  | 0  |             break;  | 
3162  | 0  |     }  | 
3163  |  |  | 
3164  | 0  |     switch (patternCharIndex) { | 
3165  | 0  |     case UDAT_ERA_FIELD:  | 
3166  | 0  |         if (isChineseCalendar) { | 
3167  | 0  |             if (!gotNumber) { | 
3168  | 0  |                 return -start;  | 
3169  | 0  |             }  | 
3170  | 0  |             cal.set(UCAL_ERA, value);  | 
3171  | 0  |             return pos.getIndex();  | 
3172  | 0  |         }  | 
3173  | 0  |         if (count == 5) { | 
3174  | 0  |             ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal);  | 
3175  | 0  |         } else if (count == 4) { | 
3176  | 0  |             ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal);  | 
3177  | 0  |         } else { | 
3178  | 0  |             ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal);  | 
3179  | 0  |         }  | 
3180  |  |  | 
3181  |  |         // check return position, if it equals -start, then matchString error  | 
3182  |  |         // special case the return code so we don't necessarily fail out until we  | 
3183  |  |         // verify no year information also  | 
3184  | 0  |         if (ps == -start)  | 
3185  | 0  |             ps--;  | 
3186  |  | 
  | 
3187  | 0  |         return ps;  | 
3188  |  |  | 
3189  | 0  |     case UDAT_YEAR_FIELD:  | 
3190  |  |         // If there are 3 or more YEAR pattern characters, this indicates  | 
3191  |  |         // that the year value is to be treated literally, without any  | 
3192  |  |         // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise  | 
3193  |  |         // we made adjustments to place the 2-digit year in the proper  | 
3194  |  |         // century, for parsed strings from "00" to "99".  Any other string  | 
3195  |  |         // is treated literally:  "2250", "-1", "1", "002".  | 
3196  | 0  |         if (fDateOverride.compare(hebr)==0 && value < 1000) { | 
3197  | 0  |             value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;  | 
3198  | 0  |         } else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar  | 
3199  | 0  |             && u_isdigit(text.char32At(start))  | 
3200  | 0  |             && u_isdigit(text.char32At(text.moveIndex32(start, 1))))  | 
3201  | 0  |         { | 
3202  |  |             // only adjust year for patterns less than 3.  | 
3203  | 0  |             if(count < 3) { | 
3204  |  |                 // Assume for example that the defaultCenturyStart is 6/18/1903.  | 
3205  |  |                 // This means that two-digit years will be forced into the range  | 
3206  |  |                 // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02  | 
3207  |  |                 // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond  | 
3208  |  |                 // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the  | 
3209  |  |                 // other fields specify a date before 6/18, or 1903 if they specify a  | 
3210  |  |                 // date afterwards.  As a result, 03 is an ambiguous year.  All other  | 
3211  |  |                 // two-digit years are unambiguous.  | 
3212  | 0  |                 if(fHaveDefaultCentury) { // check if this formatter even has a pivot year | 
3213  | 0  |                     int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;  | 
3214  | 0  |                     ambiguousYear[0] = (value == ambiguousTwoDigitYear);  | 
3215  | 0  |                     value += (fDefaultCenturyStartYear/100)*100 +  | 
3216  | 0  |                             (value < ambiguousTwoDigitYear ? 100 : 0);  | 
3217  | 0  |                 }  | 
3218  | 0  |             }  | 
3219  | 0  |         }  | 
3220  | 0  |         cal.set(UCAL_YEAR, value);  | 
3221  |  |  | 
3222  |  |         // Delayed checking for adjustment of Hebrew month numbers in non-leap years.  | 
3223  | 0  |         if (saveHebrewMonth >= 0) { | 
3224  | 0  |             HebrewCalendar *hc = (HebrewCalendar*)&cal;  | 
3225  | 0  |             if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) { | 
3226  | 0  |                cal.set(UCAL_MONTH,saveHebrewMonth);  | 
3227  | 0  |             } else { | 
3228  | 0  |                cal.set(UCAL_MONTH,saveHebrewMonth-1);  | 
3229  | 0  |             }  | 
3230  | 0  |             saveHebrewMonth = -1;  | 
3231  | 0  |         }  | 
3232  | 0  |         return pos.getIndex();  | 
3233  |  |  | 
3234  | 0  |     case UDAT_YEAR_WOY_FIELD:  | 
3235  |  |         // Comment is the same as for UDAT_Year_FIELDs - look above  | 
3236  | 0  |         if (fDateOverride.compare(hebr)==0 && value < 1000) { | 
3237  | 0  |             value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;  | 
3238  | 0  |         } else if (text.moveIndex32(start, 2) == pos.getIndex()  | 
3239  | 0  |             && u_isdigit(text.char32At(start))  | 
3240  | 0  |             && u_isdigit(text.char32At(text.moveIndex32(start, 1)))  | 
3241  | 0  |             && fHaveDefaultCentury )  | 
3242  | 0  |         { | 
3243  | 0  |             int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;  | 
3244  | 0  |             ambiguousYear[0] = (value == ambiguousTwoDigitYear);  | 
3245  | 0  |             value += (fDefaultCenturyStartYear/100)*100 +  | 
3246  | 0  |                 (value < ambiguousTwoDigitYear ? 100 : 0);  | 
3247  | 0  |         }  | 
3248  | 0  |         cal.set(UCAL_YEAR_WOY, value);  | 
3249  | 0  |         return pos.getIndex();  | 
3250  |  |  | 
3251  | 0  |     case UDAT_YEAR_NAME_FIELD:  | 
3252  | 0  |         if (fSymbols->fShortYearNames != NULL) { | 
3253  | 0  |             int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal);  | 
3254  | 0  |             if (newStart > 0) { | 
3255  | 0  |                 return newStart;  | 
3256  | 0  |             }  | 
3257  | 0  |         }  | 
3258  | 0  |         if (gotNumber && (getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC,status) || value > fSymbols->fShortYearNamesCount)) { | 
3259  | 0  |             cal.set(UCAL_YEAR, value);  | 
3260  | 0  |             return pos.getIndex();  | 
3261  | 0  |         }  | 
3262  | 0  |         return -start;  | 
3263  |  |  | 
3264  | 0  |     case UDAT_MONTH_FIELD:  | 
3265  | 0  |     case UDAT_STANDALONE_MONTH_FIELD:  | 
3266  | 0  |         if (gotNumber) // i.e., M or MM.  | 
3267  | 0  |         { | 
3268  |  |             // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether  | 
3269  |  |             // or not it was a leap year.  We may or may not yet know what year it is, so might have to delay checking until  | 
3270  |  |             // the year is parsed.  | 
3271  | 0  |             if (!strcmp(cal.getType(),"hebrew")) { | 
3272  | 0  |                 HebrewCalendar *hc = (HebrewCalendar*)&cal;  | 
3273  | 0  |                 if (cal.isSet(UCAL_YEAR)) { | 
3274  | 0  |                    UErrorCode monthStatus = U_ZERO_ERROR;  | 
3275  | 0  |                    if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) { | 
3276  | 0  |                        cal.set(UCAL_MONTH, value);  | 
3277  | 0  |                    } else { | 
3278  | 0  |                        cal.set(UCAL_MONTH, value - 1);  | 
3279  | 0  |                    }  | 
3280  | 0  |                 } else { | 
3281  | 0  |                     saveHebrewMonth = value;  | 
3282  | 0  |                 }  | 
3283  | 0  |             } else { | 
3284  |  |                 // Don't want to parse the month if it is a string  | 
3285  |  |                 // while pattern uses numeric style: M/MM, L/LL  | 
3286  |  |                 // [We computed 'value' above.]  | 
3287  | 0  |                 cal.set(UCAL_MONTH, value - 1);  | 
3288  | 0  |             }  | 
3289  | 0  |             return pos.getIndex();  | 
3290  | 0  |         } else { | 
3291  |  |             // count >= 3 // i.e., MMM/MMMM, LLL/LLLL  | 
3292  |  |             // Want to be able to parse both short and long forms.  | 
3293  |  |             // Try count == 4 first:  | 
3294  | 0  |             UnicodeString * wideMonthPat = NULL;  | 
3295  | 0  |             UnicodeString * shortMonthPat = NULL;  | 
3296  | 0  |             if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) { | 
3297  | 0  |                 if (patternCharIndex==UDAT_MONTH_FIELD) { | 
3298  | 0  |                     wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide];  | 
3299  | 0  |                     shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev];  | 
3300  | 0  |                 } else { | 
3301  | 0  |                     wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide];  | 
3302  | 0  |                     shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev];  | 
3303  | 0  |                 }  | 
3304  | 0  |             }  | 
3305  | 0  |             int32_t newStart = 0;  | 
3306  | 0  |             if (patternCharIndex==UDAT_MONTH_FIELD) { | 
3307  | 0  |                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { | 
3308  | 0  |                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); // try MMMM  | 
3309  | 0  |                     if (newStart > 0) { | 
3310  | 0  |                         return newStart;  | 
3311  | 0  |                     }  | 
3312  | 0  |                 }  | 
3313  | 0  |                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3314  | 0  |                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); // try MMM  | 
3315  | 0  |                 }  | 
3316  | 0  |             } else { | 
3317  | 0  |                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { | 
3318  | 0  |                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); // try LLLL  | 
3319  | 0  |                     if (newStart > 0) { | 
3320  | 0  |                         return newStart;  | 
3321  | 0  |                     }  | 
3322  | 0  |                 }  | 
3323  | 0  |                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3324  | 0  |                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); // try LLL  | 
3325  | 0  |                 }  | 
3326  | 0  |             }  | 
3327  | 0  |             if (newStart > 0 || !getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))  // currently we do not try to parse MMMMM/LLLLL: #8860  | 
3328  | 0  |                 return newStart;  | 
3329  |  |             // else we allowing parsing as number, below  | 
3330  | 0  |         }  | 
3331  | 0  |         break;  | 
3332  |  |  | 
3333  | 0  |     case UDAT_HOUR_OF_DAY1_FIELD:  | 
3334  |  |         // [We computed 'value' above.]  | 
3335  | 0  |         if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)  | 
3336  | 0  |             value = 0;  | 
3337  |  |  | 
3338  |  |         // fall through to set field  | 
3339  | 0  |         U_FALLTHROUGH;  | 
3340  | 0  |     case UDAT_HOUR_OF_DAY0_FIELD:  | 
3341  | 0  |         cal.set(UCAL_HOUR_OF_DAY, value);  | 
3342  | 0  |         return pos.getIndex();  | 
3343  |  |  | 
3344  | 0  |     case UDAT_FRACTIONAL_SECOND_FIELD:  | 
3345  |  |         // Fractional seconds left-justify  | 
3346  | 0  |         i = countDigits(text, start, pos.getIndex());  | 
3347  | 0  |         if (i < 3) { | 
3348  | 0  |             while (i < 3) { | 
3349  | 0  |                 value *= 10;  | 
3350  | 0  |                 i++;  | 
3351  | 0  |             }  | 
3352  | 0  |         } else { | 
3353  | 0  |             int32_t a = 1;  | 
3354  | 0  |             while (i > 3) { | 
3355  | 0  |                 a *= 10;  | 
3356  | 0  |                 i--;  | 
3357  | 0  |             }  | 
3358  | 0  |             value /= a;  | 
3359  | 0  |         }  | 
3360  | 0  |         cal.set(UCAL_MILLISECOND, value);  | 
3361  | 0  |         return pos.getIndex();  | 
3362  |  |  | 
3363  | 0  |     case UDAT_DOW_LOCAL_FIELD:  | 
3364  | 0  |         if (gotNumber) // i.e., e or ee  | 
3365  | 0  |         { | 
3366  |  |             // [We computed 'value' above.]  | 
3367  | 0  |             cal.set(UCAL_DOW_LOCAL, value);  | 
3368  | 0  |             return pos.getIndex();  | 
3369  | 0  |         }  | 
3370  |  |         // else for eee-eeeee fall through to handling of EEE-EEEEE  | 
3371  |  |         // fall through, do not break here  | 
3372  | 0  |         U_FALLTHROUGH;  | 
3373  | 0  |     case UDAT_DAY_OF_WEEK_FIELD:  | 
3374  | 0  |         { | 
3375  |  |             // Want to be able to parse both short and long forms.  | 
3376  |  |             // Try count == 4 (EEEE) wide first:  | 
3377  | 0  |             int32_t newStart = 0;  | 
3378  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { | 
3379  | 0  |                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,  | 
3380  | 0  |                                           fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0)  | 
3381  | 0  |                     return newStart;  | 
3382  | 0  |             }  | 
3383  |  |             // EEEE wide failed, now try EEE abbreviated  | 
3384  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3385  | 0  |                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,  | 
3386  | 0  |                                        fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0)  | 
3387  | 0  |                     return newStart;  | 
3388  | 0  |             }  | 
3389  |  |             // EEE abbreviated failed, now try EEEEEE short  | 
3390  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) { | 
3391  | 0  |                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,  | 
3392  | 0  |                                        fSymbols->fShorterWeekdays, fSymbols->fShorterWeekdaysCount, NULL, cal)) > 0)  | 
3393  | 0  |                     return newStart;  | 
3394  | 0  |             }  | 
3395  |  |             // EEEEEE short failed, now try EEEEE narrow  | 
3396  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) { | 
3397  | 0  |                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,  | 
3398  | 0  |                                        fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0)  | 
3399  | 0  |                     return newStart;  | 
3400  | 0  |             }  | 
3401  | 0  |             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status) || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD)  | 
3402  | 0  |                 return newStart;  | 
3403  |  |             // else we allowing parsing as number, below  | 
3404  | 0  |         }  | 
3405  | 0  |         break;  | 
3406  |  |  | 
3407  | 0  |     case UDAT_STANDALONE_DAY_FIELD:  | 
3408  | 0  |         { | 
3409  | 0  |             if (gotNumber) // c or cc  | 
3410  | 0  |             { | 
3411  |  |                 // [We computed 'value' above.]  | 
3412  | 0  |                 cal.set(UCAL_DOW_LOCAL, value);  | 
3413  | 0  |                 return pos.getIndex();  | 
3414  | 0  |             }  | 
3415  |  |             // Want to be able to parse both short and long forms.  | 
3416  |  |             // Try count == 4 (cccc) first:  | 
3417  | 0  |             int32_t newStart = 0;  | 
3418  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { | 
3419  | 0  |                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,  | 
3420  | 0  |                                       fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0)  | 
3421  | 0  |                     return newStart;  | 
3422  | 0  |             }  | 
3423  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3424  | 0  |                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,  | 
3425  | 0  |                                           fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0)  | 
3426  | 0  |                     return newStart;  | 
3427  | 0  |             }  | 
3428  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) { | 
3429  | 0  |                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,  | 
3430  | 0  |                                           fSymbols->fStandaloneShorterWeekdays, fSymbols->fStandaloneShorterWeekdaysCount, NULL, cal)) > 0)  | 
3431  | 0  |                     return newStart;  | 
3432  | 0  |             }  | 
3433  | 0  |             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))  | 
3434  | 0  |                 return newStart;  | 
3435  |  |             // else we allowing parsing as number, below  | 
3436  | 0  |         }  | 
3437  | 0  |         break;  | 
3438  |  |  | 
3439  | 0  |     case UDAT_AM_PM_FIELD:  | 
3440  | 0  |         { | 
3441  |  |             // optionally try both wide/abbrev and narrow forms  | 
3442  | 0  |             int32_t newStart = 0;  | 
3443  |  |             // try wide/abbrev  | 
3444  | 0  |             if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count < 5 ) { | 
3445  | 0  |                 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal)) > 0) { | 
3446  | 0  |                     return newStart;  | 
3447  | 0  |                 }  | 
3448  | 0  |             }  | 
3449  |  |             // try narrow  | 
3450  | 0  |             if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count >= 5 ) { | 
3451  | 0  |                 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fNarrowAmPms, fSymbols->fNarrowAmPmsCount, NULL, cal)) > 0) { | 
3452  | 0  |                     return newStart;  | 
3453  | 0  |                 }  | 
3454  | 0  |             }  | 
3455  |  |             // no matches for given options  | 
3456  | 0  |             return -start;  | 
3457  | 0  |         }  | 
3458  |  |  | 
3459  | 0  |     case UDAT_HOUR1_FIELD:  | 
3460  |  |         // [We computed 'value' above.]  | 
3461  | 0  |         if (value == cal.getLeastMaximum(UCAL_HOUR)+1)  | 
3462  | 0  |             value = 0;  | 
3463  |  |  | 
3464  |  |         // fall through to set field  | 
3465  | 0  |         U_FALLTHROUGH;  | 
3466  | 0  |     case UDAT_HOUR0_FIELD:  | 
3467  | 0  |         cal.set(UCAL_HOUR, value);  | 
3468  | 0  |         return pos.getIndex();  | 
3469  |  |  | 
3470  | 0  |     case UDAT_QUARTER_FIELD:  | 
3471  | 0  |         if (gotNumber) // i.e., Q or QQ.  | 
3472  | 0  |         { | 
3473  |  |             // Don't want to parse the month if it is a string  | 
3474  |  |             // while pattern uses numeric style: Q or QQ.  | 
3475  |  |             // [We computed 'value' above.]  | 
3476  | 0  |             cal.set(UCAL_MONTH, (value - 1) * 3);  | 
3477  | 0  |             return pos.getIndex();  | 
3478  | 0  |         } else { | 
3479  |  |             // count >= 3 // i.e., QQQ or QQQQ  | 
3480  |  |             // Want to be able to parse short, long, and narrow forms.  | 
3481  |  |             // Try count == 4 first:  | 
3482  | 0  |             int32_t newStart = 0;  | 
3483  |  | 
  | 
3484  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { | 
3485  | 0  |                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,  | 
3486  | 0  |                                       fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)  | 
3487  | 0  |                     return newStart;  | 
3488  | 0  |             }  | 
3489  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3490  | 0  |                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,  | 
3491  | 0  |                                           fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)  | 
3492  | 0  |                     return newStart;  | 
3493  | 0  |             }  | 
3494  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) { | 
3495  | 0  |                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,  | 
3496  | 0  |                                       fSymbols->fNarrowQuarters, fSymbols->fNarrowQuartersCount, cal)) > 0)  | 
3497  | 0  |                     return newStart;  | 
3498  | 0  |             }  | 
3499  | 0  |             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))  | 
3500  | 0  |                 return newStart;  | 
3501  |  |             // else we allowing parsing as number, below  | 
3502  | 0  |             if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))  | 
3503  | 0  |                 return -start;  | 
3504  | 0  |         }  | 
3505  | 0  |         break;  | 
3506  |  |  | 
3507  | 0  |     case UDAT_STANDALONE_QUARTER_FIELD:  | 
3508  | 0  |         if (gotNumber) // i.e., q or qq.  | 
3509  | 0  |         { | 
3510  |  |             // Don't want to parse the month if it is a string  | 
3511  |  |             // while pattern uses numeric style: q or q.  | 
3512  |  |             // [We computed 'value' above.]  | 
3513  | 0  |             cal.set(UCAL_MONTH, (value - 1) * 3);  | 
3514  | 0  |             return pos.getIndex();  | 
3515  | 0  |         } else { | 
3516  |  |             // count >= 3 // i.e., qqq or qqqq  | 
3517  |  |             // Want to be able to parse both short and long forms.  | 
3518  |  |             // Try count == 4 first:  | 
3519  | 0  |             int32_t newStart = 0;  | 
3520  |  | 
  | 
3521  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { | 
3522  | 0  |                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,  | 
3523  | 0  |                                       fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)  | 
3524  | 0  |                     return newStart;  | 
3525  | 0  |             }  | 
3526  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3527  | 0  |                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,  | 
3528  | 0  |                                           fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)  | 
3529  | 0  |                     return newStart;  | 
3530  | 0  |             }  | 
3531  | 0  |             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) { | 
3532  | 0  |                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,  | 
3533  | 0  |                                           fSymbols->fStandaloneNarrowQuarters, fSymbols->fStandaloneNarrowQuartersCount, cal)) > 0)  | 
3534  | 0  |                     return newStart;  | 
3535  | 0  |             }  | 
3536  | 0  |             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))  | 
3537  | 0  |                 return newStart;  | 
3538  |  |             // else we allowing parsing as number, below  | 
3539  | 0  |             if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))  | 
3540  | 0  |                 return -start;  | 
3541  | 0  |         }  | 
3542  | 0  |         break;  | 
3543  |  |  | 
3544  | 0  |     case UDAT_TIMEZONE_FIELD: // 'z'  | 
3545  | 0  |         { | 
3546  | 0  |             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;  | 
3547  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
3548  | 0  |             if (U_SUCCESS(status)) { | 
3549  | 0  |                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);  | 
3550  | 0  |                 if (tz != NULL) { | 
3551  | 0  |                     cal.adoptTimeZone(tz);  | 
3552  | 0  |                     return pos.getIndex();  | 
3553  | 0  |                 }  | 
3554  | 0  |             }  | 
3555  | 0  |             return -start;  | 
3556  | 0  |     }  | 
3557  | 0  |         break;  | 
3558  | 0  |     case UDAT_TIMEZONE_RFC_FIELD: // 'Z'  | 
3559  | 0  |         { | 
3560  | 0  |             UTimeZoneFormatStyle style = (count < 4) ?  | 
3561  | 0  |                 UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT);  | 
3562  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
3563  | 0  |             if (U_SUCCESS(status)) { | 
3564  | 0  |                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);  | 
3565  | 0  |                 if (tz != NULL) { | 
3566  | 0  |                     cal.adoptTimeZone(tz);  | 
3567  | 0  |                     return pos.getIndex();  | 
3568  | 0  |                 }  | 
3569  | 0  |             }  | 
3570  | 0  |             return -start;  | 
3571  | 0  |         }  | 
3572  | 0  |     case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'  | 
3573  | 0  |         { | 
3574  | 0  |             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;  | 
3575  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
3576  | 0  |             if (U_SUCCESS(status)) { | 
3577  | 0  |                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);  | 
3578  | 0  |                 if (tz != NULL) { | 
3579  | 0  |                     cal.adoptTimeZone(tz);  | 
3580  | 0  |                     return pos.getIndex();  | 
3581  | 0  |                 }  | 
3582  | 0  |             }  | 
3583  | 0  |             return -start;  | 
3584  | 0  |         }  | 
3585  | 0  |     case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'  | 
3586  | 0  |         { | 
3587  | 0  |             UTimeZoneFormatStyle style;  | 
3588  | 0  |             switch (count) { | 
3589  | 0  |             case 1:  | 
3590  | 0  |                 style = UTZFMT_STYLE_ZONE_ID_SHORT;  | 
3591  | 0  |                 break;  | 
3592  | 0  |             case 2:  | 
3593  | 0  |                 style = UTZFMT_STYLE_ZONE_ID;  | 
3594  | 0  |                 break;  | 
3595  | 0  |             case 3:  | 
3596  | 0  |                 style = UTZFMT_STYLE_EXEMPLAR_LOCATION;  | 
3597  | 0  |                 break;  | 
3598  | 0  |             default:  | 
3599  | 0  |                 style = UTZFMT_STYLE_GENERIC_LOCATION;  | 
3600  | 0  |                 break;  | 
3601  | 0  |             }  | 
3602  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
3603  | 0  |             if (U_SUCCESS(status)) { | 
3604  | 0  |                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);  | 
3605  | 0  |                 if (tz != NULL) { | 
3606  | 0  |                     cal.adoptTimeZone(tz);  | 
3607  | 0  |                     return pos.getIndex();  | 
3608  | 0  |                 }  | 
3609  | 0  |             }  | 
3610  | 0  |             return -start;  | 
3611  | 0  |         }  | 
3612  | 0  |     case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'  | 
3613  | 0  |         { | 
3614  | 0  |             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT;  | 
3615  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
3616  | 0  |             if (U_SUCCESS(status)) { | 
3617  | 0  |                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);  | 
3618  | 0  |                 if (tz != NULL) { | 
3619  | 0  |                     cal.adoptTimeZone(tz);  | 
3620  | 0  |                     return pos.getIndex();  | 
3621  | 0  |                 }  | 
3622  | 0  |             }  | 
3623  | 0  |             return -start;  | 
3624  | 0  |         }  | 
3625  | 0  |     case UDAT_TIMEZONE_ISO_FIELD: // 'X'  | 
3626  | 0  |         { | 
3627  | 0  |             UTimeZoneFormatStyle style;  | 
3628  | 0  |             switch (count) { | 
3629  | 0  |             case 1:  | 
3630  | 0  |                 style = UTZFMT_STYLE_ISO_BASIC_SHORT;  | 
3631  | 0  |                 break;  | 
3632  | 0  |             case 2:  | 
3633  | 0  |                 style = UTZFMT_STYLE_ISO_BASIC_FIXED;  | 
3634  | 0  |                 break;  | 
3635  | 0  |             case 3:  | 
3636  | 0  |                 style = UTZFMT_STYLE_ISO_EXTENDED_FIXED;  | 
3637  | 0  |                 break;  | 
3638  | 0  |             case 4:  | 
3639  | 0  |                 style = UTZFMT_STYLE_ISO_BASIC_FULL;  | 
3640  | 0  |                 break;  | 
3641  | 0  |             default:  | 
3642  | 0  |                 style = UTZFMT_STYLE_ISO_EXTENDED_FULL;  | 
3643  | 0  |                 break;  | 
3644  | 0  |             }  | 
3645  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
3646  | 0  |             if (U_SUCCESS(status)) { | 
3647  | 0  |                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);  | 
3648  | 0  |                 if (tz != NULL) { | 
3649  | 0  |                     cal.adoptTimeZone(tz);  | 
3650  | 0  |                     return pos.getIndex();  | 
3651  | 0  |                 }  | 
3652  | 0  |             }  | 
3653  | 0  |             return -start;  | 
3654  | 0  |         }  | 
3655  | 0  |     case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'  | 
3656  | 0  |         { | 
3657  | 0  |             UTimeZoneFormatStyle style;  | 
3658  | 0  |             switch (count) { | 
3659  | 0  |             case 1:  | 
3660  | 0  |                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT;  | 
3661  | 0  |                 break;  | 
3662  | 0  |             case 2:  | 
3663  | 0  |                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED;  | 
3664  | 0  |                 break;  | 
3665  | 0  |             case 3:  | 
3666  | 0  |                 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED;  | 
3667  | 0  |                 break;  | 
3668  | 0  |             case 4:  | 
3669  | 0  |                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL;  | 
3670  | 0  |                 break;  | 
3671  | 0  |             default:  | 
3672  | 0  |                 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;  | 
3673  | 0  |                 break;  | 
3674  | 0  |             }  | 
3675  | 0  |             const TimeZoneFormat *tzfmt = tzFormat(status);  | 
3676  | 0  |             if (U_SUCCESS(status)) { | 
3677  | 0  |                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);  | 
3678  | 0  |                 if (tz != NULL) { | 
3679  | 0  |                     cal.adoptTimeZone(tz);  | 
3680  | 0  |                     return pos.getIndex();  | 
3681  | 0  |                 }  | 
3682  | 0  |             }  | 
3683  | 0  |             return -start;  | 
3684  | 0  |         }  | 
3685  |  |     // currently no pattern character is defined for UDAT_TIME_SEPARATOR_FIELD  | 
3686  |  |     // so we should not get here. Leave support in for future definition.  | 
3687  | 0  |     case UDAT_TIME_SEPARATOR_FIELD:  | 
3688  | 0  |         { | 
3689  | 0  |             static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;  | 
3690  | 0  |             static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;  | 
3691  |  |  | 
3692  |  |             // Try matching a time separator.  | 
3693  | 0  |             int32_t count_sep = 1;  | 
3694  | 0  |             UnicodeString data[3];  | 
3695  | 0  |             fSymbols->getTimeSeparatorString(data[0]);  | 
3696  |  |  | 
3697  |  |             // Add the default, if different from the locale.  | 
3698  | 0  |             if (data[0].compare(&def_sep, 1) != 0) { | 
3699  | 0  |                 data[count_sep++].setTo(def_sep);  | 
3700  | 0  |             }  | 
3701  |  |  | 
3702  |  |             // If lenient, add also the alternate, if different from the locale.  | 
3703  | 0  |             if (isLenient() && data[0].compare(&alt_sep, 1) != 0) { | 
3704  | 0  |                 data[count_sep++].setTo(alt_sep);  | 
3705  | 0  |             }  | 
3706  |  | 
  | 
3707  | 0  |             return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal);  | 
3708  | 0  |         }  | 
3709  |  |  | 
3710  | 0  |     case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:  | 
3711  | 0  |     { | 
3712  | 0  |         U_ASSERT(dayPeriod != NULL);  | 
3713  | 0  |         int32_t ampmStart = subParse(text, start, 0x61, count,  | 
3714  | 0  |                            obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal,  | 
3715  | 0  |                            patLoc, numericLeapMonthFormatter, tzTimeType);  | 
3716  |  | 
  | 
3717  | 0  |         if (ampmStart > 0) { | 
3718  | 0  |             return ampmStart;  | 
3719  | 0  |         } else { | 
3720  | 0  |             int32_t newStart = 0;  | 
3721  |  |  | 
3722  |  |             // Only match the first two strings from the day period strings array.  | 
3723  | 0  |             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3724  | 0  |                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,  | 
3725  | 0  |                                                         2, *dayPeriod)) > 0) { | 
3726  | 0  |                     return newStart;  | 
3727  | 0  |                 }  | 
3728  | 0  |             }  | 
3729  | 0  |             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) { | 
3730  | 0  |                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,  | 
3731  | 0  |                                                         2, *dayPeriod)) > 0) { | 
3732  | 0  |                     return newStart;  | 
3733  | 0  |                 }  | 
3734  | 0  |             }  | 
3735  |  |             // count == 4, but allow other counts  | 
3736  | 0  |             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) { | 
3737  | 0  |                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,  | 
3738  | 0  |                                                         2, *dayPeriod)) > 0) { | 
3739  | 0  |                     return newStart;  | 
3740  | 0  |                 }  | 
3741  | 0  |             }  | 
3742  |  |  | 
3743  | 0  |             return -start;  | 
3744  | 0  |         }  | 
3745  | 0  |     }  | 
3746  |  |  | 
3747  | 0  |     case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:  | 
3748  | 0  |     { | 
3749  | 0  |         U_ASSERT(dayPeriod != NULL);  | 
3750  | 0  |         int32_t newStart = 0;  | 
3751  |  | 
  | 
3752  | 0  |         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { | 
3753  | 0  |             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,  | 
3754  | 0  |                                 fSymbols->fAbbreviatedDayPeriodsCount, *dayPeriod)) > 0) { | 
3755  | 0  |                 return newStart;  | 
3756  | 0  |             }  | 
3757  | 0  |         }  | 
3758  | 0  |         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) { | 
3759  | 0  |             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,  | 
3760  | 0  |                                 fSymbols->fNarrowDayPeriodsCount, *dayPeriod)) > 0) { | 
3761  | 0  |                 return newStart;  | 
3762  | 0  |             }  | 
3763  | 0  |         }  | 
3764  | 0  |         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { | 
3765  | 0  |             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,  | 
3766  | 0  |                                 fSymbols->fWideDayPeriodsCount, *dayPeriod)) > 0) { | 
3767  | 0  |                 return newStart;  | 
3768  | 0  |             }  | 
3769  | 0  |         }  | 
3770  |  |  | 
3771  | 0  |         return -start;  | 
3772  | 0  |     }  | 
3773  |  |  | 
3774  | 0  |     default:  | 
3775  |  |         // Handle "generic" fields  | 
3776  |  |         // this is now handled below, outside the switch block  | 
3777  | 0  |         break;  | 
3778  | 0  |     }  | 
3779  |  |     // Handle "generic" fields:  | 
3780  |  |     // switch default case now handled here (outside switch block) to allow  | 
3781  |  |     // parsing of some string fields as digits for lenient case  | 
3782  |  |  | 
3783  | 0  |     int32_t parseStart = pos.getIndex();  | 
3784  | 0  |     const UnicodeString* src;  | 
3785  | 0  |     if (obeyCount) { | 
3786  | 0  |         if ((start+count) > text.length()) { | 
3787  | 0  |             return -start;  | 
3788  | 0  |         }  | 
3789  | 0  |         text.extractBetween(0, start + count, temp);  | 
3790  | 0  |         src = &temp;  | 
3791  | 0  |     } else { | 
3792  | 0  |         src = &text;  | 
3793  | 0  |     }  | 
3794  | 0  |     parseInt(*src, number, pos, allowNegative,currentNumberFormat);  | 
3795  | 0  |     if (pos.getIndex() != parseStart) { | 
3796  | 0  |         int32_t val = number.getLong();  | 
3797  |  |  | 
3798  |  |         // Don't need suffix processing here (as in number processing at the beginning of the function);  | 
3799  |  |         // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.  | 
3800  |  | 
  | 
3801  | 0  |         if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) { | 
3802  |  |             // Check the range of the value  | 
3803  | 0  |             int32_t bias = gFieldRangeBias[patternCharIndex];  | 
3804  | 0  |             if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) { | 
3805  | 0  |                 return -start;  | 
3806  | 0  |             }  | 
3807  | 0  |         }  | 
3808  |  |  | 
3809  |  |         // For the following, need to repeat some of the "if (gotNumber)" code above:  | 
3810  |  |         // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD,  | 
3811  |  |         // UDAT_[STANDALONE_]QUARTER_FIELD  | 
3812  | 0  |         switch (patternCharIndex) { | 
3813  | 0  |         case UDAT_MONTH_FIELD:  | 
3814  |  |             // See notes under UDAT_MONTH_FIELD case above  | 
3815  | 0  |             if (!strcmp(cal.getType(),"hebrew")) { | 
3816  | 0  |                 HebrewCalendar *hc = (HebrewCalendar*)&cal;  | 
3817  | 0  |                 if (cal.isSet(UCAL_YEAR)) { | 
3818  | 0  |                    UErrorCode monthStatus = U_ZERO_ERROR;  | 
3819  | 0  |                    if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) { | 
3820  | 0  |                        cal.set(UCAL_MONTH, val);  | 
3821  | 0  |                    } else { | 
3822  | 0  |                        cal.set(UCAL_MONTH, val - 1);  | 
3823  | 0  |                    }  | 
3824  | 0  |                 } else { | 
3825  | 0  |                     saveHebrewMonth = val;  | 
3826  | 0  |                 }  | 
3827  | 0  |             } else { | 
3828  | 0  |                 cal.set(UCAL_MONTH, val - 1);  | 
3829  | 0  |             }  | 
3830  | 0  |             break;  | 
3831  | 0  |         case UDAT_STANDALONE_MONTH_FIELD:  | 
3832  | 0  |             cal.set(UCAL_MONTH, val - 1);  | 
3833  | 0  |             break;  | 
3834  | 0  |         case UDAT_DOW_LOCAL_FIELD:  | 
3835  | 0  |         case UDAT_STANDALONE_DAY_FIELD:  | 
3836  | 0  |             cal.set(UCAL_DOW_LOCAL, val);  | 
3837  | 0  |             break;  | 
3838  | 0  |         case UDAT_QUARTER_FIELD:  | 
3839  | 0  |         case UDAT_STANDALONE_QUARTER_FIELD:  | 
3840  | 0  |              cal.set(UCAL_MONTH, (val - 1) * 3);  | 
3841  | 0  |              break;  | 
3842  | 0  |         case UDAT_RELATED_YEAR_FIELD:  | 
3843  | 0  |             cal.setRelatedYear(val);  | 
3844  | 0  |             break;  | 
3845  | 0  |         default:  | 
3846  | 0  |             cal.set(field, val);  | 
3847  | 0  |             break;  | 
3848  | 0  |         }  | 
3849  | 0  |         return pos.getIndex();  | 
3850  | 0  |     }  | 
3851  | 0  |     return -start;  | 
3852  | 0  | }  | 
3853  |  |  | 
3854  |  | /**  | 
3855  |  |  * Parse an integer using fNumberFormat.  This method is semantically  | 
3856  |  |  * const, but actually may modify fNumberFormat.  | 
3857  |  |  */  | 
3858  |  | void SimpleDateFormat::parseInt(const UnicodeString& text,  | 
3859  |  |                                 Formattable& number,  | 
3860  |  |                                 ParsePosition& pos,  | 
3861  |  |                                 UBool allowNegative,  | 
3862  | 0  |                                 const NumberFormat *fmt) const { | 
3863  | 0  |     parseInt(text, number, -1, pos, allowNegative,fmt);  | 
3864  | 0  | }  | 
3865  |  |  | 
3866  |  | /**  | 
3867  |  |  * Parse an integer using fNumberFormat up to maxDigits.  | 
3868  |  |  */  | 
3869  |  | void SimpleDateFormat::parseInt(const UnicodeString& text,  | 
3870  |  |                                 Formattable& number,  | 
3871  |  |                                 int32_t maxDigits,  | 
3872  |  |                                 ParsePosition& pos,  | 
3873  |  |                                 UBool allowNegative,  | 
3874  | 0  |                                 const NumberFormat *fmt) const { | 
3875  | 0  |     UnicodeString oldPrefix;  | 
3876  | 0  |     auto* fmtAsDF = dynamic_cast<const DecimalFormat*>(fmt);  | 
3877  | 0  |     LocalPointer<DecimalFormat> df;  | 
3878  | 0  |     if (!allowNegative && fmtAsDF != nullptr) { | 
3879  | 0  |         df.adoptInstead(fmtAsDF->clone());  | 
3880  | 0  |         if (df.isNull()) { | 
3881  |  |             // Memory allocation error  | 
3882  | 0  |             return;  | 
3883  | 0  |         }  | 
3884  | 0  |         df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));  | 
3885  | 0  |         fmt = df.getAlias();  | 
3886  | 0  |     }  | 
3887  | 0  |     int32_t oldPos = pos.getIndex();  | 
3888  | 0  |     fmt->parse(text, number, pos);  | 
3889  |  | 
  | 
3890  | 0  |     if (maxDigits > 0) { | 
3891  |  |         // adjust the result to fit into  | 
3892  |  |         // the maxDigits and move the position back  | 
3893  | 0  |         int32_t nDigits = pos.getIndex() - oldPos;  | 
3894  | 0  |         if (nDigits > maxDigits) { | 
3895  | 0  |             int32_t val = number.getLong();  | 
3896  | 0  |             nDigits -= maxDigits;  | 
3897  | 0  |             while (nDigits > 0) { | 
3898  | 0  |                 val /= 10;  | 
3899  | 0  |                 nDigits--;  | 
3900  | 0  |             }  | 
3901  | 0  |             pos.setIndex(oldPos + maxDigits);  | 
3902  | 0  |             number.setLong(val);  | 
3903  | 0  |         }  | 
3904  | 0  |     }  | 
3905  | 0  | }  | 
3906  |  |  | 
3907  | 0  | int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const { | 
3908  | 0  |     int32_t numDigits = 0;  | 
3909  | 0  |     int32_t idx = start;  | 
3910  | 0  |     while (idx < end) { | 
3911  | 0  |         UChar32 cp = text.char32At(idx);  | 
3912  | 0  |         if (u_isdigit(cp)) { | 
3913  | 0  |             numDigits++;  | 
3914  | 0  |         }  | 
3915  | 0  |         idx += U16_LENGTH(cp);  | 
3916  | 0  |     }  | 
3917  | 0  |     return numDigits;  | 
3918  | 0  | }  | 
3919  |  |  | 
3920  |  | //----------------------------------------------------------------------  | 
3921  |  |  | 
3922  |  | void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,  | 
3923  |  |                                         UnicodeString& translatedPattern,  | 
3924  |  |                                         const UnicodeString& from,  | 
3925  |  |                                         const UnicodeString& to,  | 
3926  |  |                                         UErrorCode& status)  | 
3927  | 0  | { | 
3928  |  |     // run through the pattern and convert any pattern symbols from the version  | 
3929  |  |     // in "from" to the corresponding character in "to".  This code takes  | 
3930  |  |     // quoted strings into account (it doesn't try to translate them), and it signals  | 
3931  |  |     // an error if a particular "pattern character" doesn't appear in "from".  | 
3932  |  |     // Depending on the values of "from" and "to" this can convert from generic  | 
3933  |  |     // to localized patterns or localized to generic.  | 
3934  | 0  |     if (U_FAILURE(status)) { | 
3935  | 0  |         return;  | 
3936  | 0  |     }  | 
3937  |  |  | 
3938  | 0  |     translatedPattern.remove();  | 
3939  | 0  |     UBool inQuote = FALSE;  | 
3940  | 0  |     for (int32_t i = 0; i < originalPattern.length(); ++i) { | 
3941  | 0  |         UChar c = originalPattern[i];  | 
3942  | 0  |         if (inQuote) { | 
3943  | 0  |             if (c == QUOTE) { | 
3944  | 0  |                 inQuote = FALSE;  | 
3945  | 0  |             }  | 
3946  | 0  |         } else { | 
3947  | 0  |             if (c == QUOTE) { | 
3948  | 0  |                 inQuote = TRUE;  | 
3949  | 0  |             } else if (isSyntaxChar(c)) { | 
3950  | 0  |                 int32_t ci = from.indexOf(c);  | 
3951  | 0  |                 if (ci == -1) { | 
3952  | 0  |                     status = U_INVALID_FORMAT_ERROR;  | 
3953  | 0  |                     return;  | 
3954  | 0  |                 }  | 
3955  | 0  |                 c = to[ci];  | 
3956  | 0  |             }  | 
3957  | 0  |         }  | 
3958  | 0  |         translatedPattern += c;  | 
3959  | 0  |     }  | 
3960  | 0  |     if (inQuote) { | 
3961  | 0  |         status = U_INVALID_FORMAT_ERROR;  | 
3962  | 0  |         return;  | 
3963  | 0  |     }  | 
3964  | 0  | }  | 
3965  |  |  | 
3966  |  | //----------------------------------------------------------------------  | 
3967  |  |  | 
3968  |  | UnicodeString&  | 
3969  |  | SimpleDateFormat::toPattern(UnicodeString& result) const  | 
3970  | 0  | { | 
3971  | 0  |     result = fPattern;  | 
3972  | 0  |     return result;  | 
3973  | 0  | }  | 
3974  |  |  | 
3975  |  | //----------------------------------------------------------------------  | 
3976  |  |  | 
3977  |  | UnicodeString&  | 
3978  |  | SimpleDateFormat::toLocalizedPattern(UnicodeString& result,  | 
3979  |  |                                      UErrorCode& status) const  | 
3980  | 0  | { | 
3981  | 0  |     translatePattern(fPattern, result,  | 
3982  | 0  |                      UnicodeString(DateFormatSymbols::getPatternUChars()),  | 
3983  | 0  |                      fSymbols->fLocalPatternChars, status);  | 
3984  | 0  |     return result;  | 
3985  | 0  | }  | 
3986  |  |  | 
3987  |  | //----------------------------------------------------------------------  | 
3988  |  |  | 
3989  |  | void  | 
3990  |  | SimpleDateFormat::applyPattern(const UnicodeString& pattern)  | 
3991  | 0  | { | 
3992  | 0  |     fPattern = pattern;  | 
3993  | 0  |     parsePattern();  | 
3994  |  |  | 
3995  |  |     // Hack to update use of Gannen year numbering for ja@calendar=japanese -  | 
3996  |  |     // use only if format is non-numeric (includes 年) and no other fDateOverride.  | 
3997  | 0  |     if (fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&  | 
3998  | 0  |             uprv_strcmp(fLocale.getLanguage(),"ja") == 0) { | 
3999  | 0  |         if (fDateOverride==UnicodeString(u"y=jpanyear") && !fHasHanYearChar) { | 
4000  |  |             // Gannen numbering is set but new pattern should not use it, unset;  | 
4001  |  |             // use procedure from adoptNumberFormat to clear overrides  | 
4002  | 0  |             if (fSharedNumberFormatters) { | 
4003  | 0  |                 freeSharedNumberFormatters(fSharedNumberFormatters);  | 
4004  | 0  |                 fSharedNumberFormatters = NULL;  | 
4005  | 0  |             }  | 
4006  | 0  |             fDateOverride.setToBogus(); // record status  | 
4007  | 0  |         } else if (fDateOverride.isBogus() && fHasHanYearChar) { | 
4008  |  |             // No current override (=> no Gannen numbering) but new pattern needs it;  | 
4009  |  |             // use procedures from initNUmberFormatters / adoptNumberFormat  | 
4010  | 0  |             umtx_lock(&LOCK);  | 
4011  | 0  |             if (fSharedNumberFormatters == NULL) { | 
4012  | 0  |                 fSharedNumberFormatters = allocSharedNumberFormatters();  | 
4013  | 0  |             }  | 
4014  | 0  |             umtx_unlock(&LOCK);  | 
4015  | 0  |             if (fSharedNumberFormatters != NULL) { | 
4016  | 0  |                 Locale ovrLoc(fLocale.getLanguage(),fLocale.getCountry(),fLocale.getVariant(),"numbers=jpanyear");  | 
4017  | 0  |                 UErrorCode status = U_ZERO_ERROR;  | 
4018  | 0  |                 const SharedNumberFormat *snf = createSharedNumberFormat(ovrLoc, status);  | 
4019  | 0  |                 if (U_SUCCESS(status)) { | 
4020  |  |                     // Now that we have an appropriate number formatter, fill in the  | 
4021  |  |                     // appropriate slot in the number formatters table.  | 
4022  | 0  |                     UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(u'y');  | 
4023  | 0  |                     SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);  | 
4024  | 0  |                     snf->deleteIfZeroRefCount();  | 
4025  | 0  |                     fDateOverride.setTo(u"y=jpanyear", -1); // record status  | 
4026  | 0  |                 }  | 
4027  | 0  |             }  | 
4028  | 0  |         }  | 
4029  | 0  |     }  | 
4030  | 0  | }  | 
4031  |  |  | 
4032  |  | //----------------------------------------------------------------------  | 
4033  |  |  | 
4034  |  | void  | 
4035  |  | SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,  | 
4036  |  |                                         UErrorCode &status)  | 
4037  | 0  | { | 
4038  | 0  |     translatePattern(pattern, fPattern,  | 
4039  | 0  |                      fSymbols->fLocalPatternChars,  | 
4040  | 0  |                      UnicodeString(DateFormatSymbols::getPatternUChars()), status);  | 
4041  | 0  | }  | 
4042  |  |  | 
4043  |  | //----------------------------------------------------------------------  | 
4044  |  |  | 
4045  |  | const DateFormatSymbols*  | 
4046  |  | SimpleDateFormat::getDateFormatSymbols() const  | 
4047  | 0  | { | 
4048  | 0  |     return fSymbols;  | 
4049  | 0  | }  | 
4050  |  |  | 
4051  |  | //----------------------------------------------------------------------  | 
4052  |  |  | 
4053  |  | void  | 
4054  |  | SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)  | 
4055  | 0  | { | 
4056  | 0  |     delete fSymbols;  | 
4057  | 0  |     fSymbols = newFormatSymbols;  | 
4058  | 0  | }  | 
4059  |  |  | 
4060  |  | //----------------------------------------------------------------------  | 
4061  |  | void  | 
4062  |  | SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)  | 
4063  | 0  | { | 
4064  | 0  |     delete fSymbols;  | 
4065  | 0  |     fSymbols = new DateFormatSymbols(newFormatSymbols);  | 
4066  | 0  | }  | 
4067  |  |  | 
4068  |  | //----------------------------------------------------------------------  | 
4069  |  | const TimeZoneFormat*  | 
4070  | 0  | SimpleDateFormat::getTimeZoneFormat(void) const { | 
4071  |  |     // TimeZoneFormat initialization might fail when out of memory.  | 
4072  |  |     // If we always initialize TimeZoneFormat instance, we can return  | 
4073  |  |     // such status there. For now, this implementation lazily instantiates  | 
4074  |  |     // a TimeZoneFormat for performance optimization reasons, but cannot  | 
4075  |  |     // propagate such error (probably just out of memory case) to the caller.  | 
4076  | 0  |     UErrorCode status = U_ZERO_ERROR;  | 
4077  | 0  |     return (const TimeZoneFormat*)tzFormat(status);  | 
4078  | 0  | }  | 
4079  |  |  | 
4080  |  | //----------------------------------------------------------------------  | 
4081  |  | void  | 
4082  |  | SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt)  | 
4083  | 0  | { | 
4084  | 0  |     delete fTimeZoneFormat;  | 
4085  | 0  |     fTimeZoneFormat = timeZoneFormatToAdopt;  | 
4086  | 0  | }  | 
4087  |  |  | 
4088  |  | //----------------------------------------------------------------------  | 
4089  |  | void  | 
4090  |  | SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)  | 
4091  | 0  | { | 
4092  | 0  |     delete fTimeZoneFormat;  | 
4093  | 0  |     fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat);  | 
4094  | 0  | }  | 
4095  |  |  | 
4096  |  | //----------------------------------------------------------------------  | 
4097  |  |  | 
4098  |  |  | 
4099  |  | void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)  | 
4100  | 0  | { | 
4101  | 0  |   UErrorCode status = U_ZERO_ERROR;  | 
4102  | 0  |   Locale calLocale(fLocale);  | 
4103  | 0  |   calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status); | 
4104  | 0  |   DateFormatSymbols *newSymbols =  | 
4105  | 0  |           DateFormatSymbols::createForLocale(calLocale, status);  | 
4106  | 0  |   if (U_FAILURE(status)) { | 
4107  | 0  |       delete calendarToAdopt;  | 
4108  | 0  |       return;  | 
4109  | 0  |   }  | 
4110  | 0  |   DateFormat::adoptCalendar(calendarToAdopt);  | 
4111  | 0  |   delete fSymbols;  | 
4112  | 0  |   fSymbols = newSymbols;  | 
4113  | 0  |   initializeDefaultCentury();  // we need a new century (possibly)  | 
4114  | 0  | }  | 
4115  |  |  | 
4116  |  |  | 
4117  |  | //----------------------------------------------------------------------  | 
4118  |  |  | 
4119  |  |  | 
4120  |  | // override the DateFormat implementation in order to  | 
4121  |  | // lazily initialize fCapitalizationBrkIter  | 
4122  |  | void  | 
4123  |  | SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)  | 
4124  | 0  | { | 
4125  | 0  |     DateFormat::setContext(value, status);  | 
4126  | 0  | #if !UCONFIG_NO_BREAK_ITERATION  | 
4127  | 0  |     if (U_SUCCESS(status)) { | 
4128  | 0  |         if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||  | 
4129  | 0  |                 value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) { | 
4130  | 0  |             status = U_ZERO_ERROR;  | 
4131  | 0  |             fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);  | 
4132  | 0  |             if (U_FAILURE(status)) { | 
4133  | 0  |                 delete fCapitalizationBrkIter;  | 
4134  | 0  |                 fCapitalizationBrkIter = NULL;  | 
4135  | 0  |             }  | 
4136  | 0  |         }  | 
4137  | 0  |     }  | 
4138  | 0  | #endif  | 
4139  | 0  | }  | 
4140  |  |  | 
4141  |  |  | 
4142  |  | //----------------------------------------------------------------------  | 
4143  |  |  | 
4144  |  |  | 
4145  |  | UBool  | 
4146  | 0  | SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const { | 
4147  | 0  |     return isFieldUnitIgnored(fPattern, field);  | 
4148  | 0  | }  | 
4149  |  |  | 
4150  |  |  | 
4151  |  | UBool  | 
4152  |  | SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,  | 
4153  | 0  |                                      UCalendarDateFields field) { | 
4154  | 0  |     int32_t fieldLevel = fgCalendarFieldToLevel[field];  | 
4155  | 0  |     int32_t level;  | 
4156  | 0  |     UChar ch;  | 
4157  | 0  |     UBool inQuote = FALSE;  | 
4158  | 0  |     UChar prevCh = 0;  | 
4159  | 0  |     int32_t count = 0;  | 
4160  |  | 
  | 
4161  | 0  |     for (int32_t i = 0; i < pattern.length(); ++i) { | 
4162  | 0  |         ch = pattern[i];  | 
4163  | 0  |         if (ch != prevCh && count > 0) { | 
4164  | 0  |             level = getLevelFromChar(prevCh);  | 
4165  |  |             // the larger the level, the smaller the field unit.  | 
4166  | 0  |             if (fieldLevel <= level) { | 
4167  | 0  |                 return FALSE;  | 
4168  | 0  |             }  | 
4169  | 0  |             count = 0;  | 
4170  | 0  |         }  | 
4171  | 0  |         if (ch == QUOTE) { | 
4172  | 0  |             if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) { | 
4173  | 0  |                 ++i;  | 
4174  | 0  |             } else { | 
4175  | 0  |                 inQuote = ! inQuote;  | 
4176  | 0  |             }  | 
4177  | 0  |         }  | 
4178  | 0  |         else if (!inQuote && isSyntaxChar(ch)) { | 
4179  | 0  |             prevCh = ch;  | 
4180  | 0  |             ++count;  | 
4181  | 0  |         }  | 
4182  | 0  |     }  | 
4183  | 0  |     if (count > 0) { | 
4184  |  |         // last item  | 
4185  | 0  |         level = getLevelFromChar(prevCh);  | 
4186  | 0  |         if (fieldLevel <= level) { | 
4187  | 0  |             return FALSE;  | 
4188  | 0  |         }  | 
4189  | 0  |     }  | 
4190  | 0  |     return TRUE;  | 
4191  | 0  | }  | 
4192  |  |  | 
4193  |  | //----------------------------------------------------------------------  | 
4194  |  |  | 
4195  |  | const Locale&  | 
4196  | 0  | SimpleDateFormat::getSmpFmtLocale(void) const { | 
4197  | 0  |     return fLocale;  | 
4198  | 0  | }  | 
4199  |  |  | 
4200  |  | //----------------------------------------------------------------------  | 
4201  |  |  | 
4202  |  | int32_t  | 
4203  |  | SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,  | 
4204  | 0  |                                  int32_t patLoc, UBool isNegative) const { | 
4205  |  |     // local variables  | 
4206  | 0  |     UnicodeString suf;  | 
4207  | 0  |     int32_t patternMatch;  | 
4208  | 0  |     int32_t textPreMatch;  | 
4209  | 0  |     int32_t textPostMatch;  | 
4210  |  |  | 
4211  |  |     // check that we are still in range  | 
4212  | 0  |     if ( (start > text.length()) ||  | 
4213  | 0  |          (start < 0) ||  | 
4214  | 0  |          (patLoc < 0) ||  | 
4215  | 0  |          (patLoc > fPattern.length())) { | 
4216  |  |         // out of range, don't advance location in text  | 
4217  | 0  |         return start;  | 
4218  | 0  |     }  | 
4219  |  |  | 
4220  |  |     // get the suffix  | 
4221  | 0  |     DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);  | 
4222  | 0  |     if (decfmt != NULL) { | 
4223  | 0  |         if (isNegative) { | 
4224  | 0  |             suf = decfmt->getNegativeSuffix(suf);  | 
4225  | 0  |         }  | 
4226  | 0  |         else { | 
4227  | 0  |             suf = decfmt->getPositiveSuffix(suf);  | 
4228  | 0  |         }  | 
4229  | 0  |     }  | 
4230  |  |  | 
4231  |  |     // check for suffix  | 
4232  | 0  |     if (suf.length() <= 0) { | 
4233  | 0  |         return start;  | 
4234  | 0  |     }  | 
4235  |  |  | 
4236  |  |     // check suffix will be encountered in the pattern  | 
4237  | 0  |     patternMatch = compareSimpleAffix(suf,fPattern,patLoc);  | 
4238  |  |  | 
4239  |  |     // check if a suffix will be encountered in the text  | 
4240  | 0  |     textPreMatch = compareSimpleAffix(suf,text,start);  | 
4241  |  |  | 
4242  |  |     // check if a suffix was encountered in the text  | 
4243  | 0  |     textPostMatch = compareSimpleAffix(suf,text,start-suf.length());  | 
4244  |  |  | 
4245  |  |     // check for suffix match  | 
4246  | 0  |     if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) { | 
4247  | 0  |         return start;  | 
4248  | 0  |     }  | 
4249  | 0  |     else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) { | 
4250  | 0  |         return  start - suf.length();  | 
4251  | 0  |     }  | 
4252  |  |  | 
4253  |  |     // should not get here  | 
4254  | 0  |     return start;  | 
4255  | 0  | }  | 
4256  |  |  | 
4257  |  | //----------------------------------------------------------------------  | 
4258  |  |  | 
4259  |  | int32_t  | 
4260  |  | SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,  | 
4261  |  |                    const UnicodeString& input,  | 
4262  | 0  |                    int32_t pos) const { | 
4263  | 0  |     int32_t start = pos;  | 
4264  | 0  |     for (int32_t i=0; i<affix.length(); ) { | 
4265  | 0  |         UChar32 c = affix.char32At(i);  | 
4266  | 0  |         int32_t len = U16_LENGTH(c);  | 
4267  | 0  |         if (PatternProps::isWhiteSpace(c)) { | 
4268  |  |             // We may have a pattern like: \u200F \u0020  | 
4269  |  |             //        and input text like: \u200F \u0020  | 
4270  |  |             // Note that U+200F and U+0020 are Pattern_White_Space but only  | 
4271  |  |             // U+0020 is UWhiteSpace.  So we have to first do a direct  | 
4272  |  |             // match of the run of Pattern_White_Space in the pattern,  | 
4273  |  |             // then match any extra characters.  | 
4274  | 0  |             UBool literalMatch = FALSE;  | 
4275  | 0  |             while (pos < input.length() &&  | 
4276  | 0  |                    input.char32At(pos) == c) { | 
4277  | 0  |                 literalMatch = TRUE;  | 
4278  | 0  |                 i += len;  | 
4279  | 0  |                 pos += len;  | 
4280  | 0  |                 if (i == affix.length()) { | 
4281  | 0  |                     break;  | 
4282  | 0  |                 }  | 
4283  | 0  |                 c = affix.char32At(i);  | 
4284  | 0  |                 len = U16_LENGTH(c);  | 
4285  | 0  |                 if (!PatternProps::isWhiteSpace(c)) { | 
4286  | 0  |                     break;  | 
4287  | 0  |                 }  | 
4288  | 0  |             }  | 
4289  |  |  | 
4290  |  |             // Advance over run in pattern  | 
4291  | 0  |             i = skipPatternWhiteSpace(affix, i);  | 
4292  |  |  | 
4293  |  |             // Advance over run in input text  | 
4294  |  |             // Must see at least one white space char in input,  | 
4295  |  |             // unless we've already matched some characters literally.  | 
4296  | 0  |             int32_t s = pos;  | 
4297  | 0  |             pos = skipUWhiteSpace(input, pos);  | 
4298  | 0  |             if (pos == s && !literalMatch) { | 
4299  | 0  |                 return -1;  | 
4300  | 0  |             }  | 
4301  |  |  | 
4302  |  |             // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.  | 
4303  |  |             // Otherwise, the previous lines may have skipped over text (such as U+00A0) that  | 
4304  |  |             // is also in the affix.  | 
4305  | 0  |             i = skipUWhiteSpace(affix, i);  | 
4306  | 0  |         } else { | 
4307  | 0  |             if (pos < input.length() &&  | 
4308  | 0  |                 input.char32At(pos) == c) { | 
4309  | 0  |                 i += len;  | 
4310  | 0  |                 pos += len;  | 
4311  | 0  |             } else { | 
4312  | 0  |                 return -1;  | 
4313  | 0  |             }  | 
4314  | 0  |         }  | 
4315  | 0  |     }  | 
4316  | 0  |     return pos - start;  | 
4317  | 0  | }  | 
4318  |  |  | 
4319  |  | //----------------------------------------------------------------------  | 
4320  |  |  | 
4321  |  | int32_t  | 
4322  | 0  | SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const { | 
4323  | 0  |     const UChar* s = text.getBuffer();  | 
4324  | 0  |     return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);  | 
4325  | 0  | }  | 
4326  |  |  | 
4327  |  | //----------------------------------------------------------------------  | 
4328  |  |  | 
4329  |  | int32_t  | 
4330  | 0  | SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const { | 
4331  | 0  |     while (pos < text.length()) { | 
4332  | 0  |         UChar32 c = text.char32At(pos);  | 
4333  | 0  |         if (!u_isUWhiteSpace(c)) { | 
4334  | 0  |             break;  | 
4335  | 0  |         }  | 
4336  | 0  |         pos += U16_LENGTH(c);  | 
4337  | 0  |     }  | 
4338  | 0  |     return pos;  | 
4339  | 0  | }  | 
4340  |  |  | 
4341  |  | //----------------------------------------------------------------------  | 
4342  |  |  | 
4343  |  | // Lazy TimeZoneFormat instantiation, semantically const.  | 
4344  |  | TimeZoneFormat *  | 
4345  | 0  | SimpleDateFormat::tzFormat(UErrorCode &status) const { | 
4346  | 0  |     Mutex m(&LOCK);  | 
4347  | 0  |     if (fTimeZoneFormat == nullptr && U_SUCCESS(status)) { | 
4348  | 0  |         const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat =  | 
4349  | 0  |                 TimeZoneFormat::createInstance(fLocale, status);  | 
4350  | 0  |     }  | 
4351  | 0  |     return fTimeZoneFormat;  | 
4352  | 0  | }  | 
4353  |  |  | 
4354  | 0  | void SimpleDateFormat::parsePattern() { | 
4355  | 0  |     fHasMinute = FALSE;  | 
4356  | 0  |     fHasSecond = FALSE;  | 
4357  | 0  |     fHasHanYearChar = FALSE;  | 
4358  |  | 
  | 
4359  | 0  |     int len = fPattern.length();  | 
4360  | 0  |     UBool inQuote = FALSE;  | 
4361  | 0  |     for (int32_t i = 0; i < len; ++i) { | 
4362  | 0  |         UChar ch = fPattern[i];  | 
4363  | 0  |         if (ch == QUOTE) { | 
4364  | 0  |             inQuote = !inQuote;  | 
4365  | 0  |         }  | 
4366  | 0  |         if (ch == 0x5E74) { // don't care whether this is inside quotes | 
4367  | 0  |             fHasHanYearChar = TRUE;  | 
4368  | 0  |         }  | 
4369  | 0  |         if (!inQuote) { | 
4370  | 0  |             if (ch == 0x6D) {  // 0x6D == 'm' | 
4371  | 0  |                 fHasMinute = TRUE;  | 
4372  | 0  |             }  | 
4373  | 0  |             if (ch == 0x73) {  // 0x73 == 's' | 
4374  | 0  |                 fHasSecond = TRUE;  | 
4375  | 0  |             }  | 
4376  | 0  |         }  | 
4377  | 0  |     }  | 
4378  | 0  | }  | 
4379  |  |  | 
4380  |  | U_NAMESPACE_END  | 
4381  |  |  | 
4382  |  | #endif /* #if !UCONFIG_NO_FORMATTING */  | 
4383  |  |  | 
4384  |  | //eof  |