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