1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/txtstrm.cpp
3 // Purpose:     Text stream classes
4 // Author:      Guilhem Lavaux
5 // Modified by:
6 // Created:     28/06/98
7 // Copyright:   (c) Guilhem Lavaux
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15   #pragma hdrstop
16 #endif
17 
18 #if wxUSE_STREAMS
19 
20 #include "wx/txtstrm.h"
21 
22 #ifndef WX_PRECOMP
23     #include "wx/crt.h"
24 #endif
25 
26 #include <ctype.h>
27 
28 // ----------------------------------------------------------------------------
29 // wxTextInputStream
30 // ----------------------------------------------------------------------------
31 
32 #if wxUSE_UNICODE
wxTextInputStream(wxInputStream & s,const wxString & sep,const wxMBConv & conv)33 wxTextInputStream::wxTextInputStream(wxInputStream &s,
34                                      const wxString &sep,
35                                      const wxMBConv& conv)
36   : m_input(s), m_separators(sep), m_conv(conv.Clone())
37 {
38     memset((void*)m_lastBytes, 0, 10);
39 }
40 #else
wxTextInputStream(wxInputStream & s,const wxString & sep)41 wxTextInputStream::wxTextInputStream(wxInputStream &s, const wxString &sep)
42   : m_input(s), m_separators(sep)
43 {
44     memset((void*)m_lastBytes, 0, 10);
45 }
46 #endif
47 
~wxTextInputStream()48 wxTextInputStream::~wxTextInputStream()
49 {
50 #if wxUSE_UNICODE
51     delete m_conv;
52 #endif // wxUSE_UNICODE
53 }
54 
UngetLast()55 void wxTextInputStream::UngetLast()
56 {
57     size_t byteCount = 0;
58     while(m_lastBytes[byteCount]) // pseudo ANSI strlen (even for Unicode!)
59         byteCount++;
60     m_input.Ungetch(m_lastBytes, byteCount);
61     memset((void*)m_lastBytes, 0, 10);
62 }
63 
NextChar()64 wxChar wxTextInputStream::NextChar()
65 {
66 #if wxUSE_UNICODE
67     wxChar wbuf[2];
68     memset((void*)m_lastBytes, 0, 10);
69     for(size_t inlen = 0; inlen < 9; inlen++)
70     {
71         // actually read the next character
72         m_lastBytes[inlen] = m_input.GetC();
73 
74         if(m_input.LastRead() <= 0)
75             return wxEOT;
76 
77         switch ( m_conv->ToWChar(wbuf, WXSIZEOF(wbuf), m_lastBytes, inlen + 1) )
78         {
79             case 0:
80                 // this is a bug in converter object as it should either fail
81                 // or decode non-empty string to something non-empty
82                 wxFAIL_MSG("ToWChar() can't return 0 for non-empty input");
83                 break;
84 
85             case wxCONV_FAILED:
86                 // the buffer probably doesn't contain enough bytes to decode
87                 // as a complete character, try with more bytes
88                 break;
89 
90             default:
91                 // if we couldn't decode a single character during the last
92                 // loop iteration we shouldn't be able to decode 2 or more of
93                 // them with an extra single byte, something fishy is going on
94                 wxFAIL_MSG("unexpected decoding result");
95                 // fall through nevertheless and return at least something
96 
97             case 1:
98                 // we finally decoded a character
99                 return wbuf[0];
100         }
101     }
102 
103     // there should be no encoding which requires more than nine bytes for one
104     // character so something must be wrong with our conversion but we have no
105     // way to signal it from here
106     return wxEOT;
107 #else
108     m_lastBytes[0] = m_input.GetC();
109 
110     if(m_input.LastRead() <= 0)
111         return wxEOT;
112 
113     return m_lastBytes[0];
114 #endif
115 
116 }
117 
NextNonSeparators()118 wxChar wxTextInputStream::NextNonSeparators()
119 {
120     for (;;)
121     {
122         wxChar c = NextChar();
123         if (c == wxEOT) return (wxChar) 0;
124 
125         if (c != wxT('\n') &&
126             c != wxT('\r') &&
127             m_separators.Find(c) < 0)
128           return c;
129     }
130 
131 }
132 
EatEOL(const wxChar & c)133 bool wxTextInputStream::EatEOL(const wxChar &c)
134 {
135     if (c == wxT('\n')) return true; // eat on UNIX
136 
137     if (c == wxT('\r')) // eat on both Mac and DOS
138     {
139         wxChar c2 = NextChar();
140         if(c2 == wxEOT) return true; // end of stream reached, had enough :-)
141 
142         if (c2 != wxT('\n')) UngetLast(); // Don't eat on Mac
143         return true;
144     }
145 
146     return false;
147 }
148 
Read32(int base)149 wxUint32 wxTextInputStream::Read32(int base)
150 {
151     wxASSERT_MSG( !base || (base > 1 && base <= 36), wxT("invalid base") );
152     if(!m_input) return 0;
153 
154     wxString word = ReadWord();
155     if(word.empty())
156         return 0;
157     return wxStrtoul(word.c_str(), 0, base);
158 }
159 
Read16(int base)160 wxUint16 wxTextInputStream::Read16(int base)
161 {
162     return (wxUint16)Read32(base);
163 }
164 
Read8(int base)165 wxUint8 wxTextInputStream::Read8(int base)
166 {
167     return (wxUint8)Read32(base);
168 }
169 
Read32S(int base)170 wxInt32 wxTextInputStream::Read32S(int base)
171 {
172     wxASSERT_MSG( !base || (base > 1 && base <= 36), wxT("invalid base") );
173     if(!m_input) return 0;
174 
175     wxString word = ReadWord();
176     if(word.empty())
177         return 0;
178     return wxStrtol(word.c_str(), 0, base);
179 }
180 
Read16S(int base)181 wxInt16 wxTextInputStream::Read16S(int base)
182 {
183     return (wxInt16)Read32S(base);
184 }
185 
Read8S(int base)186 wxInt8 wxTextInputStream::Read8S(int base)
187 {
188     return (wxInt8)Read32S(base);
189 }
190 
ReadDouble()191 double wxTextInputStream::ReadDouble()
192 {
193     if(!m_input) return 0;
194     wxString word = ReadWord();
195     if(word.empty())
196         return 0;
197     return wxStrtod(word.c_str(), 0);
198 }
199 
200 #if WXWIN_COMPATIBILITY_2_6
201 
ReadString()202 wxString wxTextInputStream::ReadString()
203 {
204     return ReadLine();
205 }
206 
207 #endif // WXWIN_COMPATIBILITY_2_6
208 
ReadLine()209 wxString wxTextInputStream::ReadLine()
210 {
211     wxString line;
212 
213     while ( !m_input.Eof() )
214     {
215         wxChar c = NextChar();
216         if(c == wxEOT)
217             break;
218 
219         if (EatEOL(c))
220             break;
221 
222         line += c;
223     }
224 
225     return line;
226 }
227 
ReadWord()228 wxString wxTextInputStream::ReadWord()
229 {
230     wxString word;
231 
232     if ( !m_input )
233         return word;
234 
235     wxChar c = NextNonSeparators();
236     if ( !c )
237         return word;
238 
239     word += c;
240 
241     while ( !m_input.Eof() )
242     {
243         c = NextChar();
244         if(c == wxEOT)
245             break;
246 
247         if (m_separators.Find(c) >= 0)
248             break;
249 
250         if (EatEOL(c))
251             break;
252 
253         word += c;
254     }
255 
256     return word;
257 }
258 
operator >>(wxString & word)259 wxTextInputStream& wxTextInputStream::operator>>(wxString& word)
260 {
261     word = ReadWord();
262     return *this;
263 }
264 
operator >>(char & c)265 wxTextInputStream& wxTextInputStream::operator>>(char& c)
266 {
267     c = m_input.GetC();
268     if(m_input.LastRead() <= 0) c = 0;
269 
270     if (EatEOL(c))
271         c = '\n';
272 
273     return *this;
274 }
275 
276 #if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE
277 
operator >>(wchar_t & wc)278 wxTextInputStream& wxTextInputStream::operator>>(wchar_t& wc)
279 {
280     wc = GetChar();
281 
282     return *this;
283 }
284 
285 #endif // wxUSE_UNICODE
286 
operator >>(wxInt16 & i)287 wxTextInputStream& wxTextInputStream::operator>>(wxInt16& i)
288 {
289     i = (wxInt16)Read16();
290     return *this;
291 }
292 
operator >>(wxInt32 & i)293 wxTextInputStream& wxTextInputStream::operator>>(wxInt32& i)
294 {
295     i = (wxInt32)Read32();
296     return *this;
297 }
298 
operator >>(wxUint16 & i)299 wxTextInputStream& wxTextInputStream::operator>>(wxUint16& i)
300 {
301     i = Read16();
302     return *this;
303 }
304 
operator >>(wxUint32 & i)305 wxTextInputStream& wxTextInputStream::operator>>(wxUint32& i)
306 {
307     i = Read32();
308     return *this;
309 }
310 
operator >>(double & i)311 wxTextInputStream& wxTextInputStream::operator>>(double& i)
312 {
313     i = ReadDouble();
314     return *this;
315 }
316 
operator >>(float & f)317 wxTextInputStream& wxTextInputStream::operator>>(float& f)
318 {
319     f = (float)ReadDouble();
320     return *this;
321 }
322 
323 
324 
325 #if wxUSE_UNICODE
wxTextOutputStream(wxOutputStream & s,wxEOL mode,const wxMBConv & conv)326 wxTextOutputStream::wxTextOutputStream(wxOutputStream& s,
327                                        wxEOL mode,
328                                        const wxMBConv& conv)
329   : m_output(s), m_conv(conv.Clone())
330 #else
331 wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, wxEOL mode)
332   : m_output(s)
333 #endif
334 {
335     m_mode = mode;
336     if (m_mode == wxEOL_NATIVE)
337     {
338 #if defined(__WINDOWS__) || defined(__WXPM__)
339         m_mode = wxEOL_DOS;
340 #else
341         m_mode = wxEOL_UNIX;
342 #endif
343     }
344 }
345 
~wxTextOutputStream()346 wxTextOutputStream::~wxTextOutputStream()
347 {
348 #if wxUSE_UNICODE
349     delete m_conv;
350 #endif // wxUSE_UNICODE
351 }
352 
SetMode(wxEOL mode)353 void wxTextOutputStream::SetMode(wxEOL mode)
354 {
355     m_mode = mode;
356     if (m_mode == wxEOL_NATIVE)
357     {
358 #if defined(__WINDOWS__) || defined(__WXPM__)
359         m_mode = wxEOL_DOS;
360 #else
361         m_mode = wxEOL_UNIX;
362 #endif
363     }
364 }
365 
Write32(wxUint32 i)366 void wxTextOutputStream::Write32(wxUint32 i)
367 {
368     wxString str;
369     str.Printf(wxT("%u"), i);
370 
371     WriteString(str);
372 }
373 
Write16(wxUint16 i)374 void wxTextOutputStream::Write16(wxUint16 i)
375 {
376     wxString str;
377     str.Printf(wxT("%u"), (unsigned)i);
378 
379     WriteString(str);
380 }
381 
Write8(wxUint8 i)382 void wxTextOutputStream::Write8(wxUint8 i)
383 {
384     wxString str;
385     str.Printf(wxT("%u"), (unsigned)i);
386 
387     WriteString(str);
388 }
389 
WriteDouble(double d)390 void wxTextOutputStream::WriteDouble(double d)
391 {
392     wxString str;
393 
394     str.Printf(wxT("%f"), d);
395     WriteString(str);
396 }
397 
WriteString(const wxString & string)398 void wxTextOutputStream::WriteString(const wxString& string)
399 {
400     size_t len = string.length();
401 
402     wxString out;
403     out.reserve(len);
404 
405     for ( size_t i = 0; i < len; i++ )
406     {
407         const wxChar c = string[i];
408         if ( c == wxT('\n') )
409         {
410             switch ( m_mode )
411             {
412                 case wxEOL_DOS:
413                     out << wxT("\r\n");
414                     continue;
415 
416                 case wxEOL_MAC:
417                     out << wxT('\r');
418                     continue;
419 
420                 default:
421                     wxFAIL_MSG( wxT("unknown EOL mode in wxTextOutputStream") );
422                     // fall through
423 
424                 case wxEOL_UNIX:
425                     // don't treat '\n' specially
426                     ;
427             }
428         }
429 
430         out << c;
431     }
432 
433 #if wxUSE_UNICODE
434     // FIXME-UTF8: use wxCharBufferWithLength if/when we have it
435     wxCharBuffer buffer = m_conv->cWC2MB(out.wc_str(), out.length(), &len);
436     m_output.Write(buffer, len);
437 #else
438     m_output.Write(out.c_str(), out.length() );
439 #endif
440 }
441 
PutChar(wxChar c)442 wxTextOutputStream& wxTextOutputStream::PutChar(wxChar c)
443 {
444 #if wxUSE_UNICODE
445     WriteString( wxString(&c, *m_conv, 1) );
446 #else
447     WriteString( wxString(&c, wxConvLocal, 1) );
448 #endif
449     return *this;
450 }
451 
Flush()452 void wxTextOutputStream::Flush()
453 {
454 #if wxUSE_UNICODE
455     const size_t len = m_conv->FromWChar(NULL, 0, L"", 1);
456     if ( len > m_conv->GetMBNulLen() )
457     {
458         wxCharBuffer buf(len);
459         m_conv->FromWChar(buf.data(), len, L"", 1);
460         m_output.Write(buf, len - m_conv->GetMBNulLen());
461     }
462 #endif // wxUSE_UNICODE
463 }
464 
operator <<(const wxString & string)465 wxTextOutputStream& wxTextOutputStream::operator<<(const wxString& string)
466 {
467     WriteString( string );
468     return *this;
469 }
470 
operator <<(char c)471 wxTextOutputStream& wxTextOutputStream::operator<<(char c)
472 {
473     WriteString( wxString::FromAscii(c) );
474 
475     return *this;
476 }
477 
478 #if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE
479 
operator <<(wchar_t wc)480 wxTextOutputStream& wxTextOutputStream::operator<<(wchar_t wc)
481 {
482     WriteString( wxString(&wc, *m_conv, 1) );
483 
484     return *this;
485 }
486 
487 #endif // wxUSE_UNICODE
488 
operator <<(wxInt16 c)489 wxTextOutputStream& wxTextOutputStream::operator<<(wxInt16 c)
490 {
491     wxString str;
492     str.Printf(wxT("%d"), (signed int)c);
493     WriteString(str);
494 
495     return *this;
496 }
497 
operator <<(wxInt32 c)498 wxTextOutputStream& wxTextOutputStream::operator<<(wxInt32 c)
499 {
500     wxString str;
501     str.Printf(wxT("%ld"), (signed long)c);
502     WriteString(str);
503 
504     return *this;
505 }
506 
operator <<(wxUint16 c)507 wxTextOutputStream& wxTextOutputStream::operator<<(wxUint16 c)
508 {
509     wxString str;
510     str.Printf(wxT("%u"), (unsigned int)c);
511     WriteString(str);
512 
513     return *this;
514 }
515 
operator <<(wxUint32 c)516 wxTextOutputStream& wxTextOutputStream::operator<<(wxUint32 c)
517 {
518     wxString str;
519     str.Printf(wxT("%lu"), (unsigned long)c);
520     WriteString(str);
521 
522     return *this;
523 }
524 
operator <<(double f)525 wxTextOutputStream &wxTextOutputStream::operator<<(double f)
526 {
527     WriteDouble(f);
528     return *this;
529 }
530 
operator <<(float f)531 wxTextOutputStream& wxTextOutputStream::operator<<(float f)
532 {
533     WriteDouble((double)f);
534     return *this;
535 }
536 
endl(wxTextOutputStream & stream)537 wxTextOutputStream &endl( wxTextOutputStream &stream )
538 {
539     return stream.PutChar(wxT('\n'));
540 }
541 
542 #endif
543   // wxUSE_STREAMS
544