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 wxT("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
, wxT("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, wxT("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, wxT("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
, wxT("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 wxT("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, wxT("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
, wxT("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, wxT("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, wxT("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
, wxT("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, wxT("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, wxT("can't write to this buffer") );
547 wxCHECK_MSG( sbuf
->m_mode
!= write
, 0, wxT("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( wxT("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), wxT("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
, wxT("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
, wxT("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
, wxT("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 others 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 // avoid unnecessary seek operations (optimization)
927 wxFileOffset currentPos
= TellI(), size
= GetLength();
928 if ((mode
== wxFromStart
&& currentPos
== pos
) ||
929 (mode
== wxFromCurrent
&& pos
== 0) ||
930 (mode
== wxFromEnd
&& size
!= wxInvalidOffset
&& currentPos
== size
-pos
))
933 if (!IsSeekable() && mode
== wxFromCurrent
&& pos
> 0)
935 // rather than seeking, we can just read data and discard it;
936 // this allows to forward-seek also non-seekable streams!
937 char buf
[BUF_TEMP_SIZE
];
940 // read chunks of BUF_TEMP_SIZE bytes until we reach the new position
941 for ( ; pos
>= BUF_TEMP_SIZE
; pos
-= bytes_read
)
943 bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
944 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
945 return wxInvalidOffset
;
947 wxASSERT(bytes_read
== WXSIZEOF(buf
));
950 // read the last 'pos' bytes
951 bytes_read
= Read(buf
, (size_t)pos
).LastRead();
952 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
953 return wxInvalidOffset
;
955 wxASSERT(bytes_read
== (size_t)pos
);
957 // we should now have seeked to the right position...
961 /* RR: A call to SeekI() will automatically invalidate any previous
962 call to Ungetch(), otherwise it would be possible to SeekI() to
963 one position, unread some bytes there, SeekI() to another position
964 and the data would be corrupted.
966 GRG: Could add code here to try to navigate within the wback
967 buffer if possible, but is it really needed? It would only work
968 when seeking in wxFromCurrent mode, else it would invalidate
973 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
981 return OnSysSeek(pos
, mode
);
984 wxFileOffset
wxInputStream::TellI() const
986 wxFileOffset pos
= OnSysTell();
988 if (pos
!= wxInvalidOffset
)
989 pos
-= (m_wbacksize
- m_wbackcur
);
995 // ----------------------------------------------------------------------------
997 // ----------------------------------------------------------------------------
999 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
1001 wxOutputStream::wxOutputStream()
1005 wxOutputStream::~wxOutputStream()
1009 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
1010 size_t WXUNUSED(bufsize
))
1015 void wxOutputStream::PutC(char c
)
1017 Write(&c
, sizeof(c
));
1020 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
1022 m_lastcount
= OnSysWrite(buffer
, size
);
1026 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
1028 stream_in
.Read(*this);
1032 wxFileOffset
wxOutputStream::TellO() const
1037 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1039 return OnSysSeek(pos
, mode
);
1042 void wxOutputStream::Sync()
1047 // ----------------------------------------------------------------------------
1048 // wxCountingOutputStream
1049 // ----------------------------------------------------------------------------
1051 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
1053 wxCountingOutputStream::wxCountingOutputStream ()
1058 wxFileOffset
wxCountingOutputStream::GetLength() const
1063 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1066 m_currentPos
+= size
;
1067 if (m_currentPos
> m_lastcount
)
1068 m_lastcount
= m_currentPos
;
1070 return m_currentPos
;
1073 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1075 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1080 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1084 new_pos
= m_lastcount
+ new_pos
;
1085 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastcount
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1089 new_pos
= m_currentPos
+ new_pos
;
1090 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1094 wxFAIL_MSG( wxT("invalid seek mode") );
1095 return wxInvalidOffset
;
1098 m_currentPos
= new_pos
;
1100 if (m_currentPos
> m_lastcount
)
1101 m_lastcount
= m_currentPos
;
1103 return m_currentPos
;
1106 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1108 return m_currentPos
;
1111 // ----------------------------------------------------------------------------
1112 // wxFilterInputStream
1113 // ----------------------------------------------------------------------------
1115 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1117 wxFilterInputStream::wxFilterInputStream()
1118 : m_parent_i_stream(NULL
),
1123 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1124 : m_parent_i_stream(&stream
),
1129 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1130 : m_parent_i_stream(stream
),
1135 wxFilterInputStream::~wxFilterInputStream()
1138 delete m_parent_i_stream
;
1141 // ----------------------------------------------------------------------------
1142 // wxFilterOutputStream
1143 // ----------------------------------------------------------------------------
1145 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1147 wxFilterOutputStream::wxFilterOutputStream()
1148 : m_parent_o_stream(NULL
),
1153 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1154 : m_parent_o_stream(&stream
),
1159 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1160 : m_parent_o_stream(stream
),
1165 bool wxFilterOutputStream::Close()
1167 if (m_parent_o_stream
&& m_owns
)
1168 return m_parent_o_stream
->Close();
1173 wxFilterOutputStream::~wxFilterOutputStream()
1176 delete m_parent_o_stream
;
1179 // ----------------------------------------------------------------------------
1180 // wxFilterClassFactoryBase
1181 // ----------------------------------------------------------------------------
1183 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1185 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1187 return location
.substr(0, FindExtension(location
));
1190 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1191 const wxString
& location
) const
1193 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1195 if ( location
.EndsWith(*p
) )
1196 return location
.length() - wxStrlen(*p
);
1199 return wxString::npos
;
1202 bool wxFilterClassFactoryBase::CanHandle(const wxString
& protocol
,
1203 wxStreamProtocolType type
) const
1205 if (type
== wxSTREAM_FILEEXT
)
1206 return FindExtension(protocol
) != wxString::npos
;
1208 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1215 // ----------------------------------------------------------------------------
1216 // wxFilterClassFactory
1217 // ----------------------------------------------------------------------------
1219 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1221 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1223 void wxFilterClassFactory::Remove()
1227 wxFilterClassFactory
**pp
= &sm_first
;
1230 pp
= &(*pp
)->m_next
;
1238 // ----------------------------------------------------------------------------
1239 // wxBufferedInputStream
1240 // ----------------------------------------------------------------------------
1245 // helper function used for initializing the buffer used by
1246 // wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1247 // not NULL or creates a buffer of the given size otherwise
1248 template <typename T
>
1250 CreateBufferIfNeeded(T
& stream
, wxStreamBuffer
*buffer
, size_t bufsize
= 1024)
1252 return buffer
? buffer
: new wxStreamBuffer(bufsize
, stream
);
1255 } // anonymous namespace
1257 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1258 wxStreamBuffer
*buffer
)
1259 : wxFilterInputStream(stream
)
1261 m_i_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1264 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1266 : wxFilterInputStream(stream
)
1268 m_i_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1271 wxBufferedInputStream::~wxBufferedInputStream()
1273 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1276 delete m_i_streambuf
;
1279 char wxBufferedInputStream::Peek()
1281 return m_i_streambuf
->Peek();
1284 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1286 // reset the error flag
1289 // first read from the already cached data
1290 m_lastcount
= GetWBack(buf
, size
);
1292 // do we have to read anything more?
1293 if ( m_lastcount
< size
)
1295 size
-= m_lastcount
;
1296 buf
= (char *)buf
+ m_lastcount
;
1298 // the call to wxStreamBuffer::Read() below may reset our m_lastcount
1299 // (but it also may not do it if the buffer is associated to another
1300 // existing stream and wasn't created by us), so save it
1301 size_t countOld
= m_lastcount
;
1303 // the new count of the bytes read is the count of bytes read this time
1304 m_lastcount
= m_i_streambuf
->Read(buf
, size
);
1306 // plus those we had read before
1307 m_lastcount
+= countOld
;
1313 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1315 // RR: Look at wxInputStream for comments.
1317 if (m_lasterror
==wxSTREAM_EOF
)
1322 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1330 return m_i_streambuf
->Seek(pos
, mode
);
1333 wxFileOffset
wxBufferedInputStream::TellI() const
1335 wxFileOffset pos
= m_i_streambuf
->Tell();
1337 if (pos
!= wxInvalidOffset
)
1338 pos
-= (m_wbacksize
- m_wbackcur
);
1343 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1345 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1348 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1350 return m_parent_i_stream
->SeekI(seek
, mode
);
1353 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1355 return m_parent_i_stream
->TellI();
1358 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1360 wxCHECK_RET( buffer
, wxT("wxBufferedInputStream needs buffer") );
1362 delete m_i_streambuf
;
1363 m_i_streambuf
= buffer
;
1366 // ----------------------------------------------------------------------------
1367 // wxBufferedOutputStream
1368 // ----------------------------------------------------------------------------
1370 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1371 wxStreamBuffer
*buffer
)
1372 : wxFilterOutputStream(stream
)
1374 m_o_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1377 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1379 : wxFilterOutputStream(stream
)
1381 m_o_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1384 wxBufferedOutputStream::~wxBufferedOutputStream()
1387 delete m_o_streambuf
;
1390 bool wxBufferedOutputStream::Close()
1397 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1400 m_o_streambuf
->Write(buffer
, size
);
1404 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1407 return m_o_streambuf
->Seek(pos
, mode
);
1410 wxFileOffset
wxBufferedOutputStream::TellO() const
1412 return m_o_streambuf
->Tell();
1415 void wxBufferedOutputStream::Sync()
1417 m_o_streambuf
->FlushBuffer();
1418 m_parent_o_stream
->Sync();
1421 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1423 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1426 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1428 return m_parent_o_stream
->SeekO(seek
, mode
);
1431 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1433 return m_parent_o_stream
->TellO();
1436 wxFileOffset
wxBufferedOutputStream::GetLength() const
1438 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1441 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1443 wxCHECK_RET( buffer
, wxT("wxBufferedOutputStream needs buffer") );
1445 delete m_o_streambuf
;
1446 m_o_streambuf
= buffer
;
1449 // ----------------------------------------------------------------------------
1450 // Some IOManip function
1451 // ----------------------------------------------------------------------------
1453 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1455 static const wxChar
*eol
= wxTextFile::GetEOL();
1457 return stream
.Write(eol
, wxStrlen(eol
));
1460 #endif // wxUSE_STREAMS