* Fixes (AIF works on Linux)
[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 #include <ctype.h>
19 #include <wx/stream.h>
20 #include <wx/datstrm.h>
21 #include <wx/objstrm.h>
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #define BUF_TEMP_SIZE 10000
28
29 // ----------------------------------------------------------------------------
30 // wxStreamBuffer
31 // ----------------------------------------------------------------------------
32
33 #define CHECK_ERROR(err) \
34 if (m_stream->m_lasterror == wxStream_NOERROR) \
35 m_stream->m_lasterror = err
36
37 wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
38 : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL),
39 m_buffer_size(0), m_wback(NULL), m_wbacksize(0), m_wbackcur(0),
40 m_fixed(TRUE), m_flushable(TRUE), m_stream(&stream),
41 m_mode(mode), m_destroybuf(FALSE), m_destroystream(FALSE)
42 {
43 }
44
45 wxStreamBuffer::wxStreamBuffer(BufMode mode)
46 : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL),
47 m_buffer_size(0), m_wback(NULL), m_wbacksize(0), m_wbackcur(0),
48 m_fixed(TRUE), m_flushable(FALSE), m_stream(NULL),
49 m_mode(mode), m_destroybuf(FALSE), m_destroystream(TRUE)
50 {
51 m_stream = new wxStreamBase();
52 }
53
54 wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
55 {
56 m_buffer_start = buffer.m_buffer_start;
57 m_buffer_end = buffer.m_buffer_end;
58 m_buffer_pos = buffer.m_buffer_pos;
59 m_buffer_size = buffer.m_buffer_size;
60 m_fixed = buffer.m_fixed;
61 m_flushable = buffer.m_flushable;
62 m_stream = buffer.m_stream;
63 m_mode = buffer.m_mode;
64 m_destroybuf = FALSE;
65 m_destroystream = FALSE;
66 m_wback = NULL;
67 m_wbacksize = 0;
68 m_wbackcur = 0;
69 }
70
71 wxStreamBuffer::~wxStreamBuffer()
72 {
73 if (m_wback)
74 free(m_wback);
75 if (m_destroybuf)
76 wxDELETEA(m_buffer_start);
77 if (m_destroystream)
78 delete m_stream;
79 }
80
81 size_t wxStreamBuffer::WriteBack(const char *buf, size_t bufsize)
82 {
83 char *ptrback;
84
85 ptrback = AllocSpaceWBack(bufsize);
86 if (!ptrback)
87 return 0;
88
89 memcpy(ptrback, buf, bufsize);
90 return bufsize;
91 }
92
93 bool wxStreamBuffer::WriteBack(char c)
94 {
95 char *ptrback;
96
97 ptrback = AllocSpaceWBack(1);
98 if (!ptrback)
99 return FALSE;
100
101 *ptrback = c;
102 return TRUE;
103 }
104
105 void wxStreamBuffer::SetBufferIO(char *buffer_start, char *buffer_end)
106 {
107 if (m_destroybuf)
108 wxDELETEA(m_buffer_start);
109 m_buffer_start = buffer_start;
110 m_buffer_end = buffer_end;
111
112 m_buffer_size = m_buffer_end-m_buffer_start;
113 m_destroybuf = FALSE;
114 ResetBuffer();
115 }
116
117 void wxStreamBuffer::SetBufferIO(size_t bufsize)
118 {
119 char *b_start;
120
121 if (m_destroybuf)
122 wxDELETEA(m_buffer_start);
123
124 if (!bufsize) {
125 m_buffer_start = NULL;
126 m_buffer_end = NULL;
127 m_buffer_pos = NULL;
128 m_buffer_size = 0;
129 return;
130 }
131
132 b_start = new char[bufsize];
133 SetBufferIO(b_start, b_start + bufsize);
134 m_destroybuf = TRUE;
135 }
136
137 void wxStreamBuffer::ResetBuffer()
138 {
139 m_stream->m_lasterror = wxStream_NOERROR;
140 if (m_mode == read)
141 m_buffer_pos = m_buffer_end;
142 else
143 m_buffer_pos = m_buffer_start;
144 }
145
146 char *wxStreamBuffer::AllocSpaceWBack(size_t needed_size)
147 {
148 char *temp_b;
149
150 m_wbacksize += needed_size;
151
152 if (!m_wback)
153 temp_b = (char *)malloc(m_wbacksize);
154 else
155 temp_b = (char *)realloc(m_wback, m_wbacksize);
156
157 if (!temp_b)
158 return NULL;
159 m_wback = temp_b;
160 printf("Buffer(0x%x)->Write: 0x%x, %d\n", this, m_wback, m_wbacksize);
161 return (char *)(m_wback+(m_wbacksize-needed_size));
162 }
163
164 size_t wxStreamBuffer::GetWBack(char *buf, size_t bsize)
165 {
166 size_t s_toget = m_wbacksize-m_wbackcur;
167
168 printf("Buffer(0x%x): 0x%x, %d\n", this, m_wback, m_wbacksize);
169 if (bsize < s_toget)
170 s_toget = bsize;
171
172 memcpy(buf, (m_wback+m_wbackcur), s_toget);
173
174 m_wbackcur += s_toget;
175 if (m_wbackcur == m_wbacksize) {
176 free(m_wback);
177 m_wback = (char *)NULL;
178 m_wbacksize = 0;
179 m_wbackcur = 0;
180 }
181
182 return s_toget;
183 }
184
185 bool wxStreamBuffer::FillBuffer()
186 {
187 size_t count;
188
189 count = m_stream->OnSysRead(m_buffer_start, m_buffer_size);
190 m_buffer_end = m_buffer_start+count;
191 m_buffer_pos = m_buffer_start;
192
193 if (count == 0)
194 return FALSE;
195 return TRUE;
196 }
197
198 bool wxStreamBuffer::FlushBuffer()
199 {
200 size_t count, current;
201
202 if (m_buffer_pos == m_buffer_start || !m_flushable)
203 return FALSE;
204
205 current = m_buffer_pos-m_buffer_start;
206 count = m_stream->OnSysWrite(m_buffer_start, current);
207 if (count != current)
208 return FALSE;
209 m_buffer_pos = m_buffer_start;
210
211 return TRUE;
212 }
213
214 void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
215 {
216 size_t s_toget = m_buffer_end-m_buffer_pos;
217
218 if (size < s_toget)
219 s_toget = size;
220
221 memcpy(buffer, m_buffer_pos, s_toget);
222 m_buffer_pos += s_toget;
223 }
224
225 void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
226 {
227 size_t s_toput = m_buffer_end-m_buffer_pos;
228
229 if (s_toput < size && !m_fixed) {
230 m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size+size);
231 // I round a bit
232 m_buffer_size += size;
233 m_buffer_end = m_buffer_start+m_buffer_size;
234 s_toput = size;
235 }
236 if (s_toput > size)
237 s_toput = size;
238 memcpy(m_buffer_pos, buffer, s_toput);
239 m_buffer_pos += s_toput;
240 }
241
242 void wxStreamBuffer::PutChar(char c)
243 {
244 wxASSERT(m_stream != NULL);
245
246 if (!m_buffer_size) {
247 m_stream->OnSysWrite(&c, 1);
248 return;
249 }
250
251 if (!GetDataLeft() && !FlushBuffer()) {
252 CHECK_ERROR(wxStream_READ_ERR);
253 return;
254 }
255
256 PutToBuffer(&c, 1);
257 m_stream->m_lastcount = 1;
258 }
259
260 char wxStreamBuffer::GetChar()
261 {
262 char c;
263
264 wxASSERT(m_stream != NULL);
265
266 if (!m_buffer_size) {
267 m_stream->OnSysRead(&c, 1);
268 return c;
269 }
270
271 if (!GetDataLeft()) {
272 CHECK_ERROR(wxStream_READ_ERR);
273 return 0;
274 }
275
276 GetFromBuffer(&c, 1);
277 m_stream->m_lastcount = 1;
278 return c;
279 }
280
281 size_t wxStreamBuffer::Read(void *buffer, size_t size)
282 {
283 wxASSERT(m_stream != NULL);
284
285 // ------------------
286 // Buffering disabled
287 // ------------------
288
289 m_stream->m_lasterror = wxStream_NOERROR;
290 m_stream->m_lastcount = GetWBack((char *)buffer, size);
291 size -= m_stream->m_lastcount;
292 if (size == 0)
293 return m_stream->m_lastcount;
294
295 buffer = (void *)((char *)buffer+m_stream->m_lastcount);
296
297 if (!m_buffer_size)
298 return (m_stream->m_lastcount += m_stream->OnSysRead(buffer, size));
299
300 // -----------------
301 // Buffering enabled
302 // -----------------
303 size_t buf_left, orig_size = size;
304
305 while (size > 0) {
306 buf_left = GetDataLeft();
307
308 // First case: the requested buffer is larger than the stream buffer,
309 // we split it.
310 if (size > buf_left) {
311 GetFromBuffer(buffer, buf_left);
312 size -= buf_left;
313 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
314
315 if (!FillBuffer()) {
316 CHECK_ERROR(wxStream_READ_ERR);
317 return (m_stream->m_lastcount = orig_size-size);
318 }
319 } else {
320
321 // Second case: we just copy from the stream buffer.
322 GetFromBuffer(buffer, size);
323 break;
324 }
325 }
326 return (m_stream->m_lastcount += orig_size);
327 }
328
329 size_t wxStreamBuffer::Read(wxStreamBuffer *s_buf)
330 {
331 char buf[BUF_TEMP_SIZE];
332 size_t s = 0, bytes_read = BUF_TEMP_SIZE;
333
334 while (bytes_read == BUF_TEMP_SIZE) {
335 bytes_read = Read(buf, bytes_read);
336 bytes_read = s_buf->Write(buf, bytes_read);
337 s += bytes_read;
338 }
339 return s;
340 }
341
342 size_t wxStreamBuffer::Write(const void *buffer, size_t size)
343 {
344 wxASSERT(m_stream != NULL);
345
346 // ------------------
347 // Buffering disabled
348 // ------------------
349
350 m_stream->m_lasterror = wxStream_NOERROR;
351 if (!m_buffer_size)
352 return (m_stream->m_lastcount = m_stream->OnSysWrite(buffer, size));
353
354 // ------------------
355 // Buffering enabled
356 // ------------------
357
358 size_t buf_left, orig_size = size;
359
360 while (size > 0) {
361 buf_left = m_buffer_end - m_buffer_pos;
362
363 // First case: the buffer to write is larger than the stream buffer,
364 // we split it
365 if (size > buf_left) {
366 PutToBuffer(buffer, buf_left);
367 size -= buf_left;
368 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
369
370 if (!FlushBuffer()) {
371 CHECK_ERROR(wxStream_WRITE_ERR);
372 return (m_stream->m_lastcount = orig_size-size);
373 }
374
375 m_buffer_pos = m_buffer_start;
376
377 } else {
378
379 // Second case: just copy it in the stream buffer.
380 PutToBuffer(buffer, size);
381 break;
382 }
383 }
384 return (m_stream->m_lastcount = orig_size);
385 }
386
387 size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
388 {
389 char buf[BUF_TEMP_SIZE];
390 size_t s = 0, bytes_count = BUF_TEMP_SIZE, b_count2;
391
392 while (bytes_count == BUF_TEMP_SIZE) {
393 b_count2 = sbuf->Read(buf, bytes_count);
394 bytes_count = Write(buf, b_count2);
395 if (b_count2 > bytes_count)
396 sbuf->WriteBack(buf+bytes_count, b_count2-bytes_count);
397 s += bytes_count;
398 }
399 return s;
400 }
401
402 off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode)
403 {
404 off_t ret_off, diff, last_access;
405
406 last_access = GetLastAccess();
407
408 if (!m_flushable) {
409 diff = pos + GetIntPosition();
410 if (diff < 0 || diff > last_access)
411 return wxInvalidOffset;
412 SetIntPosition(diff);
413 return diff;
414 }
415
416 switch (mode) {
417 case wxFromStart: {
418 // We'll try to compute an internal position later ...
419 ret_off = m_stream->OnSysSeek(pos, wxFromStart);
420 ResetBuffer();
421 return ret_off;
422 }
423 case wxFromCurrent: {
424 diff = pos + GetIntPosition();
425
426 if ( (diff > last_access) || (diff < 0) ) {
427 ret_off = m_stream->OnSysSeek(pos, wxFromCurrent);
428 ResetBuffer();
429 return ret_off;
430 } else {
431 SetIntPosition(diff);
432 return pos;
433 }
434 }
435 case wxFromEnd:
436 // Hard to compute: always seek to the requested position.
437 ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
438 ResetBuffer();
439 return ret_off;
440 }
441 return wxInvalidOffset;
442 }
443
444 off_t wxStreamBuffer::Tell() const
445 {
446 off_t pos;
447
448 if (m_flushable) {
449 pos = m_stream->OnSysTell();
450 if (pos == wxInvalidOffset)
451 return wxInvalidOffset;
452 return pos - GetLastAccess() + GetIntPosition();
453 } else
454 return GetIntPosition();
455 }
456
457 size_t wxStreamBuffer::GetDataLeft()
458 {
459 if (m_buffer_end == m_buffer_pos && m_flushable)
460 FillBuffer();
461 return m_buffer_end-m_buffer_pos;
462 }
463
464 // ----------------------------------------------------------------------------
465 // wxStreamBase
466 // ----------------------------------------------------------------------------
467
468 wxStreamBase::wxStreamBase()
469 {
470 m_lasterror = wxStream_NOERROR;
471 m_lastcount = 0;
472 }
473
474 wxStreamBase::~wxStreamBase()
475 {
476 }
477
478 size_t wxStreamBase::OnSysRead(void *WXUNUSED(buffer), size_t WXUNUSED(size))
479 {
480 return 0;
481 }
482
483 size_t wxStreamBase::OnSysWrite(const void *WXUNUSED(buffer), size_t WXUNUSED(bufsize))
484 {
485 return 0;
486 }
487
488 off_t wxStreamBase::OnSysSeek(off_t WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
489 {
490 return wxInvalidOffset;
491 }
492
493 off_t wxStreamBase::OnSysTell() const
494 {
495 return wxInvalidOffset;
496 }
497
498 // ----------------------------------------------------------------------------
499 // wxInputStream
500 // ----------------------------------------------------------------------------
501
502 wxInputStream::wxInputStream()
503 : wxStreamBase()
504 {
505 m_i_destroybuf = TRUE;
506 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
507 }
508
509 wxInputStream::wxInputStream(wxStreamBuffer *buffer)
510 : wxStreamBase()
511 {
512 m_i_destroybuf = FALSE;
513 m_i_streambuf = buffer;
514 }
515
516 wxInputStream::~wxInputStream()
517 {
518 if (m_i_destroybuf)
519 delete m_i_streambuf;
520 }
521
522 char wxInputStream::GetC()
523 {
524 char c;
525 m_i_streambuf->Read(&c, 1);
526 return c;
527 }
528
529 wxInputStream& wxInputStream::Read(void *buffer, size_t size)
530 {
531 m_i_streambuf->Read(buffer, size);
532 // wxStreamBuffer sets all variables for us
533 return *this;
534 }
535
536 char wxInputStream::Peek()
537 {
538 m_i_streambuf->GetDataLeft();
539
540 return *(m_i_streambuf->GetBufferPos());
541 }
542
543
544 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
545 {
546 char buf[BUF_TEMP_SIZE];
547 size_t bytes_read = BUF_TEMP_SIZE;
548
549 while (bytes_read == BUF_TEMP_SIZE) {
550 bytes_read = Read(buf, bytes_read).LastRead();
551 bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
552 }
553 return *this;
554 }
555
556 off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
557 {
558 return m_i_streambuf->Seek(pos, mode);
559 }
560
561 off_t wxInputStream::TellI() const
562 {
563 return m_i_streambuf->Tell();
564 }
565
566 // --------------------
567 // Overloaded operators
568 // --------------------
569
570 wxInputStream& wxInputStream::operator>>(wxString& line)
571 {
572 wxDataInputStream s(*this);
573
574 line = s.ReadLine();
575 return *this;
576 }
577
578 wxInputStream& wxInputStream::operator>>(char& c)
579 {
580 c = GetC();
581 return *this;
582 }
583
584 wxInputStream& wxInputStream::operator>>(short& i)
585 {
586 long l;
587
588 *this >> l;
589 i = (short)l;
590 return *this;
591 }
592
593 wxInputStream& wxInputStream::operator>>(int& i)
594 {
595 long l;
596
597 *this >> l;
598 i = (short)l;
599 return *this;
600 }
601
602 wxInputStream& wxInputStream::operator>>(long& i)
603 {
604 /* I only implemented a simple integer parser */
605 int c, sign;
606
607 while (isspace( c = GetC() ) )
608 /* Do nothing */ ;
609
610 i = 0;
611 if (! (c == '-' || isdigit(c)) ) {
612 InputStreamBuffer()->WriteBack(c);
613 return *this;
614 }
615
616 if (c == '-') {
617 sign = -1;
618 c = GetC();
619 } else
620 sign = 1;
621
622 while (isdigit(c)) {
623 i = i*10 + c;
624 c = GetC();
625 }
626
627 i *= sign;
628
629 return *this;
630 }
631
632 wxInputStream& wxInputStream::operator>>(double& f)
633 {
634 /* I only implemented a simple float parser */
635 int c, sign;
636
637 while (isspace( c = GetC() ) )
638 /* Do nothing */ ;
639
640 f = 0.0;
641 if (! (c == '-' || isdigit(c)) ) {
642 InputStreamBuffer()->WriteBack(c);
643 return *this;
644 }
645
646 if (c == '-') {
647 sign = -1;
648 c = GetC();
649 } else
650 sign = 1;
651
652 while (isdigit(c)) {
653 f = f*10 + (c - '0');
654 c = GetC();
655 }
656
657 if (c == '.') {
658 double f_multiplicator = (double) 0.1;
659 c = GetC();
660
661 while (isdigit(c)) {
662 f += (c-'0')*f_multiplicator;
663 f_multiplicator /= 10;
664 c = GetC();
665 }
666 }
667
668 f *= sign;
669
670 return *this;
671 }
672
673 #if wxUSE_SERIAL
674 wxInputStream& wxInputStream::operator>>(wxObject *& obj)
675 {
676 wxObjectInputStream obj_s(*this);
677 obj = obj_s.LoadObject();
678 return *this;
679 }
680 #endif
681
682
683 // ----------------------------------------------------------------------------
684 // wxOutputStream
685 // ----------------------------------------------------------------------------
686 wxOutputStream::wxOutputStream()
687 : wxStreamBase()
688 {
689 m_o_destroybuf = TRUE;
690 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
691 }
692
693 wxOutputStream::wxOutputStream(wxStreamBuffer *buffer)
694 : wxStreamBase()
695 {
696 m_o_destroybuf = FALSE;
697 m_o_streambuf = buffer;
698 }
699
700 wxOutputStream::~wxOutputStream()
701 {
702 if (m_o_destroybuf)
703 delete m_o_streambuf;
704 }
705
706 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
707 {
708 m_o_streambuf->Write(buffer, size);
709 return *this;
710 }
711
712 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
713 {
714 stream_in.Read(*this);
715 return *this;
716 }
717
718 off_t wxOutputStream::TellO() const
719 {
720 return m_o_streambuf->Tell();
721 }
722
723 off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
724 {
725 return m_o_streambuf->Seek(pos, mode);
726 }
727
728 void wxOutputStream::Sync()
729 {
730 m_o_streambuf->FlushBuffer();
731 }
732
733 wxOutputStream& wxOutputStream::operator<<(const char *string)
734 {
735 return Write(string, strlen(string));
736 }
737
738 wxOutputStream& wxOutputStream::operator<<(wxString& string)
739 {
740 return Write(string, string.Len());
741 }
742
743 wxOutputStream& wxOutputStream::operator<<(char c)
744 {
745 return Write(&c, 1);
746 }
747
748 wxOutputStream& wxOutputStream::operator<<(short i)
749 {
750 wxString strint;
751
752 strint.Printf("%i", i);
753 return Write(strint, strint.Len());
754 }
755
756 wxOutputStream& wxOutputStream::operator<<(int i)
757 {
758 wxString strint;
759
760 strint.Printf("%i", i);
761 return Write(strint, strint.Len());
762 }
763
764 wxOutputStream& wxOutputStream::operator<<(long i)
765 {
766 wxString strlong;
767
768 strlong.Printf("%i", i);
769 return Write((const char *)strlong, strlong.Len());
770 }
771
772 wxOutputStream& wxOutputStream::operator<<(double f)
773 {
774 wxString strfloat;
775
776 strfloat.Printf("%f", f);
777 return Write(strfloat, strfloat.Len());
778 }
779
780 #if wxUSE_SERIAL
781 wxOutputStream& wxOutputStream::operator<<(wxObject& obj)
782 {
783 wxObjectOutputStream obj_s(*this);
784 obj_s.SaveObject(obj);
785 return *this;
786 }
787 #endif
788
789 // ----------------------------------------------------------------------------
790 // wxFilterInputStream
791 // ----------------------------------------------------------------------------
792 wxFilterInputStream::wxFilterInputStream()
793 : wxInputStream(NULL)
794 {
795 // WARNING streambuf set to NULL !
796 }
797
798 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
799 : wxInputStream(stream.InputStreamBuffer())
800 {
801 m_parent_i_stream = &stream;
802 }
803
804 wxFilterInputStream::~wxFilterInputStream()
805 {
806 }
807
808 // ----------------------------------------------------------------------------
809 // wxFilterOutputStream
810 // ----------------------------------------------------------------------------
811 wxFilterOutputStream::wxFilterOutputStream()
812 : wxOutputStream(NULL)
813 {
814 }
815
816 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
817 : wxOutputStream(stream.OutputStreamBuffer())
818 {
819 m_parent_o_stream = &stream;
820 }
821
822 wxFilterOutputStream::~wxFilterOutputStream()
823 {
824 }
825
826 // ----------------------------------------------------------------------------
827 // Some IOManip function
828 // ----------------------------------------------------------------------------
829
830 wxOutputStream& wxEndL(wxOutputStream& stream)
831 {
832 #ifdef __MSW__
833 return stream.Write("\r\n", 2);
834 #else
835 return stream.Write("\n", 1);
836 #endif
837 }