]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/stream.cpp
fixed bug/assert failure when refreshing items in non report mode
[wxWidgets.git] / src / common / stream.cpp
... / ...
CommitLineData
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
59void wxStreamBuffer::SetError(wxStreamError err)
60{
61 if ( m_stream->m_lasterror == wxStream_NOERROR )
62 m_stream->m_lasterror = err;
63}
64
65void 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
76void wxStreamBuffer::Init()
77{
78 InitBuffer();
79
80 m_fixed = TRUE;
81}
82
83wxStreamBuffer::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
94wxStreamBuffer::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
105wxStreamBuffer::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
124void wxStreamBuffer::FreeBuffer()
125{
126 if ( m_destroybuf )
127 free(m_buffer_start);
128}
129
130wxStreamBuffer::~wxStreamBuffer()
131{
132 FreeBuffer();
133
134 if ( m_destroystream )
135 delete m_stream;
136}
137
138wxInputStream *wxStreamBuffer::GetInputStream() const
139{
140 return m_mode == write ? NULL : (wxInputStream *)m_stream;
141}
142
143wxOutputStream *wxStreamBuffer::GetOutputStream() const
144{
145 return m_mode == read ? NULL : (wxOutputStream *)m_stream;
146}
147
148void 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
156void 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
174void 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
189void 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)
202bool 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)
219bool 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
241size_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
251void 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
264void 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
302void 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
329char 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
347char 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
375size_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()"
424size_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
446size_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
504size_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
539off_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
607off_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
625wxStreamBase::wxStreamBase()
626{
627 m_lasterror = wxStream_NOERROR;
628 m_lastcount = 0;
629}
630
631wxStreamBase::~wxStreamBase()
632{
633}
634
635off_t wxStreamBase::OnSysSeek(off_t WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
636{
637 return wxInvalidOffset;
638}
639
640off_t wxStreamBase::OnSysTell() const
641{
642 return wxInvalidOffset;
643}
644
645// ----------------------------------------------------------------------------
646// wxInputStream
647// ----------------------------------------------------------------------------
648
649wxInputStream::wxInputStream()
650{
651 m_wback = NULL;
652 m_wbacksize =
653 m_wbackcur = 0;
654}
655
656wxInputStream::~wxInputStream()
657{
658 free(m_wback);
659}
660
661size_t wxInputStream::OnSysRead(void * WXUNUSED(buffer),
662 size_t WXUNUSED(bufsize))
663{
664 return 0;
665}
666
667bool 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
688char *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
714size_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
738size_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
748bool 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
758char wxInputStream::GetC()
759{
760 char c;
761 Read(&c, 1);
762 return c;
763}
764
765wxInputStream& 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
781char 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
794wxInputStream& 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
807off_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
835off_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
851wxInputStream& 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
864wxOutputStream::wxOutputStream()
865{
866}
867
868wxOutputStream::~wxOutputStream()
869{
870}
871
872size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
873 size_t WXUNUSED(bufsize))
874{
875 return 0;
876}
877
878void wxOutputStream::PutC(char c)
879{
880 Write(&c, 1);
881}
882
883wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
884{
885 m_lastcount = OnSysWrite(buffer, size);
886 return *this;
887}
888
889wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
890{
891 stream_in.Read(*this);
892 return *this;
893}
894
895off_t wxOutputStream::TellO() const
896{
897 return OnSysTell();
898}
899
900off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
901{
902 return OnSysSeek(pos, mode);
903}
904
905void wxOutputStream::Sync()
906{
907}
908
909#if wxUSE_SERIAL
910wxOutputStream& 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
922wxCountingOutputStream::wxCountingOutputStream ()
923{
924 m_currentPos = 0;
925}
926
927size_t wxCountingOutputStream::GetSize() const
928{
929 return m_lastcount;
930}
931
932size_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
942off_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
969off_t wxCountingOutputStream::OnSysTell() const
970{
971 return m_currentPos;
972}
973
974// ----------------------------------------------------------------------------
975// wxFilterInputStream
976// ----------------------------------------------------------------------------
977
978wxFilterInputStream::wxFilterInputStream()
979{
980 m_parent_i_stream = NULL;
981}
982
983wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
984{
985 m_parent_i_stream = &stream;
986}
987
988wxFilterInputStream::~wxFilterInputStream()
989{
990}
991
992// ----------------------------------------------------------------------------
993// wxFilterOutputStream
994// ----------------------------------------------------------------------------
995
996wxFilterOutputStream::wxFilterOutputStream()
997{
998 m_parent_o_stream = NULL;
999}
1000
1001wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
1002{
1003 m_parent_o_stream = &stream;
1004}
1005
1006wxFilterOutputStream::~wxFilterOutputStream()
1007{
1008}
1009
1010// ----------------------------------------------------------------------------
1011// wxBufferedInputStream
1012// ----------------------------------------------------------------------------
1013
1014wxBufferedInputStream::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
1031wxBufferedInputStream::~wxBufferedInputStream()
1032{
1033 m_parent_i_stream->SeekI(-(off_t)m_i_streambuf->GetBytesLeft(),
1034 wxFromCurrent);
1035
1036 delete m_i_streambuf;
1037}
1038
1039char wxBufferedInputStream::Peek()
1040{
1041 return m_i_streambuf->Peek();
1042}
1043
1044wxInputStream& 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
1063off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
1064{
1065 return m_i_streambuf->Seek(pos, mode);
1066}
1067
1068off_t wxBufferedInputStream::TellI() const
1069{
1070 return m_i_streambuf->Tell();
1071}
1072
1073size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
1074{
1075 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
1076}
1077
1078off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode)
1079{
1080 return m_parent_i_stream->SeekI(seek, mode);
1081}
1082
1083off_t wxBufferedInputStream::OnSysTell() const
1084{
1085 return m_parent_i_stream->TellI();
1086}
1087
1088void 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
1100wxBufferedOutputStream::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
1116wxBufferedOutputStream::~wxBufferedOutputStream()
1117{
1118 Sync();
1119 delete m_o_streambuf;
1120}
1121
1122wxOutputStream& 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
1129off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode)
1130{
1131 Sync();
1132 return m_o_streambuf->Seek(pos, mode);
1133}
1134
1135off_t wxBufferedOutputStream::TellO() const
1136{
1137 return m_o_streambuf->Tell();
1138}
1139
1140void wxBufferedOutputStream::Sync()
1141{
1142 m_o_streambuf->FlushBuffer();
1143 m_parent_o_stream->Sync();
1144}
1145
1146size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
1147{
1148 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
1149}
1150
1151off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode)
1152{
1153 return m_parent_o_stream->SeekO(seek, mode);
1154}
1155
1156off_t wxBufferedOutputStream::OnSysTell() const
1157{
1158 return m_parent_o_stream->TellO();
1159}
1160
1161size_t wxBufferedOutputStream::GetSize() const
1162{
1163 return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
1164}
1165
1166void 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
1178wxOutputStream& 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