new set of fixes for problems due to huge files support: drop wxFileSize_t, use wxFil...
[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 wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
661 {
662 return wxInvalidOffset;
663 }
664
665 wxFileOffset wxStreamBase::OnSysTell() const
666 {
667 return wxInvalidOffset;
668 }
669
670 // ----------------------------------------------------------------------------
671 // wxInputStream
672 // ----------------------------------------------------------------------------
673
674 wxInputStream::wxInputStream()
675 {
676 m_wback = NULL;
677 m_wbacksize =
678 m_wbackcur = 0;
679 }
680
681 wxInputStream::~wxInputStream()
682 {
683 free(m_wback);
684 }
685
686 bool wxInputStream::CanRead() const
687 {
688 // we don't know if there is anything to read or not and by default we
689 // prefer to be optimistic and try to read data unless we know for sure
690 // there is no more of it
691 return m_lasterror != wxSTREAM_EOF;
692 }
693
694 bool wxInputStream::Eof() const
695 {
696 // the only way the base class can know we're at EOF is when we'd already
697 // tried to read beyond it in which case last error is set accordingly
698 return GetLastError() == wxSTREAM_EOF;
699 }
700
701 char *wxInputStream::AllocSpaceWBack(size_t needed_size)
702 {
703 // get number of bytes left from previous wback buffer
704 size_t toget = m_wbacksize - m_wbackcur;
705
706 // allocate a buffer large enough to hold prev + new data
707 char *temp_b = (char *)malloc(needed_size + toget);
708
709 if (!temp_b)
710 return NULL;
711
712 // copy previous data (and free old buffer) if needed
713 if (m_wback)
714 {
715 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
716 free(m_wback);
717 }
718
719 // done
720 m_wback = temp_b;
721 m_wbackcur = 0;
722 m_wbacksize = needed_size + toget;
723
724 return m_wback;
725 }
726
727 size_t wxInputStream::GetWBack(void *buf, size_t size)
728 {
729 if (!m_wback)
730 return 0;
731
732 // how many bytes do we have in the buffer?
733 size_t toget = m_wbacksize - m_wbackcur;
734
735 if ( size < toget )
736 {
737 // we won't read everything
738 toget = size;
739 }
740
741 // copy the data from the cache
742 memcpy(buf, m_wback + m_wbackcur, toget);
743
744 m_wbackcur += toget;
745 if ( m_wbackcur == m_wbacksize )
746 {
747 // TODO: should we really free it here all the time? maybe keep it?
748 free(m_wback);
749 m_wback = NULL;
750 m_wbacksize = 0;
751 m_wbackcur = 0;
752 }
753
754 // return the number of bytes copied
755 return toget;
756 }
757
758 size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
759 {
760 if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF )
761 {
762 // can't operate on this stream until the error is cleared
763 return 0;
764 }
765
766 char *ptrback = AllocSpaceWBack(bufsize);
767 if (!ptrback)
768 return 0;
769
770 // Eof() shouldn't return true any longer
771 if ( m_lasterror == wxSTREAM_EOF )
772 m_lasterror = wxSTREAM_NO_ERROR;
773
774 memcpy(ptrback, buf, bufsize);
775 return bufsize;
776 }
777
778 bool wxInputStream::Ungetch(char c)
779 {
780 return Ungetch(&c, sizeof(c)) != 0;
781 }
782
783 char wxInputStream::GetC()
784 {
785 char c;
786 Read(&c, sizeof(c));
787 return c;
788 }
789
790 wxInputStream& wxInputStream::Read(void *buf, size_t size)
791 {
792 char *p = (char *)buf;
793 m_lastcount = 0;
794
795 size_t read = GetWBack(buf, size);
796 for ( ;; )
797 {
798 size -= read;
799 m_lastcount += read;
800 p += read;
801
802 if ( !size )
803 {
804 // we read the requested amount of data
805 break;
806 }
807
808 if ( p != buf && !CanRead() )
809 {
810 // we have already read something and we would block in OnSysRead()
811 // now: don't do it but return immediately
812 break;
813 }
814
815 read = OnSysRead(p, size);
816 if ( !read )
817 {
818 // no more data available
819 break;
820 }
821 }
822
823 return *this;
824 }
825
826 char wxInputStream::Peek()
827 {
828 char c;
829 Read(&c, sizeof(c));
830 if (m_lasterror == wxSTREAM_NO_ERROR)
831 {
832 Ungetch(c);
833 return c;
834 }
835
836 return 0;
837 }
838
839 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
840 {
841 char buf[BUF_TEMP_SIZE];
842
843 for ( ;; )
844 {
845 size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
846 if ( !bytes_read )
847 break;
848
849 if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read )
850 break;
851 }
852
853 return *this;
854 }
855
856 wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
857 {
858 // RR: This code is duplicated in wxBufferedInputStream. This is
859 // not really a good design, but buffered stream are different
860 // from all other in that they handle two stream-related objects,
861 // the stream buffer and parent stream.
862
863 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
864 if (m_lasterror==wxSTREAM_EOF)
865 m_lasterror=wxSTREAM_NO_ERROR;
866
867 /* RR: A call to SeekI() will automatically invalidate any previous
868 call to Ungetch(), otherwise it would be possible to SeekI() to
869 one position, unread some bytes there, SeekI() to another position
870 and the data would be corrupted.
871
872 GRG: Could add code here to try to navigate within the wback
873 buffer if possible, but is it really needed? It would only work
874 when seeking in wxFromCurrent mode, else it would invalidate
875 anyway... */
876
877 if (m_wback)
878 {
879 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
880
881 free(m_wback);
882 m_wback = NULL;
883 m_wbacksize = 0;
884 m_wbackcur = 0;
885 }
886
887 return OnSysSeek(pos, mode);
888 }
889
890 wxFileOffset wxInputStream::TellI() const
891 {
892 wxFileOffset pos = OnSysTell();
893
894 if (pos != wxInvalidOffset)
895 pos -= (m_wbacksize - m_wbackcur);
896
897 return pos;
898 }
899
900
901 // ----------------------------------------------------------------------------
902 // wxOutputStream
903 // ----------------------------------------------------------------------------
904
905 wxOutputStream::wxOutputStream()
906 {
907 }
908
909 wxOutputStream::~wxOutputStream()
910 {
911 }
912
913 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
914 size_t WXUNUSED(bufsize))
915 {
916 return 0;
917 }
918
919 void wxOutputStream::PutC(char c)
920 {
921 Write(&c, sizeof(c));
922 }
923
924 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
925 {
926 m_lastcount = OnSysWrite(buffer, size);
927 return *this;
928 }
929
930 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
931 {
932 stream_in.Read(*this);
933 return *this;
934 }
935
936 wxFileOffset wxOutputStream::TellO() const
937 {
938 return OnSysTell();
939 }
940
941 wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
942 {
943 return OnSysSeek(pos, mode);
944 }
945
946 void wxOutputStream::Sync()
947 {
948 }
949
950
951 // ----------------------------------------------------------------------------
952 // wxCountingOutputStream
953 // ----------------------------------------------------------------------------
954
955 wxCountingOutputStream::wxCountingOutputStream ()
956 {
957 m_currentPos = 0;
958 }
959
960 size_t wxCountingOutputStream::GetSize() const
961 {
962 return m_lastcount;
963 }
964
965 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
966 size_t size)
967 {
968 m_currentPos += size;
969 if (m_currentPos > m_lastcount)
970 m_lastcount = m_currentPos;
971
972 return m_currentPos;
973 }
974
975 wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
976 {
977 switch ( mode )
978 {
979 case wxFromStart:
980 m_currentPos = pos;
981 break;
982
983 case wxFromEnd:
984 m_currentPos = m_lastcount + pos;
985 break;
986
987 case wxFromCurrent:
988 m_currentPos += pos;
989 break;
990
991 default:
992 wxFAIL_MSG( _T("invalid seek mode") );
993 return wxInvalidOffset;
994 }
995
996 if (m_currentPos > m_lastcount)
997 m_lastcount = m_currentPos;
998
999 return m_currentPos;
1000 }
1001
1002 wxFileOffset wxCountingOutputStream::OnSysTell() const
1003 {
1004 return m_currentPos;
1005 }
1006
1007 // ----------------------------------------------------------------------------
1008 // wxFilterInputStream
1009 // ----------------------------------------------------------------------------
1010
1011 wxFilterInputStream::wxFilterInputStream()
1012 {
1013 m_parent_i_stream = NULL;
1014 }
1015
1016 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
1017 {
1018 m_parent_i_stream = &stream;
1019 }
1020
1021 wxFilterInputStream::~wxFilterInputStream()
1022 {
1023 }
1024
1025 // ----------------------------------------------------------------------------
1026 // wxFilterOutputStream
1027 // ----------------------------------------------------------------------------
1028
1029 wxFilterOutputStream::wxFilterOutputStream()
1030 {
1031 m_parent_o_stream = NULL;
1032 }
1033
1034 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
1035 {
1036 m_parent_o_stream = &stream;
1037 }
1038
1039 wxFilterOutputStream::~wxFilterOutputStream()
1040 {
1041 }
1042
1043 // ----------------------------------------------------------------------------
1044 // wxBufferedInputStream
1045 // ----------------------------------------------------------------------------
1046
1047 wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1048 wxStreamBuffer *buffer)
1049 : wxFilterInputStream(s)
1050 {
1051 if ( buffer )
1052 {
1053 // use the buffer provided by the user
1054 m_i_streambuf = buffer;
1055 }
1056 else // create a default buffer
1057 {
1058 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
1059
1060 m_i_streambuf->SetBufferIO(1024);
1061 }
1062 }
1063
1064 wxBufferedInputStream::~wxBufferedInputStream()
1065 {
1066 m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(),
1067 wxFromCurrent);
1068
1069 delete m_i_streambuf;
1070 }
1071
1072 char wxBufferedInputStream::Peek()
1073 {
1074 return m_i_streambuf->Peek();
1075 }
1076
1077 wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1078 {
1079 // reset the error flag
1080 Reset();
1081
1082 // first read from the already cached data
1083 m_lastcount = GetWBack(buf, size);
1084
1085 // do we have to read anything more?
1086 if ( m_lastcount < size )
1087 {
1088 size -= m_lastcount;
1089 buf = (char *)buf + m_lastcount;
1090
1091 // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
1092 // so save it
1093 size_t countOld = m_lastcount;
1094
1095 m_i_streambuf->Read(buf, size);
1096
1097 m_lastcount += countOld;
1098 }
1099
1100 return *this;
1101 }
1102
1103 wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
1104 {
1105 // RR: Look at wxInputStream for comments.
1106
1107 if (m_lasterror==wxSTREAM_EOF)
1108 Reset();
1109
1110 if (m_wback)
1111 {
1112 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1113
1114 free(m_wback);
1115 m_wback = NULL;
1116 m_wbacksize = 0;
1117 m_wbackcur = 0;
1118 }
1119
1120 return m_i_streambuf->Seek(pos, mode);
1121 }
1122
1123 wxFileOffset wxBufferedInputStream::TellI() const
1124 {
1125 wxFileOffset pos = m_i_streambuf->Tell();
1126
1127 if (pos != wxInvalidOffset)
1128 pos -= (m_wbacksize - m_wbackcur);
1129
1130 return pos;
1131 }
1132
1133 size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
1134 {
1135 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
1136 }
1137
1138 wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1139 {
1140 return m_parent_i_stream->SeekI(seek, mode);
1141 }
1142
1143 wxFileOffset wxBufferedInputStream::OnSysTell() const
1144 {
1145 return m_parent_i_stream->TellI();
1146 }
1147
1148 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1149 {
1150 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1151
1152 delete m_i_streambuf;
1153 m_i_streambuf = buffer;
1154 }
1155
1156 // ----------------------------------------------------------------------------
1157 // wxBufferedOutputStream
1158 // ----------------------------------------------------------------------------
1159
1160 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1161 wxStreamBuffer *buffer)
1162 : wxFilterOutputStream(s)
1163 {
1164 if ( buffer )
1165 {
1166 m_o_streambuf = buffer;
1167 }
1168 else // create a default one
1169 {
1170 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1171
1172 m_o_streambuf->SetBufferIO(1024);
1173 }
1174 }
1175
1176 wxBufferedOutputStream::~wxBufferedOutputStream()
1177 {
1178 Sync();
1179 delete m_o_streambuf;
1180 }
1181
1182 wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
1183 {
1184 m_lastcount = 0;
1185 m_o_streambuf->Write(buffer, size);
1186 return *this;
1187 }
1188
1189 wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
1190 {
1191 Sync();
1192 return m_o_streambuf->Seek(pos, mode);
1193 }
1194
1195 wxFileOffset wxBufferedOutputStream::TellO() const
1196 {
1197 return m_o_streambuf->Tell();
1198 }
1199
1200 void wxBufferedOutputStream::Sync()
1201 {
1202 m_o_streambuf->FlushBuffer();
1203 m_parent_o_stream->Sync();
1204 }
1205
1206 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
1207 {
1208 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
1209 }
1210
1211 wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1212 {
1213 return m_parent_o_stream->SeekO(seek, mode);
1214 }
1215
1216 wxFileOffset wxBufferedOutputStream::OnSysTell() const
1217 {
1218 return m_parent_o_stream->TellO();
1219 }
1220
1221 size_t wxBufferedOutputStream::GetSize() const
1222 {
1223 return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
1224 }
1225
1226 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1227 {
1228 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1229
1230 delete m_o_streambuf;
1231 m_o_streambuf = buffer;
1232 }
1233
1234 // ----------------------------------------------------------------------------
1235 // Some IOManip function
1236 // ----------------------------------------------------------------------------
1237
1238 wxOutputStream& wxEndL(wxOutputStream& stream)
1239 {
1240 static const wxChar *eol = wxTextFile::GetEOL();
1241
1242 return stream.Write(eol, wxStrlen(eol));
1243 }
1244
1245 #endif
1246 // wxUSE_STREAMS