]>
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
429 pos
= m_stream
->OnSysTell();
430 if (pos
== wxInvalidOffset
)
431 return wxInvalidOffset
;
432 return pos
- GetLastAccess() + GetIntPosition();
434 return GetIntPosition();
437 size_t wxStreamBuffer::GetDataLeft()
439 if (m_buffer_end
== m_buffer_pos
&& m_flushable
)
441 return m_buffer_end
-m_buffer_pos
;
444 // ----------------------------------------------------------------------------
446 // ----------------------------------------------------------------------------
448 wxStreamBase::wxStreamBase()
450 m_lasterror
= wxStream_NOERROR
;
454 wxStreamBase::~wxStreamBase()
458 size_t wxStreamBase::OnSysRead(void *WXUNUSED(buffer
), size_t WXUNUSED(size
))
463 size_t wxStreamBase::OnSysWrite(const void *WXUNUSED(buffer
), size_t WXUNUSED(bufsize
))
468 off_t
wxStreamBase::OnSysSeek(off_t
WXUNUSED(seek
), wxSeekMode
WXUNUSED(mode
))
470 return wxInvalidOffset
;
473 off_t
wxStreamBase::OnSysTell() const
475 return wxInvalidOffset
;
478 // ----------------------------------------------------------------------------
480 // ----------------------------------------------------------------------------
482 wxInputStream::wxInputStream()
484 m_wback(NULL
), m_wbacksize(0), m_wbackcur(0)
488 wxInputStream::~wxInputStream()
494 char *wxInputStream::AllocSpaceWBack(size_t needed_size
)
499 /* get number of bytes left from previous wback buffer */
500 toget
= m_wbacksize
- m_wbackcur
;
502 /* allocate a buffer large enough to hold prev + new data */
503 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
) {
538 m_wback
= (char *)NULL
;
546 size_t wxInputStream::Ungetch(const void *buf
, size_t bufsize
)
550 ptrback
= AllocSpaceWBack(bufsize
);
554 memcpy(ptrback
, buf
, bufsize
);
558 bool wxInputStream::Ungetch(char c
)
562 ptrback
= AllocSpaceWBack(1);
570 char wxInputStream::GetC()
577 wxInputStream
& wxInputStream::Read(void *buffer
, size_t size
)
580 char *buf
= (char *)buffer
;
582 retsize
= GetWBack(buf
, size
);
583 if (retsize
== size
) {
585 m_lasterror
= wxStream_NOERROR
;
591 m_lastcount
= OnSysRead(buf
, size
) + retsize
;
595 char wxInputStream::Peek()
600 if (m_lasterror
== wxStream_NOERROR
) {
607 wxInputStream
& wxInputStream::Read(wxOutputStream
& stream_out
)
609 char buf
[BUF_TEMP_SIZE
];
610 size_t bytes_read
= BUF_TEMP_SIZE
;
612 while (bytes_read
== BUF_TEMP_SIZE
) {
613 bytes_read
= Read(buf
, bytes_read
).LastRead();
614 bytes_read
= stream_out
.Write(buf
, bytes_read
).LastWrite();
619 off_t
wxInputStream::SeekI(off_t pos
, wxSeekMode mode
)
621 // Should be check and improve, just to remove a slight bug !
622 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ?
623 if (m_lasterror
==wxSTREAM_EOF
)
624 m_lasterror
=wxSTREAM_NOERROR
;
626 // A call to SeekI() will automatically invalidate any previous call
627 // to Ungetch(), otherwise it would be possible to SeeI() to one
628 // one position, unread some bytes there, SeekI() to another position
629 // and the data would be corrupted.
632 m_wback
= (char*) NULL
;
637 return OnSysSeek(pos
, mode
);
640 off_t
wxInputStream::TellI() const
645 // --------------------
646 // Overloaded operators
647 // --------------------
650 wxInputStream
& wxInputStream::operator>>(wxObject
*& obj
)
652 wxObjectInputStream
obj_s(*this);
653 obj
= obj_s
.LoadObject();
659 // ----------------------------------------------------------------------------
661 // ----------------------------------------------------------------------------
662 wxOutputStream::wxOutputStream()
667 wxOutputStream::~wxOutputStream()
671 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
673 m_lastcount
= OnSysWrite(buffer
, size
);
677 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
679 stream_in
.Read(*this);
683 off_t
wxOutputStream::TellO() const
688 off_t
wxOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
690 return OnSysSeek(pos
, mode
);
693 void wxOutputStream::Sync()
698 wxOutputStream
& wxOutputStream::operator<<(wxObject
& obj
)
700 wxObjectOutputStream
obj_s(*this);
701 obj_s
.SaveObject(obj
);
706 // ----------------------------------------------------------------------------
707 // wxCountingOutputStream
708 // ----------------------------------------------------------------------------
710 wxCountingOutputStream::wxCountingOutputStream ()
716 size_t wxCountingOutputStream::GetSize() const
721 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
), size_t size
)
723 m_currentPos
+= size
;
724 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
728 off_t
wxCountingOutputStream::OnSysSeek(off_t pos
, wxSeekMode mode
)
730 if (mode
== wxFromStart
)
734 if (mode
== wxFromEnd
)
736 m_currentPos
= m_lastcount
+ pos
;
742 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
744 return m_currentPos
; // ?
747 off_t
wxCountingOutputStream::OnSysTell() const
749 return m_currentPos
; // ?
752 // ----------------------------------------------------------------------------
753 // wxFilterInputStream
754 // ----------------------------------------------------------------------------
756 wxFilterInputStream::wxFilterInputStream()
761 wxFilterInputStream::wxFilterInputStream(wxInputStream
& stream
)
764 m_parent_i_stream
= &stream
;
767 wxFilterInputStream::~wxFilterInputStream()
771 // ----------------------------------------------------------------------------
772 // wxFilterOutputStream
773 // ----------------------------------------------------------------------------
774 wxFilterOutputStream::wxFilterOutputStream()
779 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream
& stream
)
782 m_parent_o_stream
= &stream
;
785 wxFilterOutputStream::~wxFilterOutputStream()
789 // ----------------------------------------------------------------------------
790 // wxBufferedInputStream
791 // ----------------------------------------------------------------------------
792 wxBufferedInputStream::wxBufferedInputStream(wxInputStream
& s
)
793 : wxFilterInputStream(s
)
795 m_i_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::read
);
796 m_i_streambuf
->SetBufferIO(1024);
799 wxBufferedInputStream::~wxBufferedInputStream()
801 delete m_i_streambuf
;
804 char wxBufferedInputStream::Peek()
806 return m_i_streambuf
->Peek();
809 wxInputStream
& wxBufferedInputStream::Read(void *buffer
, size_t size
)
812 char *buf
= (char *)buffer
;
814 retsize
= GetWBack(buf
, size
);
815 m_lastcount
= retsize
;
816 if (retsize
== size
) {
817 m_lasterror
= wxStream_NOERROR
;
823 m_i_streambuf
->Read(buf
, size
);
828 off_t
wxBufferedInputStream::SeekI(off_t pos
, wxSeekMode mode
)
830 return m_i_streambuf
->Seek(pos
, mode
);
833 off_t
wxBufferedInputStream::TellI() const
835 return m_i_streambuf
->Tell();
838 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
840 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
843 off_t
wxBufferedInputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
845 return m_parent_i_stream
->SeekI(seek
, mode
);
848 off_t
wxBufferedInputStream::OnSysTell() const
850 return m_parent_i_stream
->TellI();
853 // ----------------------------------------------------------------------------
854 // wxBufferedOutputStream
855 // ----------------------------------------------------------------------------
857 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& s
)
858 : wxFilterOutputStream(s
)
860 m_o_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::write
);
861 m_o_streambuf
->SetBufferIO(1024);
864 wxBufferedOutputStream::~wxBufferedOutputStream()
867 delete m_o_streambuf
;
870 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
873 m_o_streambuf
->Write(buffer
, size
);
877 off_t
wxBufferedOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
880 return m_o_streambuf
->Seek(pos
, mode
);
883 off_t
wxBufferedOutputStream::TellO() const
885 return m_o_streambuf
->Tell();
888 void wxBufferedOutputStream::Sync()
890 m_o_streambuf
->FlushBuffer();
891 m_parent_o_stream
->Sync();
894 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
896 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
899 off_t
wxBufferedOutputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
901 return m_parent_o_stream
->SeekO(seek
, mode
);
904 off_t
wxBufferedOutputStream::OnSysTell() const
906 return m_parent_o_stream
->TellO();
909 // ----------------------------------------------------------------------------
910 // Some IOManip function
911 // ----------------------------------------------------------------------------
913 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
916 return stream
.Write("\r\n", 2);
919 return stream
.Write("\r", 1);
921 return stream
.Write("\n", 1);