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_
);
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 m_lastcount
+= 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
)
944 // Advance the buffer before trying to read the rest of data.
952 wxFileOffset
wxInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
954 // RR: This code is duplicated in wxBufferedInputStream. This is
955 // not really a good design, but buffered stream are different
956 // from all others in that they handle two stream-related objects:
957 // the stream buffer and parent stream.
959 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
960 if (m_lasterror
==wxSTREAM_EOF
)
961 m_lasterror
=wxSTREAM_NO_ERROR
;
963 // avoid unnecessary seek operations (optimization)
964 wxFileOffset currentPos
= TellI(), size
= GetLength();
965 if ((mode
== wxFromStart
&& currentPos
== pos
) ||
966 (mode
== wxFromCurrent
&& pos
== 0) ||
967 (mode
== wxFromEnd
&& size
!= wxInvalidOffset
&& currentPos
== size
-pos
))
970 if (!IsSeekable() && mode
== wxFromCurrent
&& pos
> 0)
972 // rather than seeking, we can just read data and discard it;
973 // this allows to forward-seek also non-seekable streams!
974 char buf
[BUF_TEMP_SIZE
];
977 // read chunks of BUF_TEMP_SIZE bytes until we reach the new position
978 for ( ; pos
>= BUF_TEMP_SIZE
; pos
-= bytes_read
)
980 bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
981 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
982 return wxInvalidOffset
;
984 wxASSERT(bytes_read
== WXSIZEOF(buf
));
987 // read the last 'pos' bytes
988 bytes_read
= Read(buf
, (size_t)pos
).LastRead();
989 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
990 return wxInvalidOffset
;
992 wxASSERT(bytes_read
== (size_t)pos
);
994 // we should now have sought to the right position...
998 /* RR: A call to SeekI() will automatically invalidate any previous
999 call to Ungetch(), otherwise it would be possible to SeekI() to
1000 one position, unread some bytes there, SeekI() to another position
1001 and the data would be corrupted.
1003 GRG: Could add code here to try to navigate within the wback
1004 buffer if possible, but is it really needed? It would only work
1005 when seeking in wxFromCurrent mode, else it would invalidate
1010 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1018 return OnSysSeek(pos
, mode
);
1021 wxFileOffset
wxInputStream::TellI() const
1023 wxFileOffset pos
= OnSysTell();
1025 if (pos
!= wxInvalidOffset
)
1026 pos
-= (m_wbacksize
- m_wbackcur
);
1032 // ----------------------------------------------------------------------------
1034 // ----------------------------------------------------------------------------
1036 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
1038 wxOutputStream::wxOutputStream()
1042 wxOutputStream::~wxOutputStream()
1046 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
1047 size_t WXUNUSED(bufsize
))
1052 void wxOutputStream::PutC(char c
)
1054 Write(&c
, sizeof(c
));
1057 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
1059 m_lastcount
= OnSysWrite(buffer
, size
);
1063 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
1065 stream_in
.Read(*this);
1069 bool wxOutputStream::WriteAll(const void *buffer_
, size_t size
)
1071 // This exactly mirrors ReadAll(), see there for more comments.
1072 const char* buffer
= static_cast<const char*>(buffer_
);
1078 const size_t lastCount
= Write(buffer
, size
).LastWrite();
1082 m_lastcount
+= lastCount
;
1087 if ( lastCount
>= size
)
1091 buffer
+= lastCount
;
1097 wxFileOffset
wxOutputStream::TellO() const
1102 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1104 return OnSysSeek(pos
, mode
);
1107 void wxOutputStream::Sync()
1112 // ----------------------------------------------------------------------------
1113 // wxCountingOutputStream
1114 // ----------------------------------------------------------------------------
1116 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
1118 wxCountingOutputStream::wxCountingOutputStream ()
1123 wxFileOffset
wxCountingOutputStream::GetLength() const
1128 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1131 m_currentPos
+= size
;
1132 if (m_currentPos
> m_lastcount
)
1133 m_lastcount
= m_currentPos
;
1135 return m_currentPos
;
1138 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1140 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1145 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1149 new_pos
= m_lastcount
+ new_pos
;
1150 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastcount
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1154 new_pos
= m_currentPos
+ new_pos
;
1155 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1159 wxFAIL_MSG( wxT("invalid seek mode") );
1160 return wxInvalidOffset
;
1163 m_currentPos
= new_pos
;
1165 if (m_currentPos
> m_lastcount
)
1166 m_lastcount
= m_currentPos
;
1168 return m_currentPos
;
1171 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1173 return m_currentPos
;
1176 // ----------------------------------------------------------------------------
1177 // wxFilterInputStream
1178 // ----------------------------------------------------------------------------
1180 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1182 wxFilterInputStream::wxFilterInputStream()
1183 : m_parent_i_stream(NULL
),
1188 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1189 : m_parent_i_stream(&stream
),
1194 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1195 : m_parent_i_stream(stream
),
1200 wxFilterInputStream::~wxFilterInputStream()
1203 delete m_parent_i_stream
;
1206 // ----------------------------------------------------------------------------
1207 // wxFilterOutputStream
1208 // ----------------------------------------------------------------------------
1210 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1212 wxFilterOutputStream::wxFilterOutputStream()
1213 : m_parent_o_stream(NULL
),
1218 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1219 : m_parent_o_stream(&stream
),
1224 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1225 : m_parent_o_stream(stream
),
1230 bool wxFilterOutputStream::Close()
1232 if (m_parent_o_stream
&& m_owns
)
1233 return m_parent_o_stream
->Close();
1238 wxFilterOutputStream::~wxFilterOutputStream()
1241 delete m_parent_o_stream
;
1244 // ----------------------------------------------------------------------------
1245 // wxFilterClassFactoryBase
1246 // ----------------------------------------------------------------------------
1248 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1250 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1252 return location
.substr(0, FindExtension(location
));
1255 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1256 const wxString
& location
) const
1258 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1260 if ( location
.EndsWith(*p
) )
1261 return location
.length() - wxStrlen(*p
);
1264 return wxString::npos
;
1267 bool wxFilterClassFactoryBase::CanHandle(const wxString
& protocol
,
1268 wxStreamProtocolType type
) const
1270 if (type
== wxSTREAM_FILEEXT
)
1271 return FindExtension(protocol
) != wxString::npos
;
1273 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1280 // ----------------------------------------------------------------------------
1281 // wxFilterClassFactory
1282 // ----------------------------------------------------------------------------
1284 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1286 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1288 void wxFilterClassFactory::Remove()
1292 wxFilterClassFactory
**pp
= &sm_first
;
1295 pp
= &(*pp
)->m_next
;
1303 // ----------------------------------------------------------------------------
1304 // wxBufferedInputStream
1305 // ----------------------------------------------------------------------------
1310 // helper function used for initializing the buffer used by
1311 // wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1312 // not NULL or creates a buffer of the given size otherwise
1313 template <typename T
>
1315 CreateBufferIfNeeded(T
& stream
, wxStreamBuffer
*buffer
, size_t bufsize
= 1024)
1317 return buffer
? buffer
: new wxStreamBuffer(bufsize
, stream
);
1320 } // anonymous namespace
1322 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1323 wxStreamBuffer
*buffer
)
1324 : wxFilterInputStream(stream
)
1326 m_i_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1329 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1331 : wxFilterInputStream(stream
)
1333 m_i_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1336 wxBufferedInputStream::~wxBufferedInputStream()
1338 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1341 delete m_i_streambuf
;
1344 char wxBufferedInputStream::Peek()
1346 return m_i_streambuf
->Peek();
1349 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1351 // reset the error flag
1354 // first read from the already cached data
1355 m_lastcount
= GetWBack(buf
, size
);
1357 // do we have to read anything more?
1358 if ( m_lastcount
< size
)
1360 size
-= m_lastcount
;
1361 buf
= (char *)buf
+ m_lastcount
;
1363 // the call to wxStreamBuffer::Read() below may reset our m_lastcount
1364 // (but it also may not do it if the buffer is associated to another
1365 // existing stream and wasn't created by us), so save it
1366 size_t countOld
= m_lastcount
;
1368 // the new count of the bytes read is the count of bytes read this time
1369 m_lastcount
= m_i_streambuf
->Read(buf
, size
);
1371 // plus those we had read before
1372 m_lastcount
+= countOld
;
1378 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1380 // RR: Look at wxInputStream for comments.
1382 if (m_lasterror
==wxSTREAM_EOF
)
1387 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1395 return m_i_streambuf
->Seek(pos
, mode
);
1398 wxFileOffset
wxBufferedInputStream::TellI() const
1400 wxFileOffset pos
= m_i_streambuf
->Tell();
1402 if (pos
!= wxInvalidOffset
)
1403 pos
-= (m_wbacksize
- m_wbackcur
);
1408 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1410 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1413 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1415 return m_parent_i_stream
->SeekI(seek
, mode
);
1418 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1420 return m_parent_i_stream
->TellI();
1423 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1425 wxCHECK_RET( buffer
, wxT("wxBufferedInputStream needs buffer") );
1427 delete m_i_streambuf
;
1428 m_i_streambuf
= buffer
;
1431 // ----------------------------------------------------------------------------
1432 // wxBufferedOutputStream
1433 // ----------------------------------------------------------------------------
1435 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1436 wxStreamBuffer
*buffer
)
1437 : wxFilterOutputStream(stream
)
1439 m_o_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1442 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1444 : wxFilterOutputStream(stream
)
1446 m_o_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1449 wxBufferedOutputStream::~wxBufferedOutputStream()
1452 delete m_o_streambuf
;
1455 bool wxBufferedOutputStream::Close()
1462 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1465 m_o_streambuf
->Write(buffer
, size
);
1469 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1472 return m_o_streambuf
->Seek(pos
, mode
);
1475 wxFileOffset
wxBufferedOutputStream::TellO() const
1477 return m_o_streambuf
->Tell();
1480 void wxBufferedOutputStream::Sync()
1482 m_o_streambuf
->FlushBuffer();
1483 m_parent_o_stream
->Sync();
1486 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1488 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1491 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1493 return m_parent_o_stream
->SeekO(seek
, mode
);
1496 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1498 return m_parent_o_stream
->TellO();
1501 wxFileOffset
wxBufferedOutputStream::GetLength() const
1503 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1506 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1508 wxCHECK_RET( buffer
, wxT("wxBufferedOutputStream needs buffer") );
1510 delete m_o_streambuf
;
1511 m_o_streambuf
= buffer
;
1514 // ---------------------------------------------------------------------------
1515 // wxWrapperInputStream implementation
1516 // ---------------------------------------------------------------------------
1518 wxWrapperInputStream::wxWrapperInputStream()
1520 m_lasterror
= wxSTREAM_READ_ERROR
;
1523 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
& stream
)
1524 : wxFilterInputStream(stream
)
1526 SynchronizeLastError();
1529 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
*stream
)
1530 : wxFilterInputStream(stream
)
1532 if ( m_parent_i_stream
)
1533 SynchronizeLastError();
1535 m_lasterror
= wxSTREAM_READ_ERROR
;
1538 void wxWrapperInputStream::InitParentStream(wxInputStream
& stream
)
1540 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1542 m_parent_i_stream
= &stream
;
1544 SynchronizeLastError();
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 if ( m_parent_i_stream
)
1557 SynchronizeLastError();
1561 wxFileOffset
wxWrapperInputStream::GetLength() const
1563 wxCHECK_MSG(m_parent_i_stream
, wxInvalidOffset
, "Stream not valid");
1565 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1566 return m_parent_i_stream
->GetLength();
1569 bool wxWrapperInputStream::IsSeekable() const
1571 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1572 return m_parent_i_stream
->IsSeekable();
1575 size_t wxWrapperInputStream::OnSysRead(void *buffer
, size_t size
)
1577 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1579 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1581 m_parent_i_stream
->Read(buffer
, size
);
1582 return m_parent_i_stream
->LastRead();
1585 wxFileOffset
wxWrapperInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1587 wxCHECK_MSG(IsSeekable(), false, "Stream not seekable");
1589 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1590 return m_parent_i_stream
->SeekI (pos
, mode
);
1593 wxFileOffset
wxWrapperInputStream::OnSysTell() const
1595 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1597 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1598 return m_parent_i_stream
->TellI();
1601 // ----------------------------------------------------------------------------
1602 // Some IOManip function
1603 // ----------------------------------------------------------------------------
1605 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1607 static const wxChar
*eol
= wxTextFile::GetEOL();
1609 return stream
.Write(eol
, wxStrlen(eol
));
1612 #endif // wxUSE_STREAMS