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: sstream.cpp 45772 2007-05-03 02:19:16Z VZ $ |
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 |
#if wxUSE_UNICODE |
32 |
#include "wx/hashmap.h" |
33 |
#endif |
34 |
|
35 |
// ============================================================================ |
36 |
// wxStringInputStream implementation |
37 |
// ============================================================================ |
38 |
|
39 |
// ---------------------------------------------------------------------------- |
40 |
// construction/destruction |
41 |
// ---------------------------------------------------------------------------- |
42 |
|
43 |
// TODO: Do we want to include the null char in the stream? If so then |
44 |
// just add +1 to m_len in the ctor |
45 |
wxStringInputStream::wxStringInputStream(const wxString& s) |
46 |
#if wxUSE_UNICODE |
47 |
: m_str(s), m_buf(wxMBConvUTF8().cWX2MB(s).release()), m_len(strlen(m_buf)) |
48 |
#else |
49 |
: m_str(s), m_buf((char*)s.c_str()), m_len(s.length()) |
50 |
#endif |
51 |
{ |
52 |
#if wxUSE_UNICODE |
53 |
wxASSERT_MSG(m_buf != NULL, _T("Could not convert string to UTF8!")); |
54 |
#endif |
55 |
m_pos = 0; |
56 |
} |
57 |
|
58 |
wxStringInputStream::~wxStringInputStream() |
59 |
{ |
60 |
#if wxUSE_UNICODE |
61 |
// Note: wx[W]CharBuffer uses malloc()/free() |
62 |
// PCSX2 : wx[W]CharBuffer now uses the wxString local heap! --air |
63 |
//free(m_buf); |
64 |
_freeHeap_wxString(m_buf); |
65 |
#endif |
66 |
} |
67 |
|
68 |
// ---------------------------------------------------------------------------- |
69 |
// getlength |
70 |
// ---------------------------------------------------------------------------- |
71 |
|
72 |
wxFileOffset wxStringInputStream::GetLength() const |
73 |
{ |
74 |
return m_len; |
75 |
} |
76 |
|
77 |
// ---------------------------------------------------------------------------- |
78 |
// seek/tell |
79 |
// ---------------------------------------------------------------------------- |
80 |
|
81 |
wxFileOffset wxStringInputStream::OnSysSeek(wxFileOffset ofs, wxSeekMode mode) |
82 |
{ |
83 |
switch ( mode ) |
84 |
{ |
85 |
case wxFromStart: |
86 |
// nothing to do, ofs already ok |
87 |
break; |
88 |
|
89 |
case wxFromEnd: |
90 |
ofs += m_len; |
91 |
break; |
92 |
|
93 |
case wxFromCurrent: |
94 |
ofs += m_pos; |
95 |
break; |
96 |
|
97 |
default: |
98 |
wxFAIL_MSG( _T("invalid seek mode") ); |
99 |
return wxInvalidOffset; |
100 |
} |
101 |
|
102 |
if ( ofs < 0 || ofs > wx_static_cast(wxFileOffset, m_len) ) |
103 |
return wxInvalidOffset; |
104 |
|
105 |
// FIXME: this can't be right |
106 |
m_pos = wx_truncate_cast(size_t, ofs); |
107 |
|
108 |
return ofs; |
109 |
} |
110 |
|
111 |
wxFileOffset wxStringInputStream::OnSysTell() const |
112 |
{ |
113 |
return wx_static_cast(wxFileOffset, m_pos); |
114 |
} |
115 |
|
116 |
// ---------------------------------------------------------------------------- |
117 |
// actual IO |
118 |
// ---------------------------------------------------------------------------- |
119 |
|
120 |
size_t wxStringInputStream::OnSysRead(void *buffer, size_t size) |
121 |
{ |
122 |
const size_t sizeMax = m_len - m_pos; |
123 |
|
124 |
if ( size >= sizeMax ) |
125 |
{ |
126 |
if ( sizeMax == 0 ) |
127 |
{ |
128 |
m_lasterror = wxSTREAM_EOF; |
129 |
return 0; |
130 |
} |
131 |
|
132 |
size = sizeMax; |
133 |
} |
134 |
|
135 |
memcpy(buffer, m_buf + m_pos, size); |
136 |
m_pos += size; |
137 |
|
138 |
return size; |
139 |
} |
140 |
|
141 |
// ============================================================================ |
142 |
// wxStringOutputStream implementation |
143 |
// ============================================================================ |
144 |
|
145 |
// ---------------------------------------------------------------------------- |
146 |
// seek/tell |
147 |
// ---------------------------------------------------------------------------- |
148 |
|
149 |
wxFileOffset wxStringOutputStream::OnSysTell() const |
150 |
{ |
151 |
return wx_static_cast(wxFileOffset, m_pos); |
152 |
} |
153 |
|
154 |
// ---------------------------------------------------------------------------- |
155 |
// actual IO |
156 |
// ---------------------------------------------------------------------------- |
157 |
|
158 |
#if wxUSE_UNICODE |
159 |
|
160 |
// we can't add a member to wxStringOutputStream in 2.8 branch without breaking |
161 |
// backwards binary compatibility, so we emulate it by using a hash indexed by |
162 |
// wxStringOutputStream pointers |
163 |
|
164 |
// can't use wxCharBuffer as it has incorrect copying semantics and doesn't |
165 |
// store the length which we need here |
166 |
WX_DECLARE_VOIDPTR_HASH_MAP(wxMemoryBuffer, wxStringStreamUnconvBuffers); |
167 |
|
168 |
static wxStringStreamUnconvBuffers gs_unconverted; |
169 |
|
170 |
wxStringOutputStream::~wxStringOutputStream() |
171 |
{ |
172 |
// TODO: check that nothing remains (i.e. the unconverted buffer is empty)? |
173 |
gs_unconverted.erase(this); |
174 |
} |
175 |
|
176 |
#endif // wxUSE_UNICODE |
177 |
|
178 |
size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size) |
179 |
{ |
180 |
const char *p = wx_static_cast(const char *, buffer); |
181 |
|
182 |
#if wxUSE_UNICODE |
183 |
// the part of the string we have here may be incomplete, i.e. it can stop |
184 |
// in the middle of an UTF-8 character and so converting it would fail; if |
185 |
// this is the case, accumulate the part which we failed to convert until |
186 |
// we get the rest (and also take into account the part which we might have |
187 |
// left unconverted before) |
188 |
const char *src; |
189 |
size_t srcLen; |
190 |
wxMemoryBuffer& unconv = gs_unconverted[this]; |
191 |
if ( unconv.GetDataLen() ) |
192 |
{ |
193 |
// append the new data to the data remaining since the last time |
194 |
unconv.AppendData(p, size); |
195 |
src = unconv; |
196 |
srcLen = unconv.GetDataLen(); |
197 |
} |
198 |
else // no unconverted data left, avoid extra copy |
199 |
{ |
200 |
src = p; |
201 |
srcLen = size; |
202 |
} |
203 |
|
204 |
wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, NULL /* out len */)); |
205 |
if ( wbuf ) |
206 |
{ |
207 |
// conversion succeeded, clear the unconverted buffer |
208 |
unconv = wxMemoryBuffer(0); |
209 |
|
210 |
*m_str += wbuf; |
211 |
} |
212 |
else // conversion failed |
213 |
{ |
214 |
// remember unconverted data if there had been none before (otherwise |
215 |
// we've already got it in the buffer) |
216 |
if ( src == p ) |
217 |
unconv.AppendData(src, srcLen); |
218 |
|
219 |
// pretend that we wrote the data anyhow, otherwise the caller would |
220 |
// believe there was an error and this might not be the case, but do |
221 |
// not update m_pos as m_str hasn't changed |
222 |
return size; |
223 |
} |
224 |
#else // !wxUSE_UNICODE |
225 |
// append directly, no conversion necessary |
226 |
m_str->Append(wxString(p, size)); |
227 |
#endif // wxUSE_UNICODE/!wxUSE_UNICODE |
228 |
|
229 |
// update position |
230 |
m_pos += size; |
231 |
|
232 |
// return number of bytes actually written |
233 |
return size; |
234 |
} |
235 |
|
236 |
#endif // wxUSE_STREAMS |
237 |
|