+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
-* Copyright (C) 2007-2010, International Business Machines Corporation and
+* Copyright (C) 2007-2016, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
-#include <typeinfo> // for 'typeid' to work
+#include "utypeinfo.h" // for 'typeid' to work
#include "unicode/utypes.h"
#include "cmemory.h"
#include "uvector.h"
#include "gregoimp.h"
-#include "uhash.h"
+#include "uassert.h"
U_NAMESPACE_BEGIN
digits[i++] = number % 10;
number /= 10;
} while (number != 0);
- length = i;
+ length = static_cast<uint8_t>(i);
} else {
// fixed digits
for (i = 0; i < length; i++) {
/*
* Create a default TZNAME from TZID
*/
-static void getDefaultTZName(const UnicodeString tzid, UBool isDST, UnicodeString& zonename) {
+static void getDefaultTZName(const UnicodeString &tzid, UBool isDST, UnicodeString& zonename) {
zonename = tzid;
if (isDST) {
zonename += UNICODE_STRING_SIMPLE("(DST)");
goto rruleParseError;
}
- if (attr.compare(ICAL_FREQ) == 0) {
+ if (attr.compare(ICAL_FREQ, -1) == 0) {
// only support YEARLY frequency type
- if (value.compare(ICAL_YEARLY) == 0) {
+ if (value.compare(ICAL_YEARLY, -1) == 0) {
yearly = TRUE;
} else {
goto rruleParseError;
}
- } else if (attr.compare(ICAL_UNTIL) == 0) {
+ } else if (attr.compare(ICAL_UNTIL, -1) == 0) {
// ISO8601 UTC format, for example, "20060315T020000Z"
until = parseDateTimeString(value, 0, status);
if (U_FAILURE(status)) {
goto rruleParseError;
}
- } else if (attr.compare(ICAL_BYMONTH) == 0) {
+ } else if (attr.compare(ICAL_BYMONTH, -1) == 0) {
// Note: BYMONTH may contain multiple months, but only single month make sense for
// VTIMEZONE property.
if (value.length() > 2) {
if (U_FAILURE(status) || month < 0 || month >= 12) {
goto rruleParseError;
}
- } else if (attr.compare(ICAL_BYDAY) == 0) {
+ } else if (attr.compare(ICAL_BYDAY, -1) == 0) {
// Note: BYDAY may contain multiple day of week separated by comma. It is unlikely used for
// VTIMEZONE property. We do not support the case.
} else {
goto rruleParseError;
}
- } else if (attr.compare(ICAL_BYMONTHDAY) == 0) {
+ } else if (attr.compare(ICAL_BYMONTHDAY, -1) == 0) {
// Note: BYMONTHDAY may contain multiple days delimitted by comma
//
// A value of BYMONTHDAY could be negative, for example, -1 means
UnicodeString rrule = *((UnicodeString*)dates->elementAt(0));
int32_t month, dayOfWeek, nthDayOfWeek, dayOfMonth = 0;
int32_t days[7];
- int32_t daysCount = sizeof(days)/sizeof(days[0]);
+ int32_t daysCount = UPRV_LENGTHOF(days);
UDate until;
parseRRULE(rrule, month, dayOfWeek, nthDayOfWeek, days, daysCount, until, status);
UDate tmp_until;
int32_t tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek;
int32_t tmp_days[7];
- int32_t tmp_daysCount = sizeof(tmp_days)/sizeof(tmp_days[0]);
+ int32_t tmp_daysCount = UPRV_LENGTHOF(tmp_days);
parseRRULE(rrule, tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek, tmp_days, tmp_daysCount, tmp_until, status);
if (U_FAILURE(status)) {
return NULL;
void write(const UnicodeString& str);
void write(UChar ch);
+ void write(const UChar* str);
//void write(const UChar* str, int32_t length);
private:
UnicodeString* out;
out->append(ch);
}
+void
+VTZWriter::write(const UChar* str) {
+ out->append(str, -1);
+}
+
/*
void
VTZWriter::write(const UChar* str, int32_t length) {
if (source.vtzlines != NULL) {
UErrorCode status = U_ZERO_ERROR;
int32_t size = source.vtzlines->size();
- vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, size, status);
+ vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
if (U_SUCCESS(status)) {
for (int32_t i = 0; i < size; i++) {
UnicodeString *line = (UnicodeString*)source.vtzlines->elementAt(i);
if (right.vtzlines != NULL) {
UErrorCode status = U_ZERO_ERROR;
int32_t size = right.vtzlines->size();
- vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, size, status);
+ vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
if (U_SUCCESS(status)) {
for (int32_t i = 0; i < size; i++) {
UnicodeString *line = (UnicodeString*)right.vtzlines->elementAt(i);
}
void
-VTimeZone::write(UDate start, UnicodeString& result, UErrorCode& status) /*const*/ {
+VTimeZone::write(UDate start, UnicodeString& result, UErrorCode& status) const {
result.remove();
VTZWriter writer(result);
write(start, writer, status);
}
void
-VTimeZone::writeSimple(UDate time, UnicodeString& result, UErrorCode& status) /*const*/ {
+VTimeZone::writeSimple(UDate time, UnicodeString& result, UErrorCode& status) const {
result.remove();
VTZWriter writer(result);
writeSimple(time, writer, status);
}
UBool
-VTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+VTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
return tz->getNextTransition(base, inclusive, result);
}
UBool
-VTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+VTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
return tz->getPreviousTransition(base, inclusive, result);
}
int32_t
-VTimeZone::countTransitionRules(UErrorCode& status) /*const*/ {
+VTimeZone::countTransitionRules(UErrorCode& status) const {
return tz->countTransitionRules(status);
}
void
VTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
const TimeZoneRule* trsrules[], int32_t& trscount,
- UErrorCode& status) /*const*/ {
+ UErrorCode& status) const {
tz->getTimeZoneRules(initial, trsrules, trscount, status);
}
void
VTimeZone::load(VTZReader& reader, UErrorCode& status) {
- vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, DEFAULT_VTIMEZONE_LINES, status);
+ vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, DEFAULT_VTIMEZONE_LINES, status);
if (U_FAILURE(status)) {
return;
}
UChar ch = reader.read();
if (ch == 0xFFFF) {
// end of file
- if (start && line.startsWith(ICAL_END_VTIMEZONE)) {
+ if (start && line.startsWith(ICAL_END_VTIMEZONE, -1)) {
vtzlines->addElement(new UnicodeString(line), status);
if (U_FAILURE(status)) {
goto cleanupVtzlines;
// LF
eol = TRUE;
if (start) {
- if (line.startsWith(ICAL_END_VTIMEZONE)) {
+ if (line.startsWith(ICAL_END_VTIMEZONE, -1)) {
vtzlines->addElement(new UnicodeString(line), status);
if (U_FAILURE(status)) {
goto cleanupVtzlines;
break;
}
} else {
- if (line.startsWith(ICAL_BEGIN_VTIMEZONE)) {
+ if (line.startsWith(ICAL_BEGIN_VTIMEZONE, -1)) {
vtzlines->addElement(new UnicodeString(line), status);
if (U_FAILURE(status)) {
goto cleanupVtzlines;
// Set the deleter to remove TimeZoneRule vectors to avoid memory leaks due to unowned TimeZoneRules.
rules->setDeleter(deleteTimeZoneRule);
- dates = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ dates = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
if (U_FAILURE(status)) {
goto cleanupParse;
}
switch (state) {
case INI:
- if (name.compare(ICAL_BEGIN) == 0
- && value.compare(ICAL_VTIMEZONE) == 0) {
+ if (name.compare(ICAL_BEGIN, -1) == 0
+ && value.compare(ICAL_VTIMEZONE, -1) == 0) {
state = VTZ;
}
break;
case VTZ:
- if (name.compare(ICAL_TZID) == 0) {
+ if (name.compare(ICAL_TZID, -1) == 0) {
tzid = value;
- } else if (name.compare(ICAL_TZURL) == 0) {
+ } else if (name.compare(ICAL_TZURL, -1) == 0) {
tzurl = value;
- } else if (name.compare(ICAL_LASTMOD) == 0) {
+ } else if (name.compare(ICAL_LASTMOD, -1) == 0) {
// Always in 'Z' format, so the offset argument for the parse method
// can be any value.
lastmod = parseDateTimeString(value, 0, status);
if (U_FAILURE(status)) {
goto cleanupParse;
}
- } else if (name.compare(ICAL_BEGIN) == 0) {
- UBool isDST = (value.compare(ICAL_DAYLIGHT) == 0);
- if (value.compare(ICAL_STANDARD) == 0 || isDST) {
+ } else if (name.compare(ICAL_BEGIN, -1) == 0) {
+ UBool isDST = (value.compare(ICAL_DAYLIGHT, -1) == 0);
+ if (value.compare(ICAL_STANDARD, -1) == 0 || isDST) {
// tzid must be ready at this point
if (tzid.length() == 0) {
goto cleanupParse;
// must not be there.
goto cleanupParse;
}
- } else if (name.compare(ICAL_END) == 0) {
+ } else if (name.compare(ICAL_END, -1) == 0) {
break;
}
break;
case TZI:
- if (name.compare(ICAL_DTSTART) == 0) {
+ if (name.compare(ICAL_DTSTART, -1) == 0) {
dtstart = value;
- } else if (name.compare(ICAL_TZNAME) == 0) {
+ } else if (name.compare(ICAL_TZNAME, -1) == 0) {
zonename = value;
- } else if (name.compare(ICAL_TZOFFSETFROM) == 0) {
+ } else if (name.compare(ICAL_TZOFFSETFROM, -1) == 0) {
from = value;
- } else if (name.compare(ICAL_TZOFFSETTO) == 0) {
+ } else if (name.compare(ICAL_TZOFFSETTO, -1) == 0) {
to = value;
- } else if (name.compare(ICAL_RDATE) == 0) {
+ } else if (name.compare(ICAL_RDATE, -1) == 0) {
// RDATE mixed with RRULE is not supported
if (isRRULE) {
goto cleanupParse;
}
dstart = dend + 1;
}
- } else if (name.compare(ICAL_RRULE) == 0) {
+ } else if (name.compare(ICAL_RRULE, -1) == 0) {
// RRULE mixed with RDATE is not supported
if (!isRRULE && dates->size() != 0) {
goto cleanupParse;
if (U_FAILURE(status)) {
goto cleanupParse;
}
- } else if (name.compare(ICAL_END) == 0) {
+ } else if (name.compare(ICAL_END, -1) == 0) {
// Mandatory properties
if (dtstart.length() == 0 || from.length() == 0 || to.length() == 0) {
goto cleanupParse;
if (vtzlines != NULL) {
for (int32_t i = 0; i < vtzlines->size(); i++) {
UnicodeString *line = (UnicodeString*)vtzlines->elementAt(i);
- if (line->startsWith(ICAL_TZURL)
+ if (line->startsWith(ICAL_TZURL, -1)
&& line->charAt(u_strlen(ICAL_TZURL)) == COLON) {
writer.write(ICAL_TZURL);
writer.write(COLON);
writer.write(tzurl);
writer.write(ICAL_NEWLINE);
- } else if (line->startsWith(ICAL_LASTMOD)
+ } else if (line->startsWith(ICAL_LASTMOD, -1)
&& line->charAt(u_strlen(ICAL_LASTMOD)) == COLON) {
UnicodeString utcString;
writer.write(ICAL_LASTMOD);
}
}
} else {
- UVector *customProps = NULL;
+ UnicodeString icutzprop;
+ UVector customProps(nullptr, uhash_compareUnicodeString, status);
if (olsonzid.length() > 0 && icutzver.length() > 0) {
- customProps = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
- if (U_FAILURE(status)) {
- return;
- }
- UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
- icutzprop->append(olsonzid);
- icutzprop->append((UChar)0x005B/*'['*/);
- icutzprop->append(icutzver);
- icutzprop->append((UChar)0x005D/*']'*/);
- customProps->addElement(icutzprop, status);
- if (U_FAILURE(status)) {
- delete icutzprop;
- delete customProps;
- return;
- }
+ icutzprop.append(olsonzid);
+ icutzprop.append(u'[');
+ icutzprop.append(icutzver);
+ icutzprop.append(u']');
+ customProps.addElement(&icutzprop, status);
}
- writeZone(writer, *tz, customProps, status);
- delete customProps;
+ writeZone(writer, *tz, &customProps, status);
}
}
void
-VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) /*const*/ {
+VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
InitialTimeZoneRule *initial = NULL;
UVector *transitionRules = NULL;
- UVector customProps(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
UnicodeString tzid;
// Extract rules applicable to dates after the start time
icutzprop->append(olsonzid);
icutzprop->append((UChar)0x005B/*'['*/);
icutzprop->append(icutzver);
- icutzprop->append(ICU_TZINFO_PARTIAL);
+ icutzprop->append(ICU_TZINFO_PARTIAL, -1);
appendMillis(start, *icutzprop);
icutzprop->append((UChar)0x005D/*']'*/);
customProps.addElement(icutzprop, status);
}
void
-VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) /*const*/ {
+VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
- UVector customProps(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
UnicodeString tzid;
// Extract simple rules
icutzprop->append(olsonzid);
icutzprop->append((UChar)0x005B/*'['*/);
icutzprop->append(icutzver);
- icutzprop->append(ICU_TZINFO_SIMPLE);
+ icutzprop->append(ICU_TZINFO_SIMPLE, -1);
appendMillis(time, *icutzprop);
icutzprop->append((UChar)0x005D/*']'*/);
customProps.addElement(icutzprop, status);
if (U_FAILURE(status)) {
goto cleanupWriteZone;
}
- writeFinalRule(w, TRUE, finalDstRule,
- dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, dstStartTime, status);
+ UDate nextStart;
+ UBool nextStartAvail = finalDstRule->getNextStart(dstUntilTime, dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, false, nextStart);
+ U_ASSERT(nextStartAvail);
+ if (nextStartAvail) {
+ writeFinalRule(w, TRUE, finalDstRule,
+ dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, nextStart, status);
+ }
}
}
if (U_FAILURE(status)) {
// Use a single rule if possible
if (isEquivalentDateRule(stdMonth, stdWeekInMonth, stdDayOfWeek, finalStdRule->getRule())) {
writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
- stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, MAX_MILLIS, status);
+ stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, MAX_MILLIS, status);
} else {
// Not equivalent rule - write out two different rules
writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
if (U_FAILURE(status)) {
goto cleanupWriteZone;
}
- writeFinalRule(w, FALSE, finalStdRule,
- stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, stdStartTime, status);
+ UDate nextStart;
+ UBool nextStartAvail = finalStdRule->getNextStart(stdUntilTime, stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, false, nextStart);
+ U_ASSERT(nextStartAvail);
+ if (nextStartAvail) {
+ writeFinalRule(w, FALSE, finalStdRule,
+ stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, nextStart, status);
+ }
}
}
if (U_FAILURE(status)) {