more fixes to stream code: allow deriving from wxStreamBuffer and using custom
[wxWidgets.git] / src / common / stream.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/stream.cpp
3 // Purpose: wxStream base classes
4 // Author: Guilhem Lavaux
5 // Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory,
6 // general code review
7 // Created: 11/07/98
8 // RCS-ID: $Id$
9 // Copyright: (c) Guilhem Lavaux
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 #ifdef __GNUG__
22 #pragma implementation "stream.h"
23 #endif
24
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 #ifndef WX_PRECOMP
33 #include "wx/defs.h"
34 #endif
35
36 #if wxUSE_STREAMS
37
38 #include <ctype.h>
39 #include "wx/stream.h"
40 #include "wx/datstrm.h"
41 #include "wx/objstrm.h"
42
43 // ----------------------------------------------------------------------------
44 // constants
45 // ----------------------------------------------------------------------------
46
47 // the temporary buffer size used when copying from stream to stream
48 #define BUF_TEMP_SIZE 10000
49
50 // ============================================================================
51 // implementation
52 // ============================================================================
53
54 // ----------------------------------------------------------------------------
55 // wxStreamBuffer
56 // ----------------------------------------------------------------------------
57
58 void wxStreamBuffer::SetError(wxStreamError err)
59 {
60 if ( m_stream->m_lasterror == wxStream_NOERROR )
61 m_stream->m_lasterror = err;
62 }
63
64 void wxStreamBuffer::InitBuffer()
65 {
66 m_buffer_start =
67 m_buffer_end =
68 m_buffer_pos = NULL;
69 m_buffer_size = 0;
70
71 // there is nothing to destroy anyhow
72 m_destroybuf = FALSE;
73 }
74
75 void wxStreamBuffer::Init()
76 {
77 InitBuffer();
78
79 m_fixed = TRUE;
80 }
81
82 wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
83 {
84 m_stream = &stream;
85 m_mode = mode;
86
87 m_flushable = TRUE;
88 m_destroystream = FALSE;
89 }
90
91 wxStreamBuffer::wxStreamBuffer(BufMode mode)
92 {
93 m_stream = new wxStreamBase;
94 m_mode = mode;
95
96 m_flushable = FALSE;
97 m_destroystream = TRUE;
98 }
99
100 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
101 {
102 // doing this has big chances to lead to a crashwhen the source buffer is
103 // destroyed (otherwise assume the caller knows what he does)
104 wxASSERT_MSG( !buffer.m_destroybuf && !buffer.m_destroystream,
105 _T("it's a bad idea to copy this buffer") );
106
107 m_buffer_start = buffer.m_buffer_start;
108 m_buffer_end = buffer.m_buffer_end;
109 m_buffer_pos = buffer.m_buffer_pos;
110 m_buffer_size = buffer.m_buffer_size;
111 m_fixed = buffer.m_fixed;
112 m_flushable = buffer.m_flushable;
113 m_stream = buffer.m_stream;
114 m_mode = buffer.m_mode;
115 m_destroybuf = FALSE;
116 m_destroystream = FALSE;
117 }
118
119 void wxStreamBuffer::FreeBuffer()
120 {
121 if ( m_destroybuf )
122 free(m_buffer_start);
123 }
124
125 wxStreamBuffer::~wxStreamBuffer()
126 {
127 FreeBuffer();
128
129 if ( m_destroystream )
130 delete m_stream;
131 }
132
133 wxInputStream *wxStreamBuffer::GetInputStream() const
134 {
135 return m_mode == write ? NULL : (wxInputStream *)m_stream;
136 }
137
138 wxOutputStream *wxStreamBuffer::GetOutputStream() const
139 {
140 return m_mode == read ? NULL : (wxOutputStream *)m_stream;
141 }
142
143 void wxStreamBuffer::SetBufferIO(void *buffer_start,
144 void *buffer_end,
145 bool takeOwnership)
146 {
147 SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start,
148 takeOwnership);
149 }
150
151 void wxStreamBuffer::SetBufferIO(void *start,
152 size_t len,
153 bool takeOwnership)
154 {
155 // start by freeing the old buffer
156 FreeBuffer();
157
158 m_buffer_start = (char *)start;
159 m_buffer_end = m_buffer_start + len;
160
161 m_buffer_size = len;
162
163 // if we own it, we free it
164 m_destroybuf = !takeOwnership;
165
166 ResetBuffer();
167 }
168
169 void wxStreamBuffer::SetBufferIO(size_t bufsize)
170 {
171 // start by freeing the old buffer
172 FreeBuffer();
173
174 if ( bufsize )
175 {
176 SetBufferIO(malloc(bufsize), bufsize, TRUE /* take ownership */);
177 }
178 else // no buffer size => no buffer
179 {
180 InitBuffer();
181 }
182 }
183
184 void wxStreamBuffer::ResetBuffer()
185 {
186 wxCHECK_RET( m_stream, _T("should have a stream in wxStreamBuffer") );
187
188 m_stream->m_lasterror = wxStream_NOERROR;
189 m_stream->m_lastcount = 0;
190 if (m_mode == read && m_flushable)
191 m_buffer_pos = m_buffer_end;
192 else
193 m_buffer_pos = m_buffer_start;
194 }
195
196 // fill the buffer with as much data as possible (only for read buffers)
197 bool wxStreamBuffer::FillBuffer()
198 {
199 wxInputStream *inStream = GetInputStream();
200
201 wxCHECK_MSG( inStream, FALSE, _T("should have a stream in wxStreamBuffer") );
202
203 size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
204 if ( !count )
205 return FALSE;
206
207 m_buffer_end = m_buffer_start + count;
208 m_buffer_pos = m_buffer_start;
209
210 return TRUE;
211 }
212
213 // write the buffer contents to the stream (only for write buffers)
214 bool wxStreamBuffer::FlushBuffer()
215 {
216 wxCHECK_MSG( m_flushable, FALSE, _T("can't flush this buffer") );
217
218 // FIXME: what is this check for? (VZ)
219 if ( m_buffer_pos == m_buffer_start )
220 return FALSE;
221
222 wxOutputStream *outStream = GetOutputStream();
223
224 wxCHECK_MSG( outStream, FALSE, _T("should have a stream in wxStreamBuffer") );
225
226 size_t current = m_buffer_pos - m_buffer_start;
227 size_t count = outStream->OnSysWrite(m_buffer_start, current);
228 if ( count != current )
229 return FALSE;
230
231 m_buffer_pos = m_buffer_start;
232
233 return TRUE;
234 }
235
236 size_t wxStreamBuffer::GetDataLeft()
237 {
238 /* Why is this done? RR. */
239 if ( m_buffer_pos == m_buffer_end && m_flushable)
240 FillBuffer();
241
242 return GetBytesLeft();
243 }
244
245 // copy up to size bytes from our buffer into the provided one
246 void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
247 {
248 // don't get more bytes than left in the buffer
249 size_t left = GetBytesLeft();
250
251 if ( size > left )
252 size = left;
253
254 memcpy(buffer, m_buffer_pos, size);
255 m_buffer_pos += size;
256 }
257
258 // copy the contents of the provided buffer into this one
259 void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
260 {
261 size_t left = GetBytesLeft();
262 if ( size > left )
263 {
264 if ( m_fixed )
265 {
266 // we can't realloc the buffer, so just copy what we can
267 size = left;
268 }
269 else // !m_fixed
270 {
271 // realloc the buffer to have enough space for the data
272 size_t delta = m_buffer_pos - m_buffer_start;
273
274 char *startOld = m_buffer_start;
275 m_buffer_size += size;
276 m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size);
277 if ( !m_buffer_start )
278 {
279 // don't leak memory if realloc() failed
280 m_buffer_start = startOld;
281 m_buffer_size -= size;
282
283 // what else can we do?
284 return;
285 }
286
287 // adjust the pointers invalidated by realloc()
288 m_buffer_pos = m_buffer_start + delta;
289 m_buffer_end = m_buffer_start + m_buffer_size;
290 }
291 }
292
293 memcpy(m_buffer_pos, buffer, size);
294 m_buffer_pos += size;
295 }
296
297 void wxStreamBuffer::PutChar(char c)
298 {
299 wxOutputStream *outStream = GetOutputStream();
300
301 wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") );
302
303 // if we don't have buffer at all, just forward this call to the stream,
304 if ( !HasBuffer() )
305 {
306 outStream->OnSysWrite(&c, 1);
307 }
308 else
309 {
310 // otherwise check we have enough space left
311 if ( !GetDataLeft() && !FlushBuffer() )
312 {
313 // we don't
314 SetError(wxStream_WRITE_ERR);
315 }
316 else
317 {
318 PutToBuffer(&c, 1);
319 m_stream->m_lastcount = 1;
320 }
321 }
322 }
323
324 char wxStreamBuffer::Peek()
325 {
326 wxCHECK_MSG( m_stream && HasBuffer(), 0,
327 _T("should have the stream and the buffer in wxStreamBuffer") );
328
329 if ( !GetDataLeft() )
330 {
331 SetError(wxStream_READ_ERR);
332 return 0;
333 }
334
335 char c;
336 GetFromBuffer(&c, 1);
337 m_buffer_pos--;
338
339 return c;
340 }
341
342 char wxStreamBuffer::GetChar()
343 {
344 wxInputStream *inStream = GetInputStream();
345
346 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
347
348 char c;
349 if ( !HasBuffer() )
350 {
351 inStream->OnSysRead(&c, 1);
352 }
353 else
354 {
355 if ( !GetDataLeft() )
356 {
357 SetError(wxStream_READ_ERR);
358 c = 0;
359 }
360 else
361 {
362 GetFromBuffer(&c, 1);
363 m_stream->m_lastcount = 1;
364 }
365 }
366
367 return c;
368 }
369
370 size_t wxStreamBuffer::Read(void *buffer, size_t size)
371 {
372 wxInputStream *inStream = GetInputStream();
373
374 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
375
376 // lasterror is reset before all new IO calls
377 m_stream->m_lasterror = wxStream_NOERROR;
378
379 if ( !HasBuffer() )
380 {
381 m_stream->m_lastcount = inStream->OnSysRead(buffer, size);
382 }
383 else // we have a buffer, use it
384 {
385 size_t orig_size = size;
386
387 while ( size > 0 )
388 {
389 size_t left = GetDataLeft();
390
391 // if the requested number of bytes if greater than the buffer
392 // size, read data in chunks
393 if ( size > left )
394 {
395 GetFromBuffer(buffer, left);
396 size -= left;
397 buffer = (char *)buffer + left;
398
399 if ( !FillBuffer() )
400 {
401 SetError(wxStream_EOF);
402 break;
403 }
404 }
405 else // otherwise just do it in one gulp
406 {
407 GetFromBuffer(buffer, size);
408 size = 0;
409 }
410 }
411
412 m_stream->m_lastcount = orig_size - size;
413 }
414
415 return m_stream->m_lastcount;
416 }
417
418 // this should really be called "Copy()"
419 size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
420 {
421 wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") );
422
423 char buf[BUF_TEMP_SIZE];
424 size_t nRead,
425 total = 0;
426
427 do
428 {
429 nRead = Read(dbuf, WXSIZEOF(buf));
430 if ( nRead )
431 {
432 nRead = dbuf->Write(buf, nRead);
433 total += nRead;
434 }
435 }
436 while ( nRead );
437
438 return total;
439 }
440
441 size_t wxStreamBuffer::Write(const void *buffer, size_t size)
442 {
443 wxOutputStream *outStream = GetOutputStream();
444
445 wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
446
447 // lasterror is reset before all new IO calls
448 m_stream->m_lasterror = wxStream_NOERROR;
449
450 if ( !HasBuffer() && m_fixed )
451 {
452 // no buffer, just forward the call to the stream
453 m_stream->m_lastcount = outStream->OnSysWrite(buffer, size);
454 }
455 else // we [may] have a buffer, use it
456 {
457 size_t orig_size = size;
458
459 while ( size > 0 )
460 {
461 size_t left = GetBytesLeft();
462
463 // if the buffer is too large to fit in the stream buffer, split
464 // it in smaller parts
465 //
466 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
467 // we always go to the second case.
468 //
469 // FIXME: fine, but if it fails we should (re)try writing it by
470 // chunks as this will (hopefully) always work (VZ)
471 if ( size > left && m_fixed )
472 {
473 PutToBuffer(buffer, left);
474 size -= left;
475 buffer = (char *)buffer + left;
476
477 if ( !FlushBuffer() )
478 {
479 SetError(wxStream_WRITE_ERR);
480
481 break;
482 }
483
484 m_buffer_pos = m_buffer_start;
485 }
486 else // we can do it in one gulp
487 {
488 PutToBuffer(buffer, size);
489 size = 0;
490 }
491 }
492
493 m_stream->m_lastcount = orig_size - size;
494 }
495
496 return m_stream->m_lastcount;
497 }
498
499 size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
500 {
501 wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") );
502 wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") );
503
504 char buf[BUF_TEMP_SIZE];
505 size_t nWrite,
506 total = 0;
507
508 do
509 {
510 size_t nRead = sbuf->Read(buf, WXSIZEOF(buf));
511 if ( nRead )
512 {
513 nWrite = Write(buf, nRead);
514 if ( nWrite < nRead )
515 {
516 // put back data we couldn't copy
517 wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream();
518
519 in_stream->Ungetch(buf + nWrite, nRead - nWrite);
520 }
521
522 total += nWrite;
523 }
524 else
525 {
526 nWrite = 0;
527 }
528 }
529 while ( nWrite == WXSIZEOF(buf) );
530
531 return total;
532 }
533
534 off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode)
535 {
536 off_t ret_off, diff;
537
538 off_t last_access = GetLastAccess();
539
540 if ( !m_flushable )
541 {
542 switch (mode)
543 {
544 case wxFromStart:
545 diff = pos;
546 break;
547
548 case wxFromCurrent:
549 diff = pos + GetIntPosition();
550 break;
551
552 case wxFromEnd:
553 diff = pos + last_access;
554 break;
555
556 default:
557 wxFAIL_MSG( _T("invalid seek mode") );
558
559 return wxInvalidOffset;
560 }
561 if (diff < 0 || diff > last_access)
562 return wxInvalidOffset;
563 SetIntPosition(diff);
564 return diff;
565 }
566
567 switch ( mode )
568 {
569 case wxFromStart:
570 // We'll try to compute an internal position later ...
571 ret_off = m_stream->OnSysSeek(pos, wxFromStart);
572 ResetBuffer();
573 return ret_off;
574
575 case wxFromCurrent:
576 diff = pos + GetIntPosition();
577
578 if ( (diff > last_access) || (diff < 0) )
579 {
580 // We must take into account the fact that we have read
581 // something previously.
582 ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
583 ResetBuffer();
584 return ret_off;
585 }
586 else
587 {
588 SetIntPosition(diff);
589 return pos;
590 }
591
592 case wxFromEnd:
593 // Hard to compute: always seek to the requested position.
594 ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
595 ResetBuffer();
596 return ret_off;
597 }
598
599 return wxInvalidOffset;
600 }
601
602 off_t wxStreamBuffer::Tell() const
603 {
604 off_t pos = m_stream->OnSysTell();
605 if ( pos == wxInvalidOffset )
606 return wxInvalidOffset;
607
608 pos += GetIntPosition();
609
610 if ( m_mode == read && m_flushable )
611 pos -= GetLastAccess();
612
613 return pos;
614 }
615
616 // ----------------------------------------------------------------------------
617 // wxStreamBase
618 // ----------------------------------------------------------------------------
619
620 wxStreamBase::wxStreamBase()
621 {
622 m_lasterror = wxStream_NOERROR;
623 m_lastcount = 0;
624 }
625
626 wxStreamBase::~wxStreamBase()
627 {
628 }
629
630 // ----------------------------------------------------------------------------
631 // wxInputStream
632 // ----------------------------------------------------------------------------
633
634 wxInputStream::wxInputStream()
635 {
636 m_wback = NULL;
637 m_wbacksize =
638 m_wbackcur = 0;
639 }
640
641 wxInputStream::~wxInputStream()
642 {
643 free(m_wback);
644 }
645
646 size_t wxInputStream::OnSysRead(void * WXUNUSED(buffer),
647 size_t WXUNUSED(bufsize))
648 {
649 return 0;
650 }
651
652 bool wxInputStream::Eof() const
653 {
654 wxInputStream *self = wxConstCast(this, wxInputStream);
655
656 char c;
657 self->Read(&c, 1);
658 if ( GetLastError() == wxSTREAM_EOF )
659 {
660 return TRUE;
661 }
662
663 self->Ungetch(c);
664
665 return FALSE;
666 }
667
668 char *wxInputStream::AllocSpaceWBack(size_t needed_size)
669 {
670 // get number of bytes left from previous wback buffer
671 size_t toget = m_wbacksize - m_wbackcur;
672
673 // allocate a buffer large enough to hold prev + new data
674 char *temp_b = (char *)malloc(needed_size + toget);
675
676 if (!temp_b)
677 return NULL;
678
679 /* copy previous data (and free old buffer) if needed */
680 if (m_wback)
681 {
682 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
683 free(m_wback);
684 }
685
686 /* done */
687 m_wback = temp_b;
688 m_wbackcur = 0;
689 m_wbacksize = needed_size + toget;
690
691 return m_wback;
692 }
693
694 size_t wxInputStream::GetWBack(void *buf, size_t bsize)
695 {
696 size_t toget = m_wbacksize-m_wbackcur;
697
698 if (!m_wback)
699 return 0;
700
701 if (bsize < toget)
702 toget = bsize;
703
704 memcpy(buf, (m_wback+m_wbackcur), toget);
705
706 m_wbackcur += toget;
707 if (m_wbackcur == m_wbacksize)
708 {
709 free(m_wback);
710 m_wback = NULL;
711 m_wbacksize = 0;
712 m_wbackcur = 0;
713 }
714
715 return toget;
716 }
717
718 size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
719 {
720 char *ptrback = AllocSpaceWBack(bufsize);
721 if (!ptrback)
722 return 0;
723
724 memcpy(ptrback, buf, bufsize);
725 return bufsize;
726 }
727
728 bool wxInputStream::Ungetch(char c)
729 {
730 void *ptrback = AllocSpaceWBack(1);
731 if (!ptrback)
732 return FALSE;
733
734 *(char *)ptrback = c;
735 return TRUE;
736 }
737
738 char wxInputStream::GetC()
739 {
740 char c;
741 Read(&c, 1);
742 return c;
743 }
744
745 wxInputStream& wxInputStream::Read(void *buf, size_t size)
746 {
747 size_t retsize = GetWBack(buf, size);
748 if (retsize == size)
749 {
750 m_lastcount = size;
751 m_lasterror = wxStream_NOERROR;
752 return *this;
753 }
754 size -= retsize;
755 buf = (char *)buf + retsize;
756
757 m_lastcount = OnSysRead(buf, size) + retsize;
758 return *this;
759 }
760
761 char wxInputStream::Peek()
762 {
763 char c;
764 Read(&c, 1);
765 if (m_lasterror == wxStream_NOERROR)
766 {
767 Ungetch(c);
768 return c;
769 }
770
771 return 0;
772 }
773
774 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
775 {
776 char buf[BUF_TEMP_SIZE];
777 size_t bytes_read = BUF_TEMP_SIZE;
778
779 while (bytes_read == BUF_TEMP_SIZE)
780 {
781 bytes_read = Read(buf, bytes_read).LastRead();
782 bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
783 }
784 return *this;
785 }
786
787 off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
788 {
789 /* Should be check and improve, just to remove a slight bug !
790 I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
791 if (m_lasterror==wxSTREAM_EOF)
792 m_lasterror=wxSTREAM_NOERROR;
793
794 /* A call to SeekI() will automatically invalidate any previous call
795 to Ungetch(), otherwise it would be possible to SeekI() to one
796 one position, unread some bytes there, SeekI() to another position
797 and the data would be corrupted.
798
799 GRG: Could add code here to try to navigate within the wback
800 buffer if possible, but is it really needed? It would only work
801 when seeking in wxFromCurrent mode, else it would invalidate
802 anyway...
803 */
804 if (m_wback)
805 {
806 free(m_wback);
807 m_wback = NULL;
808 m_wbacksize = 0;
809 m_wbackcur = 0;
810 }
811
812 return OnSysSeek(pos, mode);
813 }
814
815 off_t wxInputStream::TellI() const
816 {
817 /* GRG: Changed to make it compatible with the wback buffer */
818 off_t pos = OnSysTell();
819
820 if (pos != wxInvalidOffset)
821 pos -= (m_wbacksize - m_wbackcur);
822
823 return pos;
824 }
825
826 // --------------------
827 // Overloaded operators
828 // --------------------
829
830 #if wxUSE_SERIAL
831 wxInputStream& wxInputStream::operator>>(wxObject *& obj)
832 {
833 wxObjectInputStream obj_s(*this);
834 obj = obj_s.LoadObject();
835 return *this;
836 }
837 #endif // wxUSE_SERIAL
838
839
840 // ----------------------------------------------------------------------------
841 // wxOutputStream
842 // ----------------------------------------------------------------------------
843
844 wxOutputStream::wxOutputStream()
845 {
846 }
847
848 wxOutputStream::~wxOutputStream()
849 {
850 }
851
852 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
853 size_t WXUNUSED(bufsize))
854 {
855 return 0;
856 }
857
858 void wxOutputStream::PutC(char c)
859 {
860 Write(&c, 1);
861 }
862
863 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
864 {
865 m_lastcount = OnSysWrite(buffer, size);
866 return *this;
867 }
868
869 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
870 {
871 stream_in.Read(*this);
872 return *this;
873 }
874
875 off_t wxOutputStream::TellO() const
876 {
877 return OnSysTell();
878 }
879
880 off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
881 {
882 return OnSysSeek(pos, mode);
883 }
884
885 void wxOutputStream::Sync()
886 {
887 }
888
889 #if wxUSE_SERIAL
890 wxOutputStream& wxOutputStream::operator<<(wxObject& obj)
891 {
892 wxObjectOutputStream obj_s(*this);
893 obj_s.SaveObject(obj);
894 return *this;
895 }
896 #endif // wxUSE_SERIAL
897
898 // ----------------------------------------------------------------------------
899 // wxCountingOutputStream
900 // ----------------------------------------------------------------------------
901
902 wxCountingOutputStream::wxCountingOutputStream ()
903 {
904 m_currentPos = 0;
905 }
906
907 size_t wxCountingOutputStream::GetSize() const
908 {
909 return m_lastcount;
910 }
911
912 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
913 size_t size)
914 {
915 m_currentPos += size;
916 if (m_currentPos > m_lastcount)
917 m_lastcount = m_currentPos;
918
919 return m_currentPos;
920 }
921
922 off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode)
923 {
924 switch ( mode )
925 {
926 case wxFromStart:
927 m_currentPos = pos;
928 break;
929
930 case wxFromEnd:
931 m_currentPos = m_lastcount + pos;
932 break;
933
934 case wxFromCurrent:
935 m_currentPos += pos;
936 break;
937
938 default:
939 wxFAIL_MSG( _T("invalid seek mode") );
940 return wxInvalidOffset;
941 }
942
943 if (m_currentPos > m_lastcount)
944 m_lastcount = m_currentPos;
945
946 return m_currentPos;
947 }
948
949 off_t wxCountingOutputStream::OnSysTell() const
950 {
951 return m_currentPos;
952 }
953
954 // ----------------------------------------------------------------------------
955 // wxFilterInputStream
956 // ----------------------------------------------------------------------------
957
958 wxFilterInputStream::wxFilterInputStream()
959 {
960 m_parent_i_stream = NULL;
961 }
962
963 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
964 {
965 m_parent_i_stream = &stream;
966 }
967
968 wxFilterInputStream::~wxFilterInputStream()
969 {
970 }
971
972 // ----------------------------------------------------------------------------
973 // wxFilterOutputStream
974 // ----------------------------------------------------------------------------
975
976 wxFilterOutputStream::wxFilterOutputStream()
977 {
978 m_parent_o_stream = NULL;
979 }
980
981 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
982 {
983 m_parent_o_stream = &stream;
984 }
985
986 wxFilterOutputStream::~wxFilterOutputStream()
987 {
988 }
989
990 // ----------------------------------------------------------------------------
991 // wxBufferedInputStream
992 // ----------------------------------------------------------------------------
993
994 wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
995 wxStreamBuffer *buffer)
996 : wxFilterInputStream(s)
997 {
998 if ( buffer )
999 {
1000 // use the buffer provided by the user
1001 m_i_streambuf = buffer;
1002 }
1003 else // create a default buffer
1004 {
1005 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
1006
1007 m_i_streambuf->SetBufferIO(1024);
1008 }
1009 }
1010
1011 wxBufferedInputStream::~wxBufferedInputStream()
1012 {
1013 m_parent_i_stream->SeekI(-m_i_streambuf->GetBytesLeft(), wxFromCurrent);
1014
1015 delete m_i_streambuf;
1016 }
1017
1018 char wxBufferedInputStream::Peek()
1019 {
1020 return m_i_streambuf->Peek();
1021 }
1022
1023 wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1024 {
1025 size_t retsize;
1026
1027 retsize = GetWBack(buf, size);
1028 m_lastcount = retsize;
1029 if ( retsize == size )
1030 {
1031 m_lasterror = wxStream_NOERROR;
1032 return *this;
1033 }
1034 size -= retsize;
1035 buf = (char *)buf + retsize;
1036
1037 m_i_streambuf->Read(buf, size);
1038
1039 return *this;
1040 }
1041
1042 off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
1043 {
1044 return m_i_streambuf->Seek(pos, mode);
1045 }
1046
1047 off_t wxBufferedInputStream::TellI() const
1048 {
1049 return m_i_streambuf->Tell();
1050 }
1051
1052 size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
1053 {
1054 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
1055 }
1056
1057 off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode)
1058 {
1059 return m_parent_i_stream->SeekI(seek, mode);
1060 }
1061
1062 off_t wxBufferedInputStream::OnSysTell() const
1063 {
1064 return m_parent_i_stream->TellI();
1065 }
1066
1067 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1068 {
1069 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1070
1071 delete m_i_streambuf;
1072 m_i_streambuf = buffer;
1073 }
1074
1075 // ----------------------------------------------------------------------------
1076 // wxBufferedOutputStream
1077 // ----------------------------------------------------------------------------
1078
1079 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1080 wxStreamBuffer *buffer)
1081 : wxFilterOutputStream(s)
1082 {
1083 if ( buffer )
1084 {
1085 m_o_streambuf = buffer;
1086 }
1087 else // create a default one
1088 {
1089 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1090
1091 m_o_streambuf->SetBufferIO(1024);
1092 }
1093 }
1094
1095 wxBufferedOutputStream::~wxBufferedOutputStream()
1096 {
1097 Sync();
1098 delete m_o_streambuf;
1099 }
1100
1101 wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
1102 {
1103 m_lastcount = 0;
1104 m_o_streambuf->Write(buffer, size);
1105 return *this;
1106 }
1107
1108 off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode)
1109 {
1110 Sync();
1111 return m_o_streambuf->Seek(pos, mode);
1112 }
1113
1114 off_t wxBufferedOutputStream::TellO() const
1115 {
1116 return m_o_streambuf->Tell();
1117 }
1118
1119 void wxBufferedOutputStream::Sync()
1120 {
1121 m_o_streambuf->FlushBuffer();
1122 m_parent_o_stream->Sync();
1123 }
1124
1125 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
1126 {
1127 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
1128 }
1129
1130 off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode)
1131 {
1132 return m_parent_o_stream->SeekO(seek, mode);
1133 }
1134
1135 off_t wxBufferedOutputStream::OnSysTell() const
1136 {
1137 return m_parent_o_stream->TellO();
1138 }
1139
1140 size_t wxBufferedOutputStream::GetSize() const
1141 {
1142 return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
1143 }
1144
1145 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1146 {
1147 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1148
1149 delete m_o_streambuf;
1150 m_o_streambuf = buffer;
1151 }
1152
1153 // ----------------------------------------------------------------------------
1154 // Some IOManip function
1155 // ----------------------------------------------------------------------------
1156
1157 wxOutputStream& wxEndL(wxOutputStream& stream)
1158 {
1159 #ifdef __MSW__
1160 return stream.Write("\r\n", 2);
1161 #else
1162 #ifdef __WXMAC__
1163 return stream.Write("\r", 1);
1164 #else
1165 return stream.Write("\n", 1);
1166 #endif
1167 #endif
1168 }
1169
1170 #endif
1171 // wxUSE_STREAMS