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