blob: f350d3a85bf5d171044f3e84ca1a0b75f6205479 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 1997-2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
* File DTFMTSYM.CPP
*
* Modification History:
*
* Date Name Description
* 02/19/97 aliu Converted from java.
* 07/21/98 stephen Added getZoneIndex
* Changed weekdays/short weekdays to be one-based
* 06/14/99 stephen Removed SimpleDateFormat::fgTimeZoneDataSuffix
* 11/16/99 weiv Added 'Y' and 'e' to fgPatternChars
* 03/27/00 weiv Keeping resource bundle around!
* 06/30/05 emmons Added eraNames, narrow month/day, standalone context
* 10/12/05 emmons Added setters for eraNames, month/day by width/context
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/ustring.h"
#include "unicode/dtfmtsym.h"
#include "unicode/smpdtfmt.h"
#include "unicode/msgfmt.h"
#include "cpputils.h"
#include "ucln_in.h"
#include "umutex.h"
#include "cmemory.h"
#include "cstring.h"
#include "locbased.h"
#include "gregoimp.h"
#include "hash.h"
#include "uresimp.h"
// *****************************************************************************
// class DateFormatSymbols
// *****************************************************************************
/**
* These are static arrays we use only in the case where we have no
* resource data.
*/
#define PATTERN_CHARS_LEN 30
/**
* Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
* locales use the same these unlocalized pattern characters.
*/
static const UChar gPatternChars[] = {
// GyMdkHmsSEDFwWahKzYeugAZvcLQqV
0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56, 0
};
/* length of an array */
#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
//------------------------------------------------------
// 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 month names and abbreviations of last resort.
static const UChar gLastResortMonthNames[13][3] =
{
{0x0030, 0x0031, 0x0000}, /* "01" */
{0x0030, 0x0032, 0x0000}, /* "02" */
{0x0030, 0x0033, 0x0000}, /* "03" */
{0x0030, 0x0034, 0x0000}, /* "04" */
{0x0030, 0x0035, 0x0000}, /* "05" */
{0x0030, 0x0036, 0x0000}, /* "06" */
{0x0030, 0x0037, 0x0000}, /* "07" */
{0x0030, 0x0038, 0x0000}, /* "08" */
{0x0030, 0x0039, 0x0000}, /* "09" */
{0x0031, 0x0030, 0x0000}, /* "10" */
{0x0031, 0x0031, 0x0000}, /* "11" */
{0x0031, 0x0032, 0x0000}, /* "12" */
{0x0031, 0x0033, 0x0000} /* "13" */
};
// These are the weekday names and abbreviations of last resort.
static const UChar 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.
static const UChar 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.
static const UChar gLastResortAmPmMarkers[2][3] =
{
{0x0041, 0x004D, 0x0000}, /* "AM" */
{0x0050, 0x004D, 0x0000} /* "PM" */
};
static const UChar gLastResortEras[2][3] =
{
{0x0042, 0x0043, 0x0000}, /* "BC" */
{0x0041, 0x0044, 0x0000} /* "AD" */
};
// These are the zone strings of last resort.
static const UChar gLastResortZoneStrings[7][4] =
{
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
{0x0047, 0x004D, 0x0054, 0x0000} /* "GMT" */
};
/* Sizes for the last resort string arrays */
typedef enum LastResortSize {
kMonthNum = 13,
kMonthLen = 3,
kDayNum = 8,
kDayLen = 2,
kAmPmNum = 2,
kAmPmLen = 3,
kQuarterNum = 4,
kQuarterLen = 2,
kEraNum = 2,
kEraLen = 3,
kZoneNum = 5,
kZoneLen = 4
} LastResortSize;
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)
#define kSUPPLEMENTAL "supplementalData"
/**
* These are the tags we expect to see in normal resource bundle files associated
* with a locale and calendar
*/
static const char gErasTag[]="eras";
static const char gAbbreviatedTag[] = "abbreviated";
static const char gMonthNamesTag[]="monthNames";
static const char gDayNamesTag[]="dayNames";
static const char gNamesWideTag[]="wide";
static const char gNamesAbbrTag[]="abbreviated";
static const char gNamesNarrowTag[]="narrow";
static const char gNamesStandaloneTag[]="stand-alone";
static const char gAmPmMarkersTag[]="AmPmMarkers";
static const char gQuartersTag[]="quarters";
static const char gMaptimezonesTag[]="mapTimezones";
static const char gMetazonesTag[]="metazones";
static const char gTerritoryTag[]="territory";
static const char gCountriesTag[]="Countries";
static const char gZoneFormattingTag[]="zoneFormatting";
static const char gMultizoneTag[]="multizone";
static const char gRegionFormatTag[]="zoneStrings/regionFormat";
static const char gFallbackFormatTag[]="zoneStrings/fallbackFormat";
/**
* These are the tags we expect to see in time zone data resource bundle files
* associated with a locale.
*/
static const char gZoneStringsTag[]="zoneStrings";
static const char gLocalPatternCharsTag[]="localPatternChars";
static UMTX LOCK;
/*
* Keep this variable in synch with max length of display strings
*/
#define ZID_KEY_MAX 128
#define UTZ_MAX_DISPLAY_STRINGS_LENGTH 7
#define UTZ_SHORT_GENERIC "sg"
#define UTZ_SHORT_STANDARD "ss"
#define UTZ_SHORT_DAYLIGHT "sd"
#define UTZ_LONG_GENERIC "lg"
#define UTZ_LONG_STANDARD "ls"
#define UTZ_LONG_DAYLIGHT "ld"
#define UTZ_EXEMPLAR_CITY "ec"
#define UTZ_USES_METAZONE "um"
#define UTZ_COMMONLY_USED "cu"
/**
* Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly.
* Work around this.
*/
static inline UnicodeString* newUnicodeStringArray(size_t count) {
return new UnicodeString[count ? count : 1];
}
U_CDECL_BEGIN
static void deleteUnicodeStringArray(void* obj) {
delete[] (UnicodeString*)obj;
}
U_CDECL_END
//------------------------------------------------------
DateFormatSymbols::DateFormatSymbols(const Locale& locale,
UErrorCode& status)
: UObject()
{
initializeData(locale, NULL, status);
}
DateFormatSymbols::DateFormatSymbols(UErrorCode& status)
: UObject()
{
initializeData(Locale::getDefault(), NULL, status, TRUE);
}
DateFormatSymbols::DateFormatSymbols(const Locale& locale,
const char *type,
UErrorCode& status)
: UObject()
{
initializeData(locale, type, status);
}
DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status)
: UObject()
{
initializeData(Locale::getDefault(), type, status, TRUE);
}
DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other)
: UObject(other)
{
copyData(other);
}
void
DateFormatSymbols::assignArray(UnicodeString*& dstArray,
int32_t& dstCount,
const UnicodeString* srcArray,
int32_t srcCount)
{
// assignArray() is only called by copyData(), 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()).
dstCount = srcCount;
dstArray = newUnicodeStringArray(srcCount);
if(dstArray != NULL) {
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;
fZoneStrings = (UnicodeString **)uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString *));
for (row=0; row<fZoneStringsRowCount; ++row)
{
fZoneStrings[row] = newUnicodeStringArray(fZoneStringsColCount);
for (col=0; col<fZoneStringsColCount; ++col) {
// fastCopyFrom() - see assignArray comments
fZoneStrings[row][col].fastCopyFrom(otherStrings[row][col]);
}
}
}
/**
* Copy all of the other's data to this.
*/
void
DateFormatSymbols::copyData(const DateFormatSymbols& other) {
assignArray(fEras, fErasCount, other.fEras, other.fErasCount);
assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount);
assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount);
assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount);
assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount);
assignArray(fStandaloneMonths, fStandaloneMonthsCount, other.fStandaloneMonths, other.fStandaloneMonthsCount);
assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, other.fStandaloneShortMonths, other.fStandaloneShortMonthsCount);
assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, other.fStandaloneNarrowMonths, other.fStandaloneNarrowMonthsCount);
assignArray(fWeekdays, fWeekdaysCount, other.fWeekdays, other.fWeekdaysCount);
assignArray(fShortWeekdays, fShortWeekdaysCount, other.fShortWeekdays, other.fShortWeekdaysCount);
assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount);
assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, other.fStandaloneWeekdays, other.fStandaloneWeekdaysCount);
assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, other.fStandaloneShortWeekdays, other.fStandaloneShortWeekdaysCount);
assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount);
assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount);
assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount);
assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
// the zoneStrings data is initialized on demand
//fZoneStringsRowCount = other.fZoneStringsRowCount;
//fZoneStringsColCount = other.fZoneStringsColCount;
//createZoneStrings((const UnicodeString**)other.fZoneStrings);
// initialize on demand
fZoneStringsHash = NULL;
fZoneIDEnumeration = NULL;
fZoneStrings = NULL;
fZoneStringsColCount = 0;
fZoneStringsRowCount = 0;
fResourceBundle = NULL;
fCountry = other.fCountry;
if(other.fZoneStringsHash!=NULL){
fZoneStringsHash = createZoneStringsHash(other.fZoneStringsHash);
fZoneIDEnumeration = other.fZoneIDEnumeration->clone();
}else{
UErrorCode status =U_ZERO_ERROR;
fResourceBundle = ures_clone(other.fResourceBundle, &status);
// TODO: what should be done in case of error?
}
// fastCopyFrom() - see assignArray comments
fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
}
/**
* Assignment operator.
*/
DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
{
dispose();
copyData(other);
return *this;
}
DateFormatSymbols::~DateFormatSymbols()
{
dispose();
}
void DateFormatSymbols::dispose()
{
if (fEras) delete[] fEras;
if (fEraNames) delete[] fEraNames;
if (fMonths) delete[] fMonths;
if (fShortMonths) delete[] fShortMonths;
if (fNarrowMonths) delete[] fNarrowMonths;
if (fStandaloneMonths) delete[] fStandaloneMonths;
if (fStandaloneShortMonths) delete[] fStandaloneShortMonths;
if (fStandaloneNarrowMonths) delete[] fStandaloneNarrowMonths;
if (fWeekdays) delete[] fWeekdays;
if (fShortWeekdays) delete[] fShortWeekdays;
if (fNarrowWeekdays) delete[] fNarrowWeekdays;
if (fStandaloneWeekdays) delete[] fStandaloneWeekdays;
if (fStandaloneShortWeekdays) delete[] fStandaloneShortWeekdays;
if (fStandaloneNarrowWeekdays) delete[] fStandaloneNarrowWeekdays;
if (fAmPms) delete[] fAmPms;
if (fQuarters) delete[] fQuarters;
if (fShortQuarters) delete[] fShortQuarters;
if (fStandaloneQuarters) delete[] fStandaloneQuarters;
if (fStandaloneShortQuarters) delete[] fStandaloneShortQuarters;
disposeZoneStrings();
}
void DateFormatSymbols::disposeZoneStrings()
{
if (fZoneStrings) {
for (int32_t row=0; row<fZoneStringsRowCount; ++row)
delete[] fZoneStrings[row];
uprv_free(fZoneStrings);
}
if(fZoneStringsHash){
delete fZoneStringsHash;
fZoneStringsHash = NULL;
}
if(fZoneIDEnumeration){
delete fZoneIDEnumeration;
fZoneIDEnumeration = NULL;
}
if (fResourceBundle){
ures_close(fResourceBundle);
fResourceBundle = NULL;
}
}
UBool
DateFormatSymbols::arrayCompare(const UnicodeString* array1,
const UnicodeString* array2,
int32_t count)
{
if (array1 == array2) return TRUE;
while (count>0)
{
--count;
if (array1[count] != array2[count]) return FALSE;
}
return TRUE;
}
UBool
DateFormatSymbols::operator==(const DateFormatSymbols& other) const
{
// First do cheap comparisons
if (this == &other) {
return TRUE;
}
if (fErasCount == other.fErasCount &&
fEraNamesCount == other.fEraNamesCount &&
fMonthsCount == other.fMonthsCount &&
fShortMonthsCount == other.fShortMonthsCount &&
fNarrowMonthsCount == other.fNarrowMonthsCount &&
fStandaloneMonthsCount == other.fStandaloneMonthsCount &&
fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount &&
fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount &&
fWeekdaysCount == other.fWeekdaysCount &&
fShortWeekdaysCount == other.fShortWeekdaysCount &&
fNarrowWeekdaysCount == other.fNarrowWeekdaysCount &&
fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount &&
fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount &&
fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount &&
fAmPmsCount == other.fAmPmsCount &&
fQuartersCount == other.fQuartersCount &&
fShortQuartersCount == other.fShortQuartersCount &&
fStandaloneQuartersCount == other.fStandaloneQuartersCount &&
fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount)
{
// Now compare the arrays themselves
if (arrayCompare(fEras, other.fEras, fErasCount) &&
arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) &&
arrayCompare(fMonths, other.fMonths, fMonthsCount) &&
arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) &&
arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) &&
arrayCompare(fStandaloneMonths, other.fStandaloneMonths, fStandaloneMonthsCount) &&
arrayCompare(fStandaloneShortMonths, other.fStandaloneShortMonths, fStandaloneShortMonthsCount) &&
arrayCompare(fStandaloneNarrowMonths, other.fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount) &&
arrayCompare(fWeekdays, other.fWeekdays, fWeekdaysCount) &&
arrayCompare(fShortWeekdays, other.fShortWeekdays, fShortWeekdaysCount) &&
arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) &&
arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) &&
arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) &&
arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) &&
arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) &&
arrayCompare(fQuarters, other.fQuarters, fQuartersCount) &&
arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) &&
arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount))
{
if(fZoneStringsHash == NULL || other.fZoneStringsHash == NULL){
// fZoneStringsHash is not initialized compare the resource bundles
if(ures_equal(fResourceBundle, other.fResourceBundle)== FALSE){
return FALSE;
}
}else{
if(fZoneStringsHash->equals(*other.fZoneStringsHash) == FALSE){
return FALSE;
}
// we always make sure that we update the enumeration when the hash is
// updated. So we can be sure that once we compare the hashes the
// enumerations are also equal
}
// since fZoneStrings data member is deprecated .. and may not be initialized
// so don't compare them
return TRUE;
}
}
return FALSE;
}
//------------------------------------------------------
const UnicodeString*
DateFormatSymbols::getEras(int32_t &count) const
{
count = fErasCount;
return fEras;
}
const UnicodeString*
DateFormatSymbols::getEraNames(int32_t &count) const
{
count = fEraNamesCount;
return fEraNames;
}
const UnicodeString*
DateFormatSymbols::getMonths(int32_t &count) const
{
count = fMonthsCount;
return fMonths;
}
const UnicodeString*
DateFormatSymbols::getShortMonths(int32_t &count) const
{
count = fShortMonthsCount;
return fShortMonths;
}
const UnicodeString*
DateFormatSymbols::getMonths(int32_t &count, DtContextType context, DtWidthType width ) const
{
UnicodeString *returnValue = NULL;
switch (context) {
case FORMAT :
switch(width) {
case WIDE :
count = fMonthsCount;
returnValue = fMonths;
break;
case ABBREVIATED :
count = fShortMonthsCount;
returnValue = fShortMonths;
break;
case NARROW :
count = fNarrowMonthsCount;
returnValue = fNarrowMonths;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case STANDALONE :
switch(width) {
case WIDE :
count = fStandaloneMonthsCount;
returnValue = fStandaloneMonths;
break;
case ABBREVIATED :
count = fStandaloneShortMonthsCount;
returnValue = fStandaloneShortMonths;
break;
case NARROW :
count = fStandaloneNarrowMonthsCount;
returnValue = fStandaloneNarrowMonths;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case DT_CONTEXT_COUNT :
break;
}
return returnValue;
}
const UnicodeString*
DateFormatSymbols::getWeekdays(int32_t &count) const
{
count = fWeekdaysCount;
return fWeekdays;
}
const UnicodeString*
DateFormatSymbols::getShortWeekdays(int32_t &count) const
{
count = fShortWeekdaysCount;
return fShortWeekdays;
}
const UnicodeString*
DateFormatSymbols::getWeekdays(int32_t &count, DtContextType context, DtWidthType width) const
{
UnicodeString *returnValue = NULL;
switch (context) {
case FORMAT :
switch(width) {
case WIDE :
count = fWeekdaysCount;
returnValue = fWeekdays;
break;
case ABBREVIATED :
count = fShortWeekdaysCount;
returnValue = fShortWeekdays;
break;
case NARROW :
count = fNarrowWeekdaysCount;
returnValue = fNarrowWeekdays;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case STANDALONE :
switch(width) {
case WIDE :
count = fStandaloneWeekdaysCount;
returnValue = fStandaloneWeekdays;
break;
case ABBREVIATED :
count = fStandaloneShortWeekdaysCount;
returnValue = fStandaloneShortWeekdays;
break;
case NARROW :
count = fStandaloneNarrowWeekdaysCount;
returnValue = fStandaloneNarrowWeekdays;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case DT_CONTEXT_COUNT :
break;
}
return returnValue;
}
const UnicodeString*
DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthType width ) const
{
UnicodeString *returnValue = NULL;
switch (context) {
case FORMAT :
switch(width) {
case WIDE :
count = fQuartersCount;
returnValue = fQuarters;
break;
case ABBREVIATED :
count = fShortQuartersCount;
returnValue = fShortQuarters;
break;
case NARROW :
count = 0;
returnValue = NULL;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case STANDALONE :
switch(width) {
case WIDE :
count = fStandaloneQuartersCount;
returnValue = fStandaloneQuarters;
break;
case ABBREVIATED :
count = fStandaloneShortQuartersCount;
returnValue = fStandaloneShortQuarters;
break;
case NARROW :
count = 0;
returnValue = NULL;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case DT_CONTEXT_COUNT :
break;
}
return returnValue;
}
const UnicodeString*
DateFormatSymbols::getAmPmStrings(int32_t &count) const
{
count = fAmPmsCount;
return fAmPms;
}
//------------------------------------------------------
void
DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count)
{
// delete the old list if we own it
if (fEras)
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
if (fEraNames)
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::setMonths(const UnicodeString* monthsArray, int32_t count)
{
// delete the old list if we own it
if (fMonths)
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
if (fShortMonths)
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)
switch (context) {
case FORMAT :
switch (width) {
case WIDE :
if (fMonths)
delete[] fMonths;
fMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fMonths,count);
fMonthsCount = count;
break;
case ABBREVIATED :
if (fShortMonths)
delete[] fShortMonths;
fShortMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fShortMonths,count);
fShortMonthsCount = count;
break;
case NARROW :
if (fNarrowMonths)
delete[] fNarrowMonths;
fNarrowMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fNarrowMonths,count);
fNarrowMonthsCount = count;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case STANDALONE :
switch (width) {
case WIDE :
if (fStandaloneMonths)
delete[] fStandaloneMonths;
fStandaloneMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fStandaloneMonths,count);
fStandaloneMonthsCount = count;
break;
case ABBREVIATED :
if (fStandaloneShortMonths)
delete[] fStandaloneShortMonths;
fStandaloneShortMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fStandaloneShortMonths,count);
fStandaloneShortMonthsCount = count;
break;
case NARROW :
if (fStandaloneNarrowMonths)
delete[] fStandaloneNarrowMonths;
fStandaloneNarrowMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count);
fStandaloneNarrowMonthsCount = count;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case DT_CONTEXT_COUNT :
break;
}
}
void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count)
{
// delete the old list if we own it
if (fWeekdays)
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
if (fShortWeekdays)
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)
switch (context) {
case FORMAT :
switch (width) {
case WIDE :
if (fWeekdays)
delete[] fWeekdays;
fWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fWeekdays, count);
fWeekdaysCount = count;
break;
case ABBREVIATED :
if (fShortWeekdays)
delete[] fShortWeekdays;
fShortWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fShortWeekdays, count);
fShortWeekdaysCount = count;
break;
case NARROW :
if (fNarrowWeekdays)
delete[] fNarrowWeekdays;
fNarrowWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count);
fNarrowWeekdaysCount = count;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case STANDALONE :
switch (width) {
case WIDE :
if (fStandaloneWeekdays)
delete[] fStandaloneWeekdays;
fStandaloneWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fStandaloneWeekdays, count);
fStandaloneWeekdaysCount = count;
break;
case ABBREVIATED :
if (fStandaloneShortWeekdays)
delete[] fStandaloneShortWeekdays;
fStandaloneShortWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fStandaloneShortWeekdays, count);
fStandaloneShortWeekdaysCount = count;
break;
case NARROW :
if (fStandaloneNarrowWeekdays)
delete[] fStandaloneNarrowWeekdays;
fStandaloneNarrowWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count);
fStandaloneNarrowWeekdaysCount = count;
break;
case DT_WIDTH_COUNT :
break;
}
break;
case DT_CONTEXT_COUNT :
break;
}
}
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)
switch (context) {
case FORMAT :
switch (width) {
case WIDE :
if (fQuarters)
delete[] fQuarters;
fQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fQuarters,count);
fQuartersCount = count;
break;
case ABBREVIATED :
if (fShortQuarters)
delete[] fShortQuarters;
fShortQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fShortQuarters,count);
fShortQuartersCount = count;
break;
case NARROW :
/*
if (fNarrowQuarters)
delete[] fNarrowQuarters;
fNarrowQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fNarrowQuarters,count);
fNarrowQuartersCount = count;
*/
break;
case DT_WIDTH_COUNT :
break;
}
break;
case STANDALONE :
switch (width) {
case WIDE :
if (fStandaloneQuarters)
delete[] fStandaloneQuarters;
fStandaloneQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fStandaloneQuarters,count);
fStandaloneQuartersCount = count;
break;
case ABBREVIATED :
if (fStandaloneShortQuarters)
delete[] fStandaloneShortQuarters;
fStandaloneShortQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fStandaloneShortQuarters,count);
fStandaloneShortQuartersCount = count;
break;
case NARROW :
/*
if (fStandaloneNarrowQuarters)
delete[] fStandaloneNarrowQuarters;
fStandaloneNarrowQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count);
fStandaloneNarrowQuartersCount = count;
*/
break;
case DT_WIDTH_COUNT :
break;
}
break;
case DT_CONTEXT_COUNT :
break;
}
}
void
DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count)
{
// delete the old list if we own it
if (fAmPms) 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;
}
//------------------------------------------------------
const UnicodeString**
DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
{
umtx_lock(&LOCK);
UErrorCode status = U_ZERO_ERROR;
if(fZoneStrings==NULL){
// cast away const to get around the problem for lazy initialization
((DateFormatSymbols*)this)->initZoneStringsArray(status);
}
rowCount = fZoneStringsRowCount;
columnCount = fZoneStringsColCount;
umtx_unlock(&LOCK);
if(U_FAILURE(status)){
rowCount = 0;
columnCount = 0;
return NULL;
}
return (const UnicodeString**)fZoneStrings; // Compiler requires cast
}
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();
UErrorCode status = U_ZERO_ERROR;
// 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 UnicodeString**)strings);
initZoneStrings((const UnicodeString**)strings, rowCount,columnCount, status);
}
//------------------------------------------------------
const UChar * U_EXPORT2
DateFormatSymbols::getPatternUChars(void)
{
return gPatternChars;
}
//------------------------------------------------------
UnicodeString&
DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const
{
// fastCopyFrom() - see assignArray comments
return result.fastCopyFrom(fLocalPatternChars);
}
//------------------------------------------------------
void
DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars)
{
fLocalPatternChars = newLocalPatternChars;
}
//------------------------------------------------------
static void
initField(UnicodeString **field, int32_t& length, const UResourceBundle *data, UErrorCode &status) {
if (U_SUCCESS(status)) {
int32_t strLen = 0;
length = ures_getSize(data);
*field = newUnicodeStringArray(length);
if (*field) {
for(int32_t i = 0; i<length; i++) {
const UChar *resStr = ures_getStringByIndex(data, i, &strLen, &status);
// setTo() - see assignArray comments
(*(field)+i)->setTo(TRUE, resStr, strLen);
}
}
else {
length = 0;
status = U_MEMORY_ALLOCATION_ERROR;
}
}
}
static void
initField(UnicodeString **field, int32_t& length, const UChar *data, LastResortSize numStr, LastResortSize strLen, UErrorCode &status) {
if (U_SUCCESS(status)) {
length = numStr;
*field = newUnicodeStringArray((size_t)numStr);
if (*field) {
for(int32_t i = 0; i<length; i++) {
// readonly aliases - all "data" strings are constant
// -1 as length for variable-length strings (gLastResortDayNames[0] is empty)
(*(field)+i)->setTo(TRUE, data+(i*((int32_t)strLen)), -1);
}
}
else {
length = 0;
status = U_MEMORY_ALLOCATION_ERROR;
}
}
}
void
DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData)
{
int32_t i;
int32_t len = 0;
const UChar *resStr;
/* In case something goes wrong, initialize all of the data to NULL. */
fEras = NULL;
fErasCount = 0;
fEraNames = NULL;
fEraNamesCount = 0;
fMonths = NULL;
fMonthsCount=0;
fShortMonths = NULL;
fShortMonthsCount=0;
fNarrowMonths = NULL;
fNarrowMonthsCount=0;
fStandaloneMonths = NULL;
fStandaloneMonthsCount=0;
fStandaloneShortMonths = NULL;
fStandaloneShortMonthsCount=0;
fStandaloneNarrowMonths = NULL;
fStandaloneNarrowMonthsCount=0;
fWeekdays = NULL;
fWeekdaysCount=0;
fShortWeekdays = NULL;
fShortWeekdaysCount=0;
fNarrowWeekdays = NULL;
fNarrowWeekdaysCount=0;
fStandaloneWeekdays = NULL;
fStandaloneWeekdaysCount=0;
fStandaloneShortWeekdays = NULL;
fStandaloneShortWeekdaysCount=0;
fStandaloneNarrowWeekdays = NULL;
fStandaloneNarrowWeekdaysCount=0;
fAmPms = NULL;
fAmPmsCount=0;
fQuarters = NULL;
fQuartersCount = 0;
fShortQuarters = NULL;
fShortQuartersCount = 0;
fStandaloneQuarters = NULL;
fStandaloneQuartersCount = 0;
fStandaloneShortQuarters = NULL;
fStandaloneShortQuartersCount = 0;
fZoneStringsRowCount = 0;
fZoneStringsColCount = 0;
fZoneStrings = NULL;
fZoneStringsHash = NULL;
fZoneIDEnumeration = NULL;
fResourceBundle = NULL;
fCountry = NULL;
if (U_FAILURE(status)) return;
/**
* Retrieve the string arrays we need from the resource bundle file.
* We cast away const here, but that's okay; we won't delete any of
* these.
*/
CalendarData calData(locale, type, status);
fResourceBundle = ures_open(NULL, locale.getName(), &status);
fCountry = locale.getCountry();
// load the first data item
UResourceBundle *erasMain = calData.getByKey(gErasTag, status);
UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status);
UErrorCode oldStatus = status;
UResourceBundle *eraNames = ures_getByKeyWithFallback(erasMain, gNamesWideTag, NULL, &status);
if ( status == U_MISSING_RESOURCE_ERROR ) { // Workaround because eras/wide was omitted from CLDR 1.3
status = oldStatus;
eraNames = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status);
}
UResourceBundle *lsweekdaysData = NULL; // Data closed by calData
UResourceBundle *weekdaysData = NULL; // Data closed by calData
UResourceBundle *narrowWeekdaysData = NULL; // Data closed by calData
UResourceBundle *standaloneWeekdaysData = NULL; // Data closed by calData
UResourceBundle *standaloneShortWeekdaysData = NULL; // Data closed by calData
UResourceBundle *standaloneNarrowWeekdaysData = NULL; // Data closed by calData
U_LOCALE_BASED(locBased, *this);
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.
status = U_USING_FALLBACK_WARNING;
initField(&fEras, fErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status);
initField(&fEraNames, fEraNamesCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status);
initField(&fMonths, fMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
initField(&fShortMonths, fShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
initField(&fNarrowMonths, fNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
initField(&fStandaloneMonths, fStandaloneMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
initField(&fWeekdays, fWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
initField(&fShortWeekdays, fShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
initField(&fNarrowWeekdays, fNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
initField(&fAmPms, fAmPmsCount, (const UChar *)gLastResortAmPmMarkers, kAmPmNum, kAmPmLen, status);
initField(&fQuarters, fQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fShortQuarters, fShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fStandaloneQuarters, fStandaloneQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN);
}
goto cleanup;
}
// 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(eras, ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(eras, ULOC_ACTUAL_LOCALE, &status));
initField(&fEras, fErasCount, eras, status);
initField(&fEraNames, fEraNamesCount, eraNames, status);
initField(&fMonths, fMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status);
initField(&fShortMonths, fShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status);
if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
}
if ( status == U_MISSING_RESOURCE_ERROR ) { /* If format/narrow not available, use format/abbreviated */
status = U_ZERO_ERROR;
initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
}
initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status);
if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/wide not available, use format/wide */
status = U_ZERO_ERROR;
initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status);
}
initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/abbreviated not available, use format/abbreviated */
status = U_ZERO_ERROR;
initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
}
initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
if ( status == U_MISSING_RESOURCE_ERROR ) { /* if standalone/narrow not availabe, try format/narrow */
status = U_ZERO_ERROR;
initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status);
if ( status == U_MISSING_RESOURCE_ERROR ) { /* if still not there, use format/abbreviated */
status = U_ZERO_ERROR;
initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
}
}
initField(&fAmPms, fAmPmsCount, calData.getByKey(gAmPmMarkersTag, status), status);
initField(&fQuarters, fQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status);
initField(&fShortQuarters, fShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status);
initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status);
if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status);
}
initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status);
}
// 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);
// {sfb} fixed to handle 1-based weekdays
weekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status);
fWeekdaysCount = ures_getSize(weekdaysData);
fWeekdays = new UnicodeString[fWeekdaysCount+1];
/* pin the blame on system. If we cannot get a chunk of memory .. the system is dying!*/
if (fWeekdays == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanup;
}
// leave fWeekdays[0] empty
for(i = 0; i<fWeekdaysCount; i++) {
resStr = ures_getStringByIndex(weekdaysData, i, &len, &status);
// setTo() - see assignArray comments
fWeekdays[i+1].setTo(TRUE, resStr, len);
}
fWeekdaysCount++;
lsweekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
fShortWeekdaysCount = ures_getSize(lsweekdaysData);
fShortWeekdays = new UnicodeString[fShortWeekdaysCount+1];
/* test for NULL */
if (fShortWeekdays == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanup;
}
// leave fShortWeekdays[0] empty
for(i = 0; i<fShortWeekdaysCount; i++) {
resStr = ures_getStringByIndex(lsweekdaysData, i, &len, &status);
// setTo() - see assignArray comments
fShortWeekdays[i+1].setTo(TRUE, resStr, len);
}
fShortWeekdaysCount++;
narrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesNarrowTag, status);
if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
narrowWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status);
}
if ( status == U_MISSING_RESOURCE_ERROR ) {
status = U_ZERO_ERROR;
narrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
}
fNarrowWeekdaysCount = ures_getSize(narrowWeekdaysData);
fNarrowWeekdays = new UnicodeString[fNarrowWeekdaysCount+1];
/* test for NULL */
if (fNarrowWeekdays == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanup;
}
// leave fNarrowWeekdays[0] empty
for(i = 0; i<fNarrowWeekdaysCount; i++) {
resStr = ures_getStringByIndex(narrowWeekdaysData, i, &len, &status);
// setTo() - see assignArray comments
fNarrowWeekdays[i+1].setTo(TRUE, resStr, len);
}
fNarrowWeekdaysCount++;
standaloneWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status);
if ( status == U_MISSING_RESOURCE_ERROR ) {
status = U_ZERO_ERROR;
standaloneWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status);
}
fStandaloneWeekdaysCount = ures_getSize(standaloneWeekdaysData);
fStandaloneWeekdays = new UnicodeString[fStandaloneWeekdaysCount+1];
/* test for NULL */
if (fStandaloneWeekdays == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanup;
}
// leave fStandaloneWeekdays[0] empty
for(i = 0; i<fStandaloneWeekdaysCount; i++) {
resStr = ures_getStringByIndex(standaloneWeekdaysData, i, &len, &status);
// setTo() - see assignArray comments
fStandaloneWeekdays[i+1].setTo(TRUE, resStr, len);
}
fStandaloneWeekdaysCount++;
standaloneShortWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status);
if ( status == U_MISSING_RESOURCE_ERROR ) {
status = U_ZERO_ERROR;
standaloneShortWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
}
fStandaloneShortWeekdaysCount = ures_getSize(standaloneShortWeekdaysData);
fStandaloneShortWeekdays = new UnicodeString[fStandaloneShortWeekdaysCount+1];
/* test for NULL */
if (fStandaloneShortWeekdays == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanup;
}
// leave fStandaloneShortWeekdays[0] empty
for(i = 0; i<fStandaloneShortWeekdaysCount; i++) {
resStr = ures_getStringByIndex(standaloneShortWeekdaysData, i, &len, &status);
// setTo() - see assignArray comments
fStandaloneShortWeekdays[i+1].setTo(TRUE, resStr, len);
}
fStandaloneShortWeekdaysCount++;
standaloneNarrowWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status);
if ( status == U_MISSING_RESOURCE_ERROR ) {
status = U_ZERO_ERROR;
standaloneNarrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesNarrowTag, status);
if ( status == U_MISSING_RESOURCE_ERROR ) {
status = U_ZERO_ERROR;
standaloneNarrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
}
}
fStandaloneNarrowWeekdaysCount = ures_getSize(standaloneNarrowWeekdaysData);
fStandaloneNarrowWeekdays = new UnicodeString[fStandaloneNarrowWeekdaysCount+1];
/* test for NULL */
if (fStandaloneNarrowWeekdays == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanup;
}
// leave fStandaloneNarrowWeekdays[0] empty
for(i = 0; i<fStandaloneNarrowWeekdaysCount; i++) {
resStr = ures_getStringByIndex(standaloneNarrowWeekdaysData, i, &len, &status);
// setTo() - see assignArray comments
fStandaloneNarrowWeekdays[i+1].setTo(TRUE, resStr, len);
}
fStandaloneNarrowWeekdaysCount++;
cleanup:
ures_close(eras);
ures_close(eraNames);
}
/**
* Package private: used by SimpleDateFormat
* Gets the index for the given time zone ID to obtain the timezone
* strings for formatting. The time zone ID is just for programmatic
* lookup. NOT LOCALIZED!!!
* @param ID the given time zone ID.
* @return the index of the given time zone ID. Returns -1 if
* the given time zone ID can't be located in the DateFormatSymbols object.
* @see java.util.SimpleTimeZone
*/
int32_t DateFormatSymbols::getZoneIndex(const UnicodeString& ID) const
{
int32_t result = _getZoneIndex(ID);
if (result >= 0) {
return result;
}
// Do a search through the equivalency group for the given ID
int32_t n = TimeZone::countEquivalentIDs(ID);
if (n > 1) {
int32_t i;
for (i=0; i<n; ++i) {
UnicodeString equivID = TimeZone::getEquivalentID(ID, i);
if (equivID != ID) {
int32_t equivResult = _getZoneIndex(equivID);
if (equivResult >= 0) {
return equivResult;
}
}
}
}
return -1;
}
/**
* Lookup the given ID. Do NOT do an equivalency search.
*/
int32_t DateFormatSymbols::_getZoneIndex(const UnicodeString& ID) const
{
for(int32_t index = 0; index < fZoneStringsRowCount; index++) {
if (0 == ID.caseCompare(fZoneStrings[index][0], 0)) {
return index;
}
}
return -1;
}
Locale
DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
U_LOCALE_BASED(locBased, *this);
return locBased.getLocale(type, status);
}
class TimeZoneKeysEnumeration : public StringEnumeration {
private:
UnicodeString* strings;
int32_t length;
int32_t current;
int32_t capacity;
TimeZoneKeysEnumeration(UnicodeString* oldStrs, int32_t count){
strings = newUnicodeStringArray(count);
if(strings==NULL){
return;
}
capacity = count;
current = 0;
for(length = 0; length<capacity; length++){
strings[length].setTo(oldStrs[length]);
}
}
public:
static UClassID U_EXPORT2 getStaticClassID(void);
virtual UClassID getDynamicClassID(void) const;
TimeZoneKeysEnumeration(int32_t count, UErrorCode status){
strings = newUnicodeStringArray(count);
if(strings == NULL){
status = U_MEMORY_ALLOCATION_ERROR;
}
length = 0;
current = 0;
capacity = count;
}
void put(const UnicodeString& str, UErrorCode& status){
if(length < capacity){
strings[length++].setTo(str);
}else{
status = U_INDEX_OUTOFBOUNDS_ERROR;
}
}
virtual ~TimeZoneKeysEnumeration() {
delete[] strings;
}
virtual StringEnumeration * clone() const
{
return new TimeZoneKeysEnumeration(strings, length);
}
virtual int32_t count(UErrorCode &/*status*/) const {
return length;
}
virtual const UChar* unext(int32_t *resultLength, UErrorCode& /*status*/){
if(current < length){
const UChar* ret = strings[current].getBuffer();
*resultLength = strings[current].length();
current++;
return ret;
}
return NULL;
}
virtual const UnicodeString* snext(UErrorCode& status) {
if(U_FAILURE(status)){
return NULL;
}
if(current < length){
return &strings[current++];
}
return NULL;
}
/* this method is for thread safe iteration */
const UnicodeString* snext(int32_t& pos, UErrorCode& status)const {
if(U_FAILURE(status)){
return NULL;
}
if(pos < length){
return &strings[pos++];
}
return NULL;
}
virtual void reset(UErrorCode& /*status*/) {
current = 0;
}
private:
UBool equals(const StringEnumeration& other) const{
if (other.getDynamicClassID() != TimeZoneKeysEnumeration::getStaticClassID()) {
return FALSE;
}
TimeZoneKeysEnumeration& enum2 = (TimeZoneKeysEnumeration&)(other);
UErrorCode status = U_ZERO_ERROR;
int32_t count1 = count(status);
int32_t count2 = other.count(status);
if(count1 != count2){
return FALSE;
}
int32_t pos1 = 0;
int32_t pos2 = 0;
const UnicodeString* str1 = NULL;
const UnicodeString* str2 = NULL;
while((str1 = snext(pos1, status))!=NULL){
str2 = enum2.snext(pos2, status);
if(U_FAILURE(status)){
return FALSE;
}
if(*str1 != *str2){
// bail out at the first failure
return FALSE;
}
}
// if we reached here that means that the enumerations are equal
return TRUE;
}
public:
virtual UBool operator==(const StringEnumeration& that)const{
return ((this == &that) ||
(getDynamicClassID() == that.getDynamicClassID() &&
StringEnumeration::operator==(that) &&
equals(that)));
}
};
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeZoneKeysEnumeration)
void
DateFormatSymbols::initZoneStringsArray(UErrorCode& status){
if(fZoneStringsHash == NULL){
initZoneStrings(status);
}
if(U_FAILURE(status)){
return;
}
fZoneStringsRowCount = fZoneIDEnumeration->count(status);
fZoneStringsColCount = 8;
fZoneStrings = (UnicodeString **)uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString *));
/* if we can't get a chunk of heap then the system is going down. Pin the blame on system*/
if (fZoneStrings == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
const UnicodeString *zid = NULL;
TimeZoneKeysEnumeration *keys = (TimeZoneKeysEnumeration*) fZoneIDEnumeration;
int32_t pos = 0;
int32_t i = 0;
while((zid=keys->snext(pos,status))!=NULL){
*(fZoneStrings+i) = newUnicodeStringArray(fZoneStringsColCount);
/* test for NULL */
if ((*(fZoneStrings+i)) == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(*zid);
fZoneStrings[i][0].setTo(*zid);
fZoneStrings[i][1].setTo(strings[TIMEZONE_LONG_STANDARD]);
fZoneStrings[i][2].setTo(strings[TIMEZONE_SHORT_STANDARD]);
fZoneStrings[i][3].setTo(strings[TIMEZONE_LONG_DAYLIGHT]);
fZoneStrings[i][4].setTo(strings[TIMEZONE_SHORT_DAYLIGHT]);
fZoneStrings[i][5].setTo(strings[TIMEZONE_EXEMPLAR_CITY]);
fZoneStrings[i][6].setTo(strings[TIMEZONE_LONG_GENERIC]);
fZoneStrings[i][7].setTo(strings[TIMEZONE_SHORT_GENERIC]);
i++;
}
}
U_CDECL_BEGIN
static UBool U_CALLCONV
compareTZHashValues(const UHashTok val1, const UHashTok val2){
const UnicodeString* array1 = (UnicodeString*) val1.pointer;
const UnicodeString* array2 = (UnicodeString*) val2.pointer;
if(array1==array2){
return TRUE;
}
if(array1==NULL || array2==NULL){
return FALSE;
}
for(int32_t j=0; j< UTZ_MAX_DISPLAY_STRINGS_LENGTH; j++){
if(array1[j] != array2[j]){
return FALSE;
}
}
return TRUE;
}
U_CDECL_END
void
DateFormatSymbols::initZoneStrings(UErrorCode &status){
if(U_FAILURE(status)){
return;
}
if(fZoneStringsHash != NULL){
return;
}
int32_t i;
fZoneStringsHash = new Hashtable(uhash_compareUnicodeString, compareTZHashValues, status);
if(fZoneStringsHash==NULL){
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
fZoneStringsHash->setValueDeleter(deleteUnicodeStringArray);
if(fResourceBundle != NULL){
UnicodeString solidus = UNICODE_STRING_SIMPLE("/");
UnicodeString colon = UNICODE_STRING_SIMPLE(":");
UResourceBundle *zoneArray, *zoneItem;
for(const UResourceBundle* rb = fResourceBundle; rb!=NULL; rb=ures_getParentBundle(rb)){
zoneArray = ures_getByKey(rb, gZoneStringsTag, NULL, &status);
if(U_FAILURE(status)){
break;
}
while(ures_hasNext(zoneArray)){
UErrorCode tempStatus = U_ZERO_ERROR;
zoneItem = ures_getNextResource(zoneArray, NULL, &status);
UnicodeString key(ures_getKey(zoneItem), -1, US_INV);
if (key.indexOf(colon) == -1) {
ures_close(zoneItem);
continue;
}
UnicodeString* strArray = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH);
key.findAndReplace(colon, solidus);
int32_t len = 0;
//fetch the strings with fine grained fallback
const UChar* str = ures_getStringByKeyWithFallback(zoneItem,UTZ_SHORT_STANDARD, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_SHORT_STANDARD].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
str = ures_getStringByKeyWithFallback(zoneItem,UTZ_SHORT_GENERIC, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_SHORT_GENERIC].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
str = ures_getStringByKeyWithFallback(zoneItem,UTZ_SHORT_DAYLIGHT, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_SHORT_DAYLIGHT].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
str = ures_getStringByKeyWithFallback(zoneItem,UTZ_LONG_STANDARD, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_LONG_STANDARD].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
str = ures_getStringByKeyWithFallback(zoneItem,UTZ_LONG_GENERIC, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_LONG_GENERIC].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
str = ures_getStringByKeyWithFallback(zoneItem,UTZ_LONG_DAYLIGHT, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_LONG_DAYLIGHT].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
str = ures_getStringByKeyWithFallback(zoneItem,UTZ_EXEMPLAR_CITY, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_EXEMPLAR_CITY].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
// store the strings in hash
fZoneStringsHash->put(key, strArray, status);
ures_close(zoneItem);
}
ures_close(zoneArray);
}
// Need to make sure that all zoneStrings in root are covered as well, otherwise metazone lookups won't
// work properly
UResourceBundle* root_res = ures_open(NULL, "", &status);
zoneArray = ures_getByKey(root_res, gZoneStringsTag, NULL, &status);
if (U_SUCCESS(status)) {
while(ures_hasNext(zoneArray)){
UErrorCode tempStatus = U_ZERO_ERROR;
zoneItem = ures_getNextResource(zoneArray, NULL, &status);
UnicodeString key(ures_getKey(zoneItem), -1, US_INV);
if ( key.indexOf(colon) == -1 ) {
ures_close(zoneItem);
continue;
}
key.findAndReplace(colon, solidus);
// Don't step on anything that is already there
UnicodeString* existingArray = (UnicodeString*)fZoneStringsHash->get(key);
if(existingArray != NULL){
ures_close(zoneItem);
continue;
}
UnicodeString* strArray = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH);
int32_t len = 0;
const UChar *str = ures_getStringByKeyWithFallback(zoneItem,UTZ_EXEMPLAR_CITY, &len, &tempStatus);
if(U_SUCCESS(tempStatus)){
strArray[TIMEZONE_EXEMPLAR_CITY].setTo(TRUE, str, len);
}else{
tempStatus = U_ZERO_ERROR;
}
// store the strings in hash
fZoneStringsHash->put(key, strArray, status);
ures_close(zoneItem);
}
ures_close(zoneArray);
ures_close(root_res);
}
int32_t length = fZoneStringsHash->count();
TimeZoneKeysEnumeration* keysEnum = new TimeZoneKeysEnumeration(length, status);
fZoneIDEnumeration = keysEnum;
if(fZoneIDEnumeration==NULL){
delete fZoneStringsHash;
fZoneStringsHash = NULL;
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
int32_t pos=-1;
const UnicodeString* key;
const UHashElement* elem = NULL;
while((elem = fZoneStringsHash->nextElement(pos))!= NULL){
const UHashTok keyTok = elem->key;
key = (const UnicodeString*)keyTok.pointer;
keysEnum->put(*key, status);
}
}else{
//last resort strings
UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH);
if(array==NULL){
delete fZoneStringsHash;
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
int32_t length = ARRAY_LENGTH(gLastResortZoneStrings);
UnicodeString key(gLastResortZoneStrings[0]);
TimeZoneKeysEnumeration* keysEnum = new TimeZoneKeysEnumeration(length, status);
fZoneIDEnumeration = keysEnum;
if(fZoneIDEnumeration==NULL){
delete fZoneStringsHash;
delete[] array;
fZoneStringsHash = NULL;
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
keysEnum->put(key, status);
int32_t j=1;
for(i=0; i< length; ){
array[i++].setTo(gLastResortZoneStrings[j++]);
}
fZoneStringsHash->put(key, array, status);
}
}
void
DateFormatSymbols::initZoneStrings(const UnicodeString** strings, int32_t rowCount, int32_t columnCount, UErrorCode& status){
if(strings==NULL || rowCount<0 || columnCount<0){
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
TimeZoneKeysEnumeration* keysEnum = new TimeZoneKeysEnumeration(rowCount, status);
fZoneIDEnumeration = keysEnum;
if(U_FAILURE(status)){
return;
}
if(fZoneIDEnumeration==NULL){
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
fZoneStringsHash = new Hashtable(uhash_compareUnicodeString, compareTZHashValues, status);
if(U_FAILURE(status)){
return;
}
if(fZoneStringsHash==NULL){
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
fZoneStringsHash->setValueDeleter(deleteUnicodeStringArray);
for (int32_t row=0; row<rowCount; ++row){
// the first string in the array is the key.
UnicodeString key = strings[row][0];
keysEnum->put(key, status);
UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH);
if(array==NULL){
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
for (int32_t col=1; col<columnCount; ++col) {
// fastCopyFrom() - see assignArray comments
switch (col){
case 1:
array[TIMEZONE_LONG_STANDARD].setTo(strings[row][col]);
break;
case 2:
array[TIMEZONE_SHORT_STANDARD].setTo(strings[row][col]);
break;
case 3:
array[TIMEZONE_LONG_DAYLIGHT].setTo(strings[row][col]);
break;
case 4:
array[TIMEZONE_LONG_DAYLIGHT].setTo(strings[row][col]);
break;
case 5:
array[TIMEZONE_EXEMPLAR_CITY].setTo(strings[row][col]);
break;
case 6:
array[TIMEZONE_LONG_GENERIC].setTo(strings[row][col]);
break;
case 7:
array[TIMEZONE_SHORT_GENERIC].setTo(strings[row][col]);
break;
default:
status = U_ILLEGAL_ARGUMENT_ERROR;
}
// populate the hash table
fZoneStringsHash->put(strings[row][0], array, status);
}
}
}
UnicodeString&
DateFormatSymbols::getZoneString(const UnicodeString &zid, const TimeZoneTranslationType type,
UnicodeString &result, UErrorCode &status){
if(fZoneStringsHash == NULL){
//lazy initialization
initZoneStrings(status);
}
if(U_FAILURE(status)){
return result;
}
UnicodeString* stringsArray = (UnicodeString*)fZoneStringsHash->get(zid);
if(stringsArray != NULL){
result.setTo(stringsArray[type],0);
}
return result;
}
UnicodeString
DateFormatSymbols::getMetazoneString(const UnicodeString &zid, const TimeZoneTranslationType type, Calendar &cal,
UnicodeString &result, UErrorCode &status)
{
UErrorCode tempStatus = U_ZERO_ERROR;
int32_t len;
UnicodeString mzid(UNICODE_STRING_SIMPLE("meta/"));
// Get the appropriate metazone mapping from the resource bundles
char usesMetazoneKey[ZID_KEY_MAX];
char zidkey[ZID_KEY_MAX];
uprv_strcpy(usesMetazoneKey,gZoneStringsTag);
uprv_strcat(usesMetazoneKey,"/");
len = zid.length();
len = (len >= (ZID_KEY_MAX-1) ? ZID_KEY_MAX-1 : len);
u_UCharsToChars(zid.getBuffer(), zidkey, len);
zidkey[len] = 0; // NULL terminate
// Replace / with : for zid
len = (int32_t)uprv_strlen(zidkey);
for (int i = 0; i < len; i++) {
if (zidkey[i] == '/') {
zidkey[i] = ':';
}
}
uprv_strcat(usesMetazoneKey,zidkey);
uprv_strcat(usesMetazoneKey,"/");
uprv_strcat(usesMetazoneKey,UTZ_USES_METAZONE);
UResourceBundle *um = ures_getByKeyWithFallback(fResourceBundle, usesMetazoneKey, NULL, &tempStatus);
if (U_FAILURE(tempStatus)) {
return result;
}
UnicodeString* stringsArray = (UnicodeString*)fZoneStringsHash->get(zid);
if(stringsArray != NULL){
SimpleDateFormat df(UNICODE_STRING_SIMPLE("yyyy-MM-dd HH:mm"), Locale(""),tempStatus);
TimeZone *tz = TimeZone::createTimeZone(zid);
df.setTimeZone(*tz);
delete tz;
UnicodeString theTime;
df.format(cal.getTime(tempStatus),theTime);
while (ures_hasNext(um)) {
UResourceBundle *mz = ures_getNextResource(um,NULL,&status);
const UChar *mz_name = ures_getStringByIndex(mz,0,&len,&status);
const UChar *mz_from = ures_getStringByIndex(mz,1,&len,&status);
const UChar *mz_to = ures_getStringByIndex(mz,2,&len,&status);
ures_close(mz);
if(U_FAILURE(status)){
break;
}
if (mz_name[0] != 0 &&
UnicodeString(TRUE, mz_from, -1) <= theTime &&
UnicodeString(TRUE, mz_to, -1) > theTime )
{
mzid += mz_name;
getZoneString(mzid,type,result,status);
break;
}
}
}
ures_close(um);
if ( mzid.length() > 5 ) {
return mzid;
}
return result;
}
UnicodeString&
DateFormatSymbols::getFallbackString(const UnicodeString &zid, UnicodeString &result, UErrorCode &status)
{
UnicodeString exemplarCity;
char zidkey[ZID_KEY_MAX];
char zoneTerritoryChars[ULOC_COUNTRY_CAPACITY];
UnicodeString displayCountry;
UnicodeString solidus = UNICODE_STRING_SIMPLE("/");
UnicodeString und = UNICODE_STRING_SIMPLE("_");
UnicodeString spc = UNICODE_STRING_SIMPLE(" ");
const UChar* aZone = NULL;
UBool IsMultiZone = FALSE;
int32_t len = zid.length();
len = (len >= (ZID_KEY_MAX-1) ? ZID_KEY_MAX-1 : len);
u_UCharsToChars(zid.getBuffer(), zidkey, len);
zidkey[len] = 0; // NULL terminate
// Replace / with : for zid
len = (int32_t)uprv_strlen(zidkey);
for (int i = 0; i < len; i++) {
if (zidkey[i] == '/') {
zidkey[i] = ':';
}
}
result.remove();
UResourceBundle* supplementalDataBundle = ures_openDirect(NULL, kSUPPLEMENTAL, &status);
if (U_FAILURE(status) || fResourceBundle == NULL ) {
return result;
}
UResourceBundle* zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status);
UResourceBundle* thisZone = ures_getByKey(zoneFormatting, zidkey, NULL, &status);
if (U_FAILURE(status)) {
ures_close(zoneFormatting);
ures_close(supplementalDataBundle);
return result;
}
UResourceBundle* multiZone = ures_getByKey(zoneFormatting, gMultizoneTag, NULL, &status);
const UChar *zoneTerritory = ures_getStringByKey(thisZone,gTerritoryTag,&len,&status);
u_UCharsToChars(zoneTerritory, zoneTerritoryChars, u_strlen(zoneTerritory));
zoneTerritoryChars[u_strlen(zoneTerritory)] = 0; // NULL terminate
UResourceBundle* countries = ures_getByKey(fResourceBundle, gCountriesTag, NULL, &status);
if ( u_strlen(zoneTerritory) > 0 && countries != NULL ) {
displayCountry = ures_getStringByKeyWithFallback(countries,zoneTerritoryChars,&len,&status);
}
if ( U_FAILURE(status) ) {
status = U_ZERO_ERROR;
displayCountry = UnicodeString(zoneTerritory);
}
while ( ures_hasNext(multiZone) ) {
aZone = ures_getNextString(multiZone,&len,NULL,&status);
if ( u_strcmp(aZone,zoneTerritory) == 0 ) {
IsMultiZone = TRUE;
continue;
}
}
if ( IsMultiZone ) {
getZoneString(zid, TIMEZONE_EXEMPLAR_CITY, exemplarCity, status);
if ( exemplarCity.length()==0 ) {
exemplarCity.setTo(UnicodeString(zid,zid.lastIndexOf(solidus)+1));
exemplarCity.findAndReplace(und,spc);
}
Formattable cityCountryArray[2];
UnicodeString pattern = UnicodeString(ures_getStringByKeyWithFallback(fResourceBundle,gFallbackFormatTag,&len,&status));
if ( U_FAILURE(status) ) {
pattern = UNICODE_STRING_SIMPLE("{1} ({0})");
status = U_ZERO_ERROR;
}
cityCountryArray[0].adoptString(new UnicodeString(exemplarCity));
cityCountryArray[1].adoptString(new UnicodeString(displayCountry));
MessageFormat::format(pattern,cityCountryArray, 2, result, status);
} else {
Formattable countryArray[1];
UnicodeString pattern = UnicodeString(ures_getStringByKeyWithFallback(fResourceBundle,gRegionFormatTag,&len,&status));
if ( U_FAILURE(status) ) {
pattern = UNICODE_STRING_SIMPLE("{0}");
status = U_ZERO_ERROR;
}
countryArray[0].adoptString(new UnicodeString(displayCountry));
MessageFormat::format(pattern,countryArray, 1, result, status);
}
ures_close(thisZone);
ures_close(zoneFormatting);
ures_close(supplementalDataBundle);
ures_close(countries);
ures_close(multiZone);
return result;
}
UBool
DateFormatSymbols::isCommonlyUsed(const UnicodeString &zid){
UErrorCode status=U_ZERO_ERROR;
UResourceBundle *zoneArray, *zoneItem, *cuRes;
UnicodeString solidus = UNICODE_STRING_SIMPLE("/");
UnicodeString colon = UNICODE_STRING_SIMPLE(":");
UnicodeString key(zid);
char keychars[ZID_KEY_MAX+1];
key.findAndReplace(solidus,colon);
for(const UResourceBundle* rb = fResourceBundle; rb!=NULL; rb=ures_getParentBundle(rb)){
zoneArray = ures_getByKey(rb, gZoneStringsTag, NULL, &status);
if(U_FAILURE(status)){
status = U_ZERO_ERROR;
continue;
}
int32_t len = key.length();
u_UCharsToChars(key.getBuffer(), keychars, len);
keychars[len] = 0; // NULL terminate
zoneItem = ures_getByKey(zoneArray,keychars,NULL, &status);
if(U_FAILURE(status)){
ures_close(zoneArray);
status = U_ZERO_ERROR;
continue;
}
cuRes = ures_getByKey(zoneItem,UTZ_COMMONLY_USED,NULL,&status);
if(U_FAILURE(status)){
ures_close(zoneItem);
ures_close(zoneArray);
status = U_ZERO_ERROR;
continue;
}
int32_t cuValue = ures_getInt(cuRes,&status);
ures_close(cuRes);
ures_close(zoneItem);
ures_close(zoneArray);
if(U_FAILURE(status)){
status = U_ZERO_ERROR;
continue;
}
if ( cuValue == 1 ) {
return TRUE;
}
}
return FALSE;
}
StringEnumeration*
DateFormatSymbols::createZoneStringIDs(UErrorCode &status){
if(U_FAILURE(status)){
return NULL;
}
if(fZoneStringsHash == NULL){
//lazy initialization
initZoneStrings(status);
}
return fZoneIDEnumeration->clone();
}
/**
* Sets timezone strings.
* @draft ICU 3.6
*/
void
DateFormatSymbols::setZoneString(const UnicodeString &zid, const TimeZoneTranslationType type,
const UnicodeString &value, UErrorCode &status){
if(fZoneStringsHash == NULL){
//lazy initialization
initZoneStrings(status);
}
if(U_FAILURE(status)){
return;
}
UnicodeString* stringsArray = (UnicodeString*)fZoneStringsHash->get(zid);
if(stringsArray != NULL){
stringsArray[type].setTo(value);
}else{
stringsArray = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH);
if(stringsArray==NULL){
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
stringsArray[type].setTo(value);
fZoneStringsHash->put(zid, stringsArray, status);
TimeZoneKeysEnumeration* keys = (TimeZoneKeysEnumeration*) fZoneIDEnumeration;
keys->put(zid, status);
}
}
Hashtable*
DateFormatSymbols::createZoneStringsHash(const Hashtable* otherHash){
UErrorCode status = U_ZERO_ERROR;
Hashtable* hash = new Hashtable(uhash_compareUnicodeString, compareTZHashValues, status);
if(hash==NULL){
return NULL;
}
if(U_FAILURE(status)){
return NULL;
}
hash->setValueDeleter(deleteUnicodeStringArray);
int32_t pos = -1;
const UHashElement* elem = NULL;
// walk through the hash table and create a deep clone
while((elem = otherHash->nextElement(pos))!= NULL){
const UHashTok otherKeyTok = elem->key;
const UHashTok otherValueTok = elem->value;
UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
UnicodeString* otherArray = (UnicodeString*)otherValueTok.pointer;
UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH);
if(array==NULL){
return NULL;
}
UnicodeString key(*otherKey);
for(int32_t i=0; i<UTZ_MAX_DISPLAY_STRINGS_LENGTH; i++){
array[i].setTo(otherArray[i]);
}
hash->put(key, array, status);
if(U_FAILURE(status)){
delete[] array;
return NULL;
}
}
return hash;
}
UnicodeString&
DateFormatSymbols::getZoneID(const UnicodeString& zid, UnicodeString& result, UErrorCode& status){
if(fZoneStringsHash == NULL){
initZoneStrings(status);
}
if(U_FAILURE(status)){
return result;
}
UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(zid);
if (strings != NULL) {
return result.setTo(zid,0);
}
// Do a search through the equivalency group for the given ID
int32_t n = TimeZone::countEquivalentIDs(zid);
if (n > 1) {
int32_t i;
for (i=0; i<n; ++i) {
UnicodeString equivID = TimeZone::getEquivalentID(zid, i);
if (equivID != zid) {
strings = (UnicodeString*)fZoneStringsHash->get(equivID);
if (strings != NULL) {
return result.setTo(equivID,0);
}
}
}
}else{
result.setTo(zid);
}
return result;
}
void
DateFormatSymbols::getZoneType(const UnicodeString& zid, const UnicodeString& text, int32_t start,
TimeZoneTranslationType& type, UnicodeString& value, UErrorCode& status){
if(fZoneStringsHash == NULL){
initZoneStrings(status);
}
if(U_FAILURE(status)){
return;
}
type = TIMEZONE_COUNT;
UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(zid);
if(strings != NULL){
for(int32_t j=0; j<UTZ_MAX_DISPLAY_STRINGS_LENGTH; j++){
if(strings[j].length() >0 && text.caseCompare(start, strings[j].length(), strings[j], 0)==0){
type = (TimeZoneTranslationType)j;
value.setTo(strings[j]);
return;
}
}
}
}
void
DateFormatSymbols::findZoneIDTypeValue( UnicodeString& zid, const UnicodeString& text, int32_t start,
TimeZoneTranslationType& type, UnicodeString& value,
UErrorCode& status){
if(fZoneStringsHash == NULL){
initZoneStrings(status);
}
if(U_FAILURE(status)){
return;
}
const UnicodeString* myKey = NULL;
int32_t pos = 0;
TimeZoneKeysEnumeration *keys = (TimeZoneKeysEnumeration*)fZoneIDEnumeration;
while( (myKey=keys->snext(pos, status))!= NULL){
UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(*myKey);
if(strings != NULL){
for(int32_t j=0; j<UTZ_MAX_DISPLAY_STRINGS_LENGTH; j++){
if(strings[j].length()>0 && text.caseCompare(start, strings[j].length(), strings[j], 0)==0){
type = (TimeZoneTranslationType)j;
value.setTo(strings[j]);
if (myKey->startsWith(UNICODE_STRING_SIMPLE("meta"))) {
zid.setTo(resolveParsedMetazone(*myKey));
}
else {
zid.setTo(*myKey);
}
return;
}
}
}
}
// Check for generic tz fallback strings if we have gone through all zone strings and haven't found
// anything.
UnicodeString fbString;
StringEnumeration *tzKeys = TimeZone::createEnumeration();
while( (myKey=tzKeys->snext(status))!= NULL){
status = U_ZERO_ERROR;
this->getFallbackString(*myKey,fbString,status);
if ( U_FAILURE(status) ) {
status = U_ZERO_ERROR;
continue;
}
if(fbString.length()>0 && text.compare(start, fbString.length(), fbString)==0){
type = (TimeZoneTranslationType) TIMEZONE_LONG_GENERIC;
value.setTo(fbString);
zid.setTo(*myKey);
break;
}
}
delete tzKeys;
}
UnicodeString
DateFormatSymbols::resolveParsedMetazone( const UnicodeString& zid ) {
UErrorCode status = U_ZERO_ERROR;
UResourceBundle* supplementalDataBundle = ures_openDirect(NULL, kSUPPLEMENTAL, &status);
UResourceBundle* mapTz = ures_getByKey(supplementalDataBundle, gMaptimezonesTag, NULL, &status);
if(U_FAILURE(status)){
ures_close(supplementalDataBundle);
return UNICODE_STRING_SIMPLE("Etc/GMT");
}
UResourceBundle* metazoneMap = ures_getByKey(mapTz, gMetazonesTag, NULL, &status);
char mzMapKey[ZID_KEY_MAX+4];
int32_t len = zid.length();
len = (len >= (ZID_KEY_MAX-1) ? ZID_KEY_MAX-1 : len);
u_UCharsToChars(zid.getBuffer(), mzMapKey, len);
mzMapKey[len] = 0; // NULL terminate
for (int i = 0; i < len; i++) {
if (mzMapKey[i] == '/') {
mzMapKey[i] = ':';
}
}
uprv_strcat(mzMapKey,"_");
uprv_strcat(mzMapKey,fCountry);
int32_t len2;
const UChar* resStr = ures_getStringByKey(metazoneMap, mzMapKey, &len2, &status);
// If we can't find a territory-specific metazone mapping, then use the generic one
// which is the metazone name followed by _001
if(U_FAILURE(status)){
status = U_ZERO_ERROR;
mzMapKey[len] = 0;
uprv_strcat(mzMapKey,"_001");
resStr = ures_getStringByKey(metazoneMap, mzMapKey, &len2, &status);
}
ures_close(metazoneMap);
ures_close(mapTz);
ures_close(supplementalDataBundle);
if(U_SUCCESS(status)){
return resStr;
}
else {
return UNICODE_STRING_SIMPLE("Etc/GMT");
}
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
//eof