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