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