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