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