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 // fill the buffer with as much data as possible (only for read buffers)
196 bool wxStreamBuffer::FillBuffer()
198 wxInputStream
*inStream
= GetInputStream();
200 // It's legal to have no stream, so we don't complain about it just return false
204 size_t count
= inStream
->OnSysRead(m_buffer_start
, m_buffer_size
);
208 m_buffer_end
= m_buffer_start
+ count
;
209 m_buffer_pos
= m_buffer_start
;
214 // write the buffer contents to the stream (only for write buffers)
215 bool wxStreamBuffer::FlushBuffer()
217 wxCHECK_MSG( m_flushable
, false, _T("can't flush this buffer") );
219 // FIXME: what is this check for? (VZ)
220 if ( m_buffer_pos
== m_buffer_start
)
223 wxOutputStream
*outStream
= GetOutputStream();
225 wxCHECK_MSG( outStream
, false, _T("should have a stream in wxStreamBuffer") );
227 size_t current
= m_buffer_pos
- m_buffer_start
;
228 size_t count
= outStream
->OnSysWrite(m_buffer_start
, current
);
229 if ( count
!= current
)
232 m_buffer_pos
= m_buffer_start
;
237 size_t wxStreamBuffer::GetDataLeft()
239 /* Why is this done? RR. */
240 if ( m_buffer_pos
== m_buffer_end
&& m_flushable
)
243 return GetBytesLeft();
246 // copy up to size bytes from our buffer into the provided one
247 void wxStreamBuffer::GetFromBuffer(void *buffer
, size_t size
)
249 // don't get more bytes than left in the buffer
250 size_t left
= GetBytesLeft();
255 memcpy(buffer
, m_buffer_pos
, size
);
256 m_buffer_pos
+= size
;
259 // copy the contents of the provided buffer into this one
260 void wxStreamBuffer::PutToBuffer(const void *buffer
, size_t size
)
262 size_t left
= GetBytesLeft();
268 // we can't realloc the buffer, so just copy what we can
273 // realloc the buffer to have enough space for the data
274 size_t delta
= m_buffer_pos
- m_buffer_start
;
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
)
281 // don't leak memory if realloc() failed
282 m_buffer_start
= startOld
;
283 m_buffer_size
-= size
;
285 // what else can we do?
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
;
295 memcpy(m_buffer_pos
, buffer
, size
);
296 m_buffer_pos
+= size
;
299 void wxStreamBuffer::PutChar(char c
)
301 wxOutputStream
*outStream
= GetOutputStream();
303 wxCHECK_RET( outStream
, _T("should have a stream in wxStreamBuffer") );
305 // if we don't have buffer at all, just forward this call to the stream,
308 outStream
->OnSysWrite(&c
, sizeof(c
));
312 // otherwise check we have enough space left
313 if ( !GetDataLeft() && !FlushBuffer() )
316 SetError(wxSTREAM_WRITE_ERROR
);
320 PutToBuffer(&c
, sizeof(c
));
321 m_stream
->m_lastcount
= 1;
326 char wxStreamBuffer::Peek()
328 wxCHECK_MSG( m_stream
&& HasBuffer(), 0,
329 _T("should have the stream and the buffer in wxStreamBuffer") );
331 if ( !GetDataLeft() )
333 SetError(wxSTREAM_READ_ERROR
);
338 GetFromBuffer(&c
, sizeof(c
));
344 char wxStreamBuffer::GetChar()
346 wxInputStream
*inStream
= GetInputStream();
348 wxCHECK_MSG( inStream
, 0, _T("should have a stream in wxStreamBuffer") );
353 inStream
->OnSysRead(&c
, sizeof(c
));
357 if ( !GetDataLeft() )
359 SetError(wxSTREAM_READ_ERROR
);
364 GetFromBuffer(&c
, sizeof(c
));
365 m_stream
->m_lastcount
= 1;
372 size_t wxStreamBuffer::Read(void *buffer
, size_t size
)
374 wxASSERT_MSG( buffer
, _T("Warning: Null pointer is about to be used") );
376 /* Clear buffer first */
377 memset(buffer
, 0x00, size
);
379 // lasterror is reset before all new IO calls
386 wxInputStream
*inStream
= GetInputStream();
388 wxCHECK_MSG( inStream
, 0, _T("should have a stream in wxStreamBuffer") );
390 readBytes
= inStream
->OnSysRead(buffer
, size
);
392 else // we have a buffer, use it
394 size_t orig_size
= size
;
398 size_t left
= GetDataLeft();
400 // if the requested number of bytes if greater than the buffer
401 // size, read data in chunks
404 GetFromBuffer(buffer
, left
);
406 buffer
= (char *)buffer
+ left
;
410 SetError(wxSTREAM_EOF
);
414 else // otherwise just do it in one gulp
416 GetFromBuffer(buffer
, size
);
421 readBytes
= orig_size
- size
;
425 m_stream
->m_lastcount
= readBytes
;
430 // this should really be called "Copy()"
431 size_t wxStreamBuffer::Read(wxStreamBuffer
*dbuf
)
433 wxCHECK_MSG( m_mode
!= write
, 0, _T("can't read from this buffer") );
435 char buf
[BUF_TEMP_SIZE
];
441 nRead
= Read(buf
, WXSIZEOF(buf
));
444 nRead
= dbuf
->Write(buf
, nRead
);
453 size_t wxStreamBuffer::Write(const void *buffer
, size_t size
)
455 wxASSERT_MSG( buffer
, _T("Warning: Null pointer is about to be send") );
459 // lasterror is reset before all new IO calls
465 if ( !HasBuffer() && m_fixed
)
467 wxOutputStream
*outStream
= GetOutputStream();
469 wxCHECK_MSG( outStream
, 0, _T("should have a stream in wxStreamBuffer") );
471 // no buffer, just forward the call to the stream
472 ret
= outStream
->OnSysWrite(buffer
, size
);
474 else // we [may] have a buffer, use it
476 size_t orig_size
= size
;
480 size_t left
= GetBytesLeft();
482 // if the buffer is too large to fit in the stream buffer, split
483 // it in smaller parts
485 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
486 // we always go to the second case.
488 // FIXME: fine, but if it fails we should (re)try writing it by
489 // chunks as this will (hopefully) always work (VZ)
491 if ( size
> left
&& m_fixed
)
493 PutToBuffer(buffer
, left
);
495 buffer
= (char *)buffer
+ left
;
497 if ( !FlushBuffer() )
499 SetError(wxSTREAM_WRITE_ERROR
);
504 m_buffer_pos
= m_buffer_start
;
506 else // we can do it in one gulp
508 PutToBuffer(buffer
, size
);
513 ret
= orig_size
- size
;
518 // i am not entirely sure what we do this for
519 m_stream
->m_lastcount
= ret
;
525 size_t wxStreamBuffer::Write(wxStreamBuffer
*sbuf
)
527 wxCHECK_MSG( m_mode
!= read
, 0, _T("can't write to this buffer") );
528 wxCHECK_MSG( sbuf
->m_mode
!= write
, 0, _T("can't read from that buffer") );
530 char buf
[BUF_TEMP_SIZE
];
536 size_t nRead
= sbuf
->Read(buf
, WXSIZEOF(buf
));
539 nWrite
= Write(buf
, nRead
);
540 if ( nWrite
< nRead
)
542 // put back data we couldn't copy
543 wxInputStream
*in_stream
= (wxInputStream
*)sbuf
->GetStream();
545 in_stream
->Ungetch(buf
+ nWrite
, nRead
- nWrite
);
555 while ( nWrite
== WXSIZEOF(buf
) );
560 wxFileOffset
wxStreamBuffer::Seek(wxFileOffset pos
, wxSeekMode mode
)
562 wxFileOffset ret_off
, diff
;
564 wxFileOffset last_access
= GetLastAccess();
575 diff
= pos
+ GetIntPosition();
579 diff
= pos
+ last_access
;
583 wxFAIL_MSG( _T("invalid seek mode") );
585 return wxInvalidOffset
;
587 if (diff
< 0 || diff
> last_access
)
588 return wxInvalidOffset
;
589 size_t int_diff
= wx_truncate_cast(size_t, diff
);
590 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
591 SetIntPosition(int_diff
);
598 // We'll try to compute an internal position later ...
599 ret_off
= m_stream
->OnSysSeek(pos
, wxFromStart
);
604 diff
= pos
+ GetIntPosition();
606 if ( (diff
> last_access
) || (diff
< 0) )
608 // We must take into account the fact that we have read
609 // something previously.
610 ret_off
= m_stream
->OnSysSeek(diff
-last_access
, wxFromCurrent
);
616 size_t int_diff
= wx_truncate_cast(size_t, diff
);
617 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
618 SetIntPosition(int_diff
);
623 // Hard to compute: always seek to the requested position.
624 ret_off
= m_stream
->OnSysSeek(pos
, wxFromEnd
);
629 return wxInvalidOffset
;
632 wxFileOffset
wxStreamBuffer::Tell() const
636 // ask the stream for position if we have a real one
639 pos
= m_stream
->OnSysTell();
640 if ( pos
== wxInvalidOffset
)
641 return wxInvalidOffset
;
643 else // no associated stream
648 pos
+= GetIntPosition();
650 if ( m_mode
== read
&& m_flushable
)
651 pos
-= GetLastAccess();
656 // ----------------------------------------------------------------------------
658 // ----------------------------------------------------------------------------
660 IMPLEMENT_ABSTRACT_CLASS(wxStreamBase
, wxObject
)
662 wxStreamBase::wxStreamBase()
664 m_lasterror
= wxSTREAM_NO_ERROR
;
668 wxStreamBase::~wxStreamBase()
672 size_t wxStreamBase::GetSize() const
674 wxFileOffset length
= GetLength();
675 if ( length
== (wxFileOffset
)wxInvalidOffset
)
678 const size_t len
= wx_truncate_cast(size_t, length
);
679 wxASSERT_MSG( len
== length
+ size_t(0), _T("large files not supported") );
684 wxFileOffset
wxStreamBase::OnSysSeek(wxFileOffset
WXUNUSED(seek
), wxSeekMode
WXUNUSED(mode
))
686 return wxInvalidOffset
;
689 wxFileOffset
wxStreamBase::OnSysTell() const
691 return wxInvalidOffset
;
694 // ----------------------------------------------------------------------------
696 // ----------------------------------------------------------------------------
698 IMPLEMENT_ABSTRACT_CLASS(wxInputStream
, wxStreamBase
)
700 wxInputStream::wxInputStream()
707 wxInputStream::~wxInputStream()
712 bool wxInputStream::CanRead() const
714 // we don't know if there is anything to read or not and by default we
715 // prefer to be optimistic and try to read data unless we know for sure
716 // there is no more of it
717 return m_lasterror
!= wxSTREAM_EOF
;
720 bool wxInputStream::Eof() const
722 // the only way the base class can know we're at EOF is when we'd already
723 // tried to read beyond it in which case last error is set accordingly
724 return GetLastError() == wxSTREAM_EOF
;
727 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
729 // get number of bytes left from previous wback buffer
730 size_t toget
= m_wbacksize
- m_wbackcur
;
732 // allocate a buffer large enough to hold prev + new data
733 char *temp_b
= (char *)malloc(needed_size
+ toget
);
738 // copy previous data (and free old buffer) if needed
741 memmove(temp_b
+ needed_size
, m_wback
+ m_wbackcur
, toget
);
748 m_wbacksize
= needed_size
+ toget
;
753 size_t wxInputStream::GetWBack(void *buf
, size_t size
)
755 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be used") );
757 /* Clear buffer first */
758 memset(buf
, 0x00, size
);
763 // how many bytes do we have in the buffer?
764 size_t toget
= m_wbacksize
- m_wbackcur
;
768 // we won't read everything
772 // copy the data from the cache
773 memcpy(buf
, m_wback
+ m_wbackcur
, toget
);
776 if ( m_wbackcur
== m_wbacksize
)
778 // TODO: should we really free it here all the time? maybe keep it?
785 // return the number of bytes copied
789 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
791 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be used in Ungetch()") );
793 if ( m_lasterror
!= wxSTREAM_NO_ERROR
&& m_lasterror
!= wxSTREAM_EOF
)
795 // can't operate on this stream until the error is cleared
799 char *ptrback
= AllocSpaceWBack(bufsize
);
803 // Eof() shouldn't return true any longer
804 if ( m_lasterror
== wxSTREAM_EOF
)
805 m_lasterror
= wxSTREAM_NO_ERROR
;
807 memcpy(ptrback
, buf
, bufsize
);
811 bool wxInputStream::Ungetch(char c
)
813 return Ungetch(&c
, sizeof(c
)) != 0;
816 int wxInputStream::GetC()
820 return LastRead() ? c
: wxEOF
;
823 wxInputStream
& wxInputStream::Read(void *buf
, size_t size
)
825 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be read") );
827 char *p
= (char *)buf
;
830 size_t read
= GetWBack(buf
, size
);
839 // we read the requested amount of data
843 if ( p
!= buf
&& !CanRead() )
845 // we have already read something and we would block in OnSysRead()
846 // now: don't do it but return immediately
850 read
= OnSysRead(p
, size
);
853 // no more data available
861 char wxInputStream::Peek()
865 if (m_lasterror
== wxSTREAM_NO_ERROR
)
874 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
876 size_t lastcount
= 0;
877 char buf
[BUF_TEMP_SIZE
];
881 size_t bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
885 if ( stream_out
.Write(buf
, bytes_read
).LastWrite() != bytes_read
)
888 lastcount
+= bytes_read
;
891 m_lastcount
= lastcount
;
896 wxFileOffset
wxInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
898 // RR: This code is duplicated in wxBufferedInputStream. This is
899 // not really a good design, but buffered stream are different
900 // from all other in that they handle two stream-related objects,
901 // the stream buffer and parent stream.
903 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
904 if (m_lasterror
==wxSTREAM_EOF
)
905 m_lasterror
=wxSTREAM_NO_ERROR
;
907 /* RR: A call to SeekI() will automatically invalidate any previous
908 call to Ungetch(), otherwise it would be possible to SeekI() to
909 one position, unread some bytes there, SeekI() to another position
910 and the data would be corrupted.
912 GRG: Could add code here to try to navigate within the wback
913 buffer if possible, but is it really needed? It would only work
914 when seeking in wxFromCurrent mode, else it would invalidate
919 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
927 return OnSysSeek(pos
, mode
);
930 wxFileOffset
wxInputStream::TellI() const
932 wxFileOffset pos
= OnSysTell();
934 if (pos
!= wxInvalidOffset
)
935 pos
-= (m_wbacksize
- m_wbackcur
);
941 // ----------------------------------------------------------------------------
943 // ----------------------------------------------------------------------------
945 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
947 wxOutputStream::wxOutputStream()
951 wxOutputStream::~wxOutputStream()
955 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
956 size_t WXUNUSED(bufsize
))
961 void wxOutputStream::PutC(char c
)
963 Write(&c
, sizeof(c
));
966 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
968 m_lastcount
= OnSysWrite(buffer
, size
);
972 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
974 stream_in
.Read(*this);
978 wxFileOffset
wxOutputStream::TellO() const
983 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
985 return OnSysSeek(pos
, mode
);
988 void wxOutputStream::Sync()
993 // ----------------------------------------------------------------------------
994 // wxCountingOutputStream
995 // ----------------------------------------------------------------------------
997 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
999 wxCountingOutputStream::wxCountingOutputStream ()
1004 wxFileOffset
wxCountingOutputStream::GetLength() const
1009 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1012 m_currentPos
+= size
;
1013 if (m_currentPos
> m_lastcount
)
1014 m_lastcount
= m_currentPos
;
1016 return m_currentPos
;
1019 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1021 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1026 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1030 new_pos
= m_lastcount
+ new_pos
;
1031 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastcount
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1035 new_pos
= m_currentPos
+ new_pos
;
1036 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1040 wxFAIL_MSG( _T("invalid seek mode") );
1041 return wxInvalidOffset
;
1044 m_currentPos
= new_pos
;
1046 if (m_currentPos
> m_lastcount
)
1047 m_lastcount
= m_currentPos
;
1049 return m_currentPos
;
1052 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1054 return m_currentPos
;
1057 // ----------------------------------------------------------------------------
1058 // wxFilterInputStream
1059 // ----------------------------------------------------------------------------
1061 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1063 wxFilterInputStream::wxFilterInputStream()
1064 : m_parent_i_stream(NULL
),
1069 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1070 : m_parent_i_stream(&stream
),
1075 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1076 : m_parent_i_stream(stream
),
1081 wxFilterInputStream::~wxFilterInputStream()
1084 delete m_parent_i_stream
;
1087 // ----------------------------------------------------------------------------
1088 // wxFilterOutputStream
1089 // ----------------------------------------------------------------------------
1091 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1093 wxFilterOutputStream::wxFilterOutputStream()
1094 : m_parent_o_stream(NULL
),
1099 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1100 : m_parent_o_stream(&stream
),
1105 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1106 : m_parent_o_stream(stream
),
1111 bool wxFilterOutputStream::Close()
1113 if (m_parent_o_stream
&& m_owns
)
1114 return m_parent_o_stream
->Close();
1119 wxFilterOutputStream::~wxFilterOutputStream()
1122 delete m_parent_o_stream
;
1125 // ----------------------------------------------------------------------------
1126 // wxFilterClassFactoryBase
1127 // ----------------------------------------------------------------------------
1129 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1131 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1133 return location
.substr(0, FindExtension(location
));
1136 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1137 const wxChar
*location
) const
1139 size_t len
= wxStrlen(location
);
1141 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1143 size_t l
= wxStrlen(*p
);
1145 if (l
<= len
&& wxStrcmp(*p
, location
+ len
- l
) == 0)
1149 return wxString::npos
;
1152 bool wxFilterClassFactoryBase::CanHandle(const wxChar
*protocol
,
1153 wxStreamProtocolType type
) const
1155 if (type
== wxSTREAM_FILEEXT
)
1156 return FindExtension(protocol
) != wxString::npos
;
1158 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1159 if (wxStrcmp(*p
, protocol
) == 0)
1165 // ----------------------------------------------------------------------------
1166 // wxFilterClassFactory
1167 // ----------------------------------------------------------------------------
1169 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1171 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1173 void wxFilterClassFactory::Remove()
1177 wxFilterClassFactory
**pp
= &sm_first
;
1180 pp
= &(*pp
)->m_next
;
1188 // ----------------------------------------------------------------------------
1189 // wxBufferedInputStream
1190 // ----------------------------------------------------------------------------
1192 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& s
,
1193 wxStreamBuffer
*buffer
)
1194 : wxFilterInputStream(s
)
1198 // use the buffer provided by the user
1199 m_i_streambuf
= buffer
;
1201 else // create a default buffer
1203 m_i_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::read
);
1205 m_i_streambuf
->SetBufferIO(1024);
1209 wxBufferedInputStream::~wxBufferedInputStream()
1211 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1214 delete m_i_streambuf
;
1217 char wxBufferedInputStream::Peek()
1219 return m_i_streambuf
->Peek();
1222 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1224 // reset the error flag
1227 // first read from the already cached data
1228 m_lastcount
= GetWBack(buf
, size
);
1230 // do we have to read anything more?
1231 if ( m_lastcount
< size
)
1233 size
-= m_lastcount
;
1234 buf
= (char *)buf
+ m_lastcount
;
1236 // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
1238 size_t countOld
= m_lastcount
;
1240 m_i_streambuf
->Read(buf
, size
);
1242 m_lastcount
+= countOld
;
1248 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1250 // RR: Look at wxInputStream for comments.
1252 if (m_lasterror
==wxSTREAM_EOF
)
1257 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1265 return m_i_streambuf
->Seek(pos
, mode
);
1268 wxFileOffset
wxBufferedInputStream::TellI() const
1270 wxFileOffset pos
= m_i_streambuf
->Tell();
1272 if (pos
!= wxInvalidOffset
)
1273 pos
-= (m_wbacksize
- m_wbackcur
);
1278 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1280 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1283 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1285 return m_parent_i_stream
->SeekI(seek
, mode
);
1288 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1290 return m_parent_i_stream
->TellI();
1293 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1295 wxCHECK_RET( buffer
, _T("wxBufferedInputStream needs buffer") );
1297 delete m_i_streambuf
;
1298 m_i_streambuf
= buffer
;
1301 // ----------------------------------------------------------------------------
1302 // wxBufferedOutputStream
1303 // ----------------------------------------------------------------------------
1305 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& s
,
1306 wxStreamBuffer
*buffer
)
1307 : wxFilterOutputStream(s
)
1311 m_o_streambuf
= buffer
;
1313 else // create a default one
1315 m_o_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::write
);
1317 m_o_streambuf
->SetBufferIO(1024);
1321 wxBufferedOutputStream::~wxBufferedOutputStream()
1324 delete m_o_streambuf
;
1327 bool wxBufferedOutputStream::Close()
1334 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1337 m_o_streambuf
->Write(buffer
, size
);
1341 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1344 return m_o_streambuf
->Seek(pos
, mode
);
1347 wxFileOffset
wxBufferedOutputStream::TellO() const
1349 return m_o_streambuf
->Tell();
1352 void wxBufferedOutputStream::Sync()
1354 m_o_streambuf
->FlushBuffer();
1355 m_parent_o_stream
->Sync();
1358 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1360 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1363 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1365 return m_parent_o_stream
->SeekO(seek
, mode
);
1368 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1370 return m_parent_o_stream
->TellO();
1373 wxFileOffset
wxBufferedOutputStream::GetLength() const
1375 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1378 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1380 wxCHECK_RET( buffer
, _T("wxBufferedOutputStream needs buffer") );
1382 delete m_o_streambuf
;
1383 m_o_streambuf
= buffer
;
1386 // ----------------------------------------------------------------------------
1387 // Some IOManip function
1388 // ----------------------------------------------------------------------------
1390 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1392 static const wxChar
*eol
= wxTextFile::GetEOL();
1394 return stream
.Write(eol
, wxStrlen(eol
));
1397 #endif // wxUSE_STREAMS