diff --git a/icu4c/source/common/ucase.cpp b/icu4c/source/common/ucase.cpp index cbd5a6efb56..8414c527d49 100644 --- a/icu4c/source/common/ucase.cpp +++ b/icu4c/source/common/ucase.cpp @@ -270,6 +270,7 @@ ucase_addCaseClosure(UChar32 c, const USetAdder *sa) { } } if(HAS_SLOT(excWord, UCASE_EXC_DELTA)) { + pe=pe0; int32_t delta; GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); sa->add(sa->set, (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta); @@ -1167,7 +1168,7 @@ ucase_toFullLower(UChar32 c, if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_IS_UPPER_OR_TITLE(props)) { int32_t delta; - GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe2, delta); return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; } if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) { @@ -1261,7 +1262,7 @@ toUpperOrTitle(UChar32 c, if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_GET_TYPE(props)==UCASE_LOWER) { int32_t delta; - GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe2, delta); return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; } if(!upperNotTitle && HAS_SLOT(excWord, UCASE_EXC_TITLE)) { @@ -1469,7 +1470,7 @@ ucase_toFullFolding(UChar32 c, } if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_IS_UPPER_OR_TITLE(props)) { int32_t delta; - GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe2, delta); return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; } if(HAS_SLOT(excWord, UCASE_EXC_FOLD)) { diff --git a/icu4c/source/test/intltest/strcase.cpp b/icu4c/source/test/intltest/strcase.cpp index fe983da181c..3fb05849925 100644 --- a/icu4c/source/test/intltest/strcase.cpp +++ b/icu4c/source/test/intltest/strcase.cpp @@ -68,6 +68,7 @@ public: void TestBug13127(); void TestInPlaceTitle(); void TestCaseMapEditsIteratorDocs(); + void TestCaseMapGreekExtended(); private: void assertGreekUpper(const char16_t *s, const char16_t *expected); @@ -113,6 +114,7 @@ StringCaseTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha TESTCASE_AUTO(TestInPlaceTitle); #endif TESTCASE_AUTO(TestCaseMapEditsIteratorDocs); + TESTCASE_AUTO(TestCaseMapGreekExtended); TESTCASE_AUTO_END; } @@ -1685,4 +1687,17 @@ void StringCaseTest::TestCaseMapEditsIteratorDocs() { } } +void StringCaseTest::TestCaseMapGreekExtended() { + // Ticket 13851 + UnicodeString s(u"\u1F80\u1F88\u1FFC"); + UnicodeString result(s); + result.toLower(Locale::getRoot()); + assertEquals(u"lower", u"\u1F80\u1F80\u1FF3", result); +#if !UCONFIG_NO_BREAK_ITERATION + result = s; + result.toTitle(nullptr, Locale::getRoot()); + assertEquals(u"title", u"\u1F88\u1F80\u1FF3", result); +#endif +} + //#endif diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/UCaseProps.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/UCaseProps.java index ae267bbbe79..a925507eed6 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/UCaseProps.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/UCaseProps.java @@ -318,6 +318,7 @@ public final class UCaseProps { } } if(hasSlot(excWord, EXC_DELTA)) { + excOffset=excOffset0; int delta=getSlotValue(excWord, EXC_DELTA, excOffset); set.add((excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta); } @@ -1131,7 +1132,7 @@ public final class UCaseProps { } if(hasSlot(excWord, EXC_DELTA) && isUpperOrTitleFromProps(props)) { - int delta=getSlotValue(excWord, EXC_DELTA, excOffset); + int delta=getSlotValue(excWord, EXC_DELTA, excOffset2); return (excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; } if(hasSlot(excWord, EXC_LOWER)) { @@ -1227,7 +1228,7 @@ public final class UCaseProps { } if(hasSlot(excWord, EXC_DELTA) && getTypeFromProps(props)==LOWER) { - int delta=getSlotValue(excWord, EXC_DELTA, excOffset); + int delta=getSlotValue(excWord, EXC_DELTA, excOffset2); return (excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; } if(!upperNotTitle && hasSlot(excWord, EXC_TITLE)) { @@ -1448,7 +1449,7 @@ public final class UCaseProps { return ~c; } if(hasSlot(excWord, EXC_DELTA) && isUpperOrTitleFromProps(props)) { - int delta=getSlotValue(excWord, EXC_DELTA, excOffset); + int delta=getSlotValue(excWord, EXC_DELTA, excOffset2); return (excWord&EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; } if(hasSlot(excWord, EXC_FOLD)) { diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/lang/UCharacterCaseTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/lang/UCharacterCaseTest.java index 7ee1f55c5a4..1649a718d70 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/lang/UCharacterCaseTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/lang/UCharacterCaseTest.java @@ -1493,6 +1493,16 @@ public final class UCharacterCaseTest extends TestFmwk } } + @Test + public void TestCaseMapGreekExtended() { + // Ticket 13851 + String s = "\u1F80\u1F88\u1FFC"; + String result = CaseMap.toLower().apply(Locale.ROOT, s); + assertEquals("lower", "\u1F80\u1F80\u1FF3", result); + result = CaseMap.toTitle().apply(Locale.ROOT, null, s); + assertEquals("title", "\u1F88\u1F80\u1FF3", result); + } + // private data members - test data -------------------------------------- private static final Locale TURKISH_LOCALE_ = new Locale("tr", "TR");