linking fix
[wxWidgets.git] / src / common / stream.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/stream.cpp
3 // Purpose: wxStream base classes
4 // Author: Guilhem Lavaux
5 // Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory,
6 // general code review
7 // Created: 11/07/98
8 // RCS-ID: $Id$
9 // Copyright: (c) Guilhem Lavaux
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 #ifdef __GNUG__
22 #pragma implementation "stream.h"
23 #endif
24
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 #ifndef WX_PRECOMP
33 #include "wx/defs.h"
34 #endif
35
36 #if wxUSE_STREAMS
37
38 #include <ctype.h>
39 #include "wx/stream.h"
40 #include "wx/datstrm.h"
41 #include "wx/objstrm.h"
42
43 // ----------------------------------------------------------------------------
44 // constants
45 // ----------------------------------------------------------------------------
46
47 // the temporary buffer size used when copying from stream to stream
48 #define BUF_TEMP_SIZE 10000
49
50 // ============================================================================
51 // implementation
52 // ============================================================================
53
54 // ----------------------------------------------------------------------------
55 // wxStreamBuffer
56 // ----------------------------------------------------------------------------
57
58 void wxStreamBuffer::SetError(wxStreamError err)
59 {
60 if ( m_stream->m_lasterror == wxStream_NOERROR )
61 m_stream->m_lasterror = err;
62 }
63
64 void wxStreamBuffer::InitBuffer()
65 {
66 m_buffer_start =
67 m_buffer_end =
68 m_buffer_pos = NULL;
69 m_buffer_size = 0;
70
71 // there is nothing to destroy anyhow
72 m_destroybuf = FALSE;
73 }
74
75 void wxStreamBuffer::Init()
76 {
77 InitBuffer();
78
79 m_fixed = TRUE;
80 }
81
82 wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
83 {
84 m_stream = &stream;
85 m_mode = mode;
86
87 m_flushable = TRUE;
88 m_destroystream = FALSE;
89 }
90
91 wxStreamBuffer::wxStreamBuffer(BufMode mode)
92 {
93 m_stream = new wxStreamBase;
94 m_mode = mode;
95
96 m_flushable = FALSE;
97 m_destroystream = TRUE;
98 }
99
100 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
101 {
102 // doing this has big chances to lead to a crashwhen the source buffer is
103 // destroyed (otherwise assume the caller knows what he does)
104 wxASSERT_MSG( !buffer.m_destroybuf && !buffer.m_destroystream,
105 _T("it's a bad idea to copy this buffer") );
106
107 m_buffer_start = buffer.m_buffer_start;
108 m_buffer_end = buffer.m_buffer_end;
109 m_buffer_pos = buffer.m_buffer_pos;
110 m_buffer_size = buffer.m_buffer_size;
111 m_fixed = buffer.m_fixed;
112 m_flushable = buffer.m_flushable;
113 m_stream = buffer.m_stream;
114 m_mode = buffer.m_mode;
115 m_destroybuf = FALSE;
116 m_destroystream = FALSE;
117 }
118
119 void wxStreamBuffer::FreeBuffer()
120 {
121 if ( m_destroybuf )
122 free(m_buffer_start);
123 }
124
125 wxStreamBuffer::~wxStreamBuffer()
126 {
127 FreeBuffer();
128
129 if ( m_destroystream )
130 delete m_stream;
131 }
132
133 wxInputStream *wxStreamBuffer::GetInputStream() const
134 {
135 return m_mode == write ? NULL : (wxInputStream *)m_stream;
136 }
137
138 wxOutputStream *wxStreamBuffer::GetOutputStream() const
139 {
140 return m_mode == read ? NULL : (wxOutputStream *)m_stream;
141 }
142
143 void wxStreamBuffer::SetBufferIO(void *buffer_start,
144 void *buffer_end,
145 bool takeOwnership)
146 {
147 SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start,
148 takeOwnership);
149 }
150
151 void wxStreamBuffer::SetBufferIO(void *start,
152 size_t len,
153 bool takeOwnership)
154 {
155 // start by freeing the old buffer
156 FreeBuffer();
157
158 m_buffer_start = (char *)start;
159 m_buffer_end = m_buffer_start + len;
160
161 m_buffer_size = len;
162
163 // if we own it, we free it
164 m_destroybuf = !takeOwnership;
165
166 ResetBuffer();
167 }
168
169 void wxStreamBuffer::SetBufferIO(size_t bufsize)
170 {
171 // start by freeing the old buffer
172 FreeBuffer();
173
174 if ( bufsize )
175 {
176 SetBufferIO(malloc(bufsize), bufsize, TRUE /* take ownership */);
177 }
178 else // no buffer size => no buffer
179 {
180 InitBuffer();
181 }
182 }
183
184 void wxStreamBuffer::ResetBuffer()
185 {
186 wxCHECK_RET( m_stream, _T("should have a stream in wxStreamBuffer") );
187
188 m_stream->m_lasterror = wxStream_NOERROR;
189 m_stream->m_lastcount = 0;
190 if (m_mode == read && m_flushable)
191 m_buffer_pos = m_buffer_end;
192 else
193 m_buffer_pos = m_buffer_start;
194 }
195
196 // fill the buffer with as much data as possible (only for read buffers)
197 bool wxStreamBuffer::FillBuffer()
198 {
199 wxInputStream *inStream = GetInputStream();
200
201 wxCHECK_MSG( inStream, FALSE, _T("should have a stream in wxStreamBuffer") );
202
203 size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
204 if ( !count )
205 return FALSE;
206
207 m_buffer_end = m_buffer_start + count;
208 m_buffer_pos = m_buffer_start;
209
210 return TRUE;
211 }
212
213 // write the buffer contents to the stream (only for write buffers)
214 bool wxStreamBuffer::FlushBuffer()
215 {
216 wxCHECK_MSG( m_flushable, FALSE, _T("can't flush this buffer") );
217
218 // FIXME: what is this check for? (VZ)
219 if ( m_buffer_pos == m_buffer_start )
220 return FALSE;
221
222 wxOutputStream *outStream = GetOutputStream();
223
224 wxCHECK_MSG( outStream, FALSE, _T("should have a stream in wxStreamBuffer") );
225
226 size_t current = m_buffer_pos - m_buffer_start;
227 size_t count = outStream->OnSysWrite(m_buffer_start, current);
228 if ( count != current )
229 return FALSE;
230
231 m_buffer_pos = m_buffer_start;
232
233 return TRUE;
234 }
235
236 size_t wxStreamBuffer::GetDataLeft()
237 {
238 /* Why is this done? RR. */
239 if ( m_buffer_pos == m_buffer_end && m_flushable)
240 FillBuffer();
241
242 return GetBytesLeft();
243 }
244
245 // copy up to size bytes from our buffer into the provided one
246 void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
247 {
248 // don't get more bytes than left in the buffer
249 size_t left = GetBytesLeft();
250
251 if ( size > left )
252 size = left;
253
254 memcpy(buffer, m_buffer_pos, size);
255 m_buffer_pos += size;
256 }
257
258 // copy the contents of the provided buffer into this one
259 void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
260 {
261 size_t left = GetBytesLeft();
262 if ( size > left )
263 {
264 if ( m_fixed )
265 {
266 // we can't realloc the buffer, so just copy what we can
267 size = left;
268 }
269 else // !m_fixed
270 {
271 // realloc the buffer to have enough space for the data
272 size_t delta = m_buffer_pos - m_buffer_start;
273
274 char *startOld = m_buffer_start;
275 m_buffer_size += size;
276 m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size);
277 if ( !m_buffer_start )
278 {
279 // don't leak memory if realloc() failed
280 m_buffer_start = startOld;
281 m_buffer_size -= size;
282
283 // what else can we do?
284 return;
285 }
286
287 // adjust the pointers invalidated by realloc()
288 m_buffer_pos = m_buffer_start + delta;
289 m_buffer_end = m_buffer_start + m_buffer_size;
290 }
291 }
292
293 memcpy(m_buffer_pos, buffer, size);
294 m_buffer_pos += size;
295 }
296
297 void wxStreamBuffer::PutChar(char c)
298 {
299 wxOutputStream *outStream = GetOutputStream();
300
301 wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") );
302
303 // if we don't have buffer at all, just forward this call to the stream,
304 if ( !HasBuffer() )
305 {
306 outStream->OnSysWrite(&c, 1);
307 }
308 else
309 {
310 // otherwise check we have enough space left
311 if ( !GetDataLeft() && !FlushBuffer() )
312 {
313 // we don't
314 SetError(wxStream_WRITE_ERR);
315 }
316 else
317 {
318 PutToBuffer(&c, 1);
319 m_stream->m_lastcount = 1;
320 }
321 }
322 }
323
324 char wxStreamBuffer::Peek()
325 {
326 wxCHECK_MSG( m_stream && HasBuffer(), 0,
327 _T("should have the stream and the buffer in wxStreamBuffer") );
328
329 if ( !GetDataLeft() )
330 {
331 SetError(wxStream_READ_ERR);
332 return 0;
333 }
334
335 char c;
336 GetFromBuffer(&c, 1);
337 m_buffer_pos--;
338
339 return c;
340 }
341
342 char wxStreamBuffer::GetChar()
343 {
344 wxInputStream *inStream = GetInputStream();
345
346 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
347
348 char c;
349 if ( !HasBuffer() )
350 {
351 inStream->OnSysRead(&c, 1);
352 }
353 else
354 {
355 if ( !GetDataLeft() )
356 {
357 SetError(wxStream_READ_ERR);
358 c = 0;
359 }
360 else
361 {
362 GetFromBuffer(&c, 1);
363 m_stream->m_lastcount = 1;
364 }
365 }
366
367 return c;
368 }
369
370 size_t wxStreamBuffer::Read(void *buffer, size_t size)
371 {
372 wxInputStream *inStream = GetInputStream();
373
374 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
375
376 // lasterror is reset before all new IO calls
377 m_stream->m_lasterror = wxStream_NOERROR;
378
379 if ( !HasBuffer() )
380 {
381 m_stream->m_lastcount = inStream->OnSysRead(buffer, size);
382 }
383 else // we have a buffer, use it
384 {
385 size_t orig_size = size;
386
387 while ( size > 0 )
388 {
389 size_t left = GetDataLeft();
390
391 // if the requested number of bytes if greater than the buffer
392 // size, read data in chunks
393 if ( size > left )
394 {
395 GetFromBuffer(buffer, left);
396 size -= left;
397 buffer = (char *)buffer + left;
398
399 if ( !FillBuffer() )
400 {
401 SetError(wxStream_EOF);
402 break;
403 }
404 }
405 else // otherwise just do it in one gulp
406 {
407 GetFromBuffer(buffer, size);
408 size = 0;
409 }
410 }
411
412 m_stream->m_lastcount = orig_size - size;
413 }
414
415 return m_stream->m_lastcount;
416 }
417
418 // this should really be called "Copy()"
419 size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
420 {
421 wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") );
422
423 char buf[BUF_TEMP_SIZE];
424 size_t nRead,
425 total = 0;
426
427 do
428 {
429 nRead = Read(dbuf, WXSIZEOF(buf));
430 if ( nRead )
431 {
432 nRead = dbuf->Write(buf, nRead);
433 total += nRead;
434 }
435 }
436 while ( nRead );
437
438 return total;
439 }
440
441 size_t wxStreamBuffer::Write(const void *buffer, size_t size)
442 {
443 wxOutputStream *outStream = GetOutputStream();
444
445 wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
446
447 // lasterror is reset before all new IO calls
448 m_stream->m_lasterror = wxStream_NOERROR;
449
450 if ( !HasBuffer() && m_fixed )
451 {
452 // no buffer, just forward the call to the stream
453 m_stream->m_lastcount = outStream->OnSysWrite(buffer, size);
454 }
455 else // we [may] have a buffer, use it
456 {
457 size_t orig_size = size;
458
459 while ( size > 0 )
460 {
461 size_t left = GetBytesLeft();
462
463 // if the buffer is too large to fit in the stream buffer, split
464 // it in smaller parts
465 //
466 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
467 // we always go to the second case.
468 //
469 // FIXME: fine, but if it fails we should (re)try writing it by
470 // chunks as this will (hopefully) always work (VZ)
471 if ( size > left && m_fixed )
472 {
473 PutToBuffer(buffer, left);
474 size -= left;
475 buffer = (char *)buffer + left;
476
477 if ( !FlushBuffer() )
478 {
479 SetError(wxStream_WRITE_ERR);
480
481 break;
482 }
483
484 m_buffer_pos = m_buffer_start;
485 }
486 else // we can do it in one gulp
487 {
488 PutToBuffer(buffer, size);
489 size = 0;
490 }
491 }
492
493 m_stream->m_lastcount = orig_size - size;
494 }
495
496 return m_stream->m_lastcount;
497 }
498
499 size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
500 {
501 wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") );
502 wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") );
503
504 char buf[BUF_TEMP_SIZE];
505 size_t nWrite,
506 total = 0;
507
508 do
509 {
510 size_t nRead = sbuf->Read(buf, WXSIZEOF(buf));
511 if ( nRead )
512 {
513 nWrite = Write(buf, nRead);
514 if ( nWrite < nRead )
515 {
516 // put back data we couldn't copy
517 wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream();
518
519 in_stream->Ungetch(buf + nWrite, nRead - nWrite);
520 }
521
522 total += nWrite;
523 }
524 else
525 {
526 nWrite = 0;
527 }
528 }
529 while ( nWrite == WXSIZEOF(buf) );
530
531 return total;
532 }
533
534 off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode)
535 {
536 off_t ret_off, diff;
537
538 off_t last_access = GetLastAccess();
539
540 if ( !m_flushable )
541 {
542 switch (mode)
543 {
544 case wxFromStart:
545 diff = pos;
546 break;
547
548 case wxFromCurrent:
549 diff = pos + GetIntPosition();
550 break;
551
552 case wxFromEnd:
553 diff = pos + last_access;
554 break;
555
556 default:
557 wxFAIL_MSG( _T("invalid seek mode") );
558
559 return wxInvalidOffset;
560 }
561 if (diff < 0 || diff > last_access)
562 return wxInvalidOffset;
563 SetIntPosition(diff);
564 return diff;
565 }
566
567 switch ( mode )
568 {
569 case wxFromStart:
570 // We'll try to compute an internal position later ...
571 ret_off = m_stream->OnSysSeek(pos, wxFromStart);
572 ResetBuffer();
573 return ret_off;
574
575 case wxFromCurrent:
576 diff = pos + GetIntPosition();
577
578 if ( (diff > last_access) || (diff < 0) )
579 {
580 // We must take into account the fact that we have read
581 // something previously.
582 ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
583 ResetBuffer();
584 return ret_off;
585 }
586 else
587 {
588 SetIntPosition(diff);
589 return pos;
590 }
591
592 case wxFromEnd:
593 // Hard to compute: always seek to the requested position.
594 ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
595 ResetBuffer();
596 return ret_off;
597 }
598
599 return wxInvalidOffset;
600 }
601
602 off_t wxStreamBuffer::Tell() const
603 {
604 off_t pos = m_stream->OnSysTell();
605 if ( pos == wxInvalidOffset )
606 return wxInvalidOffset;
607
608 pos += GetIntPosition();
609
610 if ( m_mode == read && m_flushable )
611 pos -= GetLastAccess();
612
613 return pos;
614 }
615
616 // ----------------------------------------------------------------------------
617 // wxStreamBase
618 // ----------------------------------------------------------------------------
619
620 wxStreamBase::wxStreamBase()
621 {
622 m_lasterror = wxStream_NOERROR;
623 m_lastcount = 0;
624 }
625
626 wxStreamBase::~wxStreamBase()
627 {
628 }
629
630 off_t wxStreamBase::OnSysSeek(off_t WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
631 {
632 return wxInvalidOffset;
633 }
634
635 off_t wxStreamBase::OnSysTell() const
636 {
637 return wxInvalidOffset;
638 }
639
640 // ----------------------------------------------------------------------------
641 // wxInputStream
642 // ----------------------------------------------------------------------------
643
644 wxInputStream::wxInputStream()
645 {
646 m_wback = NULL;
647 m_wbacksize =
648 m_wbackcur = 0;
649 }
650
651 wxInputStream::~wxInputStream()
652 {
653 free(m_wback);
654 }
655
656 size_t wxInputStream::OnSysRead(void * WXUNUSED(buffer),
657 size_t WXUNUSED(bufsize))
658 {
659 return 0;
660 }
661
662 bool wxInputStream::Eof() const
663 {
664 wxInputStream *self = wxConstCast(this, wxInputStream);
665
666 char c;
667 self->Read(&c, 1);
668 if ( GetLastError() == wxSTREAM_EOF )
669 {
670 return TRUE;
671 }
672
673 self->Ungetch(c);
674
675 return FALSE;
676 }
677
678 char *wxInputStream::AllocSpaceWBack(size_t needed_size)
679 {
680 // get number of bytes left from previous wback buffer
681 size_t toget = m_wbacksize - m_wbackcur;
682
683 // allocate a buffer large enough to hold prev + new data
684 char *temp_b = (char *)malloc(needed_size + toget);
685
686 if (!temp_b)
687 return NULL;
688
689 /* copy previous data (and free old buffer) if needed */
690 if (m_wback)
691 {
692 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
693 free(m_wback);
694 }
695
696 /* done */
697 m_wback = temp_b;
698 m_wbackcur = 0;
699 m_wbacksize = needed_size + toget;
700
701 return m_wback;
702 }
703
704 size_t wxInputStream::GetWBack(void *buf, size_t bsize)
705 {
706 size_t toget = m_wbacksize-m_wbackcur;
707
708 if (!m_wback)
709 return 0;
710
711 if (bsize < toget)
712 toget = bsize;
713
714 memcpy(buf, (m_wback+m_wbackcur), toget);
715
716 m_wbackcur += toget;
717 if (m_wbackcur == m_wbacksize)
718 {
719 free(m_wback);
720 m_wback = NULL;
721 m_wbacksize = 0;
722 m_wbackcur = 0;
723 }
724
725 return toget;
726 }
727
728 size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
729 {
730 char *ptrback = AllocSpaceWBack(bufsize);
731 if (!ptrback)
732 return 0;
733
734 memcpy(ptrback, buf, bufsize);
735 return bufsize;
736 }
737
738 bool wxInputStream::Ungetch(char c)
739 {
740 void *ptrback = AllocSpaceWBack(1);
741 if (!ptrback)
742 return FALSE;
743
744 *(char *)ptrback = c;
745 return TRUE;
746 }
747
748 char wxInputStream::GetC()
749 {
750 char c;
751 Read(&c, 1);
752 return c;
753 }
754
755 wxInputStream& wxInputStream::Read(void *buf, size_t size)
756 {
757 size_t retsize = GetWBack(buf, size);
758 if (retsize == size)
759 {
760 m_lastcount = size;
761 m_lasterror = wxStream_NOERROR;
762 return *this;
763 }
764 size -= retsize;
765 buf = (char *)buf + retsize;
766
767 m_lastcount = OnSysRead(buf, size) + retsize;
768 return *this;
769 }
770
771 char wxInputStream::Peek()
772 {
773 char c;
774 Read(&c, 1);
775 if (m_lasterror == wxStream_NOERROR)
776 {
777 Ungetch(c);
778 return c;
779 }
780
781 return 0;
782 }
783
784 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
785 {
786 char buf[BUF_TEMP_SIZE];
787 size_t bytes_read = BUF_TEMP_SIZE;
788
789 while (bytes_read == BUF_TEMP_SIZE)
790 {
791 bytes_read = Read(buf, bytes_read).LastRead();
792 bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
793 }
794 return *this;
795 }
796
797 off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
798 {
799 /* Should be check and improve, just to remove a slight bug !
800 I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
801 if (m_lasterror==wxSTREAM_EOF)
802 m_lasterror=wxSTREAM_NOERROR;
803
804 /* A call to SeekI() will automatically invalidate any previous call
805 to Ungetch(), otherwise it would be possible to SeekI() to one
806 one position, unread some bytes there, SeekI() to another position
807 and the data would be corrupted.
808
809 GRG: Could add code here to try to navigate within the wback
810 buffer if possible, but is it really needed? It would only work
811 when seeking in wxFromCurrent mode, else it would invalidate
812 anyway...
813 */
814 if (m_wback)
815 {
816 free(m_wback);
817 m_wback = NULL;
818 m_wbacksize = 0;
819 m_wbackcur = 0;
820 }
821
822 return OnSysSeek(pos, mode);
823 }
824
825 off_t wxInputStream::TellI() const
826 {
827 /* GRG: Changed to make it compatible with the wback buffer */
828 off_t pos = OnSysTell();
829
830 if (pos != wxInvalidOffset)
831 pos -= (m_wbacksize - m_wbackcur);
832
833 return pos;
834 }
835
836 // --------------------
837 // Overloaded operators
838 // --------------------
839
840 #if wxUSE_SERIAL
841 wxInputStream& wxInputStream::operator>>(wxObject *& obj)
842 {
843 wxObjectInputStream obj_s(*this);
844 obj = obj_s.LoadObject();
845 return *this;
846 }
847 #endif // wxUSE_SERIAL
848
849
850 // ----------------------------------------------------------------------------
851 // wxOutputStream
852 // ----------------------------------------------------------------------------
853
854 wxOutputStream::wxOutputStream()
855 {
856 }
857
858 wxOutputStream::~wxOutputStream()
859 {
860 }
861
862 size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
863 size_t WXUNUSED(bufsize))
864 {
865 return 0;
866 }
867
868 void wxOutputStream::PutC(char c)
869 {
870 Write(&c, 1);
871 }
872
873 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
874 {
875 m_lastcount = OnSysWrite(buffer, size);
876 return *this;
877 }
878
879 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
880 {
881 stream_in.Read(*this);
882 return *this;
883 }
884
885 off_t wxOutputStream::TellO() const
886 {
887 return OnSysTell();
888 }
889
890 off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
891 {
892 return OnSysSeek(pos, mode);
893 }
894
895 void wxOutputStream::Sync()
896 {
897 }
898
899 #if wxUSE_SERIAL
900 wxOutputStream& wxOutputStream::operator<<(wxObject& obj)
901 {
902 wxObjectOutputStream obj_s(*this);
903 obj_s.SaveObject(obj);
904 return *this;
905 }
906 #endif // wxUSE_SERIAL
907
908 // ----------------------------------------------------------------------------
909 // wxCountingOutputStream
910 // ----------------------------------------------------------------------------
911
912 wxCountingOutputStream::wxCountingOutputStream ()
913 {
914 m_currentPos = 0;
915 }
916
917 size_t wxCountingOutputStream::GetSize() const
918 {
919 return m_lastcount;
920 }
921
922 size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
923 size_t size)
924 {
925 m_currentPos += size;
926 if (m_currentPos > m_lastcount)
927 m_lastcount = m_currentPos;
928
929 return m_currentPos;
930 }
931
932 off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode)
933 {
934 switch ( mode )
935 {
936 case wxFromStart:
937 m_currentPos = pos;
938 break;
939
940 case wxFromEnd:
941 m_currentPos = m_lastcount + pos;
942 break;
943
944 case wxFromCurrent:
945 m_currentPos += pos;
946 break;
947
948 default:
949 wxFAIL_MSG( _T("invalid seek mode") );
950 return wxInvalidOffset;
951 }
952
953 if (m_currentPos > m_lastcount)
954 m_lastcount = m_currentPos;
955
956 return m_currentPos;
957 }
958
959 off_t wxCountingOutputStream::OnSysTell() const
960 {
961 return m_currentPos;
962 }
963
964 // ----------------------------------------------------------------------------
965 // wxFilterInputStream
966 // ----------------------------------------------------------------------------
967
968 wxFilterInputStream::wxFilterInputStream()
969 {
970 m_parent_i_stream = NULL;
971 }
972
973 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
974 {
975 m_parent_i_stream = &stream;
976 }
977
978 wxFilterInputStream::~wxFilterInputStream()
979 {
980 }
981
982 // ----------------------------------------------------------------------------
983 // wxFilterOutputStream
984 // ----------------------------------------------------------------------------
985
986 wxFilterOutputStream::wxFilterOutputStream()
987 {
988 m_parent_o_stream = NULL;
989 }
990
991 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
992 {
993 m_parent_o_stream = &stream;
994 }
995
996 wxFilterOutputStream::~wxFilterOutputStream()
997 {
998 }
999
1000 // ----------------------------------------------------------------------------
1001 // wxBufferedInputStream
1002 // ----------------------------------------------------------------------------
1003
1004 wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1005 wxStreamBuffer *buffer)
1006 : wxFilterInputStream(s)
1007 {
1008 if ( buffer )
1009 {
1010 // use the buffer provided by the user
1011 m_i_streambuf = buffer;
1012 }
1013 else // create a default buffer
1014 {
1015 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
1016
1017 m_i_streambuf->SetBufferIO(1024);
1018 }
1019 }
1020
1021 wxBufferedInputStream::~wxBufferedInputStream()
1022 {
1023 m_parent_i_stream->SeekI(-m_i_streambuf->GetBytesLeft(), wxFromCurrent);
1024
1025 delete m_i_streambuf;
1026 }
1027
1028 char wxBufferedInputStream::Peek()
1029 {
1030 return m_i_streambuf->Peek();
1031 }
1032
1033 wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1034 {
1035 size_t retsize;
1036
1037 retsize = GetWBack(buf, size);
1038 m_lastcount = retsize;
1039 if ( retsize == size )
1040 {
1041 m_lasterror = wxStream_NOERROR;
1042 return *this;
1043 }
1044 size -= retsize;
1045 buf = (char *)buf + retsize;
1046
1047 m_i_streambuf->Read(buf, size);
1048
1049 return *this;
1050 }
1051
1052 off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
1053 {
1054 return m_i_streambuf->Seek(pos, mode);
1055 }
1056
1057 off_t wxBufferedInputStream::TellI() const
1058 {
1059 return m_i_streambuf->Tell();
1060 }
1061
1062 size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
1063 {
1064 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
1065 }
1066
1067 off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode)
1068 {
1069 return m_parent_i_stream->SeekI(seek, mode);
1070 }
1071
1072 off_t wxBufferedInputStream::OnSysTell() const
1073 {
1074 return m_parent_i_stream->TellI();
1075 }
1076
1077 void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1078 {
1079 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1080
1081 delete m_i_streambuf;
1082 m_i_streambuf = buffer;
1083 }
1084
1085 // ----------------------------------------------------------------------------
1086 // wxBufferedOutputStream
1087 // ----------------------------------------------------------------------------
1088
1089 wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1090 wxStreamBuffer *buffer)
1091 : wxFilterOutputStream(s)
1092 {
1093 if ( buffer )
1094 {
1095 m_o_streambuf = buffer;
1096 }
1097 else // create a default one
1098 {
1099 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1100
1101 m_o_streambuf->SetBufferIO(1024);
1102 }
1103 }
1104
1105 wxBufferedOutputStream::~wxBufferedOutputStream()
1106 {
1107 Sync();
1108 delete m_o_streambuf;
1109 }
1110
1111 wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
1112 {
1113 m_lastcount = 0;
1114 m_o_streambuf->Write(buffer, size);
1115 return *this;
1116 }
1117
1118 off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode)
1119 {
1120 Sync();
1121 return m_o_streambuf->Seek(pos, mode);
1122 }
1123
1124 off_t wxBufferedOutputStream::TellO() const
1125 {
1126 return m_o_streambuf->Tell();
1127 }
1128
1129 void wxBufferedOutputStream::Sync()
1130 {
1131 m_o_streambuf->FlushBuffer();
1132 m_parent_o_stream->Sync();
1133 }
1134
1135 size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
1136 {
1137 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
1138 }
1139
1140 off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode)
1141 {
1142 return m_parent_o_stream->SeekO(seek, mode);
1143 }
1144
1145 off_t wxBufferedOutputStream::OnSysTell() const
1146 {
1147 return m_parent_o_stream->TellO();
1148 }
1149
1150 size_t wxBufferedOutputStream::GetSize() const
1151 {
1152 return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
1153 }
1154
1155 void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1156 {
1157 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1158
1159 delete m_o_streambuf;
1160 m_o_streambuf = buffer;
1161 }
1162
1163 // ----------------------------------------------------------------------------
1164 // Some IOManip function
1165 // ----------------------------------------------------------------------------
1166
1167 wxOutputStream& wxEndL(wxOutputStream& stream)
1168 {
1169 #ifdef __MSW__
1170 return stream.Write("\r\n", 2);
1171 #else
1172 #ifdef __WXMAC__
1173 return stream.Write("\r", 1);
1174 #else
1175 return stream.Write("\n", 1);
1176 #endif
1177 #endif
1178 }
1179
1180 #endif
1181 // wxUSE_STREAMS