]> git.saurik.com Git - wxWidgets.git/blob - src/common/stream.cpp
8061deeb7bdf0482ca0c40a94cdcbfa3bc714b9e
[wxWidgets.git] / src / common / stream.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/stream.cpp
3 // Purpose: wxStream base classes
4 // Author: Guilhem Lavaux
5 // Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory,
6 // general code review
7 // Created: 11/07/98
8 // RCS-ID: $Id$
9 // Copyright: (c) Guilhem Lavaux
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #ifndef WX_PRECOMP
29 #include "wx/defs.h"
30 #endif
31
32 #if wxUSE_STREAMS
33
34 #include <ctype.h>
35 #include "wx/stream.h"
36 #include "wx/datstrm.h"
37 #include "wx/textfile.h"
38 #include "wx/log.h"
39
40 // ----------------------------------------------------------------------------
41 // constants
42 // ----------------------------------------------------------------------------
43
44 // the temporary buffer size used when copying from stream to stream
45 #define BUF_TEMP_SIZE 4096
46
47 // ============================================================================
48 // implementation
49 // ============================================================================
50
51 // ----------------------------------------------------------------------------
52 // wxStreamBuffer
53 // ----------------------------------------------------------------------------
54
55 void wxStreamBuffer::SetError(wxStreamError err)
56 {
57 if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR )
58 m_stream->m_lasterror = err;
59 }
60
61 void wxStreamBuffer::InitBuffer()
62 {
63 m_buffer_start =
64 m_buffer_end =
65 m_buffer_pos = NULL;
66 m_buffer_size = 0;
67
68 // if we are going to allocate the buffer, we should free it later as well
69 m_destroybuf = true;
70 }
71
72 void wxStreamBuffer::Init()
73 {
74 InitBuffer();
75
76 m_fixed = true;
77 }
78
79 wxStreamBuffer::wxStreamBuffer(BufMode mode)
80 {
81 Init();
82
83 m_stream = NULL;
84 m_mode = mode;
85
86 m_flushable = false;
87 }
88
89 wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
90 {
91 Init();
92
93 m_stream = &stream;
94 m_mode = mode;
95
96 m_flushable = true;
97 }
98
99 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
100 {
101 // doing this has big chances to lead to a crash when the source buffer is
102 // destroyed (otherwise assume the caller knows what he does)
103 wxASSERT_MSG( !buffer.m_destroybuf,
104 _T("it's a bad idea to copy this buffer") );
105
106 m_buffer_start = buffer.m_buffer_start;
107 m_buffer_end = buffer.m_buffer_end;
108 m_buffer_pos = buffer.m_buffer_pos;
109 m_buffer_size = buffer.m_buffer_size;
110 m_fixed = buffer.m_fixed;
111 m_flushable = buffer.m_flushable;
112 m_stream = buffer.m_stream;
113 m_mode = buffer.m_mode;
114 m_destroybuf = false;
115 }
116
117 void wxStreamBuffer::FreeBuffer()
118 {
119 if ( m_destroybuf )
120 free(m_buffer_start);
121 }
122
123 wxStreamBuffer::~wxStreamBuffer()
124 {
125 FreeBuffer();
126 }
127
128 wxInputStream *wxStreamBuffer::GetInputStream() const
129 {
130 return m_mode == write ? NULL : (wxInputStream *)m_stream;
131 }
132
133 wxOutputStream *wxStreamBuffer::GetOutputStream() const
134 {
135 return m_mode == read ? NULL : (wxOutputStream *)m_stream;
136 }
137
138 void wxStreamBuffer::SetBufferIO(void *buffer_start,
139 void *buffer_end,
140 bool takeOwnership)
141 {
142 SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start,
143 takeOwnership);
144 }
145
146 void wxStreamBuffer::SetBufferIO(void *start,
147 size_t len,
148 bool takeOwnership)
149 {
150 // start by freeing the old buffer
151 FreeBuffer();
152
153 m_buffer_start = (char *)start;
154 m_buffer_end = m_buffer_start + len;
155
156 m_buffer_size = len;
157
158 // if we own it, we free it
159 m_destroybuf = takeOwnership;
160
161 ResetBuffer();
162 }
163
164 void wxStreamBuffer::SetBufferIO(size_t bufsize)
165 {
166 // start by freeing the old buffer
167 FreeBuffer();
168
169 if ( bufsize )
170 {
171 SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */);
172 }
173 else // no buffer size => no buffer
174 {
175 InitBuffer();
176 }
177 }
178
179 void wxStreamBuffer::ResetBuffer()
180 {
181 if ( m_stream )
182 {
183 m_stream->Reset();
184 m_stream->m_lastcount = 0;
185 }
186
187 m_buffer_pos = m_mode == read && m_flushable
188 ? m_buffer_end
189 : m_buffer_start;
190 }
191
192 // fill the buffer with as much data as possible (only for read buffers)
193 bool wxStreamBuffer::FillBuffer()
194 {
195 wxInputStream *inStream = GetInputStream();
196
197 // It's legal to have no stream, so we don't complain about it just return false
198 if ( !inStream )
199 return false;
200
201 size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
202 if ( !count )
203 return false;
204
205 m_buffer_end = m_buffer_start + count;
206 m_buffer_pos = m_buffer_start;
207
208 return true;
209 }
210
211 // write the buffer contents to the stream (only for write buffers)
212 bool wxStreamBuffer::FlushBuffer()
213 {
214 wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") );
215
216 // FIXME: what is this check for? (VZ)
217 if ( m_buffer_pos == m_buffer_start )
218 return false;
219
220 wxOutputStream *outStream = GetOutputStream();
221
222 wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") );
223
224 size_t current = m_buffer_pos - m_buffer_start;
225 size_t count = outStream->OnSysWrite(m_buffer_start, current);
226 if ( count != current )
227 return false;
228
229 m_buffer_pos = m_buffer_start;
230
231 return true;
232 }
233
234 size_t wxStreamBuffer::GetDataLeft()
235 {
236 /* Why is this done? RR. */
237 if ( m_buffer_pos == m_buffer_end && m_flushable)
238 FillBuffer();
239
240 return GetBytesLeft();
241 }
242
243 // copy up to size bytes from our buffer into the provided one
244 void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
245 {
246 // don't get more bytes than left in the buffer
247 size_t left = GetBytesLeft();
248
249 if ( size > left )
250 size = left;
251
252 memcpy(buffer, m_buffer_pos, size);
253 m_buffer_pos += size;
254 }
255
256 // copy the contents of the provided buffer into this one
257 void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
258 {
259 size_t left = GetBytesLeft();
260
261 if ( size > left )
262 {
263 if ( m_fixed )
264 {
265 // we can't realloc the buffer, so just copy what we can
266 size = left;
267 }
268 else // !m_fixed
269 {
270 // realloc the buffer to have enough space for the data
271 size_t delta = m_buffer_pos - m_buffer_start;
272
273 char *startOld = m_buffer_start;
274 m_buffer_size += size;
275 m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size);
276 if ( !m_buffer_start )
277 {
278 // don't leak memory if realloc() failed
279 m_buffer_start = startOld;
280 m_buffer_size -= size;
281
282 // what else can we do?
283 return;
284 }
285
286 // adjust the pointers invalidated by realloc()
287 m_buffer_pos = m_buffer_start + delta;
288 m_buffer_end = m_buffer_start + m_buffer_size;
289 }
290 }
291
292 memcpy(m_buffer_pos, buffer, size);
293 m_buffer_pos += size;
294 }
295
296 void wxStreamBuffer::PutChar(char c)
297 {
298 wxOutputStream *outStream = GetOutputStream();
299
300 wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") );
301
302 // if we don't have buffer at all, just forward this call to the stream,
303 if ( !HasBuffer() )
304 {
305 outStream->OnSysWrite(&c, sizeof(c));
306 }
307 else
308 {
309 // otherwise check we have enough space left
310 if ( !GetDataLeft() && !FlushBuffer() )
311 {
312 // we don't
313 SetError(wxSTREAM_WRITE_ERROR);
314 }
315 else
316 {
317 PutToBuffer(&c, sizeof(c));
318 m_stream->m_lastcount = 1;
319 }
320 }
321 }
322
323 char wxStreamBuffer::Peek()
324 {
325 wxCHECK_MSG( m_stream && HasBuffer(), 0,
326 _T("should have the stream and the buffer in wxStreamBuffer") );
327
328 if ( !GetDataLeft() )
329 {
330 SetError(wxSTREAM_READ_ERROR);
331 return 0;
332 }
333
334 char c;
335 GetFromBuffer(&c, sizeof(c));
336 m_buffer_pos--;
337
338 return c;
339 }
340
341 char wxStreamBuffer::GetChar()
342 {
343 wxInputStream *inStream = GetInputStream();
344
345 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
346
347 char c;
348 if ( !HasBuffer() )
349 {
350 inStream->OnSysRead(&c, sizeof(c));
351 }
352 else
353 {
354 if ( !GetDataLeft() )
355 {
356 SetError(wxSTREAM_READ_ERROR);
357 c = 0;
358 }
359 else
360 {
361 GetFromBuffer(&c, sizeof(c));
362 m_stream->m_lastcount = 1;
363 }
364 }
365
366 return c;
367 }
368
369 size_t wxStreamBuffer::Read(void *buffer, size_t size)
370 {
371 // lasterror is reset before all new IO calls
372 if ( m_stream )
373 m_stream->Reset();
374
375 size_t readBytes;
376 if ( !HasBuffer() )
377 {
378 wxInputStream *inStream = GetInputStream();
379
380 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
381
382 readBytes = inStream->OnSysRead(buffer, size);
383 }
384 else // we have a buffer, use it
385 {
386 size_t orig_size = size;
387
388 while ( size > 0 )
389 {
390 size_t left = GetDataLeft();
391
392 // if the requested number of bytes if greater than the buffer
393 // size, read data in chunks
394 if ( size > left )
395 {
396 GetFromBuffer(buffer, left);
397 size -= left;
398 buffer = (char *)buffer + left;
399
400 if ( !FillBuffer() )
401 {
402 SetError(wxSTREAM_EOF);
403 break;
404 }
405 }
406 else // otherwise just do it in one gulp
407 {
408 GetFromBuffer(buffer, size);
409 size = 0;
410 }
411 }
412
413 readBytes = orig_size - size;
414 }
415
416 if ( m_stream )
417 m_stream->m_lastcount = readBytes;
418
419 return readBytes;
420 }
421
422 // this should really be called "Copy()"
423 size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
424 {
425 wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") );
426
427 char buf[BUF_TEMP_SIZE];
428 size_t nRead,
429 total = 0;
430
431 do
432 {
433 nRead = Read(buf, WXSIZEOF(buf));
434 if ( nRead )
435 {
436 nRead = dbuf->Write(buf, nRead);
437 total += nRead;
438 }
439 }
440 while ( nRead );
441
442 return total;
443 }
444
445 size_t wxStreamBuffer::Write(const void *buffer, size_t size)
446 {
447 if (m_stream)
448 {
449 // lasterror is reset before all new IO calls
450 m_stream->Reset();
451 }
452
453 size_t ret;
454
455 if ( !HasBuffer() && m_fixed )
456 {
457 wxOutputStream *outStream = GetOutputStream();
458
459 wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
460
461 // no buffer, just forward the call to the stream
462 ret = outStream->OnSysWrite(buffer, size);
463 }
464 else // we [may] have a buffer, use it
465 {
466 size_t orig_size = size;
467
468 while ( size > 0 )
469 {
470 size_t left = GetBytesLeft();
471
472 // if the buffer is too large to fit in the stream buffer, split
473 // it in smaller parts
474 //
475 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
476 // we always go to the second case.
477 //
478 // FIXME: fine, but if it fails we should (re)try writing it by
479 // chunks as this will (hopefully) always work (VZ)
480
481 if ( size > left && m_fixed )
482 {
483 PutToBuffer(buffer, left);
484 size -= left;
485 buffer = (char *)buffer + left;
486
487 if ( !FlushBuffer() )
488 {
489 SetError(wxSTREAM_WRITE_ERROR);
490
491 break;
492 }
493
494 m_buffer_pos = m_buffer_start;
495 }
496 else // we can do it in one gulp
497 {
498 PutToBuffer(buffer, size);
499 size = 0;
500 }
501 }
502
503 ret = orig_size - size;
504 }
505
506 if (m_stream)
507 {
508 // i am not entirely sure what we do this for
509 m_stream->m_lastcount = ret;
510 }
511
512 return ret;
513 }
514
515 size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
516 {
517 wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") );
518 wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") );
519
520 char buf[BUF_TEMP_SIZE];
521 size_t nWrite,
522 total = 0;
523
524 do
525 {
526 size_t nRead = sbuf->Read(buf, WXSIZEOF(buf));
527 if ( nRead )
528 {
529 nWrite = Write(buf, nRead);
530 if ( nWrite < nRead )
531 {
532 // put back data we couldn't copy
533 wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream();
534
535 in_stream->Ungetch(buf + nWrite, nRead - nWrite);
536 }
537
538 total += nWrite;
539 }
540 else
541 {
542 nWrite = 0;
543 }
544 }
545 while ( nWrite == WXSIZEOF(buf) );
546
547 return total;
548 }
549
550 wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode)
551 {
552 wxFileOffset ret_off, diff;
553
554 wxFileOffset last_access = GetLastAccess();
555
556 if ( !m_flushable )
557 {
558 switch (mode)
559 {
560 case wxFromStart:
561 diff = pos;
562 break;
563
564 case wxFromCurrent:
565 diff = pos + GetIntPosition();
566 break;
567
568 case wxFromEnd:
569 diff = pos + last_access;
570 break;
571
572 default:
573 wxFAIL_MSG( _T("invalid seek mode") );
574
575 return wxInvalidOffset;
576 }
577 if (diff < 0 || diff > last_access)
578 return wxInvalidOffset;
579 size_t int_diff = (size_t)diff;
580 wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
581 SetIntPosition(int_diff);
582 return diff;
583 }
584
585 switch ( mode )
586 {
587 case wxFromStart:
588 // We'll try to compute an internal position later ...
589 ret_off = m_stream->OnSysSeek(pos, wxFromStart);
590 ResetBuffer();
591 return ret_off;
592
593 case wxFromCurrent:
594 diff = pos + GetIntPosition();
595
596 if ( (diff > last_access) || (diff < 0) )
597 {
598 // We must take into account the fact that we have read
599 // something previously.
600 ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
601 ResetBuffer();
602 return ret_off;
603 }
604 else
605 {
606 size_t int_diff = (size_t)diff;
607 wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
608 SetIntPosition(int_diff);
609 return pos;
610 }
611
612 case wxFromEnd:
613 // Hard to compute: always seek to the requested position.
614 ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
615 ResetBuffer();
616 return ret_off;
617 }
618
619 return wxInvalidOffset;
620 }
621
622 wxFileOffset wxStreamBuffer::Tell() const
623 {
624 wxFileOffset pos;
625
626 // ask the stream for position if we have a real one
627 if ( m_stream )
628 {
629 pos = m_stream->OnSysTell();
630 if ( pos == wxInvalidOffset )
631 return wxInvalidOffset;
632 }
633 else // no associated stream
634 {
635 pos = 0;
636 }
637
638 pos += GetIntPosition();
639
640 if ( m_mode == read && m_flushable )
641 pos -= GetLastAccess();
642
643 return pos;
644 }
645
646 // ----------------------------------------------------------------------------
647 // wxStreamBase
648 // ----------------------------------------------------------------------------
649
650 wxStreamBase::wxStreamBase()
651 {
652 m_lasterror = wxSTREAM_NO_ERROR;
653 m_lastcount = 0;
654 }
655
656 wxStreamBase::~wxStreamBase()
657 {
658 }
659
660 size_t wxStreamBase::GetSize() const
661 {
662 wxFileOffset length = GetLength();
663 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 ssize_t new_pos = (ssize_t)pos;
998
999 switch ( mode )
1000 {
1001 case wxFromStart:
1002 wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") );
1003 break;
1004
1005 case wxFromEnd:
1006 new_pos = m_lastcount + new_pos;
1007 wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") );
1008 break;
1009
1010 case wxFromCurrent:
1011 new_pos = m_currentPos + new_pos;
1012 wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") );
1013 break;
1014
1015 default:
1016 wxFAIL_MSG( _T("invalid seek mode") );
1017 return wxInvalidOffset;
1018 }
1019
1020 m_currentPos = new_pos;
1021
1022 if (m_currentPos > m_lastcount)
1023 m_lastcount = m_currentPos;
1024
1025 return m_currentPos;
1026 }
1027
1028 wxFileOffset wxCountingOutputStream::OnSysTell() const
1029 {
1030 return m_currentPos;
1031 }
1032
1033 // ----------------------------------------------------------------------------
1034 // wxFilterInputStream
1035 // ----------------------------------------------------------------------------
1036
1037 wxFilterInputStream::wxFilterInputStream()
1038 {
1039 m_parent_i_stream = NULL;
1040 }
1041
1042 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
1043 {
1044 m_parent_i_stream = &stream;
1045 }
1046
1047 wxFilterInputStream::~wxFilterInputStream()
1048 {
1049 }
1050
1051 // ----------------------------------------------------------------------------
1052 // wxFilterOutputStream
1053 // ----------------------------------------------------------------------------
1054
1055 wxFilterOutputStream::wxFilterOutputStream()
1056 {
1057 m_parent_o_stream = NULL;
1058 }
1059
1060 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
1061 {
1062 m_parent_o_stream = &stream;
1063 }
1064
1065 wxFilterOutputStream::~wxFilterOutputStream()
1066 {
1067 }
1068
1069 // ----------------------------------------------------------------------------
1070 // wxBufferedInputStream
1071 // ----------------------------------------------------------------------------
1072
1073 wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1074 wxStreamBuffer *buffer)
1075 : wxFilterInputStream(s)
1076 {
1077 if ( buffer )
1078 {
1079 // use the buffer provided by the user
1080 m_i_streambuf = buffer;
1081 }
1082 else // create a default buffer
1083 {
1084 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
1085
1086 m_i_streambuf->SetBufferIO(1024);
1087 }
1088 }
1089
1090 wxBufferedInputStream::~wxBufferedInputStream()
1091 {
1092 m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(),
1093 wxFromCurrent);
1094
1095 delete m_i_streambuf;
1096 }
1097
1098 char wxBufferedInputStream::Peek()
1099 {
1100 return m_i_streambuf->Peek();
1101 }
1102
1103 wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1104 {
1105 // reset the error flag
1106 Reset();
1107
1108 // first read from the already cached data
1109 m_lastcount = GetWBack(buf, size);
1110
1111 // do we have to read anything more?
1112 if ( m_lastcount < size )
1113 {
1114 size -= m_lastcount;
1115 buf = (char *)buf + m_lastcount;
1116
1117 // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
1118 // so save it
1119 size_t countOld = m_lastcount;
1120
1121 m_i_streambuf->Read(buf, size);
1122
1123 m_lastcount += countOld;
1124 }
1125
1126 return *this;
1127 }
1128
1129 wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
1130 {
1131 // RR: Look at wxInputStream for comments.
1132
1133 if (m_lasterror==wxSTREAM_EOF)
1134 Reset();
1135
1136 if (m_wback)
1137 {
1138 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1139
1140 free(m_wback);
1141 m_wback = NULL;
1142 m_wbacksize = 0;
1143 m_wbackcur = 0;
1144 }
1145
1146 return m_i_streambuf->Seek(pos, mode);
1147 }
1148
1149 wxFileOffset wxBufferedInputStream::TellI() const
1150 {
1151 wxFileOffset pos = m_i_streambuf->Tell();
1152
1153 if (pos != wxInvalidOffset)
1154 pos -= (m_wbacksize - m_wbackcur);
1155
1156 return pos;
1157 }
1158
1159 size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
1160 {
1161 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
1162 }
1163
1164 wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1165 {
1166 return m_parent_i_stream->SeekI(seek, mode);
1167 }
1168
1169 wxFileOffset wxBufferedInputStream::OnSysTell() const
1170 {
1171 return m_parent_i_stream->TellI();
1172 }
1173
1174 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1175 {
1176 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1177
1178 delete m_i_streambuf;
1179 m_i_streambuf = buffer;
1180 }
1181
1182 // ----------------------------------------------------------------------------
1183 // wxBufferedOutputStream
1184 // ----------------------------------------------------------------------------
1185
1186 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1187 wxStreamBuffer *buffer)
1188 : wxFilterOutputStream(s)
1189 {
1190 if ( buffer )
1191 {
1192 m_o_streambuf = buffer;
1193 }
1194 else // create a default one
1195 {
1196 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1197
1198 m_o_streambuf->SetBufferIO(1024);
1199 }
1200 }
1201
1202 wxBufferedOutputStream::~wxBufferedOutputStream()
1203 {
1204 Sync();
1205 delete m_o_streambuf;
1206 }
1207
1208 bool wxBufferedOutputStream::Close()
1209 {
1210 Sync();
1211 return IsOk();
1212 }
1213
1214
1215 wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
1216 {
1217 m_lastcount = 0;
1218 m_o_streambuf->Write(buffer, size);
1219 return *this;
1220 }
1221
1222 wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
1223 {
1224 Sync();
1225 return m_o_streambuf->Seek(pos, mode);
1226 }
1227
1228 wxFileOffset wxBufferedOutputStream::TellO() const
1229 {
1230 return m_o_streambuf->Tell();
1231 }
1232
1233 void wxBufferedOutputStream::Sync()
1234 {
1235 m_o_streambuf->FlushBuffer();
1236 m_parent_o_stream->Sync();
1237 }
1238
1239 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
1240 {
1241 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
1242 }
1243
1244 wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1245 {
1246 return m_parent_o_stream->SeekO(seek, mode);
1247 }
1248
1249 wxFileOffset wxBufferedOutputStream::OnSysTell() const
1250 {
1251 return m_parent_o_stream->TellO();
1252 }
1253
1254 wxFileOffset wxBufferedOutputStream::GetLength() const
1255 {
1256 return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition();
1257 }
1258
1259 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1260 {
1261 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1262
1263 delete m_o_streambuf;
1264 m_o_streambuf = buffer;
1265 }
1266
1267 // ----------------------------------------------------------------------------
1268 // Some IOManip function
1269 // ----------------------------------------------------------------------------
1270
1271 wxOutputStream& wxEndL(wxOutputStream& stream)
1272 {
1273 static const wxChar *eol = wxTextFile::GetEOL();
1274
1275 return stream.Write(eol, wxStrlen(eol));
1276 }
1277
1278 #endif // wxUSE_STREAMS