]> git.saurik.com Git - wxWidgets.git/blob - src/common/stream.cpp
fix recently introduced memory leak of m_conv (bug 1466559)
[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 {
121 free(m_buffer_start);
122 m_buffer_start = NULL;
123 }
124 }
125
126 wxStreamBuffer::~wxStreamBuffer()
127 {
128 FreeBuffer();
129 }
130
131 wxInputStream *wxStreamBuffer::GetInputStream() const
132 {
133 return m_mode == write ? NULL : (wxInputStream *)m_stream;
134 }
135
136 wxOutputStream *wxStreamBuffer::GetOutputStream() const
137 {
138 return m_mode == read ? NULL : (wxOutputStream *)m_stream;
139 }
140
141 void wxStreamBuffer::SetBufferIO(void *buffer_start,
142 void *buffer_end,
143 bool takeOwnership)
144 {
145 SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start,
146 takeOwnership);
147 }
148
149 void wxStreamBuffer::SetBufferIO(void *start,
150 size_t len,
151 bool takeOwnership)
152 {
153 // start by freeing the old buffer
154 FreeBuffer();
155
156 m_buffer_start = (char *)start;
157 m_buffer_end = m_buffer_start + len;
158
159 m_buffer_size = len;
160
161 // if we own it, we free it
162 m_destroybuf = takeOwnership;
163
164 ResetBuffer();
165 }
166
167 void wxStreamBuffer::SetBufferIO(size_t bufsize)
168 {
169 if ( bufsize )
170 {
171 // this will free the old buffer and allocate the new one
172 SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */);
173 }
174 else // no buffer size => no buffer
175 {
176 // still free the old one
177 FreeBuffer();
178 InitBuffer();
179 }
180 }
181
182 void wxStreamBuffer::ResetBuffer()
183 {
184 if ( m_stream )
185 {
186 m_stream->Reset();
187 m_stream->m_lastcount = 0;
188 }
189
190 m_buffer_pos = m_mode == read && m_flushable
191 ? m_buffer_end
192 : m_buffer_start;
193 }
194
195 // fill the buffer with as much data as possible (only for read buffers)
196 bool wxStreamBuffer::FillBuffer()
197 {
198 wxInputStream *inStream = GetInputStream();
199
200 // It's legal to have no stream, so we don't complain about it just return false
201 if ( !inStream )
202 return false;
203
204 size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
205 if ( !count )
206 return false;
207
208 m_buffer_end = m_buffer_start + count;
209 m_buffer_pos = m_buffer_start;
210
211 return true;
212 }
213
214 // write the buffer contents to the stream (only for write buffers)
215 bool wxStreamBuffer::FlushBuffer()
216 {
217 wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") );
218
219 // FIXME: what is this check for? (VZ)
220 if ( m_buffer_pos == m_buffer_start )
221 return false;
222
223 wxOutputStream *outStream = GetOutputStream();
224
225 wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") );
226
227 size_t current = m_buffer_pos - m_buffer_start;
228 size_t count = outStream->OnSysWrite(m_buffer_start, current);
229 if ( count != current )
230 return false;
231
232 m_buffer_pos = m_buffer_start;
233
234 return true;
235 }
236
237 size_t wxStreamBuffer::GetDataLeft()
238 {
239 /* Why is this done? RR. */
240 if ( m_buffer_pos == m_buffer_end && m_flushable)
241 FillBuffer();
242
243 return GetBytesLeft();
244 }
245
246 // copy up to size bytes from our buffer into the provided one
247 void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
248 {
249 // don't get more bytes than left in the buffer
250 size_t left = GetBytesLeft();
251
252 if ( size > left )
253 size = left;
254
255 memcpy(buffer, m_buffer_pos, size);
256 m_buffer_pos += size;
257 }
258
259 // copy the contents of the provided buffer into this one
260 void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
261 {
262 size_t left = GetBytesLeft();
263
264 if ( size > left )
265 {
266 if ( m_fixed )
267 {
268 // we can't realloc the buffer, so just copy what we can
269 size = left;
270 }
271 else // !m_fixed
272 {
273 // realloc the buffer to have enough space for the data
274 size_t delta = m_buffer_pos - m_buffer_start;
275
276 char *startOld = m_buffer_start;
277 m_buffer_size += size;
278 m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size);
279 if ( !m_buffer_start )
280 {
281 // don't leak memory if realloc() failed
282 m_buffer_start = startOld;
283 m_buffer_size -= size;
284
285 // what else can we do?
286 return;
287 }
288
289 // adjust the pointers invalidated by realloc()
290 m_buffer_pos = m_buffer_start + delta;
291 m_buffer_end = m_buffer_start + m_buffer_size;
292 }
293 }
294
295 memcpy(m_buffer_pos, buffer, size);
296 m_buffer_pos += size;
297 }
298
299 void wxStreamBuffer::PutChar(char c)
300 {
301 wxOutputStream *outStream = GetOutputStream();
302
303 wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") );
304
305 // if we don't have buffer at all, just forward this call to the stream,
306 if ( !HasBuffer() )
307 {
308 outStream->OnSysWrite(&c, sizeof(c));
309 }
310 else
311 {
312 // otherwise check we have enough space left
313 if ( !GetDataLeft() && !FlushBuffer() )
314 {
315 // we don't
316 SetError(wxSTREAM_WRITE_ERROR);
317 }
318 else
319 {
320 PutToBuffer(&c, sizeof(c));
321 m_stream->m_lastcount = 1;
322 }
323 }
324 }
325
326 char wxStreamBuffer::Peek()
327 {
328 wxCHECK_MSG( m_stream && HasBuffer(), 0,
329 _T("should have the stream and the buffer in wxStreamBuffer") );
330
331 if ( !GetDataLeft() )
332 {
333 SetError(wxSTREAM_READ_ERROR);
334 return 0;
335 }
336
337 char c;
338 GetFromBuffer(&c, sizeof(c));
339 m_buffer_pos--;
340
341 return c;
342 }
343
344 char wxStreamBuffer::GetChar()
345 {
346 wxInputStream *inStream = GetInputStream();
347
348 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
349
350 char c;
351 if ( !HasBuffer() )
352 {
353 inStream->OnSysRead(&c, sizeof(c));
354 }
355 else
356 {
357 if ( !GetDataLeft() )
358 {
359 SetError(wxSTREAM_READ_ERROR);
360 c = 0;
361 }
362 else
363 {
364 GetFromBuffer(&c, sizeof(c));
365 m_stream->m_lastcount = 1;
366 }
367 }
368
369 return c;
370 }
371
372 size_t wxStreamBuffer::Read(void *buffer, size_t size)
373 {
374 // lasterror is reset before all new IO calls
375 if ( m_stream )
376 m_stream->Reset();
377
378 size_t readBytes;
379 if ( !HasBuffer() )
380 {
381 wxInputStream *inStream = GetInputStream();
382
383 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
384
385 readBytes = inStream->OnSysRead(buffer, size);
386 }
387 else // we have a buffer, use it
388 {
389 size_t orig_size = size;
390
391 while ( size > 0 )
392 {
393 size_t left = GetDataLeft();
394
395 // if the requested number of bytes if greater than the buffer
396 // size, read data in chunks
397 if ( size > left )
398 {
399 GetFromBuffer(buffer, left);
400 size -= left;
401 buffer = (char *)buffer + left;
402
403 if ( !FillBuffer() )
404 {
405 SetError(wxSTREAM_EOF);
406 break;
407 }
408 }
409 else // otherwise just do it in one gulp
410 {
411 GetFromBuffer(buffer, size);
412 size = 0;
413 }
414 }
415
416 readBytes = orig_size - size;
417 }
418
419 if ( m_stream )
420 m_stream->m_lastcount = readBytes;
421
422 return readBytes;
423 }
424
425 // this should really be called "Copy()"
426 size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
427 {
428 wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") );
429
430 char buf[BUF_TEMP_SIZE];
431 size_t nRead,
432 total = 0;
433
434 do
435 {
436 nRead = Read(buf, WXSIZEOF(buf));
437 if ( nRead )
438 {
439 nRead = dbuf->Write(buf, nRead);
440 total += nRead;
441 }
442 }
443 while ( nRead );
444
445 return total;
446 }
447
448 size_t wxStreamBuffer::Write(const void *buffer, size_t size)
449 {
450 if (m_stream)
451 {
452 // lasterror is reset before all new IO calls
453 m_stream->Reset();
454 }
455
456 size_t ret;
457
458 if ( !HasBuffer() && m_fixed )
459 {
460 wxOutputStream *outStream = GetOutputStream();
461
462 wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
463
464 // no buffer, just forward the call to the stream
465 ret = outStream->OnSysWrite(buffer, size);
466 }
467 else // we [may] have a buffer, use it
468 {
469 size_t orig_size = size;
470
471 while ( size > 0 )
472 {
473 size_t left = GetBytesLeft();
474
475 // if the buffer is too large to fit in the stream buffer, split
476 // it in smaller parts
477 //
478 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
479 // we always go to the second case.
480 //
481 // FIXME: fine, but if it fails we should (re)try writing it by
482 // chunks as this will (hopefully) always work (VZ)
483
484 if ( size > left && m_fixed )
485 {
486 PutToBuffer(buffer, left);
487 size -= left;
488 buffer = (char *)buffer + left;
489
490 if ( !FlushBuffer() )
491 {
492 SetError(wxSTREAM_WRITE_ERROR);
493
494 break;
495 }
496
497 m_buffer_pos = m_buffer_start;
498 }
499 else // we can do it in one gulp
500 {
501 PutToBuffer(buffer, size);
502 size = 0;
503 }
504 }
505
506 ret = orig_size - size;
507 }
508
509 if (m_stream)
510 {
511 // i am not entirely sure what we do this for
512 m_stream->m_lastcount = ret;
513 }
514
515 return ret;
516 }
517
518 size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
519 {
520 wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") );
521 wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") );
522
523 char buf[BUF_TEMP_SIZE];
524 size_t nWrite,
525 total = 0;
526
527 do
528 {
529 size_t nRead = sbuf->Read(buf, WXSIZEOF(buf));
530 if ( nRead )
531 {
532 nWrite = Write(buf, nRead);
533 if ( nWrite < nRead )
534 {
535 // put back data we couldn't copy
536 wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream();
537
538 in_stream->Ungetch(buf + nWrite, nRead - nWrite);
539 }
540
541 total += nWrite;
542 }
543 else
544 {
545 nWrite = 0;
546 }
547 }
548 while ( nWrite == WXSIZEOF(buf) );
549
550 return total;
551 }
552
553 wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode)
554 {
555 wxFileOffset ret_off, diff;
556
557 wxFileOffset last_access = GetLastAccess();
558
559 if ( !m_flushable )
560 {
561 switch (mode)
562 {
563 case wxFromStart:
564 diff = pos;
565 break;
566
567 case wxFromCurrent:
568 diff = pos + GetIntPosition();
569 break;
570
571 case wxFromEnd:
572 diff = pos + last_access;
573 break;
574
575 default:
576 wxFAIL_MSG( _T("invalid seek mode") );
577
578 return wxInvalidOffset;
579 }
580 if (diff < 0 || diff > last_access)
581 return wxInvalidOffset;
582 size_t int_diff = wx_truncate_cast(size_t, diff);
583 wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
584 SetIntPosition(int_diff);
585 return diff;
586 }
587
588 switch ( mode )
589 {
590 case wxFromStart:
591 // We'll try to compute an internal position later ...
592 ret_off = m_stream->OnSysSeek(pos, wxFromStart);
593 ResetBuffer();
594 return ret_off;
595
596 case wxFromCurrent:
597 diff = pos + GetIntPosition();
598
599 if ( (diff > last_access) || (diff < 0) )
600 {
601 // We must take into account the fact that we have read
602 // something previously.
603 ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
604 ResetBuffer();
605 return ret_off;
606 }
607 else
608 {
609 size_t int_diff = wx_truncate_cast(size_t, diff);
610 wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
611 SetIntPosition(int_diff);
612 return pos;
613 }
614
615 case wxFromEnd:
616 // Hard to compute: always seek to the requested position.
617 ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
618 ResetBuffer();
619 return ret_off;
620 }
621
622 return wxInvalidOffset;
623 }
624
625 wxFileOffset wxStreamBuffer::Tell() const
626 {
627 wxFileOffset pos;
628
629 // ask the stream for position if we have a real one
630 if ( m_stream )
631 {
632 pos = m_stream->OnSysTell();
633 if ( pos == wxInvalidOffset )
634 return wxInvalidOffset;
635 }
636 else // no associated stream
637 {
638 pos = 0;
639 }
640
641 pos += GetIntPosition();
642
643 if ( m_mode == read && m_flushable )
644 pos -= GetLastAccess();
645
646 return pos;
647 }
648
649 // ----------------------------------------------------------------------------
650 // wxStreamBase
651 // ----------------------------------------------------------------------------
652
653 wxStreamBase::wxStreamBase()
654 {
655 m_lasterror = wxSTREAM_NO_ERROR;
656 m_lastcount = 0;
657 }
658
659 wxStreamBase::~wxStreamBase()
660 {
661 }
662
663 size_t wxStreamBase::GetSize() const
664 {
665 wxFileOffset length = GetLength();
666 if ( length == wxInvalidOffset )
667 return 0;
668
669 const size_t len = wx_truncate_cast(size_t, length);
670 wxASSERT_MSG( len == length + size_t(0), _T("large files not supported") );
671
672 return len;
673 }
674
675 wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
676 {
677 return wxInvalidOffset;
678 }
679
680 wxFileOffset wxStreamBase::OnSysTell() const
681 {
682 return wxInvalidOffset;
683 }
684
685 // ----------------------------------------------------------------------------
686 // wxInputStream
687 // ----------------------------------------------------------------------------
688
689 wxInputStream::wxInputStream()
690 {
691 m_wback = NULL;
692 m_wbacksize =
693 m_wbackcur = 0;
694 }
695
696 wxInputStream::~wxInputStream()
697 {
698 free(m_wback);
699 }
700
701 bool wxInputStream::CanRead() const
702 {
703 // we don't know if there is anything to read or not and by default we
704 // prefer to be optimistic and try to read data unless we know for sure
705 // there is no more of it
706 return m_lasterror != wxSTREAM_EOF;
707 }
708
709 bool wxInputStream::Eof() const
710 {
711 // the only way the base class can know we're at EOF is when we'd already
712 // tried to read beyond it in which case last error is set accordingly
713 return GetLastError() == wxSTREAM_EOF;
714 }
715
716 char *wxInputStream::AllocSpaceWBack(size_t needed_size)
717 {
718 // get number of bytes left from previous wback buffer
719 size_t toget = m_wbacksize - m_wbackcur;
720
721 // allocate a buffer large enough to hold prev + new data
722 char *temp_b = (char *)malloc(needed_size + toget);
723
724 if (!temp_b)
725 return NULL;
726
727 // copy previous data (and free old buffer) if needed
728 if (m_wback)
729 {
730 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
731 free(m_wback);
732 }
733
734 // done
735 m_wback = temp_b;
736 m_wbackcur = 0;
737 m_wbacksize = needed_size + toget;
738
739 return m_wback;
740 }
741
742 size_t wxInputStream::GetWBack(void *buf, size_t size)
743 {
744 if (!m_wback)
745 return 0;
746
747 // how many bytes do we have in the buffer?
748 size_t toget = m_wbacksize - m_wbackcur;
749
750 if ( size < toget )
751 {
752 // we won't read everything
753 toget = size;
754 }
755
756 // copy the data from the cache
757 memcpy(buf, m_wback + m_wbackcur, toget);
758
759 m_wbackcur += toget;
760 if ( m_wbackcur == m_wbacksize )
761 {
762 // TODO: should we really free it here all the time? maybe keep it?
763 free(m_wback);
764 m_wback = NULL;
765 m_wbacksize = 0;
766 m_wbackcur = 0;
767 }
768
769 // return the number of bytes copied
770 return toget;
771 }
772
773 size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
774 {
775 if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF )
776 {
777 // can't operate on this stream until the error is cleared
778 return 0;
779 }
780
781 char *ptrback = AllocSpaceWBack(bufsize);
782 if (!ptrback)
783 return 0;
784
785 // Eof() shouldn't return true any longer
786 if ( m_lasterror == wxSTREAM_EOF )
787 m_lasterror = wxSTREAM_NO_ERROR;
788
789 memcpy(ptrback, buf, bufsize);
790 return bufsize;
791 }
792
793 bool wxInputStream::Ungetch(char c)
794 {
795 return Ungetch(&c, sizeof(c)) != 0;
796 }
797
798 char wxInputStream::GetC()
799 {
800 char c;
801 Read(&c, sizeof(c));
802 return c;
803 }
804
805 wxInputStream& wxInputStream::Read(void *buf, size_t size)
806 {
807 char *p = (char *)buf;
808 m_lastcount = 0;
809
810 size_t read = GetWBack(buf, size);
811 for ( ;; )
812 {
813 size -= read;
814 m_lastcount += read;
815 p += read;
816
817 if ( !size )
818 {
819 // we read the requested amount of data
820 break;
821 }
822
823 if ( p != buf && !CanRead() )
824 {
825 // we have already read something and we would block in OnSysRead()
826 // now: don't do it but return immediately
827 break;
828 }
829
830 read = OnSysRead(p, size);
831 if ( !read )
832 {
833 // no more data available
834 break;
835 }
836 }
837
838 return *this;
839 }
840
841 char wxInputStream::Peek()
842 {
843 char c;
844 Read(&c, sizeof(c));
845 if (m_lasterror == wxSTREAM_NO_ERROR)
846 {
847 Ungetch(c);
848 return c;
849 }
850
851 return 0;
852 }
853
854 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
855 {
856 char buf[BUF_TEMP_SIZE];
857
858 for ( ;; )
859 {
860 size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
861 if ( !bytes_read )
862 break;
863
864 if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read )
865 break;
866 }
867
868 return *this;
869 }
870
871 wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
872 {
873 // RR: This code is duplicated in wxBufferedInputStream. This is
874 // not really a good design, but buffered stream are different
875 // from all other in that they handle two stream-related objects,
876 // the stream buffer and parent stream.
877
878 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
879 if (m_lasterror==wxSTREAM_EOF)
880 m_lasterror=wxSTREAM_NO_ERROR;
881
882 /* RR: A call to SeekI() will automatically invalidate any previous
883 call to Ungetch(), otherwise it would be possible to SeekI() to
884 one position, unread some bytes there, SeekI() to another position
885 and the data would be corrupted.
886
887 GRG: Could add code here to try to navigate within the wback
888 buffer if possible, but is it really needed? It would only work
889 when seeking in wxFromCurrent mode, else it would invalidate
890 anyway... */
891
892 if (m_wback)
893 {
894 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
895
896 free(m_wback);
897 m_wback = NULL;
898 m_wbacksize = 0;
899 m_wbackcur = 0;
900 }
901
902 return OnSysSeek(pos, mode);
903 }
904
905 wxFileOffset wxInputStream::TellI() const
906 {
907 wxFileOffset pos = OnSysTell();
908
909 if (pos != wxInvalidOffset)
910 pos -= (m_wbacksize - m_wbackcur);
911
912 return pos;
913 }
914
915
916 // ----------------------------------------------------------------------------
917 // wxOutputStream
918 // ----------------------------------------------------------------------------
919
920 wxOutputStream::wxOutputStream()
921 {
922 }
923
924 wxOutputStream::~wxOutputStream()
925 {
926 }
927
928 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
929 size_t WXUNUSED(bufsize))
930 {
931 return 0;
932 }
933
934 void wxOutputStream::PutC(char c)
935 {
936 Write(&c, sizeof(c));
937 }
938
939 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
940 {
941 m_lastcount = OnSysWrite(buffer, size);
942 return *this;
943 }
944
945 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
946 {
947 stream_in.Read(*this);
948 return *this;
949 }
950
951 wxFileOffset wxOutputStream::TellO() const
952 {
953 return OnSysTell();
954 }
955
956 wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
957 {
958 return OnSysSeek(pos, mode);
959 }
960
961 void wxOutputStream::Sync()
962 {
963 }
964
965
966 // ----------------------------------------------------------------------------
967 // wxCountingOutputStream
968 // ----------------------------------------------------------------------------
969
970 wxCountingOutputStream::wxCountingOutputStream ()
971 {
972 m_currentPos = 0;
973 }
974
975 wxFileOffset wxCountingOutputStream::GetLength() const
976 {
977 return m_lastcount;
978 }
979
980 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
981 size_t size)
982 {
983 m_currentPos += size;
984 if (m_currentPos > m_lastcount)
985 m_lastcount = m_currentPos;
986
987 return m_currentPos;
988 }
989
990 wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
991 {
992 ssize_t new_pos = wx_truncate_cast(ssize_t, pos);
993
994 switch ( mode )
995 {
996 case wxFromStart:
997 wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") );
998 break;
999
1000 case wxFromEnd:
1001 new_pos = m_lastcount + new_pos;
1002 wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") );
1003 break;
1004
1005 case wxFromCurrent:
1006 new_pos = m_currentPos + new_pos;
1007 wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") );
1008 break;
1009
1010 default:
1011 wxFAIL_MSG( _T("invalid seek mode") );
1012 return wxInvalidOffset;
1013 }
1014
1015 m_currentPos = new_pos;
1016
1017 if (m_currentPos > m_lastcount)
1018 m_lastcount = m_currentPos;
1019
1020 return m_currentPos;
1021 }
1022
1023 wxFileOffset wxCountingOutputStream::OnSysTell() const
1024 {
1025 return m_currentPos;
1026 }
1027
1028 // ----------------------------------------------------------------------------
1029 // wxFilterInputStream
1030 // ----------------------------------------------------------------------------
1031
1032 wxFilterInputStream::wxFilterInputStream()
1033 {
1034 m_parent_i_stream = NULL;
1035 }
1036
1037 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
1038 {
1039 m_parent_i_stream = &stream;
1040 }
1041
1042 wxFilterInputStream::~wxFilterInputStream()
1043 {
1044 }
1045
1046 // ----------------------------------------------------------------------------
1047 // wxFilterOutputStream
1048 // ----------------------------------------------------------------------------
1049
1050 wxFilterOutputStream::wxFilterOutputStream()
1051 {
1052 m_parent_o_stream = NULL;
1053 }
1054
1055 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
1056 {
1057 m_parent_o_stream = &stream;
1058 }
1059
1060 wxFilterOutputStream::~wxFilterOutputStream()
1061 {
1062 }
1063
1064 // ----------------------------------------------------------------------------
1065 // wxBufferedInputStream
1066 // ----------------------------------------------------------------------------
1067
1068 wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1069 wxStreamBuffer *buffer)
1070 : wxFilterInputStream(s)
1071 {
1072 if ( buffer )
1073 {
1074 // use the buffer provided by the user
1075 m_i_streambuf = buffer;
1076 }
1077 else // create a default buffer
1078 {
1079 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
1080
1081 m_i_streambuf->SetBufferIO(1024);
1082 }
1083 }
1084
1085 wxBufferedInputStream::~wxBufferedInputStream()
1086 {
1087 m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(),
1088 wxFromCurrent);
1089
1090 delete m_i_streambuf;
1091 }
1092
1093 char wxBufferedInputStream::Peek()
1094 {
1095 return m_i_streambuf->Peek();
1096 }
1097
1098 wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1099 {
1100 // reset the error flag
1101 Reset();
1102
1103 // first read from the already cached data
1104 m_lastcount = GetWBack(buf, size);
1105
1106 // do we have to read anything more?
1107 if ( m_lastcount < size )
1108 {
1109 size -= m_lastcount;
1110 buf = (char *)buf + m_lastcount;
1111
1112 // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
1113 // so save it
1114 size_t countOld = m_lastcount;
1115
1116 m_i_streambuf->Read(buf, size);
1117
1118 m_lastcount += countOld;
1119 }
1120
1121 return *this;
1122 }
1123
1124 wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
1125 {
1126 // RR: Look at wxInputStream for comments.
1127
1128 if (m_lasterror==wxSTREAM_EOF)
1129 Reset();
1130
1131 if (m_wback)
1132 {
1133 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1134
1135 free(m_wback);
1136 m_wback = NULL;
1137 m_wbacksize = 0;
1138 m_wbackcur = 0;
1139 }
1140
1141 return m_i_streambuf->Seek(pos, mode);
1142 }
1143
1144 wxFileOffset wxBufferedInputStream::TellI() const
1145 {
1146 wxFileOffset pos = m_i_streambuf->Tell();
1147
1148 if (pos != wxInvalidOffset)
1149 pos -= (m_wbacksize - m_wbackcur);
1150
1151 return pos;
1152 }
1153
1154 size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
1155 {
1156 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
1157 }
1158
1159 wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1160 {
1161 return m_parent_i_stream->SeekI(seek, mode);
1162 }
1163
1164 wxFileOffset wxBufferedInputStream::OnSysTell() const
1165 {
1166 return m_parent_i_stream->TellI();
1167 }
1168
1169 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1170 {
1171 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1172
1173 delete m_i_streambuf;
1174 m_i_streambuf = buffer;
1175 }
1176
1177 // ----------------------------------------------------------------------------
1178 // wxBufferedOutputStream
1179 // ----------------------------------------------------------------------------
1180
1181 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1182 wxStreamBuffer *buffer)
1183 : wxFilterOutputStream(s)
1184 {
1185 if ( buffer )
1186 {
1187 m_o_streambuf = buffer;
1188 }
1189 else // create a default one
1190 {
1191 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1192
1193 m_o_streambuf->SetBufferIO(1024);
1194 }
1195 }
1196
1197 wxBufferedOutputStream::~wxBufferedOutputStream()
1198 {
1199 Sync();
1200 delete m_o_streambuf;
1201 }
1202
1203 bool wxBufferedOutputStream::Close()
1204 {
1205 Sync();
1206 return IsOk();
1207 }
1208
1209
1210 wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
1211 {
1212 m_lastcount = 0;
1213 m_o_streambuf->Write(buffer, size);
1214 return *this;
1215 }
1216
1217 wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
1218 {
1219 Sync();
1220 return m_o_streambuf->Seek(pos, mode);
1221 }
1222
1223 wxFileOffset wxBufferedOutputStream::TellO() const
1224 {
1225 return m_o_streambuf->Tell();
1226 }
1227
1228 void wxBufferedOutputStream::Sync()
1229 {
1230 m_o_streambuf->FlushBuffer();
1231 m_parent_o_stream->Sync();
1232 }
1233
1234 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
1235 {
1236 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
1237 }
1238
1239 wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1240 {
1241 return m_parent_o_stream->SeekO(seek, mode);
1242 }
1243
1244 wxFileOffset wxBufferedOutputStream::OnSysTell() const
1245 {
1246 return m_parent_o_stream->TellO();
1247 }
1248
1249 wxFileOffset wxBufferedOutputStream::GetLength() const
1250 {
1251 return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition();
1252 }
1253
1254 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1255 {
1256 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1257
1258 delete m_o_streambuf;
1259 m_o_streambuf = buffer;
1260 }
1261
1262 // ----------------------------------------------------------------------------
1263 // Some IOManip function
1264 // ----------------------------------------------------------------------------
1265
1266 wxOutputStream& wxEndL(wxOutputStream& stream)
1267 {
1268 static const wxChar *eol = wxTextFile::GetEOL();
1269
1270 return stream.Write(eol, wxStrlen(eol));
1271 }
1272
1273 #endif // wxUSE_STREAMS