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 licence
11 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
30 #include "wx/stream.h"
37 #include "wx/datstrm.h"
38 #include "wx/textfile.h"
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 // the temporary buffer size used when copying from stream to stream
45 #define BUF_TEMP_SIZE 4096
47 // ============================================================================
49 // ============================================================================
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 void wxStreamBuffer::SetError(wxStreamError err
)
57 if ( m_stream
&& m_stream
->m_lasterror
== wxSTREAM_NO_ERROR
)
58 m_stream
->m_lasterror
= err
;
61 void wxStreamBuffer::InitBuffer()
68 // if we are going to allocate the buffer, we should free it later as well
72 void wxStreamBuffer::Init()
79 wxStreamBuffer::wxStreamBuffer(BufMode mode
)
89 wxStreamBuffer::wxStreamBuffer(wxStreamBase
& stream
, BufMode mode
)
99 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer
& buffer
)
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") );
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;
117 void wxStreamBuffer::FreeBuffer()
121 free(m_buffer_start
);
122 m_buffer_start
= NULL
;
126 wxStreamBuffer::~wxStreamBuffer()
131 wxInputStream
*wxStreamBuffer::GetInputStream() const
133 return m_mode
== write
? NULL
: (wxInputStream
*)m_stream
;
136 wxOutputStream
*wxStreamBuffer::GetOutputStream() const
138 return m_mode
== read
? NULL
: (wxOutputStream
*)m_stream
;
141 void wxStreamBuffer::SetBufferIO(void *buffer_start
,
145 SetBufferIO(buffer_start
, (char *)buffer_end
- (char *)buffer_start
,
149 void wxStreamBuffer::SetBufferIO(void *start
,
153 // start by freeing the old buffer
156 m_buffer_start
= (char *)start
;
157 m_buffer_end
= m_buffer_start
+ len
;
161 // if we own it, we free it
162 m_destroybuf
= takeOwnership
;
167 void wxStreamBuffer::SetBufferIO(size_t bufsize
)
171 // this will free the old buffer and allocate the new one
172 SetBufferIO(malloc(bufsize
), bufsize
, true /* take ownership */);
174 else // no buffer size => no buffer
176 // still free the old one
182 void wxStreamBuffer::ResetBuffer()
187 m_stream
->m_lastcount
= 0;
190 m_buffer_pos
= m_mode
== read
&& m_flushable
195 void wxStreamBuffer::Truncate()
197 size_t new_size
= m_buffer_pos
- m_buffer_start
;
198 if ( new_size
== m_buffer_size
)
208 char *new_start
= (char *)realloc(m_buffer_start
, new_size
);
209 wxCHECK_RET( new_size
, _T("shrinking buffer shouldn't fail") );
211 m_buffer_start
= new_start
;
212 m_buffer_size
= new_size
;
213 m_buffer_end
= m_buffer_start
+ m_buffer_size
;
214 m_buffer_pos
= m_buffer_end
;
217 // fill the buffer with as much data as possible (only for read buffers)
218 bool wxStreamBuffer::FillBuffer()
220 wxInputStream
*inStream
= GetInputStream();
222 // It's legal to have no stream, so we don't complain about it just return false
226 size_t count
= inStream
->OnSysRead(m_buffer_start
, m_buffer_size
);
230 m_buffer_end
= m_buffer_start
+ count
;
231 m_buffer_pos
= m_buffer_start
;
236 // write the buffer contents to the stream (only for write buffers)
237 bool wxStreamBuffer::FlushBuffer()
239 wxCHECK_MSG( m_flushable
, false, _T("can't flush this buffer") );
241 // FIXME: what is this check for? (VZ)
242 if ( m_buffer_pos
== m_buffer_start
)
245 wxOutputStream
*outStream
= GetOutputStream();
247 wxCHECK_MSG( outStream
, false, _T("should have a stream in wxStreamBuffer") );
249 size_t current
= m_buffer_pos
- m_buffer_start
;
250 size_t count
= outStream
->OnSysWrite(m_buffer_start
, current
);
251 if ( count
!= current
)
254 m_buffer_pos
= m_buffer_start
;
259 size_t wxStreamBuffer::GetDataLeft()
261 /* Why is this done? RR. */
262 if ( m_buffer_pos
== m_buffer_end
&& m_flushable
)
265 return GetBytesLeft();
268 // copy up to size bytes from our buffer into the provided one
269 void wxStreamBuffer::GetFromBuffer(void *buffer
, size_t size
)
271 // don't get more bytes than left in the buffer
272 size_t left
= GetBytesLeft();
277 memcpy(buffer
, m_buffer_pos
, size
);
278 m_buffer_pos
+= size
;
281 // copy the contents of the provided buffer into this one
282 void wxStreamBuffer::PutToBuffer(const void *buffer
, size_t size
)
284 size_t left
= GetBytesLeft();
290 // we can't realloc the buffer, so just copy what we can
295 // realloc the buffer to have enough space for the data
296 size_t delta
= m_buffer_pos
- m_buffer_start
;
298 char *startOld
= m_buffer_start
;
299 m_buffer_size
+= size
;
300 m_buffer_start
= (char *)realloc(m_buffer_start
, m_buffer_size
);
301 if ( !m_buffer_start
)
303 // don't leak memory if realloc() failed
304 m_buffer_start
= startOld
;
305 m_buffer_size
-= size
;
307 // what else can we do?
311 // adjust the pointers invalidated by realloc()
312 m_buffer_pos
= m_buffer_start
+ delta
;
313 m_buffer_end
= m_buffer_start
+ m_buffer_size
;
317 memcpy(m_buffer_pos
, buffer
, size
);
318 m_buffer_pos
+= size
;
321 void wxStreamBuffer::PutChar(char c
)
323 wxOutputStream
*outStream
= GetOutputStream();
325 wxCHECK_RET( outStream
, _T("should have a stream in wxStreamBuffer") );
327 // if we don't have buffer at all, just forward this call to the stream,
330 outStream
->OnSysWrite(&c
, sizeof(c
));
334 // otherwise check we have enough space left
335 if ( !GetDataLeft() && !FlushBuffer() )
338 SetError(wxSTREAM_WRITE_ERROR
);
342 PutToBuffer(&c
, sizeof(c
));
343 m_stream
->m_lastcount
= 1;
348 char wxStreamBuffer::Peek()
350 wxCHECK_MSG( m_stream
&& HasBuffer(), 0,
351 _T("should have the stream and the buffer in wxStreamBuffer") );
353 if ( !GetDataLeft() )
355 SetError(wxSTREAM_READ_ERROR
);
360 GetFromBuffer(&c
, sizeof(c
));
366 char wxStreamBuffer::GetChar()
368 wxInputStream
*inStream
= GetInputStream();
370 wxCHECK_MSG( inStream
, 0, _T("should have a stream in wxStreamBuffer") );
375 inStream
->OnSysRead(&c
, sizeof(c
));
379 if ( !GetDataLeft() )
381 SetError(wxSTREAM_READ_ERROR
);
386 GetFromBuffer(&c
, sizeof(c
));
387 m_stream
->m_lastcount
= 1;
394 size_t wxStreamBuffer::Read(void *buffer
, size_t size
)
396 wxASSERT_MSG( buffer
, _T("Warning: Null pointer is about to be used") );
398 /* Clear buffer first */
399 memset(buffer
, 0x00, size
);
401 // lasterror is reset before all new IO calls
408 wxInputStream
*inStream
= GetInputStream();
410 wxCHECK_MSG( inStream
, 0, _T("should have a stream in wxStreamBuffer") );
412 readBytes
= inStream
->OnSysRead(buffer
, size
);
414 else // we have a buffer, use it
416 size_t orig_size
= size
;
420 size_t left
= GetDataLeft();
422 // if the requested number of bytes if greater than the buffer
423 // size, read data in chunks
426 GetFromBuffer(buffer
, left
);
428 buffer
= (char *)buffer
+ left
;
432 SetError(wxSTREAM_EOF
);
436 else // otherwise just do it in one gulp
438 GetFromBuffer(buffer
, size
);
443 readBytes
= orig_size
- size
;
447 m_stream
->m_lastcount
= readBytes
;
452 // this should really be called "Copy()"
453 size_t wxStreamBuffer::Read(wxStreamBuffer
*dbuf
)
455 wxCHECK_MSG( m_mode
!= write
, 0, _T("can't read from this buffer") );
457 char buf
[BUF_TEMP_SIZE
];
463 nRead
= Read(buf
, WXSIZEOF(buf
));
466 nRead
= dbuf
->Write(buf
, nRead
);
475 size_t wxStreamBuffer::Write(const void *buffer
, size_t size
)
477 wxASSERT_MSG( buffer
, _T("Warning: Null pointer is about to be send") );
481 // lasterror is reset before all new IO calls
487 if ( !HasBuffer() && m_fixed
)
489 wxOutputStream
*outStream
= GetOutputStream();
491 wxCHECK_MSG( outStream
, 0, _T("should have a stream in wxStreamBuffer") );
493 // no buffer, just forward the call to the stream
494 ret
= outStream
->OnSysWrite(buffer
, size
);
496 else // we [may] have a buffer, use it
498 size_t orig_size
= size
;
502 size_t left
= GetBytesLeft();
504 // if the buffer is too large to fit in the stream buffer, split
505 // it in smaller parts
507 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
508 // we always go to the second case.
510 // FIXME: fine, but if it fails we should (re)try writing it by
511 // chunks as this will (hopefully) always work (VZ)
513 if ( size
> left
&& m_fixed
)
515 PutToBuffer(buffer
, left
);
517 buffer
= (char *)buffer
+ left
;
519 if ( !FlushBuffer() )
521 SetError(wxSTREAM_WRITE_ERROR
);
526 m_buffer_pos
= m_buffer_start
;
528 else // we can do it in one gulp
530 PutToBuffer(buffer
, size
);
535 ret
= orig_size
- size
;
540 // i am not entirely sure what we do this for
541 m_stream
->m_lastcount
= ret
;
547 size_t wxStreamBuffer::Write(wxStreamBuffer
*sbuf
)
549 wxCHECK_MSG( m_mode
!= read
, 0, _T("can't write to this buffer") );
550 wxCHECK_MSG( sbuf
->m_mode
!= write
, 0, _T("can't read from that buffer") );
552 char buf
[BUF_TEMP_SIZE
];
558 size_t nRead
= sbuf
->Read(buf
, WXSIZEOF(buf
));
561 nWrite
= Write(buf
, nRead
);
562 if ( nWrite
< nRead
)
564 // put back data we couldn't copy
565 wxInputStream
*in_stream
= (wxInputStream
*)sbuf
->GetStream();
567 in_stream
->Ungetch(buf
+ nWrite
, nRead
- nWrite
);
577 while ( nWrite
== WXSIZEOF(buf
) );
582 wxFileOffset
wxStreamBuffer::Seek(wxFileOffset pos
, wxSeekMode mode
)
584 wxFileOffset ret_off
, diff
;
586 wxFileOffset last_access
= GetLastAccess();
597 diff
= pos
+ GetIntPosition();
601 diff
= pos
+ last_access
;
605 wxFAIL_MSG( _T("invalid seek mode") );
607 return wxInvalidOffset
;
609 if (diff
< 0 || diff
> last_access
)
610 return wxInvalidOffset
;
611 size_t int_diff
= wx_truncate_cast(size_t, diff
);
612 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
613 SetIntPosition(int_diff
);
620 // We'll try to compute an internal position later ...
621 ret_off
= m_stream
->OnSysSeek(pos
, wxFromStart
);
626 diff
= pos
+ GetIntPosition();
628 if ( (diff
> last_access
) || (diff
< 0) )
630 // We must take into account the fact that we have read
631 // something previously.
632 ret_off
= m_stream
->OnSysSeek(diff
-last_access
, wxFromCurrent
);
638 size_t int_diff
= wx_truncate_cast(size_t, diff
);
639 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
640 SetIntPosition(int_diff
);
645 // Hard to compute: always seek to the requested position.
646 ret_off
= m_stream
->OnSysSeek(pos
, wxFromEnd
);
651 return wxInvalidOffset
;
654 wxFileOffset
wxStreamBuffer::Tell() const
658 // ask the stream for position if we have a real one
661 pos
= m_stream
->OnSysTell();
662 if ( pos
== wxInvalidOffset
)
663 return wxInvalidOffset
;
665 else // no associated stream
670 pos
+= GetIntPosition();
672 if ( m_mode
== read
&& m_flushable
)
673 pos
-= GetLastAccess();
678 // ----------------------------------------------------------------------------
680 // ----------------------------------------------------------------------------
682 IMPLEMENT_ABSTRACT_CLASS(wxStreamBase
, wxObject
)
684 wxStreamBase::wxStreamBase()
686 m_lasterror
= wxSTREAM_NO_ERROR
;
690 wxStreamBase::~wxStreamBase()
694 size_t wxStreamBase::GetSize() const
696 wxFileOffset length
= GetLength();
697 if ( length
== (wxFileOffset
)wxInvalidOffset
)
700 const size_t len
= wx_truncate_cast(size_t, length
);
701 wxASSERT_MSG( len
== length
+ size_t(0), _T("large files not supported") );
706 wxFileOffset
wxStreamBase::OnSysSeek(wxFileOffset
WXUNUSED(seek
), wxSeekMode
WXUNUSED(mode
))
708 return wxInvalidOffset
;
711 wxFileOffset
wxStreamBase::OnSysTell() const
713 return wxInvalidOffset
;
716 // ----------------------------------------------------------------------------
718 // ----------------------------------------------------------------------------
720 IMPLEMENT_ABSTRACT_CLASS(wxInputStream
, wxStreamBase
)
722 wxInputStream::wxInputStream()
729 wxInputStream::~wxInputStream()
734 bool wxInputStream::CanRead() const
736 // we don't know if there is anything to read or not and by default we
737 // prefer to be optimistic and try to read data unless we know for sure
738 // there is no more of it
739 return m_lasterror
!= wxSTREAM_EOF
;
742 bool wxInputStream::Eof() const
744 // the only way the base class can know we're at EOF is when we'd already
745 // tried to read beyond it in which case last error is set accordingly
746 return GetLastError() == wxSTREAM_EOF
;
749 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
751 // get number of bytes left from previous wback buffer
752 size_t toget
= m_wbacksize
- m_wbackcur
;
754 // allocate a buffer large enough to hold prev + new data
755 char *temp_b
= (char *)malloc(needed_size
+ toget
);
760 // copy previous data (and free old buffer) if needed
763 memmove(temp_b
+ needed_size
, m_wback
+ m_wbackcur
, toget
);
770 m_wbacksize
= needed_size
+ toget
;
775 size_t wxInputStream::GetWBack(void *buf
, size_t size
)
777 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be used") );
779 /* Clear buffer first */
780 memset(buf
, 0x00, size
);
785 // how many bytes do we have in the buffer?
786 size_t toget
= m_wbacksize
- m_wbackcur
;
790 // we won't read everything
794 // copy the data from the cache
795 memcpy(buf
, m_wback
+ m_wbackcur
, toget
);
798 if ( m_wbackcur
== m_wbacksize
)
800 // TODO: should we really free it here all the time? maybe keep it?
807 // return the number of bytes copied
811 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
813 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be used in Ungetch()") );
815 if ( m_lasterror
!= wxSTREAM_NO_ERROR
&& m_lasterror
!= wxSTREAM_EOF
)
817 // can't operate on this stream until the error is cleared
821 char *ptrback
= AllocSpaceWBack(bufsize
);
825 // Eof() shouldn't return true any longer
826 if ( m_lasterror
== wxSTREAM_EOF
)
827 m_lasterror
= wxSTREAM_NO_ERROR
;
829 memcpy(ptrback
, buf
, bufsize
);
833 bool wxInputStream::Ungetch(char c
)
835 return Ungetch(&c
, sizeof(c
)) != 0;
838 int wxInputStream::GetC()
842 return LastRead() ? c
: wxEOF
;
845 wxInputStream
& wxInputStream::Read(void *buf
, size_t size
)
847 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be read") );
849 char *p
= (char *)buf
;
852 size_t read
= GetWBack(buf
, size
);
861 // we read the requested amount of data
865 if ( p
!= buf
&& !CanRead() )
867 // we have already read something and we would block in OnSysRead()
868 // now: don't do it but return immediately
872 read
= OnSysRead(p
, size
);
875 // no more data available
883 char wxInputStream::Peek()
887 if (m_lasterror
== wxSTREAM_NO_ERROR
)
896 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
898 size_t lastcount
= 0;
899 char buf
[BUF_TEMP_SIZE
];
903 size_t bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
907 if ( stream_out
.Write(buf
, bytes_read
).LastWrite() != bytes_read
)
910 lastcount
+= bytes_read
;
913 m_lastcount
= lastcount
;
918 wxFileOffset
wxInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
920 // RR: This code is duplicated in wxBufferedInputStream. This is
921 // not really a good design, but buffered stream are different
922 // from all other in that they handle two stream-related objects,
923 // the stream buffer and parent stream.
925 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
926 if (m_lasterror
==wxSTREAM_EOF
)
927 m_lasterror
=wxSTREAM_NO_ERROR
;
929 /* RR: A call to SeekI() will automatically invalidate any previous
930 call to Ungetch(), otherwise it would be possible to SeekI() to
931 one position, unread some bytes there, SeekI() to another position
932 and the data would be corrupted.
934 GRG: Could add code here to try to navigate within the wback
935 buffer if possible, but is it really needed? It would only work
936 when seeking in wxFromCurrent mode, else it would invalidate
941 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
949 return OnSysSeek(pos
, mode
);
952 wxFileOffset
wxInputStream::TellI() const
954 wxFileOffset pos
= OnSysTell();
956 if (pos
!= wxInvalidOffset
)
957 pos
-= (m_wbacksize
- m_wbackcur
);
963 // ----------------------------------------------------------------------------
965 // ----------------------------------------------------------------------------
967 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
969 wxOutputStream::wxOutputStream()
973 wxOutputStream::~wxOutputStream()
977 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
978 size_t WXUNUSED(bufsize
))
983 void wxOutputStream::PutC(char c
)
985 Write(&c
, sizeof(c
));
988 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
990 m_lastcount
= OnSysWrite(buffer
, size
);
994 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
996 stream_in
.Read(*this);
1000 wxFileOffset
wxOutputStream::TellO() const
1005 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1007 return OnSysSeek(pos
, mode
);
1010 void wxOutputStream::Sync()
1015 // ----------------------------------------------------------------------------
1016 // wxCountingOutputStream
1017 // ----------------------------------------------------------------------------
1019 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
1021 wxCountingOutputStream::wxCountingOutputStream ()
1026 wxFileOffset
wxCountingOutputStream::GetLength() const
1031 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1034 m_currentPos
+= size
;
1035 if (m_currentPos
> m_lastcount
)
1036 m_lastcount
= m_currentPos
;
1038 return m_currentPos
;
1041 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1043 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1048 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1052 new_pos
= m_lastcount
+ new_pos
;
1053 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastcount
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1057 new_pos
= m_currentPos
+ new_pos
;
1058 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1062 wxFAIL_MSG( _T("invalid seek mode") );
1063 return wxInvalidOffset
;
1066 m_currentPos
= new_pos
;
1068 if (m_currentPos
> m_lastcount
)
1069 m_lastcount
= m_currentPos
;
1071 return m_currentPos
;
1074 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1076 return m_currentPos
;
1079 // ----------------------------------------------------------------------------
1080 // wxFilterInputStream
1081 // ----------------------------------------------------------------------------
1083 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1085 wxFilterInputStream::wxFilterInputStream()
1086 : m_parent_i_stream(NULL
),
1091 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1092 : m_parent_i_stream(&stream
),
1097 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1098 : m_parent_i_stream(stream
),
1103 wxFilterInputStream::~wxFilterInputStream()
1106 delete m_parent_i_stream
;
1109 // ----------------------------------------------------------------------------
1110 // wxFilterOutputStream
1111 // ----------------------------------------------------------------------------
1113 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1115 wxFilterOutputStream::wxFilterOutputStream()
1116 : m_parent_o_stream(NULL
),
1121 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1122 : m_parent_o_stream(&stream
),
1127 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1128 : m_parent_o_stream(stream
),
1133 bool wxFilterOutputStream::Close()
1135 if (m_parent_o_stream
&& m_owns
)
1136 return m_parent_o_stream
->Close();
1141 wxFilterOutputStream::~wxFilterOutputStream()
1144 delete m_parent_o_stream
;
1147 // ----------------------------------------------------------------------------
1148 // wxFilterClassFactoryBase
1149 // ----------------------------------------------------------------------------
1151 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1153 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1155 return location
.substr(0, FindExtension(location
));
1158 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1159 const wxChar
*location
) const
1161 size_t len
= wxStrlen(location
);
1163 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1165 size_t l
= wxStrlen(*p
);
1167 if (l
<= len
&& wxStrcmp(*p
, location
+ len
- l
) == 0)
1171 return wxString::npos
;
1174 bool wxFilterClassFactoryBase::CanHandle(const wxChar
*protocol
,
1175 wxStreamProtocolType type
) const
1177 if (type
== wxSTREAM_FILEEXT
)
1178 return FindExtension(protocol
) != wxString::npos
;
1180 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1181 if (wxStrcmp(*p
, protocol
) == 0)
1187 // ----------------------------------------------------------------------------
1188 // wxFilterClassFactory
1189 // ----------------------------------------------------------------------------
1191 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1193 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1195 void wxFilterClassFactory::Remove()
1199 wxFilterClassFactory
**pp
= &sm_first
;
1202 pp
= &(*pp
)->m_next
;
1210 // ----------------------------------------------------------------------------
1211 // wxBufferedInputStream
1212 // ----------------------------------------------------------------------------
1214 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& s
,
1215 wxStreamBuffer
*buffer
)
1216 : wxFilterInputStream(s
)
1220 // use the buffer provided by the user
1221 m_i_streambuf
= buffer
;
1223 else // create a default buffer
1225 m_i_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::read
);
1227 m_i_streambuf
->SetBufferIO(1024);
1231 wxBufferedInputStream::~wxBufferedInputStream()
1233 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1236 delete m_i_streambuf
;
1239 char wxBufferedInputStream::Peek()
1241 return m_i_streambuf
->Peek();
1244 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1246 // reset the error flag
1249 // first read from the already cached data
1250 m_lastcount
= GetWBack(buf
, size
);
1252 // do we have to read anything more?
1253 if ( m_lastcount
< size
)
1255 size
-= m_lastcount
;
1256 buf
= (char *)buf
+ m_lastcount
;
1258 // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
1260 size_t countOld
= m_lastcount
;
1262 m_i_streambuf
->Read(buf
, size
);
1264 m_lastcount
+= countOld
;
1270 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1272 // RR: Look at wxInputStream for comments.
1274 if (m_lasterror
==wxSTREAM_EOF
)
1279 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1287 return m_i_streambuf
->Seek(pos
, mode
);
1290 wxFileOffset
wxBufferedInputStream::TellI() const
1292 wxFileOffset pos
= m_i_streambuf
->Tell();
1294 if (pos
!= wxInvalidOffset
)
1295 pos
-= (m_wbacksize
- m_wbackcur
);
1300 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1302 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1305 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1307 return m_parent_i_stream
->SeekI(seek
, mode
);
1310 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1312 return m_parent_i_stream
->TellI();
1315 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1317 wxCHECK_RET( buffer
, _T("wxBufferedInputStream needs buffer") );
1319 delete m_i_streambuf
;
1320 m_i_streambuf
= buffer
;
1323 // ----------------------------------------------------------------------------
1324 // wxBufferedOutputStream
1325 // ----------------------------------------------------------------------------
1327 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& s
,
1328 wxStreamBuffer
*buffer
)
1329 : wxFilterOutputStream(s
)
1333 m_o_streambuf
= buffer
;
1335 else // create a default one
1337 m_o_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::write
);
1339 m_o_streambuf
->SetBufferIO(1024);
1343 wxBufferedOutputStream::~wxBufferedOutputStream()
1346 delete m_o_streambuf
;
1349 bool wxBufferedOutputStream::Close()
1356 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1359 m_o_streambuf
->Write(buffer
, size
);
1363 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1366 return m_o_streambuf
->Seek(pos
, mode
);
1369 wxFileOffset
wxBufferedOutputStream::TellO() const
1371 return m_o_streambuf
->Tell();
1374 void wxBufferedOutputStream::Sync()
1376 m_o_streambuf
->FlushBuffer();
1377 m_parent_o_stream
->Sync();
1380 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1382 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1385 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1387 return m_parent_o_stream
->SeekO(seek
, mode
);
1390 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1392 return m_parent_o_stream
->TellO();
1395 wxFileOffset
wxBufferedOutputStream::GetLength() const
1397 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1400 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1402 wxCHECK_RET( buffer
, _T("wxBufferedOutputStream needs buffer") );
1404 delete m_o_streambuf
;
1405 m_o_streambuf
= buffer
;
1408 // ----------------------------------------------------------------------------
1409 // Some IOManip function
1410 // ----------------------------------------------------------------------------
1412 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1414 static const wxChar
*eol
= wxTextFile::GetEOL();
1416 return stream
.Write(eol
, wxStrlen(eol
));
1419 #endif // wxUSE_STREAMS