]>
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 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
499 /* get number of bytes left from previous wback buffer */
500 size_t toget
= m_wbacksize
- m_wbackcur
;
502 /* allocate a buffer large enough to hold prev + new data */
503 char *temp_b
= (char *) malloc(needed_size
+ toget
);
508 /* copy previous data (and free old buffer) if needed */
511 memmove(temp_b
+ needed_size
, m_wback
+ m_wbackcur
, toget
);
518 m_wbacksize
= needed_size
+ toget
;
520 return (char *) m_wback
;
523 size_t wxInputStream::GetWBack(char *buf
, size_t bsize
)
525 size_t s_toget
= m_wbacksize
-m_wbackcur
;
533 memcpy(buf
, (m_wback
+m_wbackcur
), s_toget
);
535 m_wbackcur
+= s_toget
;
536 if (m_wbackcur
== m_wbacksize
)
539 m_wback
= (char *)NULL
;
547 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
549 char *ptrback
= AllocSpaceWBack(bufsize
);
553 memcpy(ptrback
, buf
, bufsize
);
557 bool wxInputStream::Ungetch(char c
)
559 char * ptrback
= AllocSpaceWBack(1);
567 char wxInputStream::GetC()
574 wxInputStream
& wxInputStream::Read(void *buffer
, size_t size
)
576 char *buf
= (char *)buffer
;
578 size_t retsize
= GetWBack(buf
, size
);
582 m_lasterror
= wxStream_NOERROR
;
588 m_lastcount
= OnSysRead(buf
, size
) + retsize
;
592 char wxInputStream::Peek()
596 if (m_lasterror
== wxStream_NOERROR
)
605 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
607 char buf
[BUF_TEMP_SIZE
];
608 size_t bytes_read
= BUF_TEMP_SIZE
;
610 while (bytes_read
== BUF_TEMP_SIZE
)
612 bytes_read
= Read(buf
, bytes_read
).LastRead();
613 bytes_read
= stream_out
.Write(buf
, bytes_read
).LastWrite();
618 off_t
wxInputStream::SeekI(off_t pos
, wxSeekMode mode
)
620 /* Should be check and improve, just to remove a slight bug !
621 I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
622 if (m_lasterror
==wxSTREAM_EOF
)
623 m_lasterror
=wxSTREAM_NOERROR
;
625 /* A call to SeekI() will automatically invalidate any previous call
626 to Ungetch(), otherwise it would be possible to SeekI() to one
627 one position, unread some bytes there, SeekI() to another position
628 and the data would be corrupted.
630 GRG: Could add code here to try to navigate within the wback
631 buffer if possible, but is it really needed? It would only work
632 when seeking in wxFromCurrent mode, else it would invalidate
638 m_wback
= (char*) NULL
;
643 return OnSysSeek(pos
, mode
);
646 off_t
wxInputStream::TellI() const
648 /* GRG: Changed to make it compatible with the wback buffer */
649 off_t pos
= OnSysTell();
651 if (pos
!= wxInvalidOffset
)
652 pos
-= (m_wbacksize
- m_wbackcur
);
657 // --------------------
658 // Overloaded operators
659 // --------------------
662 wxInputStream
& wxInputStream::operator>>(wxObject
*& obj
)
664 wxObjectInputStream
obj_s(*this);
665 obj
= obj_s
.LoadObject();
671 // ----------------------------------------------------------------------------
673 // ----------------------------------------------------------------------------
674 wxOutputStream::wxOutputStream()
679 wxOutputStream::~wxOutputStream()
683 void wxOutputStream::PutC(char c
)
685 Write((void *) &c
, 1);
688 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
690 m_lastcount
= OnSysWrite(buffer
, size
);
694 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
696 stream_in
.Read(*this);
700 off_t
wxOutputStream::TellO() const
705 off_t
wxOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
707 return OnSysSeek(pos
, mode
);
710 void wxOutputStream::Sync()
715 wxOutputStream
& wxOutputStream::operator<<(wxObject
& obj
)
717 wxObjectOutputStream
obj_s(*this);
718 obj_s
.SaveObject(obj
);
723 // ----------------------------------------------------------------------------
724 // wxCountingOutputStream
725 // ----------------------------------------------------------------------------
727 wxCountingOutputStream::wxCountingOutputStream ()
733 size_t wxCountingOutputStream::GetSize() const
738 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
), size_t size
)
740 m_currentPos
+= size
;
741 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
745 off_t
wxCountingOutputStream::OnSysSeek(off_t pos
, wxSeekMode mode
)
747 if (mode
== wxFromStart
)
749 if (mode
== wxFromEnd
)
750 m_currentPos
= m_lastcount
+ pos
;
754 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
759 off_t
wxCountingOutputStream::OnSysTell() const
764 // ----------------------------------------------------------------------------
765 // wxFilterInputStream
766 // ----------------------------------------------------------------------------
768 wxFilterInputStream::wxFilterInputStream()
773 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
776 m_parent_i_stream
= &stream
;
779 wxFilterInputStream::~wxFilterInputStream()
783 // ----------------------------------------------------------------------------
784 // wxFilterOutputStream
785 // ----------------------------------------------------------------------------
786 wxFilterOutputStream::wxFilterOutputStream()
791 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
794 m_parent_o_stream
= &stream
;
797 wxFilterOutputStream::~wxFilterOutputStream()
801 // ----------------------------------------------------------------------------
802 // wxBufferedInputStream
803 // ----------------------------------------------------------------------------
804 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& s
)
805 : wxFilterInputStream(s
)
807 m_i_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::read
);
808 m_i_streambuf
->SetBufferIO(1024);
811 wxBufferedInputStream::~wxBufferedInputStream()
813 off_t unused_bytes
=m_i_streambuf
->GetBufferPos()-m_i_streambuf
->GetBufferEnd();
814 m_parent_i_stream
->SeekI(unused_bytes
,wxFromCurrent
);
816 delete m_i_streambuf
;
819 char wxBufferedInputStream::Peek()
821 return m_i_streambuf
->Peek();
824 wxInputStream
& wxBufferedInputStream::Read(void *buffer
, size_t size
)
827 char *buf
= (char *)buffer
;
829 retsize
= GetWBack(buf
, size
);
830 m_lastcount
= retsize
;
833 m_lasterror
= wxStream_NOERROR
;
839 m_i_streambuf
->Read(buf
, size
);
844 off_t
wxBufferedInputStream::SeekI(off_t pos
, wxSeekMode mode
)
846 return m_i_streambuf
->Seek(pos
, mode
);
849 off_t
wxBufferedInputStream::TellI() const
851 return m_i_streambuf
->Tell();
854 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
856 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
859 off_t
wxBufferedInputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
861 return m_parent_i_stream
->SeekI(seek
, mode
);
864 off_t
wxBufferedInputStream::OnSysTell() const
866 return m_parent_i_stream
->TellI();
870 // ----------------------------------------------------------------------------
871 // wxBufferedOutputStream
872 // ----------------------------------------------------------------------------
874 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& s
)
875 : wxFilterOutputStream(s
)
877 m_o_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::write
);
878 m_o_streambuf
->SetBufferIO(1024);
881 wxBufferedOutputStream::~wxBufferedOutputStream()
884 delete m_o_streambuf
;
887 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
890 m_o_streambuf
->Write(buffer
, size
);
894 off_t
wxBufferedOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
897 return m_o_streambuf
->Seek(pos
, mode
);
900 off_t
wxBufferedOutputStream::TellO() const
902 return m_o_streambuf
->Tell();
905 void wxBufferedOutputStream::Sync()
907 m_o_streambuf
->FlushBuffer();
908 m_parent_o_stream
->Sync();
911 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
913 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
916 off_t
wxBufferedOutputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
918 return m_parent_o_stream
->SeekO(seek
, mode
);
921 off_t
wxBufferedOutputStream::OnSysTell() const
923 return m_parent_o_stream
->TellO();
926 size_t wxBufferedOutputStream::GetSize() const
928 return m_parent_o_stream
->GetSize() + m_o_streambuf
->GetIntPosition();
931 // ----------------------------------------------------------------------------
932 // Some IOManip function
933 // ----------------------------------------------------------------------------
935 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
938 return stream
.Write("\r\n", 2);
941 return stream
.Write("\r", 1);
943 return stream
.Write("\n", 1);