From e09d87f54bdfe7fcfff004162d1faacdf50611c7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 2 Nov 2017 23:33:57 +0100 Subject: [PATCH 1/3] Move wxStringOutputStream ctor to the source file There is no real need for this not quite trivial function to be inline. No real changes. --- include/wx/sstream.h | 10 +--------- src/common/sstream.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/wx/sstream.h b/include/wx/sstream.h index 19f37c58d3..f24419f8ad 100644 --- a/include/wx/sstream.h +++ b/include/wx/sstream.h @@ -63,15 +63,7 @@ public: // Note that the conversion object should have the life time greater than // this stream. wxStringOutputStream(wxString *pString = NULL, - wxMBConv& conv = wxConvUTF8) - : m_conv(conv) -#if wxUSE_UNICODE - , m_unconv(0) -#endif // wxUSE_UNICODE - { - m_str = pString ? pString : &m_strInternal; - m_pos = m_str->length() / sizeof(wxChar); - } + wxMBConv& conv = wxConvUTF8); // get the string containing current output const wxString& GetString() const { return *m_str; } diff --git a/src/common/sstream.cpp b/src/common/sstream.cpp index 009e2c04b6..1ed54f5c9d 100644 --- a/src/common/sstream.cpp +++ b/src/common/sstream.cpp @@ -128,6 +128,16 @@ size_t wxStringInputStream::OnSysRead(void *buffer, size_t size) // wxStringOutputStream implementation // ============================================================================ +wxStringOutputStream::wxStringOutputStream(wxString *pString, wxMBConv& conv) + : m_conv(conv) +#if wxUSE_UNICODE + , m_unconv(0) +#endif // wxUSE_UNICODE +{ + m_str = pString ? pString : &m_strInternal; + m_pos = m_str->length() / sizeof(wxChar); +} + // ---------------------------------------------------------------------------- // seek/tell // ---------------------------------------------------------------------------- From 8e7fef5f081dda8241f55b9cc75482e96ab251b8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 2 Nov 2017 23:34:38 +0100 Subject: [PATCH 2/3] Make wxStringOutputStream ctor explicit Avoid accidentally creating wxStringOutputStream from a wxString pointer, this seems unlikely, but why take the risk of it happening at all. --- include/wx/sstream.h | 4 ++-- interface/wx/sstream.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wx/sstream.h b/include/wx/sstream.h index f24419f8ad..47d17565a4 100644 --- a/include/wx/sstream.h +++ b/include/wx/sstream.h @@ -62,8 +62,8 @@ public: // // Note that the conversion object should have the life time greater than // this stream. - wxStringOutputStream(wxString *pString = NULL, - wxMBConv& conv = wxConvUTF8); + explicit wxStringOutputStream(wxString *pString = NULL, + wxMBConv& conv = wxConvUTF8); // get the string containing current output const wxString& GetString() const { return *m_str; } diff --git a/interface/wx/sstream.h b/interface/wx/sstream.h index a1250e5ff8..e9522db36e 100644 --- a/interface/wx/sstream.h +++ b/interface/wx/sstream.h @@ -62,7 +62,7 @@ public: with default value of this argument the data written to the stream must be valid UTF-8, pass @c wxConvISO8859_1 to deal with arbitrary 8 bit data. */ - wxStringOutputStream(wxString* pString = 0, wxMBConv& conv = wxConvUTF8); + explicit wxStringOutputStream(wxString* pString = NULL, wxMBConv& conv = wxConvUTF8); /** Returns the string containing all the data written to the stream so far. From e3589af56a00468815835b99e16a150856c36b31 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 2 Nov 2017 23:35:49 +0100 Subject: [PATCH 3/3] Fix wxStringOutputStream position when using external string Initialize m_pos correctly when using an existing, and hence possibly not empty, string (and not the internal one which is always empty initially). The old code was totally wrong as it divided the string length by the size of wxChar instead of multiplying by it, but doing this could have been wrong too with UTF-16 and surrogates, so use the conversion object to compute the real length of the string representation in the corresponding encoding. Add a simple unit test checking that this works as intended. Closes #17985. --- src/common/sstream.cpp | 9 ++++++++- tests/streams/sstream.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/common/sstream.cpp b/src/common/sstream.cpp index 1ed54f5c9d..a67cd23152 100644 --- a/src/common/sstream.cpp +++ b/src/common/sstream.cpp @@ -135,7 +135,14 @@ wxStringOutputStream::wxStringOutputStream(wxString *pString, wxMBConv& conv) #endif // wxUSE_UNICODE { m_str = pString ? pString : &m_strInternal; - m_pos = m_str->length() / sizeof(wxChar); + +#if wxUSE_UNICODE_WCHAR + m_pos = m_conv.FromWChar(NULL, 0, m_str->wc_str(), m_str->length()); +#elif wxUSE_UNICODE_UTF8 + m_pos = m_str->utf8_length(); +#else // !wxUSE_UNICODE + m_pos = m_str->length(); +#endif // wxUSE_UNICODE/!wxUSE_UNICODE } // ---------------------------------------------------------------------------- diff --git a/tests/streams/sstream.cpp b/tests/streams/sstream.cpp index f421b8f4e2..6b2903b2ff 100644 --- a/tests/streams/sstream.cpp +++ b/tests/streams/sstream.cpp @@ -119,3 +119,32 @@ void strStream::Output_Check() // Register the stream sub suite, by using some stream helper macro. STREAM_TEST_SUBSUITE_NAMED_REGISTRATION(strStream) + +TEST_CASE("wxStringOutputStream::Tell", "[stream]") +{ + wxStringOutputStream ss; + CHECK( ss.TellO() == 0 ); + + const char* const s = "Hello world"; + const wxFileOffset len = strlen(s); + + ss.Write(s, len); + CHECK( ss.TellO() == len ); + + wxString str(s); + CHECK( wxStringOutputStream(&str).TellO() == len ); + + + wxMBConvUTF16 convUTF16; + wxStringOutputStream ss16(NULL, convUTF16); + CHECK( ss16.TellO() == 0 ); + + const wxCharBuffer s16 = convUTF16.cWC2MB(wxWCharBuffer(str.wc_str())); + ss16.Write(s16, s16.length()); + CHECK( ss16.TellO() == 2*len ); + CHECK( wxStringOutputStream(&str, convUTF16).TellO() == 2*len ); + + // The U+2070D character is represented by a surrogate pair in UTF-16. + wxString u2070D = wxString::FromUTF8("\xF0\xA0\x9C\x8D"); + CHECK( wxStringOutputStream(&u2070D, convUTF16).TellO() == 4 ); +}