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