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"
39 #include "wx/scopeguard.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 // the temporary buffer size used when copying from stream to stream
46 #define BUF_TEMP_SIZE 4096
48 // ============================================================================
50 // ============================================================================
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 void wxStreamBuffer::SetError(wxStreamError err
)
58 if ( m_stream
&& m_stream
->m_lasterror
== wxSTREAM_NO_ERROR
)
59 m_stream
->m_lasterror
= err
;
62 void wxStreamBuffer::InitBuffer()
68 // if we are going to allocate the buffer, we should free it later as well
72 void wxStreamBuffer::Init()
79 void wxStreamBuffer::InitWithStream(wxStreamBase
& stream
, BufMode mode
)
89 wxStreamBuffer::wxStreamBuffer(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 wxT("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_fixed
= buffer
.m_fixed
;
110 m_flushable
= buffer
.m_flushable
;
111 m_stream
= buffer
.m_stream
;
112 m_mode
= buffer
.m_mode
;
113 m_destroybuf
= false;
116 void wxStreamBuffer::FreeBuffer()
120 free(m_buffer_start
);
121 m_buffer_start
= NULL
;
125 wxStreamBuffer::~wxStreamBuffer()
130 wxInputStream
*wxStreamBuffer::GetInputStream() const
132 return m_mode
== write
? NULL
: (wxInputStream
*)m_stream
;
135 wxOutputStream
*wxStreamBuffer::GetOutputStream() const
137 return m_mode
== read
? NULL
: (wxOutputStream
*)m_stream
;
140 void wxStreamBuffer::SetBufferIO(void *buffer_start
,
144 SetBufferIO(buffer_start
, (char *)buffer_end
- (char *)buffer_start
,
148 void wxStreamBuffer::SetBufferIO(void *start
,
152 // start by freeing the old buffer
155 m_buffer_start
= (char *)start
;
156 m_buffer_end
= m_buffer_start
+ len
;
158 // if we own it, we free it
159 m_destroybuf
= takeOwnership
;
164 void wxStreamBuffer::SetBufferIO(size_t bufsize
)
168 // this will free the old buffer and allocate the new one
169 SetBufferIO(malloc(bufsize
), bufsize
, true /* take ownership */);
171 else // no buffer size => no buffer
173 // still free the old one
179 void wxStreamBuffer::ResetBuffer()
184 m_stream
->m_lastcount
= 0;
187 m_buffer_pos
= m_mode
== read
&& m_flushable
192 void wxStreamBuffer::Truncate()
194 size_t new_size
= m_buffer_pos
- m_buffer_start
;
195 if ( m_buffer_pos
== m_buffer_end
)
205 char *new_start
= (char *)realloc(m_buffer_start
, new_size
);
206 wxCHECK_RET( new_size
, wxT("shrinking buffer shouldn't fail") );
208 m_buffer_start
= new_start
;
209 m_buffer_end
= m_buffer_start
+ new_size
;
210 m_buffer_pos
= m_buffer_end
;
213 // fill the buffer with as much data as possible (only for read buffers)
214 bool wxStreamBuffer::FillBuffer()
216 wxInputStream
*inStream
= GetInputStream();
218 // It's legal to have no stream, so we don't complain about it just return false
222 size_t count
= inStream
->OnSysRead(GetBufferStart(), GetBufferSize());
226 m_buffer_end
= m_buffer_start
+ count
;
227 m_buffer_pos
= m_buffer_start
;
232 // write the buffer contents to the stream (only for write buffers)
233 bool wxStreamBuffer::FlushBuffer()
235 wxCHECK_MSG( m_flushable
, false, wxT("can't flush this buffer") );
237 // FIXME: what is this check for? (VZ)
238 if ( m_buffer_pos
== m_buffer_start
)
241 wxOutputStream
*outStream
= GetOutputStream();
243 wxCHECK_MSG( outStream
, false, wxT("should have a stream in wxStreamBuffer") );
245 size_t current
= m_buffer_pos
- m_buffer_start
;
246 size_t count
= outStream
->OnSysWrite(m_buffer_start
, current
);
247 if ( count
!= current
)
250 m_buffer_pos
= m_buffer_start
;
255 size_t wxStreamBuffer::GetDataLeft()
257 /* Why is this done? RR. */
258 if ( m_buffer_pos
== m_buffer_end
&& m_flushable
)
261 return GetBytesLeft();
264 // copy up to size bytes from our buffer into the provided one
265 void wxStreamBuffer::GetFromBuffer(void *buffer
, size_t size
)
267 // don't get more bytes than left in the buffer
268 size_t left
= GetBytesLeft();
273 memcpy(buffer
, m_buffer_pos
, size
);
274 m_buffer_pos
+= size
;
277 // copy the contents of the provided buffer into this one
278 void wxStreamBuffer::PutToBuffer(const void *buffer
, size_t size
)
280 size_t left
= GetBytesLeft();
286 // we can't realloc the buffer, so just copy what we can
291 // realloc the buffer to have enough space for the data
292 if ( m_buffer_pos
+ size
> m_buffer_end
)
294 size_t delta
= m_buffer_pos
- m_buffer_start
;
295 size_t new_size
= delta
+ size
;
297 char *startOld
= m_buffer_start
;
298 m_buffer_start
= (char *)realloc(m_buffer_start
, new_size
);
299 if ( !m_buffer_start
)
301 // don't leak memory if realloc() failed
302 m_buffer_start
= startOld
;
304 // what else can we do?
308 // adjust the pointers invalidated by realloc()
309 m_buffer_pos
= m_buffer_start
+ delta
;
310 m_buffer_end
= m_buffer_start
+ new_size
;
311 } // else: the buffer is big enough
315 memcpy(m_buffer_pos
, buffer
, size
);
316 m_buffer_pos
+= size
;
319 void wxStreamBuffer::PutChar(char c
)
321 wxOutputStream
*outStream
= GetOutputStream();
323 wxCHECK_RET( outStream
, wxT("should have a stream in wxStreamBuffer") );
325 // if we don't have buffer at all, just forward this call to the stream,
328 outStream
->OnSysWrite(&c
, sizeof(c
));
332 // otherwise check we have enough space left
333 if ( !GetDataLeft() && !FlushBuffer() )
336 SetError(wxSTREAM_WRITE_ERROR
);
340 PutToBuffer(&c
, sizeof(c
));
341 m_stream
->m_lastcount
= 1;
346 char wxStreamBuffer::Peek()
348 wxCHECK_MSG( m_stream
&& HasBuffer(), 0,
349 wxT("should have the stream and the buffer in wxStreamBuffer") );
351 if ( !GetDataLeft() )
353 SetError(wxSTREAM_READ_ERROR
);
358 GetFromBuffer(&c
, sizeof(c
));
364 char wxStreamBuffer::GetChar()
366 wxInputStream
*inStream
= GetInputStream();
368 wxCHECK_MSG( inStream
, 0, wxT("should have a stream in wxStreamBuffer") );
373 inStream
->OnSysRead(&c
, sizeof(c
));
377 if ( !GetDataLeft() )
379 SetError(wxSTREAM_READ_ERROR
);
384 GetFromBuffer(&c
, sizeof(c
));
385 m_stream
->m_lastcount
= 1;
392 size_t wxStreamBuffer::Read(void *buffer
, size_t size
)
394 wxASSERT_MSG( buffer
, wxT("Warning: Null pointer is about to be used") );
396 /* Clear buffer first */
397 memset(buffer
, 0x00, size
);
399 // lasterror is reset before all new IO calls
406 wxInputStream
*inStream
= GetInputStream();
408 wxCHECK_MSG( inStream
, 0, wxT("should have a stream in wxStreamBuffer") );
410 readBytes
= inStream
->OnSysRead(buffer
, size
);
412 else // we have a buffer, use it
414 size_t orig_size
= size
;
418 size_t left
= GetDataLeft();
420 // if the requested number of bytes if greater than the buffer
421 // size, read data in chunks
424 GetFromBuffer(buffer
, left
);
426 buffer
= (char *)buffer
+ left
;
430 SetError(wxSTREAM_EOF
);
434 else // otherwise just do it in one gulp
436 GetFromBuffer(buffer
, size
);
441 readBytes
= orig_size
- size
;
445 m_stream
->m_lastcount
= readBytes
;
450 // this should really be called "Copy()"
451 size_t wxStreamBuffer::Read(wxStreamBuffer
*dbuf
)
453 wxCHECK_MSG( m_mode
!= write
, 0, wxT("can't read from this buffer") );
455 char buf
[BUF_TEMP_SIZE
];
461 nRead
= Read(buf
, WXSIZEOF(buf
));
464 nRead
= dbuf
->Write(buf
, nRead
);
473 size_t wxStreamBuffer::Write(const void *buffer
, size_t size
)
475 wxASSERT_MSG( buffer
, wxT("Warning: Null pointer is about to be send") );
479 // lasterror is reset before all new IO calls
485 if ( !HasBuffer() && m_fixed
)
487 wxOutputStream
*outStream
= GetOutputStream();
489 wxCHECK_MSG( outStream
, 0, wxT("should have a stream in wxStreamBuffer") );
491 // no buffer, just forward the call to the stream
492 ret
= outStream
->OnSysWrite(buffer
, size
);
494 else // we [may] have a buffer, use it
496 size_t orig_size
= size
;
500 size_t left
= GetBytesLeft();
502 // if the buffer is too large to fit in the stream buffer, split
503 // it in smaller parts
505 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
506 // we always go to the second case.
508 // FIXME: fine, but if it fails we should (re)try writing it by
509 // chunks as this will (hopefully) always work (VZ)
511 if ( size
> left
&& m_fixed
)
513 PutToBuffer(buffer
, left
);
515 buffer
= (char *)buffer
+ left
;
517 if ( !FlushBuffer() )
519 SetError(wxSTREAM_WRITE_ERROR
);
524 m_buffer_pos
= m_buffer_start
;
526 else // we can do it in one gulp
528 PutToBuffer(buffer
, size
);
533 ret
= orig_size
- size
;
538 // i am not entirely sure what we do this for
539 m_stream
->m_lastcount
= ret
;
545 size_t wxStreamBuffer::Write(wxStreamBuffer
*sbuf
)
547 wxCHECK_MSG( m_mode
!= read
, 0, wxT("can't write to this buffer") );
548 wxCHECK_MSG( sbuf
->m_mode
!= write
, 0, wxT("can't read from that buffer") );
550 char buf
[BUF_TEMP_SIZE
];
556 size_t nRead
= sbuf
->Read(buf
, WXSIZEOF(buf
));
559 nWrite
= Write(buf
, nRead
);
560 if ( nWrite
< nRead
)
562 // put back data we couldn't copy
563 wxInputStream
*in_stream
= (wxInputStream
*)sbuf
->GetStream();
565 in_stream
->Ungetch(buf
+ nWrite
, nRead
- nWrite
);
575 while ( nWrite
== WXSIZEOF(buf
) );
580 wxFileOffset
wxStreamBuffer::Seek(wxFileOffset pos
, wxSeekMode mode
)
582 wxFileOffset ret_off
, diff
;
584 wxFileOffset last_access
= GetLastAccess();
595 diff
= pos
+ GetIntPosition();
599 diff
= pos
+ last_access
;
603 wxFAIL_MSG( wxT("invalid seek mode") );
605 return wxInvalidOffset
;
607 if (diff
< 0 || diff
> last_access
)
608 return wxInvalidOffset
;
609 size_t int_diff
= wx_truncate_cast(size_t, diff
);
610 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
611 SetIntPosition(int_diff
);
618 // We'll try to compute an internal position later ...
619 ret_off
= m_stream
->OnSysSeek(pos
, wxFromStart
);
624 diff
= pos
+ GetIntPosition();
626 if ( (diff
> last_access
) || (diff
< 0) )
628 // We must take into account the fact that we have read
629 // something previously.
630 ret_off
= m_stream
->OnSysSeek(diff
-last_access
, wxFromCurrent
);
636 size_t int_diff
= wx_truncate_cast(size_t, diff
);
637 wxCHECK_MSG( (wxFileOffset
)int_diff
== diff
, wxInvalidOffset
, wxT("huge file not supported") );
638 SetIntPosition(int_diff
);
643 // Hard to compute: always seek to the requested position.
644 ret_off
= m_stream
->OnSysSeek(pos
, wxFromEnd
);
649 return wxInvalidOffset
;
652 wxFileOffset
wxStreamBuffer::Tell() const
656 // ask the stream for position if we have a real one
659 pos
= m_stream
->OnSysTell();
660 if ( pos
== wxInvalidOffset
)
661 return wxInvalidOffset
;
663 else // no associated stream
668 pos
+= GetIntPosition();
670 if ( m_mode
== read
&& m_flushable
)
671 pos
-= GetLastAccess();
676 // ----------------------------------------------------------------------------
678 // ----------------------------------------------------------------------------
680 IMPLEMENT_ABSTRACT_CLASS(wxStreamBase
, wxObject
)
682 wxStreamBase::wxStreamBase()
684 m_lasterror
= wxSTREAM_NO_ERROR
;
688 wxStreamBase::~wxStreamBase()
692 size_t wxStreamBase::GetSize() const
694 wxFileOffset length
= GetLength();
695 if ( length
== (wxFileOffset
)wxInvalidOffset
)
698 const size_t len
= wx_truncate_cast(size_t, length
);
699 wxASSERT_MSG( len
== length
+ size_t(0), wxT("large files not supported") );
704 wxFileOffset
wxStreamBase::OnSysSeek(wxFileOffset
WXUNUSED(seek
), wxSeekMode
WXUNUSED(mode
))
706 return wxInvalidOffset
;
709 wxFileOffset
wxStreamBase::OnSysTell() const
711 return wxInvalidOffset
;
714 // ----------------------------------------------------------------------------
716 // ----------------------------------------------------------------------------
718 IMPLEMENT_ABSTRACT_CLASS(wxInputStream
, wxStreamBase
)
720 wxInputStream::wxInputStream()
727 wxInputStream::~wxInputStream()
732 bool wxInputStream::CanRead() const
734 // we don't know if there is anything to read or not and by default we
735 // prefer to be optimistic and try to read data unless we know for sure
736 // there is no more of it
737 return m_lasterror
!= wxSTREAM_EOF
;
740 bool wxInputStream::Eof() const
742 // the only way the base class can know we're at EOF is when we'd already
743 // tried to read beyond it in which case last error is set accordingly
744 return GetLastError() == wxSTREAM_EOF
;
747 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
749 // get number of bytes left from previous wback buffer
750 size_t toget
= m_wbacksize
- m_wbackcur
;
752 // allocate a buffer large enough to hold prev + new data
753 char *temp_b
= (char *)malloc(needed_size
+ toget
);
758 // copy previous data (and free old buffer) if needed
761 memmove(temp_b
+ needed_size
, m_wback
+ m_wbackcur
, toget
);
768 m_wbacksize
= needed_size
+ toget
;
773 size_t wxInputStream::GetWBack(void *buf
, size_t size
)
775 wxASSERT_MSG( buf
, wxT("Warning: Null pointer is about to be used") );
777 /* Clear buffer first */
778 memset(buf
, 0x00, size
);
783 // how many bytes do we have in the buffer?
784 size_t toget
= m_wbacksize
- m_wbackcur
;
788 // we won't read everything
792 // copy the data from the cache
793 memcpy(buf
, m_wback
+ m_wbackcur
, toget
);
796 if ( m_wbackcur
== m_wbacksize
)
798 // TODO: should we really free it here all the time? maybe keep it?
805 // return the number of bytes copied
809 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
811 wxASSERT_MSG( buf
, wxT("Warning: Null pointer is about to be used in Ungetch()") );
813 if ( m_lasterror
!= wxSTREAM_NO_ERROR
&& m_lasterror
!= wxSTREAM_EOF
)
815 // can't operate on this stream until the error is cleared
819 char *ptrback
= AllocSpaceWBack(bufsize
);
823 // Eof() shouldn't return true any longer
824 if ( m_lasterror
== wxSTREAM_EOF
)
825 m_lasterror
= wxSTREAM_NO_ERROR
;
827 memcpy(ptrback
, buf
, bufsize
);
831 bool wxInputStream::Ungetch(char c
)
833 return Ungetch(&c
, sizeof(c
)) != 0;
836 int wxInputStream::GetC()
840 return LastRead() ? c
: wxEOF
;
843 wxInputStream
& wxInputStream::Read(void *buf
, size_t size
)
845 wxASSERT_MSG( buf
, wxT("Warning: Null pointer is about to be read") );
847 char *p
= (char *)buf
;
850 size_t read
= GetWBack(buf
, size
);
859 // we read the requested amount of data
863 if ( p
!= buf
&& !CanRead() )
865 // we have already read something and we would block in OnSysRead()
866 // now: don't do it but return immediately
870 read
= OnSysRead(p
, size
);
873 // no more data available
881 char wxInputStream::Peek()
885 if (m_lasterror
== wxSTREAM_NO_ERROR
)
894 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
896 size_t lastcount
= 0;
897 char buf
[BUF_TEMP_SIZE
];
901 size_t bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
905 if ( stream_out
.Write(buf
, bytes_read
).LastWrite() != bytes_read
)
908 lastcount
+= bytes_read
;
911 m_lastcount
= lastcount
;
916 bool wxInputStream::ReadAll(void *buffer_
, size_t size
)
918 char* buffer
= static_cast<char*>(buffer_
);
920 size_t totalCount
= 0;
924 const size_t lastCount
= Read(buffer
, size
).LastRead();
926 // There is no point in continuing looping if we can't read anything at
931 totalCount
+= lastCount
;
933 // ... Or if an error occurred on the stream.
937 // Return successfully if we read exactly the requested number of
938 // bytes (normally the ">" case should never occur and so we could use
939 // "==" test, but be safe and avoid overflowing size even in case of
940 // bugs in LastRead()).
941 if ( lastCount
>= size
)
947 // Advance the buffer before trying to read the rest of data.
952 m_lastcount
= totalCount
;
957 wxFileOffset
wxInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
959 // RR: This code is duplicated in wxBufferedInputStream. This is
960 // not really a good design, but buffered stream are different
961 // from all others in that they handle two stream-related objects:
962 // the stream buffer and parent stream.
964 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
965 if (m_lasterror
==wxSTREAM_EOF
)
966 m_lasterror
=wxSTREAM_NO_ERROR
;
968 // avoid unnecessary seek operations (optimization)
969 wxFileOffset currentPos
= TellI(), size
= GetLength();
970 if ((mode
== wxFromStart
&& currentPos
== pos
) ||
971 (mode
== wxFromCurrent
&& pos
== 0) ||
972 (mode
== wxFromEnd
&& size
!= wxInvalidOffset
&& currentPos
== size
-pos
))
975 if (!IsSeekable() && mode
== wxFromCurrent
&& pos
> 0)
977 // rather than seeking, we can just read data and discard it;
978 // this allows to forward-seek also non-seekable streams!
979 char buf
[BUF_TEMP_SIZE
];
982 // read chunks of BUF_TEMP_SIZE bytes until we reach the new position
983 for ( ; pos
>= BUF_TEMP_SIZE
; pos
-= bytes_read
)
985 bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
986 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
987 return wxInvalidOffset
;
989 wxASSERT(bytes_read
== WXSIZEOF(buf
));
992 // read the last 'pos' bytes
993 bytes_read
= Read(buf
, (size_t)pos
).LastRead();
994 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
995 return wxInvalidOffset
;
997 wxASSERT(bytes_read
== (size_t)pos
);
999 // we should now have sought to the right position...
1003 /* RR: A call to SeekI() will automatically invalidate any previous
1004 call to Ungetch(), otherwise it would be possible to SeekI() to
1005 one position, unread some bytes there, SeekI() to another position
1006 and the data would be corrupted.
1008 GRG: Could add code here to try to navigate within the wback
1009 buffer if possible, but is it really needed? It would only work
1010 when seeking in wxFromCurrent mode, else it would invalidate
1015 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1023 return OnSysSeek(pos
, mode
);
1026 wxFileOffset
wxInputStream::TellI() const
1028 wxFileOffset pos
= OnSysTell();
1030 if (pos
!= wxInvalidOffset
)
1031 pos
-= (m_wbacksize
- m_wbackcur
);
1037 // ----------------------------------------------------------------------------
1039 // ----------------------------------------------------------------------------
1041 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
1043 wxOutputStream::wxOutputStream()
1047 wxOutputStream::~wxOutputStream()
1051 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
1052 size_t WXUNUSED(bufsize
))
1057 void wxOutputStream::PutC(char c
)
1059 Write(&c
, sizeof(c
));
1062 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
1064 m_lastcount
= OnSysWrite(buffer
, size
);
1068 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
1070 stream_in
.Read(*this);
1074 bool wxOutputStream::WriteAll(const void *buffer_
, size_t size
)
1076 // This exactly mirrors ReadAll(), see there for more comments.
1077 const char* buffer
= static_cast<const char*>(buffer_
);
1079 size_t totalCount
= 0;
1083 const size_t lastCount
= Write(buffer
, size
).LastWrite();
1087 totalCount
+= lastCount
;
1092 if ( lastCount
>= size
)
1099 buffer
+= lastCount
;
1102 m_lastcount
= totalCount
;
1106 wxFileOffset
wxOutputStream::TellO() const
1111 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1113 return OnSysSeek(pos
, mode
);
1116 void wxOutputStream::Sync()
1121 // ----------------------------------------------------------------------------
1122 // wxCountingOutputStream
1123 // ----------------------------------------------------------------------------
1125 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
1127 wxCountingOutputStream::wxCountingOutputStream ()
1133 wxFileOffset
wxCountingOutputStream::GetLength() const
1138 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1141 m_currentPos
+= size
;
1142 if ( m_currentPos
> m_lastPos
)
1143 m_lastPos
= m_currentPos
;
1148 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1150 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1155 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1159 new_pos
+= m_lastPos
;
1160 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1164 new_pos
+= m_currentPos
;
1165 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1169 wxFAIL_MSG( wxT("invalid seek mode") );
1170 return wxInvalidOffset
;
1173 m_currentPos
= new_pos
;
1175 if ( m_currentPos
> m_lastPos
)
1176 m_lastPos
= m_currentPos
;
1178 return m_currentPos
;
1181 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1183 return m_currentPos
;
1186 // ----------------------------------------------------------------------------
1187 // wxFilterInputStream
1188 // ----------------------------------------------------------------------------
1190 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1192 wxFilterInputStream::wxFilterInputStream()
1193 : m_parent_i_stream(NULL
),
1198 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1199 : m_parent_i_stream(&stream
),
1204 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1205 : m_parent_i_stream(stream
),
1210 wxFilterInputStream::~wxFilterInputStream()
1213 delete m_parent_i_stream
;
1216 // ----------------------------------------------------------------------------
1217 // wxFilterOutputStream
1218 // ----------------------------------------------------------------------------
1220 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1222 wxFilterOutputStream::wxFilterOutputStream()
1223 : m_parent_o_stream(NULL
),
1228 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1229 : m_parent_o_stream(&stream
),
1234 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1235 : m_parent_o_stream(stream
),
1240 bool wxFilterOutputStream::Close()
1242 if (m_parent_o_stream
&& m_owns
)
1243 return m_parent_o_stream
->Close();
1248 wxFilterOutputStream::~wxFilterOutputStream()
1251 delete m_parent_o_stream
;
1254 // ----------------------------------------------------------------------------
1255 // wxFilterClassFactoryBase
1256 // ----------------------------------------------------------------------------
1258 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1260 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1262 return location
.substr(0, FindExtension(location
));
1265 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1266 const wxString
& location
) const
1268 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1270 if ( location
.EndsWith(*p
) )
1271 return location
.length() - wxStrlen(*p
);
1274 return wxString::npos
;
1277 bool wxFilterClassFactoryBase::CanHandle(const wxString
& protocol
,
1278 wxStreamProtocolType type
) const
1280 if (type
== wxSTREAM_FILEEXT
)
1281 return FindExtension(protocol
) != wxString::npos
;
1283 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1290 // ----------------------------------------------------------------------------
1291 // wxFilterClassFactory
1292 // ----------------------------------------------------------------------------
1294 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1296 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1298 void wxFilterClassFactory::Remove()
1302 wxFilterClassFactory
**pp
= &sm_first
;
1305 pp
= &(*pp
)->m_next
;
1313 // ----------------------------------------------------------------------------
1314 // wxBufferedInputStream
1315 // ----------------------------------------------------------------------------
1320 // helper function used for initializing the buffer used by
1321 // wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1322 // not NULL or creates a buffer of the given size otherwise
1323 template <typename T
>
1325 CreateBufferIfNeeded(T
& stream
, wxStreamBuffer
*buffer
, size_t bufsize
= 1024)
1327 return buffer
? buffer
: new wxStreamBuffer(bufsize
, stream
);
1330 } // anonymous namespace
1332 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1333 wxStreamBuffer
*buffer
)
1334 : wxFilterInputStream(stream
)
1336 m_i_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1339 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1341 : wxFilterInputStream(stream
)
1343 m_i_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1346 wxBufferedInputStream::~wxBufferedInputStream()
1348 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1351 delete m_i_streambuf
;
1354 char wxBufferedInputStream::Peek()
1356 return m_i_streambuf
->Peek();
1359 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1361 // reset the error flag
1364 // first read from the already cached data
1365 m_lastcount
= GetWBack(buf
, size
);
1367 // do we have to read anything more?
1368 if ( m_lastcount
< size
)
1370 size
-= m_lastcount
;
1371 buf
= (char *)buf
+ m_lastcount
;
1373 // the call to wxStreamBuffer::Read() below may reset our m_lastcount
1374 // (but it also may not do it if the buffer is associated to another
1375 // existing stream and wasn't created by us), so save it
1376 size_t countOld
= m_lastcount
;
1378 // the new count of the bytes read is the count of bytes read this time
1379 m_lastcount
= m_i_streambuf
->Read(buf
, size
);
1381 // plus those we had read before
1382 m_lastcount
+= countOld
;
1388 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1390 // RR: Look at wxInputStream for comments.
1392 if (m_lasterror
==wxSTREAM_EOF
)
1397 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1405 return m_i_streambuf
->Seek(pos
, mode
);
1408 wxFileOffset
wxBufferedInputStream::TellI() const
1410 wxFileOffset pos
= m_i_streambuf
->Tell();
1412 if (pos
!= wxInvalidOffset
)
1413 pos
-= (m_wbacksize
- m_wbackcur
);
1418 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1420 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1423 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1425 return m_parent_i_stream
->SeekI(seek
, mode
);
1428 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1430 return m_parent_i_stream
->TellI();
1433 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1435 wxCHECK_RET( buffer
, wxT("wxBufferedInputStream needs buffer") );
1437 delete m_i_streambuf
;
1438 m_i_streambuf
= buffer
;
1441 // ----------------------------------------------------------------------------
1442 // wxBufferedOutputStream
1443 // ----------------------------------------------------------------------------
1445 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1446 wxStreamBuffer
*buffer
)
1447 : wxFilterOutputStream(stream
)
1449 m_o_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1452 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1454 : wxFilterOutputStream(stream
)
1456 m_o_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1459 wxBufferedOutputStream::~wxBufferedOutputStream()
1462 delete m_o_streambuf
;
1465 bool wxBufferedOutputStream::Close()
1472 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1475 m_o_streambuf
->Write(buffer
, size
);
1479 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1482 return m_o_streambuf
->Seek(pos
, mode
);
1485 wxFileOffset
wxBufferedOutputStream::TellO() const
1487 return m_o_streambuf
->Tell();
1490 void wxBufferedOutputStream::Sync()
1492 m_o_streambuf
->FlushBuffer();
1493 m_parent_o_stream
->Sync();
1496 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1498 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1501 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1503 return m_parent_o_stream
->SeekO(seek
, mode
);
1506 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1508 return m_parent_o_stream
->TellO();
1511 wxFileOffset
wxBufferedOutputStream::GetLength() const
1513 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1516 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1518 wxCHECK_RET( buffer
, wxT("wxBufferedOutputStream needs buffer") );
1520 delete m_o_streambuf
;
1521 m_o_streambuf
= buffer
;
1524 // ---------------------------------------------------------------------------
1525 // wxWrapperInputStream implementation
1526 // ---------------------------------------------------------------------------
1528 wxWrapperInputStream::wxWrapperInputStream()
1530 m_lasterror
= wxSTREAM_READ_ERROR
;
1533 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
& stream
)
1534 : wxFilterInputStream(stream
)
1536 SynchronizeLastError();
1539 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
*stream
)
1540 : wxFilterInputStream(stream
)
1542 if ( m_parent_i_stream
)
1543 SynchronizeLastError();
1545 m_lasterror
= wxSTREAM_READ_ERROR
;
1548 void wxWrapperInputStream::InitParentStream(wxInputStream
& stream
)
1550 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1552 m_parent_i_stream
= &stream
;
1554 SynchronizeLastError();
1557 void wxWrapperInputStream::InitParentStream(wxInputStream
* stream
)
1559 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1561 m_parent_i_stream
= stream
;
1563 if ( m_parent_i_stream
)
1567 SynchronizeLastError();
1571 wxFileOffset
wxWrapperInputStream::GetLength() const
1573 wxCHECK_MSG(m_parent_i_stream
, wxInvalidOffset
, "Stream not valid");
1575 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1576 return m_parent_i_stream
->GetLength();
1579 bool wxWrapperInputStream::IsSeekable() const
1581 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1582 return m_parent_i_stream
->IsSeekable();
1585 size_t wxWrapperInputStream::OnSysRead(void *buffer
, size_t size
)
1587 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1589 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1591 m_parent_i_stream
->Read(buffer
, size
);
1592 return m_parent_i_stream
->LastRead();
1595 wxFileOffset
wxWrapperInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1597 wxCHECK_MSG(IsSeekable(), false, "Stream not seekable");
1599 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1600 return m_parent_i_stream
->SeekI (pos
, mode
);
1603 wxFileOffset
wxWrapperInputStream::OnSysTell() const
1605 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1607 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1608 return m_parent_i_stream
->TellI();
1611 // ----------------------------------------------------------------------------
1612 // Some IOManip function
1613 // ----------------------------------------------------------------------------
1615 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1617 static const wxChar
*eol
= wxTextFile::GetEOL();
1619 return stream
.Write(eol
, wxStrlen(eol
));
1622 #endif // wxUSE_STREAMS