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