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