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 wxFileOffset
wxInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
918 // RR: This code is duplicated in wxBufferedInputStream. This is
919 // not really a good design, but buffered stream are different
920 // from all others in that they handle two stream-related objects:
921 // the stream buffer and parent stream.
923 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
924 if (m_lasterror
==wxSTREAM_EOF
)
925 m_lasterror
=wxSTREAM_NO_ERROR
;
927 // avoid unnecessary seek operations (optimization)
928 wxFileOffset currentPos
= TellI(), size
= GetLength();
929 if ((mode
== wxFromStart
&& currentPos
== pos
) ||
930 (mode
== wxFromCurrent
&& pos
== 0) ||
931 (mode
== wxFromEnd
&& size
!= wxInvalidOffset
&& currentPos
== size
-pos
))
934 if (!IsSeekable() && mode
== wxFromCurrent
&& pos
> 0)
936 // rather than seeking, we can just read data and discard it;
937 // this allows to forward-seek also non-seekable streams!
938 char buf
[BUF_TEMP_SIZE
];
941 // read chunks of BUF_TEMP_SIZE bytes until we reach the new position
942 for ( ; pos
>= BUF_TEMP_SIZE
; pos
-= bytes_read
)
944 bytes_read
= Read(buf
, WXSIZEOF(buf
)).LastRead();
945 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
946 return wxInvalidOffset
;
948 wxASSERT(bytes_read
== WXSIZEOF(buf
));
951 // read the last 'pos' bytes
952 bytes_read
= Read(buf
, (size_t)pos
).LastRead();
953 if ( m_lasterror
!= wxSTREAM_NO_ERROR
)
954 return wxInvalidOffset
;
956 wxASSERT(bytes_read
== (size_t)pos
);
958 // we should now have sought to the right position...
962 /* RR: A call to SeekI() will automatically invalidate any previous
963 call to Ungetch(), otherwise it would be possible to SeekI() to
964 one position, unread some bytes there, SeekI() to another position
965 and the data would be corrupted.
967 GRG: Could add code here to try to navigate within the wback
968 buffer if possible, but is it really needed? It would only work
969 when seeking in wxFromCurrent mode, else it would invalidate
974 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
982 return OnSysSeek(pos
, mode
);
985 wxFileOffset
wxInputStream::TellI() const
987 wxFileOffset pos
= OnSysTell();
989 if (pos
!= wxInvalidOffset
)
990 pos
-= (m_wbacksize
- m_wbackcur
);
996 // ----------------------------------------------------------------------------
998 // ----------------------------------------------------------------------------
1000 IMPLEMENT_ABSTRACT_CLASS(wxOutputStream
, wxStreamBase
)
1002 wxOutputStream::wxOutputStream()
1006 wxOutputStream::~wxOutputStream()
1010 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer
),
1011 size_t WXUNUSED(bufsize
))
1016 void wxOutputStream::PutC(char c
)
1018 Write(&c
, sizeof(c
));
1021 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
1023 m_lastcount
= OnSysWrite(buffer
, size
);
1027 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
1029 stream_in
.Read(*this);
1033 wxFileOffset
wxOutputStream::TellO() const
1038 wxFileOffset
wxOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1040 return OnSysSeek(pos
, mode
);
1043 void wxOutputStream::Sync()
1048 // ----------------------------------------------------------------------------
1049 // wxCountingOutputStream
1050 // ----------------------------------------------------------------------------
1052 IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream
, wxOutputStream
)
1054 wxCountingOutputStream::wxCountingOutputStream ()
1059 wxFileOffset
wxCountingOutputStream::GetLength() const
1064 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
),
1067 m_currentPos
+= size
;
1068 if (m_currentPos
> m_lastcount
)
1069 m_lastcount
= m_currentPos
;
1071 return m_currentPos
;
1074 wxFileOffset
wxCountingOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1076 ssize_t new_pos
= wx_truncate_cast(ssize_t
, pos
);
1081 wxCHECK_MSG( (wxFileOffset
)new_pos
== pos
, wxInvalidOffset
, wxT("huge position not supported") );
1085 new_pos
= m_lastcount
+ new_pos
;
1086 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_lastcount
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1090 new_pos
= m_currentPos
+ new_pos
;
1091 wxCHECK_MSG( (wxFileOffset
)new_pos
== (wxFileOffset
)(m_currentPos
+ pos
), wxInvalidOffset
, wxT("huge position not supported") );
1095 wxFAIL_MSG( wxT("invalid seek mode") );
1096 return wxInvalidOffset
;
1099 m_currentPos
= new_pos
;
1101 if (m_currentPos
> m_lastcount
)
1102 m_lastcount
= m_currentPos
;
1104 return m_currentPos
;
1107 wxFileOffset
wxCountingOutputStream::OnSysTell() const
1109 return m_currentPos
;
1112 // ----------------------------------------------------------------------------
1113 // wxFilterInputStream
1114 // ----------------------------------------------------------------------------
1116 IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream
, wxInputStream
)
1118 wxFilterInputStream::wxFilterInputStream()
1119 : m_parent_i_stream(NULL
),
1124 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
1125 : m_parent_i_stream(&stream
),
1130 wxFilterInputStream::wxFilterInputStream(wxInputStream
*stream
)
1131 : m_parent_i_stream(stream
),
1136 wxFilterInputStream::~wxFilterInputStream()
1139 delete m_parent_i_stream
;
1142 // ----------------------------------------------------------------------------
1143 // wxFilterOutputStream
1144 // ----------------------------------------------------------------------------
1146 IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream
, wxOutputStream
)
1148 wxFilterOutputStream::wxFilterOutputStream()
1149 : m_parent_o_stream(NULL
),
1154 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
1155 : m_parent_o_stream(&stream
),
1160 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
*stream
)
1161 : m_parent_o_stream(stream
),
1166 bool wxFilterOutputStream::Close()
1168 if (m_parent_o_stream
&& m_owns
)
1169 return m_parent_o_stream
->Close();
1174 wxFilterOutputStream::~wxFilterOutputStream()
1177 delete m_parent_o_stream
;
1180 // ----------------------------------------------------------------------------
1181 // wxFilterClassFactoryBase
1182 // ----------------------------------------------------------------------------
1184 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase
, wxObject
)
1186 wxString
wxFilterClassFactoryBase::PopExtension(const wxString
& location
) const
1188 return location
.substr(0, FindExtension(location
));
1191 wxString::size_type
wxFilterClassFactoryBase::FindExtension(
1192 const wxString
& location
) const
1194 for (const wxChar
*const *p
= GetProtocols(wxSTREAM_FILEEXT
); *p
; p
++)
1196 if ( location
.EndsWith(*p
) )
1197 return location
.length() - wxStrlen(*p
);
1200 return wxString::npos
;
1203 bool wxFilterClassFactoryBase::CanHandle(const wxString
& protocol
,
1204 wxStreamProtocolType type
) const
1206 if (type
== wxSTREAM_FILEEXT
)
1207 return FindExtension(protocol
) != wxString::npos
;
1209 for (const wxChar
*const *p
= GetProtocols(type
); *p
; p
++)
1216 // ----------------------------------------------------------------------------
1217 // wxFilterClassFactory
1218 // ----------------------------------------------------------------------------
1220 IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory
, wxFilterClassFactoryBase
)
1222 wxFilterClassFactory
*wxFilterClassFactory::sm_first
= NULL
;
1224 void wxFilterClassFactory::Remove()
1228 wxFilterClassFactory
**pp
= &sm_first
;
1231 pp
= &(*pp
)->m_next
;
1239 // ----------------------------------------------------------------------------
1240 // wxBufferedInputStream
1241 // ----------------------------------------------------------------------------
1246 // helper function used for initializing the buffer used by
1247 // wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1248 // not NULL or creates a buffer of the given size otherwise
1249 template <typename T
>
1251 CreateBufferIfNeeded(T
& stream
, wxStreamBuffer
*buffer
, size_t bufsize
= 1024)
1253 return buffer
? buffer
: new wxStreamBuffer(bufsize
, stream
);
1256 } // anonymous namespace
1258 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1259 wxStreamBuffer
*buffer
)
1260 : wxFilterInputStream(stream
)
1262 m_i_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1265 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& stream
,
1267 : wxFilterInputStream(stream
)
1269 m_i_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1272 wxBufferedInputStream::~wxBufferedInputStream()
1274 m_parent_i_stream
->SeekI(-(wxFileOffset
)m_i_streambuf
->GetBytesLeft(),
1277 delete m_i_streambuf
;
1280 char wxBufferedInputStream::Peek()
1282 return m_i_streambuf
->Peek();
1285 wxInputStream
& wxBufferedInputStream::Read(void *buf
, size_t size
)
1287 // reset the error flag
1290 // first read from the already cached data
1291 m_lastcount
= GetWBack(buf
, size
);
1293 // do we have to read anything more?
1294 if ( m_lastcount
< size
)
1296 size
-= m_lastcount
;
1297 buf
= (char *)buf
+ m_lastcount
;
1299 // the call to wxStreamBuffer::Read() below may reset our m_lastcount
1300 // (but it also may not do it if the buffer is associated to another
1301 // existing stream and wasn't created by us), so save it
1302 size_t countOld
= m_lastcount
;
1304 // the new count of the bytes read is the count of bytes read this time
1305 m_lastcount
= m_i_streambuf
->Read(buf
, size
);
1307 // plus those we had read before
1308 m_lastcount
+= countOld
;
1314 wxFileOffset
wxBufferedInputStream::SeekI(wxFileOffset pos
, wxSeekMode mode
)
1316 // RR: Look at wxInputStream for comments.
1318 if (m_lasterror
==wxSTREAM_EOF
)
1323 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1331 return m_i_streambuf
->Seek(pos
, mode
);
1334 wxFileOffset
wxBufferedInputStream::TellI() const
1336 wxFileOffset pos
= m_i_streambuf
->Tell();
1338 if (pos
!= wxInvalidOffset
)
1339 pos
-= (m_wbacksize
- m_wbackcur
);
1344 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
1346 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
1349 wxFileOffset
wxBufferedInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1351 return m_parent_i_stream
->SeekI(seek
, mode
);
1354 wxFileOffset
wxBufferedInputStream::OnSysTell() const
1356 return m_parent_i_stream
->TellI();
1359 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer
*buffer
)
1361 wxCHECK_RET( buffer
, wxT("wxBufferedInputStream needs buffer") );
1363 delete m_i_streambuf
;
1364 m_i_streambuf
= buffer
;
1367 // ----------------------------------------------------------------------------
1368 // wxBufferedOutputStream
1369 // ----------------------------------------------------------------------------
1371 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1372 wxStreamBuffer
*buffer
)
1373 : wxFilterOutputStream(stream
)
1375 m_o_streambuf
= CreateBufferIfNeeded(*this, buffer
);
1378 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& stream
,
1380 : wxFilterOutputStream(stream
)
1382 m_o_streambuf
= CreateBufferIfNeeded(*this, NULL
, bufsize
);
1385 wxBufferedOutputStream::~wxBufferedOutputStream()
1388 delete m_o_streambuf
;
1391 bool wxBufferedOutputStream::Close()
1398 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
1401 m_o_streambuf
->Write(buffer
, size
);
1405 wxFileOffset
wxBufferedOutputStream::SeekO(wxFileOffset pos
, wxSeekMode mode
)
1408 return m_o_streambuf
->Seek(pos
, mode
);
1411 wxFileOffset
wxBufferedOutputStream::TellO() const
1413 return m_o_streambuf
->Tell();
1416 void wxBufferedOutputStream::Sync()
1418 m_o_streambuf
->FlushBuffer();
1419 m_parent_o_stream
->Sync();
1422 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
1424 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
1427 wxFileOffset
wxBufferedOutputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
)
1429 return m_parent_o_stream
->SeekO(seek
, mode
);
1432 wxFileOffset
wxBufferedOutputStream::OnSysTell() const
1434 return m_parent_o_stream
->TellO();
1437 wxFileOffset
wxBufferedOutputStream::GetLength() const
1439 return m_parent_o_stream
->GetLength() + m_o_streambuf
->GetIntPosition();
1442 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer
*buffer
)
1444 wxCHECK_RET( buffer
, wxT("wxBufferedOutputStream needs buffer") );
1446 delete m_o_streambuf
;
1447 m_o_streambuf
= buffer
;
1450 // ---------------------------------------------------------------------------
1451 // wxWrapperInputStream implementation
1452 // ---------------------------------------------------------------------------
1454 wxWrapperInputStream::wxWrapperInputStream()
1456 m_lasterror
= wxSTREAM_READ_ERROR
;
1459 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
& stream
)
1460 : wxFilterInputStream(stream
)
1462 SynchronizeLastError();
1465 wxWrapperInputStream::wxWrapperInputStream(wxInputStream
*stream
)
1466 : wxFilterInputStream(stream
)
1468 if ( m_parent_i_stream
)
1469 SynchronizeLastError();
1471 m_lasterror
= wxSTREAM_READ_ERROR
;
1474 void wxWrapperInputStream::InitParentStream(wxInputStream
& stream
)
1476 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1478 m_parent_i_stream
= &stream
;
1480 SynchronizeLastError();
1483 void wxWrapperInputStream::InitParentStream(wxInputStream
* stream
)
1485 wxCHECK_RET( !m_parent_i_stream
, "Can't init parent stream twice" );
1487 m_parent_i_stream
= stream
;
1489 if ( m_parent_i_stream
)
1493 SynchronizeLastError();
1497 wxFileOffset
wxWrapperInputStream::GetLength() const
1499 wxCHECK_MSG(m_parent_i_stream
, wxInvalidOffset
, "Stream not valid");
1501 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1502 return m_parent_i_stream
->GetLength();
1505 bool wxWrapperInputStream::IsSeekable() const
1507 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1508 return m_parent_i_stream
->IsSeekable();
1511 size_t wxWrapperInputStream::OnSysRead(void *buffer
, size_t size
)
1513 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1515 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1517 m_parent_i_stream
->Read(buffer
, size
);
1518 return m_parent_i_stream
->LastRead();
1521 wxFileOffset
wxWrapperInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
1523 wxCHECK_MSG(IsSeekable(), false, "Stream not seekable");
1525 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1526 return m_parent_i_stream
->SeekI (pos
, mode
);
1529 wxFileOffset
wxWrapperInputStream::OnSysTell() const
1531 wxCHECK_MSG(m_parent_i_stream
, false, "Stream not valid");
1533 wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError
);
1534 return m_parent_i_stream
->TellI();
1537 // ----------------------------------------------------------------------------
1538 // Some IOManip function
1539 // ----------------------------------------------------------------------------
1541 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
1543 static const wxChar
*eol
= wxTextFile::GetEOL();
1545 return stream
.Write(eol
, wxStrlen(eol
));
1548 #endif // wxUSE_STREAMS