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