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