Issue #1971 - Part 2: Update ICU source to 63.2.

This commit is contained in:
Job Bautista 2022-07-24 21:03:27 +08:00 committed by roytam1
commit 1e69214382
3160 changed files with 275815 additions and 234203 deletions

View file

@ -1,4 +1,4 @@
// Copyright (C) 2016 and later: Unicode, Inc. and others.
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@ -48,10 +48,12 @@
#include "unicode/simpletz.h"
#include "unicode/rbtz.h"
#include "unicode/tzfmt.h"
#include "unicode/ucasemap.h"
#include "unicode/utf16.h"
#include "unicode/vtzone.h"
#include "unicode/udisplaycontext.h"
#include "unicode/brkiter.h"
#include "unicode/rbnf.h"
#include "uresimp.h"
#include "olsontz.h"
#include "patternprops.h"
@ -64,11 +66,14 @@
#include <float.h>
#include "smpdtfst.h"
#include "sharednumberformat.h"
#include "ucasemap_imp.h"
#include "ustr_imp.h"
#include "charstr.h"
#include "uvector.h"
#include "cstr.h"
#include "dayperiodrules.h"
#include "tznames_impl.h" // ZONE_NAME_U16_MAX
#include "number_utypes.h"
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
#include <stdio.h>
@ -239,9 +244,9 @@ SimpleDateFormat::NSOverride::~NSOverride() {
void SimpleDateFormat::NSOverride::free() {
NSOverride *cur = this;
while (cur) {
NSOverride *next = cur->next;
NSOverride *next_temp = cur->next;
delete cur;
cur = next;
cur = next_temp;
}
}
@ -309,57 +314,6 @@ const NumberFormat *SimpleDateFormat::getNumberFormatByIndex(
return &(**fSharedNumberFormatters[index]);
}
class SimpleDateFormatMutableNFNode {
public:
const NumberFormat *key;
NumberFormat *value;
SimpleDateFormatMutableNFNode()
: key(NULL), value(NULL) { }
~SimpleDateFormatMutableNFNode() {
delete value;
}
private:
SimpleDateFormatMutableNFNode(const SimpleDateFormatMutableNFNode &);
SimpleDateFormatMutableNFNode &operator=(const SimpleDateFormatMutableNFNode &);
};
// Single threaded cache of non const NumberFormats. Designed to be stack
// allocated and used for a single format call.
class SimpleDateFormatMutableNFs : public UMemory {
public:
SimpleDateFormatMutableNFs() {
}
// Returns a non-const clone of nf which can be safely modified.
// Subsequent calls with same nf will return the same non-const clone.
// This object maintains ownership of all returned non-const
// NumberFormat objects. On memory allocation error returns NULL.
// Caller must check for NULL return value.
NumberFormat *get(const NumberFormat *nf) {
if (nf == NULL) {
return NULL;
}
int32_t idx = 0;
while (nodes[idx].value) {
if (nf == nodes[idx].key) {
return nodes[idx].value;
}
++idx;
}
U_ASSERT(idx < UDAT_FIELD_COUNT);
nodes[idx].key = nf;
nodes[idx].value = (NumberFormat *) nf->clone();
return nodes[idx].value;
}
private:
// +1 extra for sentinel. If each field had its own NumberFormat, this
// cache would have to allocate UDAT_FIELD_COUNT mutable versions worst
// case.
SimpleDateFormatMutableNFNode nodes[UDAT_FIELD_COUNT + 1];
SimpleDateFormatMutableNFs(const SimpleDateFormatMutableNFs &);
SimpleDateFormatMutableNFs &operator=(const SimpleDateFormatMutableNFs &);
};
//----------------------------------------------------------------------
SimpleDateFormat::~SimpleDateFormat()
@ -371,6 +325,7 @@ SimpleDateFormat::~SimpleDateFormat()
if (fTimeZoneFormat) {
delete fTimeZoneFormat;
}
freeFastNumberFormatters();
#if !UCONFIG_NO_BREAK_ITERATION
delete fCapitalizationBrkIter;
@ -656,6 +611,10 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
}
}
UErrorCode localStatus = U_ZERO_ERROR;
freeFastNumberFormatters();
initFastNumberFormatters(localStatus);
return *this;
}
@ -905,7 +864,8 @@ SimpleDateFormat::initialize(const Locale& locale,
fixNumberFormatForDates(*fNumberFormat);
//fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
initNumberFormatters(locale,status);
initNumberFormatters(locale, status);
initFastNumberFormatters(status);
}
else if (U_SUCCESS(status))
@ -1020,11 +980,6 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
int32_t fieldNum = 0;
UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
// Create temporary cache of mutable number format objects. This way
// subFormat won't have to clone the const NumberFormat for each field.
// if several fields share the same NumberFormat, which will almost
// always be the case, this is a big save.
SimpleDateFormatMutableNFs mutableNFs;
// loop through the pattern string character by character
for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
UChar ch = fPattern[i];
@ -1032,7 +987,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
// Use subFormat() to format a repeated pattern character
// when a different pattern or non-pattern character is seen
if (ch != prevCh && count > 0) {
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status);
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
count = 0;
}
if (ch == QUOTE) {
@ -1059,7 +1014,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
// Format the last item in the pattern, if any
if (count > 0) {
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status);
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
}
if (calClone != NULL) {
@ -1254,6 +1209,43 @@ _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeSt
}
//----------------------------------------------------------------------
static number::LocalizedNumberFormatter*
createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt) {
return new number::LocalizedNumberFormatter(
df->toNumberFormatter()
.integerWidth(number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)));
}
void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
auto* df = dynamic_cast<const DecimalFormat*>(fNumberFormat);
if (df == nullptr) {
return;
}
fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10);
fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10);
fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10);
fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10);
fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2);
}
void SimpleDateFormat::freeFastNumberFormatters() {
delete fFastNumberFormatters[SMPDTFMT_NF_1x10];
delete fFastNumberFormatters[SMPDTFMT_NF_2x10];
delete fFastNumberFormatters[SMPDTFMT_NF_3x10];
delete fFastNumberFormatters[SMPDTFMT_NF_4x10];
delete fFastNumberFormatters[SMPDTFMT_NF_2x2];
fFastNumberFormatters[SMPDTFMT_NF_1x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_2x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_3x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_4x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_2x2] = nullptr;
}
void
SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
if (U_FAILURE(status)) {
@ -1312,15 +1304,15 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
int32_t nsNameHash = nsName.hashCode();
// See if the numbering system is in the override list, if not, then add it.
NSOverride *cur = overrideList;
NSOverride *curr = overrideList;
const SharedNumberFormat *snf = NULL;
UBool found = FALSE;
while ( cur && !found ) {
if ( cur->hash == nsNameHash ) {
snf = cur->snf;
while ( curr && !found ) {
if ( curr->hash == nsNameHash ) {
snf = curr->snf;
found = TRUE;
}
cur = cur->next;
curr = curr->next;
}
if (!found) {
@ -1403,7 +1395,6 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
int32_t fieldNum,
FieldPositionHandler& handler,
Calendar& cal,
SimpleDateFormatMutableNFs &mutableNFs,
UErrorCode& status) const
{
if (U_FAILURE(status)) {
@ -1416,7 +1407,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
const int32_t maxIntCount = 10;
int32_t beginOffset = appendTo.length();
NumberFormat *currentNumberFormat;
const NumberFormat *currentNumberFormat;
DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);
@ -1441,9 +1432,9 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
return;
}
currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex));
currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
if (currentNumberFormat == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
status = U_INTERNAL_PROGRAM_ERROR;
return;
}
UnicodeString hebr("hebr", 4, US_INV);
@ -1563,18 +1554,15 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
case UDAT_FRACTIONAL_SECOND_FIELD:
// Fractional seconds left-justify
{
currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
currentNumberFormat->setMaximumIntegerDigits(maxIntCount);
int32_t minDigits = (count > 3) ? 3 : count;
if (count == 1) {
value /= 100;
} else if (count == 2) {
value /= 10;
}
FieldPosition p(FieldPosition::DONT_CARE);
currentNumberFormat->format(value, appendTo, p);
zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount);
if (count > 3) {
currentNumberFormat->setMinimumIntegerDigits(count - 3);
currentNumberFormat->format((int32_t)0, appendTo, p);
zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount);
}
}
break;
@ -1688,104 +1676,105 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
case UDAT_TIMEZONE_ISO_FIELD: // 'X'
case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
{
UChar zsbuf[64];
UChar zsbuf[ZONE_NAME_U16_MAX];
UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));
const TimeZone& tz = cal.getTimeZone();
UDate date = cal.getTime(status);
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
if (count < 4) {
// "z", "zz", "zzz"
tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
} else {
// "zzzz" or longer
tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
}
}
else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
if (count < 4) {
// "Z"
tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
} else if (count == 5) {
// "ZZZZZ"
tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
} else {
// "ZZ", "ZZZ", "ZZZZ"
tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
}
}
else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
if (count == 1) {
// "v"
tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
} else if (count == 4) {
// "vvvv"
tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
}
}
else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) {
if (count == 1) {
// "V"
tzFormat()->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
} else if (count == 2) {
// "VV"
tzFormat()->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
} else if (count == 3) {
// "VVV"
tzFormat()->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
} else if (count == 4) {
// "VVVV"
tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
}
}
else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) {
if (count == 1) {
// "O"
tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
} else if (count == 4) {
// "OOOO"
tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
}
}
else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) {
if (count == 1) {
// "X"
tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
} else if (count == 2) {
// "XX"
tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
} else if (count == 3) {
// "XXX"
tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
} else if (count == 4) {
// "XXXX"
tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
} else if (count == 5) {
// "XXXXX"
tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
}
}
else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) {
if (count == 1) {
// "x"
tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);
} else if (count == 2) {
// "xx"
tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);
} else if (count == 3) {
// "xxx"
tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);
} else if (count == 4) {
// "xxxx"
tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
} else if (count == 5) {
// "xxxxx"
tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
}
}
else {
@ -1835,14 +1824,14 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// Stealing am/pm value to use as our array index.
// It works out: am/midnight are both 0, pm/noon are both 1,
// 12 am is 12 midnight, and 12 pm is 12 noon.
int32_t value = cal.get(UCAL_AM_PM, status);
int32_t val = cal.get(UCAL_AM_PM, status);
if (count <= 3) {
toAppend = &fSymbols->fAbbreviatedDayPeriods[value];
toAppend = &fSymbols->fAbbreviatedDayPeriods[val];
} else if (count == 4 || count > 5) {
toAppend = &fSymbols->fWideDayPeriods[value];
toAppend = &fSymbols->fWideDayPeriods[val];
} else { // count == 5
toAppend = &fSymbols->fNarrowDayPeriods[value];
toAppend = &fSymbols->fNarrowDayPeriods[val];
}
}
@ -1852,7 +1841,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
if (toAppend == NULL || toAppend->isBogus()) {
// Reformat with identical arguments except ch, now changed to 'a'.
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, mutableNFs, status);
handler, cal, status);
} else {
appendTo += *toAppend;
}
@ -1873,7 +1862,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// Data doesn't exist for the locale we're looking for.
// Falling back to am/pm.
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, mutableNFs, status);
handler, cal, status);
break;
}
@ -1944,7 +1933,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
periodType == DayPeriodRules::DAYPERIOD_PM ||
toAppend->isBogus()) {
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, mutableNFs, status);
handler, cal, status);
}
else {
appendTo += *toAppend;
@ -2001,6 +1990,11 @@ void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
freeSharedNumberFormatters(fSharedNumberFormatters);
fSharedNumberFormatters = NULL;
}
// Also re-compute the fast formatters.
UErrorCode localStatus = U_ZERO_ERROR;
freeFastNumberFormatters();
initFastNumberFormatters(localStatus);
}
void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
@ -2052,16 +2046,58 @@ SimpleDateFormat::getNumberFormatForField(UChar field) const {
//----------------------------------------------------------------------
void
SimpleDateFormat::zeroPaddingNumber(
NumberFormat *currentNumberFormat,
const NumberFormat *currentNumberFormat,
UnicodeString &appendTo,
int32_t value, int32_t minDigits, int32_t maxDigits) const
{
if (currentNumberFormat!=NULL) {
FieldPosition pos(FieldPosition::DONT_CARE);
const number::LocalizedNumberFormatter* fastFormatter = nullptr;
// NOTE: This uses the heuristic that these five min/max int settings account for the vast majority
// of SimpleDateFormat number formatting cases at the time of writing (ICU 62).
if (currentNumberFormat == fNumberFormat) {
if (maxDigits == 10) {
if (minDigits == 1) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_1x10];
} else if (minDigits == 2) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x10];
} else if (minDigits == 3) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_3x10];
} else if (minDigits == 4) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_4x10];
}
} else if (maxDigits == 2) {
if (minDigits == 2) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x2];
}
}
}
if (fastFormatter != nullptr) {
// Can use fast path
number::impl::UFormattedNumberData result;
result.quantity.setToInt(value);
UErrorCode localStatus = U_ZERO_ERROR;
fastFormatter->formatImpl(&result, localStatus);
if (U_FAILURE(localStatus)) {
return;
}
appendTo.append(result.string.toTempUnicodeString());
return;
}
currentNumberFormat->setMinimumIntegerDigits(minDigits);
currentNumberFormat->setMaximumIntegerDigits(maxDigits);
currentNumberFormat->format(value, appendTo, pos); // 3rd arg is there to speed up processing
// Check for RBNF (no clone necessary)
auto* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(currentNumberFormat);
if (rbnf != nullptr) {
FieldPosition pos(FieldPosition::DONT_CARE);
rbnf->format(value, appendTo, pos); // 3rd arg is there to speed up processing
return;
}
// Fall back to slow path (clone and mutate the NumberFormat)
if (currentNumberFormat != nullptr) {
FieldPosition pos(FieldPosition::DONT_CARE);
LocalPointer<NumberFormat> nf(dynamic_cast<NumberFormat*>(currentNumberFormat->clone()));
nf->setMinimumIntegerDigits(minDigits);
nf->setMaximumIntegerDigits(maxDigits);
nf->format(value, appendTo, pos); // 3rd arg is there to speed up processing
}
}
@ -2128,7 +2164,6 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
int32_t saveHebrewMonth = -1;
int32_t count = 0;
UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
SimpleDateFormatMutableNFs mutableNFs;
// For parsing abutting numeric fields. 'abutPat' is the
// offset into 'pattern' of the first of 2 or more abutting
@ -2222,7 +2257,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
}
pos = subParse(text, pos, ch, count,
TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs);
TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType);
// If the parse fails anywhere in the run, back up to the
// start of the run and retry.
@ -2237,7 +2272,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// fields.
else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
int32_t s = subParse(text, pos, ch, count,
FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs, &dayPeriodInt);
FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, &dayPeriodInt);
if (s == -pos-1) {
// era not present, in special cases allow this to continue
@ -2246,10 +2281,10 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
if (i+1 < fPattern.length()) {
// move to next pattern character
UChar ch = fPattern.charAt(i+1);
UChar c = fPattern.charAt(i+1);
// check for whitespace
if (PatternProps::isWhiteSpace(ch)) {
if (PatternProps::isWhiteSpace(c)) {
i++;
// Advance over run in pattern
while ((i+1)<fPattern.length() &&
@ -2855,7 +2890,7 @@ SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
*/
int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs,
int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType,
int32_t *dayPeriod) const
{
Formattable number;
@ -2865,7 +2900,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
UErrorCode status = U_ZERO_ERROR;
ParsePosition pos(0);
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
NumberFormat *currentNumberFormat;
const NumberFormat *currentNumberFormat;
UnicodeString temp;
UBool gotNumber = FALSE;
@ -2877,7 +2912,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return -start;
}
currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex));
currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
if (currentNumberFormat == NULL) {
return -start;
}
@ -3051,9 +3086,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// is treated literally: "2250", "-1", "1", "002".
if (fDateOverride.compare(hebr)==0 && value < 1000) {
value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
} else if ((pos.getIndex() - start) == 2 && !isChineseCalendar
&& u_isdigit(text.charAt(start))
&& u_isdigit(text.charAt(start+1)))
} else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar
&& u_isdigit(text.char32At(start))
&& u_isdigit(text.char32At(text.moveIndex32(start, 1))))
{
// only adjust year for patterns less than 3.
if(count < 3) {
@ -3091,9 +3126,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// Comment is the same as for UDAT_Year_FIELDs - look above
if (fDateOverride.compare(hebr)==0 && value < 1000) {
value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
} else if ((pos.getIndex() - start) == 2
&& u_isdigit(text.charAt(start))
&& u_isdigit(text.charAt(start+1))
} else if (text.moveIndex32(start, 2) == pos.getIndex()
&& u_isdigit(text.char32At(start))
&& u_isdigit(text.char32At(text.moveIndex32(start, 1)))
&& fHaveDefaultCentury )
{
int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
@ -3127,8 +3162,8 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
UErrorCode status = U_ZERO_ERROR;
if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
UErrorCode monthStatus = U_ZERO_ERROR;
if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) {
cal.set(UCAL_MONTH, value);
} else {
cal.set(UCAL_MONTH, value - 1);
@ -3199,7 +3234,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
case UDAT_FRACTIONAL_SECOND_FIELD:
// Fractional seconds left-justify
i = pos.getIndex() - start;
i = countDigits(text, start, pos.getIndex());
if (i < 3) {
while (i < 3) {
value *= 10;
@ -3390,31 +3425,41 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
case UDAT_TIMEZONE_FIELD: // 'z'
{
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
}
return -start;
}
break;
case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
{
UTimeZoneFormatStyle style = (count < 4) ?
UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT);
TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
{
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
@ -3435,20 +3480,26 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
style = UTZFMT_STYLE_GENERIC_LOCATION;
break;
}
TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
{
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT;
TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
@ -3472,10 +3523,13 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
style = UTZFMT_STYLE_ISO_EXTENDED_FULL;
break;
}
TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
@ -3499,10 +3553,13 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;
break;
}
TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
@ -3514,21 +3571,21 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
// Try matching a time separator.
int32_t count = 1;
int32_t count_sep = 1;
UnicodeString data[3];
fSymbols->getTimeSeparatorString(data[0]);
// Add the default, if different from the locale.
if (data[0].compare(&def_sep, 1) != 0) {
data[count++].setTo(def_sep);
data[count_sep++].setTo(def_sep);
}
// If lenient, add also the alternate, if different from the locale.
if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
data[count++].setTo(alt_sep);
data[count_sep++].setTo(alt_sep);
}
return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, NULL, cal);
return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal);
}
case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
@ -3536,7 +3593,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
U_ASSERT(dayPeriod != NULL);
int32_t ampmStart = subParse(text, start, 0x61, count,
obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal,
patLoc, numericLeapMonthFormatter, tzTimeType, mutableNFs);
patLoc, numericLeapMonthFormatter, tzTimeType);
if (ampmStart > 0) {
return ampmStart;
@ -3617,7 +3674,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
parseInt(*src, number, pos, allowNegative,currentNumberFormat);
if (pos.getIndex() != parseStart) {
int32_t value = number.getLong();
int32_t val = number.getLong();
// Don't need suffix processing here (as in number processing at the beginning of the function);
// the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
@ -3625,7 +3682,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) {
// Check the range of the value
int32_t bias = gFieldRangeBias[patternCharIndex];
if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) {
return -start;
}
}
@ -3639,35 +3696,35 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
UErrorCode status = U_ZERO_ERROR;
if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
cal.set(UCAL_MONTH, value);
UErrorCode monthStatus = U_ZERO_ERROR;
if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) {
cal.set(UCAL_MONTH, val);
} else {
cal.set(UCAL_MONTH, value - 1);
cal.set(UCAL_MONTH, val - 1);
}
} else {
saveHebrewMonth = value;
saveHebrewMonth = val;
}
} else {
cal.set(UCAL_MONTH, value - 1);
cal.set(UCAL_MONTH, val - 1);
}
break;
case UDAT_STANDALONE_MONTH_FIELD:
cal.set(UCAL_MONTH, value - 1);
cal.set(UCAL_MONTH, val - 1);
break;
case UDAT_DOW_LOCAL_FIELD:
case UDAT_STANDALONE_DAY_FIELD:
cal.set(UCAL_DOW_LOCAL, value);
cal.set(UCAL_DOW_LOCAL, val);
break;
case UDAT_QUARTER_FIELD:
case UDAT_STANDALONE_QUARTER_FIELD:
cal.set(UCAL_MONTH, (value - 1) * 3);
cal.set(UCAL_MONTH, (val - 1) * 3);
break;
case UDAT_RELATED_YEAR_FIELD:
cal.setRelatedYear(value);
cal.setRelatedYear(val);
break;
default:
cal.set(field, value);
cal.set(field, val);
break;
}
return pos.getIndex();
@ -3683,7 +3740,7 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
Formattable& number,
ParsePosition& pos,
UBool allowNegative,
NumberFormat *fmt) const {
const NumberFormat *fmt) const {
parseInt(text, number, -1, pos, allowNegative,fmt);
}
@ -3695,18 +3752,21 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
int32_t maxDigits,
ParsePosition& pos,
UBool allowNegative,
NumberFormat *fmt) const {
const NumberFormat *fmt) const {
UnicodeString oldPrefix;
DecimalFormat* df = NULL;
if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
df->getNegativePrefix(oldPrefix);
auto* fmtAsDF = dynamic_cast<const DecimalFormat*>(fmt);
LocalPointer<DecimalFormat> df;
if (!allowNegative && fmtAsDF != nullptr) {
df.adoptInstead(dynamic_cast<DecimalFormat*>(fmtAsDF->clone()));
if (df.isNull()) {
// Memory allocation error
return;
}
df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
fmt = df.getAlias();
}
int32_t oldPos = pos.getIndex();
fmt->parse(text, number, pos);
if (df != NULL) {
df->setNegativePrefix(oldPrefix);
}
if (maxDigits > 0) {
// adjust the result to fit into
@ -3725,6 +3785,19 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
}
}
int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const {
int32_t numDigits = 0;
int32_t idx = start;
while (idx < end) {
UChar32 cp = text.char32At(idx);
if (u_isdigit(cp)) {
numDigits++;
}
idx += U16_LENGTH(cp);
}
return numDigits;
}
//----------------------------------------------------------------------
void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
@ -3840,7 +3913,13 @@ SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols
//----------------------------------------------------------------------
const TimeZoneFormat*
SimpleDateFormat::getTimeZoneFormat(void) const {
return (const TimeZoneFormat*)tzFormat();
// TimeZoneFormat initialization might fail when out of memory.
// If we always initialize TimeZoneFormat instance, we can return
// such status there. For now, this implementation lazily instantiates
// a TimeZoneFormat for performance optimization reasons, but cannot
// propagate such error (probably just out of memory case) to the caller.
UErrorCode status = U_ZERO_ERROR;
return (const TimeZoneFormat*)tzFormat(status);
}
//----------------------------------------------------------------------
@ -3892,7 +3971,7 @@ SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
if (U_SUCCESS(status)) {
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
UErrorCode status = U_ZERO_ERROR;
status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
@ -4107,12 +4186,11 @@ SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const
// Lazy TimeZoneFormat instantiation, semantically const.
TimeZoneFormat *
SimpleDateFormat::tzFormat() const {
SimpleDateFormat::tzFormat(UErrorCode &status) const {
if (fTimeZoneFormat == NULL) {
umtx_lock(&LOCK);
{
if (fTimeZoneFormat == NULL) {
UErrorCode status = U_ZERO_ERROR;
TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
if (U_FAILURE(status)) {
return NULL;