]>
git.saurik.com Git - wxWidgets.git/blob - src/common/stream.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxStream base classes
4 // Author: Guilhem Lavaux
8 // Copyright: (c) Guilhem Lavaux
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "stream.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
30 #include "wx/stream.h"
31 #include "wx/datstrm.h"
32 #include "wx/objstrm.h"
34 #define BUF_TEMP_SIZE 10000
36 // ----------------------------------------------------------------------------
38 // ----------------------------------------------------------------------------
40 #define CHECK_ERROR(err) \
41 if (m_stream->m_lasterror == wxStream_NOERROR) \
42 m_stream->m_lasterror = err
44 wxStreamBuffer::wxStreamBuffer(wxStreamBase
& stream
, BufMode mode
)
45 : m_buffer_start(NULL
), m_buffer_end(NULL
), m_buffer_pos(NULL
),
46 m_buffer_size(0), m_fixed(TRUE
), m_flushable(TRUE
), m_stream(&stream
),
47 m_mode(mode
), m_destroybuf(FALSE
), m_destroystream(FALSE
)
51 wxStreamBuffer::wxStreamBuffer(BufMode mode
)
52 : m_buffer_start(NULL
), m_buffer_end(NULL
), m_buffer_pos(NULL
),
53 m_buffer_size(0), m_fixed(TRUE
), m_flushable(FALSE
), m_stream(NULL
),
54 m_mode(mode
), m_destroybuf(FALSE
), m_destroystream(TRUE
)
56 m_stream
= new wxStreamBase();
59 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer
& buffer
)
61 m_buffer_start
= buffer
.m_buffer_start
;
62 m_buffer_end
= buffer
.m_buffer_end
;
63 m_buffer_pos
= buffer
.m_buffer_pos
;
64 m_buffer_size
= buffer
.m_buffer_size
;
65 m_fixed
= buffer
.m_fixed
;
66 m_flushable
= buffer
.m_flushable
;
67 m_stream
= buffer
.m_stream
;
68 m_mode
= buffer
.m_mode
;
70 m_destroystream
= FALSE
;
73 wxStreamBuffer::~wxStreamBuffer()
76 wxDELETEA(m_buffer_start
);
81 void wxStreamBuffer::SetBufferIO(char *buffer_start
, char *buffer_end
)
84 wxDELETEA(m_buffer_start
);
85 m_buffer_start
= buffer_start
;
86 m_buffer_end
= buffer_end
;
88 m_buffer_size
= m_buffer_end
-m_buffer_start
;
93 void wxStreamBuffer::SetBufferIO(size_t bufsize
)
98 wxDELETEA(m_buffer_start
);
101 m_buffer_start
= (char*)NULL
;
102 m_buffer_end
= (char*)NULL
;
103 m_buffer_pos
= (char*)NULL
;
108 b_start
= new char[bufsize
];
109 SetBufferIO(b_start
, b_start
+ bufsize
);
113 void wxStreamBuffer::ResetBuffer()
115 m_stream
->m_lasterror
= wxStream_NOERROR
;
116 m_stream
->m_lastcount
= 0;
117 if (m_mode
== read
&& m_flushable
)
118 m_buffer_pos
= m_buffer_end
;
120 m_buffer_pos
= m_buffer_start
;
123 bool wxStreamBuffer::FillBuffer()
127 count
= m_stream
->OnSysRead(m_buffer_start
, m_buffer_size
);
128 m_buffer_end
= m_buffer_start
+count
;
129 m_buffer_pos
= m_buffer_start
;
136 bool wxStreamBuffer::FlushBuffer()
138 size_t count
, current
;
140 if (m_buffer_pos
== m_buffer_start
|| !m_flushable
)
143 current
= m_buffer_pos
-m_buffer_start
;
144 count
= m_stream
->OnSysWrite(m_buffer_start
, current
);
145 if (count
!= current
)
147 m_buffer_pos
= m_buffer_start
;
152 void wxStreamBuffer::GetFromBuffer(void *buffer
, size_t size
)
154 size_t s_toget
= m_buffer_end
-m_buffer_pos
;
159 memcpy(buffer
, m_buffer_pos
, s_toget
);
160 m_buffer_pos
+= s_toget
;
163 void wxStreamBuffer::PutToBuffer(const void *buffer
, size_t size
)
165 size_t s_toput
= m_buffer_end
-m_buffer_pos
;
167 if (s_toput
< size
&& !m_fixed
) {
171 size_t delta
= m_buffer_pos
-m_buffer_start
;
173 m_buffer_start
= (char *)realloc(m_buffer_start
, m_buffer_size
+size
);
174 m_buffer_pos
= m_buffer_start
+ delta
;
176 m_buffer_size
+= size
;
177 m_buffer_end
= m_buffer_start
+m_buffer_size
;
183 memcpy(m_buffer_pos
, buffer
, s_toput
);
184 m_buffer_pos
+= s_toput
;
187 void wxStreamBuffer::PutChar(char c
)
189 wxASSERT(m_stream
!= NULL
);
191 if (!m_buffer_size
) {
192 m_stream
->OnSysWrite(&c
, 1);
196 if (GetDataLeft() == 0 && !FlushBuffer()) {
197 CHECK_ERROR(wxStream_WRITE_ERR
);
202 m_stream
->m_lastcount
= 1;
205 char wxStreamBuffer::Peek()
209 wxASSERT(m_stream
!= NULL
&& m_buffer_size
!= 0);
211 if (!GetDataLeft()) {
212 CHECK_ERROR(wxStream_READ_ERR
);
216 GetFromBuffer(&c
, 1);
222 char wxStreamBuffer::GetChar()
226 wxASSERT(m_stream
!= NULL
);
228 if (!m_buffer_size
) {
229 m_stream
->OnSysRead(&c
, 1);
233 if (!GetDataLeft()) {
234 CHECK_ERROR(wxStream_READ_ERR
);
238 GetFromBuffer(&c
, 1);
240 m_stream
->m_lastcount
= 1;
244 size_t wxStreamBuffer::Read(void *buffer
, size_t size
)
246 wxASSERT(m_stream
!= NULL
);
251 // ------------------
252 // Buffering disabled
253 // ------------------
255 m_stream
->m_lasterror
= wxStream_NOERROR
;
257 return (m_stream
->m_lastcount
+= m_stream
->OnSysRead(buffer
, size
));
262 size_t buf_left
, orig_size
= size
;
265 buf_left
= GetDataLeft();
267 // First case: the requested buffer is larger than the stream buffer,
269 if (size
> buf_left
) {
270 GetFromBuffer(buffer
, buf_left
);
272 buffer
= (char *)buffer
+ buf_left
; // ANSI C++ violation.
275 CHECK_ERROR(wxStream_EOF
);
276 return (m_stream
->m_lastcount
= orig_size
-size
);
280 // Second case: we just copy from the stream buffer.
281 GetFromBuffer(buffer
, size
);
285 return (m_stream
->m_lastcount
+= orig_size
);
288 size_t wxStreamBuffer::Read(wxStreamBuffer
*s_buf
)
290 char buf
[BUF_TEMP_SIZE
];
291 size_t s
= 0, bytes_read
= BUF_TEMP_SIZE
;
296 while (bytes_read
!= 0) {
297 bytes_read
= Read(buf
, bytes_read
);
298 bytes_read
= s_buf
->Write(buf
, bytes_read
);
304 size_t wxStreamBuffer::Write(const void *buffer
, size_t size
)
306 wxASSERT(m_stream
!= NULL
);
311 // ------------------
312 // Buffering disabled
313 // ------------------
315 m_stream
->m_lasterror
= wxStream_NOERROR
;
316 if (!m_buffer_size
&& m_fixed
)
317 return (m_stream
->m_lastcount
= m_stream
->OnSysWrite(buffer
, size
));
319 // ------------------
321 // ------------------
323 size_t buf_left
, orig_size
= size
;
326 buf_left
= m_buffer_end
- m_buffer_pos
;
328 // First case: the buffer to write is larger than the stream buffer,
330 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
331 // we always go to the second case.
332 if (size
> buf_left
&& m_fixed
) {
333 PutToBuffer(buffer
, buf_left
);
335 buffer
= (char *)buffer
+ buf_left
; // ANSI C++ violation.
337 if (!FlushBuffer()) {
338 CHECK_ERROR(wxStream_WRITE_ERR
);
339 return (m_stream
->m_lastcount
= orig_size
-size
);
342 m_buffer_pos
= m_buffer_start
;
346 // Second case: just copy it in the stream buffer.
347 PutToBuffer(buffer
, size
);
351 return (m_stream
->m_lastcount
= orig_size
);
354 size_t wxStreamBuffer::Write(wxStreamBuffer
*sbuf
)
356 char buf
[BUF_TEMP_SIZE
];
357 size_t s
= 0, bytes_count
= BUF_TEMP_SIZE
, b_count2
;
358 wxInputStream
*in_stream
;
363 in_stream
= (wxInputStream
*)sbuf
->Stream();
365 while (bytes_count
== BUF_TEMP_SIZE
) {
366 b_count2
= sbuf
->Read(buf
, bytes_count
);
367 bytes_count
= Write(buf
, b_count2
);
368 if (b_count2
> bytes_count
)
369 in_stream
->Ungetch(buf
+bytes_count
, b_count2
-bytes_count
);
375 off_t
wxStreamBuffer::Seek(off_t pos
, wxSeekMode mode
)
377 off_t ret_off
, diff
, last_access
;
379 last_access
= GetLastAccess();
383 case wxFromStart
: diff
= pos
; break;
384 case wxFromCurrent
: diff
= pos
+ GetIntPosition(); break;
385 case wxFromEnd
: diff
= pos
+ last_access
; break;
386 default: return wxInvalidOffset
;
388 if (diff
< 0 || diff
> last_access
)
389 return wxInvalidOffset
;
390 SetIntPosition(diff
);
396 // We'll try to compute an internal position later ...
397 ret_off
= m_stream
->OnSysSeek(pos
, wxFromStart
);
401 case wxFromCurrent
: {
402 diff
= pos
+ GetIntPosition();
404 if ( (diff
> last_access
) || (diff
< 0) ) {
405 // We must take into account the fact that we have read something
407 ret_off
= m_stream
->OnSysSeek(diff
-last_access
, wxFromCurrent
);
411 SetIntPosition(diff
);
416 // Hard to compute: always seek to the requested position.
417 ret_off
= m_stream
->OnSysSeek(pos
, wxFromEnd
);
421 return wxInvalidOffset
;
424 off_t
wxStreamBuffer::Tell() const
426 off_t pos
= m_stream
->OnSysTell();
427 if (pos
== wxInvalidOffset
)
428 return wxInvalidOffset
;
430 pos
+= GetIntPosition();
432 if (m_mode
== read
&& m_flushable
)
433 pos
-= GetLastAccess();
438 size_t wxStreamBuffer::GetDataLeft()
440 /* Why is this done? RR. */
441 if (m_buffer_end
== m_buffer_pos
&& m_flushable
)
444 return m_buffer_end
-m_buffer_pos
;
447 // ----------------------------------------------------------------------------
449 // ----------------------------------------------------------------------------
451 wxStreamBase::wxStreamBase()
453 m_lasterror
= wxStream_NOERROR
;
457 wxStreamBase::~wxStreamBase()
461 size_t wxStreamBase::OnSysRead(void *WXUNUSED(buffer
), size_t WXUNUSED(size
))
466 size_t wxStreamBase::OnSysWrite(const void *WXUNUSED(buffer
), size_t WXUNUSED(bufsize
))
471 off_t
wxStreamBase::OnSysSeek(off_t
WXUNUSED(seek
), wxSeekMode
WXUNUSED(mode
))
473 return wxInvalidOffset
;
476 off_t
wxStreamBase::OnSysTell() const
478 return wxInvalidOffset
;
481 // ----------------------------------------------------------------------------
483 // ----------------------------------------------------------------------------
485 wxInputStream::wxInputStream()
487 m_wback(NULL
), m_wbacksize(0), m_wbackcur(0)
491 wxInputStream::~wxInputStream()
497 bool wxInputStream::Eof() const
499 wxInputStream
*self
= (wxInputStream
*)this; // const_cast
503 if ( GetLastError() == wxSTREAM_EOF
)
513 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
515 /* get number of bytes left from previous wback buffer */
516 size_t toget
= m_wbacksize
- m_wbackcur
;
518 /* allocate a buffer large enough to hold prev + new data */
519 char *temp_b
= (char *) malloc(needed_size
+ toget
);
524 /* copy previous data (and free old buffer) if needed */
527 memmove(temp_b
+ needed_size
, m_wback
+ m_wbackcur
, toget
);
534 m_wbacksize
= needed_size
+ toget
;
536 return (char *) m_wback
;
539 size_t wxInputStream::GetWBack(char *buf
, size_t bsize
)
541 size_t s_toget
= m_wbacksize
-m_wbackcur
;
549 memcpy(buf
, (m_wback
+m_wbackcur
), s_toget
);
551 m_wbackcur
+= s_toget
;
552 if (m_wbackcur
== m_wbacksize
)
555 m_wback
= (char *)NULL
;
563 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
565 char *ptrback
= AllocSpaceWBack(bufsize
);
569 memcpy(ptrback
, buf
, bufsize
);
573 bool wxInputStream::Ungetch(char c
)
575 char * ptrback
= AllocSpaceWBack(1);
583 char wxInputStream::GetC()
590 wxInputStream
& wxInputStream::Read(void *buffer
, size_t size
)
592 char *buf
= (char *)buffer
;
594 size_t retsize
= GetWBack(buf
, size
);
598 m_lasterror
= wxStream_NOERROR
;
604 m_lastcount
= OnSysRead(buf
, size
) + retsize
;
608 char wxInputStream::Peek()
612 if (m_lasterror
== wxStream_NOERROR
)
621 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
623 char buf
[BUF_TEMP_SIZE
];
624 size_t bytes_read
= BUF_TEMP_SIZE
;
626 while (bytes_read
== BUF_TEMP_SIZE
)
628 bytes_read
= Read(buf
, bytes_read
).LastRead();
629 bytes_read
= stream_out
.Write(buf
, bytes_read
).LastWrite();
634 off_t
wxInputStream::SeekI(off_t pos
, wxSeekMode mode
)
636 /* Should be check and improve, just to remove a slight bug !
637 I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
638 if (m_lasterror
==wxSTREAM_EOF
)
639 m_lasterror
=wxSTREAM_NOERROR
;
641 /* A call to SeekI() will automatically invalidate any previous call
642 to Ungetch(), otherwise it would be possible to SeekI() to one
643 one position, unread some bytes there, SeekI() to another position
644 and the data would be corrupted.
646 GRG: Could add code here to try to navigate within the wback
647 buffer if possible, but is it really needed? It would only work
648 when seeking in wxFromCurrent mode, else it would invalidate
654 m_wback
= (char*) NULL
;
659 return OnSysSeek(pos
, mode
);
662 off_t
wxInputStream::TellI() const
664 /* GRG: Changed to make it compatible with the wback buffer */
665 off_t pos
= OnSysTell();
667 if (pos
!= wxInvalidOffset
)
668 pos
-= (m_wbacksize
- m_wbackcur
);
673 // --------------------
674 // Overloaded operators
675 // --------------------
678 wxInputStream
& wxInputStream::operator>>(wxObject
*& obj
)
680 wxObjectInputStream
obj_s(*this);
681 obj
= obj_s
.LoadObject();
687 // ----------------------------------------------------------------------------
689 // ----------------------------------------------------------------------------
690 wxOutputStream::wxOutputStream()
695 wxOutputStream::~wxOutputStream()
699 void wxOutputStream::PutC(char c
)
701 Write((void *) &c
, 1);
704 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
706 m_lastcount
= OnSysWrite(buffer
, size
);
710 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
712 stream_in
.Read(*this);
716 off_t
wxOutputStream::TellO() const
721 off_t
wxOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
723 return OnSysSeek(pos
, mode
);
726 void wxOutputStream::Sync()
731 wxOutputStream
& wxOutputStream::operator<<(wxObject
& obj
)
733 wxObjectOutputStream
obj_s(*this);
734 obj_s
.SaveObject(obj
);
739 // ----------------------------------------------------------------------------
740 // wxCountingOutputStream
741 // ----------------------------------------------------------------------------
743 wxCountingOutputStream::wxCountingOutputStream ()
749 size_t wxCountingOutputStream::GetSize() const
754 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
), size_t size
)
756 m_currentPos
+= size
;
757 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
761 off_t
wxCountingOutputStream::OnSysSeek(off_t pos
, wxSeekMode mode
)
763 if (mode
== wxFromStart
)
765 if (mode
== wxFromEnd
)
766 m_currentPos
= m_lastcount
+ pos
;
770 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
775 off_t
wxCountingOutputStream::OnSysTell() const
780 // ----------------------------------------------------------------------------
781 // wxFilterInputStream
782 // ----------------------------------------------------------------------------
784 wxFilterInputStream::wxFilterInputStream()
789 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
792 m_parent_i_stream
= &stream
;
795 wxFilterInputStream::~wxFilterInputStream()
799 // ----------------------------------------------------------------------------
800 // wxFilterOutputStream
801 // ----------------------------------------------------------------------------
802 wxFilterOutputStream::wxFilterOutputStream()
807 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
810 m_parent_o_stream
= &stream
;
813 wxFilterOutputStream::~wxFilterOutputStream()
817 // ----------------------------------------------------------------------------
818 // wxBufferedInputStream
819 // ----------------------------------------------------------------------------
820 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& s
)
821 : wxFilterInputStream(s
)
823 m_i_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::read
);
824 m_i_streambuf
->SetBufferIO(1024);
827 wxBufferedInputStream::~wxBufferedInputStream()
829 off_t unused_bytes
=m_i_streambuf
->GetBufferPos()-m_i_streambuf
->GetBufferEnd();
830 m_parent_i_stream
->SeekI(unused_bytes
,wxFromCurrent
);
832 delete m_i_streambuf
;
835 char wxBufferedInputStream::Peek()
837 return m_i_streambuf
->Peek();
840 wxInputStream
& wxBufferedInputStream::Read(void *buffer
, size_t size
)
843 char *buf
= (char *)buffer
;
845 retsize
= GetWBack(buf
, size
);
846 m_lastcount
= retsize
;
849 m_lasterror
= wxStream_NOERROR
;
855 m_i_streambuf
->Read(buf
, size
);
860 off_t
wxBufferedInputStream::SeekI(off_t pos
, wxSeekMode mode
)
862 return m_i_streambuf
->Seek(pos
, mode
);
865 off_t
wxBufferedInputStream::TellI() const
867 return m_i_streambuf
->Tell();
870 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
872 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
875 off_t
wxBufferedInputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
877 return m_parent_i_stream
->SeekI(seek
, mode
);
880 off_t
wxBufferedInputStream::OnSysTell() const
882 return m_parent_i_stream
->TellI();
886 // ----------------------------------------------------------------------------
887 // wxBufferedOutputStream
888 // ----------------------------------------------------------------------------
890 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& s
)
891 : wxFilterOutputStream(s
)
893 m_o_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::write
);
894 m_o_streambuf
->SetBufferIO(1024);
897 wxBufferedOutputStream::~wxBufferedOutputStream()
900 delete m_o_streambuf
;
903 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
906 m_o_streambuf
->Write(buffer
, size
);
910 off_t
wxBufferedOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
913 return m_o_streambuf
->Seek(pos
, mode
);
916 off_t
wxBufferedOutputStream::TellO() const
918 return m_o_streambuf
->Tell();
921 void wxBufferedOutputStream::Sync()
923 m_o_streambuf
->FlushBuffer();
924 m_parent_o_stream
->Sync();
927 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
929 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
932 off_t
wxBufferedOutputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
934 return m_parent_o_stream
->SeekO(seek
, mode
);
937 off_t
wxBufferedOutputStream::OnSysTell() const
939 return m_parent_o_stream
->TellO();
942 size_t wxBufferedOutputStream::GetSize() const
944 return m_parent_o_stream
->GetSize() + m_o_streambuf
->GetIntPosition();
947 // ----------------------------------------------------------------------------
948 // Some IOManip function
949 // ----------------------------------------------------------------------------
951 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
954 return stream
.Write("\r\n", 2);
957 return stream
.Write("\r", 1);
959 return stream
.Write("\n", 1);