]>
git.saurik.com Git - wxWidgets.git/blob - 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,
9 // Copyright: (c) Guilhem Lavaux
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 #pragma implementation "stream.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
38 #include "wx/stream.h"
39 #include "wx/datstrm.h"
40 #include "wx/objstrm.h"
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 // the temporary buffer size used when copying from stream to stream
47 #define BUF_TEMP_SIZE 10000
49 // ============================================================================
51 // ============================================================================
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 void wxStreamBuffer::SetError(wxStreamError err
)
59 if ( m_stream
->m_lasterror
== wxStream_NOERROR
)
60 m_stream
->m_lasterror
= err
;
63 void wxStreamBuffer::InitBuffer()
70 // there is nothing to destroy anyhow
74 void wxStreamBuffer::Init()
81 wxStreamBuffer::wxStreamBuffer(wxStreamBase
& stream
, BufMode mode
)
87 m_destroystream
= FALSE
;
90 wxStreamBuffer::wxStreamBuffer(BufMode mode
)
92 m_stream
= new wxStreamBase
;
96 m_destroystream
= TRUE
;
99 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer
& buffer
)
101 // doing this has big chances to lead to a crashwhen the source buffer is
102 // destroyed (otherwise assume the caller knows what he does)
103 wxASSERT_MSG( !buffer
.m_destroybuf
&& !buffer
.m_destroystream
,
104 _T("it's a bad idea to copy this buffer") );
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 m_destroystream
= FALSE
;
118 void wxStreamBuffer::FreeBuffer()
121 free(m_buffer_start
);
124 wxStreamBuffer::~wxStreamBuffer()
128 if ( m_destroystream
)
132 void wxStreamBuffer::SetBufferIO(void *buffer_start
,
136 SetBufferIO(buffer_start
, (char *)buffer_end
- (char *)buffer_start
,
140 void wxStreamBuffer::SetBufferIO(void *start
,
144 // start by freeing the old buffer
147 m_buffer_start
= (char *)start
;
148 m_buffer_end
= m_buffer_start
+ len
;
152 // if we own it, we free it
153 m_destroybuf
= !takeOwnership
;
158 void wxStreamBuffer::SetBufferIO(size_t bufsize
)
160 // start by freeing the old buffer
165 SetBufferIO(malloc(bufsize
), bufsize
, TRUE
/* take ownership */);
167 else // no buffer size => no buffer
173 void wxStreamBuffer::ResetBuffer()
175 wxCHECK_RET( m_stream
, _T("should have a stream in wxStreamBuffer") );
177 m_stream
->m_lasterror
= wxStream_NOERROR
;
178 m_stream
->m_lastcount
= 0;
179 if (m_mode
== read
&& m_flushable
)
180 m_buffer_pos
= m_buffer_end
;
182 m_buffer_pos
= m_buffer_start
;
185 // fill the buffer with as much data as possible (only for read buffers)
186 bool wxStreamBuffer::FillBuffer()
188 wxCHECK_MSG( m_stream
, FALSE
, _T("should have a stream in wxStreamBuffer") );
190 size_t count
= m_stream
->OnSysRead(m_buffer_start
, m_buffer_size
);
194 m_buffer_end
= m_buffer_start
+ count
;
195 m_buffer_pos
= m_buffer_start
;
200 // write the buffer contents to the stream (only for write buffers)
201 bool wxStreamBuffer::FlushBuffer()
203 wxCHECK_MSG( m_flushable
, FALSE
, _T("can't flush this buffer") );
205 // FIXME: what is this check for? (VZ)
206 if ( m_buffer_pos
== m_buffer_start
)
209 wxCHECK_MSG( m_stream
, FALSE
, _T("should have a stream in wxStreamBuffer") );
211 size_t current
= m_buffer_pos
- m_buffer_start
;
212 size_t count
= m_stream
->OnSysWrite(m_buffer_start
, current
);
213 if ( count
!= current
)
216 m_buffer_pos
= m_buffer_start
;
221 size_t wxStreamBuffer::GetDataLeft()
223 /* Why is this done? RR. */
224 if ( m_buffer_pos
== m_buffer_end
&& m_flushable
)
227 return GetBytesLeft();
230 // copy up to size bytes from our buffer into the provided one
231 void wxStreamBuffer::GetFromBuffer(void *buffer
, size_t size
)
233 // don't get more bytes than left in the buffer
234 size_t left
= GetBytesLeft();
239 memcpy(buffer
, m_buffer_pos
, size
);
240 m_buffer_pos
+= size
;
243 // copy the contents of the provided buffer into this one
244 void wxStreamBuffer::PutToBuffer(const void *buffer
, size_t size
)
246 size_t left
= GetBytesLeft();
251 // we can't realloc the buffer, so just copy what we can
256 // realloc the buffer to have enough space for the data
257 size_t delta
= m_buffer_pos
- m_buffer_start
;
259 char *startOld
= m_buffer_start
;
260 m_buffer_size
+= size
;
261 m_buffer_start
= (char *)realloc(m_buffer_start
, m_buffer_size
);
262 if ( !m_buffer_start
)
264 // don't leak memory if realloc() failed
265 m_buffer_start
= startOld
;
266 m_buffer_size
-= size
;
268 // what else can we do?
272 // adjust the pointers invalidated by realloc()
273 m_buffer_pos
= m_buffer_start
+ delta
;
274 m_buffer_end
= m_buffer_start
+ m_buffer_size
;
278 memcpy(m_buffer_pos
, buffer
, size
);
279 m_buffer_pos
+= size
;
282 void wxStreamBuffer::PutChar(char c
)
284 wxCHECK_RET( m_stream
, _T("should have a stream in wxStreamBuffer") );
286 // if we don't have buffer at all, just forward this call to the stream,
289 m_stream
->OnSysWrite(&c
, 1);
293 // otherwise check we have enough space left
294 if ( !GetDataLeft() && !FlushBuffer() )
297 SetError(wxStream_WRITE_ERR
);
302 m_stream
->m_lastcount
= 1;
307 char wxStreamBuffer::Peek()
309 wxCHECK_MSG( m_stream
&& HasBuffer(), 0,
310 _T("should have the stream and the buffer in wxStreamBuffer") );
312 if ( !GetDataLeft() )
314 SetError(wxStream_READ_ERR
);
319 GetFromBuffer(&c
, 1);
325 char wxStreamBuffer::GetChar()
327 wxCHECK_MSG( m_stream
, 0, _T("should have a stream in wxStreamBuffer") );
332 m_stream
->OnSysRead(&c
, 1);
336 if ( !GetDataLeft() )
338 SetError(wxStream_READ_ERR
);
343 GetFromBuffer(&c
, 1);
344 m_stream
->m_lastcount
= 1;
351 size_t wxStreamBuffer::Read(void *buffer
, size_t size
)
353 wxCHECK_MSG( m_stream
, 0, _T("should have a stream in wxStreamBuffer") );
355 wxCHECK_MSG( m_mode
!= write
, 0, _T("can't read from this buffer") );
357 // lasterror is reset before all new IO calls
358 m_stream
->m_lasterror
= wxStream_NOERROR
;
362 m_stream
->m_lastcount
= m_stream
->OnSysRead(buffer
, size
);
364 else // we have a buffer, use it
366 size_t orig_size
= size
;
370 size_t left
= GetDataLeft();
372 // if the requested number of bytes if greater than the buffer
373 // size, read data in chunks
376 GetFromBuffer(buffer
, left
);
378 buffer
= (char *)buffer
+ left
;
382 SetError(wxStream_EOF
);
386 else // otherwise just do it in one gulp
388 GetFromBuffer(buffer
, size
);
393 m_stream
->m_lastcount
= orig_size
- size
;
396 return m_stream
->m_lastcount
;
399 // this should really be called "Copy()"
400 size_t wxStreamBuffer::Read(wxStreamBuffer
*dbuf
)
402 wxCHECK_MSG( m_mode
!= write
, 0, _T("can't read from this buffer") );
404 char buf
[BUF_TEMP_SIZE
];
410 nRead
= Read(dbuf
, WXSIZEOF(buf
));
413 nRead
= dbuf
->Write(buf
, nRead
);
422 size_t wxStreamBuffer::Write(const void *buffer
, size_t size
)
424 wxCHECK_MSG( m_stream
, 0, _T("should have a stream in wxStreamBuffer") );
425 wxCHECK_MSG( m_mode
!= read
, 0, _T("can't write to this buffer") );
427 // lasterror is reset before all new IO calls
428 m_stream
->m_lasterror
= wxStream_NOERROR
;
430 if ( !HasBuffer() && m_fixed
)
432 // no buffer, just forward the call to the stream
433 m_stream
->m_lastcount
= m_stream
->OnSysWrite(buffer
, size
);
435 else // we [may] have a buffer, use it
437 size_t orig_size
= size
;
441 size_t left
= GetBytesLeft();
443 // if the buffer is too large to fit in the stream buffer, split
444 // it in smaller parts
446 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
447 // we always go to the second case.
449 // FIXME: fine, but if it fails we should (re)try writing it by
450 // chunks as this will (hopefully) always work (VZ)
451 if ( size
> left
&& m_fixed
)
453 PutToBuffer(buffer
, left
);
455 buffer
= (char *)buffer
+ left
;
457 if ( !FlushBuffer() )
459 SetError(wxStream_WRITE_ERR
);
464 m_buffer_pos
= m_buffer_start
;
466 else // we can do it in one gulp
468 PutToBuffer(buffer
, size
);
473 m_stream
->m_lastcount
= orig_size
- size
;
476 return m_stream
->m_lastcount
;
479 size_t wxStreamBuffer::Write(wxStreamBuffer
*sbuf
)
481 wxCHECK_MSG( m_mode
!= read
, 0, _T("can't write to this buffer") );
482 wxCHECK_MSG( sbuf
->m_mode
!= write
, 0, _T("can't read from that buffer") );
484 char buf
[BUF_TEMP_SIZE
];
490 size_t nRead
= sbuf
->Read(buf
, WXSIZEOF(buf
));
493 nWrite
= Write(buf
, nRead
);
494 if ( nWrite
< nRead
)
496 // put back data we couldn't copy
497 wxInputStream
*in_stream
= (wxInputStream
*)sbuf
->GetStream();
499 in_stream
->Ungetch(buf
+ nWrite
, nRead
- nWrite
);
509 while ( nWrite
== WXSIZEOF(buf
) );
514 off_t
wxStreamBuffer::Seek(off_t pos
, wxSeekMode mode
)
518 off_t last_access
= GetLastAccess();
529 diff
= pos
+ GetIntPosition();
533 diff
= pos
+ last_access
;
537 wxFAIL_MSG( _T("invalid seek mode") );
539 return wxInvalidOffset
;
541 if (diff
< 0 || diff
> last_access
)
542 return wxInvalidOffset
;
543 SetIntPosition(diff
);
550 // We'll try to compute an internal position later ...
551 ret_off
= m_stream
->OnSysSeek(pos
, wxFromStart
);
556 diff
= pos
+ GetIntPosition();
558 if ( (diff
> last_access
) || (diff
< 0) )
560 // We must take into account the fact that we have read
561 // something previously.
562 ret_off
= m_stream
->OnSysSeek(diff
-last_access
, wxFromCurrent
);
568 SetIntPosition(diff
);
573 // Hard to compute: always seek to the requested position.
574 ret_off
= m_stream
->OnSysSeek(pos
, wxFromEnd
);
579 return wxInvalidOffset
;
582 off_t
wxStreamBuffer::Tell() const
584 off_t pos
= m_stream
->OnSysTell();
585 if ( pos
== wxInvalidOffset
)
586 return wxInvalidOffset
;
588 pos
+= GetIntPosition();
590 if ( m_mode
== read
&& m_flushable
)
591 pos
-= GetLastAccess();
596 // ----------------------------------------------------------------------------
598 // ----------------------------------------------------------------------------
600 wxStreamBase::wxStreamBase()
602 m_lasterror
= wxStream_NOERROR
;
606 wxStreamBase::~wxStreamBase()
610 size_t wxStreamBase::OnSysRead(void *WXUNUSED(buffer
), size_t WXUNUSED(size
))
615 size_t wxStreamBase::OnSysWrite(const void *WXUNUSED(buffer
), size_t WXUNUSED(bufsize
))
620 off_t
wxStreamBase::OnSysSeek(off_t
WXUNUSED(seek
), wxSeekMode
WXUNUSED(mode
))
622 return wxInvalidOffset
;
625 off_t
wxStreamBase::OnSysTell() const
627 return wxInvalidOffset
;
630 // ----------------------------------------------------------------------------
632 // ----------------------------------------------------------------------------
634 wxInputStream::wxInputStream()
641 wxInputStream::~wxInputStream()
646 bool wxInputStream::Eof() const
648 wxInputStream
*self
= wxConstCast(this, wxInputStream
);
652 if ( GetLastError() == wxSTREAM_EOF
)
662 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
664 // get number of bytes left from previous wback buffer
665 size_t toget
= m_wbacksize
- m_wbackcur
;
667 // allocate a buffer large enough to hold prev + new data
668 char *temp_b
= (char *)malloc(needed_size
+ toget
);
673 /* copy previous data (and free old buffer) if needed */
676 memmove(temp_b
+ needed_size
, m_wback
+ m_wbackcur
, toget
);
683 m_wbacksize
= needed_size
+ toget
;
688 size_t wxInputStream::GetWBack(void *buf
, size_t bsize
)
690 size_t toget
= m_wbacksize
-m_wbackcur
;
698 memcpy(buf
, (m_wback
+m_wbackcur
), toget
);
701 if (m_wbackcur
== m_wbacksize
)
712 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
714 char *ptrback
= AllocSpaceWBack(bufsize
);
718 memcpy(ptrback
, buf
, bufsize
);
722 bool wxInputStream::Ungetch(char c
)
724 void *ptrback
= AllocSpaceWBack(1);
728 *(char *)ptrback
= c
;
732 char wxInputStream::GetC()
739 wxInputStream
& wxInputStream::Read(void *buf
, size_t size
)
741 size_t retsize
= GetWBack(buf
, size
);
745 m_lasterror
= wxStream_NOERROR
;
749 buf
= (char *)buf
+ retsize
;
751 m_lastcount
= OnSysRead(buf
, size
) + retsize
;
755 char wxInputStream::Peek()
759 if (m_lasterror
== wxStream_NOERROR
)
768 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
770 char buf
[BUF_TEMP_SIZE
];
771 size_t bytes_read
= BUF_TEMP_SIZE
;
773 while (bytes_read
== BUF_TEMP_SIZE
)
775 bytes_read
= Read(buf
, bytes_read
).LastRead();
776 bytes_read
= stream_out
.Write(buf
, bytes_read
).LastWrite();
781 off_t
wxInputStream::SeekI(off_t pos
, wxSeekMode mode
)
783 /* Should be check and improve, just to remove a slight bug !
784 I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
785 if (m_lasterror
==wxSTREAM_EOF
)
786 m_lasterror
=wxSTREAM_NOERROR
;
788 /* A call to SeekI() will automatically invalidate any previous call
789 to Ungetch(), otherwise it would be possible to SeekI() to one
790 one position, unread some bytes there, SeekI() to another position
791 and the data would be corrupted.
793 GRG: Could add code here to try to navigate within the wback
794 buffer if possible, but is it really needed? It would only work
795 when seeking in wxFromCurrent mode, else it would invalidate
806 return OnSysSeek(pos
, mode
);
809 off_t
wxInputStream::TellI() const
811 /* GRG: Changed to make it compatible with the wback buffer */
812 off_t pos
= OnSysTell();
814 if (pos
!= wxInvalidOffset
)
815 pos
-= (m_wbacksize
- m_wbackcur
);
820 // --------------------
821 // Overloaded operators
822 // --------------------
825 wxInputStream
& wxInputStream::operator>>(wxObject
*& obj
)
827 wxObjectInputStream
obj_s(*this);
828 obj
= obj_s
.LoadObject();
831 #endif // wxUSE_SERIAL
834 // ----------------------------------------------------------------------------
836 // ----------------------------------------------------------------------------
838 wxOutputStream::wxOutputStream()
842 wxOutputStream::~wxOutputStream()
846 void wxOutputStream::PutC(char c
)
851 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
853 m_lastcount
= OnSysWrite(buffer
, size
);
857 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
859 stream_in
.Read(*this);
863 off_t
wxOutputStream::TellO() const
868 off_t
wxOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
870 return OnSysSeek(pos
, mode
);
873 void wxOutputStream::Sync()
878 wxOutputStream
& wxOutputStream::operator<<(wxObject
& obj
)
880 wxObjectOutputStream
obj_s(*this);
881 obj_s
.SaveObject(obj
);
884 #endif // wxUSE_SERIAL
886 // ----------------------------------------------------------------------------
887 // wxCountingOutputStream
888 // ----------------------------------------------------------------------------
890 wxCountingOutputStream::wxCountingOutputStream ()
895 size_t wxCountingOutputStream::GetSize() const
900 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
903 m_currentPos
+= size
;
904 if (m_currentPos
> m_lastcount
)
905 m_lastcount
= m_currentPos
;
910 off_t
wxCountingOutputStream::OnSysSeek(off_t pos
, wxSeekMode mode
)
919 m_currentPos
= m_lastcount
+ pos
;
927 wxFAIL_MSG( _T("invalid seek mode") );
928 return wxInvalidOffset
;
931 if (m_currentPos
> m_lastcount
)
932 m_lastcount
= m_currentPos
;
937 off_t
wxCountingOutputStream::OnSysTell() const
942 // ----------------------------------------------------------------------------
943 // wxFilterInputStream
944 // ----------------------------------------------------------------------------
946 wxFilterInputStream::wxFilterInputStream()
950 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
952 m_parent_i_stream
= &stream
;
955 wxFilterInputStream::~wxFilterInputStream()
959 // ----------------------------------------------------------------------------
960 // wxFilterOutputStream
961 // ----------------------------------------------------------------------------
963 wxFilterOutputStream::wxFilterOutputStream()
967 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
969 m_parent_o_stream
= &stream
;
972 wxFilterOutputStream::~wxFilterOutputStream()
976 // ----------------------------------------------------------------------------
977 // wxBufferedInputStream
978 // ----------------------------------------------------------------------------
980 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& s
)
981 : wxFilterInputStream(s
)
983 m_i_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::read
);
985 m_i_streambuf
->SetBufferIO(1024);
988 wxBufferedInputStream::~wxBufferedInputStream()
990 m_parent_i_stream
->SeekI(-m_i_streambuf
->GetBytesLeft(), wxFromCurrent
);
992 delete m_i_streambuf
;
995 char wxBufferedInputStream::Peek()
997 return m_i_streambuf
->Peek();
1000 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1004 retsize
= GetWBack(buf
, size
);
1005 m_lastcount
= retsize
;
1006 if (retsize
== size
)
1008 m_lasterror
= wxStream_NOERROR
;
1012 buf
= (char *)buf
+ retsize
;
1014 m_i_streambuf
->Read(buf
, size
);
1019 off_t
wxBufferedInputStream::SeekI(off_t pos
, wxSeekMode mode
)
1021 return m_i_streambuf
->Seek(pos
, mode
);
1024 off_t
wxBufferedInputStream::TellI() const
1026 return m_i_streambuf
->Tell();
1029 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1031 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1034 off_t
wxBufferedInputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
1036 return m_parent_i_stream
->SeekI(seek
, mode
);
1039 off_t
wxBufferedInputStream::OnSysTell() const
1041 return m_parent_i_stream
->TellI();
1044 // ----------------------------------------------------------------------------
1045 // wxBufferedOutputStream
1046 // ----------------------------------------------------------------------------
1048 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& s
)
1049 : wxFilterOutputStream(s
)
1051 m_o_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::write
);
1052 m_o_streambuf
->SetBufferIO(1024);
1055 wxBufferedOutputStream::~wxBufferedOutputStream()
1058 delete m_o_streambuf
;
1061 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1064 m_o_streambuf
->Write(buffer
, size
);
1068 off_t
wxBufferedOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
1071 return m_o_streambuf
->Seek(pos
, mode
);
1074 off_t
wxBufferedOutputStream::TellO() const
1076 return m_o_streambuf
->Tell();
1079 void wxBufferedOutputStream::Sync()
1081 m_o_streambuf
->FlushBuffer();
1082 m_parent_o_stream
->Sync();
1085 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1087 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1090 off_t
wxBufferedOutputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
1092 return m_parent_o_stream
->SeekO(seek
, mode
);
1095 off_t
wxBufferedOutputStream::OnSysTell() const
1097 return m_parent_o_stream
->TellO();
1100 size_t wxBufferedOutputStream::GetSize() const
1102 return m_parent_o_stream
->GetSize() + m_o_streambuf
->GetIntPosition();
1105 // ----------------------------------------------------------------------------
1106 // Some IOManip function
1107 // ----------------------------------------------------------------------------
1109 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1112 return stream
.Write("\r\n", 2);
1115 return stream
.Write("\r", 1);
1117 return stream
.Write("\n", 1);