* Fixes and new features in wxObject*Stream
[wxWidgets.git] / src / common / stream.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: stream.cpp
3 // Purpose: wxStream base classes
4 // Author: Guilhem Lavaux
5 // Modified by:
6 // Created: 11/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Guilhem Lavaux
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "stream.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18 #include <ctype.h>
19 #include <wx/stream.h>
20 #include <wx/datstrm.h>
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 // ----------------------------------------------------------------------------
27 // wxStreamBuffer
28 // ----------------------------------------------------------------------------
29
30 wxStreamBuffer::wxStreamBuffer(wxInputStream& i_stream)
31 : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL),
32 m_buffer_size(0), m_istream(&i_stream), m_ostream(NULL)
33 {
34 }
35
36 wxStreamBuffer::wxStreamBuffer(wxOutputStream& o_stream)
37 : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL),
38 m_buffer_size(0), m_istream(NULL), m_ostream(&o_stream)
39 {
40 }
41
42 wxStreamBuffer::~wxStreamBuffer()
43 {
44 }
45
46 void wxStreamBuffer::WriteBack(char c)
47 {
48 if (m_ostream)
49 return;
50
51 // Assume that if we write "back" we have read a few bytes: so we have some
52 // space.
53
54 m_buffer_pos--;
55 *m_buffer_pos = c;
56 }
57
58 void wxStreamBuffer::SetBufferIO(char *buffer_start, char *buffer_end)
59 {
60 m_buffer_pos = m_buffer_start = buffer_start;
61 m_buffer_end = buffer_end;
62
63 m_buffer_size = m_buffer_end-m_buffer_start;
64 }
65
66 void wxStreamBuffer::SetBufferIO(size_t bufsize)
67 {
68 if (m_buffer_start)
69 delete[] m_buffer_start;
70
71 if (!bufsize) {
72 m_buffer_start = NULL;
73 m_buffer_end = NULL;
74 m_buffer_pos = NULL;
75 m_buffer_size = 0;
76 }
77
78 m_buffer_start = new char[bufsize];
79 m_buffer_end = m_buffer_start + bufsize;
80 if (m_istream)
81 m_buffer_pos = m_buffer_end;
82 else
83 m_buffer_pos = m_buffer_start;
84 m_buffer_size = bufsize;
85 }
86
87 void wxStreamBuffer::ResetBuffer()
88 {
89 if (m_istream)
90 m_buffer_pos = m_buffer_end;
91 else
92 m_buffer_pos = m_buffer_start;
93 }
94
95 void wxStreamBuffer::Read(void *buffer, size_t size)
96 {
97 wxASSERT(m_istream != NULL);
98
99 // ------------------
100 // Buffering disabled
101 // ------------------
102
103 if (!m_buffer_size) {
104 m_istream->m_lastread = m_istream->DoRead(buffer, size);
105 return;
106 }
107
108 // -----------------
109 // Buffering enabled
110 // -----------------
111 size_t buf_left, orig_size = size;
112 size_t read_ret;
113
114 while (size > 0) {
115 buf_left = m_buffer_end - m_buffer_pos;
116
117 // First case: the requested buffer is larger than the stream buffer,
118 // we split
119 if (size > buf_left) {
120 memcpy(buffer, m_buffer_pos, buf_left);
121 size -= buf_left;
122 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
123
124 read_ret = m_istream->DoRead(m_buffer_start, m_buffer_size);
125
126 // Read failed
127 if (read_ret == 0) {
128 m_istream->m_lastread = orig_size-size;
129 m_buffer_pos = m_buffer_end = m_buffer_start;
130 return;
131 } else {
132 m_buffer_end = m_buffer_start+read_ret;
133 m_buffer_pos = m_buffer_start;
134 }
135 } else {
136
137 // Second case: we just copy from the stream buffer.
138 memcpy(buffer, m_buffer_pos, size);
139 m_buffer_pos += size;
140 break;
141 }
142 }
143 m_istream->m_lastread = orig_size;
144 }
145
146 void wxStreamBuffer::Write(const void *buffer, size_t size)
147 {
148 wxASSERT(m_ostream != NULL);
149
150 // ------------------
151 // Buffering disabled
152 // ------------------
153
154 if (!m_buffer_size) {
155 m_ostream->m_lastwrite = m_ostream->DoWrite(buffer, size);
156 return;
157 }
158
159 // ------------------
160 // Buffering enabled
161 // ------------------
162
163 size_t buf_left, orig_size = size;
164 size_t write_ret;
165
166 while (size > 0) {
167 buf_left = m_buffer_end - m_buffer_pos;
168
169 // First case: the buffer to write is larger than the stream buffer,
170 // we split it
171 if (size > buf_left) {
172 memcpy(m_buffer_pos, buffer, buf_left);
173 size -= buf_left;
174 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
175
176 write_ret = m_ostream->DoWrite(m_buffer_start, m_buffer_size);
177 if (write_ret != m_buffer_size) {
178 m_ostream->m_bad = TRUE;
179 m_ostream->m_lastwrite = orig_size-size;
180 m_buffer_pos = m_buffer_end = m_buffer_start;
181 return;
182 }
183 m_buffer_pos = m_buffer_start;
184
185 } else {
186
187 // Second case: just copy it in the stream buffer.
188
189 memcpy(m_buffer_pos, buffer, size);
190 m_buffer_pos += size;
191 break;
192 }
193 }
194 m_ostream->m_lastwrite = orig_size;
195 }
196
197 // ----------------------------------------------------------------------------
198 // wxInputStream
199 // ----------------------------------------------------------------------------
200
201 wxInputStream::wxInputStream()
202 {
203 m_i_destroybuf = TRUE;
204 m_i_streambuf = new wxStreamBuffer(*this);
205 m_eof = FALSE;
206 }
207
208 wxInputStream::wxInputStream(wxStreamBuffer *buffer)
209 {
210 m_i_destroybuf = FALSE;
211 m_i_streambuf = buffer;
212 m_eof = FALSE;
213 }
214
215 wxInputStream::~wxInputStream()
216 {
217 if (m_i_destroybuf)
218 delete m_i_streambuf;
219 }
220
221 char wxInputStream::GetC()
222 {
223 char c;
224 m_i_streambuf->Read(&c, 1);
225 return c;
226 }
227
228 wxInputStream& wxInputStream::Read(void *buffer, size_t size)
229 {
230 m_i_streambuf->Read(buffer, size);
231 // wxStreamBuffer sets all variables for us
232 return *this;
233 }
234
235 #define BUF_TEMP_SIZE 10000
236
237 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
238 {
239 char buf[BUF_TEMP_SIZE];
240 size_t bytes_read = BUF_TEMP_SIZE;
241
242 while (bytes_read == BUF_TEMP_SIZE && !stream_out.Bad()) {
243 bytes_read = Read(buf, bytes_read).LastRead();
244
245 stream_out.Write(buf, bytes_read);
246 }
247 return *this;
248 }
249
250 wxInputStream& wxInputStream::operator>>(wxString& line)
251 {
252 wxDataInputStream s(*this);
253
254 line = s.ReadLine();
255 return *this;
256 }
257
258 wxInputStream& wxInputStream::operator>>(char& c)
259 {
260 c = GetC();
261 return *this;
262 }
263
264 wxInputStream& wxInputStream::operator>>(short& i)
265 {
266 long l;
267
268 *this >> l;
269 i = (short)l;
270 return *this;
271 }
272
273 wxInputStream& wxInputStream::operator>>(long& i)
274 {
275 /* I only implemented a simple integer parser */
276 int c, sign;
277
278 while (isspace( c = GetC() ) )
279 /* Do nothing */ ;
280
281 i = 0;
282 if (! (c == '-' || isdigit(c)) ) {
283 InputStreamBuffer()->WriteBack(c);
284 return *this;
285 }
286
287 if (c == '-') {
288 sign = -1;
289 c = GetC();
290 } else
291 sign = 1;
292
293 while (isdigit(c)) {
294 i = i*10 + c;
295 c = GetC();
296 }
297
298 i *= sign;
299
300 return *this;
301 }
302
303 wxInputStream& wxInputStream::operator>>(float& f)
304 {
305 /* I only implemented a simple float parser */
306 int c, sign;
307
308 while (isspace( c = GetC() ) )
309 /* Do nothing */ ;
310
311 f = 0.0;
312 if (! (c == '-' || isdigit(c)) ) {
313 InputStreamBuffer()->WriteBack(c);
314 return *this;
315 }
316
317 if (c == '-') {
318 sign = -1;
319 c = GetC();
320 } else
321 sign = 1;
322
323 while (isdigit(c)) {
324 f = f*10 + c;
325 c = GetC();
326 }
327
328 if (c == '.') {
329 float f_multiplicator = 0.1;
330 c = GetC();
331
332 while (isdigit(c)) {
333 f += c*f_multiplicator;
334 f_multiplicator /= 10;
335 c = GetC();
336 }
337 }
338
339 f *= sign;
340
341 return *this;
342 }
343
344 off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
345 {
346 off_t ret_off;
347
348 switch (mode) {
349 case wxFromStart:
350 if ( (unsigned)abs (DoTellInput()-pos) > m_i_streambuf->GetLastAccess() ) {
351 ret_off = DoSeekInput(pos, wxFromStart);
352 m_i_streambuf->ResetBuffer();
353 return ret_off;
354 } else {
355 m_i_streambuf->SetIntPosition(DoTellInput() - pos);
356 return pos;
357 }
358 case wxFromCurrent:
359 if ( ((unsigned)pos > m_i_streambuf->GetLastAccess()) || (pos < 0) ) {
360 ret_off = DoSeekInput(pos, wxFromCurrent);
361 m_i_streambuf->ResetBuffer();
362 return ret_off;
363 } else {
364 m_i_streambuf->SetIntPosition(pos);
365 return pos;
366 }
367 case wxFromEnd:
368 // Hard to compute: always seek to the requested position.
369 ret_off = DoSeekInput(pos, wxFromEnd);
370 m_i_streambuf->ResetBuffer();
371 return ret_off;
372 }
373 return wxInvalidOffset;
374 }
375
376 off_t wxInputStream::TellI() const
377 {
378 return DoTellInput() - m_i_streambuf->GetLastAccess() +
379 m_i_streambuf->GetIntPosition();
380 }
381
382 // ----------------------------------------------------------------------------
383 // wxOutputStream
384 // ----------------------------------------------------------------------------
385 wxOutputStream::wxOutputStream()
386 {
387 m_o_destroybuf = TRUE;
388 m_o_streambuf = new wxStreamBuffer(*this);
389 }
390
391 wxOutputStream::wxOutputStream(wxStreamBuffer *buffer)
392 {
393 m_o_destroybuf = FALSE;
394 m_o_streambuf = buffer;
395 }
396
397 wxOutputStream::~wxOutputStream()
398 {
399 if (m_o_destroybuf)
400 delete m_o_streambuf;
401 }
402
403 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
404 {
405 m_o_streambuf->Write(buffer, size);
406 return *this;
407 }
408
409 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
410 {
411 stream_in.Read(*this);
412 return *this;
413 }
414
415 off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
416 {
417 off_t ret_off;
418
419 switch (mode) {
420 case wxFromStart:
421 if ( (unsigned)abs (DoTellOutput()-pos) > m_o_streambuf->GetLastAccess() ) {
422 ret_off = DoSeekOutput(pos, wxFromStart);
423 m_o_streambuf->ResetBuffer();
424 return ret_off;
425 } else {
426 m_o_streambuf->SetIntPosition( DoTellOutput() - pos);
427 return pos;
428 }
429 case wxFromCurrent:
430 if ( ((unsigned)pos > m_o_streambuf->GetLastAccess()) || (pos < 0) ) {
431 ret_off = DoSeekOutput(pos, wxFromCurrent);
432 m_o_streambuf->ResetBuffer();
433 return ret_off;
434 } else {
435 m_o_streambuf->SetIntPosition(pos);
436 return pos;
437 }
438 case wxFromEnd:
439 // Hard to compute: always seek to the requested position.
440 ret_off = DoSeekOutput(pos, wxFromEnd);
441 m_o_streambuf->ResetBuffer();
442 return ret_off;
443 }
444 return wxInvalidOffset;
445 }
446
447 off_t wxOutputStream::TellO() const
448 {
449 return DoTellOutput() - m_o_streambuf->GetLastAccess()
450 + m_o_streambuf->GetIntPosition();
451 }
452
453 void wxOutputStream::Sync()
454 {
455 DoWrite(m_o_streambuf->GetBufferStart(), m_o_streambuf->GetIntPosition());
456
457 m_o_streambuf->ResetBuffer();
458 }
459
460 wxOutputStream& wxOutputStream::operator<<(const char *string)
461 {
462 return Write(string, strlen(string));
463 }
464
465 wxOutputStream& wxOutputStream::operator<<(wxString& string)
466 {
467 return Write(string, string.Len());
468 }
469
470 wxOutputStream& wxOutputStream::operator<<(char c)
471 {
472 return Write(&c, 1);
473 }
474
475 wxOutputStream& wxOutputStream::operator<<(short i)
476 {
477 wxString strint;
478
479 strint.Printf("%i", i);
480 return Write(strint, strint.Len());
481 }
482
483 wxOutputStream& wxOutputStream::operator<<(int i)
484 {
485 wxString strint;
486
487 strint.Printf("%i", i);
488 return Write(strint, strint.Len());
489 }
490
491 wxOutputStream& wxOutputStream::operator<<(long i)
492 {
493 wxString strlong;
494
495 strlong.Printf("%i", i);
496 return Write((const char *)strlong, strlong.Len());
497 }
498
499 wxOutputStream& wxOutputStream::operator<<(double f)
500 {
501 wxString strfloat;
502
503 strfloat.Printf("%f", f);
504 return Write(strfloat, strfloat.Len());
505 }
506
507 // ----------------------------------------------------------------------------
508 // wxFilterInputStream
509 // ----------------------------------------------------------------------------
510 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
511 : wxInputStream(NULL)
512 {
513 m_parent_i_stream = &stream;
514 m_i_streambuf = stream.InputStreamBuffer();
515 }
516
517 wxFilterInputStream::~wxFilterInputStream()
518 {
519 }
520
521 size_t wxFilterInputStream::DoRead(void *buffer, size_t size)
522 {
523 return m_parent_i_stream->Read(buffer, size).LastRead();
524 }
525
526 off_t wxFilterInputStream::DoSeekInput(off_t pos, wxSeekMode mode)
527 {
528 return m_parent_i_stream->SeekI(pos, mode);
529 }
530
531 off_t wxFilterInputStream::DoTellInput() const
532 {
533 return m_parent_i_stream->TellI();
534 }
535
536
537 // ----------------------------------------------------------------------------
538 // wxFilterOutputStream
539 // ----------------------------------------------------------------------------
540 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
541 : wxOutputStream(NULL)
542 {
543 m_parent_o_stream = &stream;
544 m_o_streambuf = stream.OutputStreamBuffer();
545 }
546
547 wxFilterOutputStream::~wxFilterOutputStream()
548 {
549 }
550
551 size_t wxFilterOutputStream::DoWrite(const void *buffer, size_t size)
552 {
553 return m_parent_o_stream->Write(buffer, size).LastWrite();
554 }
555
556 off_t wxFilterOutputStream::DoSeekOutput(off_t pos, wxSeekMode mode)
557 {
558 return m_parent_o_stream->SeekO(pos, mode);
559 }
560
561 off_t wxFilterOutputStream::DoTellOutput() const
562 {
563 return m_parent_o_stream->TellO();
564 }
565
566 // ----------------------------------------------------------------------------
567 // Some IOManip function
568 // ----------------------------------------------------------------------------
569
570 wxOutputStream& wxEndL(wxOutputStream& stream)
571 {
572 #ifdef __MSW__
573 return stream.Write("\r\n", 2);
574 #else
575 return stream.Write("\n", 1);
576 #endif
577 }