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