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