diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp
index e656a7a8b90..6ed008df614 100644
--- a/icu4c/source/i18n/timezone.cpp
+++ b/icu4c/source/i18n/timezone.cpp
@@ -1,6 +1,6 @@
/*
*******************************************************************************
-* Copyright (C) 1997-2013, International Business Machines Corporation and
+* Copyright (C) 1997-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
@@ -1293,6 +1293,8 @@ TimeZone::getCustomID(const UnicodeString& id, UnicodeString& normalized, UError
int32_t sign, hour, min, sec;
if (parseCustomID(id, sign, hour, min, sec)) {
formatCustomID(hour, min, sec, (sign < 0), normalized);
+ } else {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
}
return normalized;
}
@@ -1538,6 +1540,11 @@ TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode
getCanonicalID(id, canonicalID, isSystemID, status);
if (U_FAILURE(status) || !isSystemID) {
// mapping data is only applicable to tz database IDs
+ if (status == U_ILLEGAL_ARGUMENT_ERROR) {
+ // getWindowsID() sets an empty string where
+ // getCanonicalID() sets a U_ILLEGAL_ARGUMENT_ERROR.
+ status = U_ZERO_ERROR;
+ }
return winid;
}
diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h
index 6be60e07108..6490879f792 100644
--- a/icu4c/source/i18n/unicode/timezone.h
+++ b/icu4c/source/i18n/unicode/timezone.h
@@ -1,5 +1,5 @@
/*************************************************************************
-* Copyright (c) 1997-2013, International Business Machines Corporation
+* Copyright (c) 1997-2014, International Business Machines Corporation
* and others. All Rights Reserved.
**************************************************************************
*
@@ -330,7 +330,7 @@ public:
* @param id The input time zone ID to be canonicalized.
* @param canonicalID Receives the canonical system time zone ID
* or the custom time zone ID in normalized format.
- * @param status Recevies the status. When the given time zone ID
+ * @param status Receives the status. When the given time zone ID
* is neither a known system time zone ID nor a
* valid custom time zone ID, U_ILLEGAL_ARGUMENT_ERROR
* is set.
@@ -348,7 +348,7 @@ public:
* or the custom time zone ID in normalized format.
* @param isSystemID Receives if the given ID is a known system
* time zone ID.
- * @param status Recevies the status. When the given time zone ID
+ * @param status Receives the status. When the given time zone ID
* is neither a known system time zone ID nor a
* valid custom time zone ID, U_ILLEGAL_ARGUMENT_ERROR
* is set.
diff --git a/icu4c/source/i18n/unicode/tzfmt.h b/icu4c/source/i18n/unicode/tzfmt.h
index fa8e8d64442..cb1006deae3 100644
--- a/icu4c/source/i18n/unicode/tzfmt.h
+++ b/icu4c/source/i18n/unicode/tzfmt.h
@@ -1,7 +1,7 @@
/*
*******************************************************************************
-* Copyright (C) 2011-2013, International Business Machines Corporation and *
-* others. All Rights Reserved. *
+* Copyright (C) 2011-2014, International Business Machines Corporation and
+* others. All Rights Reserved.
*******************************************************************************
*/
#ifndef __TZFMT_H
@@ -302,7 +302,7 @@ public:
/**
* Creates an instance of TimeZoneFormat
for the given locale.
* @param locale The locale.
- * @param status Recevies the status.
+ * @param status Receives the status.
* @return An instance of TimeZoneFormat
for the given locale,
* owned by the caller.
* @stable ICU 50
diff --git a/icu4c/source/i18n/unicode/tznames.h b/icu4c/source/i18n/unicode/tznames.h
index 78669d466b4..acd40f4a94d 100644
--- a/icu4c/source/i18n/unicode/tznames.h
+++ b/icu4c/source/i18n/unicode/tznames.h
@@ -1,7 +1,7 @@
/*
*******************************************************************************
-* Copyright (C) 2011-2013, International Business Machines Corporation and *
-* others. All Rights Reserved. *
+* Copyright (C) 2011-2014, International Business Machines Corporation and
+* others. All Rights Reserved.
*******************************************************************************
*/
#ifndef __TZNAMES_H
@@ -163,7 +163,7 @@ public:
* Returns an instance of TimeZoneDisplayNames
for the specified locale.
*
* @param locale The locale.
- * @param status Recevies the status.
+ * @param status Receives the status.
* @return An instance of TimeZoneDisplayNames
* @stable ICU 50
*/
@@ -171,7 +171,7 @@ public:
/**
* Returns an enumeration of all available meta zone IDs.
- * @param status Recevies the status.
+ * @param status Receives the status.
* @return an enumeration object, owned by the caller.
* @stable ICU 50
*/
@@ -180,7 +180,7 @@ public:
/**
* Returns an enumeration of all available meta zone IDs used by the given time zone.
* @param tzID The canoical tiem zone ID.
- * @param status Recevies the status.
+ * @param status Receives the status.
* @return an enumeration object, owned by the caller.
* @stable ICU 50
*/
diff --git a/icu4c/source/i18n/unicode/ucal.h b/icu4c/source/i18n/unicode/ucal.h
index 8f0cccc4513..276e49af04e 100644
--- a/icu4c/source/i18n/unicode/ucal.h
+++ b/icu4c/source/i18n/unicode/ucal.h
@@ -1,6 +1,6 @@
/*
*******************************************************************************
- * Copyright (C) 1996-2013, International Business Machines Corporation and
+ * Copyright (C) 1996-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
@@ -1289,7 +1289,7 @@ ucal_getTZDataVersion(UErrorCode* status);
* @param resultCapacity The capacity of the result buffer.
* @param isSystemID Receives if the given ID is a known system
* timezone ID.
- * @param status Recevies the status. When the given timezone ID
+ * @param status Receives the status. When the given timezone ID
* is neither a known system time zone ID nor a
* valid custom timezone ID, U_ILLEGAL_ARGUMENT_ERROR
* is set.
diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp
index 1d34af5a9b7..be71a3b4fd9 100644
--- a/icu4c/source/i18n/zonemeta.cpp
+++ b/icu4c/source/i18n/zonemeta.cpp
@@ -1,6 +1,6 @@
/*
*******************************************************************************
-* Copyright (C) 2007-2013, International Business Machines Corporation and
+* Copyright (C) 2007-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
@@ -27,6 +27,8 @@
#include "uhash.h"
#include "olsontz.h"
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
static UMutex gZoneMetaLock = U_MUTEX_INITIALIZER;
// CLDR Canonical ID mapping table
@@ -235,8 +237,7 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
return NULL;
}
- int32_t len = tzid.length();
- if (len > ZID_KEY_MAX) {
+ if (tzid.isBogus() || tzid.length() > ZID_KEY_MAX) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
@@ -268,10 +269,7 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
// If not, resolve CLDR canonical ID with resource data
UBool isInputCanonical = FALSE;
char id[ZID_KEY_MAX + 1];
- const UChar* idChars = tzid.getBuffer();
-
- u_UCharsToChars(idChars,id,len);
- id[len] = (char) 0; // Make sure it is null terminated.
+ tzid.extract(0, 0x7fffffff, id, LENGTHOF(id), US_INV);
// replace '/' with ':'
char *p = id;
@@ -309,7 +307,7 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
if (derefer == NULL) {
status = U_ILLEGAL_ARGUMENT_ERROR;
} else {
- len = u_strlen(derefer);
+ int32_t len = u_strlen(derefer);
u_UCharsToChars(derefer,id,len);
id[len] = (char) 0; // Make sure it is null terminated.
@@ -717,7 +715,7 @@ ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &re
char keyBuf[ZID_KEY_MAX + 1];
int32_t keyLen = 0;
- if (mzid.length() > ZID_KEY_MAX) {
+ if (mzid.isBogus() || mzid.length() > ZID_KEY_MAX) {
result.setToBogus();
return result;
}
diff --git a/icu4c/source/test/intltest/tztest.cpp b/icu4c/source/test/intltest/tztest.cpp
index af4a570bdcc..dc25974e79c 100644
--- a/icu4c/source/test/intltest/tztest.cpp
+++ b/icu4c/source/test/intltest/tztest.cpp
@@ -66,6 +66,7 @@ void TimeZoneTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
TESTCASE_AUTO(TestAliasedNames);
TESTCASE_AUTO(TestFractionalDST);
TESTCASE_AUTO(TestFebruary);
+ TESTCASE_AUTO(TestCanonicalIDAPI);
TESTCASE_AUTO(TestCanonicalID);
TESTCASE_AUTO(TestDisplayNamesMeta);
TESTCASE_AUTO(TestGetRegion);
@@ -1938,6 +1939,34 @@ void TimeZoneTest::TestFebruary() {
}
}
}
+
+void TimeZoneTest::TestCanonicalIDAPI() {
+ // Bogus input string.
+ UnicodeString bogus;
+ bogus.setToBogus();
+ UnicodeString canonicalID;
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString *pResult = &TimeZone::getCanonicalID(bogus, canonicalID, ec);
+ assertEquals("TimeZone::getCanonicalID(bogus) should fail", U_ILLEGAL_ARGUMENT_ERROR, ec);
+ assertTrue("TimeZone::getCanonicalID(bogus) should return the dest string", pResult == &canonicalID);
+
+ // U_FAILURE on input.
+ UnicodeString berlin("Europe/Berlin");
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ pResult = &TimeZone::getCanonicalID(berlin, canonicalID, ec);
+ assertEquals("TimeZone::getCanonicalID(failure) should fail", U_MEMORY_ALLOCATION_ERROR, ec);
+ assertTrue("TimeZone::getCanonicalID(failure) should return the dest string", pResult == &canonicalID);
+
+ // Valid input should un-bogus the dest string.
+ canonicalID.setToBogus();
+ ec = U_ZERO_ERROR;
+ pResult = &TimeZone::getCanonicalID(berlin, canonicalID, ec);
+ assertSuccess("TimeZone::getCanonicalID(bogus dest) should succeed", ec);
+ assertTrue("TimeZone::getCanonicalID(bogus dest) should return the dest string", pResult == &canonicalID);
+ assertFalse("TimeZone::getCanonicalID(bogus dest) should un-bogus the dest string", canonicalID.isBogus());
+ assertEquals("TimeZone::getCanonicalID(bogus dest) unexpected result", canonicalID, berlin);
+}
+
void TimeZoneTest::TestCanonicalID() {
// Some canonical IDs in CLDR are defined as "Link"
diff --git a/icu4c/source/test/intltest/tztest.h b/icu4c/source/test/intltest/tztest.h
index 0fbe93fb6a8..f1737ca794f 100644
--- a/icu4c/source/test/intltest/tztest.h
+++ b/icu4c/source/test/intltest/tztest.h
@@ -1,6 +1,6 @@
/********************************************************************
- * Copyright (c) 1997-2013, International Business Machines
+ * Copyright (c) 1997-2014, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************/
@@ -90,6 +90,7 @@ public:
void TestFebruary(void);
+ void TestCanonicalIDAPI();
void TestCanonicalID(void);
virtual void TestDisplayNamesMeta();