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,
8 // Copyright: (c) Guilhem Lavaux
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/stream.h"
36 #include "wx/datstrm.h"
37 #include "wx/textfile.h"
38 #include "wx/scopeguard.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 bool wxInputStream::ReadAll(void *buffer_
, size_t size
)
917 char* buffer
= static_cast<char*>(buffer_
);
919 size_t totalCount
= 0;
923 const size_t lastCount
= Read(buffer
, size
).LastRead();
925 // There is no point in continuing looping if we can't read anything at
930 totalCount
+= lastCount
;
932 // ... Or if an error occurred on the stream.
936 // Return successfully if we read exactly the requested number of
937 // bytes (normally the ">" case should never occur and so we could use
938 // "==" test, but be safe and avoid overflowing size even in case of
939 // bugs in LastRead()).
940 if ( lastCount
>= size
)
946 // Advance the buffer before trying to read the rest of data.
951 m_lastcount
= totalCount
;
956 wxFileOffset
wxInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
958 // RR: This code is duplicated in wxBufferedInputStream. This is
959 // not really a good design, but buffered stream are different
960 // from all others in that they handle two stream-related objects:
961 // the stream buffer and parent stream.
963 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
964 if (m_lasterror
==wxSTREAM_EOF
)
965 m_lasterror
=wxSTREAM_NO_ERROR
;
967 // avoid unnecessary seek operations (optimization)
968 wxFileOffset currentPos
= TellI(), size
= GetLength();
969 if ((mode
== wxFromStart
&& currentPos
== pos
) ||
970 (mode
== wxFromCurrent
&& pos
== 0) ||
971 (mode
== wxFromEnd
&& size
!= wxInvalidOffset
&& currentPos
== size
-pos
))
974 if (!IsSeekable() && mode
== wxFromCurrent
&& pos
> 0)
976 // rather than seeking, we can just read data and discard it;
977 // this allows to forward-seek also non-seekable streams!
978 char buf
[BUF_TEMP_SIZE
];
981 // read chunks of BUF_TEMP_SIZE bytes until we reach the new position
982 for ( ; pos
>= BUF_TEMP_SIZE
; pos
-= bytes_read
)
984 bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
985 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
986 return wxInvalidOffset
;
988 wxASSERT(bytes_read
== WXSIZEOF(buf
));
991 // read the last 'pos' bytes
992 bytes_read
= Read(buf
, (size_t)pos
).LastRead();
993 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
994 return wxInvalidOffset
;
996 wxASSERT(bytes_read
== (size_t)pos
);
998 // we should now have sought to the right position...
1002 /* RR: A call to SeekI() will automatically invalidate any previous
1003 call to Ungetch(), otherwise it would be possible to SeekI() to
1004 one position, unread some bytes there, SeekI() to another position
1005 and the data would be corrupted.
1007 GRG: Could add code here to try to navigate within the wback
1008 buffer if possible, but is it really needed? It would only work
1009 when seeking in wxFromCurrent mode, else it would invalidate
1014 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1022 return OnSysSeek(pos
, mode
);
1025 wxFileOffset
wxInputStream::TellI() const
1027 wxFileOffset pos
= OnSysTell();
1029 if (pos
!= wxInvalidOffset
)
1030 pos
-= (m_wbacksize
- m_wbackcur
);
1036 // ----------------------------------------------------------------------------
1038 // ----------------------------------------------------------------------------
1040 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
1042 wxOutputStream::wxOutputStream()
1046 wxOutputStream::~wxOutputStream()
1050 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
1051 size_t WXUNUSED(bufsize
))
1056 void wxOutputStream::PutC(char c
)
1058 Write(&c
, sizeof(c
));
1061 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
1063 m_lastcount
= OnSysWrite(buffer
, size
);
1067 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
1069 stream_in
.Read(*this);
1073 bool wxOutputStream::WriteAll(const void *buffer_
, size_t size
)
1075 // This exactly mirrors ReadAll(), see there for more comments.
1076 const char* buffer
= static_cast<const char*>(buffer_
);
1078 size_t totalCount
= 0;
1082 const size_t lastCount
= Write(buffer
, size
).LastWrite();
1086 totalCount
+= lastCount
;
1091 if ( lastCount
>= size
)
1098 buffer
+= lastCount
;
1101 m_lastcount
= totalCount
;
1105 wxFileOffset
wxOutputStream::TellO() const
1110 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1112 return OnSysSeek(pos
, mode
);
1115 void wxOutputStream::Sync()
1120 // ----------------------------------------------------------------------------
1121 // wxCountingOutputStream
1122 // ----------------------------------------------------------------------------
1124 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
1126 wxCountingOutputStream::wxCountingOutputStream ()
1132 wxFileOffset
wxCountingOutputStream::GetLength() const
1137 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1140 m_currentPos
+= size
;
1141 if ( m_currentPos
> m_lastPos
)
1142 m_lastPos
= m_currentPos
;
1147 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1149 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1154 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1158 new_pos
+= m_lastPos
;
1159 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1163 new_pos
+= m_currentPos
;
1164 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1168 wxFAIL_MSG( wxT("invalid seek mode") );
1169 return wxInvalidOffset
;
1172 m_currentPos
= new_pos
;
1174 if ( m_currentPos
> m_lastPos
)
1175 m_lastPos
= m_currentPos
;
1177 return m_currentPos
;
1180 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1182 return m_currentPos
;
1185 // ----------------------------------------------------------------------------
1186 // wxFilterInputStream
1187 // ----------------------------------------------------------------------------
1189 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1191 wxFilterInputStream::wxFilterInputStream()
1192 : m_parent_i_stream(NULL
),
1197 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1198 : m_parent_i_stream(&stream
),
1203 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1204 : m_parent_i_stream(stream
),
1209 wxFilterInputStream::~wxFilterInputStream()
1212 delete m_parent_i_stream
;
1215 // ----------------------------------------------------------------------------
1216 // wxFilterOutputStream
1217 // ----------------------------------------------------------------------------
1219 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1221 wxFilterOutputStream::wxFilterOutputStream()
1222 : m_parent_o_stream(NULL
),
1227 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1228 : m_parent_o_stream(&stream
),
1233 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1234 : m_parent_o_stream(stream
),
1239 bool wxFilterOutputStream::Close()
1241 if (m_parent_o_stream
&& m_owns
)
1242 return m_parent_o_stream
->Close();
1247 wxFilterOutputStream::~wxFilterOutputStream()
1250 delete m_parent_o_stream
;
1253 // ----------------------------------------------------------------------------
1254 // wxFilterClassFactoryBase
1255 // ----------------------------------------------------------------------------
1257 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1259 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1261 return location
.substr(0, FindExtension(location
));
1264 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1265 const wxString
& location
) const
1267 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1269 if ( location
.EndsWith(*p
) )
1270 return location
.length() - wxStrlen(*p
);
1273 return wxString::npos
;
1276 bool wxFilterClassFactoryBase::CanHandle(const wxString
& protocol
,
1277 wxStreamProtocolType type
) const
1279 if (type
== wxSTREAM_FILEEXT
)
1280 return FindExtension(protocol
) != wxString::npos
;
1282 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1289 // ----------------------------------------------------------------------------
1290 // wxFilterClassFactory
1291 // ----------------------------------------------------------------------------
1293 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1295 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1297 void wxFilterClassFactory::Remove()
1301 wxFilterClassFactory
**pp
= &sm_first
;
1304 pp
= &(*pp
)->m_next
;
1312 // ----------------------------------------------------------------------------
1313 // wxBufferedInputStream
1314 // ----------------------------------------------------------------------------
1319 // helper function used for initializing the buffer used by
1320 // wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1321 // not NULL or creates a buffer of the given size otherwise
1322 template <typename T
>
1324 CreateBufferIfNeeded(T
& stream
, wxStreamBuffer
*buffer
, size_t bufsize
= 1024)
1326 return buffer
? buffer
: new wxStreamBuffer(bufsize
, stream
);
1329 } // anonymous namespace
1331 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1332 wxStreamBuffer
*buffer
)
1333 : wxFilterInputStream(stream
)
1335 m_i_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1338 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1340 : wxFilterInputStream(stream
)
1342 m_i_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1345 wxBufferedInputStream::~wxBufferedInputStream()
1347 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1350 delete m_i_streambuf
;
1353 char wxBufferedInputStream::Peek()
1355 return m_i_streambuf
->Peek();
1358 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1360 // reset the error flag
1363 // first read from the already cached data
1364 m_lastcount
= GetWBack(buf
, size
);
1366 // do we have to read anything more?
1367 if ( m_lastcount
< size
)
1369 size
-= m_lastcount
;
1370 buf
= (char *)buf
+ m_lastcount
;
1372 // the call to wxStreamBuffer::Read() below may reset our m_lastcount
1373 // (but it also may not do it if the buffer is associated to another
1374 // existing stream and wasn't created by us), so save it
1375 size_t countOld
= m_lastcount
;
1377 // the new count of the bytes read is the count of bytes read this time
1378 m_lastcount
= m_i_streambuf
->Read(buf
, size
);
1380 // plus those we had read before
1381 m_lastcount
+= countOld
;
1387 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1389 // RR: Look at wxInputStream for comments.
1391 if (m_lasterror
==wxSTREAM_EOF
)
1396 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1404 return m_i_streambuf
->Seek(pos
, mode
);
1407 wxFileOffset
wxBufferedInputStream::TellI() const
1409 wxFileOffset pos
= m_i_streambuf
->Tell();
1411 if (pos
!= wxInvalidOffset
)
1412 pos
-= (m_wbacksize
- m_wbackcur
);
1417 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1419 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1422 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1424 return m_parent_i_stream
->SeekI(seek
, mode
);
1427 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1429 return m_parent_i_stream
->TellI();
1432 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1434 wxCHECK_RET( buffer
, wxT("wxBufferedInputStream needs buffer") );
1436 delete m_i_streambuf
;
1437 m_i_streambuf
= buffer
;
1440 // ----------------------------------------------------------------------------
1441 // wxBufferedOutputStream
1442 // ----------------------------------------------------------------------------
1444 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1445 wxStreamBuffer
*buffer
)
1446 : wxFilterOutputStream(stream
)
1448 m_o_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1451 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1453 : wxFilterOutputStream(stream
)
1455 m_o_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1458 wxBufferedOutputStream::~wxBufferedOutputStream()
1461 delete m_o_streambuf
;
1464 bool wxBufferedOutputStream::Close()
1471 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1474 m_o_streambuf
->Write(buffer
, size
);
1478 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1481 return m_o_streambuf
->Seek(pos
, mode
);
1484 wxFileOffset
wxBufferedOutputStream::TellO() const
1486 return m_o_streambuf
->Tell();
1489 void wxBufferedOutputStream::Sync()
1491 m_o_streambuf
->FlushBuffer();
1492 m_parent_o_stream
->Sync();
1495 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1497 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1500 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1502 return m_parent_o_stream
->SeekO(seek
, mode
);
1505 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1507 return m_parent_o_stream
->TellO();
1510 wxFileOffset
wxBufferedOutputStream::GetLength() const
1512 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1515 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1517 wxCHECK_RET( buffer
, wxT("wxBufferedOutputStream needs buffer") );
1519 delete m_o_streambuf
;
1520 m_o_streambuf
= buffer
;
1523 // ---------------------------------------------------------------------------
1524 // wxWrapperInputStream implementation
1525 // ---------------------------------------------------------------------------
1527 wxWrapperInputStream::wxWrapperInputStream()
1529 m_lasterror
= wxSTREAM_READ_ERROR
;
1532 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
& stream
)
1533 : wxFilterInputStream(stream
)
1535 SynchronizeLastError();
1538 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
*stream
)
1539 : wxFilterInputStream(stream
)
1541 if ( m_parent_i_stream
)
1542 SynchronizeLastError();
1544 m_lasterror
= wxSTREAM_READ_ERROR
;
1547 void wxWrapperInputStream::InitParentStream(wxInputStream
& stream
)
1549 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1551 m_parent_i_stream
= &stream
;
1553 SynchronizeLastError();
1556 void wxWrapperInputStream::InitParentStream(wxInputStream
* stream
)
1558 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1560 m_parent_i_stream
= stream
;
1562 if ( m_parent_i_stream
)
1566 SynchronizeLastError();
1570 wxFileOffset
wxWrapperInputStream::GetLength() const
1572 wxCHECK_MSG(m_parent_i_stream
, wxInvalidOffset
, "Stream not valid");
1574 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1575 return m_parent_i_stream
->GetLength();
1578 bool wxWrapperInputStream::IsSeekable() const
1580 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1581 return m_parent_i_stream
->IsSeekable();
1584 size_t wxWrapperInputStream::OnSysRead(void *buffer
, size_t size
)
1586 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1588 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1590 m_parent_i_stream
->Read(buffer
, size
);
1591 return m_parent_i_stream
->LastRead();
1594 wxFileOffset
wxWrapperInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1596 wxCHECK_MSG(IsSeekable(), false, "Stream not seekable");
1598 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1599 return m_parent_i_stream
->SeekI (pos
, mode
);
1602 wxFileOffset
wxWrapperInputStream::OnSysTell() const
1604 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1606 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1607 return m_parent_i_stream
->TellI();
1610 // ----------------------------------------------------------------------------
1611 // Some IOManip function
1612 // ----------------------------------------------------------------------------
1614 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1616 static const wxChar
*eol
= wxTextFile::GetEOL();
1618 return stream
.Write(eol
, wxStrlen(eol
));
1621 #endif // wxUSE_STREAMS