diff options
author | Neil <nyamatongwe@gmail.com> | 2013-07-07 11:57:42 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2013-07-07 11:57:42 +1000 |
commit | c8021790271b0895713b6384af69ec4afa98d2a7 (patch) | |
tree | eb2b5a3e22b2b27572c7eef929b47e1f184a43e1 | |
parent | feaf60a96bfb0426e54b5a517b111070e388b97b (diff) | |
download | scintilla-mirror-c8021790271b0895713b6384af69ec4afa98d2a7.tar.gz |
When case conversion changes the length of the text, ensure only
valid memory accessed and that the converted text is selected.
-rw-r--r-- | src/Editor.cxx | 22 | ||||
-rw-r--r-- | test/simpleTests.py | 35 |
2 files changed, 51 insertions, 6 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx index f778ea933..f925beab7 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -5000,18 +5000,28 @@ void Editor::ChangeCaseOfSelection(int caseMapping) { size_t firstDifference = 0; while (sMapped[firstDifference] == sText[firstDifference]) firstDifference++; - size_t lastDifference = sMapped.size() - 1; - while (sMapped[lastDifference] == sText[lastDifference]) - lastDifference--; - size_t endSame = sMapped.size() - 1 - lastDifference; + size_t lastDifferenceText = sText.size() - 1; + size_t lastDifferenceMapped = sMapped.size() - 1; + while (sMapped[lastDifferenceMapped] == sText[lastDifferenceText]) { + lastDifferenceText--; + lastDifferenceMapped--; + } + size_t endDifferenceText = sText.size() - 1 - lastDifferenceText; pdoc->DeleteChars( static_cast<int>(currentNoVS.Start().Position() + firstDifference), - static_cast<int>(rangeBytes - firstDifference - endSame)); + static_cast<int>(rangeBytes - firstDifference - endDifferenceText)); pdoc->InsertString( static_cast<int>(currentNoVS.Start().Position() + firstDifference), sMapped.c_str() + firstDifference, - static_cast<int>(lastDifference - firstDifference + 1)); + static_cast<int>(lastDifferenceMapped - firstDifference + 1)); // Automatic movement changes selection so reset to exactly the same as it was. + int diffSizes = sMapped.size() - sText.size(); + if (diffSizes != 0) { + if (current.anchor > current.caret) + current.anchor.Add(diffSizes); + else + current.caret.Add(diffSizes); + } sel.Range(r) = current; } } diff --git a/test/simpleTests.py b/test/simpleTests.py index a101857f8..e9aef81e2 100644 --- a/test/simpleTests.py +++ b/test/simpleTests.py @@ -1413,6 +1413,41 @@ class TestCaseMapping(unittest.TestCase): self.assertEquals(self.ed.Length, 1) self.assertEquals(self.ed.Contents(), r) + def testUTFGrows(self): + # FIXME: change to using Unicode compliant case conversion on Windows + if sys.platform != "win32": + # This crashed at one point in debug builds due to looking past end of shorter string + self.ed.SetCodePage(65001) + # ﬖ is a single character ligature taking 3 bytes in UTF8: EF AC 96 + t = 'ﬖﬖ'.encode("UTF-8") + self.ed.SetText(len(t), t) + self.assertEquals(self.ed.Length, 6) + self.ed.SetSel(0,self.ed.Length) + self.ed.UpperCase() + # To convert to upper case the ligature is separated into վ and ն then uppercased to Վ and Ն + # each of which takes 2 bytes in UTF-8: D5 8E D5 86 + r = 'ՎՆՎՆ'.encode("UTF-8") + self.assertEquals(self.ed.Length, 8) + self.assertEquals(self.ed.Contents(), r) + self.assertEquals(self.ed.SelectionEnd, self.ed.Length) + + def testUTFShrinks(self): + # FIXME: change to using Unicode compliant case conversion on Windows + if sys.platform != "win32": + self.ed.SetCodePage(65001) + # fi is a single character ligature taking 3 bytes in UTF8: EF AC 81 + t = 'fifi'.encode("UTF-8") + self.ed.SetText(len(t), t) + self.assertEquals(self.ed.Length, 6) + self.ed.SetSel(0,self.ed.Length) + self.ed.UpperCase() + # To convert to upper case the ligature is separated into f and i then uppercased to F and I + # each of which takes 1 byte in UTF-8: 46 49 + r = 'FIFI'.encode("UTF-8") + self.assertEquals(self.ed.Length, 4) + self.assertEquals(self.ed.Contents(), r) + self.assertEquals(self.ed.SelectionEnd, self.ed.Length) + class TestCaseInsensitiveSearch(unittest.TestCase): def setUp(self): self.xite = Xite.xiteFrame |