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