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