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 ()
1124 wxFileOffset
wxCountingOutputStream::GetLength() const
1129 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1132 m_currentPos
+= size
;
1133 if ( m_currentPos
> m_lastPos
)
1134 m_lastPos
= m_currentPos
;
1139 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1141 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1146 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1150 new_pos
+= m_lastPos
;
1151 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1155 new_pos
+= m_currentPos
;
1156 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1160 wxFAIL_MSG( wxT("invalid seek mode") );
1161 return wxInvalidOffset
;
1164 m_currentPos
= new_pos
;
1166 if ( m_currentPos
> m_lastPos
)
1167 m_lastPos
= m_currentPos
;
1169 return m_currentPos
;
1172 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1174 return m_currentPos
;
1177 // ----------------------------------------------------------------------------
1178 // wxFilterInputStream
1179 // ----------------------------------------------------------------------------
1181 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1183 wxFilterInputStream::wxFilterInputStream()
1184 : m_parent_i_stream(NULL
),
1189 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1190 : m_parent_i_stream(&stream
),
1195 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1196 : m_parent_i_stream(stream
),
1201 wxFilterInputStream::~wxFilterInputStream()
1204 delete m_parent_i_stream
;
1207 // ----------------------------------------------------------------------------
1208 // wxFilterOutputStream
1209 // ----------------------------------------------------------------------------
1211 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1213 wxFilterOutputStream::wxFilterOutputStream()
1214 : m_parent_o_stream(NULL
),
1219 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1220 : m_parent_o_stream(&stream
),
1225 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1226 : m_parent_o_stream(stream
),
1231 bool wxFilterOutputStream::Close()
1233 if (m_parent_o_stream
&& m_owns
)
1234 return m_parent_o_stream
->Close();
1239 wxFilterOutputStream::~wxFilterOutputStream()
1242 delete m_parent_o_stream
;
1245 // ----------------------------------------------------------------------------
1246 // wxFilterClassFactoryBase
1247 // ----------------------------------------------------------------------------
1249 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1251 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1253 return location
.substr(0, FindExtension(location
));
1256 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1257 const wxString
& location
) const
1259 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1261 if ( location
.EndsWith(*p
) )
1262 return location
.length() - wxStrlen(*p
);
1265 return wxString::npos
;
1268 bool wxFilterClassFactoryBase::CanHandle(const wxString
& protocol
,
1269 wxStreamProtocolType type
) const
1271 if (type
== wxSTREAM_FILEEXT
)
1272 return FindExtension(protocol
) != wxString::npos
;
1274 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1281 // ----------------------------------------------------------------------------
1282 // wxFilterClassFactory
1283 // ----------------------------------------------------------------------------
1285 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1287 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1289 void wxFilterClassFactory::Remove()
1293 wxFilterClassFactory
**pp
= &sm_first
;
1296 pp
= &(*pp
)->m_next
;
1304 // ----------------------------------------------------------------------------
1305 // wxBufferedInputStream
1306 // ----------------------------------------------------------------------------
1311 // helper function used for initializing the buffer used by
1312 // wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1313 // not NULL or creates a buffer of the given size otherwise
1314 template <typename T
>
1316 CreateBufferIfNeeded(T
& stream
, wxStreamBuffer
*buffer
, size_t bufsize
= 1024)
1318 return buffer
? buffer
: new wxStreamBuffer(bufsize
, stream
);
1321 } // anonymous namespace
1323 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1324 wxStreamBuffer
*buffer
)
1325 : wxFilterInputStream(stream
)
1327 m_i_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1330 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1332 : wxFilterInputStream(stream
)
1334 m_i_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1337 wxBufferedInputStream::~wxBufferedInputStream()
1339 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1342 delete m_i_streambuf
;
1345 char wxBufferedInputStream::Peek()
1347 return m_i_streambuf
->Peek();
1350 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1352 // reset the error flag
1355 // first read from the already cached data
1356 m_lastcount
= GetWBack(buf
, size
);
1358 // do we have to read anything more?
1359 if ( m_lastcount
< size
)
1361 size
-= m_lastcount
;
1362 buf
= (char *)buf
+ m_lastcount
;
1364 // the call to wxStreamBuffer::Read() below may reset our m_lastcount
1365 // (but it also may not do it if the buffer is associated to another
1366 // existing stream and wasn't created by us), so save it
1367 size_t countOld
= m_lastcount
;
1369 // the new count of the bytes read is the count of bytes read this time
1370 m_lastcount
= m_i_streambuf
->Read(buf
, size
);
1372 // plus those we had read before
1373 m_lastcount
+= countOld
;
1379 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1381 // RR: Look at wxInputStream for comments.
1383 if (m_lasterror
==wxSTREAM_EOF
)
1388 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1396 return m_i_streambuf
->Seek(pos
, mode
);
1399 wxFileOffset
wxBufferedInputStream::TellI() const
1401 wxFileOffset pos
= m_i_streambuf
->Tell();
1403 if (pos
!= wxInvalidOffset
)
1404 pos
-= (m_wbacksize
- m_wbackcur
);
1409 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1411 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1414 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1416 return m_parent_i_stream
->SeekI(seek
, mode
);
1419 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1421 return m_parent_i_stream
->TellI();
1424 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1426 wxCHECK_RET( buffer
, wxT("wxBufferedInputStream needs buffer") );
1428 delete m_i_streambuf
;
1429 m_i_streambuf
= buffer
;
1432 // ----------------------------------------------------------------------------
1433 // wxBufferedOutputStream
1434 // ----------------------------------------------------------------------------
1436 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1437 wxStreamBuffer
*buffer
)
1438 : wxFilterOutputStream(stream
)
1440 m_o_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1443 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1445 : wxFilterOutputStream(stream
)
1447 m_o_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1450 wxBufferedOutputStream::~wxBufferedOutputStream()
1453 delete m_o_streambuf
;
1456 bool wxBufferedOutputStream::Close()
1463 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1466 m_o_streambuf
->Write(buffer
, size
);
1470 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1473 return m_o_streambuf
->Seek(pos
, mode
);
1476 wxFileOffset
wxBufferedOutputStream::TellO() const
1478 return m_o_streambuf
->Tell();
1481 void wxBufferedOutputStream::Sync()
1483 m_o_streambuf
->FlushBuffer();
1484 m_parent_o_stream
->Sync();
1487 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1489 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1492 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1494 return m_parent_o_stream
->SeekO(seek
, mode
);
1497 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1499 return m_parent_o_stream
->TellO();
1502 wxFileOffset
wxBufferedOutputStream::GetLength() const
1504 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1507 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1509 wxCHECK_RET( buffer
, wxT("wxBufferedOutputStream needs buffer") );
1511 delete m_o_streambuf
;
1512 m_o_streambuf
= buffer
;
1515 // ---------------------------------------------------------------------------
1516 // wxWrapperInputStream implementation
1517 // ---------------------------------------------------------------------------
1519 wxWrapperInputStream::wxWrapperInputStream()
1521 m_lasterror
= wxSTREAM_READ_ERROR
;
1524 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
& stream
)
1525 : wxFilterInputStream(stream
)
1527 SynchronizeLastError();
1530 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
*stream
)
1531 : wxFilterInputStream(stream
)
1533 if ( m_parent_i_stream
)
1534 SynchronizeLastError();
1536 m_lasterror
= wxSTREAM_READ_ERROR
;
1539 void wxWrapperInputStream::InitParentStream(wxInputStream
& stream
)
1541 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1543 m_parent_i_stream
= &stream
;
1545 SynchronizeLastError();
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 if ( m_parent_i_stream
)
1558 SynchronizeLastError();
1562 wxFileOffset
wxWrapperInputStream::GetLength() const
1564 wxCHECK_MSG(m_parent_i_stream
, wxInvalidOffset
, "Stream not valid");
1566 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1567 return m_parent_i_stream
->GetLength();
1570 bool wxWrapperInputStream::IsSeekable() const
1572 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1573 return m_parent_i_stream
->IsSeekable();
1576 size_t wxWrapperInputStream::OnSysRead(void *buffer
, size_t size
)
1578 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1580 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1582 m_parent_i_stream
->Read(buffer
, size
);
1583 return m_parent_i_stream
->LastRead();
1586 wxFileOffset
wxWrapperInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1588 wxCHECK_MSG(IsSeekable(), false, "Stream not seekable");
1590 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1591 return m_parent_i_stream
->SeekI (pos
, mode
);
1594 wxFileOffset
wxWrapperInputStream::OnSysTell() const
1596 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1598 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1599 return m_parent_i_stream
->TellI();
1602 // ----------------------------------------------------------------------------
1603 // Some IOManip function
1604 // ----------------------------------------------------------------------------
1606 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1608 static const wxChar
*eol
= wxTextFile::GetEOL();
1610 return stream
.Write(eol
, wxStrlen(eol
));
1613 #endif // wxUSE_STREAMS