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