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