Hack compilation using the latest MinGW release.
[wxWidgets.git] / src / common / txtstrm.cpp
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
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
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
48 wxTextInputStream::~wxTextInputStream()
49 {
50 #if wxUSE_UNICODE
51 delete m_conv;
52 #endif // wxUSE_UNICODE
53 }
54
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
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
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
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
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
160 wxUint16 wxTextInputStream::Read16(int base)
161 {
162 return (wxUint16)Read32(base);
163 }
164
165 wxUint8 wxTextInputStream::Read8(int base)
166 {
167 return (wxUint8)Read32(base);
168 }
169
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
181 wxInt16 wxTextInputStream::Read16S(int base)
182 {
183 return (wxInt16)Read32S(base);
184 }
185
186 wxInt8 wxTextInputStream::Read8S(int base)
187 {
188 return (wxInt8)Read32S(base);
189 }
190
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
202 wxString wxTextInputStream::ReadString()
203 {
204 return ReadLine();
205 }
206
207 #endif // WXWIN_COMPATIBILITY_2_6
208
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
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
259 wxTextInputStream& wxTextInputStream::operator>>(wxString& word)
260 {
261 word = ReadWord();
262 return *this;
263 }
264
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
278 wxTextInputStream& wxTextInputStream::operator>>(wchar_t& wc)
279 {
280 wc = GetChar();
281
282 return *this;
283 }
284
285 #endif // wxUSE_UNICODE
286
287 wxTextInputStream& wxTextInputStream::operator>>(wxInt16& i)
288 {
289 i = (wxInt16)Read16();
290 return *this;
291 }
292
293 wxTextInputStream& wxTextInputStream::operator>>(wxInt32& i)
294 {
295 i = (wxInt32)Read32();
296 return *this;
297 }
298
299 wxTextInputStream& wxTextInputStream::operator>>(wxUint16& i)
300 {
301 i = Read16();
302 return *this;
303 }
304
305 wxTextInputStream& wxTextInputStream::operator>>(wxUint32& i)
306 {
307 i = Read32();
308 return *this;
309 }
310
311 wxTextInputStream& wxTextInputStream::operator>>(double& i)
312 {
313 i = ReadDouble();
314 return *this;
315 }
316
317 wxTextInputStream& wxTextInputStream::operator>>(float& f)
318 {
319 f = (float)ReadDouble();
320 return *this;
321 }
322
323
324
325 #if wxUSE_UNICODE
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
346 wxTextOutputStream::~wxTextOutputStream()
347 {
348 #if wxUSE_UNICODE
349 delete m_conv;
350 #endif // wxUSE_UNICODE
351 }
352
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
366 void wxTextOutputStream::Write32(wxUint32 i)
367 {
368 wxString str;
369 str.Printf(wxT("%u"), i);
370
371 WriteString(str);
372 }
373
374 void wxTextOutputStream::Write16(wxUint16 i)
375 {
376 wxString str;
377 str.Printf(wxT("%u"), (unsigned)i);
378
379 WriteString(str);
380 }
381
382 void wxTextOutputStream::Write8(wxUint8 i)
383 {
384 wxString str;
385 str.Printf(wxT("%u"), (unsigned)i);
386
387 WriteString(str);
388 }
389
390 void wxTextOutputStream::WriteDouble(double d)
391 {
392 wxString str;
393
394 str.Printf(wxT("%f"), d);
395 WriteString(str);
396 }
397
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
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
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
465 wxTextOutputStream& wxTextOutputStream::operator<<(const wxString& string)
466 {
467 WriteString( string );
468 return *this;
469 }
470
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
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
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
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
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
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
525 wxTextOutputStream &wxTextOutputStream::operator<<(double f)
526 {
527 WriteDouble(f);
528 return *this;
529 }
530
531 wxTextOutputStream& wxTextOutputStream::operator<<(float f)
532 {
533 WriteDouble((double)f);
534 return *this;
535 }
536
537 wxTextOutputStream &endl( wxTextOutputStream &stream )
538 {
539 return stream.PutChar(wxT('\n'));
540 }
541
542 #endif
543 // wxUSE_STREAMS