Old API clearly deprecated.
[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 #if WXWIN_COMPATIBILITY_2_2
677
678 wxStreamError wxStreamBase::LastError() const
679 {
680 return m_lasterror;
681 }
682
683 size_t wxStreamBase::StreamSize() const
684 {
685 return GetSize();
686 }
687
688 #endif // WXWIN_COMPATIBILITY_2_2
689
690 // ----------------------------------------------------------------------------
691 // wxInputStream
692 // ----------------------------------------------------------------------------
693
694 wxInputStream::wxInputStream()
695 {
696 m_wback = NULL;
697 m_wbacksize =
698 m_wbackcur = 0;
699 }
700
701 wxInputStream::~wxInputStream()
702 {
703 free(m_wback);
704 }
705
706 bool wxInputStream::CanRead() const
707 {
708 // we don't know if there is anything to read or not and by default we
709 // prefer to be optimistic and try to read data unless we know for sure
710 // there is no more of it
711 return m_lasterror != wxSTREAM_EOF;
712 }
713
714 bool wxInputStream::Eof() const
715 {
716 // the only way the base class can know we're at EOF is when we'd already
717 // tried to read beyond it in which case last error is set accordingly
718 return GetLastError() == wxSTREAM_EOF;
719 }
720
721 char *wxInputStream::AllocSpaceWBack(size_t needed_size)
722 {
723 // get number of bytes left from previous wback buffer
724 size_t toget = m_wbacksize - m_wbackcur;
725
726 // allocate a buffer large enough to hold prev + new data
727 char *temp_b = (char *)malloc(needed_size + toget);
728
729 if (!temp_b)
730 return NULL;
731
732 // copy previous data (and free old buffer) if needed
733 if (m_wback)
734 {
735 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
736 free(m_wback);
737 }
738
739 // done
740 m_wback = temp_b;
741 m_wbackcur = 0;
742 m_wbacksize = needed_size + toget;
743
744 return m_wback;
745 }
746
747 size_t wxInputStream::GetWBack(void *buf, size_t size)
748 {
749 if (!m_wback)
750 return 0;
751
752 // how many bytes do we have in the buffer?
753 size_t toget = m_wbacksize - m_wbackcur;
754
755 if ( size < toget )
756 {
757 // we won't read everything
758 toget = size;
759 }
760
761 // copy the data from the cache
762 memcpy(buf, m_wback + m_wbackcur, toget);
763
764 m_wbackcur += toget;
765 if ( m_wbackcur == m_wbacksize )
766 {
767 // TODO: should we really free it here all the time? maybe keep it?
768 free(m_wback);
769 m_wback = NULL;
770 m_wbacksize = 0;
771 m_wbackcur = 0;
772 }
773
774 // return the number of bytes copied
775 return toget;
776 }
777
778 size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
779 {
780 if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF )
781 {
782 // can't operate on this stream until the error is cleared
783 return 0;
784 }
785
786 char *ptrback = AllocSpaceWBack(bufsize);
787 if (!ptrback)
788 return 0;
789
790 // Eof() shouldn't return true any longer
791 if ( m_lasterror == wxSTREAM_EOF )
792 m_lasterror = wxSTREAM_NO_ERROR;
793
794 memcpy(ptrback, buf, bufsize);
795 return bufsize;
796 }
797
798 bool wxInputStream::Ungetch(char c)
799 {
800 return Ungetch(&c, sizeof(c)) != 0;
801 }
802
803 char wxInputStream::GetC()
804 {
805 char c;
806 Read(&c, sizeof(c));
807 return c;
808 }
809
810 wxInputStream& wxInputStream::Read(void *buf, size_t size)
811 {
812 char *p = (char *)buf;
813 m_lastcount = 0;
814
815 size_t read = GetWBack(buf, size);
816 for ( ;; )
817 {
818 size -= read;
819 m_lastcount += read;
820 p += read;
821
822 if ( !size )
823 {
824 // we read the requested amount of data
825 break;
826 }
827
828 if ( p != buf && !CanRead() )
829 {
830 // we have already read something and we would block in OnSysRead()
831 // now: don't do it but return immediately
832 break;
833 }
834
835 read = OnSysRead(p, size);
836 if ( !read )
837 {
838 // no more data available
839 break;
840 }
841 }
842
843 return *this;
844 }
845
846 char wxInputStream::Peek()
847 {
848 char c;
849 Read(&c, sizeof(c));
850 if (m_lasterror == wxSTREAM_NO_ERROR)
851 {
852 Ungetch(c);
853 return c;
854 }
855
856 return 0;
857 }
858
859 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
860 {
861 char buf[BUF_TEMP_SIZE];
862
863 for ( ;; )
864 {
865 size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
866 if ( !bytes_read )
867 break;
868
869 if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read )
870 break;
871 }
872
873 return *this;
874 }
875
876 wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
877 {
878 // RR: This code is duplicated in wxBufferedInputStream. This is
879 // not really a good design, but buffered stream are different
880 // from all other in that they handle two stream-related objects,
881 // the stream buffer and parent stream.
882
883 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
884 if (m_lasterror==wxSTREAM_EOF)
885 m_lasterror=wxSTREAM_NO_ERROR;
886
887 /* RR: A call to SeekI() will automatically invalidate any previous
888 call to Ungetch(), otherwise it would be possible to SeekI() to
889 one position, unread some bytes there, SeekI() to another position
890 and the data would be corrupted.
891
892 GRG: Could add code here to try to navigate within the wback
893 buffer if possible, but is it really needed? It would only work
894 when seeking in wxFromCurrent mode, else it would invalidate
895 anyway... */
896
897 if (m_wback)
898 {
899 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
900
901 free(m_wback);
902 m_wback = NULL;
903 m_wbacksize = 0;
904 m_wbackcur = 0;
905 }
906
907 return OnSysSeek(pos, mode);
908 }
909
910 wxFileOffset wxInputStream::TellI() const
911 {
912 wxFileOffset pos = OnSysTell();
913
914 if (pos != wxInvalidOffset)
915 pos -= (m_wbacksize - m_wbackcur);
916
917 return pos;
918 }
919
920
921 // ----------------------------------------------------------------------------
922 // wxOutputStream
923 // ----------------------------------------------------------------------------
924
925 wxOutputStream::wxOutputStream()
926 {
927 }
928
929 wxOutputStream::~wxOutputStream()
930 {
931 }
932
933 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
934 size_t WXUNUSED(bufsize))
935 {
936 return 0;
937 }
938
939 void wxOutputStream::PutC(char c)
940 {
941 Write(&c, sizeof(c));
942 }
943
944 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
945 {
946 m_lastcount = OnSysWrite(buffer, size);
947 return *this;
948 }
949
950 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
951 {
952 stream_in.Read(*this);
953 return *this;
954 }
955
956 wxFileOffset wxOutputStream::TellO() const
957 {
958 return OnSysTell();
959 }
960
961 wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
962 {
963 return OnSysSeek(pos, mode);
964 }
965
966 void wxOutputStream::Sync()
967 {
968 }
969
970
971 // ----------------------------------------------------------------------------
972 // wxCountingOutputStream
973 // ----------------------------------------------------------------------------
974
975 wxCountingOutputStream::wxCountingOutputStream ()
976 {
977 m_currentPos = 0;
978 }
979
980 wxFileOffset wxCountingOutputStream::GetLength() const
981 {
982 return m_lastcount;
983 }
984
985 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
986 size_t size)
987 {
988 m_currentPos += size;
989 if (m_currentPos > m_lastcount)
990 m_lastcount = m_currentPos;
991
992 return m_currentPos;
993 }
994
995 wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
996 {
997 switch ( mode )
998 {
999 case wxFromStart:
1000 m_currentPos = pos;
1001 break;
1002
1003 case wxFromEnd:
1004 m_currentPos = m_lastcount + pos;
1005 break;
1006
1007 case wxFromCurrent:
1008 m_currentPos += pos;
1009 break;
1010
1011 default:
1012 wxFAIL_MSG( _T("invalid seek mode") );
1013 return wxInvalidOffset;
1014 }
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
1273 // wxUSE_STREAMS