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