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()
67 // if we are going to allocate the buffer, we should free it later as well
71 void wxStreamBuffer::Init()
78 void wxStreamBuffer::InitWithStream(wxStreamBase
& stream
, BufMode mode
)
88 wxStreamBuffer::wxStreamBuffer(BufMode mode
)
98 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer
& buffer
)
100 // doing this has big chances to lead to a crash when the source buffer is
101 // destroyed (otherwise assume the caller knows what he does)
102 wxASSERT_MSG( !buffer
.m_destroybuf
,
103 _T("it's a bad idea to copy this buffer") );
105 m_buffer_start
= buffer
.m_buffer_start
;
106 m_buffer_end
= buffer
.m_buffer_end
;
107 m_buffer_pos
= buffer
.m_buffer_pos
;
108 m_fixed
= buffer
.m_fixed
;
109 m_flushable
= buffer
.m_flushable
;
110 m_stream
= buffer
.m_stream
;
111 m_mode
= buffer
.m_mode
;
112 m_destroybuf
= false;
115 void wxStreamBuffer::FreeBuffer()
119 free(m_buffer_start
);
120 m_buffer_start
= NULL
;
124 wxStreamBuffer::~wxStreamBuffer()
129 wxInputStream
*wxStreamBuffer::GetInputStream() const
131 return m_mode
== write
? NULL
: (wxInputStream
*)m_stream
;
134 wxOutputStream
*wxStreamBuffer::GetOutputStream() const
136 return m_mode
== read
? NULL
: (wxOutputStream
*)m_stream
;
139 void wxStreamBuffer::SetBufferIO(void *buffer_start
,
143 SetBufferIO(buffer_start
, (char *)buffer_end
- (char *)buffer_start
,
147 void wxStreamBuffer::SetBufferIO(void *start
,
151 // start by freeing the old buffer
154 m_buffer_start
= (char *)start
;
155 m_buffer_end
= m_buffer_start
+ len
;
157 // if we own it, we free it
158 m_destroybuf
= takeOwnership
;
163 void wxStreamBuffer::SetBufferIO(size_t bufsize
)
167 // this will free the old buffer and allocate the new one
168 SetBufferIO(malloc(bufsize
), bufsize
, true /* take ownership */);
170 else // no buffer size => no buffer
172 // still free the old one
178 void wxStreamBuffer::ResetBuffer()
183 m_stream
->m_lastcount
= 0;
186 m_buffer_pos
= m_mode
== read
&& m_flushable
191 void wxStreamBuffer::Truncate()
193 size_t new_size
= m_buffer_pos
- m_buffer_start
;
194 if ( m_buffer_pos
== m_buffer_end
)
204 char *new_start
= (char *)realloc(m_buffer_start
, new_size
);
205 wxCHECK_RET( new_size
, _T("shrinking buffer shouldn't fail") );
207 m_buffer_start
= new_start
;
208 m_buffer_end
= m_buffer_start
+ new_size
;
209 m_buffer_pos
= m_buffer_end
;
212 // fill the buffer with as much data as possible (only for read buffers)
213 bool wxStreamBuffer::FillBuffer()
215 wxInputStream
*inStream
= GetInputStream();
217 // It's legal to have no stream, so we don't complain about it just return false
221 size_t count
= inStream
->OnSysRead(GetBufferStart(), GetBufferSize());
225 m_buffer_end
= m_buffer_start
+ count
;
226 m_buffer_pos
= m_buffer_start
;
231 // write the buffer contents to the stream (only for write buffers)
232 bool wxStreamBuffer::FlushBuffer()
234 wxCHECK_MSG( m_flushable
, false, _T("can't flush this buffer") );
236 // FIXME: what is this check for? (VZ)
237 if ( m_buffer_pos
== m_buffer_start
)
240 wxOutputStream
*outStream
= GetOutputStream();
242 wxCHECK_MSG( outStream
, false, _T("should have a stream in wxStreamBuffer") );
244 size_t current
= m_buffer_pos
- m_buffer_start
;
245 size_t count
= outStream
->OnSysWrite(m_buffer_start
, current
);
246 if ( count
!= current
)
249 m_buffer_pos
= m_buffer_start
;
254 size_t wxStreamBuffer::GetDataLeft()
256 /* Why is this done? RR. */
257 if ( m_buffer_pos
== m_buffer_end
&& m_flushable
)
260 return GetBytesLeft();
263 // copy up to size bytes from our buffer into the provided one
264 void wxStreamBuffer::GetFromBuffer(void *buffer
, size_t size
)
266 // don't get more bytes than left in the buffer
267 size_t left
= GetBytesLeft();
272 memcpy(buffer
, m_buffer_pos
, size
);
273 m_buffer_pos
+= size
;
276 // copy the contents of the provided buffer into this one
277 void wxStreamBuffer::PutToBuffer(const void *buffer
, size_t size
)
279 size_t left
= GetBytesLeft();
285 // we can't realloc the buffer, so just copy what we can
290 // realloc the buffer to have enough space for the data
291 if ( m_buffer_pos
+ size
> m_buffer_end
)
293 size_t delta
= m_buffer_pos
- m_buffer_start
;
294 size_t new_size
= delta
+ size
;
296 char *startOld
= m_buffer_start
;
297 m_buffer_start
= (char *)realloc(m_buffer_start
, new_size
);
298 if ( !m_buffer_start
)
300 // don't leak memory if realloc() failed
301 m_buffer_start
= startOld
;
303 // what else can we do?
307 // adjust the pointers invalidated by realloc()
308 m_buffer_pos
= m_buffer_start
+ delta
;
309 m_buffer_end
= m_buffer_start
+ new_size
;
310 } // else: the buffer is big enough
314 memcpy(m_buffer_pos
, buffer
, size
);
315 m_buffer_pos
+= size
;
318 void wxStreamBuffer::PutChar(char c
)
320 wxOutputStream
*outStream
= GetOutputStream();
322 wxCHECK_RET( outStream
, _T("should have a stream in wxStreamBuffer") );
324 // if we don't have buffer at all, just forward this call to the stream,
327 outStream
->OnSysWrite(&c
, sizeof(c
));
331 // otherwise check we have enough space left
332 if ( !GetDataLeft() && !FlushBuffer() )
335 SetError(wxSTREAM_WRITE_ERROR
);
339 PutToBuffer(&c
, sizeof(c
));
340 m_stream
->m_lastcount
= 1;
345 char wxStreamBuffer::Peek()
347 wxCHECK_MSG( m_stream
&& HasBuffer(), 0,
348 _T("should have the stream and the buffer in wxStreamBuffer") );
350 if ( !GetDataLeft() )
352 SetError(wxSTREAM_READ_ERROR
);
357 GetFromBuffer(&c
, sizeof(c
));
363 char wxStreamBuffer::GetChar()
365 wxInputStream
*inStream
= GetInputStream();
367 wxCHECK_MSG( inStream
, 0, _T("should have a stream in wxStreamBuffer") );
372 inStream
->OnSysRead(&c
, sizeof(c
));
376 if ( !GetDataLeft() )
378 SetError(wxSTREAM_READ_ERROR
);
383 GetFromBuffer(&c
, sizeof(c
));
384 m_stream
->m_lastcount
= 1;
391 size_t wxStreamBuffer::Read(void *buffer
, size_t size
)
393 wxASSERT_MSG( buffer
, _T("Warning: Null pointer is about to be used") );
395 /* Clear buffer first */
396 memset(buffer
, 0x00, size
);
398 // lasterror is reset before all new IO calls
405 wxInputStream
*inStream
= GetInputStream();
407 wxCHECK_MSG( inStream
, 0, _T("should have a stream in wxStreamBuffer") );
409 readBytes
= inStream
->OnSysRead(buffer
, size
);
411 else // we have a buffer, use it
413 size_t orig_size
= size
;
417 size_t left
= GetDataLeft();
419 // if the requested number of bytes if greater than the buffer
420 // size, read data in chunks
423 GetFromBuffer(buffer
, left
);
425 buffer
= (char *)buffer
+ left
;
429 SetError(wxSTREAM_EOF
);
433 else // otherwise just do it in one gulp
435 GetFromBuffer(buffer
, size
);
440 readBytes
= orig_size
- size
;
444 m_stream
->m_lastcount
= readBytes
;
449 // this should really be called "Copy()"
450 size_t wxStreamBuffer::Read(wxStreamBuffer
*dbuf
)
452 wxCHECK_MSG( m_mode
!= write
, 0, _T("can't read from this buffer") );
454 char buf
[BUF_TEMP_SIZE
];
460 nRead
= Read(buf
, WXSIZEOF(buf
));
463 nRead
= dbuf
->Write(buf
, nRead
);
472 size_t wxStreamBuffer::Write(const void *buffer
, size_t size
)
474 wxASSERT_MSG( buffer
, _T("Warning: Null pointer is about to be send") );
478 // lasterror is reset before all new IO calls
484 if ( !HasBuffer() && m_fixed
)
486 wxOutputStream
*outStream
= GetOutputStream();
488 wxCHECK_MSG( outStream
, 0, _T("should have a stream in wxStreamBuffer") );
490 // no buffer, just forward the call to the stream
491 ret
= outStream
->OnSysWrite(buffer
, size
);
493 else // we [may] have a buffer, use it
495 size_t orig_size
= size
;
499 size_t left
= GetBytesLeft();
501 // if the buffer is too large to fit in the stream buffer, split
502 // it in smaller parts
504 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
505 // we always go to the second case.
507 // FIXME: fine, but if it fails we should (re)try writing it by
508 // chunks as this will (hopefully) always work (VZ)
510 if ( size
> left
&& m_fixed
)
512 PutToBuffer(buffer
, left
);
514 buffer
= (char *)buffer
+ left
;
516 if ( !FlushBuffer() )
518 SetError(wxSTREAM_WRITE_ERROR
);
523 m_buffer_pos
= m_buffer_start
;
525 else // we can do it in one gulp
527 PutToBuffer(buffer
, size
);
532 ret
= orig_size
- size
;
537 // i am not entirely sure what we do this for
538 m_stream
->m_lastcount
= ret
;
544 size_t wxStreamBuffer::Write(wxStreamBuffer
*sbuf
)
546 wxCHECK_MSG( m_mode
!= read
, 0, _T("can't write to this buffer") );
547 wxCHECK_MSG( sbuf
->m_mode
!= write
, 0, _T("can't read from that buffer") );
549 char buf
[BUF_TEMP_SIZE
];
555 size_t nRead
= sbuf
->Read(buf
, WXSIZEOF(buf
));
558 nWrite
= Write(buf
, nRead
);
559 if ( nWrite
< nRead
)
561 // put back data we couldn't copy
562 wxInputStream
*in_stream
= (wxInputStream
*)sbuf
->GetStream();
564 in_stream
->Ungetch(buf
+ nWrite
, nRead
- nWrite
);
574 while ( nWrite
== WXSIZEOF(buf
) );
579 wxFileOffset
wxStreamBuffer::Seek(wxFileOffset pos
, wxSeekMode mode
)
581 wxFileOffset ret_off
, diff
;
583 wxFileOffset last_access
= GetLastAccess();
594 diff
= pos
+ GetIntPosition();
598 diff
= pos
+ last_access
;
602 wxFAIL_MSG( _T("invalid seek mode") );
604 return wxInvalidOffset
;
606 if (diff
< 0 || diff
> last_access
)
607 return wxInvalidOffset
;
608 size_t int_diff
= wx_truncate_cast(size_t, diff
);
609 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
610 SetIntPosition(int_diff
);
617 // We'll try to compute an internal position later ...
618 ret_off
= m_stream
->OnSysSeek(pos
, wxFromStart
);
623 diff
= pos
+ GetIntPosition();
625 if ( (diff
> last_access
) || (diff
< 0) )
627 // We must take into account the fact that we have read
628 // something previously.
629 ret_off
= m_stream
->OnSysSeek(diff
-last_access
, wxFromCurrent
);
635 size_t int_diff
= wx_truncate_cast(size_t, diff
);
636 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
637 SetIntPosition(int_diff
);
642 // Hard to compute: always seek to the requested position.
643 ret_off
= m_stream
->OnSysSeek(pos
, wxFromEnd
);
648 return wxInvalidOffset
;
651 wxFileOffset
wxStreamBuffer::Tell() const
655 // ask the stream for position if we have a real one
658 pos
= m_stream
->OnSysTell();
659 if ( pos
== wxInvalidOffset
)
660 return wxInvalidOffset
;
662 else // no associated stream
667 pos
+= GetIntPosition();
669 if ( m_mode
== read
&& m_flushable
)
670 pos
-= GetLastAccess();
675 // ----------------------------------------------------------------------------
677 // ----------------------------------------------------------------------------
679 IMPLEMENT_ABSTRACT_CLASS(wxStreamBase
, wxObject
)
681 wxStreamBase::wxStreamBase()
683 m_lasterror
= wxSTREAM_NO_ERROR
;
687 wxStreamBase::~wxStreamBase()
691 size_t wxStreamBase::GetSize() const
693 wxFileOffset length
= GetLength();
694 if ( length
== (wxFileOffset
)wxInvalidOffset
)
697 const size_t len
= wx_truncate_cast(size_t, length
);
698 wxASSERT_MSG( len
== length
+ size_t(0), _T("large files not supported") );
703 wxFileOffset
wxStreamBase::OnSysSeek(wxFileOffset
WXUNUSED(seek
), wxSeekMode
WXUNUSED(mode
))
705 return wxInvalidOffset
;
708 wxFileOffset
wxStreamBase::OnSysTell() const
710 return wxInvalidOffset
;
713 // ----------------------------------------------------------------------------
715 // ----------------------------------------------------------------------------
717 IMPLEMENT_ABSTRACT_CLASS(wxInputStream
, wxStreamBase
)
719 wxInputStream::wxInputStream()
726 wxInputStream::~wxInputStream()
731 bool wxInputStream::CanRead() const
733 // we don't know if there is anything to read or not and by default we
734 // prefer to be optimistic and try to read data unless we know for sure
735 // there is no more of it
736 return m_lasterror
!= wxSTREAM_EOF
;
739 bool wxInputStream::Eof() const
741 // the only way the base class can know we're at EOF is when we'd already
742 // tried to read beyond it in which case last error is set accordingly
743 return GetLastError() == wxSTREAM_EOF
;
746 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
748 // get number of bytes left from previous wback buffer
749 size_t toget
= m_wbacksize
- m_wbackcur
;
751 // allocate a buffer large enough to hold prev + new data
752 char *temp_b
= (char *)malloc(needed_size
+ toget
);
757 // copy previous data (and free old buffer) if needed
760 memmove(temp_b
+ needed_size
, m_wback
+ m_wbackcur
, toget
);
767 m_wbacksize
= needed_size
+ toget
;
772 size_t wxInputStream::GetWBack(void *buf
, size_t size
)
774 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be used") );
776 /* Clear buffer first */
777 memset(buf
, 0x00, size
);
782 // how many bytes do we have in the buffer?
783 size_t toget
= m_wbacksize
- m_wbackcur
;
787 // we won't read everything
791 // copy the data from the cache
792 memcpy(buf
, m_wback
+ m_wbackcur
, toget
);
795 if ( m_wbackcur
== m_wbacksize
)
797 // TODO: should we really free it here all the time? maybe keep it?
804 // return the number of bytes copied
808 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
810 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be used in Ungetch()") );
812 if ( m_lasterror
!= wxSTREAM_NO_ERROR
&& m_lasterror
!= wxSTREAM_EOF
)
814 // can't operate on this stream until the error is cleared
818 char *ptrback
= AllocSpaceWBack(bufsize
);
822 // Eof() shouldn't return true any longer
823 if ( m_lasterror
== wxSTREAM_EOF
)
824 m_lasterror
= wxSTREAM_NO_ERROR
;
826 memcpy(ptrback
, buf
, bufsize
);
830 bool wxInputStream::Ungetch(char c
)
832 return Ungetch(&c
, sizeof(c
)) != 0;
835 int wxInputStream::GetC()
839 return LastRead() ? c
: wxEOF
;
842 wxInputStream
& wxInputStream::Read(void *buf
, size_t size
)
844 wxASSERT_MSG( buf
, _T("Warning: Null pointer is about to be read") );
846 char *p
= (char *)buf
;
849 size_t read
= GetWBack(buf
, size
);
858 // we read the requested amount of data
862 if ( p
!= buf
&& !CanRead() )
864 // we have already read something and we would block in OnSysRead()
865 // now: don't do it but return immediately
869 read
= OnSysRead(p
, size
);
872 // no more data available
880 char wxInputStream::Peek()
884 if (m_lasterror
== wxSTREAM_NO_ERROR
)
893 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
895 size_t lastcount
= 0;
896 char buf
[BUF_TEMP_SIZE
];
900 size_t bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
904 if ( stream_out
.Write(buf
, bytes_read
).LastWrite() != bytes_read
)
907 lastcount
+= bytes_read
;
910 m_lastcount
= lastcount
;
915 wxFileOffset
wxInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
917 // RR: This code is duplicated in wxBufferedInputStream. This is
918 // not really a good design, but buffered stream are different
919 // from all other in that they handle two stream-related objects,
920 // the stream buffer and parent stream.
922 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
923 if (m_lasterror
==wxSTREAM_EOF
)
924 m_lasterror
=wxSTREAM_NO_ERROR
;
926 /* RR: A call to SeekI() will automatically invalidate any previous
927 call to Ungetch(), otherwise it would be possible to SeekI() to
928 one position, unread some bytes there, SeekI() to another position
929 and the data would be corrupted.
931 GRG: Could add code here to try to navigate within the wback
932 buffer if possible, but is it really needed? It would only work
933 when seeking in wxFromCurrent mode, else it would invalidate
938 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
946 return OnSysSeek(pos
, mode
);
949 wxFileOffset
wxInputStream::TellI() const
951 wxFileOffset pos
= OnSysTell();
953 if (pos
!= wxInvalidOffset
)
954 pos
-= (m_wbacksize
- m_wbackcur
);
960 // ----------------------------------------------------------------------------
962 // ----------------------------------------------------------------------------
964 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
966 wxOutputStream::wxOutputStream()
970 wxOutputStream::~wxOutputStream()
974 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
975 size_t WXUNUSED(bufsize
))
980 void wxOutputStream::PutC(char c
)
982 Write(&c
, sizeof(c
));
985 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
987 m_lastcount
= OnSysWrite(buffer
, size
);
991 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
993 stream_in
.Read(*this);
997 wxFileOffset
wxOutputStream::TellO() const
1002 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1004 return OnSysSeek(pos
, mode
);
1007 void wxOutputStream::Sync()
1012 // ----------------------------------------------------------------------------
1013 // wxCountingOutputStream
1014 // ----------------------------------------------------------------------------
1016 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
1018 wxCountingOutputStream::wxCountingOutputStream ()
1023 wxFileOffset
wxCountingOutputStream::GetLength() const
1028 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1031 m_currentPos
+= size
;
1032 if (m_currentPos
> m_lastcount
)
1033 m_lastcount
= m_currentPos
;
1035 return m_currentPos
;
1038 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1040 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1045 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1049 new_pos
= m_lastcount
+ new_pos
;
1050 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastcount
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1054 new_pos
= m_currentPos
+ new_pos
;
1055 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1059 wxFAIL_MSG( _T("invalid seek mode") );
1060 return wxInvalidOffset
;
1063 m_currentPos
= new_pos
;
1065 if (m_currentPos
> m_lastcount
)
1066 m_lastcount
= m_currentPos
;
1068 return m_currentPos
;
1071 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1073 return m_currentPos
;
1076 // ----------------------------------------------------------------------------
1077 // wxFilterInputStream
1078 // ----------------------------------------------------------------------------
1080 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1082 wxFilterInputStream::wxFilterInputStream()
1083 : m_parent_i_stream(NULL
),
1088 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1089 : m_parent_i_stream(&stream
),
1094 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1095 : m_parent_i_stream(stream
),
1100 wxFilterInputStream::~wxFilterInputStream()
1103 delete m_parent_i_stream
;
1106 // ----------------------------------------------------------------------------
1107 // wxFilterOutputStream
1108 // ----------------------------------------------------------------------------
1110 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1112 wxFilterOutputStream::wxFilterOutputStream()
1113 : m_parent_o_stream(NULL
),
1118 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1119 : m_parent_o_stream(&stream
),
1124 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1125 : m_parent_o_stream(stream
),
1130 bool wxFilterOutputStream::Close()
1132 if (m_parent_o_stream
&& m_owns
)
1133 return m_parent_o_stream
->Close();
1138 wxFilterOutputStream::~wxFilterOutputStream()
1141 delete m_parent_o_stream
;
1144 // ----------------------------------------------------------------------------
1145 // wxFilterClassFactoryBase
1146 // ----------------------------------------------------------------------------
1148 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1150 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1152 return location
.substr(0, FindExtension(location
));
1155 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1156 const wxString
& location
) const
1158 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1160 if ( location
.EndsWith(*p
) )
1161 return location
.length() - wxStrlen(*p
);
1164 return wxString::npos
;
1167 bool wxFilterClassFactoryBase::CanHandle(const wxString
& protocol
,
1168 wxStreamProtocolType type
) const
1170 if (type
== wxSTREAM_FILEEXT
)
1171 return FindExtension(protocol
) != wxString::npos
;
1173 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1180 // ----------------------------------------------------------------------------
1181 // wxFilterClassFactory
1182 // ----------------------------------------------------------------------------
1184 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1186 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1188 void wxFilterClassFactory::Remove()
1192 wxFilterClassFactory
**pp
= &sm_first
;
1195 pp
= &(*pp
)->m_next
;
1203 // ----------------------------------------------------------------------------
1204 // wxBufferedInputStream
1205 // ----------------------------------------------------------------------------
1210 // helper function used for initializing the buffer used by
1211 // wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1212 // not NULL or creates a buffer of the given size otherwise
1213 template <typename T
>
1215 CreateBufferIfNeeded(T
& stream
, wxStreamBuffer
*buffer
, size_t bufsize
= 1024)
1217 return buffer
? buffer
: new wxStreamBuffer(bufsize
, stream
);
1220 } // anonymous namespace
1222 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1223 wxStreamBuffer
*buffer
)
1224 : wxFilterInputStream(stream
)
1226 m_i_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1229 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1231 : wxFilterInputStream(stream
)
1233 m_i_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1236 wxBufferedInputStream::~wxBufferedInputStream()
1238 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1241 delete m_i_streambuf
;
1244 char wxBufferedInputStream::Peek()
1246 return m_i_streambuf
->Peek();
1249 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1251 // reset the error flag
1254 // first read from the already cached data
1255 m_lastcount
= GetWBack(buf
, size
);
1257 // do we have to read anything more?
1258 if ( m_lastcount
< size
)
1260 size
-= m_lastcount
;
1261 buf
= (char *)buf
+ m_lastcount
;
1263 // the call to wxStreamBuffer::Read() below may reset our m_lastcount
1264 // (but it also may not do it if the buffer is associated to another
1265 // existing stream and wasn't created by us), so save it
1266 size_t countOld
= m_lastcount
;
1268 // the new count of the bytes read is the count of bytes read this time
1269 m_lastcount
= m_i_streambuf
->Read(buf
, size
);
1271 // plus those we had read before
1272 m_lastcount
+= countOld
;
1278 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1280 // RR: Look at wxInputStream for comments.
1282 if (m_lasterror
==wxSTREAM_EOF
)
1287 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1295 return m_i_streambuf
->Seek(pos
, mode
);
1298 wxFileOffset
wxBufferedInputStream::TellI() const
1300 wxFileOffset pos
= m_i_streambuf
->Tell();
1302 if (pos
!= wxInvalidOffset
)
1303 pos
-= (m_wbacksize
- m_wbackcur
);
1308 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1310 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1313 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1315 return m_parent_i_stream
->SeekI(seek
, mode
);
1318 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1320 return m_parent_i_stream
->TellI();
1323 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1325 wxCHECK_RET( buffer
, _T("wxBufferedInputStream needs buffer") );
1327 delete m_i_streambuf
;
1328 m_i_streambuf
= buffer
;
1331 // ----------------------------------------------------------------------------
1332 // wxBufferedOutputStream
1333 // ----------------------------------------------------------------------------
1335 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1336 wxStreamBuffer
*buffer
)
1337 : wxFilterOutputStream(stream
)
1339 m_o_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1342 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1344 : wxFilterOutputStream(stream
)
1346 m_o_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1349 wxBufferedOutputStream::~wxBufferedOutputStream()
1352 delete m_o_streambuf
;
1355 bool wxBufferedOutputStream::Close()
1362 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1365 m_o_streambuf
->Write(buffer
, size
);
1369 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1372 return m_o_streambuf
->Seek(pos
, mode
);
1375 wxFileOffset
wxBufferedOutputStream::TellO() const
1377 return m_o_streambuf
->Tell();
1380 void wxBufferedOutputStream::Sync()
1382 m_o_streambuf
->FlushBuffer();
1383 m_parent_o_stream
->Sync();
1386 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1388 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1391 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1393 return m_parent_o_stream
->SeekO(seek
, mode
);
1396 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1398 return m_parent_o_stream
->TellO();
1401 wxFileOffset
wxBufferedOutputStream::GetLength() const
1403 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1406 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1408 wxCHECK_RET( buffer
, _T("wxBufferedOutputStream needs buffer") );
1410 delete m_o_streambuf
;
1411 m_o_streambuf
= buffer
;
1414 // ----------------------------------------------------------------------------
1415 // Some IOManip function
1416 // ----------------------------------------------------------------------------
1418 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1420 static const wxChar
*eol
= wxTextFile::GetEOL();
1422 return stream
.Write(eol
, wxStrlen(eol
));
1425 #endif // wxUSE_STREAMS