aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2019-06-15 11:10:49 +1000
committerNeil <nyamatongwe@gmail.com>2019-06-15 11:10:49 +1000
commitae703a47e6ad96c83376f4958f2fafee8135735f (patch)
treee2aed1bbb95bb9064f1189814adf384977670d95
parent835a30b479530979e3b6d5c4a9cfbc469f582723 (diff)
downloadscintilla-mirror-ae703a47e6ad96c83376f4958f2fafee8135735f.tar.gz
Bug [#2110]. Limit text returned from WM_GETTEXT to length specified in wParam.
Changed GetTextLength to use same logic as GetText to ensure they agree.
-rw-r--r--doc/ScintillaHistory.html4
-rw-r--r--test/MessageNumbers.py1
-rw-r--r--test/win32Tests.py162
-rw-r--r--win32/ScintillaWin.cxx39
4 files changed, 185 insertions, 21 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 1ece8653b..659eba28a 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -565,6 +565,10 @@
Lexer added for DataFlex.
<a href="https://sourceforge.net/p/scintilla/feature-requests/1295/">Feature #1295</a>.
</li>
+ <li>
+ On Win32, limit text returned from WM_GETTEXT to the length specified in wParam.
+ <a href="https://sourceforge.net/p/scintilla/bugs/2110/">Bug #2110</a>.
+ </li>
</ul>
<h3>
<a href="https://www.scintilla.org/scite417.zip">Release 4.1.7</a>
diff --git a/test/MessageNumbers.py b/test/MessageNumbers.py
index 782027069..440a0f668 100644
--- a/test/MessageNumbers.py
+++ b/test/MessageNumbers.py
@@ -14,6 +14,7 @@ msgs = {
"WM_EXITSIZEMOVE":562,
"WM_GETMINMAXINFO":36,
"WM_GETTEXT":13,
+"WM_GETTEXTLENGTH":14,
"WM_IME_SETCONTEXT":0x0281,
"WM_IME_NOTIFY":0x0282,
"WM_KEYDOWN":256,
diff --git a/test/win32Tests.py b/test/win32Tests.py
new file mode 100644
index 000000000..21a89dbed
--- /dev/null
+++ b/test/win32Tests.py
@@ -0,0 +1,162 @@
+# -*- coding: utf-8 -*-
+# Requires Python 2.7 or later
+
+# These are tests that run only on Win32 as they use Win32 SendMessage call
+# to send WM_* messages to Scintilla that are not implemented on other platforms.
+# These help Scintilla behave like a Win32 text control and can help screen readers,
+# for example.
+
+from __future__ import with_statement
+from __future__ import unicode_literals
+
+import codecs, ctypes, os, sys, unittest
+
+from MessageNumbers import msgs, sgsm
+
+import ctypes
+user32 = ctypes.windll.user32
+
+import XiteWin as Xite
+
+class TestWins(unittest.TestCase):
+
+ def setUp(self):
+ self.xite = Xite.xiteFrame
+ self.ed = self.xite.ed
+ self.sciHwnd = self.xite.sciHwnd
+ self.ed.ClearAll()
+ self.ed.EmptyUndoBuffer()
+ self.ed.SetCodePage(0)
+ self.ed.SetStatus(0)
+
+ # Helper methods
+
+ def Send(self, msg, w, l):
+ return user32.SendMessageW(self.sciHwnd, msgs[msg], w, l)
+
+ def GetTextLength(self):
+ return self.Send("WM_GETTEXTLENGTH", 0, 0)
+
+ def GetText(self, n, s):
+ # n = The maximum number of characters to be copied, including the terminating null character.
+ # returns the number of characters copied, not including the terminating null character
+ return self.Send("WM_GETTEXT", n, s)
+
+ def TextValue(self):
+ self.assertEquals(self.ed.GetStatus(), 0)
+ lenValue = self.GetTextLength()
+ lenValueWithNUL = lenValue + 1
+ value = ctypes.create_unicode_buffer(lenValueWithNUL)
+ lenData = self.GetText(lenValueWithNUL, value)
+ self.assertEquals(self.ed.GetStatus(), 0)
+ self.assertEquals(lenData, lenValue)
+ return value.value
+
+ def SetText(self, s):
+ return self.Send("WM_SETTEXT", 0, s)
+
+ # Tests
+
+ def testSetText(self):
+ self.SetText(b"ab")
+ self.assertEquals(self.ed.Length, 2)
+
+ def testGetTextLength(self):
+ self.SetText(b"ab")
+ self.assertEquals(self.GetTextLength(), 2)
+
+ def testGetText(self):
+ self.SetText(b"ab")
+ data = ctypes.create_unicode_buffer(100)
+ lenData = self.GetText(100, data)
+ self.assertEquals(lenData, 2)
+ self.assertEquals(len(data.value), 2)
+ self.assertEquals(data.value, "ab")
+
+ def testGetUTF8Text(self):
+ self.ed.SetCodePage(65001)
+ t = "å"
+ tu8 = t.encode("UTF-8")
+ self.SetText(tu8)
+ value = self.TextValue()
+ self.assertEquals(value, t)
+
+ def testGetBadUTF8Text(self):
+ self.ed.SetCodePage(65001)
+ tu8 = b't\xc2'
+ t = "t\xc2"
+ self.SetText(tu8)
+ value = self.TextValue()
+ self.assertEquals(len(value), 2)
+ self.assertEquals(value, t)
+
+ def testGetJISText(self):
+ self.ed.SetCodePage(932)
+ t = "\N{HIRAGANA LETTER KA}"
+ tu8 = t.encode("shift-jis")
+ self.SetText(tu8)
+ value = self.TextValue()
+ self.assertEquals(len(value), 1)
+ self.assertEquals(value, t)
+
+ def testGetBadJISText(self):
+ self.ed.SetCodePage(932)
+ # This is invalid Shift-JIS, surrounded by []
+ tu8 = b'[\x85\xff]'
+ # Win32 uses Katakana Middle Dot to indicate some invalid Shift-JIS text
+ # At other times \uF8F3 is used which is a private use area character
+ # See https://unicodebook.readthedocs.io/operating_systems.html
+ katakanaMiddleDot = '[\N{KATAKANA MIDDLE DOT}]'
+ privateBad = '[\uf8f3]'
+ self.SetText(tu8)
+ value = self.TextValue()
+ self.assertEquals(len(value), 3)
+ self.assertEquals(value, katakanaMiddleDot)
+
+ # This is even less valid Shift-JIS
+ tu8 = b'[\xff]'
+ self.SetText(tu8)
+ value = self.TextValue()
+ self.assertEquals(len(value), 3)
+ self.assertEquals(value, privateBad)
+
+ def testGetTextLong(self):
+ self.assertEquals(self.ed.GetStatus(), 0)
+ self.SetText(b"ab")
+ data = ctypes.create_unicode_buffer(100)
+ lenData = self.GetText(4, data)
+ self.assertEquals(self.ed.GetStatus(), 0)
+ self.assertEquals(lenData, 2)
+ self.assertEquals(data.value, "ab")
+
+ def testGetTextShort(self):
+ self.assertEquals(self.ed.GetStatus(), 0)
+ self.SetText(b"ab")
+ data = ctypes.create_unicode_buffer(100)
+ lenData = self.GetText(2, data)
+ self.assertEquals(self.ed.GetStatus(), 0)
+ self.assertEquals(lenData, 1)
+ self.assertEquals(data.value, "a")
+
+ def testGetTextJustNUL(self):
+ self.assertEquals(self.ed.GetStatus(), 0)
+ self.SetText(b"ab")
+ data = ctypes.create_unicode_buffer(100)
+ lenData = self.GetText(1, data)
+ self.assertEquals(self.ed.GetStatus(), 0)
+ #~ print(data)
+ self.assertEquals(lenData, 0)
+ self.assertEquals(data.value, "")
+
+ def testGetTextZeroLength(self):
+ self.assertEquals(self.ed.GetStatus(), 0)
+ self.SetText(b"ab")
+ data = ctypes.create_unicode_buffer(100)
+ lenData = self.GetText(0, data)
+ self.assertEquals(self.ed.GetStatus(), 0)
+ #~ print(data)
+ self.assertEquals(lenData, 0)
+ self.assertEquals(data.value, "")
+
+if __name__ == '__main__':
+ uu = Xite.main("win32Tests")
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index a11ac94a1..31b9a59c6 100644
--- a/win32/ScintillaWin.cxx
+++ b/win32/ScintillaWin.cxx
@@ -1201,34 +1201,31 @@ UINT ScintillaWin::CodePageOfDocument() const {
}
sptr_t ScintillaWin::GetTextLength() {
- if (pdoc->Length() == 0)
- return 0;
- std::string docBytes(pdoc->Length(), '\0');
- pdoc->GetCharRange(&docBytes[0], 0, pdoc->Length());
- if (IsUnicodeMode()) {
- return UTF16Length(std::string_view(&docBytes[0], docBytes.size()));
- } else {
- return WideCharLenFromMultiByte(CodePageOfDocument(), docBytes);
- }
+ return pdoc->CountUTF16(0, pdoc->Length());
}
sptr_t ScintillaWin::GetText(uptr_t wParam, sptr_t lParam) {
+ if (lParam == 0) {
+ return pdoc->CountUTF16(0, pdoc->Length());
+ }
+ if (wParam == 0) {
+ return 0;
+ }
wchar_t *ptr = static_cast<wchar_t *>(PtrFromSPtr(lParam));
if (pdoc->Length() == 0) {
*ptr = L'\0';
return 0;
}
- std::string docBytes(pdoc->Length(), '\0');
- pdoc->GetCharRange(&docBytes[0], 0, pdoc->Length());
+ const Sci::Position lengthWanted = wParam - 1;
+ Sci::Position sizeRequestedRange = pdoc->GetRelativePositionUTF16(0, lengthWanted);
+ if (sizeRequestedRange < 0) {
+ // Requested more text than there is in the document.
+ sizeRequestedRange = pdoc->CountUTF16(0, pdoc->Length());
+ }
+ std::string docBytes(sizeRequestedRange, '\0');
+ pdoc->GetCharRange(&docBytes[0], 0, sizeRequestedRange);
if (IsUnicodeMode()) {
- const std::string_view sv(&docBytes[0], docBytes.size());
- const size_t lengthUTF16 = UTF16Length(sv);
- if (lParam == 0)
- return lengthUTF16;
- if (wParam == 0)
- return 0;
- size_t uLen = UTF16FromUTF8(sv,
- ptr, wParam - 1);
+ const size_t uLen = UTF16FromUTF8(docBytes, ptr, lengthWanted);
ptr[uLen] = L'\0';
return uLen;
} else {
@@ -1236,8 +1233,8 @@ sptr_t ScintillaWin::GetText(uptr_t wParam, sptr_t lParam) {
// Convert to Unicode using the current Scintilla code page
const UINT cpSrc = CodePageOfDocument();
int lengthUTF16 = WideCharLenFromMultiByte(cpSrc, docBytes);
- if (lengthUTF16 >= static_cast<int>(wParam))
- lengthUTF16 = static_cast<int>(wParam)-1;
+ if (lengthUTF16 > lengthWanted)
+ lengthUTF16 = static_cast<int>(lengthWanted);
WideCharFromMultiByte(cpSrc, docBytes, ptr, lengthUTF16);
ptr[lengthUTF16] = L'\0';
return lengthUTF16;