1. wxProcess changes to make capturing subprocess output easier (and more
[wxWidgets.git] / src / common / stream.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: stream.cpp
3 // Purpose: wxStream base classes
4 // Author: Guilhem Lavaux
5 // Modified by:
6 // Created: 11/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Guilhem Lavaux
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "stream.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #endif
26
27 #if wxUSE_STREAMS
28
29 #include <ctype.h>
30 #include "wx/stream.h"
31 #include "wx/datstrm.h"
32 #include "wx/objstrm.h"
33
34 #define BUF_TEMP_SIZE 10000
35
36 // ----------------------------------------------------------------------------
37 // wxStreamBuffer
38 // ----------------------------------------------------------------------------
39
40 #define CHECK_ERROR(err) \
41 if (m_stream->m_lasterror == wxStream_NOERROR) \
42 m_stream->m_lasterror = err
43
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)
48 {
49 }
50
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)
55 {
56 m_stream = new wxStreamBase();
57 }
58
59 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
60 {
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;
69 m_destroybuf = FALSE;
70 m_destroystream = FALSE;
71 }
72
73 wxStreamBuffer::~wxStreamBuffer()
74 {
75 if (m_destroybuf)
76 wxDELETEA(m_buffer_start);
77 if (m_destroystream)
78 delete m_stream;
79 }
80
81 void wxStreamBuffer::SetBufferIO(char *buffer_start, char *buffer_end)
82 {
83 if (m_destroybuf)
84 wxDELETEA(m_buffer_start);
85 m_buffer_start = buffer_start;
86 m_buffer_end = buffer_end;
87
88 m_buffer_size = m_buffer_end-m_buffer_start;
89 m_destroybuf = FALSE;
90 ResetBuffer();
91 }
92
93 void wxStreamBuffer::SetBufferIO(size_t bufsize)
94 {
95 char *b_start;
96
97 if (m_destroybuf)
98 wxDELETEA(m_buffer_start);
99
100 if (!bufsize) {
101 m_buffer_start = (char*)NULL;
102 m_buffer_end = (char*)NULL;
103 m_buffer_pos = (char*)NULL;
104 m_buffer_size = 0;
105 return;
106 }
107
108 b_start = new char[bufsize];
109 SetBufferIO(b_start, b_start + bufsize);
110 m_destroybuf = TRUE;
111 }
112
113 void wxStreamBuffer::ResetBuffer()
114 {
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;
119 else
120 m_buffer_pos = m_buffer_start;
121 }
122
123 bool wxStreamBuffer::FillBuffer()
124 {
125 size_t count;
126
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;
130
131 if (count == 0)
132 return FALSE;
133 return TRUE;
134 }
135
136 bool wxStreamBuffer::FlushBuffer()
137 {
138 size_t count, current;
139
140 if (m_buffer_pos == m_buffer_start || !m_flushable)
141 return FALSE;
142
143 current = m_buffer_pos-m_buffer_start;
144 count = m_stream->OnSysWrite(m_buffer_start, current);
145 if (count != current)
146 return FALSE;
147 m_buffer_pos = m_buffer_start;
148
149 return TRUE;
150 }
151
152 void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
153 {
154 size_t s_toget = m_buffer_end-m_buffer_pos;
155
156 if (size < s_toget)
157 s_toget = size;
158
159 memcpy(buffer, m_buffer_pos, s_toget);
160 m_buffer_pos += s_toget;
161 }
162
163 void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
164 {
165 size_t s_toput = m_buffer_end-m_buffer_pos;
166
167 if (s_toput < size && !m_fixed) {
168 if (!m_buffer_start)
169 SetBufferIO(size);
170 else {
171 size_t delta = m_buffer_pos-m_buffer_start;
172
173 m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size+size);
174 m_buffer_pos = m_buffer_start + delta;
175 // I round a bit
176 m_buffer_size += size;
177 m_buffer_end = m_buffer_start+m_buffer_size;
178 }
179 s_toput = size;
180 }
181 if (s_toput > size)
182 s_toput = size;
183 memcpy(m_buffer_pos, buffer, s_toput);
184 m_buffer_pos += s_toput;
185 }
186
187 void wxStreamBuffer::PutChar(char c)
188 {
189 wxASSERT(m_stream != NULL);
190
191 if (!m_buffer_size) {
192 m_stream->OnSysWrite(&c, 1);
193 return;
194 }
195
196 if (GetDataLeft() == 0 && !FlushBuffer()) {
197 CHECK_ERROR(wxStream_WRITE_ERR);
198 return;
199 }
200
201 PutToBuffer(&c, 1);
202 m_stream->m_lastcount = 1;
203 }
204
205 char wxStreamBuffer::Peek()
206 {
207 char c;
208
209 wxASSERT(m_stream != NULL && m_buffer_size != 0);
210
211 if (!GetDataLeft()) {
212 CHECK_ERROR(wxStream_READ_ERR);
213 return 0;
214 }
215
216 GetFromBuffer(&c, 1);
217 m_buffer_pos--;
218
219 return c;
220 }
221
222 char wxStreamBuffer::GetChar()
223 {
224 char c;
225
226 wxASSERT(m_stream != NULL);
227
228 if (!m_buffer_size) {
229 m_stream->OnSysRead(&c, 1);
230 return c;
231 }
232
233 if (!GetDataLeft()) {
234 CHECK_ERROR(wxStream_READ_ERR);
235 return 0;
236 }
237
238 GetFromBuffer(&c, 1);
239
240 m_stream->m_lastcount = 1;
241 return c;
242 }
243
244 size_t wxStreamBuffer::Read(void *buffer, size_t size)
245 {
246 wxASSERT(m_stream != NULL);
247
248 if (m_mode == write)
249 return 0;
250
251 // ------------------
252 // Buffering disabled
253 // ------------------
254
255 m_stream->m_lasterror = wxStream_NOERROR;
256 if (!m_buffer_size)
257 return (m_stream->m_lastcount += m_stream->OnSysRead(buffer, size));
258
259 // -----------------
260 // Buffering enabled
261 // -----------------
262 size_t buf_left, orig_size = size;
263
264 while (size > 0) {
265 buf_left = GetDataLeft();
266
267 // First case: the requested buffer is larger than the stream buffer,
268 // we split it.
269 if (size > buf_left) {
270 GetFromBuffer(buffer, buf_left);
271 size -= buf_left;
272 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
273
274 if (!FillBuffer()) {
275 CHECK_ERROR(wxStream_EOF);
276 return (m_stream->m_lastcount = orig_size-size);
277 }
278 } else {
279
280 // Second case: we just copy from the stream buffer.
281 GetFromBuffer(buffer, size);
282 break;
283 }
284 }
285 return (m_stream->m_lastcount += orig_size);
286 }
287
288 size_t wxStreamBuffer::Read(wxStreamBuffer *s_buf)
289 {
290 char buf[BUF_TEMP_SIZE];
291 size_t s = 0, bytes_read = BUF_TEMP_SIZE;
292
293 if (m_mode == write)
294 return 0;
295
296 while (bytes_read != 0) {
297 bytes_read = Read(buf, bytes_read);
298 bytes_read = s_buf->Write(buf, bytes_read);
299 s += bytes_read;
300 }
301 return s;
302 }
303
304 size_t wxStreamBuffer::Write(const void *buffer, size_t size)
305 {
306 wxASSERT(m_stream != NULL);
307
308 if (m_mode == read)
309 return 0;
310
311 // ------------------
312 // Buffering disabled
313 // ------------------
314
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));
318
319 // ------------------
320 // Buffering enabled
321 // ------------------
322
323 size_t buf_left, orig_size = size;
324
325 while (size > 0) {
326 buf_left = m_buffer_end - m_buffer_pos;
327
328 // First case: the buffer to write is larger than the stream buffer,
329 // we split it
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);
334 size -= buf_left;
335 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
336
337 if (!FlushBuffer()) {
338 CHECK_ERROR(wxStream_WRITE_ERR);
339 return (m_stream->m_lastcount = orig_size-size);
340 }
341
342 m_buffer_pos = m_buffer_start;
343
344 } else {
345
346 // Second case: just copy it in the stream buffer.
347 PutToBuffer(buffer, size);
348 break;
349 }
350 }
351 return (m_stream->m_lastcount = orig_size);
352 }
353
354 size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
355 {
356 char buf[BUF_TEMP_SIZE];
357 size_t s = 0, bytes_count = BUF_TEMP_SIZE, b_count2;
358 wxInputStream *in_stream;
359
360 if (m_mode == read)
361 return 0;
362
363 in_stream = (wxInputStream *)sbuf->Stream();
364
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);
370 s += bytes_count;
371 }
372 return s;
373 }
374
375 off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode)
376 {
377 off_t ret_off, diff, last_access;
378
379 last_access = GetLastAccess();
380
381 if (!m_flushable) {
382 switch (mode) {
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;
387 }
388 if (diff < 0 || diff > last_access)
389 return wxInvalidOffset;
390 SetIntPosition(diff);
391 return diff;
392 }
393
394 switch (mode) {
395 case wxFromStart: {
396 // We'll try to compute an internal position later ...
397 ret_off = m_stream->OnSysSeek(pos, wxFromStart);
398 ResetBuffer();
399 return ret_off;
400 }
401 case wxFromCurrent: {
402 diff = pos + GetIntPosition();
403
404 if ( (diff > last_access) || (diff < 0) ) {
405 // We must take into account the fact that we have read something
406 // previously.
407 ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
408 ResetBuffer();
409 return ret_off;
410 } else {
411 SetIntPosition(diff);
412 return pos;
413 }
414 }
415 case wxFromEnd:
416 // Hard to compute: always seek to the requested position.
417 ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
418 ResetBuffer();
419 return ret_off;
420 }
421 return wxInvalidOffset;
422 }
423
424 off_t wxStreamBuffer::Tell() const
425 {
426 off_t pos = m_stream->OnSysTell();
427 if (pos == wxInvalidOffset)
428 return wxInvalidOffset;
429
430 pos += GetIntPosition();
431
432 if (m_mode == read && m_flushable)
433 pos -= GetLastAccess();
434
435 return pos;
436 }
437
438 size_t wxStreamBuffer::GetDataLeft()
439 {
440 /* Why is this done? RR. */
441 if (m_buffer_end == m_buffer_pos && m_flushable)
442 FillBuffer();
443
444 return m_buffer_end-m_buffer_pos;
445 }
446
447 // ----------------------------------------------------------------------------
448 // wxStreamBase
449 // ----------------------------------------------------------------------------
450
451 wxStreamBase::wxStreamBase()
452 {
453 m_lasterror = wxStream_NOERROR;
454 m_lastcount = 0;
455 }
456
457 wxStreamBase::~wxStreamBase()
458 {
459 }
460
461 size_t wxStreamBase::OnSysRead(void *WXUNUSED(buffer), size_t WXUNUSED(size))
462 {
463 return 0;
464 }
465
466 size_t wxStreamBase::OnSysWrite(const void *WXUNUSED(buffer), size_t WXUNUSED(bufsize))
467 {
468 return 0;
469 }
470
471 off_t wxStreamBase::OnSysSeek(off_t WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
472 {
473 return wxInvalidOffset;
474 }
475
476 off_t wxStreamBase::OnSysTell() const
477 {
478 return wxInvalidOffset;
479 }
480
481 // ----------------------------------------------------------------------------
482 // wxInputStream
483 // ----------------------------------------------------------------------------
484
485 wxInputStream::wxInputStream()
486 : wxStreamBase(),
487 m_wback(NULL), m_wbacksize(0), m_wbackcur(0)
488 {
489 }
490
491 wxInputStream::~wxInputStream()
492 {
493 if (m_wback)
494 free(m_wback);
495 }
496
497 bool wxInputStream::Eof() const
498 {
499 wxInputStream *self = (wxInputStream *)this; // const_cast
500
501 char c;
502 self->Read(&c, 1);
503 if ( GetLastError() == wxSTREAM_EOF )
504 {
505 return TRUE;
506 }
507
508 self->Ungetch(c);
509
510 return FALSE;
511 }
512
513 char *wxInputStream::AllocSpaceWBack(size_t needed_size)
514 {
515 /* get number of bytes left from previous wback buffer */
516 size_t toget = m_wbacksize - m_wbackcur;
517
518 /* allocate a buffer large enough to hold prev + new data */
519 char *temp_b = (char *) malloc(needed_size + toget);
520
521 if (!temp_b)
522 return NULL;
523
524 /* copy previous data (and free old buffer) if needed */
525 if (m_wback)
526 {
527 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
528 free(m_wback);
529 }
530
531 /* done */
532 m_wback = temp_b;
533 m_wbackcur = 0;
534 m_wbacksize = needed_size + toget;
535
536 return (char *) m_wback;
537 }
538
539 size_t wxInputStream::GetWBack(char *buf, size_t bsize)
540 {
541 size_t s_toget = m_wbacksize-m_wbackcur;
542
543 if (!m_wback)
544 return 0;
545
546 if (bsize < s_toget)
547 s_toget = bsize;
548
549 memcpy(buf, (m_wback+m_wbackcur), s_toget);
550
551 m_wbackcur += s_toget;
552 if (m_wbackcur == m_wbacksize)
553 {
554 free(m_wback);
555 m_wback = (char *)NULL;
556 m_wbacksize = 0;
557 m_wbackcur = 0;
558 }
559
560 return s_toget;
561 }
562
563 size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
564 {
565 char *ptrback = AllocSpaceWBack(bufsize);
566 if (!ptrback)
567 return 0;
568
569 memcpy(ptrback, buf, bufsize);
570 return bufsize;
571 }
572
573 bool wxInputStream::Ungetch(char c)
574 {
575 char * ptrback = AllocSpaceWBack(1);
576 if (!ptrback)
577 return FALSE;
578
579 *ptrback = c;
580 return TRUE;
581 }
582
583 char wxInputStream::GetC()
584 {
585 char c;
586 Read(&c, 1);
587 return c;
588 }
589
590 wxInputStream& wxInputStream::Read(void *buffer, size_t size)
591 {
592 char *buf = (char *)buffer;
593
594 size_t retsize = GetWBack(buf, size);
595 if (retsize == size)
596 {
597 m_lastcount = size;
598 m_lasterror = wxStream_NOERROR;
599 return *this;
600 }
601 size -= retsize;
602 buf += retsize;
603
604 m_lastcount = OnSysRead(buf, size) + retsize;
605 return *this;
606 }
607
608 char wxInputStream::Peek()
609 {
610 char c;
611 Read(&c, 1);
612 if (m_lasterror == wxStream_NOERROR)
613 {
614 Ungetch(c);
615 return c;
616 }
617
618 return 0;
619 }
620
621 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
622 {
623 char buf[BUF_TEMP_SIZE];
624 size_t bytes_read = BUF_TEMP_SIZE;
625
626 while (bytes_read == BUF_TEMP_SIZE)
627 {
628 bytes_read = Read(buf, bytes_read).LastRead();
629 bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
630 }
631 return *this;
632 }
633
634 off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
635 {
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;
640
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.
645
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
649 anyway...
650 */
651 if (m_wback)
652 {
653 free(m_wback);
654 m_wback = (char*) NULL;
655 m_wbacksize = 0;
656 m_wbackcur = 0;
657 }
658
659 return OnSysSeek(pos, mode);
660 }
661
662 off_t wxInputStream::TellI() const
663 {
664 /* GRG: Changed to make it compatible with the wback buffer */
665 off_t pos = OnSysTell();
666
667 if (pos != wxInvalidOffset)
668 pos -= (m_wbacksize - m_wbackcur);
669
670 return pos;
671 }
672
673 // --------------------
674 // Overloaded operators
675 // --------------------
676
677 #if wxUSE_SERIAL
678 wxInputStream& wxInputStream::operator>>(wxObject *& obj)
679 {
680 wxObjectInputStream obj_s(*this);
681 obj = obj_s.LoadObject();
682 return *this;
683 }
684 #endif
685
686
687 // ----------------------------------------------------------------------------
688 // wxOutputStream
689 // ----------------------------------------------------------------------------
690 wxOutputStream::wxOutputStream()
691 : wxStreamBase()
692 {
693 }
694
695 wxOutputStream::~wxOutputStream()
696 {
697 }
698
699 void wxOutputStream::PutC(char c)
700 {
701 Write((void *) &c, 1);
702 }
703
704 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
705 {
706 m_lastcount = OnSysWrite(buffer, size);
707 return *this;
708 }
709
710 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
711 {
712 stream_in.Read(*this);
713 return *this;
714 }
715
716 off_t wxOutputStream::TellO() const
717 {
718 return OnSysTell();
719 }
720
721 off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
722 {
723 return OnSysSeek(pos, mode);
724 }
725
726 void wxOutputStream::Sync()
727 {
728 }
729
730 #if wxUSE_SERIAL
731 wxOutputStream& wxOutputStream::operator<<(wxObject& obj)
732 {
733 wxObjectOutputStream obj_s(*this);
734 obj_s.SaveObject(obj);
735 return *this;
736 }
737 #endif
738
739 // ----------------------------------------------------------------------------
740 // wxCountingOutputStream
741 // ----------------------------------------------------------------------------
742
743 wxCountingOutputStream::wxCountingOutputStream ()
744 : wxOutputStream()
745 {
746 m_currentPos = 0;
747 }
748
749 size_t wxCountingOutputStream::GetSize() const
750 {
751 return m_lastcount;
752 }
753
754 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer), size_t size)
755 {
756 m_currentPos += size;
757 if (m_currentPos > m_lastcount) m_lastcount = m_currentPos;
758 return m_currentPos;
759 }
760
761 off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode)
762 {
763 if (mode == wxFromStart)
764 m_currentPos = pos;
765 if (mode == wxFromEnd)
766 m_currentPos = m_lastcount + pos;
767 else
768 m_currentPos += pos;
769
770 if (m_currentPos > m_lastcount) m_lastcount = m_currentPos;
771
772 return m_currentPos;
773 }
774
775 off_t wxCountingOutputStream::OnSysTell() const
776 {
777 return m_currentPos;
778 }
779
780 // ----------------------------------------------------------------------------
781 // wxFilterInputStream
782 // ----------------------------------------------------------------------------
783
784 wxFilterInputStream::wxFilterInputStream()
785 : wxInputStream()
786 {
787 }
788
789 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
790 : wxInputStream()
791 {
792 m_parent_i_stream = &stream;
793 }
794
795 wxFilterInputStream::~wxFilterInputStream()
796 {
797 }
798
799 // ----------------------------------------------------------------------------
800 // wxFilterOutputStream
801 // ----------------------------------------------------------------------------
802 wxFilterOutputStream::wxFilterOutputStream()
803 : wxOutputStream()
804 {
805 }
806
807 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
808 : wxOutputStream()
809 {
810 m_parent_o_stream = &stream;
811 }
812
813 wxFilterOutputStream::~wxFilterOutputStream()
814 {
815 }
816
817 // ----------------------------------------------------------------------------
818 // wxBufferedInputStream
819 // ----------------------------------------------------------------------------
820 wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s)
821 : wxFilterInputStream(s)
822 {
823 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
824 m_i_streambuf->SetBufferIO(1024);
825 }
826
827 wxBufferedInputStream::~wxBufferedInputStream()
828 {
829 off_t unused_bytes=m_i_streambuf->GetBufferPos()-m_i_streambuf->GetBufferEnd();
830 m_parent_i_stream->SeekI(unused_bytes,wxFromCurrent);
831
832 delete m_i_streambuf;
833 }
834
835 char wxBufferedInputStream::Peek()
836 {
837 return m_i_streambuf->Peek();
838 }
839
840 wxInputStream& wxBufferedInputStream::Read(void *buffer, size_t size)
841 {
842 size_t retsize;
843 char *buf = (char *)buffer;
844
845 retsize = GetWBack(buf, size);
846 m_lastcount = retsize;
847 if (retsize == size)
848 {
849 m_lasterror = wxStream_NOERROR;
850 return *this;
851 }
852 size -= retsize;
853 buf += retsize;
854
855 m_i_streambuf->Read(buf, size);
856
857 return *this;
858 }
859
860 off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
861 {
862 return m_i_streambuf->Seek(pos, mode);
863 }
864
865 off_t wxBufferedInputStream::TellI() const
866 {
867 return m_i_streambuf->Tell();
868 }
869
870 size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
871 {
872 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
873 }
874
875 off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode)
876 {
877 return m_parent_i_stream->SeekI(seek, mode);
878 }
879
880 off_t wxBufferedInputStream::OnSysTell() const
881 {
882 return m_parent_i_stream->TellI();
883 }
884
885
886 // ----------------------------------------------------------------------------
887 // wxBufferedOutputStream
888 // ----------------------------------------------------------------------------
889
890 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s)
891 : wxFilterOutputStream(s)
892 {
893 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
894 m_o_streambuf->SetBufferIO(1024);
895 }
896
897 wxBufferedOutputStream::~wxBufferedOutputStream()
898 {
899 Sync();
900 delete m_o_streambuf;
901 }
902
903 wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
904 {
905 m_lastcount = 0;
906 m_o_streambuf->Write(buffer, size);
907 return *this;
908 }
909
910 off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode)
911 {
912 Sync();
913 return m_o_streambuf->Seek(pos, mode);
914 }
915
916 off_t wxBufferedOutputStream::TellO() const
917 {
918 return m_o_streambuf->Tell();
919 }
920
921 void wxBufferedOutputStream::Sync()
922 {
923 m_o_streambuf->FlushBuffer();
924 m_parent_o_stream->Sync();
925 }
926
927 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
928 {
929 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
930 }
931
932 off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode)
933 {
934 return m_parent_o_stream->SeekO(seek, mode);
935 }
936
937 off_t wxBufferedOutputStream::OnSysTell() const
938 {
939 return m_parent_o_stream->TellO();
940 }
941
942 size_t wxBufferedOutputStream::GetSize() const
943 {
944 return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
945 }
946
947 // ----------------------------------------------------------------------------
948 // Some IOManip function
949 // ----------------------------------------------------------------------------
950
951 wxOutputStream& wxEndL(wxOutputStream& stream)
952 {
953 #ifdef __MSW__
954 return stream.Write("\r\n", 2);
955 #else
956 #ifdef __WXMAC__
957 return stream.Write("\r", 1);
958 #else
959 return stream.Write("\n", 1);
960 #endif
961 #endif
962 }
963
964 #endif
965 // wxUSE_STREAMS