/** * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All * locales use the same these unlocalized pattern characters.
*/ staticconst char16_t gPatternChars[] = { // if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR: // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB: // else: // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB
/** * Map of each ASCII character to its corresponding index in the table above if * it is a pattern character and -1 otherwise.
*/ staticconst int8_t gLookupPatternChars[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ! " # $ % & ' ( ) * + , - . /
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, #else // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, #endif // @ A B C D E F G H I J K L M N O
-1, 22, 36, -1, 10, 9, 11, 0, 5, -1, -1, 16, 26, 2, -1, 31, // P Q R S T U V W X Y Z [ \ ] ^ _
-1, 27, -1, 8, -1, 30, 29, 13, 32, 18, 23, -1, -1, -1, -1, -1, // ` a b c d e f g h i j k l m n o
-1, 14, 35, 25, 3, 19, -1, 21, 15, -1, -1, 4, -1, 6, -1, -1, // p q r s t u v w x y z { | } ~
-1, 28, 34, 7, -1, 20, 24, 12, 33, 1, 17, -1, -1, -1, -1, -1
};
//------------------------------------------------------ // Strings of last resort. These are only used if we have no resource // files. They aren't designed for actual use, just for backup.
// These are the weekday names and abbreviations of last resort. staticconst char16_t gLastResortDayNames[8][2] =
{
{0x0030, 0x0000}, /* "0" */
{0x0031, 0x0000}, /* "1" */
{0x0032, 0x0000}, /* "2" */
{0x0033, 0x0000}, /* "3" */
{0x0034, 0x0000}, /* "4" */
{0x0035, 0x0000}, /* "5" */
{0x0036, 0x0000}, /* "6" */
{0x0037, 0x0000} /* "7" */
};
// These are the quarter names and abbreviations of last resort. staticconst char16_t gLastResortQuarters[4][2] =
{
{0x0031, 0x0000}, /* "1" */
{0x0032, 0x0000}, /* "2" */
{0x0033, 0x0000}, /* "3" */
{0x0034, 0x0000}, /* "4" */
};
// These are the am/pm and BC/AD markers of last resort. staticconst char16_t gLastResortAmPmMarkers[2][3] =
{
{0x0041, 0x004D, 0x0000}, /* "AM" */
{0x0050, 0x004D, 0x0000} /* "PM" */
};
void
DateFormatSymbols::assignArray(UnicodeString*& dstArray,
int32_t& dstCount, const UnicodeString* srcArray,
int32_t srcCount)
{ // assignArray() is only called by copyData() and initializeData(), which in turn // implements the copy constructor and the assignment operator. // All strings in a DateFormatSymbols object are created in one of the following // three ways that all allow to safely use UnicodeString::fastCopyFrom(): // - readonly-aliases from resource bundles // - readonly-aliases or allocated strings from constants // - safely cloned strings (with owned buffers) from setXYZ() functions // // Note that this is true for as long as DateFormatSymbols can be constructed // only from a locale bundle or set via the cloning API, // *and* for as long as all the strings are in *private* fields, preventing // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()). if(srcArray == nullptr) { // Do not attempt to copy bogus input (which will crash). // Note that this assignArray method already had the potential to return a null dstArray; // see handling below for "if(dstArray != nullptr)".
dstCount = 0;
dstArray = nullptr; return;
}
dstCount = srcCount;
dstArray = newUnicodeStringArray(srcCount); if(dstArray != nullptr) {
int32_t i; for(i=0; i<srcCount; ++i) {
dstArray[i].fastCopyFrom(srcArray[i]);
}
}
}
/** * Create a copy, in fZoneStrings, of the given zone strings array. The * member variables fZoneStringsRowCount and fZoneStringsColCount should * be set already by the caller.
*/ void
DateFormatSymbols::createZoneStrings(const UnicodeString *const * otherStrings)
{
int32_t row, col;
UBool failed = false;
fZoneStrings = static_cast<UnicodeString**>(uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString*))); if (fZoneStrings != nullptr) { for (row=0; row<fZoneStringsRowCount; ++row)
{
fZoneStrings[row] = newUnicodeStringArray(fZoneStringsColCount); if (fZoneStrings[row] == nullptr) {
failed = true; break;
} for (col=0; col<fZoneStringsColCount; ++col) { // fastCopyFrom() - see assignArray comments
fZoneStrings[row][col].fastCopyFrom(otherStrings[row][col]);
}
}
} // If memory allocation failed, roll back and delete fZoneStrings if (failed) { for (int i = row; i >= 0; i--) { delete[] fZoneStrings[i];
}
uprv_free(fZoneStrings);
fZoneStrings = nullptr;
}
}
} else {
fZoneStrings = nullptr;
fZoneStringsColCount = 0;
fZoneStringsRowCount = 0;
}
fZSFLocale = other.fZSFLocale; // Other zone strings data is created on demand
fLocaleZoneStrings = nullptr;
// fastCopyFrom() - see assignArray comments
fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
void
DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count)
{ // delete the old list if we own it delete[] fEras;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fEras = newUnicodeStringArray(count);
uprv_arrayCopy(erasArray,fEras, count);
fErasCount = count;
}
void
DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count)
{ // delete the old list if we own it delete[] fEraNames;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fEraNames = newUnicodeStringArray(count);
uprv_arrayCopy(eraNamesArray,fEraNames, count);
fEraNamesCount = count;
}
void
DateFormatSymbols::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count)
{ // delete the old list if we own it delete[] fNarrowEras;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fNarrowEras = newUnicodeStringArray(count);
uprv_arrayCopy(narrowErasArray,fNarrowEras, count);
fNarrowErasCount = count;
}
void
DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count)
{ // delete the old list if we own it delete[] fMonths;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fMonths,count);
fMonthsCount = count;
}
void
DateFormatSymbols::setShortMonths(const UnicodeString* shortMonthsArray, int32_t count)
{ // delete the old list if we own it delete[] fShortMonths;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fShortMonths = newUnicodeStringArray(count);
uprv_arrayCopy(shortMonthsArray,fShortMonths, count);
fShortMonthsCount = count;
}
void
DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, DtContextType context, DtWidthType width)
{ // delete the old list if we own it // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count)
{ // delete the old list if we own it delete[] fWeekdays;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray,fWeekdays,count);
fWeekdaysCount = count;
}
void
DateFormatSymbols::setShortWeekdays(const UnicodeString* shortWeekdaysArray, int32_t count)
{ // delete the old list if we own it delete[] fShortWeekdays;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fShortWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(shortWeekdaysArray, fShortWeekdays, count);
fShortWeekdaysCount = count;
}
void
DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count, DtContextType context, DtWidthType width)
{ // delete the old list if we own it // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
void
DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count, DtContextType context, DtWidthType width)
{ // delete the old list if we own it // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
void
DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count)
{ // delete the old list if we own it delete[] fAmPms;
// we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fAmPms = newUnicodeStringArray(count);
uprv_arrayCopy(amPmsArray,fAmPms,count);
fAmPmsCount = count;
}
umtx_lock(&LOCK); if (fZoneStrings == nullptr) { if (fLocaleZoneStrings == nullptr) { const_cast<DateFormatSymbols*>(this)->initZoneStringsArray();
}
result = (const UnicodeString**)fLocaleZoneStrings;
} else {
result = (const UnicodeString**)fZoneStrings;
}
rowCount = fZoneStringsRowCount;
columnCount = fZoneStringsColCount;
umtx_unlock(&LOCK);
return result;
}
// For now, we include all zones #define ZONE_SET UCAL_ZONE_TYPE_ANY
// This code must be called within a synchronized block void
DateFormatSymbols::initZoneStringsArray() { if (fZoneStrings != nullptr || fLocaleZoneStrings != nullptr) { return;
}
if (U_FAILURE(status)) { if (zarray) { for (int32_t i = 0; i < rows; i++) { if (zarray[i]) { delete[] zarray[i];
}
}
uprv_free(zarray);
zarray = nullptr;
}
}
void
DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount)
{ // since deleting a 2-d array is a pain in the butt, we offload that task to // a separate function
disposeZoneStrings(); // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in)
fZoneStringsRowCount = rowCount;
fZoneStringsColCount = columnCount;
createZoneStrings(const_cast<const UnicodeString**>(strings));
}
staticconst uint64_t kNumericFieldsAlways =
(static_cast<uint64_t>(1) << UDAT_YEAR_FIELD) | // y
(static_cast<uint64_t>(1) << UDAT_DATE_FIELD) | // d
(static_cast<uint64_t>(1) << UDAT_HOUR_OF_DAY1_FIELD) | // k
(static_cast<uint64_t>(1) << UDAT_HOUR_OF_DAY0_FIELD) | // H
(static_cast<uint64_t>(1) << UDAT_MINUTE_FIELD) | // m
(static_cast<uint64_t>(1) << UDAT_SECOND_FIELD) | // s
(static_cast<uint64_t>(1) << UDAT_FRACTIONAL_SECOND_FIELD) | // S
(static_cast<uint64_t>(1) << UDAT_DAY_OF_YEAR_FIELD) | // D
(static_cast<uint64_t>(1) << UDAT_DAY_OF_WEEK_IN_MONTH_FIELD) | // F
(static_cast<uint64_t>(1) << UDAT_WEEK_OF_YEAR_FIELD) | // w
(static_cast<uint64_t>(1) << UDAT_WEEK_OF_MONTH_FIELD) | // W
(static_cast<uint64_t>(1) << UDAT_HOUR1_FIELD) | // h
(static_cast<uint64_t>(1) << UDAT_HOUR0_FIELD) | // K
(static_cast<uint64_t>(1) << UDAT_YEAR_WOY_FIELD) | // Y
(static_cast<uint64_t>(1) << UDAT_EXTENDED_YEAR_FIELD) | // u
(static_cast<uint64_t>(1) << UDAT_JULIAN_DAY_FIELD) | // g
(static_cast<uint64_t>(1) << UDAT_MILLISECONDS_IN_DAY_FIELD) | // A
(static_cast<uint64_t>(1) << UDAT_RELATED_YEAR_FIELD); // r
staticconst uint64_t kNumericFieldsForCount12 =
(static_cast<uint64_t>(1) << UDAT_MONTH_FIELD) | // M or MM
(static_cast<uint64_t>(1) << UDAT_DOW_LOCAL_FIELD) | // e or ee
(static_cast<uint64_t>(1) << UDAT_STANDALONE_DAY_FIELD) | // c or cc
(static_cast<uint64_t>(1) << UDAT_STANDALONE_MONTH_FIELD) | // L or LL
(static_cast<uint64_t>(1) << UDAT_QUARTER_FIELD) | // Q or QQ
(static_cast<uint64_t>(1) << UDAT_STANDALONE_QUARTER_FIELD); // q or qq
// ResourceSink to enumerate all calendar resources struct CalendarDataSink : public ResourceSink {
// Enum which specifies the type of alias received, or no alias enum AliasType {
SAME_CALENDAR,
DIFFERENT_CALENDAR,
GREGORIAN,
NONE
};
// Data structures to store resources from the current resource bundle
Hashtable arrays;
Hashtable arraySizes;
Hashtable maps; /** * Whenever there are aliases, the same object will be added twice to 'map'. * To avoid double deletion, 'maps' won't take ownership of the objects. Instead, * 'mapRefs' will own them and will delete them when CalendarDataSink is deleted.
*/
MemoryPool<Hashtable> mapRefs;
// Paths and the aliases they point to
UVector aliasPathPairs;
// Current and next calendar resource table which should be loaded
UnicodeString currentCalendarType;
UnicodeString nextCalendarType;
// Resources to visit when enumerating fallback calendars
LocalPointer<UVector> resourcesToVisit;
// Alias' relative path populated whenever an alias is read
UnicodeString aliasRelativePath;
// Stores the resources to visit on the next calendar.
LocalPointer<UVector> resourcesToVisitNext(nullptr);
ResourceTable calendarData = value.getTable(errorCode); if (U_FAILURE(errorCode)) { return; }
// Enumerate all resources for this calendar for (int i = 0; calendarData.getKeyAndValue(i, key, value); i++) {
UnicodeString keyUString(key, -1, US_INV);
// == Handle aliases ==
AliasType aliasType = processAliasFromValue(keyUString, value, errorCode); if (U_FAILURE(errorCode)) { return; } if (aliasType == GREGORIAN) { // Ignore aliases to the gregorian calendar, all of its resources will be loaded anyway. continue;
} elseif (aliasType == DIFFERENT_CALENDAR) { // Whenever an alias to the next calendar (except gregorian) is encountered, register the // calendar type it's pointing to if (resourcesToVisitNext.isNull()) {
resourcesToVisitNext
.adoptInsteadAndCheckErrorCode(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, errorCode),
errorCode); if (U_FAILURE(errorCode)) { return; }
}
LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
resourcesToVisitNext->adoptElement(aliasRelativePathCopy.orphan(), errorCode); if (U_FAILURE(errorCode)) { return; } continue;
// Only visit the resources that were referenced by an alias on the previous calendar // (AmPmMarkersAbbr is an exception). if (!resourcesToVisit.isNull() && !resourcesToVisit->isEmpty() && !resourcesToVisit->contains(&keyUString)
&& uprv_strcmp(key, gAmPmMarkersAbbrTag) != 0) { continue; }
// Iterate over all the elements of the table and add them to the map for (int i = 0; table.getKeyAndValue(i, key, value); i++) {
UnicodeString keyUString(key, -1, US_INV);
// Ignore '%variant' keys if (keyUString.endsWith(kVariantTagUChar, UPRV_LENGTHOF(kVariantTagUChar))) { continue;
}
// == Handle String elements == if (value.getType() == URES_STRING) { // We are on a leaf, store the map elements into the stringMap if (i == 0) { // mapRefs will keep ownership of 'stringMap':
stringMap = mapRefs.create(false, errorCode); if (stringMap == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR; return;
}
maps.put(path, stringMap, errorCode); if (U_FAILURE(errorCode)) { return; }
stringMap->setValueDeleter(uprv_deleteUObject);
}
U_ASSERT(stringMap != nullptr);
int32_t valueStringSize; const char16_t *valueString = value.getString(valueStringSize, errorCode); if (U_FAILURE(errorCode)) { return; }
LocalPointer<UnicodeString> valueUString(new UnicodeString(true, valueString, valueStringSize), errorCode);
stringMap->put(keyUString, valueUString.orphan(), errorCode); if (U_FAILURE(errorCode)) { return; } continue;
}
U_ASSERT(stringMap == nullptr);
// Store the current path's length and append the current key to the path.
int32_t pathLength = path.length();
path.append(SOLIDUS).append(keyUString);
// In cyclicNameSets ignore everything but years/format/abbreviated // and zodiacs/format/abbreviated if (path.startsWith(kCyclicNameSetsTagUChar, UPRV_LENGTHOF(kCyclicNameSetsTagUChar))) {
UBool skip = true;
int32_t startIndex = UPRV_LENGTHOF(kCyclicNameSetsTagUChar);
int32_t length = 0; if (startIndex == path.length()
|| path.compare(startIndex, (length = UPRV_LENGTHOF(kZodiacsUChar)), kZodiacsUChar, 0, UPRV_LENGTHOF(kZodiacsUChar)) == 0
|| path.compare(startIndex, (length = UPRV_LENGTHOF(kYearsTagUChar)), kYearsTagUChar, 0, UPRV_LENGTHOF(kYearsTagUChar)) == 0
|| path.compare(startIndex, (length = UPRV_LENGTHOF(kDayPartsTagUChar)), kDayPartsTagUChar, 0, UPRV_LENGTHOF(kDayPartsTagUChar)) == 0) {
startIndex += length;
length = 0; if (startIndex == path.length()
|| path.compare(startIndex, (length = UPRV_LENGTHOF(kFormatTagUChar)), kFormatTagUChar, 0, UPRV_LENGTHOF(kFormatTagUChar)) == 0) {
startIndex += length;
length = 0; if (startIndex == path.length()
|| path.compare(startIndex, (length = UPRV_LENGTHOF(kAbbrTagUChar)), kAbbrTagUChar, 0, UPRV_LENGTHOF(kAbbrTagUChar)) == 0) {
skip = false;
}
}
} if (skip) { // Drop the latest key on the path and continue
path.retainBetween(0, pathLength); continue;
}
}
// == Handle aliases == if (arrays.get(path) != nullptr || maps.get(path) != nullptr) { // Drop the latest key on the path and continue
path.retainBetween(0, pathLength); continue;
}
AliasType aliasType = processAliasFromValue(path, value, errorCode); if (U_FAILURE(errorCode)) { return; } if (aliasType == SAME_CALENDAR) { // Store the alias path and the current path on aliasPathPairs
LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
aliasPathPairs.adoptElement(aliasRelativePathCopy.orphan(), errorCode); if (U_FAILURE(errorCode)) { return; }
LocalPointer<UnicodeString> pathCopy(path.clone(), errorCode);
aliasPathPairs.adoptElement(pathCopy.orphan(), errorCode); if (U_FAILURE(errorCode)) { return; }
// Drop the latest key on the path and continue
path.retainBetween(0, pathLength); continue;
}
U_ASSERT(aliasType == NONE);
// == Handle data == if (value.getType() == URES_ARRAY) { // We are on a leaf, store the array
ResourceArray rDataArray = value.getArray(errorCode);
int32_t dataArraySize = rDataArray.getSize();
LocalArray<UnicodeString> dataArray(new UnicodeString[dataArraySize], errorCode);
value.getStringArray(dataArray.getAlias(), dataArraySize, errorCode);
arrays.put(path, dataArray.orphan(), errorCode);
arraySizes.puti(path, dataArraySize, errorCode); if (U_FAILURE(errorCode)) { return; }
} elseif (value.getType() == URES_TABLE) { // We are not on a leaf, recursively process the subtable.
processResource(path, key, value, errorCode); if (U_FAILURE(errorCode)) { return; }
}
// Drop the latest key on the path
path.retainBetween(0, pathLength);
}
}
// Populates an AliasIdentifier with the alias information contained on the UResource.Value.
AliasType processAliasFromValue(UnicodeString ¤tRelativePath, ResourceValue &value,
UErrorCode &errorCode) { if (U_FAILURE(errorCode)) { return NONE; }
if (currentCalendarType == aliasCalendarType
&& currentRelativePath != aliasRelativePath) { // If we have an alias to the same calendar, the path to the resource must be different return SAME_CALENDAR;
} elseif (currentCalendarType != aliasCalendarType
&& currentRelativePath == aliasRelativePath) { // If we have an alias to a different calendar, the path to the resource must be the same if (aliasCalendarType.compare(kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)) == 0) { return GREGORIAN;
} elseif (nextCalendarType.isBogus()) {
nextCalendarType = aliasCalendarType; return DIFFERENT_CALENDAR;
} elseif (nextCalendarType == aliasCalendarType) { return DIFFERENT_CALENDAR;
}
}
}
}
errorCode = U_INTERNAL_PROGRAM_ERROR; return NONE;
} return NONE;
}
// Deleter function to be used by 'arrays' staticvoid U_CALLCONV deleteUnicodeStringArray(void *uArray) { delete[] static_cast<UnicodeString *>(uArray);
}
}; // Virtual destructors have to be defined out of line
CalendarDataSink::~CalendarDataSink() {
arrays.setValueDeleter(deleteUnicodeStringArray);
}
}
// Resource keys to look up localized strings for day periods. // The first one must be midnight and the second must be noon, so that their indices coincide // with the am/pm field. Formatting and parsing code for day periods relies on this coincidence. staticconstchar *dayPeriodKeys[] = {"midnight", "noon", "morning1", "afternoon1", "evening1", "night1", "morning2", "afternoon2", "evening2", "night2"};
// We need to preserve the requested locale for // lazy ZoneStringFormat instantiation. ZoneStringFormat // is region sensitive, thus, bundle locale bundle's locale // is not sufficient.
fZSFLocale = locale;
if (U_FAILURE(status)) return;
// Create a CalendarDataSink to process this data and the resource bundles
CalendarDataSink calendarSink(status);
LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getBaseName(), &status));
LocalUResourceBundlePointer cb(ures_getByKey(rb.getAlias(), gCalendarTag, nullptr, &status));
if (U_FAILURE(status)) return;
// Iterate over the resource bundle data following the fallbacks through different calendar types
UnicodeString calendarType((type != nullptr && *type != '\0')? type : gGregorianTag, -1, US_INV); while (!calendarType.isBogus()) {
CharString calendarTypeBuffer;
calendarTypeBuffer.appendInvariantChars(calendarType, status); if (U_FAILURE(status)) { return; } constchar *calendarTypeCArray = calendarTypeBuffer.data();
// Enumerate this calendar type. If the calendar is not found fallback to gregorian
UErrorCode oldStatus = status;
LocalUResourceBundlePointer ctb(ures_getByKeyWithFallback(cb.getAlias(), calendarTypeCArray, nullptr, &status)); if (status == U_MISSING_RESOURCE_ERROR) { if (uprv_strcmp(calendarTypeCArray, gGregorianTag) != 0) {
calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar));
calendarSink.visitAllResources();
status = oldStatus; continue;
} return;
}
calendarSink.preEnumerate(calendarType);
ures_getAllItemsWithFallback(ctb.getAlias(), "", calendarSink, status); if (U_FAILURE(status)) break;
// Stop loading when gregorian was loaded if (uprv_strcmp(calendarTypeCArray, gGregorianTag) == 0) { break;
}
// Get the next calendar type to process from the sink
calendarType = calendarSink.nextCalendarType;
// Gregorian is always the last fallback if (calendarType.isBogus()) {
calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar));
calendarSink.visitAllResources();
}
}
// CharString object to build paths
CharString path;
// Load Leap Month Patterns
UErrorCode tempStatus = status;
fLeapMonthPatterns = newUnicodeStringArray(kMonthPatternsCount); if (fLeapMonthPatterns) {
initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatWide, calendarSink,
buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesWideTag, tempStatus), tempStatus);
initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatAbbrev, calendarSink,
buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus);
initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatNarrow, calendarSink,
buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesNarrowTag, tempStatus), tempStatus);
initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneWide, calendarSink,
buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesWideTag, tempStatus), tempStatus);
initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneAbbrev, calendarSink,
buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesAbbrTag, tempStatus), tempStatus);
initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneNarrow, calendarSink,
buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesNarrowTag, tempStatus), tempStatus);
initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternNumeric, calendarSink,
buildResourcePath(path, gMonthPatternsTag, gNamesNumericTag, gNamesAllTag, tempStatus), tempStatus); if (U_SUCCESS(tempStatus)) { // Hack to fix bad C inheritance for dangi monthPatterns (OK in J); this should be handled by aliases in root, but isn't. // The ordering of the following statements is important. if (fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
} if (fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].setTo(fLeapMonthPatterns[kLeapMonthPatternStandaloneNarrow]);
} if (fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
} if (fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev]);
} // end of hack
fLeapMonthPatternsCount = kMonthPatternsCount;
} else { delete[] fLeapMonthPatterns;
fLeapMonthPatterns = nullptr;
}
}
// Fill in for missing/bogus items (dayPeriods are a map so single items might be missing) if (U_SUCCESS(status)) { for (int32_t dpidx = 0; dpidx < fAbbreviatedDayPeriodsCount; ++dpidx) { if (dpidx < fWideDayPeriodsCount && fWideDayPeriods != nullptr && fWideDayPeriods[dpidx].isBogus()) {
fWideDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
} if (dpidx < fNarrowDayPeriodsCount && fNarrowDayPeriods != nullptr && fNarrowDayPeriods[dpidx].isBogus()) {
fNarrowDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
} if (dpidx < fStandaloneAbbreviatedDayPeriodsCount && fStandaloneAbbreviatedDayPeriods != nullptr && fStandaloneAbbreviatedDayPeriods[dpidx].isBogus()) {
fStandaloneAbbreviatedDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
} if (dpidx < fStandaloneWideDayPeriodsCount && fStandaloneWideDayPeriods != nullptr && fStandaloneWideDayPeriods[dpidx].isBogus()) {
fStandaloneWideDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]);
} if (dpidx < fStandaloneNarrowDayPeriodsCount && fStandaloneNarrowDayPeriods != nullptr && fStandaloneNarrowDayPeriods[dpidx].isBogus()) {
fStandaloneNarrowDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]);
}
}
}
U_LOCALE_BASED(locBased, *this); // if we make it to here, the resource data is cool, and we can get everything out // of it that we need except for the time-zone and localized-pattern data, which // are stored in a separate file
locBased.setLocaleIDs(ures_getLocaleByType(cb.getAlias(), ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(cb.getAlias(), ULOC_ACTUAL_LOCALE, &status));
// Load eras
initField(&fEras, fErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesAbbrTag, status), status);
UErrorCode oldStatus = status;
initField(&fEraNames, fEraNamesCount, calendarSink, buildResourcePath(path, gErasTag, gNamesWideTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3
status = oldStatus;
assignArray(fEraNames, fEraNamesCount, fEras, fErasCount);
} // current ICU4J falls back to abbreviated if narrow eras are missing, so we will too
oldStatus = status;
initField(&fNarrowEras, fNarrowErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesNarrowTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3
status = oldStatus;
assignArray(fNarrowEras, fNarrowErasCount, fEras, fErasCount);
}
// Load month names
initField(&fMonths, fMonthsCount, calendarSink,
buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesWideTag, status), status);
initField(&fShortMonths, fShortMonthsCount, calendarSink,
buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesAbbrTag, status), status);
initField(&fStandaloneMonths, fStandaloneMonthsCount, calendarSink,
buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide not available, use format/wide */
status = U_ZERO_ERROR;
assignArray(fStandaloneMonths, fStandaloneMonthsCount, fMonths, fMonthsCount);
}
initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calendarSink,
buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated not available, use format/abbreviated */
status = U_ZERO_ERROR;
assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, fShortMonths, fShortMonthsCount);
}
UErrorCode narrowMonthsEC = status;
UErrorCode standaloneNarrowMonthsEC = status;
initField(&fNarrowMonths, fNarrowMonthsCount, calendarSink,
buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesNarrowTag, narrowMonthsEC), narrowMonthsEC);
initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calendarSink,
buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, narrowMonthsEC), standaloneNarrowMonthsEC); if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC != U_MISSING_RESOURCE_ERROR) { // If format/narrow not available, use standalone/narrow
assignArray(fNarrowMonths, fNarrowMonthsCount, fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount);
} elseif (narrowMonthsEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) { // If standalone/narrow not available, use format/narrow
assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fNarrowMonths, fNarrowMonthsCount);
} elseif (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) { // If neither is available, use format/abbreviated
assignArray(fNarrowMonths, fNarrowMonthsCount, fShortMonths, fShortMonthsCount);
assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fShortMonths, fShortMonthsCount);
}
// Load AM/PM markers; if wide or narrow not available, use short
UErrorCode ampmStatus = U_ZERO_ERROR;
initField(&fAmPms, fAmPmsCount, calendarSink,
buildResourcePath(path, gAmPmMarkersTag, ampmStatus), ampmStatus); if (U_FAILURE(ampmStatus)) {
initField(&fAmPms, fAmPmsCount, calendarSink,
buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
}
ampmStatus = U_ZERO_ERROR;
initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
buildResourcePath(path, gAmPmMarkersNarrowTag, ampmStatus), ampmStatus); if (U_FAILURE(ampmStatus)) {
initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
} if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
assignArray(fNarrowAmPms, fNarrowAmPmsCount, fAmPms, fAmPmsCount);
}
// unlike the fields above, narrow format quarters fall back on narrow standalone quarters
initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, calendarSink,
buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
initField(&fNarrowQuarters, fNarrowQuartersCount, calendarSink,
buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesNarrowTag, status), status); if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
assignArray(fNarrowQuarters, fNarrowQuartersCount, fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount);
}
// ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597) /* // fastCopyFrom()/setTo() - see assignArray comments resStr = ures_getStringByKey(fResourceBundle, gLocalPatternCharsTag, &len, &status); fLocalPatternChars.setTo(true, resStr, len); // If the locale data does not include new pattern chars, use the defaults // TODO: Consider making this an error, since this may add conflicting characters. if (len < PATTERN_CHARS_LEN) { fLocalPatternChars.append(UnicodeString(true, &gPatternChars[len], PATTERN_CHARS_LEN-len)); }
*/
fLocalPatternChars.setTo(true, gPatternChars, PATTERN_CHARS_LEN);
// Format short weekdays -> fShorterWeekdays (fall back to abbreviated)
initField(&fShorterWeekdays, fShorterWeekdaysCount, calendarSink,
buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesShortTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
assignArray(fShorterWeekdays, fShorterWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
}
// Stand-alone wide weekdays -> fStandaloneWeekdays
initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, calendarSink,
buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide is not available, use format/wide */
status = U_ZERO_ERROR;
assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, fWeekdays, fWeekdaysCount);
}
// Stand-alone abbreviated weekdays -> fStandaloneShortWeekdays
initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, calendarSink,
buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated is not available, use format/abbreviated */
status = U_ZERO_ERROR;
assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
}
// Stand-alone short weekdays -> fStandaloneShorterWeekdays (fall back to format abbreviated)
initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, calendarSink,
buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesShortTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/short is not available, use format/short */
status = U_ZERO_ERROR;
assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, fShorterWeekdays, fShorterWeekdaysCount);
}
if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC != U_MISSING_RESOURCE_ERROR) { // If format/narrow not available, use standalone/narrow
assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount);
} elseif (narrowWeeksEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR) { // If standalone/narrow not available, use format/narrow
assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fNarrowWeekdays, fNarrowWeekdaysCount);
} elseif (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR ) { // If neither is available, use format/abbreviated
assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
}
// Last resort fallback in case previous data wasn't loaded if (U_FAILURE(status))
{ if (useLastResortData)
{ // Handle the case in which there is no resource data present. // We don't have to generate usable patterns in this situation; // we just need to produce something that will be semi-intelligible // in most locales.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.