]>
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. */
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 void wxOutputStream::PutC(char c
)
673 Write((void *) &c
, 1);
676 wxOutputStream
& wxOutputStream::Write(const void *buffer
, size_t size
)
678 m_lastcount
= OnSysWrite(buffer
, size
);
682 wxOutputStream
& wxOutputStream::Write(wxInputStream
& stream_in
)
684 stream_in
.Read(*this);
688 off_t
wxOutputStream::TellO() const
693 off_t
wxOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
695 return OnSysSeek(pos
, mode
);
698 void wxOutputStream::Sync()
703 wxOutputStream
& wxOutputStream::operator<<(wxObject
& obj
)
705 wxObjectOutputStream
obj_s(*this);
706 obj_s
.SaveObject(obj
);
711 // ----------------------------------------------------------------------------
712 // wxCountingOutputStream
713 // ----------------------------------------------------------------------------
715 wxCountingOutputStream::wxCountingOutputStream ()
721 size_t wxCountingOutputStream::GetSize() const
726 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer
), size_t size
)
728 m_currentPos
+= size
;
729 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
733 off_t
wxCountingOutputStream::OnSysSeek(off_t pos
, wxSeekMode mode
)
735 if (mode
== wxFromStart
)
737 if (mode
== wxFromEnd
)
738 m_currentPos
= m_lastcount
+ pos
;
742 if (m_currentPos
> m_lastcount
) m_lastcount
= m_currentPos
;
747 off_t
wxCountingOutputStream::OnSysTell() const
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 off_t unused_bytes
=m_i_streambuf
->GetBufferPos()-m_i_streambuf
->GetBufferEnd();
802 m_parent_i_stream
->SeekI(unused_bytes
,wxFromCurrent
);
804 delete m_i_streambuf
;
807 char wxBufferedInputStream::Peek()
809 return m_i_streambuf
->Peek();
812 wxInputStream
& wxBufferedInputStream::Read(void *buffer
, size_t size
)
815 char *buf
= (char *)buffer
;
817 retsize
= GetWBack(buf
, size
);
818 m_lastcount
= retsize
;
821 m_lasterror
= wxStream_NOERROR
;
827 m_i_streambuf
->Read(buf
, size
);
832 off_t
wxBufferedInputStream::SeekI(off_t pos
, wxSeekMode mode
)
834 return m_i_streambuf
->Seek(pos
, mode
);
837 off_t
wxBufferedInputStream::TellI() const
839 return m_i_streambuf
->Tell();
842 size_t wxBufferedInputStream::OnSysRead(void *buffer
, size_t bufsize
)
844 return m_parent_i_stream
->Read(buffer
, bufsize
).LastRead();
847 off_t
wxBufferedInputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
849 return m_parent_i_stream
->SeekI(seek
, mode
);
852 off_t
wxBufferedInputStream::OnSysTell() const
854 return m_parent_i_stream
->TellI();
858 // ----------------------------------------------------------------------------
859 // wxBufferedOutputStream
860 // ----------------------------------------------------------------------------
862 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream
& s
)
863 : wxFilterOutputStream(s
)
865 m_o_streambuf
= new wxStreamBuffer(*this, wxStreamBuffer::write
);
866 m_o_streambuf
->SetBufferIO(1024);
869 wxBufferedOutputStream::~wxBufferedOutputStream()
872 delete m_o_streambuf
;
875 wxOutputStream
& wxBufferedOutputStream::Write(const void *buffer
, size_t size
)
878 m_o_streambuf
->Write(buffer
, size
);
882 off_t
wxBufferedOutputStream::SeekO(off_t pos
, wxSeekMode mode
)
885 return m_o_streambuf
->Seek(pos
, mode
);
888 off_t
wxBufferedOutputStream::TellO() const
890 return m_o_streambuf
->Tell();
893 void wxBufferedOutputStream::Sync()
895 m_o_streambuf
->FlushBuffer();
896 m_parent_o_stream
->Sync();
899 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer
, size_t bufsize
)
901 return m_parent_o_stream
->Write(buffer
, bufsize
).LastWrite();
904 off_t
wxBufferedOutputStream::OnSysSeek(off_t seek
, wxSeekMode mode
)
906 return m_parent_o_stream
->SeekO(seek
, mode
);
909 off_t
wxBufferedOutputStream::OnSysTell() const
911 return m_parent_o_stream
->TellO();
914 size_t wxBufferedOutputStream::GetSize() const
916 return m_parent_o_stream
->GetSize() + m_o_streambuf
->GetIntPosition();
919 // ----------------------------------------------------------------------------
920 // Some IOManip function
921 // ----------------------------------------------------------------------------
923 wxOutputStream
& wxEndL(wxOutputStream
& stream
)
926 return stream
.Write("\r\n", 2);
929 return stream
.Write("\r", 1);
931 return stream
.Write("\n", 1);