• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2011, International Business Machines Corporation and    *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 *
7 * File SMPDTFMT.CPP
8 *
9 * Modification History:
10 *
11 *   Date        Name        Description
12 *   02/19/97    aliu        Converted from java.
13 *   03/31/97    aliu        Modified extensively to work with 50 locales.
14 *   04/01/97    aliu        Added support for centuries.
15 *   07/09/97    helena      Made ParsePosition into a class.
16 *   07/21/98    stephen     Added initializeDefaultCentury.
17 *                             Removed getZoneIndex (added in DateFormatSymbols)
18 *                             Removed subParseLong
19 *                             Removed chk
20 *  02/22/99     stephen     Removed character literals for EBCDIC safety
21 *   10/14/99    aliu        Updated 2-digit year parsing so that only "00" thru
22 *                           "99" are recognized. {j28 4182066}
23 *   11/15/99    weiv        Added support for week of year/day of week format
24 ********************************************************************************
25 */
26 
27 #define ZID_KEY_MAX 128
28 
29 #include "unicode/utypes.h"
30 
31 #if !UCONFIG_NO_FORMATTING
32 
33 #include "unicode/smpdtfmt.h"
34 #include "unicode/dtfmtsym.h"
35 #include "unicode/ures.h"
36 #include "unicode/msgfmt.h"
37 #include "unicode/calendar.h"
38 #include "unicode/gregocal.h"
39 #include "unicode/timezone.h"
40 #include "unicode/decimfmt.h"
41 #include "unicode/dcfmtsym.h"
42 #include "unicode/uchar.h"
43 #include "unicode/uniset.h"
44 #include "unicode/ustring.h"
45 #include "unicode/basictz.h"
46 #include "unicode/simpletz.h"
47 #include "unicode/rbtz.h"
48 #include "unicode/vtzone.h"
49 #include "olsontz.h"
50 #include "patternprops.h"
51 #include "fphdlimp.h"
52 #include "gregoimp.h"
53 #include "hebrwcal.h"
54 #include "cstring.h"
55 #include "uassert.h"
56 #include "cmemory.h"
57 #include "umutex.h"
58 #include "tzfmt.h"
59 #include <float.h>
60 #include "smpdtfst.h"
61 
62 #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
63 #include <stdio.h>
64 #endif
65 
66 // *****************************************************************************
67 // class SimpleDateFormat
68 // *****************************************************************************
69 
70 U_NAMESPACE_BEGIN
71 
72 static const UChar PATTERN_CHAR_BASE = 0x40;
73 
74 /**
75  * Last-resort string to use for "GMT" when constructing time zone strings.
76  */
77 // For time zones that have no names, use strings GMT+minutes and
78 // GMT-minutes. For instance, in France the time zone is GMT+60.
79 // Also accepted are GMT+H:MM or GMT-H:MM.
80 static const UChar gGmt[]      = {0x0047, 0x004D, 0x0054, 0x0000};         // "GMT"
81 static const UChar gGmtPlus[]  = {0x0047, 0x004D, 0x0054, 0x002B, 0x0000}; // "GMT+"
82 static const UChar gGmtMinus[] = {0x0047, 0x004D, 0x0054, 0x002D, 0x0000}; // "GMT-"
83 static const UChar gDefGmtPat[]       = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
84 static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* -HH:mm:ss */
85 static const UChar gDefGmtNegHmPat[]  = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */
86 static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */
87 static const UChar gDefGmtPosHmPat[]  = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */
88 static const UChar gUt[]       = {0x0055, 0x0054, 0x0000};  // "UT"
89 static const UChar gUtc[]      = {0x0055, 0x0054, 0x0043, 0x0000};  // "UT"
90 
91 typedef enum GmtPatSize {
92     kGmtLen = 3,
93     kGmtPatLen = 6,
94     kNegHmsLen = 9,
95     kNegHmLen = 6,
96     kPosHmsLen = 9,
97     kPosHmLen = 6,
98     kUtLen = 2,
99     kUtcLen = 3
100 } GmtPatSize;
101 
102 // Stuff needed for numbering system overrides
103 
104 typedef enum OvrStrType {
105     kOvrStrDate = 0,
106     kOvrStrTime = 1,
107     kOvrStrBoth = 2
108 } OvrStrType;
109 
110 static const UDateFormatField kDateFields[] = {
111     UDAT_YEAR_FIELD,
112     UDAT_MONTH_FIELD,
113     UDAT_DATE_FIELD,
114     UDAT_DAY_OF_YEAR_FIELD,
115     UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
116     UDAT_WEEK_OF_YEAR_FIELD,
117     UDAT_WEEK_OF_MONTH_FIELD,
118     UDAT_YEAR_WOY_FIELD,
119     UDAT_EXTENDED_YEAR_FIELD,
120     UDAT_JULIAN_DAY_FIELD,
121     UDAT_STANDALONE_DAY_FIELD,
122     UDAT_STANDALONE_MONTH_FIELD,
123     UDAT_QUARTER_FIELD,
124     UDAT_STANDALONE_QUARTER_FIELD };
125 static const int8_t kDateFieldsCount = 13;
126 
127 static const UDateFormatField kTimeFields[] = {
128     UDAT_HOUR_OF_DAY1_FIELD,
129     UDAT_HOUR_OF_DAY0_FIELD,
130     UDAT_MINUTE_FIELD,
131     UDAT_SECOND_FIELD,
132     UDAT_FRACTIONAL_SECOND_FIELD,
133     UDAT_HOUR1_FIELD,
134     UDAT_HOUR0_FIELD,
135     UDAT_MILLISECONDS_IN_DAY_FIELD,
136     UDAT_TIMEZONE_RFC_FIELD };
137 static const int8_t kTimeFieldsCount = 9;
138 
139 
140 // This is a pattern-of-last-resort used when we can't load a usable pattern out
141 // of a resource.
142 static const UChar gDefaultPattern[] =
143 {
144     0x79, 0x79, 0x79, 0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0
145 };  /* "yyyyMMdd hh:mm a" */
146 
147 // This prefix is designed to NEVER MATCH real text, in order to
148 // suppress the parsing of negative numbers.  Adjust as needed (if
149 // this becomes valid Unicode).
150 static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0};
151 
152 /**
153  * These are the tags we expect to see in normal resource bundle files associated
154  * with a locale.
155  */
156 static const char gDateTimePatternsTag[]="DateTimePatterns";
157 
158 static const UChar gEtcUTC[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x54, 0x43, 0x00}; // "Etc/UTC"
159 static const UChar QUOTE = 0x27; // Single quote
160 
161 /*
162  * The field range check bias for each UDateFormatField.
163  * The bias is added to the minimum and maximum values
164  * before they are compared to the parsed number.
165  * For example, the calendar stores zero-based month numbers
166  * but the parsed month numbers start at 1, so the bias is 1.
167  *
168  * A value of -1 means that the value is not checked.
169  */
170 static const int32_t gFieldRangeBias[] = {
171     -1,  // 'G' - UDAT_ERA_FIELD
172     -1,  // 'y' - UDAT_YEAR_FIELD
173      1,  // 'M' - UDAT_MONTH_FIELD
174      0,  // 'd' - UDAT_DATE_FIELD
175     -1,  // 'k' - UDAT_HOUR_OF_DAY1_FIELD
176     -1,  // 'H' - UDAT_HOUR_OF_DAY0_FIELD
177      0,  // 'm' - UDAT_MINUTE_FIELD
178      0,  // 's' - UDAT_SEOND_FIELD
179     -1,  // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)
180     -1,  // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)
181     -1,  // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)
182     -1,  // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?)
183     -1,  // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?)
184     -1,  // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?)
185     -1,  // 'a' - UDAT_AM_PM_FIELD
186     -1,  // 'h' - UDAT_HOUR1_FIELD
187     -1,  // 'K' - UDAT_HOUR0_FIELD
188     -1,  // 'z' - UDAT_TIMEZONE_FIELD
189     -1,  // 'Y' - UDAT_YEAR_WOY_FIELD
190     -1,  // 'e' - UDAT_DOW_LOCAL_FIELD
191     -1,  // 'u' - UDAT_EXTENDED_YEAR_FIELD
192     -1,  // 'g' - UDAT_JULIAN_DAY_FIELD
193     -1,  // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD
194     -1,  // 'Z' - UDAT_TIMEZONE_RFC_FIELD
195     -1,  // 'v' - UDAT_TIMEZONE_GENERIC_FIELD
196      0,  // 'c' - UDAT_STANDALONE_DAY_FIELD
197      1,  // 'L' - UDAT_STANDALONE_MONTH_FIELD
198     -1,  // 'Q' - UDAT_QUARTER_FIELD (1-4?)
199     -1,  // 'q' - UDAT_STANDALONE_QUARTER_FIELD
200     -1   // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
201 };
202 
203 static UMTX LOCK;
204 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)205 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
206 
207 //----------------------------------------------------------------------
208 
209 SimpleDateFormat::~SimpleDateFormat()
210 {
211     delete fSymbols;
212     if (fGMTFormatters) {
213         for (int32_t i = 0; i < kNumGMTFormatters; i++) {
214             if (fGMTFormatters[i]) {
215                 delete fGMTFormatters[i];
216             }
217         }
218         uprv_free(fGMTFormatters);
219 
220     }
221     if (fNumberFormatters) {
222         uprv_free(fNumberFormatters);
223     }
224     if (fTimeZoneFormat) {
225         delete fTimeZoneFormat;
226     }
227 
228     while (fOverrideList) {
229         NSOverride *cur = fOverrideList;
230         fOverrideList = cur->next;
231         delete cur->nf;
232         uprv_free(cur);
233     }
234 }
235 
236 //----------------------------------------------------------------------
237 
SimpleDateFormat(UErrorCode & status)238 SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
239   :   fLocale(Locale::getDefault()),
240       fSymbols(NULL),
241       fTimeZoneFormat(NULL),
242       fGMTFormatters(NULL),
243       fNumberFormatters(NULL),
244       fOverrideList(NULL)
245 {
246     construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
247     initializeDefaultCentury();
248 }
249 
250 //----------------------------------------------------------------------
251 
SimpleDateFormat(const UnicodeString & pattern,UErrorCode & status)252 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
253                                    UErrorCode &status)
254 :   fPattern(pattern),
255     fLocale(Locale::getDefault()),
256     fSymbols(NULL),
257     fTimeZoneFormat(NULL),
258     fGMTFormatters(NULL),
259     fNumberFormatters(NULL),
260     fOverrideList(NULL)
261 {
262     fDateOverride.setToBogus();
263     fTimeOverride.setToBogus();
264     initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
265     initialize(fLocale, status);
266     initializeDefaultCentury();
267 
268 }
269 //----------------------------------------------------------------------
270 
SimpleDateFormat(const UnicodeString & pattern,const UnicodeString & override,UErrorCode & status)271 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
272                                    const UnicodeString& override,
273                                    UErrorCode &status)
274 :   fPattern(pattern),
275     fLocale(Locale::getDefault()),
276     fSymbols(NULL),
277     fTimeZoneFormat(NULL),
278     fGMTFormatters(NULL),
279     fNumberFormatters(NULL),
280     fOverrideList(NULL)
281 {
282     fDateOverride.setTo(override);
283     fTimeOverride.setToBogus();
284     initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
285     initialize(fLocale, status);
286     initializeDefaultCentury();
287 
288     processOverrideString(fLocale,override,kOvrStrBoth,status);
289 
290 }
291 
292 //----------------------------------------------------------------------
293 
SimpleDateFormat(const UnicodeString & pattern,const Locale & locale,UErrorCode & status)294 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
295                                    const Locale& locale,
296                                    UErrorCode& status)
297 :   fPattern(pattern),
298     fLocale(locale),
299     fTimeZoneFormat(NULL),
300     fGMTFormatters(NULL),
301     fNumberFormatters(NULL),
302     fOverrideList(NULL)
303 {
304 
305     fDateOverride.setToBogus();
306     fTimeOverride.setToBogus();
307 
308     initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
309     initialize(fLocale, status);
310     initializeDefaultCentury();
311 }
312 
313 //----------------------------------------------------------------------
314 
SimpleDateFormat(const UnicodeString & pattern,const UnicodeString & override,const Locale & locale,UErrorCode & status)315 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
316                                    const UnicodeString& override,
317                                    const Locale& locale,
318                                    UErrorCode& status)
319 :   fPattern(pattern),
320     fLocale(locale),
321     fTimeZoneFormat(NULL),
322     fGMTFormatters(NULL),
323     fNumberFormatters(NULL),
324     fOverrideList(NULL)
325 {
326 
327     fDateOverride.setTo(override);
328     fTimeOverride.setToBogus();
329 
330     initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
331     initialize(fLocale, status);
332     initializeDefaultCentury();
333 
334     processOverrideString(locale,override,kOvrStrBoth,status);
335 
336 }
337 
338 //----------------------------------------------------------------------
339 
SimpleDateFormat(const UnicodeString & pattern,DateFormatSymbols * symbolsToAdopt,UErrorCode & status)340 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
341                                    DateFormatSymbols* symbolsToAdopt,
342                                    UErrorCode& status)
343 :   fPattern(pattern),
344     fLocale(Locale::getDefault()),
345     fSymbols(symbolsToAdopt),
346     fTimeZoneFormat(NULL),
347     fGMTFormatters(NULL),
348     fNumberFormatters(NULL),
349     fOverrideList(NULL)
350 {
351 
352     fDateOverride.setToBogus();
353     fTimeOverride.setToBogus();
354 
355     initializeCalendar(NULL,fLocale,status);
356     initialize(fLocale, status);
357     initializeDefaultCentury();
358 }
359 
360 //----------------------------------------------------------------------
361 
SimpleDateFormat(const UnicodeString & pattern,const DateFormatSymbols & symbols,UErrorCode & status)362 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
363                                    const DateFormatSymbols& symbols,
364                                    UErrorCode& status)
365 :   fPattern(pattern),
366     fLocale(Locale::getDefault()),
367     fSymbols(new DateFormatSymbols(symbols)),
368     fTimeZoneFormat(NULL),
369     fGMTFormatters(NULL),
370     fNumberFormatters(NULL),
371     fOverrideList(NULL)
372 {
373 
374     fDateOverride.setToBogus();
375     fTimeOverride.setToBogus();
376 
377     initializeCalendar(NULL, fLocale, status);
378     initialize(fLocale, status);
379     initializeDefaultCentury();
380 }
381 
382 //----------------------------------------------------------------------
383 
384 // Not for public consumption; used by DateFormat
SimpleDateFormat(EStyle timeStyle,EStyle dateStyle,const Locale & locale,UErrorCode & status)385 SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
386                                    EStyle dateStyle,
387                                    const Locale& locale,
388                                    UErrorCode& status)
389 :   fLocale(locale),
390     fSymbols(NULL),
391     fTimeZoneFormat(NULL),
392     fGMTFormatters(NULL),
393     fNumberFormatters(NULL),
394     fOverrideList(NULL)
395 {
396     construct(timeStyle, dateStyle, fLocale, status);
397     if(U_SUCCESS(status)) {
398       initializeDefaultCentury();
399     }
400 }
401 
402 //----------------------------------------------------------------------
403 
404 /**
405  * Not for public consumption; used by DateFormat.  This constructor
406  * never fails.  If the resource data is not available, it uses the
407  * the last resort symbols.
408  */
SimpleDateFormat(const Locale & locale,UErrorCode & status)409 SimpleDateFormat::SimpleDateFormat(const Locale& locale,
410                                    UErrorCode& status)
411 :   fPattern(gDefaultPattern),
412     fLocale(locale),
413     fSymbols(NULL),
414     fTimeZoneFormat(NULL),
415     fGMTFormatters(NULL),
416     fNumberFormatters(NULL),
417     fOverrideList(NULL)
418 {
419     if (U_FAILURE(status)) return;
420     initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status);
421     if (U_FAILURE(status))
422     {
423         status = U_ZERO_ERROR;
424         delete fSymbols;
425         // This constructor doesn't fail; it uses last resort data
426         fSymbols = new DateFormatSymbols(status);
427         /* test for NULL */
428         if (fSymbols == 0) {
429             status = U_MEMORY_ALLOCATION_ERROR;
430             return;
431         }
432     }
433 
434     fDateOverride.setToBogus();
435     fTimeOverride.setToBogus();
436 
437     initialize(fLocale, status);
438     if(U_SUCCESS(status)) {
439       initializeDefaultCentury();
440     }
441 }
442 
443 //----------------------------------------------------------------------
444 
SimpleDateFormat(const SimpleDateFormat & other)445 SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
446 :   DateFormat(other),
447     fSymbols(NULL),
448     fTimeZoneFormat(NULL),
449     fGMTFormatters(NULL),
450     fNumberFormatters(NULL),
451     fOverrideList(NULL)
452 {
453     *this = other;
454 }
455 
456 //----------------------------------------------------------------------
457 
operator =(const SimpleDateFormat & other)458 SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
459 {
460     if (this == &other) {
461         return *this;
462     }
463     DateFormat::operator=(other);
464 
465     delete fSymbols;
466     fSymbols = NULL;
467 
468     if (other.fSymbols)
469         fSymbols = new DateFormatSymbols(*other.fSymbols);
470 
471     fDefaultCenturyStart         = other.fDefaultCenturyStart;
472     fDefaultCenturyStartYear     = other.fDefaultCenturyStartYear;
473     fHaveDefaultCentury          = other.fHaveDefaultCentury;
474 
475     fPattern = other.fPattern;
476 
477     // TimeZoneFormat in ICU4C only depends on a locale for now
478     if (fLocale != other.fLocale) {
479         delete fTimeZoneFormat;
480     }
481 
482     return *this;
483 }
484 
485 //----------------------------------------------------------------------
486 
487 Format*
clone() const488 SimpleDateFormat::clone() const
489 {
490     return new SimpleDateFormat(*this);
491 }
492 
493 //----------------------------------------------------------------------
494 
495 UBool
operator ==(const Format & other) const496 SimpleDateFormat::operator==(const Format& other) const
497 {
498     if (DateFormat::operator==(other)) {
499         // DateFormat::operator== guarantees following cast is safe
500         SimpleDateFormat* that = (SimpleDateFormat*)&other;
501         return (fPattern             == that->fPattern &&
502                 fSymbols             != NULL && // Check for pathological object
503                 that->fSymbols       != NULL && // Check for pathological object
504                 *fSymbols            == *that->fSymbols &&
505                 fHaveDefaultCentury  == that->fHaveDefaultCentury &&
506                 fDefaultCenturyStart == that->fDefaultCenturyStart);
507     }
508     return FALSE;
509 }
510 
511 //----------------------------------------------------------------------
512 
construct(EStyle timeStyle,EStyle dateStyle,const Locale & locale,UErrorCode & status)513 void SimpleDateFormat::construct(EStyle timeStyle,
514                                  EStyle dateStyle,
515                                  const Locale& locale,
516                                  UErrorCode& status)
517 {
518     // called by several constructors to load pattern data from the resources
519     if (U_FAILURE(status)) return;
520 
521     // We will need the calendar to know what type of symbols to load.
522     initializeCalendar(NULL, locale, status);
523     if (U_FAILURE(status)) return;
524 
525     CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
526     UResourceBundle *dateTimePatterns = calData.getByKey(gDateTimePatternsTag, status);
527     UResourceBundle *currentBundle;
528 
529     if (U_FAILURE(status)) return;
530 
531     if (ures_getSize(dateTimePatterns) <= kDateTime)
532     {
533         status = U_INVALID_FORMAT_ERROR;
534         return;
535     }
536 
537     setLocaleIDs(ures_getLocaleByType(dateTimePatterns, ULOC_VALID_LOCALE, &status),
538                  ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status));
539 
540     // create a symbols object from the locale
541     initializeSymbols(locale,fCalendar, status);
542     if (U_FAILURE(status)) return;
543     /* test for NULL */
544     if (fSymbols == 0) {
545         status = U_MEMORY_ALLOCATION_ERROR;
546         return;
547     }
548 
549     const UChar *resStr,*ovrStr;
550     int32_t resStrLen,ovrStrLen = 0;
551     fDateOverride.setToBogus();
552     fTimeOverride.setToBogus();
553 
554     // if the pattern should include both date and time information, use the date/time
555     // pattern string as a guide to tell use how to glue together the appropriate date
556     // and time pattern strings.  The actual gluing-together is handled by a convenience
557     // method on MessageFormat.
558     if ((timeStyle != kNone) && (dateStyle != kNone))
559     {
560         Formattable timeDateArray[2];
561 
562         // use Formattable::adoptString() so that we can use fastCopyFrom()
563         // instead of Formattable::setString()'s unaware, safe, deep string clone
564         // see Jitterbug 2296
565 
566         currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
567         if (U_FAILURE(status)) {
568            status = U_INVALID_FORMAT_ERROR;
569            return;
570         }
571         switch (ures_getType(currentBundle)) {
572             case URES_STRING: {
573                resStr = ures_getString(currentBundle, &resStrLen, &status);
574                break;
575             }
576             case URES_ARRAY: {
577                resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
578                ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
579                fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen);
580                break;
581             }
582             default: {
583                status = U_INVALID_FORMAT_ERROR;
584                ures_close(currentBundle);
585                return;
586             }
587         }
588         ures_close(currentBundle);
589 
590         UnicodeString *tempus1 = new UnicodeString(TRUE, resStr, resStrLen);
591         // NULL pointer check
592         if (tempus1 == NULL) {
593             status = U_MEMORY_ALLOCATION_ERROR;
594             return;
595         }
596         timeDateArray[0].adoptString(tempus1);
597 
598         currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
599         if (U_FAILURE(status)) {
600            status = U_INVALID_FORMAT_ERROR;
601            return;
602         }
603         switch (ures_getType(currentBundle)) {
604             case URES_STRING: {
605                resStr = ures_getString(currentBundle, &resStrLen, &status);
606                break;
607             }
608             case URES_ARRAY: {
609                resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
610                ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
611                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
612                break;
613             }
614             default: {
615                status = U_INVALID_FORMAT_ERROR;
616                ures_close(currentBundle);
617                return;
618             }
619         }
620         ures_close(currentBundle);
621 
622         UnicodeString *tempus2 = new UnicodeString(TRUE, resStr, resStrLen);
623         // Null pointer check
624         if (tempus2 == NULL) {
625             status = U_MEMORY_ALLOCATION_ERROR;
626             return;
627         }
628         timeDateArray[1].adoptString(tempus2);
629 
630         int32_t glueIndex = kDateTime;
631         int32_t patternsSize = ures_getSize(dateTimePatterns);
632         if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
633             // Get proper date time format
634             glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));
635         }
636 
637         resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &resStrLen, &status);
638         MessageFormat::format(UnicodeString(TRUE, resStr, resStrLen), timeDateArray, 2, fPattern, status);
639     }
640     // if the pattern includes just time data or just date date, load the appropriate
641     // pattern string from the resources
642     // setTo() - see DateFormatSymbols::assignArray comments
643     else if (timeStyle != kNone) {
644         currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
645         if (U_FAILURE(status)) {
646            status = U_INVALID_FORMAT_ERROR;
647            return;
648         }
649         switch (ures_getType(currentBundle)) {
650             case URES_STRING: {
651                resStr = ures_getString(currentBundle, &resStrLen, &status);
652                break;
653             }
654             case URES_ARRAY: {
655                resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
656                ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
657                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
658                break;
659             }
660             default: {
661                status = U_INVALID_FORMAT_ERROR;
662                 ures_close(currentBundle);
663                return;
664             }
665         }
666         fPattern.setTo(TRUE, resStr, resStrLen);
667         ures_close(currentBundle);
668     }
669     else if (dateStyle != kNone) {
670         currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
671         if (U_FAILURE(status)) {
672            status = U_INVALID_FORMAT_ERROR;
673            return;
674         }
675         switch (ures_getType(currentBundle)) {
676             case URES_STRING: {
677                resStr = ures_getString(currentBundle, &resStrLen, &status);
678                break;
679             }
680             case URES_ARRAY: {
681                resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
682                ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
683                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
684                break;
685             }
686             default: {
687                status = U_INVALID_FORMAT_ERROR;
688                ures_close(currentBundle);
689                return;
690             }
691         }
692         fPattern.setTo(TRUE, resStr, resStrLen);
693         ures_close(currentBundle);
694     }
695 
696     // and if it includes _neither_, that's an error
697     else
698         status = U_INVALID_FORMAT_ERROR;
699 
700     // finally, finish initializing by creating a Calendar and a NumberFormat
701     initialize(locale, status);
702 }
703 
704 //----------------------------------------------------------------------
705 
706 Calendar*
initializeCalendar(TimeZone * adoptZone,const Locale & locale,UErrorCode & status)707 SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
708 {
709     if(!U_FAILURE(status)) {
710         fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
711     }
712     if (U_SUCCESS(status) && fCalendar == NULL) {
713         status = U_MEMORY_ALLOCATION_ERROR;
714     }
715     return fCalendar;
716 }
717 
718 void
initializeSymbols(const Locale & locale,Calendar * calendar,UErrorCode & status)719 SimpleDateFormat::initializeSymbols(const Locale& locale, Calendar* calendar, UErrorCode& status)
720 {
721   if(U_FAILURE(status)) {
722     fSymbols = NULL;
723   } else {
724     // pass in calendar type - use NULL (default) if no calendar set (or err).
725     fSymbols = new DateFormatSymbols(locale, calendar?calendar->getType() :NULL , status);
726     // Null pointer check
727     if (fSymbols == NULL) {
728         status = U_MEMORY_ALLOCATION_ERROR;
729         return;
730     }
731   }
732 }
733 
734 void
initialize(const Locale & locale,UErrorCode & status)735 SimpleDateFormat::initialize(const Locale& locale,
736                              UErrorCode& status)
737 {
738     if (U_FAILURE(status)) return;
739 
740     // We don't need to check that the row count is >= 1, since all 2d arrays have at
741     // least one row
742     fNumberFormat = NumberFormat::createInstance(locale, status);
743     if (fNumberFormat != NULL && U_SUCCESS(status))
744     {
745         // no matter what the locale's default number format looked like, we want
746         // to modify it so that it doesn't use thousands separators, doesn't always
747         // show the decimal point, and recognizes integers only when parsing
748 
749         fNumberFormat->setGroupingUsed(FALSE);
750         DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
751         if (decfmt != NULL) {
752             decfmt->setDecimalSeparatorAlwaysShown(FALSE);
753         }
754         fNumberFormat->setParseIntegerOnly(TRUE);
755         fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
756 
757         //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
758 
759         initNumberFormatters(locale,status);
760 
761     }
762     else if (U_SUCCESS(status))
763     {
764         status = U_MISSING_RESOURCE_ERROR;
765     }
766 }
767 
768 /* Initialize the fields we use to disambiguate ambiguous years. Separate
769  * so we can call it from readObject().
770  */
initializeDefaultCentury()771 void SimpleDateFormat::initializeDefaultCentury()
772 {
773   if(fCalendar) {
774     fHaveDefaultCentury = fCalendar->haveDefaultCentury();
775     if(fHaveDefaultCentury) {
776       fDefaultCenturyStart = fCalendar->defaultCenturyStart();
777       fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();
778     } else {
779       fDefaultCenturyStart = DBL_MIN;
780       fDefaultCenturyStartYear = -1;
781     }
782   }
783 }
784 
785 /* Define one-century window into which to disambiguate dates using
786  * two-digit years. Make public in JDK 1.2.
787  */
parseAmbiguousDatesAsAfter(UDate startDate,UErrorCode & status)788 void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
789 {
790     if(U_FAILURE(status)) {
791         return;
792     }
793     if(!fCalendar) {
794       status = U_ILLEGAL_ARGUMENT_ERROR;
795       return;
796     }
797 
798     fCalendar->setTime(startDate, status);
799     if(U_SUCCESS(status)) {
800         fHaveDefaultCentury = TRUE;
801         fDefaultCenturyStart = startDate;
802         fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);
803     }
804 }
805 
806 //----------------------------------------------------------------------
807 
808 UnicodeString&
format(Calendar & cal,UnicodeString & appendTo,FieldPosition & pos) const809 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
810 {
811   UErrorCode status = U_ZERO_ERROR;
812   FieldPositionOnlyHandler handler(pos);
813   return _format(cal, appendTo, handler, status);
814 }
815 
816 //----------------------------------------------------------------------
817 
818 UnicodeString&
format(Calendar & cal,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const819 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
820                          FieldPositionIterator* posIter, UErrorCode& status) const
821 {
822   FieldPositionIteratorHandler handler(posIter, status);
823   return _format(cal, appendTo, handler, status);
824 }
825 
826 //----------------------------------------------------------------------
827 
828 UnicodeString&
_format(Calendar & cal,UnicodeString & appendTo,FieldPositionHandler & handler,UErrorCode & status) const829 SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionHandler& handler,
830                           UErrorCode& status) const
831 {
832     Calendar *workCal = &cal;
833     TimeZone *backupTZ = NULL;
834     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
835         // Different calendar type
836         // We use the time and time zone from the input calendar, but
837         // do not use the input calendar for field calculation.
838         UDate t = cal.getTime(status);
839         fCalendar->setTime(t, status);
840         backupTZ = fCalendar->getTimeZone().clone();
841         fCalendar->setTimeZone(cal.getTimeZone());
842         workCal = fCalendar;
843     }
844 
845     UBool inQuote = FALSE;
846     UChar prevCh = 0;
847     int32_t count = 0;
848 
849     // loop through the pattern string character by character
850     for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
851         UChar ch = fPattern[i];
852 
853         // Use subFormat() to format a repeated pattern character
854         // when a different pattern or non-pattern character is seen
855         if (ch != prevCh && count > 0) {
856             subFormat(appendTo, prevCh, count, handler, *workCal, status);
857             count = 0;
858         }
859         if (ch == QUOTE) {
860             // Consecutive single quotes are a single quote literal,
861             // either outside of quotes or between quotes
862             if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) {
863                 appendTo += (UChar)QUOTE;
864                 ++i;
865             } else {
866                 inQuote = ! inQuote;
867             }
868         }
869         else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
870                     || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
871             // ch is a date-time pattern character to be interpreted
872             // by subFormat(); count the number of times it is repeated
873             prevCh = ch;
874             ++count;
875         }
876         else {
877             // Append quoted characters and unquoted non-pattern characters
878             appendTo += ch;
879         }
880     }
881 
882     // Format the last item in the pattern, if any
883     if (count > 0) {
884         subFormat(appendTo, prevCh, count, handler, *workCal, status);
885     }
886 
887     if (backupTZ != NULL) {
888         // Restore the original time zone
889         fCalendar->adoptTimeZone(backupTZ);
890     }
891 
892     return appendTo;
893 }
894 
895 //----------------------------------------------------------------------
896 
897 /* Map calendar field into calendar field level.
898  * the larger the level, the smaller the field unit.
899  * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10,
900  * UCAL_MONTH level is 20.
901  * NOTE: if new fields adds in, the table needs to update.
902  */
903 const int32_t
904 SimpleDateFormat::fgCalendarFieldToLevel[] =
905 {
906     /*GyM*/ 0, 10, 20,
907     /*wW*/ 20, 30,
908     /*dDEF*/ 30, 20, 30, 30,
909     /*ahHm*/ 40, 50, 50, 60,
910     /*sS..*/ 70, 80,
911     /*z?Y*/ 0, 0, 10,
912     /*eug*/ 30, 10, 0,
913     /*A*/ 40
914 };
915 
916 
917 /* Map calendar field LETTER into calendar field level.
918  * the larger the level, the smaller the field unit.
919  * NOTE: if new fields adds in, the table needs to update.
920  */
921 const int32_t
922 SimpleDateFormat::fgPatternCharToLevel[] = {
923     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
924         -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1, -1,
925     //   P   Q   R   S   T   U   V   W   X   Y   Z
926         -1, 20, -1, 80, -1, -1,  0, 30, -1, 10,  0, -1, -1, -1, -1, -1,
927     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
928         -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50, -1, 60, -1, -1,
929     //   p   q   r   s   t   u   v   w   x   y   z
930         -1, 20, -1, 70, -1, 10,  0, 20, -1, 10,  0, -1, -1, -1, -1, -1
931 };
932 
933 
934 // Map index into pattern character string to Calendar field number.
935 const UCalendarDateFields
936 SimpleDateFormat::fgPatternIndexToCalendarField[] =
937 {
938     /*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
939     /*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY,
940     /*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND,
941     /*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,
942     /*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM,
943     /*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,
944     /*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR,
945     /*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET,
946     /*v*/   UCAL_ZONE_OFFSET,
947     /*c*/   UCAL_DOW_LOCAL,
948     /*L*/   UCAL_MONTH,
949     /*Q*/   UCAL_MONTH,
950     /*q*/   UCAL_MONTH,
951     /*V*/   UCAL_ZONE_OFFSET,
952 };
953 
954 // Map index into pattern character string to DateFormat field number
955 const UDateFormatField
956 SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
957     /*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD,
958     /*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD,
959     /*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD,
960     /*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
961     /*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD,
962     /*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD,
963     /*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD,
964     /*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD,
965     /*v*/   UDAT_TIMEZONE_GENERIC_FIELD,
966     /*c*/   UDAT_STANDALONE_DAY_FIELD,
967     /*L*/   UDAT_STANDALONE_MONTH_FIELD,
968     /*Q*/   UDAT_QUARTER_FIELD,
969     /*q*/   UDAT_STANDALONE_QUARTER_FIELD,
970     /*V*/   UDAT_TIMEZONE_SPECIAL_FIELD,
971 };
972 
973 //----------------------------------------------------------------------
974 
975 /**
976  * Append symbols[value] to dst.  Make sure the array index is not out
977  * of bounds.
978  */
979 static inline void
_appendSymbol(UnicodeString & dst,int32_t value,const UnicodeString * symbols,int32_t symbolsCount)980 _appendSymbol(UnicodeString& dst,
981               int32_t value,
982               const UnicodeString* symbols,
983               int32_t symbolsCount) {
984     U_ASSERT(0 <= value && value < symbolsCount);
985     if (0 <= value && value < symbolsCount) {
986         dst += symbols[value];
987     }
988 }
989 
990 //---------------------------------------------------------------------
991 void
appendGMT(NumberFormat * currentNumberFormat,UnicodeString & appendTo,Calendar & cal,UErrorCode & status) const992 SimpleDateFormat::appendGMT(NumberFormat *currentNumberFormat,UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const{
993     int32_t offset = cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status);
994     if (U_FAILURE(status)) {
995         return;
996     }
997     if (offset == 0) {
998         // use GMT zero format
999         appendTo += fSymbols->fGmtZero;
1000     } else {
1001         if (isDefaultGMTFormat()) {
1002             formatGMTDefault(currentNumberFormat,appendTo, offset);
1003         } else {
1004             ((SimpleDateFormat*)this)->initGMTFormatters(status);
1005             if (U_SUCCESS(status)) {
1006                 int32_t type;
1007                 if (offset < 0) {
1008                     offset = -offset;
1009                     type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTNegativeHM : kGMTNegativeHMS;
1010                 } else {
1011                     type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTPositiveHM : kGMTPositiveHMS;
1012                 }
1013                 Formattable param(offset, Formattable::kIsDate);
1014                 FieldPosition fpos(0);
1015                 fGMTFormatters[type]->format(&param, 1, appendTo, fpos, status);
1016             }
1017         }
1018     }
1019 }
1020 
1021 int32_t
parseGMT(const UnicodeString & text,ParsePosition & pos) const1022 SimpleDateFormat::parseGMT(const UnicodeString &text, ParsePosition &pos) const {
1023     if (!isDefaultGMTFormat()) {
1024         int32_t start = pos.getIndex();
1025 
1026         // Quick check
1027         UBool prefixMatch = FALSE;
1028         int32_t prefixLen = fSymbols->fGmtFormat.indexOf((UChar)0x007B /* '{' */);
1029         if (prefixLen > 0 && text.compare(start, prefixLen, fSymbols->fGmtFormat, 0, prefixLen) == 0) {
1030             prefixMatch = TRUE;
1031         }
1032         if (prefixMatch) {
1033             // Prefix matched
1034             UErrorCode status = U_ZERO_ERROR;
1035             ((SimpleDateFormat*)this)->initGMTFormatters(status);
1036             if (U_SUCCESS(status)) {
1037                 Formattable parsed;
1038                 int32_t parsedCount;
1039 
1040                 // Try negative Hms
1041                 fGMTFormatters[kGMTNegativeHMS]->parseObject(text, parsed, pos);
1042                 if (pos.getErrorIndex() == -1 &&
1043                     (pos.getIndex() - start) >= fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx]) {
1044                     parsed.getArray(parsedCount);
1045                     if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
1046                         return (int32_t)(-1 * (int64_t)parsed[0].getDate());
1047                     }
1048                 }
1049 
1050                 // Reset ParsePosition
1051                 pos.setIndex(start);
1052                 pos.setErrorIndex(-1);
1053 
1054                 // Try positive Hms
1055                 fGMTFormatters[kGMTPositiveHMS]->parseObject(text, parsed, pos);
1056                 if (pos.getErrorIndex() == -1 &&
1057                     (pos.getIndex() - start) >= fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx]) {
1058                     parsed.getArray(parsedCount);
1059                     if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
1060                         return (int32_t)((int64_t)parsed[0].getDate());
1061                     }
1062                 }
1063 
1064                 // Reset ParsePosition
1065                 pos.setIndex(start);
1066                 pos.setErrorIndex(-1);
1067 
1068                 // Try negative Hm
1069                 fGMTFormatters[kGMTNegativeHM]->parseObject(text, parsed, pos);
1070                 if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
1071                     parsed.getArray(parsedCount);
1072                     if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
1073                         return (int32_t)(-1 * (int64_t)parsed[0].getDate());
1074                     }
1075                 }
1076 
1077                 // Reset ParsePosition
1078                 pos.setIndex(start);
1079                 pos.setErrorIndex(-1);
1080 
1081                 // Try positive Hm
1082                 fGMTFormatters[kGMTPositiveHM]->parseObject(text, parsed, pos);
1083                 if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
1084                     parsed.getArray(parsedCount);
1085                     if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
1086                         return (int32_t)((int64_t)parsed[0].getDate());
1087                     }
1088                 }
1089 
1090                 // Reset ParsePosition
1091                 pos.setIndex(start);
1092                 pos.setErrorIndex(-1);
1093             }
1094             // fall through to the default GMT parsing method
1095         }
1096     }
1097     return parseGMTDefault(text, pos);
1098 }
1099 
1100 void
formatGMTDefault(NumberFormat * currentNumberFormat,UnicodeString & appendTo,int32_t offset) const1101 SimpleDateFormat::formatGMTDefault(NumberFormat *currentNumberFormat,UnicodeString &appendTo, int32_t offset) const {
1102     if (offset < 0) {
1103         appendTo.append(gGmtMinus, 4);
1104         offset = -offset; // suppress the '-' sign for text display.
1105     }else{
1106         appendTo.append(gGmtPlus, 4);
1107     }
1108 
1109     offset /= U_MILLIS_PER_SECOND; // now in seconds
1110     int32_t sec = offset % 60;
1111     offset /= 60;
1112     int32_t min = offset % 60;
1113     int32_t hour = offset / 60;
1114 
1115 
1116     zeroPaddingNumber(currentNumberFormat,appendTo, hour, 2, 2);
1117     appendTo += (UChar)0x003A /*':'*/;
1118     zeroPaddingNumber(currentNumberFormat,appendTo, min, 2, 2);
1119     if (sec != 0) {
1120         appendTo += (UChar)0x003A /*':'*/;
1121         zeroPaddingNumber(currentNumberFormat,appendTo, sec, 2, 2);
1122     }
1123 }
1124 
1125 int32_t
parseGMTDefault(const UnicodeString & text,ParsePosition & pos) const1126 SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const {
1127     int32_t start = pos.getIndex();
1128     NumberFormat *currentNumberFormat = getNumberFormatByIndex(UDAT_TIMEZONE_RFC_FIELD);
1129 
1130     if (start + kUtLen + 1 >= text.length()) {
1131         pos.setErrorIndex(start);
1132         return 0;
1133     }
1134 
1135     int32_t cur = start;
1136     // "GMT"
1137     if (text.compare(start, kGmtLen, gGmt) == 0) {
1138         cur += kGmtLen;
1139     } else if (text.compare(start, kUtLen, gUt) == 0) {
1140         cur += kUtLen;
1141     } else {
1142         pos.setErrorIndex(start);
1143         return 0;
1144     }
1145     // Sign
1146     UBool negative = FALSE;
1147     if (text.charAt(cur) == (UChar)0x002D /* minus */) {
1148         negative = TRUE;
1149     } else if (text.charAt(cur) != (UChar)0x002B /* plus */) {
1150         pos.setErrorIndex(cur);
1151         return 0;
1152     }
1153     cur++;
1154 
1155     // Numbers
1156     int32_t numLen;
1157     pos.setIndex(cur);
1158 
1159     Formattable number;
1160     parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
1161     numLen = pos.getIndex() - cur;
1162 
1163     if (numLen <= 0) {
1164         pos.setIndex(start);
1165         pos.setErrorIndex(cur);
1166         return 0;
1167     }
1168 
1169     int32_t numVal = number.getLong();
1170 
1171     int32_t hour = 0;
1172     int32_t min = 0;
1173     int32_t sec = 0;
1174 
1175     if (numLen <= 2) {
1176         // H[H][:mm[:ss]]
1177         hour = numVal;
1178         cur += numLen;
1179         if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
1180             cur++;
1181             pos.setIndex(cur);
1182             parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
1183             numLen = pos.getIndex() - cur;
1184             if (numLen == 2) {
1185                 // got minute field
1186                 min = number.getLong();
1187                 cur += numLen;
1188                 if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
1189                     cur++;
1190                     pos.setIndex(cur);
1191                     parseInt(text, number, 2, pos, FALSE,currentNumberFormat);
1192                     numLen = pos.getIndex() - cur;
1193                     if (numLen == 2) {
1194                         // got second field
1195                         sec = number.getLong();
1196                     } else {
1197                         // reset position
1198                         pos.setIndex(cur - 1);
1199                         pos.setErrorIndex(-1);
1200                     }
1201                 }
1202             } else {
1203                 // reset postion
1204                 pos.setIndex(cur - 1);
1205                 pos.setErrorIndex(-1);
1206             }
1207         }
1208     } else if (numLen == 3 || numLen == 4) {
1209         // Hmm or HHmm
1210         hour = numVal / 100;
1211         min = numVal % 100;
1212     } else if (numLen == 5 || numLen == 6) {
1213         // Hmmss or HHmmss
1214         hour = numVal / 10000;
1215         min = (numVal % 10000) / 100;
1216         sec = numVal % 100;
1217     } else {
1218         // HHmmss followed by bogus numbers
1219         pos.setIndex(cur + 6);
1220 
1221         int32_t shift = numLen - 6;
1222         while (shift > 0) {
1223             numVal /= 10;
1224             shift--;
1225         }
1226         hour = numVal / 10000;
1227         min = (numVal % 10000) / 100;
1228         sec = numVal % 100;
1229     }
1230 
1231     int32_t offset = ((hour*60 + min)*60 + sec)*1000;
1232     if (negative) {
1233         offset = -offset;
1234     }
1235     return offset;
1236 }
1237 
1238 UBool
isDefaultGMTFormat() const1239 SimpleDateFormat::isDefaultGMTFormat() const {
1240     // GMT pattern
1241     if (fSymbols->fGmtFormat.length() == 0) {
1242         // No GMT pattern is set
1243         return TRUE;
1244     } else if (fSymbols->fGmtFormat.compare(gDefGmtPat, kGmtPatLen) != 0) {
1245         return FALSE;
1246     }
1247     // Hour patterns
1248     if (fSymbols->fGmtHourFormats == NULL || fSymbols->fGmtHourFormatsCount != DateFormatSymbols::GMT_HOUR_COUNT) {
1249         // No Hour pattern is set
1250         return TRUE;
1251     } else if ((fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS].compare(gDefGmtNegHmsPat, kNegHmsLen) != 0)
1252         || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM].compare(gDefGmtNegHmPat, kNegHmLen) != 0)
1253         || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS].compare(gDefGmtPosHmsPat, kPosHmsLen) != 0)
1254         || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM].compare(gDefGmtPosHmPat, kPosHmLen) != 0)) {
1255         return FALSE;
1256     }
1257     return TRUE;
1258 }
1259 
1260 void
formatRFC822TZ(UnicodeString & appendTo,int32_t offset) const1261 SimpleDateFormat::formatRFC822TZ(UnicodeString &appendTo, int32_t offset) const {
1262     UChar sign = 0x002B /* '+' */;
1263     if (offset < 0) {
1264         offset = -offset;
1265         sign = 0x002D /* '-' */;
1266     }
1267     appendTo.append(sign);
1268 
1269     int32_t offsetH = offset / U_MILLIS_PER_HOUR;
1270     offset = offset % U_MILLIS_PER_HOUR;
1271     int32_t offsetM = offset / U_MILLIS_PER_MINUTE;
1272     offset = offset % U_MILLIS_PER_MINUTE;
1273     int32_t offsetS = offset / U_MILLIS_PER_SECOND;
1274 
1275     int32_t num = 0, denom = 0;
1276     if (offsetS == 0) {
1277         offset = offsetH*100 + offsetM; // HHmm
1278         num = offset % 10000;
1279         denom = 1000;
1280     } else {
1281         offset = offsetH*10000 + offsetM*100 + offsetS; // HHmmss
1282         num = offset % 1000000;
1283         denom = 100000;
1284     }
1285     while (denom >= 1) {
1286         UChar digit = (UChar)0x0030 + (num / denom);
1287         appendTo.append(digit);
1288         num = num % denom;
1289         denom /= 10;
1290     }
1291 }
1292 
1293 void
initGMTFormatters(UErrorCode & status)1294 SimpleDateFormat::initGMTFormatters(UErrorCode &status) {
1295     if (U_FAILURE(status)) {
1296         return;
1297     }
1298     umtx_lock(&LOCK);
1299     if (fGMTFormatters == NULL) {
1300         fGMTFormatters = (MessageFormat**)uprv_malloc(kNumGMTFormatters * sizeof(MessageFormat*));
1301         if (fGMTFormatters) {
1302             for (int32_t i = 0; i < kNumGMTFormatters; i++) {
1303                 const UnicodeString *hourPattern = NULL; //initialized it to avoid warning
1304                 switch (i) {
1305                     case kGMTNegativeHMS:
1306                         hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS]);
1307                         break;
1308                     case kGMTNegativeHM:
1309                         hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM]);
1310                         break;
1311                     case kGMTPositiveHMS:
1312                         hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS]);
1313                         break;
1314                     case kGMTPositiveHM:
1315                         hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM]);
1316                         break;
1317                 }
1318                 fGMTFormatters[i] = new MessageFormat(fSymbols->fGmtFormat, status);
1319                 GregorianCalendar *gcal = new GregorianCalendar(TimeZone::createTimeZone(UnicodeString(gEtcUTC)), status);
1320                 if (U_FAILURE(status)) {
1321                     break;
1322                 }
1323                 SimpleDateFormat *sdf = (SimpleDateFormat*)this->clone();
1324                 sdf->adoptCalendar(gcal);
1325                 sdf->applyPattern(*hourPattern);
1326 
1327                 // This prevents an hours format pattern like "-HH:mm:ss" from matching
1328                 // in a string like "GMT-07:00 10:08:11 PM"
1329                 sdf->setLenient(FALSE);
1330 
1331                 fGMTFormatters[i]->adoptFormat(0, sdf);
1332 
1333                 // For parsing, we only allow Hms patterns to be equal or longer
1334                 // than its length with fixed minutes/seconds digits.
1335                 // See #6880
1336                 if (i == kGMTNegativeHMS || i == kGMTPositiveHMS) {
1337                     UnicodeString tmp;
1338                     Formattable tmpParam(60*60*1000, Formattable::kIsDate);
1339                     FieldPosition fpos(0);
1340                     fGMTFormatters[i]->format(&tmpParam, 1, tmp, fpos, status);
1341                     if (U_FAILURE(status)) {
1342                         break;
1343                     }
1344                     if (i == kGMTNegativeHMS) {
1345                         fGMTFormatHmsMinLen[kGMTNegativeHMSMinLenIdx] = tmp.length();
1346                     } else {
1347                         fGMTFormatHmsMinLen[kGMTPositiveHMSMinLenIdx] = tmp.length();
1348                     }
1349                 }
1350             }
1351         } else {
1352             status = U_MEMORY_ALLOCATION_ERROR;
1353         }
1354     }
1355     umtx_unlock(&LOCK);
1356 }
1357 
1358 void
initNumberFormatters(const Locale & locale,UErrorCode & status)1359 SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
1360     if (U_FAILURE(status)) {
1361         return;
1362     }
1363     if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
1364         return;
1365     }
1366     umtx_lock(&LOCK);
1367     if (fNumberFormatters == NULL) {
1368         fNumberFormatters = (NumberFormat**)uprv_malloc(UDAT_FIELD_COUNT * sizeof(NumberFormat*));
1369         if (fNumberFormatters) {
1370             for (int32_t i = 0; i < UDAT_FIELD_COUNT; i++) {
1371                 fNumberFormatters[i] = fNumberFormat;
1372             }
1373         } else {
1374             status = U_MEMORY_ALLOCATION_ERROR;
1375         }
1376     }
1377     umtx_unlock(&LOCK);
1378 
1379     processOverrideString(locale,fDateOverride,kOvrStrDate,status);
1380     processOverrideString(locale,fTimeOverride,kOvrStrTime,status);
1381 
1382 }
1383 
1384 void
processOverrideString(const Locale & locale,const UnicodeString & str,int8_t type,UErrorCode & status)1385 SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) {
1386     if (str.isBogus()) {
1387         return;
1388     }
1389     int32_t start = 0;
1390     int32_t len;
1391     UnicodeString nsName;
1392     UnicodeString ovrField;
1393     UBool moreToProcess = TRUE;
1394 
1395     while (moreToProcess) {
1396         int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
1397         if (delimiterPosition == -1) {
1398             moreToProcess = FALSE;
1399             len = str.length() - start;
1400         } else {
1401             len = delimiterPosition - start;
1402         }
1403         UnicodeString currentString(str,start,len);
1404         int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0);
1405         if (equalSignPosition == -1) { // Simple override string such as "hebrew"
1406             nsName.setTo(currentString);
1407             ovrField.setToBogus();
1408         } else { // Field specific override string such as "y=hebrew"
1409             nsName.setTo(currentString,equalSignPosition+1);
1410             ovrField.setTo(currentString,0,1); // We just need the first character.
1411         }
1412 
1413         int32_t nsNameHash = nsName.hashCode();
1414         // See if the numbering system is in the override list, if not, then add it.
1415         NSOverride *cur = fOverrideList;
1416         NumberFormat *nf = NULL;
1417         UBool found = FALSE;
1418         while ( cur && !found ) {
1419             if ( cur->hash == nsNameHash ) {
1420                 nf = cur->nf;
1421                 found = TRUE;
1422             }
1423             cur = cur->next;
1424         }
1425 
1426         if (!found) {
1427            cur = (NSOverride *)uprv_malloc(sizeof(NSOverride));
1428            if (cur) {
1429                char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
1430                uprv_strcpy(kw,"numbers=");
1431                nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
1432 
1433                Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
1434                nf = NumberFormat::createInstance(ovrLoc,status);
1435 
1436                // no matter what the locale's default number format looked like, we want
1437                // to modify it so that it doesn't use thousands separators, doesn't always
1438                // show the decimal point, and recognizes integers only when parsing
1439 
1440                if (U_SUCCESS(status)) {
1441                    nf->setGroupingUsed(FALSE);
1442                    DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(nf);
1443                    if (decfmt != NULL) {
1444                        decfmt->setDecimalSeparatorAlwaysShown(FALSE);
1445                    }
1446                    nf->setParseIntegerOnly(TRUE);
1447                    nf->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
1448 
1449                    cur->nf = nf;
1450                    cur->hash = nsNameHash;
1451                    cur->next = fOverrideList;
1452                    fOverrideList = cur;
1453                }
1454                else {
1455                    // clean up before returning
1456                    if (cur != NULL) {
1457                        uprv_free(cur);
1458                    }
1459                   return;
1460                }
1461 
1462            } else {
1463                status = U_MEMORY_ALLOCATION_ERROR;
1464                return;
1465            }
1466         }
1467 
1468         // Now that we have an appropriate number formatter, fill in the appropriate spaces in the
1469         // number formatters table.
1470 
1471         if (ovrField.isBogus()) {
1472             switch (type) {
1473                 case kOvrStrDate:
1474                 case kOvrStrBoth: {
1475                     for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
1476                         fNumberFormatters[kDateFields[i]] = nf;
1477                     }
1478                     if (type==kOvrStrDate) {
1479                         break;
1480                     }
1481                 }
1482                 case kOvrStrTime : {
1483                     for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
1484                         fNumberFormatters[kTimeFields[i]] = nf;
1485                     }
1486                     break;
1487                 }
1488             }
1489         } else {
1490            UChar ch = ovrField.charAt(0);
1491            UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
1492            UDateFormatField patternCharIndex;
1493 
1494            // if the pattern character is unrecognized, signal an error and bail out
1495            if (patternCharPtr == NULL) {
1496                status = U_INVALID_FORMAT_ERROR;
1497                return;
1498            }
1499            patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
1500 
1501            // Set the number formatter in the table
1502            fNumberFormatters[patternCharIndex] = nf;
1503         }
1504 
1505         start = delimiterPosition + 1;
1506     }
1507 }
1508 //---------------------------------------------------------------------
1509 void
subFormat(UnicodeString & appendTo,UChar ch,int32_t count,FieldPositionHandler & handler,Calendar & cal,UErrorCode & status) const1510 SimpleDateFormat::subFormat(UnicodeString &appendTo,
1511                             UChar ch,
1512                             int32_t count,
1513                             FieldPositionHandler& handler,
1514                             Calendar& cal,
1515                             UErrorCode& status) const
1516 {
1517     if (U_FAILURE(status)) {
1518         return;
1519     }
1520 
1521     // this function gets called by format() to produce the appropriate substitution
1522     // text for an individual pattern symbol (e.g., "HH" or "yyyy")
1523 
1524     UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
1525     UDateFormatField patternCharIndex;
1526     const int32_t maxIntCount = 10;
1527     int32_t beginOffset = appendTo.length();
1528     NumberFormat *currentNumberFormat;
1529 
1530     UBool isHebrewCalendar = !strcmp(cal.getType(),"hebrew");
1531 
1532     // if the pattern character is unrecognized, signal an error and dump out
1533     if (patternCharPtr == NULL)
1534     {
1535         status = U_INVALID_FORMAT_ERROR;
1536         return;
1537     }
1538 
1539     patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
1540     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
1541     int32_t value = cal.get(field, status);
1542     if (U_FAILURE(status)) {
1543         return;
1544     }
1545 
1546     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
1547     switch (patternCharIndex) {
1548 
1549     // for any "G" symbol, write out the appropriate era string
1550     // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name
1551     case UDAT_ERA_FIELD:
1552         if (count == 5)
1553            _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
1554         else if (count == 4)
1555            _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
1556         else
1557            _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
1558         break;
1559 
1560     // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
1561     // NEW: UTS#35:
1562 //Year         y     yy     yyy     yyyy     yyyyy
1563 //AD 1         1     01     001     0001     00001
1564 //AD 12       12     12     012     0012     00012
1565 //AD 123     123     23     123     0123     00123
1566 //AD 1234   1234     34    1234     1234     01234
1567 //AD 12345 12345     45   12345    12345     12345
1568     case UDAT_YEAR_FIELD:
1569     case UDAT_YEAR_WOY_FIELD:
1570         if(count == 2)
1571             zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);
1572         else
1573             zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);
1574         break;
1575 
1576     // for "MMMM", write out the whole month name, for "MMM", write out the month
1577     // abbreviation, for "M" or "MM", write out the month as a number with the
1578     // appropriate number of digits
1579     // for "MMMMM", use the narrow form
1580     case UDAT_MONTH_FIELD:
1581         if ( isHebrewCalendar ) {
1582            HebrewCalendar *hc = (HebrewCalendar*)&cal;
1583            if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
1584                value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
1585            if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
1586                value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
1587         }
1588         if (count == 5)
1589             _appendSymbol(appendTo, value, fSymbols->fNarrowMonths,
1590                           fSymbols->fNarrowMonthsCount);
1591         else if (count == 4)
1592             _appendSymbol(appendTo, value, fSymbols->fMonths,
1593                           fSymbols->fMonthsCount);
1594         else if (count == 3)
1595             _appendSymbol(appendTo, value, fSymbols->fShortMonths,
1596                           fSymbols->fShortMonthsCount);
1597         else
1598             zeroPaddingNumber(currentNumberFormat,appendTo, value + 1, count, maxIntCount);
1599         break;
1600 
1601     // for "LLLL", write out the whole month name, for "LLL", write out the month
1602     // abbreviation, for "L" or "LL", write out the month as a number with the
1603     // appropriate number of digits
1604     // for "LLLLL", use the narrow form
1605     case UDAT_STANDALONE_MONTH_FIELD:
1606         if (count == 5)
1607             _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowMonths,
1608                           fSymbols->fStandaloneNarrowMonthsCount);
1609         else if (count == 4)
1610             _appendSymbol(appendTo, value, fSymbols->fStandaloneMonths,
1611                           fSymbols->fStandaloneMonthsCount);
1612         else if (count == 3)
1613             _appendSymbol(appendTo, value, fSymbols->fStandaloneShortMonths,
1614                           fSymbols->fStandaloneShortMonthsCount);
1615         else
1616             zeroPaddingNumber(currentNumberFormat,appendTo, value + 1, count, maxIntCount);
1617         break;
1618 
1619     // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
1620     case UDAT_HOUR_OF_DAY1_FIELD:
1621         if (value == 0)
1622             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
1623         else
1624             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1625         break;
1626 
1627     case UDAT_FRACTIONAL_SECOND_FIELD:
1628         // Fractional seconds left-justify
1629         {
1630             currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
1631             currentNumberFormat->setMaximumIntegerDigits(maxIntCount);
1632             if (count == 1) {
1633                 value /= 100;
1634             } else if (count == 2) {
1635                 value /= 10;
1636             }
1637             FieldPosition p(0);
1638             currentNumberFormat->format(value, appendTo, p);
1639             if (count > 3) {
1640                 currentNumberFormat->setMinimumIntegerDigits(count - 3);
1641                 currentNumberFormat->format((int32_t)0, appendTo, p);
1642             }
1643         }
1644         break;
1645 
1646     // for "ee" or "e", use local numeric day-of-the-week
1647     // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name
1648     // for "EEEE" or "eeee", write out the wide day-of-the-week name
1649     // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name
1650     case UDAT_DOW_LOCAL_FIELD:
1651         if ( count < 3 ) {
1652             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1653             break;
1654         }
1655         // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week,
1656         // we want standard day-of-week, so first fix value to work for EEEEE-EEE.
1657         value = cal.get(UCAL_DAY_OF_WEEK, status);
1658         if (U_FAILURE(status)) {
1659             return;
1660         }
1661         // fall through, do not break here
1662     case UDAT_DAY_OF_WEEK_FIELD:
1663         if (count == 5)
1664             _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
1665                           fSymbols->fNarrowWeekdaysCount);
1666         else if (count == 4)
1667             _appendSymbol(appendTo, value, fSymbols->fWeekdays,
1668                           fSymbols->fWeekdaysCount);
1669         else
1670             _appendSymbol(appendTo, value, fSymbols->fShortWeekdays,
1671                           fSymbols->fShortWeekdaysCount);
1672         break;
1673 
1674     // for "ccc", write out the abbreviated day-of-the-week name
1675     // for "cccc", write out the wide day-of-the-week name
1676     // for "ccccc", use the narrow day-of-the-week name
1677     case UDAT_STANDALONE_DAY_FIELD:
1678         if ( count < 3 ) {
1679             zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);
1680             break;
1681         }
1682         // fall through to alpha DOW handling, but for that we don't want local day-of-week,
1683         // we want standard day-of-week, so first fix value.
1684         value = cal.get(UCAL_DAY_OF_WEEK, status);
1685         if (U_FAILURE(status)) {
1686             return;
1687         }
1688         if (count == 5)
1689             _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
1690                           fSymbols->fStandaloneNarrowWeekdaysCount);
1691         else if (count == 4)
1692             _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
1693                           fSymbols->fStandaloneWeekdaysCount);
1694         else // count == 3
1695             _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
1696                           fSymbols->fStandaloneShortWeekdaysCount);
1697         break;
1698 
1699     // for and "a" symbol, write out the whole AM/PM string
1700     case UDAT_AM_PM_FIELD:
1701         _appendSymbol(appendTo, value, fSymbols->fAmPms,
1702                       fSymbols->fAmPmsCount);
1703         break;
1704 
1705     // for "h" and "hh", write out the hour, adjusting noon and midnight to show up
1706     // as "12"
1707     case UDAT_HOUR1_FIELD:
1708         if (value == 0)
1709             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
1710         else
1711             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1712         break;
1713 
1714     // for the "z" symbols, we have to check our time zone data first.  If we have a
1715     // localized name for the time zone, then "zzzz" / "zzz" indicate whether
1716     // daylight time is in effect (long/short) and "zz" / "z" do not (long/short).
1717     // If we don't have a localized time zone name,
1718     // then the time zone shows up as "GMT+hh:mm" or "GMT-hh:mm" (where "hh:mm" is the
1719     // offset from GMT) regardless of how many z's were in the pattern symbol
1720     case UDAT_TIMEZONE_FIELD:
1721     case UDAT_TIMEZONE_GENERIC_FIELD:
1722     case UDAT_TIMEZONE_SPECIAL_FIELD:
1723         {
1724             UnicodeString zoneString;
1725             const TimeZone& tz = cal.getTimeZone();
1726             UDate date = cal.getTime(status);
1727             if (U_SUCCESS(status)) {
1728                 if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
1729                     if (count < 4) {
1730                         // "z", "zz", "zzz"
1731                         tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED, tz, date, zoneString);
1732                     } else {
1733                         // "zzzz"
1734                         tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
1735                     }
1736                 } else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
1737                     if (count == 1) {
1738                         // "v"
1739                         tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
1740                     } else if (count == 4) {
1741                         // "vvvv"
1742                         tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
1743                     }
1744                 } else { // patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD
1745                     if (count == 1) {
1746                         // "V"
1747                         tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
1748                     } else if (count == 4) {
1749                         // "VVVV"
1750                         tzFormat()->format(UTZFMT_STYLE_LOCATION, tz, date, zoneString);
1751                     }
1752                 }
1753             }
1754             if (zoneString.isEmpty()) {
1755                 appendGMT(currentNumberFormat,appendTo, cal, status);
1756             } else {
1757                 appendTo += zoneString;
1758             }
1759         }
1760         break;
1761 
1762     case UDAT_TIMEZONE_RFC_FIELD: // 'Z' - TIMEZONE_RFC
1763         if (count < 4) {
1764             // RFC822 format, must use ASCII digits
1765             value = (cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status));
1766             formatRFC822TZ(appendTo, value);
1767         } else {
1768             // long form, localized GMT pattern
1769             appendGMT(currentNumberFormat,appendTo, cal, status);
1770         }
1771         break;
1772 
1773     case UDAT_QUARTER_FIELD:
1774         if (count >= 4)
1775             _appendSymbol(appendTo, value/3, fSymbols->fQuarters,
1776                           fSymbols->fQuartersCount);
1777         else if (count == 3)
1778             _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,
1779                           fSymbols->fShortQuartersCount);
1780         else
1781             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
1782         break;
1783 
1784     case UDAT_STANDALONE_QUARTER_FIELD:
1785         if (count >= 4)
1786             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
1787                           fSymbols->fStandaloneQuartersCount);
1788         else if (count == 3)
1789             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,
1790                           fSymbols->fStandaloneShortQuartersCount);
1791         else
1792             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
1793         break;
1794 
1795 
1796     // all of the other pattern symbols can be formatted as simple numbers with
1797     // appropriate zero padding
1798     default:
1799         zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1800         break;
1801     }
1802 
1803     handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length());
1804 }
1805 
1806 //----------------------------------------------------------------------
1807 
1808 NumberFormat *
getNumberFormatByIndex(UDateFormatField index) const1809 SimpleDateFormat::getNumberFormatByIndex(UDateFormatField index) const {
1810     if (fNumberFormatters != NULL) {
1811         return fNumberFormatters[index];
1812     } else {
1813         return fNumberFormat;
1814     }
1815 }
1816 
1817 //----------------------------------------------------------------------
1818 void
zeroPaddingNumber(NumberFormat * currentNumberFormat,UnicodeString & appendTo,int32_t value,int32_t minDigits,int32_t maxDigits) const1819 SimpleDateFormat::zeroPaddingNumber(NumberFormat *currentNumberFormat,UnicodeString &appendTo,
1820                                     int32_t value, int32_t minDigits, int32_t maxDigits) const
1821 {
1822     if (currentNumberFormat!=NULL) {
1823         FieldPosition pos(0);
1824 
1825         currentNumberFormat->setMinimumIntegerDigits(minDigits);
1826         currentNumberFormat->setMaximumIntegerDigits(maxDigits);
1827         currentNumberFormat->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
1828     }
1829 }
1830 
1831 //----------------------------------------------------------------------
1832 
1833 /**
1834  * Format characters that indicate numeric fields.  The character
1835  * at index 0 is treated specially.
1836  */
1837 static const UChar NUMERIC_FORMAT_CHARS[] = {0x4D, 0x59, 0x79, 0x75, 0x64, 0x65, 0x68, 0x48, 0x6D, 0x73, 0x53, 0x44, 0x46, 0x77, 0x57, 0x6B, 0x4B, 0x00}; /* "MYyudehHmsSDFwWkK" */
1838 
1839 /**
1840  * Return true if the given format character, occuring count
1841  * times, represents a numeric field.
1842  */
isNumeric(UChar formatChar,int32_t count)1843 UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
1844     UnicodeString s(NUMERIC_FORMAT_CHARS);
1845     int32_t i = s.indexOf(formatChar);
1846     return (i > 0 || (i == 0 && count < 3));
1847 }
1848 
1849 void
parse(const UnicodeString & text,Calendar & cal,ParsePosition & parsePos) const1850 SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const
1851 {
1852     UErrorCode status = U_ZERO_ERROR;
1853     int32_t pos = parsePos.getIndex();
1854     int32_t start = pos;
1855 
1856     UBool ambiguousYear[] = { FALSE };
1857     int32_t saveHebrewMonth = -1;
1858     int32_t count = 0;
1859 
1860     UBool lenient = isLenient();
1861 
1862     // hack, reset tztype, cast away const
1863     ((SimpleDateFormat*)this)->tztype = TZTYPE_UNK;
1864 
1865     // For parsing abutting numeric fields. 'abutPat' is the
1866     // offset into 'pattern' of the first of 2 or more abutting
1867     // numeric fields.  'abutStart' is the offset into 'text'
1868     // where parsing the fields begins. 'abutPass' starts off as 0
1869     // and increments each time we try to parse the fields.
1870     int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields
1871     int32_t abutStart = 0;
1872     int32_t abutPass = 0;
1873     UBool inQuote = FALSE;
1874 
1875     const UnicodeString numericFormatChars(NUMERIC_FORMAT_CHARS);
1876 
1877     TimeZone *backupTZ = NULL;
1878     Calendar *workCal = &cal;
1879     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
1880         // Different calendar type
1881         // We use the time/zone from the input calendar, but
1882         // do not use the input calendar for field calculation.
1883         fCalendar->setTime(cal.getTime(status),status);
1884         if (U_FAILURE(status)) {
1885             goto ExitParse;
1886         }
1887         backupTZ = fCalendar->getTimeZone().clone();
1888         fCalendar->setTimeZone(cal.getTimeZone());
1889         workCal = fCalendar;
1890     }
1891 
1892     for (int32_t i=0; i<fPattern.length(); ++i) {
1893         UChar ch = fPattern.charAt(i);
1894 
1895         // Handle alphabetic field characters.
1896         if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // [A-Za-z]
1897             int32_t fieldPat = i;
1898 
1899             // Count the length of this field specifier
1900             count = 1;
1901             while ((i+1)<fPattern.length() &&
1902                    fPattern.charAt(i+1) == ch) {
1903                 ++count;
1904                 ++i;
1905             }
1906 
1907             if (isNumeric(ch, count)) {
1908                 if (abutPat < 0) {
1909                     // Determine if there is an abutting numeric field.  For
1910                     // most fields we can just look at the next characters,
1911                     // but the 'm' field is either numeric or text,
1912                     // depending on the count, so we have to look ahead for
1913                     // that field.
1914                     if ((i+1)<fPattern.length()) {
1915                         UBool abutting;
1916                         UChar nextCh = fPattern.charAt(i+1);
1917                         int32_t k = numericFormatChars.indexOf(nextCh);
1918                         if (k == 0) {
1919                             int32_t j = i+2;
1920                             while (j<fPattern.length() &&
1921                                    fPattern.charAt(j) == nextCh) {
1922                                 ++j;
1923                             }
1924                             abutting = (j-i) < 4; // nextCount < 3
1925                         } else {
1926                             abutting = k > 0;
1927                         }
1928 
1929                         // Record the start of a set of abutting numeric
1930                         // fields.
1931                         if (abutting) {
1932                             abutPat = fieldPat;
1933                             abutStart = pos;
1934                             abutPass = 0;
1935                         }
1936                     }
1937                 }
1938             } else {
1939                 abutPat = -1; // End of any abutting fields
1940             }
1941 
1942             // Handle fields within a run of abutting numeric fields.  Take
1943             // the pattern "HHmmss" as an example. We will try to parse
1944             // 2/2/2 characters of the input text, then if that fails,
1945             // 1/2/2.  We only adjust the width of the leftmost field; the
1946             // others remain fixed.  This allows "123456" => 12:34:56, but
1947             // "12345" => 1:23:45.  Likewise, for the pattern "yyyyMMdd" we
1948             // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2.
1949             if (abutPat >= 0) {
1950                 // If we are at the start of a run of abutting fields, then
1951                 // shorten this field in each pass.  If we can't shorten
1952                 // this field any more, then the parse of this set of
1953                 // abutting numeric fields has failed.
1954                 if (fieldPat == abutPat) {
1955                     count -= abutPass++;
1956                     if (count == 0) {
1957                         status = U_PARSE_ERROR;
1958                         goto ExitParse;
1959                     }
1960                 }
1961 
1962                 pos = subParse(text, pos, ch, count,
1963                                TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i);
1964 
1965                 // If the parse fails anywhere in the run, back up to the
1966                 // start of the run and retry.
1967                 if (pos < 0) {
1968                     i = abutPat - 1;
1969                     pos = abutStart;
1970                     continue;
1971                 }
1972             }
1973 
1974             // Handle non-numeric fields and non-abutting numeric
1975             // fields.
1976             else {
1977                 int32_t s = subParse(text, pos, ch, count,
1978                                FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i);
1979 
1980                 if (s == -pos-1) {
1981                     // era not present, in special cases allow this to continue
1982                     s++;
1983 
1984                     if (i+1 < fPattern.length()) {
1985                         // move to next pattern character
1986                         UChar ch = fPattern.charAt(i+1);
1987 
1988                         // check for whitespace
1989                         if (PatternProps::isWhiteSpace(ch)) {
1990                             i++;
1991                             // Advance over run in pattern
1992                             while ((i+1)<fPattern.length() &&
1993                                    PatternProps::isWhiteSpace(fPattern.charAt(i+1))) {
1994                                 ++i;
1995                             }
1996                         }
1997                     }
1998                 }
1999                 else if (s <= 0) {
2000                     status = U_PARSE_ERROR;
2001                     goto ExitParse;
2002                 }
2003                 pos = s;
2004             }
2005         }
2006 
2007         // Handle literal pattern characters.  These are any
2008         // quoted characters and non-alphabetic unquoted
2009         // characters.
2010         else {
2011 
2012             abutPat = -1; // End of any abutting fields
2013 
2014             if (! matchLiterals(fPattern, i, text, pos, lenient)) {
2015                 status = U_PARSE_ERROR;
2016                 goto ExitParse;
2017             }
2018         }
2019     }
2020 
2021     // At this point the fields of Calendar have been set.  Calendar
2022     // will fill in default values for missing fields when the time
2023     // is computed.
2024 
2025     parsePos.setIndex(pos);
2026 
2027     // This part is a problem:  When we call parsedDate.after, we compute the time.
2028     // Take the date April 3 2004 at 2:30 am.  When this is first set up, the year
2029     // will be wrong if we're parsing a 2-digit year pattern.  It will be 1904.
2030     // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day.  2:30 am
2031     // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am
2032     // on that day.  It is therefore parsed out to fields as 3:30 am.  Then we
2033     // add 100 years, and get April 3 2004 at 3:30 am.  Note that April 3 2004 is
2034     // a Saturday, so it can have a 2:30 am -- and it should. [LIU]
2035     /*
2036         UDate parsedDate = calendar.getTime();
2037         if( ambiguousYear[0] && !parsedDate.after(fDefaultCenturyStart) ) {
2038             calendar.add(Calendar.YEAR, 100);
2039             parsedDate = calendar.getTime();
2040         }
2041     */
2042     // Because of the above condition, save off the fields in case we need to readjust.
2043     // The procedure we use here is not particularly efficient, but there is no other
2044     // way to do this given the API restrictions present in Calendar.  We minimize
2045     // inefficiency by only performing this computation when it might apply, that is,
2046     // when the two-digit year is equal to the start year, and thus might fall at the
2047     // front or the back of the default century.  This only works because we adjust
2048     // the year correctly to start with in other cases -- see subParse().
2049     if (ambiguousYear[0] || tztype != TZTYPE_UNK) // If this is true then the two-digit year == the default start year
2050     {
2051         // We need a copy of the fields, and we need to avoid triggering a call to
2052         // complete(), which will recalculate the fields.  Since we can't access
2053         // the fields[] array in Calendar, we clone the entire object.  This will
2054         // stop working if Calendar.clone() is ever rewritten to call complete().
2055         Calendar *copy;
2056         if (ambiguousYear[0]) {
2057             copy = cal.clone();
2058             // Check for failed cloning.
2059             if (copy == NULL) {
2060                 status = U_MEMORY_ALLOCATION_ERROR;
2061                 goto ExitParse;
2062             }
2063             UDate parsedDate = copy->getTime(status);
2064             // {sfb} check internalGetDefaultCenturyStart
2065             if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) {
2066                 // We can't use add here because that does a complete() first.
2067                 cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100);
2068             }
2069             delete copy;
2070         }
2071 
2072         if (tztype != TZTYPE_UNK) {
2073             copy = cal.clone();
2074             // Check for failed cloning.
2075             if (copy == NULL) {
2076                 status = U_MEMORY_ALLOCATION_ERROR;
2077                 goto ExitParse;
2078             }
2079             const TimeZone & tz = cal.getTimeZone();
2080             BasicTimeZone *btz = NULL;
2081 
2082             if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL
2083                 || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL
2084                 || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL
2085                 || dynamic_cast<const VTimeZone *>(&tz) != NULL) {
2086                 btz = (BasicTimeZone*)&tz;
2087             }
2088 
2089             // Get local millis
2090             copy->set(UCAL_ZONE_OFFSET, 0);
2091             copy->set(UCAL_DST_OFFSET, 0);
2092             UDate localMillis = copy->getTime(status);
2093 
2094             // Make sure parsed time zone type (Standard or Daylight)
2095             // matches the rule used by the parsed time zone.
2096             int32_t raw, dst;
2097             if (btz != NULL) {
2098                 if (tztype == TZTYPE_STD) {
2099                     btz->getOffsetFromLocal(localMillis,
2100                         BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status);
2101                 } else {
2102                     btz->getOffsetFromLocal(localMillis,
2103                         BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, raw, dst, status);
2104                 }
2105             } else {
2106                 // No good way to resolve ambiguous time at transition,
2107                 // but following code work in most case.
2108                 tz.getOffset(localMillis, TRUE, raw, dst, status);
2109             }
2110 
2111             // Now, compare the results with parsed type, either standard or daylight saving time
2112             int32_t resolvedSavings = dst;
2113             if (tztype == TZTYPE_STD) {
2114                 if (dst != 0) {
2115                     // Override DST_OFFSET = 0 in the result calendar
2116                     resolvedSavings = 0;
2117                 }
2118             } else { // tztype == TZTYPE_DST
2119                 if (dst == 0) {
2120                     if (btz != NULL) {
2121                         UDate time = localMillis + raw;
2122                         // We use the nearest daylight saving time rule.
2123                         TimeZoneTransition beforeTrs, afterTrs;
2124                         UDate beforeT = time, afterT = time;
2125                         int32_t beforeSav = 0, afterSav = 0;
2126                         UBool beforeTrsAvail, afterTrsAvail;
2127 
2128                         // Search for DST rule before or on the time
2129                         while (TRUE) {
2130                             beforeTrsAvail = btz->getPreviousTransition(beforeT, TRUE, beforeTrs);
2131                             if (!beforeTrsAvail) {
2132                                 break;
2133                             }
2134                             beforeT = beforeTrs.getTime() - 1;
2135                             beforeSav = beforeTrs.getFrom()->getDSTSavings();
2136                             if (beforeSav != 0) {
2137                                 break;
2138                             }
2139                         }
2140 
2141                         // Search for DST rule after the time
2142                         while (TRUE) {
2143                             afterTrsAvail = btz->getNextTransition(afterT, FALSE, afterTrs);
2144                             if (!afterTrsAvail) {
2145                                 break;
2146                             }
2147                             afterT = afterTrs.getTime();
2148                             afterSav = afterTrs.getTo()->getDSTSavings();
2149                             if (afterSav != 0) {
2150                                 break;
2151                             }
2152                         }
2153 
2154                         if (beforeTrsAvail && afterTrsAvail) {
2155                             if (time - beforeT > afterT - time) {
2156                                 resolvedSavings = afterSav;
2157                             } else {
2158                                 resolvedSavings = beforeSav;
2159                             }
2160                         } else if (beforeTrsAvail && beforeSav != 0) {
2161                             resolvedSavings = beforeSav;
2162                         } else if (afterTrsAvail && afterSav != 0) {
2163                             resolvedSavings = afterSav;
2164                         } else {
2165                             resolvedSavings = btz->getDSTSavings();
2166                         }
2167                     } else {
2168                         resolvedSavings = tz.getDSTSavings();
2169                     }
2170                     if (resolvedSavings == 0) {
2171                         // final fallback
2172                         resolvedSavings = U_MILLIS_PER_HOUR;
2173                     }
2174                 }
2175             }
2176             cal.set(UCAL_ZONE_OFFSET, raw);
2177             cal.set(UCAL_DST_OFFSET, resolvedSavings);
2178             delete copy;
2179         }
2180     }
2181 ExitParse:
2182     // Set the parsed result if local calendar is used
2183     // instead of the input calendar
2184     if (U_SUCCESS(status) && workCal != &cal) {
2185         cal.setTimeZone(workCal->getTimeZone());
2186         cal.setTime(workCal->getTime(status), status);
2187     }
2188 
2189     // Restore the original time zone if required
2190     if (backupTZ != NULL) {
2191         fCalendar->adoptTimeZone(backupTZ);
2192     }
2193 
2194     // If any Calendar calls failed, we pretend that we
2195     // couldn't parse the string, when in reality this isn't quite accurate--
2196     // we did parse it; the Calendar calls just failed.
2197     if (U_FAILURE(status)) {
2198         parsePos.setErrorIndex(pos);
2199         parsePos.setIndex(start);
2200     }
2201 }
2202 
2203 UDate
parse(const UnicodeString & text,ParsePosition & pos) const2204 SimpleDateFormat::parse( const UnicodeString& text,
2205                          ParsePosition& pos) const {
2206     // redefined here because the other parse() function hides this function's
2207     // cunterpart on DateFormat
2208     return DateFormat::parse(text, pos);
2209 }
2210 
2211 UDate
parse(const UnicodeString & text,UErrorCode & status) const2212 SimpleDateFormat::parse(const UnicodeString& text, UErrorCode& status) const
2213 {
2214     // redefined here because the other parse() function hides this function's
2215     // counterpart on DateFormat
2216     return DateFormat::parse(text, status);
2217 }
2218 //----------------------------------------------------------------------
2219 
matchQuarterString(const UnicodeString & text,int32_t start,UCalendarDateFields field,const UnicodeString * data,int32_t dataCount,Calendar & cal) const2220 int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
2221                               int32_t start,
2222                               UCalendarDateFields field,
2223                               const UnicodeString* data,
2224                               int32_t dataCount,
2225                               Calendar& cal) const
2226 {
2227     int32_t i = 0;
2228     int32_t count = dataCount;
2229 
2230     // There may be multiple strings in the data[] array which begin with
2231     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
2232     // We keep track of the longest match, and return that.  Note that this
2233     // unfortunately requires us to test all array elements.
2234     int32_t bestMatchLength = 0, bestMatch = -1;
2235 
2236     // {sfb} kludge to support case-insensitive comparison
2237     // {markus 2002oct11} do not just use caseCompareBetween because we do not know
2238     // the length of the match after case folding
2239     // {alan 20040607} don't case change the whole string, since the length
2240     // can change
2241     // TODO we need a case-insensitive startsWith function
2242     UnicodeString lcase, lcaseText;
2243     text.extract(start, INT32_MAX, lcaseText);
2244     lcaseText.foldCase();
2245 
2246     for (; i < count; ++i)
2247     {
2248         // Always compare if we have no match yet; otherwise only compare
2249         // against potentially better matches (longer strings).
2250 
2251         lcase.fastCopyFrom(data[i]).foldCase();
2252         int32_t length = lcase.length();
2253 
2254         if (length > bestMatchLength &&
2255             lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
2256         {
2257             bestMatch = i;
2258             bestMatchLength = length;
2259         }
2260     }
2261     if (bestMatch >= 0)
2262     {
2263         cal.set(field, bestMatch * 3);
2264 
2265         // Once we have a match, we have to determine the length of the
2266         // original source string.  This will usually be == the length of
2267         // the case folded string, but it may differ (e.g. sharp s).
2268         lcase.fastCopyFrom(data[bestMatch]).foldCase();
2269 
2270         // Most of the time, the length will be the same as the length
2271         // of the string from the locale data.  Sometimes it will be
2272         // different, in which case we will have to figure it out by
2273         // adding a character at a time, until we have a match.  We do
2274         // this all in one loop, where we try 'len' first (at index
2275         // i==0).
2276         int32_t len = data[bestMatch].length(); // 99+% of the time
2277         int32_t n = text.length() - start;
2278         for (i=0; i<=n; ++i) {
2279             int32_t j=i;
2280             if (i == 0) {
2281                 j = len;
2282             } else if (i == len) {
2283                 continue; // already tried this when i was 0
2284             }
2285             text.extract(start, j, lcaseText);
2286             lcaseText.foldCase();
2287             if (lcase == lcaseText) {
2288                 return start + j;
2289             }
2290         }
2291     }
2292 
2293     return -start;
2294 }
2295 
2296 //----------------------------------------------------------------------
matchLiterals(const UnicodeString & pattern,int32_t & patternOffset,const UnicodeString & text,int32_t & textOffset,UBool lenient)2297 UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
2298                                       int32_t &patternOffset,
2299                                       const UnicodeString &text,
2300                                       int32_t &textOffset,
2301                                       UBool lenient)
2302 {
2303     UBool inQuote = FALSE;
2304     UnicodeString literal;
2305     int32_t i = patternOffset;
2306 
2307     // scan pattern looking for contiguous literal characters
2308     for ( ; i < pattern.length(); i += 1) {
2309         UChar ch = pattern.charAt(i);
2310 
2311         if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // unquoted [A-Za-z]
2312             break;
2313         }
2314 
2315         if (ch == QUOTE) {
2316             // Match a quote literal ('') inside OR outside of quotes
2317             if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
2318                 i += 1;
2319             } else {
2320                 inQuote = !inQuote;
2321                 continue;
2322             }
2323         }
2324 
2325         literal += ch;
2326     }
2327 
2328     // at this point, literal contains the literal text
2329     // and i is the index of the next non-literal pattern character.
2330     int32_t p;
2331     int32_t t = textOffset;
2332 
2333     if (lenient) {
2334         // trim leading, trailing whitespace from
2335         // the literal text
2336         literal.trim();
2337 
2338         // ignore any leading whitespace in the text
2339         while (t < text.length() && u_isWhitespace(text.charAt(t))) {
2340             t += 1;
2341         }
2342     }
2343 
2344     for (p = 0; p < literal.length() && t < text.length(); p += 1, t += 1) {
2345         UBool needWhitespace = FALSE;
2346 
2347         while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
2348             needWhitespace = TRUE;
2349             p += 1;
2350         }
2351 
2352         if (needWhitespace) {
2353             int32_t tStart = t;
2354 
2355             while (t < text.length()) {
2356                 UChar tch = text.charAt(t);
2357 
2358                 if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
2359                     break;
2360                 }
2361 
2362                 t += 1;
2363             }
2364 
2365             // TODO: should we require internal spaces
2366             // in lenient mode? (There won't be any
2367             // leading or trailing spaces)
2368             if (!lenient && t == tStart) {
2369                 // didn't find matching whitespace:
2370                 // an error in strict mode
2371                 return FALSE;
2372             }
2373 
2374             // In strict mode, this run of whitespace
2375             // may have been at the end.
2376             if (p >= literal.length()) {
2377                 break;
2378             }
2379         }
2380 
2381         if (t >= text.length() || literal.charAt(p) != text.charAt(t)) {
2382             // Ran out of text, or found a non-matching character:
2383             // OK in lenient mode, an error in strict mode.
2384             if (lenient) {
2385                 break;
2386             }
2387 
2388             return FALSE;
2389         }
2390     }
2391 
2392     // At this point if we're in strict mode we have a complete match.
2393     // If we're in lenient mode we may have a partial match, or no
2394     // match at all.
2395     if (p <= 0) {
2396         // no match. Pretend it matched a run of whitespace
2397         // and ignorables in the text.
2398         const  UnicodeSet *ignorables = NULL;
2399         UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), pattern.charAt(i));
2400 
2401         if (patternCharPtr != NULL) {
2402             UDateFormatField patternCharIndex = (UDateFormatField) (patternCharPtr - DateFormatSymbols::getPatternUChars());
2403 
2404             ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
2405         }
2406 
2407         for (t = textOffset; t < text.length(); t += 1) {
2408             UChar ch = text.charAt(t);
2409 
2410             if (ignorables == NULL || !ignorables->contains(ch)) {
2411                 break;
2412             }
2413         }
2414     }
2415 
2416     // if we get here, we've got a complete match.
2417     patternOffset = i - 1;
2418     textOffset = t;
2419 
2420     return TRUE;
2421 }
2422 
2423 //----------------------------------------------------------------------
2424 
matchString(const UnicodeString & text,int32_t start,UCalendarDateFields field,const UnicodeString * data,int32_t dataCount,Calendar & cal) const2425 int32_t SimpleDateFormat::matchString(const UnicodeString& text,
2426                               int32_t start,
2427                               UCalendarDateFields field,
2428                               const UnicodeString* data,
2429                               int32_t dataCount,
2430                               Calendar& cal) const
2431 {
2432     int32_t i = 0;
2433     int32_t count = dataCount;
2434 
2435     if (field == UCAL_DAY_OF_WEEK) i = 1;
2436 
2437     // There may be multiple strings in the data[] array which begin with
2438     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
2439     // We keep track of the longest match, and return that.  Note that this
2440     // unfortunately requires us to test all array elements.
2441     int32_t bestMatchLength = 0, bestMatch = -1;
2442 
2443     // {sfb} kludge to support case-insensitive comparison
2444     // {markus 2002oct11} do not just use caseCompareBetween because we do not know
2445     // the length of the match after case folding
2446     // {alan 20040607} don't case change the whole string, since the length
2447     // can change
2448     // TODO we need a case-insensitive startsWith function
2449     UnicodeString lcase, lcaseText;
2450     text.extract(start, INT32_MAX, lcaseText);
2451     lcaseText.foldCase();
2452 
2453     for (; i < count; ++i)
2454     {
2455         // Always compare if we have no match yet; otherwise only compare
2456         // against potentially better matches (longer strings).
2457 
2458         lcase.fastCopyFrom(data[i]).foldCase();
2459         int32_t length = lcase.length();
2460 
2461         if (length > bestMatchLength &&
2462             lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
2463         {
2464             bestMatch = i;
2465             bestMatchLength = length;
2466         }
2467     }
2468     if (bestMatch >= 0)
2469     {
2470         // Adjustment for Hebrew Calendar month Adar II
2471         if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
2472             cal.set(field,6);
2473         }
2474         else {
2475             cal.set(field, bestMatch);
2476         }
2477 
2478         // Once we have a match, we have to determine the length of the
2479         // original source string.  This will usually be == the length of
2480         // the case folded string, but it may differ (e.g. sharp s).
2481         lcase.fastCopyFrom(data[bestMatch]).foldCase();
2482 
2483         // Most of the time, the length will be the same as the length
2484         // of the string from the locale data.  Sometimes it will be
2485         // different, in which case we will have to figure it out by
2486         // adding a character at a time, until we have a match.  We do
2487         // this all in one loop, where we try 'len' first (at index
2488         // i==0).
2489         int32_t len = data[bestMatch].length(); // 99+% of the time
2490         int32_t n = text.length() - start;
2491         for (i=0; i<=n; ++i) {
2492             int32_t j=i;
2493             if (i == 0) {
2494                 j = len;
2495             } else if (i == len) {
2496                 continue; // already tried this when i was 0
2497             }
2498             text.extract(start, j, lcaseText);
2499             lcaseText.foldCase();
2500             if (lcase == lcaseText) {
2501                 return start + j;
2502             }
2503         }
2504     }
2505 
2506     return -start;
2507 }
2508 
2509 //----------------------------------------------------------------------
2510 
2511 void
set2DigitYearStart(UDate d,UErrorCode & status)2512 SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
2513 {
2514     parseAmbiguousDatesAsAfter(d, status);
2515 }
2516 
2517 /**
2518  * Private member function that converts the parsed date strings into
2519  * timeFields. Returns -start (for ParsePosition) if failed.
2520  * @param text the time text to be parsed.
2521  * @param start where to start parsing.
2522  * @param ch the pattern character for the date field text to be parsed.
2523  * @param count the count of a pattern character.
2524  * @return the new start position if matching succeeded; a negative number
2525  * indicating matching failure, otherwise.
2526  */
subParse(const UnicodeString & text,int32_t & start,UChar ch,int32_t count,UBool obeyCount,UBool allowNegative,UBool ambiguousYear[],int32_t & saveHebrewMonth,Calendar & cal,int32_t patLoc) const2527 int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
2528                            UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
2529                            int32_t patLoc) const
2530 {
2531     Formattable number;
2532     int32_t value = 0;
2533     int32_t i;
2534     int32_t ps = 0;
2535     ParsePosition pos(0);
2536     UDateFormatField patternCharIndex;
2537     NumberFormat *currentNumberFormat;
2538     UnicodeString temp;
2539     UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
2540     UBool lenient = isLenient();
2541     UBool gotNumber = FALSE;
2542 
2543 #if defined (U_DEBUG_CAL)
2544     //fprintf(stderr, "%s:%d - [%c]  st=%d \n", __FILE__, __LINE__, (char) ch, start);
2545 #endif
2546 
2547     if (patternCharPtr == NULL) {
2548         return -start;
2549     }
2550 
2551     patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
2552     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
2553     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
2554 
2555     // If there are any spaces here, skip over them.  If we hit the end
2556     // of the string, then fail.
2557     for (;;) {
2558         if (start >= text.length()) {
2559             return -start;
2560         }
2561         UChar32 c = text.char32At(start);
2562         if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) {
2563             break;
2564         }
2565         start += UTF_CHAR_LENGTH(c);
2566     }
2567     pos.setIndex(start);
2568 
2569     // We handle a few special cases here where we need to parse
2570     // a number value.  We handle further, more generic cases below.  We need
2571     // to handle some of them here because some fields require extra processing on
2572     // the parsed value.
2573     if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||                       // k
2574         patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD ||                       // H
2575         patternCharIndex == UDAT_HOUR1_FIELD ||                              // h
2576         patternCharIndex == UDAT_HOUR0_FIELD ||                              // K
2577         (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) ||          // e
2578         (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) ||     // c
2579         (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||              // M
2580         (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||   // L
2581         (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||            // Q
2582         (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q
2583         patternCharIndex == UDAT_YEAR_FIELD ||                               // y
2584         patternCharIndex == UDAT_YEAR_WOY_FIELD ||                           // Y
2585         patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)                    // S
2586     {
2587         int32_t parseStart = pos.getIndex();
2588         // It would be good to unify this with the obeyCount logic below,
2589         // but that's going to be difficult.
2590         const UnicodeString* src;
2591 
2592         if (obeyCount) {
2593             if ((start+count) > text.length()) {
2594                 return -start;
2595             }
2596 
2597             text.extractBetween(0, start + count, temp);
2598             src = &temp;
2599         } else {
2600             src = &text;
2601         }
2602 
2603         parseInt(*src, number, pos, allowNegative,currentNumberFormat);
2604 
2605         int32_t txtLoc = pos.getIndex();
2606 
2607         if (txtLoc > parseStart) {
2608             value = number.getLong();
2609             gotNumber = TRUE;
2610 
2611             // suffix processing
2612             if (value < 0 ) {
2613                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
2614                 if (txtLoc != pos.getIndex()) {
2615                     value *= -1;
2616                 }
2617             }
2618             else {
2619                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
2620             }
2621 
2622             if (!lenient) {
2623                 // Check the range of the value
2624                 int32_t bias = gFieldRangeBias[patternCharIndex];
2625                 if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
2626                     return -start;
2627                 }
2628             }
2629 
2630             pos.setIndex(txtLoc);
2631         }
2632     }
2633 
2634     // Make sure that we got a number if
2635     // we want one, and didn't get one
2636     // if we don't want one.
2637     switch (patternCharIndex) {
2638         case UDAT_HOUR_OF_DAY1_FIELD:
2639         case UDAT_HOUR_OF_DAY0_FIELD:
2640         case UDAT_HOUR1_FIELD:
2641         case UDAT_HOUR0_FIELD:
2642             // special range check for hours:
2643             if (value < 0 || value > 24) {
2644                 return -start;
2645             }
2646 
2647             // fall through to gotNumber check
2648 
2649         case UDAT_YEAR_FIELD:
2650         case UDAT_YEAR_WOY_FIELD:
2651         case UDAT_FRACTIONAL_SECOND_FIELD:
2652             // these must be a number
2653             if (! gotNumber) {
2654                 return -start;
2655             }
2656 
2657             break;
2658 
2659         default:
2660             // we check the rest of the fields below.
2661             break;
2662     }
2663 
2664     switch (patternCharIndex) {
2665     case UDAT_ERA_FIELD:
2666         if (count == 5) {
2667             ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, cal);
2668         } else if (count == 4) {
2669             ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, cal);
2670         } else {
2671             ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, cal);
2672         }
2673 
2674         // check return position, if it equals -start, then matchString error
2675         // special case the return code so we don't necessarily fail out until we
2676         // verify no year information also
2677         if (ps == -start)
2678             ps--;
2679 
2680         return ps;
2681 
2682     case UDAT_YEAR_FIELD:
2683         // If there are 3 or more YEAR pattern characters, this indicates
2684         // that the year value is to be treated literally, without any
2685         // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
2686         // we made adjustments to place the 2-digit year in the proper
2687         // century, for parsed strings from "00" to "99".  Any other string
2688         // is treated literally:  "2250", "-1", "1", "002".
2689         if ((pos.getIndex() - start) == 2
2690             && u_isdigit(text.charAt(start))
2691             && u_isdigit(text.charAt(start+1)))
2692         {
2693             // Assume for example that the defaultCenturyStart is 6/18/1903.
2694             // This means that two-digit years will be forced into the range
2695             // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
2696             // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
2697             // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
2698             // other fields specify a date before 6/18, or 1903 if they specify a
2699             // date afterwards.  As a result, 03 is an ambiguous year.  All other
2700             // two-digit years are unambiguous.
2701           if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
2702               int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
2703               ambiguousYear[0] = (value == ambiguousTwoDigitYear);
2704               value += (fDefaultCenturyStartYear/100)*100 +
2705                 (value < ambiguousTwoDigitYear ? 100 : 0);
2706             }
2707         }
2708         cal.set(UCAL_YEAR, value);
2709 
2710         // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
2711         if (saveHebrewMonth >= 0) {
2712             HebrewCalendar *hc = (HebrewCalendar*)&cal;
2713             if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) {
2714                cal.set(UCAL_MONTH,saveHebrewMonth);
2715             } else {
2716                cal.set(UCAL_MONTH,saveHebrewMonth-1);
2717             }
2718             saveHebrewMonth = -1;
2719         }
2720         return pos.getIndex();
2721 
2722     case UDAT_YEAR_WOY_FIELD:
2723         // Comment is the same as for UDAT_Year_FIELDs - look above
2724         if ((pos.getIndex() - start) == 2
2725             && u_isdigit(text.charAt(start))
2726             && u_isdigit(text.charAt(start+1))
2727             && fHaveDefaultCentury )
2728         {
2729             int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
2730             ambiguousYear[0] = (value == ambiguousTwoDigitYear);
2731             value += (fDefaultCenturyStartYear/100)*100 +
2732                 (value < ambiguousTwoDigitYear ? 100 : 0);
2733         }
2734         cal.set(UCAL_YEAR_WOY, value);
2735         return pos.getIndex();
2736 
2737     case UDAT_MONTH_FIELD:
2738         if (gotNumber) // i.e., M or MM.
2739         {
2740             // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether
2741             // 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
2742             // the year is parsed.
2743             if (!strcmp(cal.getType(),"hebrew")) {
2744                 HebrewCalendar *hc = (HebrewCalendar*)&cal;
2745                 if (cal.isSet(UCAL_YEAR)) {
2746                    UErrorCode status = U_ZERO_ERROR;
2747                    if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
2748                        cal.set(UCAL_MONTH, value);
2749                    } else {
2750                        cal.set(UCAL_MONTH, value - 1);
2751                    }
2752                 } else {
2753                     saveHebrewMonth = value;
2754                 }
2755             } else {
2756                 // Don't want to parse the month if it is a string
2757                 // while pattern uses numeric style: M or MM.
2758                 // [We computed 'value' above.]
2759                 cal.set(UCAL_MONTH, value - 1);
2760             }
2761             return pos.getIndex();
2762         } else {
2763             // count >= 3 // i.e., MMM or MMMM
2764             // Want to be able to parse both short and long forms.
2765             // Try count == 4 first:
2766             int32_t newStart = 0;
2767 
2768             if ((newStart = matchString(text, start, UCAL_MONTH, // try MMMM
2769                                       fSymbols->fMonths, fSymbols->fMonthsCount, cal)) > 0)
2770                 return newStart;
2771             else if ((newStart = matchString(text, start, UCAL_MONTH, // try MMM
2772                                           fSymbols->fShortMonths, fSymbols->fShortMonthsCount, cal)) > 0)
2773                 return newStart;
2774             else if (!lenient) // currently we do not try to parse MMMMM: #8860
2775                 return newStart;
2776             // else we allowing parsing as number, below
2777         }
2778         break;
2779 
2780     case UDAT_STANDALONE_MONTH_FIELD:
2781         if (gotNumber) // i.e., L or LL.
2782         {
2783             // Don't want to parse the month if it is a string
2784             // while pattern uses numeric style: M or MM.
2785             // [We computed 'value' above.]
2786             cal.set(UCAL_MONTH, value - 1);
2787             return pos.getIndex();
2788         } else {
2789             // count >= 3 // i.e., LLL or LLLL
2790             // Want to be able to parse both short and long forms.
2791             // Try count == 4 first:
2792             int32_t newStart = 0;
2793 
2794             if ((newStart = matchString(text, start, UCAL_MONTH,
2795                                       fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, cal)) > 0)
2796                 return newStart;
2797             else if ((newStart = matchString(text, start, UCAL_MONTH,
2798                                           fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, cal)) > 0)
2799                 return newStart;
2800             else if (!lenient) // currently we do not try to parse LLLLL: #8860
2801                 return newStart;
2802             // else we allowing parsing as number, below
2803         }
2804         break;
2805 
2806     case UDAT_HOUR_OF_DAY1_FIELD:
2807         // [We computed 'value' above.]
2808         if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
2809             value = 0;
2810 
2811         // fall through to set field
2812 
2813     case UDAT_HOUR_OF_DAY0_FIELD:
2814         cal.set(UCAL_HOUR_OF_DAY, value);
2815         return pos.getIndex();
2816 
2817     case UDAT_FRACTIONAL_SECOND_FIELD:
2818         // Fractional seconds left-justify
2819         i = pos.getIndex() - start;
2820         if (i < 3) {
2821             while (i < 3) {
2822                 value *= 10;
2823                 i++;
2824             }
2825         } else {
2826             int32_t a = 1;
2827             while (i > 3) {
2828                 a *= 10;
2829                 i--;
2830             }
2831             value = (value + (a>>1)) / a;
2832         }
2833         cal.set(UCAL_MILLISECOND, value);
2834         return pos.getIndex();
2835 
2836     case UDAT_DOW_LOCAL_FIELD:
2837         if (gotNumber) // i.e., e or ee
2838         {
2839             // [We computed 'value' above.]
2840             cal.set(UCAL_DOW_LOCAL, value);
2841             return pos.getIndex();
2842         }
2843         // else for eee-eeeee fall through to handling of EEE-EEEEE
2844         // fall through, do not break here
2845     case UDAT_DAY_OF_WEEK_FIELD:
2846         {
2847             // Want to be able to parse both short and long forms.
2848             // Try count == 4 (EEEE) first:
2849             int32_t newStart = 0;
2850             if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
2851                                       fSymbols->fWeekdays, fSymbols->fWeekdaysCount, cal)) > 0)
2852                 return newStart;
2853             // EEEE failed, now try EEE
2854             else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
2855                                    fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, cal)) > 0)
2856                 return newStart;
2857             // EEE failed, now try EEEEE
2858             else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
2859                                    fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, cal)) > 0)
2860                 return newStart;
2861             else if (!lenient || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD)
2862                 return newStart;
2863             // else we allowing parsing as number, below
2864         }
2865         break;
2866 
2867     case UDAT_STANDALONE_DAY_FIELD:
2868         {
2869             if (gotNumber) // c or cc
2870             {
2871                 // [We computed 'value' above.]
2872                 cal.set(UCAL_DOW_LOCAL, value);
2873                 return pos.getIndex();
2874             }
2875             // Want to be able to parse both short and long forms.
2876             // Try count == 4 (cccc) first:
2877             int32_t newStart = 0;
2878             if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
2879                                       fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, cal)) > 0)
2880                 return newStart;
2881             else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
2882                                           fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, cal)) > 0)
2883                 return newStart;
2884             else if (!lenient)
2885                 return newStart;
2886             // else we allowing parsing as number, below
2887         }
2888         break;
2889 
2890     case UDAT_AM_PM_FIELD:
2891         return matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, cal);
2892 
2893     case UDAT_HOUR1_FIELD:
2894         // [We computed 'value' above.]
2895         if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
2896             value = 0;
2897 
2898         // fall through to set field
2899 
2900     case UDAT_HOUR0_FIELD:
2901         cal.set(UCAL_HOUR, value);
2902         return pos.getIndex();
2903 
2904     case UDAT_QUARTER_FIELD:
2905         if (gotNumber) // i.e., Q or QQ.
2906         {
2907             // Don't want to parse the month if it is a string
2908             // while pattern uses numeric style: Q or QQ.
2909             // [We computed 'value' above.]
2910             cal.set(UCAL_MONTH, (value - 1) * 3);
2911             return pos.getIndex();
2912         } else {
2913             // count >= 3 // i.e., QQQ or QQQQ
2914             // Want to be able to parse both short and long forms.
2915             // Try count == 4 first:
2916             int32_t newStart = 0;
2917 
2918             if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
2919                                       fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
2920                 return newStart;
2921             else if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
2922                                           fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)
2923                 return newStart;
2924             else if (!lenient)
2925                 return newStart;
2926             // else we allowing parsing as number, below
2927         }
2928         break;
2929 
2930     case UDAT_STANDALONE_QUARTER_FIELD:
2931         if (gotNumber) // i.e., q or qq.
2932         {
2933             // Don't want to parse the month if it is a string
2934             // while pattern uses numeric style: q or q.
2935             // [We computed 'value' above.]
2936             cal.set(UCAL_MONTH, (value - 1) * 3);
2937             return pos.getIndex();
2938         } else {
2939             // count >= 3 // i.e., qqq or qqqq
2940             // Want to be able to parse both short and long forms.
2941             // Try count == 4 first:
2942             int32_t newStart = 0;
2943 
2944             if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
2945                                       fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
2946                 return newStart;
2947             else if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
2948                                           fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)
2949                 return newStart;
2950             else if (!lenient)
2951                 return newStart;
2952             // else we allowing parsing as number, below
2953         }
2954         break;
2955 
2956     case UDAT_TIMEZONE_FIELD:
2957     case UDAT_TIMEZONE_RFC_FIELD:
2958     case UDAT_TIMEZONE_GENERIC_FIELD:
2959     case UDAT_TIMEZONE_SPECIAL_FIELD:
2960         {
2961             int32_t offset = 0;
2962             UBool parsed = FALSE;
2963 
2964             // Step 1
2965             // Check if this is a long GMT offset string (either localized or default)
2966             offset = parseGMT(text, pos);
2967             if (pos.getIndex() - start > 0) {
2968                 parsed = TRUE;
2969             }
2970             if (!parsed) {
2971                 // Step 2
2972                 // Check if this is an RFC822 time zone offset.
2973                 // ICU supports the standard RFC822 format [+|-]HHmm
2974                 // and its extended form [+|-]HHmmSS.
2975                 do {
2976                     int32_t sign = 0;
2977                     UChar signChar = text.charAt(start);
2978                     if (signChar == (UChar)0x002B /* '+' */) {
2979                         sign = 1;
2980                     } else if (signChar == (UChar)0x002D /* '-' */) {
2981                         sign = -1;
2982                     } else {
2983                         // Not an RFC822 offset string
2984                         break;
2985                     }
2986 
2987                     // Parse digits
2988                     int32_t orgPos = start + 1;
2989                     pos.setIndex(orgPos);
2990                     parseInt(text, number, 6, pos, FALSE,currentNumberFormat);
2991                     int32_t numLen = pos.getIndex() - orgPos;
2992                     if (numLen <= 0) {
2993                         break;
2994                     }
2995 
2996                     // Followings are possible format (excluding sign char)
2997                     // HHmmSS
2998                     // HmmSS
2999                     // HHmm
3000                     // Hmm
3001                     // HH
3002                     // H
3003                     int32_t val = number.getLong();
3004                     int32_t hour = 0, min = 0, sec = 0;
3005                     switch(numLen) {
3006                     case 1: // H
3007                     case 2: // HH
3008                         hour = val;
3009                         break;
3010                     case 3: // Hmm
3011                     case 4: // HHmm
3012                         hour = val / 100;
3013                         min = val % 100;
3014                         break;
3015                     case 5: // Hmmss
3016                     case 6: // HHmmss
3017                         hour = val / 10000;
3018                         min = (val % 10000) / 100;
3019                         sec = val % 100;
3020                         break;
3021                     }
3022                     if (hour > 23 || min > 59 || sec > 59) {
3023                         // Invalid value range
3024                         break;
3025                     }
3026                     offset = (((hour * 60) + min) * 60 + sec) * 1000 * sign;
3027                     parsed = TRUE;
3028                 } while (FALSE);
3029 
3030                 if (!parsed) {
3031                     // Failed to parse.  Reset the position.
3032                     pos.setIndex(start);
3033                 }
3034             }
3035 
3036             if (parsed) {
3037                 // offset was successfully parsed as either a long GMT string or RFC822 zone offset
3038                 // string.  Create normalized zone ID for the offset.
3039 
3040                 UnicodeString tzID(gGmt);
3041                 formatRFC822TZ(tzID, offset);
3042                 //TimeZone *customTZ = TimeZone::createTimeZone(tzID);
3043                 TimeZone *customTZ = new SimpleTimeZone(offset, tzID);    // faster than TimeZone::createTimeZone
3044                 cal.adoptTimeZone(customTZ);
3045 
3046                 return pos.getIndex();
3047             }
3048 
3049             // Step 3
3050             // Is this standalone Localized GMT zero or GMT/UT/UTC?
3051             int32_t gmtLen = 0;
3052             if (text.compare(start, fSymbols->fGmtZero.length(), fSymbols->fGmtZero) == 0) {
3053                 gmtLen = fSymbols->fGmtZero.length();
3054             } else if (text.compare(start, kGmtLen, gGmt) == 0) {
3055                 gmtLen = kGmtLen;
3056             } else if (text.compare(start, kUtcLen, gUtc) == 0) {
3057                 gmtLen = kUtcLen;
3058             } else if (text.compare(start, kUtLen, gUt) == 0) {
3059                 gmtLen = kUtLen;
3060             }
3061             // If we parse the string to the end, we can exit here.
3062             // If any characters follow, we still need to proceed to the
3063             // next step. Otherwise, all time zone names starting with GMT/UT/UTC
3064             // (for example, "UTT") will fail.
3065             if (gmtLen > 0 && ((text.length() - start) == gmtLen)) {
3066                 TimeZone *tz = TimeZone::createTimeZone(UNICODE_STRING("Etc/GMT", 7));
3067                 cal.adoptTimeZone(tz);
3068                 return start + gmtLen;
3069             }
3070 
3071             // Step 4
3072             // At this point, check for named time zones by looking through
3073             // the locale data.
3074             if (patternCharIndex != UDAT_TIMEZONE_RFC_FIELD) {
3075                 UTimeZoneTimeType parsedTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
3076                 ParsePosition tmpPos(start);
3077                 UnicodeString parsedID;
3078 
3079                 switch (patternCharIndex) {
3080                 case UDAT_TIMEZONE_FIELD:
3081                     if (count < 4) {
3082                         tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_SHORT_COMMONLY_USED, text, tmpPos, parsedID, &parsedTimeType);
3083                     } else {
3084                         tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_LONG, text, tmpPos, parsedID, &parsedTimeType);
3085                     }
3086                     break;
3087                 case UDAT_TIMEZONE_GENERIC_FIELD:
3088                     if (count < 4) {
3089                         tzFormat()->parse(UTZFMT_STYLE_GENERIC_SHORT, text, tmpPos, parsedID, &parsedTimeType);
3090                     } else {
3091                         tzFormat()->parse(UTZFMT_STYLE_GENERIC_LONG, text, tmpPos, parsedID, &parsedTimeType);
3092                     }
3093                     break;
3094                 case UDAT_TIMEZONE_SPECIAL_FIELD:
3095                     if (count < 4) {
3096                         tzFormat()->parse(UTZFMT_STYLE_SPECIFIC_SHORT, text, tmpPos, parsedID, &parsedTimeType);
3097                     } else {
3098                         tzFormat()->parse(UTZFMT_STYLE_LOCATION, text, tmpPos, parsedID, &parsedTimeType);
3099                     }
3100                     break;
3101                 default:
3102                     break;
3103                 }
3104                 if (tmpPos.getErrorIndex() < 0) {
3105                     if (parsedTimeType == UTZFMT_TIME_TYPE_STANDARD) {
3106                         ((SimpleDateFormat*)this)->tztype = TZTYPE_STD;
3107                     } else if (parsedTimeType == UTZFMT_TIME_TYPE_DAYLIGHT) {
3108                         ((SimpleDateFormat*)this)->tztype = TZTYPE_DST;
3109                     }
3110 
3111                     UnicodeString current;
3112                     cal.getTimeZone().getID(current);
3113                     if (parsedID != current) {
3114                         TimeZone *tz = TimeZone::createTimeZone(parsedID);
3115                         cal.adoptTimeZone(tz);
3116                     }
3117                     return tmpPos.getIndex();
3118                 }
3119             }
3120             // Step 5
3121             // If we saw standalone GMT zero pattern, then use GMT.
3122             if (gmtLen > 0) {
3123                 TimeZone *tz = TimeZone::createTimeZone(UNICODE_STRING("Etc/GMT", 7));
3124                 cal.adoptTimeZone(tz);
3125                 return start + gmtLen;
3126             }
3127 
3128             // complete failure
3129             return -start;
3130         }
3131 
3132     default:
3133         // Handle "generic" fields
3134         // this is now handled below, outside the switch block
3135         break;
3136     }
3137     // Handle "generic" fields:
3138     // switch default case now handled here (outside switch block) to allow
3139     // parsing of some string fields as digits for lenient case
3140 
3141     int32_t parseStart = pos.getIndex();
3142     const UnicodeString* src;
3143     if (obeyCount) {
3144         if ((start+count) > text.length()) {
3145             return -start;
3146         }
3147         text.extractBetween(0, start + count, temp);
3148         src = &temp;
3149     } else {
3150         src = &text;
3151     }
3152     parseInt(*src, number, pos, allowNegative,currentNumberFormat);
3153     if (pos.getIndex() != parseStart) {
3154         int32_t value = number.getLong();
3155 
3156         // Don't need suffix processing here (as in number processing at the beginning of the function);
3157         // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
3158 
3159         if (!lenient) {
3160             // Check the range of the value
3161             int32_t bias = gFieldRangeBias[patternCharIndex];
3162             if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
3163                 return -start;
3164             }
3165         }
3166 
3167         // For the following, need to repeat some of the "if (gotNumber)" code above:
3168         // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD,
3169         // UDAT_[STANDALONE_]QUARTER_FIELD
3170         switch (patternCharIndex) {
3171         case UDAT_MONTH_FIELD:
3172             // See notes under UDAT_MONTH_FIELD case above
3173             if (!strcmp(cal.getType(),"hebrew")) {
3174                 HebrewCalendar *hc = (HebrewCalendar*)&cal;
3175                 if (cal.isSet(UCAL_YEAR)) {
3176                    UErrorCode status = U_ZERO_ERROR;
3177                    if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
3178                        cal.set(UCAL_MONTH, value);
3179                    } else {
3180                        cal.set(UCAL_MONTH, value - 1);
3181                    }
3182                 } else {
3183                     saveHebrewMonth = value;
3184                 }
3185             } else {
3186                 cal.set(UCAL_MONTH, value - 1);
3187             }
3188             break;
3189         case UDAT_STANDALONE_MONTH_FIELD:
3190             cal.set(UCAL_MONTH, value - 1);
3191             break;
3192         case UDAT_DOW_LOCAL_FIELD:
3193         case UDAT_STANDALONE_DAY_FIELD:
3194             cal.set(UCAL_DOW_LOCAL, value);
3195             break;
3196         case UDAT_QUARTER_FIELD:
3197         case UDAT_STANDALONE_QUARTER_FIELD:
3198              cal.set(UCAL_MONTH, (value - 1) * 3);
3199              break;
3200         default:
3201             cal.set(field, value);
3202             break;
3203         }
3204         return pos.getIndex();
3205     }
3206     return -start;
3207 }
3208 
3209 /**
3210  * Parse an integer using fNumberFormat.  This method is semantically
3211  * const, but actually may modify fNumberFormat.
3212  */
parseInt(const UnicodeString & text,Formattable & number,ParsePosition & pos,UBool allowNegative,NumberFormat * fmt) const3213 void SimpleDateFormat::parseInt(const UnicodeString& text,
3214                                 Formattable& number,
3215                                 ParsePosition& pos,
3216                                 UBool allowNegative,
3217                                 NumberFormat *fmt) const {
3218     parseInt(text, number, -1, pos, allowNegative,fmt);
3219 }
3220 
3221 /**
3222  * Parse an integer using fNumberFormat up to maxDigits.
3223  */
parseInt(const UnicodeString & text,Formattable & number,int32_t maxDigits,ParsePosition & pos,UBool allowNegative,NumberFormat * fmt) const3224 void SimpleDateFormat::parseInt(const UnicodeString& text,
3225                                 Formattable& number,
3226                                 int32_t maxDigits,
3227                                 ParsePosition& pos,
3228                                 UBool allowNegative,
3229                                 NumberFormat *fmt) const {
3230     UnicodeString oldPrefix;
3231     DecimalFormat* df = NULL;
3232     if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
3233         df->getNegativePrefix(oldPrefix);
3234         df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
3235     }
3236     int32_t oldPos = pos.getIndex();
3237     fmt->parse(text, number, pos);
3238     if (df != NULL) {
3239         df->setNegativePrefix(oldPrefix);
3240     }
3241 
3242     if (maxDigits > 0) {
3243         // adjust the result to fit into
3244         // the maxDigits and move the position back
3245         int32_t nDigits = pos.getIndex() - oldPos;
3246         if (nDigits > maxDigits) {
3247             int32_t val = number.getLong();
3248             nDigits -= maxDigits;
3249             while (nDigits > 0) {
3250                 val /= 10;
3251                 nDigits--;
3252             }
3253             pos.setIndex(oldPos + maxDigits);
3254             number.setLong(val);
3255         }
3256     }
3257 }
3258 
3259 //----------------------------------------------------------------------
3260 
translatePattern(const UnicodeString & originalPattern,UnicodeString & translatedPattern,const UnicodeString & from,const UnicodeString & to,UErrorCode & status)3261 void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
3262                                         UnicodeString& translatedPattern,
3263                                         const UnicodeString& from,
3264                                         const UnicodeString& to,
3265                                         UErrorCode& status)
3266 {
3267   // run through the pattern and convert any pattern symbols from the version
3268   // in "from" to the corresponding character ion "to".  This code takes
3269   // quoted strings into account (it doesn't try to translate them), and it signals
3270   // an error if a particular "pattern character" doesn't appear in "from".
3271   // Depending on the values of "from" and "to" this can convert from generic
3272   // to localized patterns or localized to generic.
3273   if (U_FAILURE(status))
3274     return;
3275 
3276   translatedPattern.remove();
3277   UBool inQuote = FALSE;
3278   for (int32_t i = 0; i < originalPattern.length(); ++i) {
3279     UChar c = originalPattern[i];
3280     if (inQuote) {
3281       if (c == QUOTE)
3282     inQuote = FALSE;
3283     }
3284     else {
3285       if (c == QUOTE)
3286     inQuote = TRUE;
3287       else if ((c >= 0x0061 /*'a'*/ && c <= 0x007A) /*'z'*/
3288            || (c >= 0x0041 /*'A'*/ && c <= 0x005A /*'Z'*/)) {
3289     int32_t ci = from.indexOf(c);
3290     if (ci == -1) {
3291       status = U_INVALID_FORMAT_ERROR;
3292       return;
3293     }
3294     c = to[ci];
3295       }
3296     }
3297     translatedPattern += c;
3298   }
3299   if (inQuote) {
3300     status = U_INVALID_FORMAT_ERROR;
3301     return;
3302   }
3303 }
3304 
3305 //----------------------------------------------------------------------
3306 
3307 UnicodeString&
toPattern(UnicodeString & result) const3308 SimpleDateFormat::toPattern(UnicodeString& result) const
3309 {
3310     result = fPattern;
3311     return result;
3312 }
3313 
3314 //----------------------------------------------------------------------
3315 
3316 UnicodeString&
toLocalizedPattern(UnicodeString & result,UErrorCode & status) const3317 SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
3318                                      UErrorCode& status) const
3319 {
3320     translatePattern(fPattern, result,
3321                      UnicodeString(DateFormatSymbols::getPatternUChars()),
3322                      fSymbols->fLocalPatternChars, status);
3323     return result;
3324 }
3325 
3326 //----------------------------------------------------------------------
3327 
3328 void
applyPattern(const UnicodeString & pattern)3329 SimpleDateFormat::applyPattern(const UnicodeString& pattern)
3330 {
3331     fPattern = pattern;
3332 }
3333 
3334 //----------------------------------------------------------------------
3335 
3336 void
applyLocalizedPattern(const UnicodeString & pattern,UErrorCode & status)3337 SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
3338                                         UErrorCode &status)
3339 {
3340     translatePattern(pattern, fPattern,
3341                      fSymbols->fLocalPatternChars,
3342                      UnicodeString(DateFormatSymbols::getPatternUChars()), status);
3343 }
3344 
3345 //----------------------------------------------------------------------
3346 
3347 const DateFormatSymbols*
getDateFormatSymbols() const3348 SimpleDateFormat::getDateFormatSymbols() const
3349 {
3350     return fSymbols;
3351 }
3352 
3353 //----------------------------------------------------------------------
3354 
3355 void
adoptDateFormatSymbols(DateFormatSymbols * newFormatSymbols)3356 SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
3357 {
3358     delete fSymbols;
3359     fSymbols = newFormatSymbols;
3360 }
3361 
3362 //----------------------------------------------------------------------
3363 void
setDateFormatSymbols(const DateFormatSymbols & newFormatSymbols)3364 SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
3365 {
3366     delete fSymbols;
3367     fSymbols = new DateFormatSymbols(newFormatSymbols);
3368 }
3369 
3370 
3371 //----------------------------------------------------------------------
3372 
3373 
adoptCalendar(Calendar * calendarToAdopt)3374 void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
3375 {
3376   UErrorCode status = U_ZERO_ERROR;
3377   DateFormat::adoptCalendar(calendarToAdopt);
3378   delete fSymbols;
3379   fSymbols=NULL;
3380   initializeSymbols(fLocale, fCalendar, status);  // we need new symbols
3381   initializeDefaultCentury();  // we need a new century (possibly)
3382 }
3383 
3384 
3385 //----------------------------------------------------------------------
3386 
3387 
3388 UBool
isFieldUnitIgnored(UCalendarDateFields field) const3389 SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
3390     return isFieldUnitIgnored(fPattern, field);
3391 }
3392 
3393 
3394 UBool
isFieldUnitIgnored(const UnicodeString & pattern,UCalendarDateFields field)3395 SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
3396                                      UCalendarDateFields field) {
3397     int32_t fieldLevel = fgCalendarFieldToLevel[field];
3398     int32_t level;
3399     UChar ch;
3400     UBool inQuote = FALSE;
3401     UChar prevCh = 0;
3402     int32_t count = 0;
3403 
3404     for (int32_t i = 0; i < pattern.length(); ++i) {
3405         ch = pattern[i];
3406         if (ch != prevCh && count > 0) {
3407             level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE];
3408             // the larger the level, the smaller the field unit.
3409             if ( fieldLevel <= level ) {
3410                 return FALSE;
3411             }
3412             count = 0;
3413         }
3414         if (ch == QUOTE) {
3415             if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) {
3416                 ++i;
3417             } else {
3418                 inQuote = ! inQuote;
3419             }
3420         }
3421         else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
3422                     || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
3423             prevCh = ch;
3424             ++count;
3425         }
3426     }
3427     if ( count > 0 ) {
3428         // last item
3429         level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE];
3430             if ( fieldLevel <= level ) {
3431                 return FALSE;
3432             }
3433     }
3434     return TRUE;
3435 }
3436 
3437 //----------------------------------------------------------------------
3438 
3439 const Locale&
getSmpFmtLocale(void) const3440 SimpleDateFormat::getSmpFmtLocale(void) const {
3441     return fLocale;
3442 }
3443 
3444 //----------------------------------------------------------------------
3445 
3446 int32_t
checkIntSuffix(const UnicodeString & text,int32_t start,int32_t patLoc,UBool isNegative) const3447 SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,
3448                                  int32_t patLoc, UBool isNegative) const {
3449     // local variables
3450     UnicodeString suf;
3451     int32_t patternMatch;
3452     int32_t textPreMatch;
3453     int32_t textPostMatch;
3454 
3455     // check that we are still in range
3456     if ( (start > text.length()) ||
3457          (start < 0) ||
3458          (patLoc < 0) ||
3459          (patLoc > fPattern.length())) {
3460         // out of range, don't advance location in text
3461         return start;
3462     }
3463 
3464     // get the suffix
3465     DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
3466     if (decfmt != NULL) {
3467         if (isNegative) {
3468             suf = decfmt->getNegativeSuffix(suf);
3469         }
3470         else {
3471             suf = decfmt->getPositiveSuffix(suf);
3472         }
3473     }
3474 
3475     // check for suffix
3476     if (suf.length() <= 0) {
3477         return start;
3478     }
3479 
3480     // check suffix will be encountered in the pattern
3481     patternMatch = compareSimpleAffix(suf,fPattern,patLoc);
3482 
3483     // check if a suffix will be encountered in the text
3484     textPreMatch = compareSimpleAffix(suf,text,start);
3485 
3486     // check if a suffix was encountered in the text
3487     textPostMatch = compareSimpleAffix(suf,text,start-suf.length());
3488 
3489     // check for suffix match
3490     if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) {
3491         return start;
3492     }
3493     else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) {
3494         return  start - suf.length();
3495     }
3496 
3497     // should not get here
3498     return start;
3499 }
3500 
3501 //----------------------------------------------------------------------
3502 
3503 int32_t
compareSimpleAffix(const UnicodeString & affix,const UnicodeString & input,int32_t pos) const3504 SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
3505                    const UnicodeString& input,
3506                    int32_t pos) const {
3507     int32_t start = pos;
3508     for (int32_t i=0; i<affix.length(); ) {
3509         UChar32 c = affix.char32At(i);
3510         int32_t len = U16_LENGTH(c);
3511         if (PatternProps::isWhiteSpace(c)) {
3512             // We may have a pattern like: \u200F \u0020
3513             //        and input text like: \u200F \u0020
3514             // Note that U+200F and U+0020 are Pattern_White_Space but only
3515             // U+0020 is UWhiteSpace.  So we have to first do a direct
3516             // match of the run of Pattern_White_Space in the pattern,
3517             // then match any extra characters.
3518             UBool literalMatch = FALSE;
3519             while (pos < input.length() &&
3520                    input.char32At(pos) == c) {
3521                 literalMatch = TRUE;
3522                 i += len;
3523                 pos += len;
3524                 if (i == affix.length()) {
3525                     break;
3526                 }
3527                 c = affix.char32At(i);
3528                 len = U16_LENGTH(c);
3529                 if (!PatternProps::isWhiteSpace(c)) {
3530                     break;
3531                 }
3532             }
3533 
3534             // Advance over run in pattern
3535             i = skipPatternWhiteSpace(affix, i);
3536 
3537             // Advance over run in input text
3538             // Must see at least one white space char in input,
3539             // unless we've already matched some characters literally.
3540             int32_t s = pos;
3541             pos = skipUWhiteSpace(input, pos);
3542             if (pos == s && !literalMatch) {
3543                 return -1;
3544             }
3545 
3546             // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
3547             // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
3548             // is also in the affix.
3549             i = skipUWhiteSpace(affix, i);
3550         } else {
3551             if (pos < input.length() &&
3552                 input.char32At(pos) == c) {
3553                 i += len;
3554                 pos += len;
3555             } else {
3556                 return -1;
3557             }
3558         }
3559     }
3560     return pos - start;
3561 }
3562 
3563 //----------------------------------------------------------------------
3564 
3565 int32_t
skipPatternWhiteSpace(const UnicodeString & text,int32_t pos) const3566 SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const {
3567     const UChar* s = text.getBuffer();
3568     return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
3569 }
3570 
3571 //----------------------------------------------------------------------
3572 
3573 int32_t
skipUWhiteSpace(const UnicodeString & text,int32_t pos) const3574 SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const {
3575     while (pos < text.length()) {
3576         UChar32 c = text.char32At(pos);
3577         if (!u_isUWhiteSpace(c)) {
3578             break;
3579         }
3580         pos += U16_LENGTH(c);
3581     }
3582     return pos;
3583 }
3584 
3585 //----------------------------------------------------------------------
3586 
3587 // Lazy TimeZoneFormat instantiation, semantically const.
3588 TimeZoneFormat *
tzFormat() const3589 SimpleDateFormat::tzFormat() const {
3590     if (fTimeZoneFormat == NULL) {
3591         umtx_lock(&LOCK);
3592         {
3593             if (fTimeZoneFormat == NULL) {
3594                 UErrorCode status = U_ZERO_ERROR;
3595                 TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
3596                 U_ASSERT(U_SUCCESS(status));
3597 
3598                 const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
3599             }
3600         }
3601         umtx_unlock(&LOCK);
3602     }
3603     return fTimeZoneFormat;
3604 }
3605 U_NAMESPACE_END
3606 
3607 #endif /* #if !UCONFIG_NO_FORMATTING */
3608 
3609 //eof
3610