From f6e3124e74d8dda826a1f4e834ea6be0ec25ac92 Mon Sep 17 00:00:00 2001 From: Yoshito Umaoka Date: Wed, 25 Oct 2017 23:41:57 +0000 Subject: [PATCH] ICU-13445 Pattern space handling in localized GMT format parser. Applied a fix to ICU4J equivalent to the ICU4C fix done by #13374. Also made a small fix in the previous ICU4C change to prevent buffer overrun with unexpected input. X-SVN-Rev: 40642 --- icu4c/source/i18n/tzfmt.cpp | 4 ++-- .../src/com/ibm/icu/text/TimeZoneFormat.java | 22 ++++++++++++++++++- .../dev/test/format/TimeZoneFormatTest.java | 6 +---- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/icu4c/source/i18n/tzfmt.cpp b/icu4c/source/i18n/tzfmt.cpp index 9e8f6081bc9..3de84f42940 100644 --- a/icu4c/source/i18n/tzfmt.cpp +++ b/icu4c/source/i18n/tzfmt.cpp @@ -1869,8 +1869,8 @@ TimeZoneFormat::parseOffsetFieldsWithPattern(const UnicodeString& text, int32_t // leading space characters might be truncated. If the first pattern text // starts with such character (e.g. Bidi control), then we need to // skip the leading space charcters. - if (!PatternProps::isWhiteSpace(text.char32At(idx))) { - for (;;) { + if (idx < text.length() && !PatternProps::isWhiteSpace(text.char32At(idx))) { + while (len > 0) { UChar32 ch; int32_t chLen; U16_GET(patStr, 0, 0, len, ch) diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/TimeZoneFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/TimeZoneFormat.java index fb9b73dcdce..3ac0de71572 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/TimeZoneFormat.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/TimeZoneFormat.java @@ -32,6 +32,7 @@ import java.util.Set; import com.ibm.icu.impl.ICUData; import com.ibm.icu.impl.ICUResourceBundle; +import com.ibm.icu.impl.PatternProps; import com.ibm.icu.impl.SoftCache; import com.ibm.icu.impl.TZDBTimeZoneNames; import com.ibm.icu.impl.TextTrieMap; @@ -2397,7 +2398,26 @@ public class TimeZoneFormat extends UFormat implements Freezable if (patternItems[i] instanceof String) { String patStr = (String)patternItems[i]; int len = patStr.length(); - if (!text.regionMatches(true, idx, patStr, 0, len)) { + int patIdx = 0; + if (i == 0) { + // When TimeZoneFormat parse() is called from SimpleDateFormat, + // leading space characters might be truncated. If the first pattern text + // starts with such character (e.g. Bidi control), then we need to + // skip the leading space characters. + if (idx < text.length() && !PatternProps.isWhiteSpace(text.codePointAt(idx))) { + while (len > 0) { + int cp = patStr.codePointAt(patIdx); + if (PatternProps.isWhiteSpace(cp)) { + int cpLen = Character.charCount(cp); + len -= cpLen; + patIdx += cpLen; + } else { + break; + } + } + } + } + if (!text.regionMatches(true, idx, patStr, patIdx, len)) { failed = true; break; } diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java index 82a48d9e114..8562992d930 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/TimeZoneFormatTest.java @@ -360,7 +360,7 @@ public class TimeZoneFormatTest extends TestFmwk { new ULocale("ko_KR"), new ULocale("nb_NO"), new ULocale("nl_NL"), new ULocale("nn_NO"), new ULocale("pl_PL"), new ULocale("pt"), new ULocale("pt_BR"), new ULocale("pt_PT"), new ULocale("ru_RU"), new ULocale("sv_SE"), new ULocale("th_TH"), new ULocale("tr_TR"), new ULocale("zh"), new ULocale("zh_Hans"), new ULocale("zh_Hans_CN"), - new ULocale("zh_Hant"), new ULocale("zh_Hant_HK"), new ULocale("zh_Hant_TW") + new ULocale("zh_Hant"), new ULocale("zh_Hant_HK"), new ULocale("zh_Hant_TW"), new ULocale("ccp"), new ULocale("fa") }; } else { LOCALES = new ULocale[] { @@ -377,10 +377,6 @@ public class TimeZoneFormatTest extends TestFmwk { int testLen = 0; for (int locidx = 0; locidx < LOCALES.length; locidx++) { logln("Locale: " + LOCALES[locidx].toString()); - if (LOCALES[locidx].getLanguage().equals("fa") - && logKnownIssue("13445", "Bidi control in localized GMT pattern")) { - continue; - } for (int patidx = 0; patidx < PATTERNS.length; patidx++) { logln(" pattern: " + PATTERNS[patidx]); String pattern = BASEPATTERN + " " + PATTERNS[patidx];