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