1 |
william |
31 |
/////////////////////////////////////////////////////////////////////////////// |
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 |
|
|
|