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