]> git.saurik.com Git - wxWidgets.git/blob - src/common/sstream.cpp
fix wxStringOutputStream::Write() in Unicode build when the output overlaps a boundar...
[wxWidgets.git] / src / common / sstream.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: common/sstream.cpp
3 // Purpose: string-based streams implementation
4 // Author: Vadim Zeitlin
5 // Modified by: Ryan Norton (UTF8 UNICODE)
6 // Created: 2004-09-19
7 // RCS-ID: $Id$
8 // Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_STREAMS
28
29 #include "wx/sstream.h"
30
31 // ============================================================================
32 // wxStringInputStream implementation
33 // ============================================================================
34
35 // ----------------------------------------------------------------------------
36 // construction/destruction
37 // ----------------------------------------------------------------------------
38
39 // TODO: Do we want to include the null char in the stream? If so then
40 // just add +1 to m_len in the ctor
41 wxStringInputStream::wxStringInputStream(const wxString& s)
42 #if wxUSE_UNICODE
43 : m_str(s), m_buf(wxMBConvUTF8().cWX2MB(s).release()), m_len(strlen(m_buf))
44 #else
45 : m_str(s), m_buf((char*)(const char*)s.c_str()), m_len(s.length())
46 #endif
47 {
48 #if wxUSE_UNICODE
49 wxASSERT_MSG(m_buf != NULL, _T("Could not convert string to UTF8!"));
50 #endif
51 m_pos = 0;
52 }
53
54 wxStringInputStream::~wxStringInputStream()
55 {
56 #if wxUSE_UNICODE
57 // Note: wx[W]CharBuffer uses malloc()/free()
58 free(m_buf);
59 #endif
60 }
61
62 // ----------------------------------------------------------------------------
63 // getlength
64 // ----------------------------------------------------------------------------
65
66 wxFileOffset wxStringInputStream::GetLength() const
67 {
68 return m_len;
69 }
70
71 // ----------------------------------------------------------------------------
72 // seek/tell
73 // ----------------------------------------------------------------------------
74
75 wxFileOffset wxStringInputStream::OnSysSeek(wxFileOffset ofs, wxSeekMode mode)
76 {
77 switch ( mode )
78 {
79 case wxFromStart:
80 // nothing to do, ofs already ok
81 break;
82
83 case wxFromEnd:
84 ofs += m_len;
85 break;
86
87 case wxFromCurrent:
88 ofs += m_pos;
89 break;
90
91 default:
92 wxFAIL_MSG( _T("invalid seek mode") );
93 return wxInvalidOffset;
94 }
95
96 if ( ofs < 0 || ofs > wx_static_cast(wxFileOffset, m_len) )
97 return wxInvalidOffset;
98
99 // FIXME: this can't be right
100 m_pos = wx_truncate_cast(size_t, ofs);
101
102 return ofs;
103 }
104
105 wxFileOffset wxStringInputStream::OnSysTell() const
106 {
107 return wx_static_cast(wxFileOffset, m_pos);
108 }
109
110 // ----------------------------------------------------------------------------
111 // actual IO
112 // ----------------------------------------------------------------------------
113
114 size_t wxStringInputStream::OnSysRead(void *buffer, size_t size)
115 {
116 const size_t sizeMax = m_len - m_pos;
117
118 if ( size >= sizeMax )
119 {
120 if ( sizeMax == 0 )
121 {
122 m_lasterror = wxSTREAM_EOF;
123 return 0;
124 }
125
126 size = sizeMax;
127 }
128
129 memcpy(buffer, m_buf + m_pos, size);
130 m_pos += size;
131
132 return size;
133 }
134
135 // ============================================================================
136 // wxStringOutputStream implementation
137 // ============================================================================
138
139 // ----------------------------------------------------------------------------
140 // seek/tell
141 // ----------------------------------------------------------------------------
142
143 wxFileOffset wxStringOutputStream::OnSysTell() const
144 {
145 return wx_static_cast(wxFileOffset, m_pos);
146 }
147
148 // ----------------------------------------------------------------------------
149 // actual IO
150 // ----------------------------------------------------------------------------
151
152 size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size)
153 {
154 const char *p = wx_static_cast(const char *, buffer);
155
156 #if wxUSE_UNICODE_WCHAR
157 // the part of the string we have here may be incomplete, i.e. it can stop
158 // in the middle of an UTF-8 character and so converting it would fail; if
159 // this is the case, accumulate the part which we failed to convert until
160 // we get the rest (and also take into account the part which we might have
161 // left unconverted before)
162 const char *src;
163 size_t srcLen;
164 if ( m_unconv.GetDataLen() )
165 {
166 // append the new data to the data remaining since the last time
167 m_unconv.AppendData(p, size);
168 src = m_unconv;
169 srcLen = m_unconv.GetDataLen();
170 }
171 else // no unconverted data left, avoid extra copy
172 {
173 src = p;
174 srcLen = size;
175 }
176
177 wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, NULL /* out len */));
178 if ( wbuf )
179 {
180 // conversion succeeded, clear the unconverted buffer
181 m_unconv = wxMemoryBuffer(0);
182
183 *m_str += wbuf;
184 }
185 else // conversion failed
186 {
187 // remember unconverted data if there had been none before (otherwise
188 // we've already got it in the buffer)
189 if ( src == p )
190 m_unconv.AppendData(src, srcLen);
191
192 // pretend that we wrote the data anyhow, otherwise the caller would
193 // believe there was an error and this might not be the case, but do
194 // not update m_pos as m_str hasn't changed
195 return size;
196 }
197 #else // !wxUSE_UNICODE_WCHAR
198 // no recoding necessary, the data is supposed to already be in UTF-8 (if
199 // supported) or ASCII otherwise
200 m_str->append(p, size);
201 #endif // wxUSE_UNICODE_WCHAR/!wxUSE_UNICODE_WCHAR
202
203 // update position
204 m_pos += size;
205
206 // return number of bytes actually written
207 return size;
208 }
209
210 #endif // wxUSE_STREAMS
211