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