From 3b85f3189ebe536025b744d5faf4093658aeb1d2 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 1 May 2007 13:52:19 +0000 Subject: [PATCH] fix wxStringOutputStream::Write() in Unicode build when the output overlaps a boundary between UTF-8 characters (bug 1701426) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@45732 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 4 +-- include/wx/sstream.h | 4 +++ src/common/sstream.cpp | 79 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 6378aa55b5..740b6fa096 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -94,6 +94,8 @@ Major new features in 2.8 release All: - Fix bug in wxFileConfig when recreating a group (Steven Van Ingelgem) +- Fix wxStringOutputStream::Write() in Unicode build when the argument + overlaps UTF-8 characters boundary - Account for lines without newline at the end in wxExecute() - Added wxString::char_str() and wchar_str() methods for forward compatiblity with wxWidgets 3 @@ -135,8 +137,6 @@ wxUniv: - Fix wxComboBox::SetSelection(wxNOT_FOUND) - Fix setting background colour for controls with transparent background ->>>>>>> 1.1006.2.35 - 2.8.3 ----- diff --git a/include/wx/sstream.h b/include/wx/sstream.h index 02f878681b..fd34ae3ab7 100644 --- a/include/wx/sstream.h +++ b/include/wx/sstream.h @@ -66,6 +66,10 @@ public: m_pos = m_str->length() / sizeof(wxChar); } +#if wxABI_VERSION >= 20804 && wxUSE_UNICODE + virtual ~wxStringOutputStream(); +#endif // wx 2.8.4+ + // 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 8033dff28c..3fbbc3fdf3 100644 --- a/src/common/sstream.cpp +++ b/src/common/sstream.cpp @@ -37,8 +37,8 @@ // ---------------------------------------------------------------------------- // TODO: Do we want to include the null char in the stream? If so then -// just add +1 to m_len in the ctor -wxStringInputStream::wxStringInputStream(const wxString& s) +// just add +1 to m_len in the ctor +wxStringInputStream::wxStringInputStream(const wxString& s) #if wxUSE_UNICODE : m_str(s), m_buf(wxMBConvUTF8().cWX2MB(s).release()), m_len(strlen(m_buf)) #else @@ -63,9 +63,9 @@ wxStringInputStream::~wxStringInputStream() // getlength // ---------------------------------------------------------------------------- -wxFileOffset wxStringInputStream::GetLength() const -{ - return m_len; +wxFileOffset wxStringInputStream::GetLength() const +{ + return m_len; } // ---------------------------------------------------------------------------- @@ -149,13 +149,76 @@ wxFileOffset wxStringOutputStream::OnSysTell() const // actual IO // ---------------------------------------------------------------------------- +#if wxUSE_UNICODE + +// we can't add a member to wxStringOutputStream in 2.8 branch without breaking +// backwards binary compatibility, so we emulate it by using a hash indexed by +// wxStringOutputStream pointers + +// can't use wxCharBuffer as it has incorrect copying semantics and doesn't +// store the length which we need here +WX_DECLARE_VOIDPTR_HASH_MAP(wxMemoryBuffer, wxStringStreamUnconvBuffers); + +static wxStringStreamUnconvBuffers gs_unconverted; + +wxStringOutputStream::~wxStringOutputStream() +{ + // TODO: check that nothing remains (i.e. the unconverted buffer is empty)? + gs_unconverted.erase(this); +} + +#endif // wxUSE_UNICODE + size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size) { const char *p = wx_static_cast(const char *, buffer); - // append the input buffer (may not be null terminated - thus - // the literal length - m_str->Append(wxString(p, m_conv, size)); +#if wxUSE_UNICODE + // the part of the string we have here may be incomplete, i.e. it can stop + // in the middle of an UTF-8 character and so converting it would fail; if + // this is the case, accumulate the part which we failed to convert until + // we get the rest (and also take into account the part which we might have + // left unconverted before) + const char *src; + size_t srcLen; + wxMemoryBuffer& unconv = gs_unconverted[this]; + if ( unconv.GetDataLen() ) + { + // append the new data to the data remaining since the last time + unconv.AppendData(p, size); + src = unconv; + srcLen = unconv.GetDataLen(); + } + else // no unconverted data left, avoid extra copy + { + src = p; + srcLen = size; + } + + wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, NULL /* out len */)); + if ( wbuf ) + { + // conversion succeeded, clear the unconverted buffer + unconv = wxMemoryBuffer(0); + + *m_str += wbuf; + } + else // conversion failed + { + // remember unconverted data if there had been none before (otherwise + // we've already got it in the buffer) + if ( src == p ) + unconv.AppendData(src, srcLen); + + // pretend that we wrote the data anyhow, otherwise the caller would + // believe there was an error and this might not be the case, but do + // not update m_pos as m_str hasn't changed + return size; + } +#else // !wxUSE_UNICODE + // append directly, no conversion necessary + m_str->Append(wxString(p, size)); +#endif // wxUSE_UNICODE/!wxUSE_UNICODE // update position m_pos += size;