]> git.saurik.com Git - wxWidgets.git/blame - src/common/stream.cpp
added test for writing empty value to the config
[wxWidgets.git] / src / common / stream.cpp
CommitLineData
3d4c6a21 1/////////////////////////////////////////////////////////////////////////////
49e399d8 2// Name: src/common/stream.cpp
3d4c6a21
GL
3// Purpose: wxStream base classes
4// Author: Guilhem Lavaux
49e399d8
VZ
5// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory,
6// general code review
3d4c6a21
GL
7// Created: 11/07/98
8// RCS-ID: $Id$
9// Copyright: (c) Guilhem Lavaux
10// Licence: wxWindows license
11/////////////////////////////////////////////////////////////////////////////
12
49e399d8
VZ
13// ============================================================================
14// declarations
15// ============================================================================
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
47fc03d2 20
3d4c6a21 21#ifdef __GNUG__
47fc03d2 22 #pragma implementation "stream.h"
3d4c6a21
GL
23#endif
24
db138a4c
JS
25// For compilers that support precompilation, includes "wx.h".
26#include "wx/wxprec.h"
ce4169a4
RR
27
28#ifdef __BORLANDC__
29 #pragma hdrstop
30#endif
31
32#ifndef WX_PRECOMP
33 #include "wx/defs.h"
34#endif
35
36#if wxUSE_STREAMS
37
6d44bf31 38#include <ctype.h>
3096bd2f
VZ
39#include "wx/stream.h"
40#include "wx/datstrm.h"
41#include "wx/objstrm.h"
733b8ed3 42#include "wx/textfile.h"
db138a4c 43
49e399d8
VZ
44// ----------------------------------------------------------------------------
45// constants
46// ----------------------------------------------------------------------------
47
48// the temporary buffer size used when copying from stream to stream
8ef6a930
GL
49#define BUF_TEMP_SIZE 10000
50
49e399d8
VZ
51// ============================================================================
52// implementation
53// ============================================================================
54
6d44bf31
GL
55// ----------------------------------------------------------------------------
56// wxStreamBuffer
57// ----------------------------------------------------------------------------
58
49e399d8
VZ
59void wxStreamBuffer::SetError(wxStreamError err)
60{
61 if ( m_stream->m_lasterror == wxStream_NOERROR )
62 m_stream->m_lasterror = err;
63}
64
65void wxStreamBuffer::InitBuffer()
66{
67 m_buffer_start =
68 m_buffer_end =
69 m_buffer_pos = NULL;
70 m_buffer_size = 0;
71
72 // there is nothing to destroy anyhow
73 m_destroybuf = FALSE;
74}
75
76void wxStreamBuffer::Init()
77{
78 InitBuffer();
79
80 m_fixed = TRUE;
81}
926c550d 82
75ed1d15 83wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
6d44bf31 84{
a2bd1fbb
VZ
85 Init();
86
49e399d8
VZ
87 m_stream = &stream;
88 m_mode = mode;
89
90 m_flushable = TRUE;
91 m_destroystream = FALSE;
6d44bf31
GL
92}
93
84b46c35 94wxStreamBuffer::wxStreamBuffer(BufMode mode)
84b46c35 95{
a2bd1fbb
VZ
96 Init();
97
49e399d8
VZ
98 m_stream = new wxStreamBase;
99 m_mode = mode;
100
101 m_flushable = FALSE;
102 m_destroystream = TRUE;
84b46c35
GL
103}
104
105wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
106{
49e399d8
VZ
107 // doing this has big chances to lead to a crashwhen the source buffer is
108 // destroyed (otherwise assume the caller knows what he does)
109 wxASSERT_MSG( !buffer.m_destroybuf && !buffer.m_destroystream,
110 _T("it's a bad idea to copy this buffer") );
111
112 m_buffer_start = buffer.m_buffer_start;
113 m_buffer_end = buffer.m_buffer_end;
114 m_buffer_pos = buffer.m_buffer_pos;
115 m_buffer_size = buffer.m_buffer_size;
116 m_fixed = buffer.m_fixed;
117 m_flushable = buffer.m_flushable;
118 m_stream = buffer.m_stream;
119 m_mode = buffer.m_mode;
120 m_destroybuf = FALSE;
121 m_destroystream = FALSE;
84b46c35
GL
122}
123
49e399d8 124void wxStreamBuffer::FreeBuffer()
6d44bf31 125{
49e399d8
VZ
126 if ( m_destroybuf )
127 free(m_buffer_start);
6d44bf31
GL
128}
129
49e399d8 130wxStreamBuffer::~wxStreamBuffer()
6d44bf31 131{
49e399d8 132 FreeBuffer();
6d44bf31 133
49e399d8
VZ
134 if ( m_destroystream )
135 delete m_stream;
6d44bf31
GL
136}
137
47fc03d2
VZ
138wxInputStream *wxStreamBuffer::GetInputStream() const
139{
140 return m_mode == write ? NULL : (wxInputStream *)m_stream;
141}
142
143wxOutputStream *wxStreamBuffer::GetOutputStream() const
144{
145 return m_mode == read ? NULL : (wxOutputStream *)m_stream;
146}
147
49e399d8
VZ
148void wxStreamBuffer::SetBufferIO(void *buffer_start,
149 void *buffer_end,
150 bool takeOwnership)
67c8c225
VZ
151{
152 SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start,
153 takeOwnership);
154}
155
156void wxStreamBuffer::SetBufferIO(void *start,
157 size_t len,
158 bool takeOwnership)
6d44bf31 159{
49e399d8
VZ
160 // start by freeing the old buffer
161 FreeBuffer();
885ee235 162
67c8c225
VZ
163 m_buffer_start = (char *)start;
164 m_buffer_end = m_buffer_start + len;
6d44bf31 165
67c8c225 166 m_buffer_size = len;
49e399d8
VZ
167
168 // if we own it, we free it
421db2ad 169 m_destroybuf = takeOwnership;
49e399d8
VZ
170
171 ResetBuffer();
172}
6d44bf31 173
49e399d8
VZ
174void wxStreamBuffer::SetBufferIO(size_t bufsize)
175{
176 // start by freeing the old buffer
177 FreeBuffer();
178
179 if ( bufsize )
180 {
67c8c225 181 SetBufferIO(malloc(bufsize), bufsize, TRUE /* take ownership */);
49e399d8
VZ
182 }
183 else // no buffer size => no buffer
184 {
185 InitBuffer();
186 }
6d44bf31
GL
187}
188
189void wxStreamBuffer::ResetBuffer()
190{
49e399d8
VZ
191 wxCHECK_RET( m_stream, _T("should have a stream in wxStreamBuffer") );
192
193 m_stream->m_lasterror = wxStream_NOERROR;
194 m_stream->m_lastcount = 0;
195 if (m_mode == read && m_flushable)
196 m_buffer_pos = m_buffer_end;
197 else
198 m_buffer_pos = m_buffer_start;
6d44bf31
GL
199}
200
49e399d8 201// fill the buffer with as much data as possible (only for read buffers)
75ed1d15
GL
202bool wxStreamBuffer::FillBuffer()
203{
47fc03d2
VZ
204 wxInputStream *inStream = GetInputStream();
205
206 wxCHECK_MSG( inStream, FALSE, _T("should have a stream in wxStreamBuffer") );
75ed1d15 207
47fc03d2 208 size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
49e399d8
VZ
209 if ( !count )
210 return FALSE;
75ed1d15 211
49e399d8
VZ
212 m_buffer_end = m_buffer_start + count;
213 m_buffer_pos = m_buffer_start;
214
215 return TRUE;
75ed1d15
GL
216}
217
49e399d8 218// write the buffer contents to the stream (only for write buffers)
75ed1d15
GL
219bool wxStreamBuffer::FlushBuffer()
220{
49e399d8 221 wxCHECK_MSG( m_flushable, FALSE, _T("can't flush this buffer") );
75ed1d15 222
49e399d8
VZ
223 // FIXME: what is this check for? (VZ)
224 if ( m_buffer_pos == m_buffer_start )
225 return FALSE;
75ed1d15 226
47fc03d2
VZ
227 wxOutputStream *outStream = GetOutputStream();
228
229 wxCHECK_MSG( outStream, FALSE, _T("should have a stream in wxStreamBuffer") );
49e399d8
VZ
230
231 size_t current = m_buffer_pos - m_buffer_start;
47fc03d2 232 size_t count = outStream->OnSysWrite(m_buffer_start, current);
49e399d8
VZ
233 if ( count != current )
234 return FALSE;
235
236 m_buffer_pos = m_buffer_start;
75ed1d15 237
49e399d8 238 return TRUE;
75ed1d15
GL
239}
240
49e399d8
VZ
241size_t wxStreamBuffer::GetDataLeft()
242{
243 /* Why is this done? RR. */
244 if ( m_buffer_pos == m_buffer_end && m_flushable)
245 FillBuffer();
246
247 return GetBytesLeft();
248}
249
250// copy up to size bytes from our buffer into the provided one
75ed1d15
GL
251void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
252{
49e399d8
VZ
253 // don't get more bytes than left in the buffer
254 size_t left = GetBytesLeft();
75ed1d15 255
49e399d8
VZ
256 if ( size > left )
257 size = left;
75ed1d15 258
49e399d8
VZ
259 memcpy(buffer, m_buffer_pos, size);
260 m_buffer_pos += size;
75ed1d15
GL
261}
262
49e399d8 263// copy the contents of the provided buffer into this one
75ed1d15
GL
264void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
265{
49e399d8
VZ
266 size_t left = GetBytesLeft();
267 if ( size > left )
268 {
269 if ( m_fixed )
270 {
271 // we can't realloc the buffer, so just copy what we can
272 size = left;
273 }
274 else // !m_fixed
275 {
276 // realloc the buffer to have enough space for the data
277 size_t delta = m_buffer_pos - m_buffer_start;
278
279 char *startOld = m_buffer_start;
280 m_buffer_size += size;
281 m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size);
282 if ( !m_buffer_start )
283 {
284 // don't leak memory if realloc() failed
285 m_buffer_start = startOld;
286 m_buffer_size -= size;
287
288 // what else can we do?
289 return;
290 }
291
292 // adjust the pointers invalidated by realloc()
293 m_buffer_pos = m_buffer_start + delta;
294 m_buffer_end = m_buffer_start + m_buffer_size;
295 }
56dc1ffd 296 }
49e399d8
VZ
297
298 memcpy(m_buffer_pos, buffer, size);
299 m_buffer_pos += size;
75ed1d15
GL
300}
301
84b46c35
GL
302void wxStreamBuffer::PutChar(char c)
303{
47fc03d2
VZ
304 wxOutputStream *outStream = GetOutputStream();
305
306 wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") );
84b46c35 307
49e399d8
VZ
308 // if we don't have buffer at all, just forward this call to the stream,
309 if ( !HasBuffer() )
310 {
47fc03d2 311 outStream->OnSysWrite(&c, 1);
49e399d8
VZ
312 }
313 else
314 {
315 // otherwise check we have enough space left
316 if ( !GetDataLeft() && !FlushBuffer() )
317 {
318 // we don't
319 SetError(wxStream_WRITE_ERR);
320 }
321 else
322 {
323 PutToBuffer(&c, 1);
324 m_stream->m_lastcount = 1;
325 }
326 }
84b46c35
GL
327}
328
6319afe3
GL
329char wxStreamBuffer::Peek()
330{
49e399d8
VZ
331 wxCHECK_MSG( m_stream && HasBuffer(), 0,
332 _T("should have the stream and the buffer in wxStreamBuffer") );
6319afe3 333
49e399d8
VZ
334 if ( !GetDataLeft() )
335 {
336 SetError(wxStream_READ_ERR);
337 return 0;
338 }
6319afe3 339
49e399d8
VZ
340 char c;
341 GetFromBuffer(&c, 1);
342 m_buffer_pos--;
6319afe3 343
49e399d8 344 return c;
6319afe3
GL
345}
346
84b46c35
GL
347char wxStreamBuffer::GetChar()
348{
47fc03d2
VZ
349 wxInputStream *inStream = GetInputStream();
350
351 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
84b46c35 352
49e399d8
VZ
353 char c;
354 if ( !HasBuffer() )
355 {
47fc03d2 356 inStream->OnSysRead(&c, 1);
49e399d8
VZ
357 }
358 else
359 {
360 if ( !GetDataLeft() )
361 {
362 SetError(wxStream_READ_ERR);
363 c = 0;
364 }
365 else
366 {
367 GetFromBuffer(&c, 1);
368 m_stream->m_lastcount = 1;
369 }
370 }
84b46c35 371
84b46c35 372 return c;
84b46c35
GL
373}
374
8ef6a930 375size_t wxStreamBuffer::Read(void *buffer, size_t size)
6d44bf31 376{
47fc03d2 377 wxInputStream *inStream = GetInputStream();
6d44bf31 378
47fc03d2 379 wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
7f42cff1 380
49e399d8
VZ
381 // lasterror is reset before all new IO calls
382 m_stream->m_lasterror = wxStream_NOERROR;
383
384 if ( !HasBuffer() )
385 {
47fc03d2 386 m_stream->m_lastcount = inStream->OnSysRead(buffer, size);
49e399d8
VZ
387 }
388 else // we have a buffer, use it
389 {
390 size_t orig_size = size;
391
392 while ( size > 0 )
393 {
394 size_t left = GetDataLeft();
395
396 // if the requested number of bytes if greater than the buffer
397 // size, read data in chunks
398 if ( size > left )
399 {
400 GetFromBuffer(buffer, left);
401 size -= left;
402 buffer = (char *)buffer + left;
403
404 if ( !FillBuffer() )
405 {
406 SetError(wxStream_EOF);
407 break;
408 }
409 }
410 else // otherwise just do it in one gulp
411 {
412 GetFromBuffer(buffer, size);
413 size = 0;
414 }
415 }
416
417 m_stream->m_lastcount = orig_size - size;
6d44bf31 418 }
49e399d8
VZ
419
420 return m_stream->m_lastcount;
6d44bf31
GL
421}
422
49e399d8
VZ
423// this should really be called "Copy()"
424size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
8ef6a930 425{
49e399d8 426 wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") );
8ef6a930 427
49e399d8
VZ
428 char buf[BUF_TEMP_SIZE];
429 size_t nRead,
430 total = 0;
7f42cff1 431
49e399d8
VZ
432 do
433 {
434 nRead = Read(dbuf, WXSIZEOF(buf));
435 if ( nRead )
436 {
437 nRead = dbuf->Write(buf, nRead);
438 total += nRead;
439 }
440 }
441 while ( nRead );
442
443 return total;
8ef6a930
GL
444}
445
446size_t wxStreamBuffer::Write(const void *buffer, size_t size)
6d44bf31 447{
47fc03d2
VZ
448 wxOutputStream *outStream = GetOutputStream();
449
450 wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
6d44bf31 451
49e399d8
VZ
452 // lasterror is reset before all new IO calls
453 m_stream->m_lasterror = wxStream_NOERROR;
6d44bf31 454
49e399d8
VZ
455 if ( !HasBuffer() && m_fixed )
456 {
457 // no buffer, just forward the call to the stream
47fc03d2 458 m_stream->m_lastcount = outStream->OnSysWrite(buffer, size);
49e399d8
VZ
459 }
460 else // we [may] have a buffer, use it
461 {
462 size_t orig_size = size;
463
464 while ( size > 0 )
465 {
466 size_t left = GetBytesLeft();
467
468 // if the buffer is too large to fit in the stream buffer, split
469 // it in smaller parts
470 //
471 // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
472 // we always go to the second case.
473 //
474 // FIXME: fine, but if it fails we should (re)try writing it by
475 // chunks as this will (hopefully) always work (VZ)
476 if ( size > left && m_fixed )
477 {
478 PutToBuffer(buffer, left);
479 size -= left;
480 buffer = (char *)buffer + left;
481
482 if ( !FlushBuffer() )
483 {
484 SetError(wxStream_WRITE_ERR);
485
486 break;
487 }
488
489 m_buffer_pos = m_buffer_start;
490 }
491 else // we can do it in one gulp
492 {
493 PutToBuffer(buffer, size);
494 size = 0;
495 }
496 }
497
498 m_stream->m_lastcount = orig_size - size;
6d44bf31 499 }
49e399d8
VZ
500
501 return m_stream->m_lastcount;
8ef6a930
GL
502}
503
504size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
505{
49e399d8
VZ
506 wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") );
507 wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") );
8ef6a930 508
49e399d8
VZ
509 char buf[BUF_TEMP_SIZE];
510 size_t nWrite,
511 total = 0;
7f42cff1 512
49e399d8
VZ
513 do
514 {
515 size_t nRead = sbuf->Read(buf, WXSIZEOF(buf));
516 if ( nRead )
517 {
518 nWrite = Write(buf, nRead);
519 if ( nWrite < nRead )
520 {
521 // put back data we couldn't copy
522 wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream();
523
524 in_stream->Ungetch(buf + nWrite, nRead - nWrite);
525 }
526
527 total += nWrite;
528 }
529 else
530 {
531 nWrite = 0;
532 }
533 }
534 while ( nWrite == WXSIZEOF(buf) );
fae05df5 535
49e399d8 536 return total;
75ed1d15
GL
537}
538
539off_t wxStreamBuffer::Seek(off_t pos, wxSeekMode mode)
540{
49e399d8 541 off_t ret_off, diff;
75ed1d15 542
49e399d8 543 off_t last_access = GetLastAccess();
75ed1d15 544
49e399d8
VZ
545 if ( !m_flushable )
546 {
547 switch (mode)
548 {
549 case wxFromStart:
550 diff = pos;
551 break;
552
553 case wxFromCurrent:
554 diff = pos + GetIntPosition();
555 break;
556
557 case wxFromEnd:
558 diff = pos + last_access;
559 break;
560
561 default:
562 wxFAIL_MSG( _T("invalid seek mode") );
563
564 return wxInvalidOffset;
565 }
566 if (diff < 0 || diff > last_access)
567 return wxInvalidOffset;
568 SetIntPosition(diff);
569 return diff;
d984207c 570 }
49e399d8
VZ
571
572 switch ( mode )
573 {
574 case wxFromStart:
575 // We'll try to compute an internal position later ...
576 ret_off = m_stream->OnSysSeek(pos, wxFromStart);
577 ResetBuffer();
578 return ret_off;
579
580 case wxFromCurrent:
581 diff = pos + GetIntPosition();
582
583 if ( (diff > last_access) || (diff < 0) )
584 {
585 // We must take into account the fact that we have read
586 // something previously.
587 ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
588 ResetBuffer();
589 return ret_off;
590 }
591 else
592 {
593 SetIntPosition(diff);
594 return pos;
595 }
596
597 case wxFromEnd:
598 // Hard to compute: always seek to the requested position.
599 ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
600 ResetBuffer();
601 return ret_off;
75ed1d15 602 }
49e399d8
VZ
603
604 return wxInvalidOffset;
75ed1d15
GL
605}
606
607off_t wxStreamBuffer::Tell() const
608{
c7a9fa36 609 off_t pos = m_stream->OnSysTell();
49e399d8 610 if ( pos == wxInvalidOffset )
c7a9fa36
RR
611 return wxInvalidOffset;
612
613 pos += GetIntPosition();
cd6ce4a9 614
49e399d8 615 if ( m_mode == read && m_flushable )
c7a9fa36 616 pos -= GetLastAccess();
cd6ce4a9 617
c7a9fa36 618 return pos;
75ed1d15
GL
619}
620
75ed1d15
GL
621// ----------------------------------------------------------------------------
622// wxStreamBase
623// ----------------------------------------------------------------------------
624
625wxStreamBase::wxStreamBase()
626{
c7a9fa36
RR
627 m_lasterror = wxStream_NOERROR;
628 m_lastcount = 0;
75ed1d15
GL
629}
630
631wxStreamBase::~wxStreamBase()
632{
633}
634
b9138710
VZ
635off_t wxStreamBase::OnSysSeek(off_t WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
636{
637 return wxInvalidOffset;
638}
639
640off_t wxStreamBase::OnSysTell() const
641{
642 return wxInvalidOffset;
643}
644
1678ad78
GL
645// ----------------------------------------------------------------------------
646// wxInputStream
647// ----------------------------------------------------------------------------
648
3d4c6a21 649wxInputStream::wxInputStream()
3d4c6a21 650{
49e399d8
VZ
651 m_wback = NULL;
652 m_wbacksize =
653 m_wbackcur = 0;
6d44bf31
GL
654}
655
fae05df5 656wxInputStream::~wxInputStream()
6d44bf31 657{
fae05df5 658 free(m_wback);
3d4c6a21
GL
659}
660
47fc03d2
VZ
661size_t wxInputStream::OnSysRead(void * WXUNUSED(buffer),
662 size_t WXUNUSED(bufsize))
663{
664 return 0;
665}
666
cd6ce4a9
VZ
667bool wxInputStream::Eof() const
668{
49e399d8 669 wxInputStream *self = wxConstCast(this, wxInputStream);
cd6ce4a9
VZ
670
671 char c;
672 self->Read(&c, 1);
4708a349
VZ
673
674 // some streams can know that they're at EOF before actually trying to
675 // read beyond the end of stream (e.g. files) while others have no way of
676 // knowing it, so to provide the same behaviour in all cases we only
677 // return TRUE from here if the character really couldn't be read
678 if ( !self->LastRead() && GetLastError() == wxSTREAM_EOF )
cd6ce4a9
VZ
679 {
680 return TRUE;
681 }
682
683 self->Ungetch(c);
684
685 return FALSE;
686}
687
fae05df5 688char *wxInputStream::AllocSpaceWBack(size_t needed_size)
3d4c6a21 689{
49e399d8 690 // get number of bytes left from previous wback buffer
c7a9fa36 691 size_t toget = m_wbacksize - m_wbackcur;
fae05df5 692
49e399d8
VZ
693 // allocate a buffer large enough to hold prev + new data
694 char *temp_b = (char *)malloc(needed_size + toget);
fae05df5 695
c7a9fa36
RR
696 if (!temp_b)
697 return NULL;
fae05df5 698
c7a9fa36
RR
699 /* copy previous data (and free old buffer) if needed */
700 if (m_wback)
701 {
702 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
703 free(m_wback);
704 }
5ac8158a 705
c7a9fa36
RR
706 /* done */
707 m_wback = temp_b;
708 m_wbackcur = 0;
709 m_wbacksize = needed_size + toget;
783ff666 710
49e399d8 711 return m_wback;
6d44bf31
GL
712}
713
49e399d8 714size_t wxInputStream::GetWBack(void *buf, size_t bsize)
6d44bf31 715{
49e399d8 716 size_t toget = m_wbacksize-m_wbackcur;
fae05df5 717
c7a9fa36
RR
718 if (!m_wback)
719 return 0;
a324a7bc 720
49e399d8
VZ
721 if (bsize < toget)
722 toget = bsize;
fae05df5 723
49e399d8 724 memcpy(buf, (m_wback+m_wbackcur), toget);
fae05df5 725
49e399d8 726 m_wbackcur += toget;
cd6ce4a9 727 if (m_wbackcur == m_wbacksize)
c7a9fa36
RR
728 {
729 free(m_wback);
49e399d8 730 m_wback = NULL;
c7a9fa36
RR
731 m_wbacksize = 0;
732 m_wbackcur = 0;
733 }
cd6ce4a9 734
49e399d8 735 return toget;
6d44bf31
GL
736}
737
8f7173ab 738size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
fae05df5 739{
c7a9fa36
RR
740 char *ptrback = AllocSpaceWBack(bufsize);
741 if (!ptrback)
742 return 0;
cd6ce4a9 743
c7a9fa36
RR
744 memcpy(ptrback, buf, bufsize);
745 return bufsize;
fae05df5
GL
746}
747
748bool wxInputStream::Ungetch(char c)
1e3eca9d 749{
49e399d8 750 void *ptrback = AllocSpaceWBack(1);
c7a9fa36
RR
751 if (!ptrback)
752 return FALSE;
1e3eca9d 753
49e399d8 754 *(char *)ptrback = c;
c7a9fa36 755 return TRUE;
fae05df5
GL
756}
757
758char wxInputStream::GetC()
759{
c7a9fa36
RR
760 char c;
761 Read(&c, 1);
762 return c;
1e3eca9d
GL
763}
764
49e399d8 765wxInputStream& wxInputStream::Read(void *buf, size_t size)
6d44bf31 766{
c7a9fa36 767 size_t retsize = GetWBack(buf, size);
cd6ce4a9 768 if (retsize == size)
c7a9fa36
RR
769 {
770 m_lastcount = size;
771 m_lasterror = wxStream_NOERROR;
772 return *this;
773 }
774 size -= retsize;
49e399d8 775 buf = (char *)buf + retsize;
fae05df5 776
c7a9fa36
RR
777 m_lastcount = OnSysRead(buf, size) + retsize;
778 return *this;
3d4c6a21
GL
779}
780
75ed1d15
GL
781char wxInputStream::Peek()
782{
c7a9fa36
RR
783 char c;
784 Read(&c, 1);
cd6ce4a9 785 if (m_lasterror == wxStream_NOERROR)
c7a9fa36
RR
786 {
787 Ungetch(c);
788 return c;
789 }
cd6ce4a9 790
c7a9fa36 791 return 0;
75ed1d15
GL
792}
793
3d4c6a21
GL
794wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
795{
cd6ce4a9 796 char buf[BUF_TEMP_SIZE];
c7a9fa36 797 size_t bytes_read = BUF_TEMP_SIZE;
3d4c6a21 798
cd6ce4a9 799 while (bytes_read == BUF_TEMP_SIZE)
c7a9fa36
RR
800 {
801 bytes_read = Read(buf, bytes_read).LastRead();
802 bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
803 }
804 return *this;
3d4c6a21
GL
805}
806
75ed1d15
GL
807off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
808{
c7a9fa36
RR
809 /* Should be check and improve, just to remove a slight bug !
810 I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
cd6ce4a9 811 if (m_lasterror==wxSTREAM_EOF)
c7a9fa36
RR
812 m_lasterror=wxSTREAM_NOERROR;
813
814 /* A call to SeekI() will automatically invalidate any previous call
815 to Ungetch(), otherwise it would be possible to SeekI() to one
816 one position, unread some bytes there, SeekI() to another position
19da7237
GRG
817 and the data would be corrupted.
818
819 GRG: Could add code here to try to navigate within the wback
820 buffer if possible, but is it really needed? It would only work
821 when seeking in wxFromCurrent mode, else it would invalidate
822 anyway...
823 */
cd6ce4a9 824 if (m_wback)
c7a9fa36
RR
825 {
826 free(m_wback);
49e399d8 827 m_wback = NULL;
c7a9fa36
RR
828 m_wbacksize = 0;
829 m_wbackcur = 0;
830 }
fe8aa971 831
c7a9fa36 832 return OnSysSeek(pos, mode);
75ed1d15
GL
833}
834
835off_t wxInputStream::TellI() const
836{
19da7237
GRG
837 /* GRG: Changed to make it compatible with the wback buffer */
838 off_t pos = OnSysTell();
839
840 if (pos != wxInvalidOffset)
841 pos -= (m_wbacksize - m_wbackcur);
842
843 return pos;
75ed1d15
GL
844}
845
846// --------------------
847// Overloaded operators
848// --------------------
849
fae05df5
GL
850#if wxUSE_SERIAL
851wxInputStream& wxInputStream::operator>>(wxObject *& obj)
1678ad78 852{
c7a9fa36
RR
853 wxObjectInputStream obj_s(*this);
854 obj = obj_s.LoadObject();
855 return *this;
1678ad78 856}
49e399d8 857#endif // wxUSE_SERIAL
1678ad78 858
1678ad78 859
fae05df5
GL
860// ----------------------------------------------------------------------------
861// wxOutputStream
862// ----------------------------------------------------------------------------
49e399d8 863
fae05df5 864wxOutputStream::wxOutputStream()
1678ad78 865{
1678ad78
GL
866}
867
fae05df5 868wxOutputStream::~wxOutputStream()
123a7fdd 869{
123a7fdd
GL
870}
871
47fc03d2
VZ
872size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
873 size_t WXUNUSED(bufsize))
874{
875 return 0;
876}
877
7513f9ff
GRG
878void wxOutputStream::PutC(char c)
879{
49e399d8 880 Write(&c, 1);
7513f9ff
GRG
881}
882
fae05df5 883wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
1678ad78 884{
c7a9fa36
RR
885 m_lastcount = OnSysWrite(buffer, size);
886 return *this;
1678ad78
GL
887}
888
fae05df5 889wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
38830220 890{
c7a9fa36
RR
891 stream_in.Read(*this);
892 return *this;
38830220
RR
893}
894
fae05df5 895off_t wxOutputStream::TellO() const
38830220 896{
c7a9fa36 897 return OnSysTell();
38830220
RR
898}
899
fae05df5 900off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
38830220 901{
c7a9fa36 902 return OnSysSeek(pos, mode);
38830220
RR
903}
904
fae05df5 905void wxOutputStream::Sync()
1678ad78 906{
1678ad78
GL
907}
908
47d67540 909#if wxUSE_SERIAL
fae05df5 910wxOutputStream& wxOutputStream::operator<<(wxObject& obj)
123a7fdd 911{
c7a9fa36
RR
912 wxObjectOutputStream obj_s(*this);
913 obj_s.SaveObject(obj);
914 return *this;
123a7fdd 915}
49e399d8 916#endif // wxUSE_SERIAL
123a7fdd 917
e2acb9ae
RR
918// ----------------------------------------------------------------------------
919// wxCountingOutputStream
920// ----------------------------------------------------------------------------
921
922wxCountingOutputStream::wxCountingOutputStream ()
e2acb9ae 923{
c7a9fa36 924 m_currentPos = 0;
e2acb9ae
RR
925}
926
927size_t wxCountingOutputStream::GetSize() const
928{
c7a9fa36 929 return m_lastcount;
e2acb9ae
RR
930}
931
49e399d8
VZ
932size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
933 size_t size)
e2acb9ae 934{
c7a9fa36 935 m_currentPos += size;
49e399d8
VZ
936 if (m_currentPos > m_lastcount)
937 m_lastcount = m_currentPos;
938
c7a9fa36 939 return m_currentPos;
e2acb9ae
RR
940}
941
942off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode)
943{
49e399d8
VZ
944 switch ( mode )
945 {
946 case wxFromStart:
947 m_currentPos = pos;
948 break;
949
950 case wxFromEnd:
951 m_currentPos = m_lastcount + pos;
952 break;
953
954 case wxFromCurrent:
955 m_currentPos += pos;
956 break;
957
958 default:
959 wxFAIL_MSG( _T("invalid seek mode") );
960 return wxInvalidOffset;
961 }
cd6ce4a9 962
49e399d8
VZ
963 if (m_currentPos > m_lastcount)
964 m_lastcount = m_currentPos;
cd6ce4a9 965
c7a9fa36 966 return m_currentPos;
e2acb9ae
RR
967}
968
969off_t wxCountingOutputStream::OnSysTell() const
970{
c7a9fa36 971 return m_currentPos;
e2acb9ae 972}
cd6ce4a9 973
1678ad78 974// ----------------------------------------------------------------------------
fae05df5 975// wxFilterInputStream
1678ad78 976// ----------------------------------------------------------------------------
e2acb9ae 977
fae05df5 978wxFilterInputStream::wxFilterInputStream()
3d4c6a21 979{
47fc03d2 980 m_parent_i_stream = NULL;
6d44bf31
GL
981}
982
fae05df5 983wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
6d44bf31 984{
c7a9fa36 985 m_parent_i_stream = &stream;
3d4c6a21
GL
986}
987
fae05df5 988wxFilterInputStream::~wxFilterInputStream()
3d4c6a21 989{
6d44bf31
GL
990}
991
fae05df5
GL
992// ----------------------------------------------------------------------------
993// wxFilterOutputStream
994// ----------------------------------------------------------------------------
49e399d8 995
fae05df5 996wxFilterOutputStream::wxFilterOutputStream()
6d44bf31 997{
47fc03d2 998 m_parent_o_stream = NULL;
3d4c6a21
GL
999}
1000
fae05df5 1001wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
3d4c6a21 1002{
c7a9fa36 1003 m_parent_o_stream = &stream;
6d44bf31
GL
1004}
1005
fae05df5 1006wxFilterOutputStream::~wxFilterOutputStream()
6d44bf31 1007{
6d44bf31
GL
1008}
1009
fae05df5
GL
1010// ----------------------------------------------------------------------------
1011// wxBufferedInputStream
1012// ----------------------------------------------------------------------------
49e399d8 1013
47fc03d2
VZ
1014wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1015 wxStreamBuffer *buffer)
49e399d8 1016 : wxFilterInputStream(s)
6d44bf31 1017{
47fc03d2
VZ
1018 if ( buffer )
1019 {
1020 // use the buffer provided by the user
1021 m_i_streambuf = buffer;
1022 }
1023 else // create a default buffer
1024 {
1025 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
49e399d8 1026
47fc03d2
VZ
1027 m_i_streambuf->SetBufferIO(1024);
1028 }
6d44bf31
GL
1029}
1030
fae05df5 1031wxBufferedInputStream::~wxBufferedInputStream()
6d44bf31 1032{
1fb45475
VZ
1033 m_parent_i_stream->SeekI(-(off_t)m_i_streambuf->GetBytesLeft(),
1034 wxFromCurrent);
672cedf8 1035
c7a9fa36 1036 delete m_i_streambuf;
6d44bf31
GL
1037}
1038
6319afe3
GL
1039char wxBufferedInputStream::Peek()
1040{
c7a9fa36 1041 return m_i_streambuf->Peek();
6319afe3
GL
1042}
1043
49e399d8 1044wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1e3eca9d 1045{
c7a9fa36 1046 size_t retsize;
1e3eca9d 1047
c7a9fa36
RR
1048 retsize = GetWBack(buf, size);
1049 m_lastcount = retsize;
47fc03d2 1050 if ( retsize == size )
c7a9fa36
RR
1051 {
1052 m_lasterror = wxStream_NOERROR;
1053 return *this;
1054 }
1055 size -= retsize;
49e399d8 1056 buf = (char *)buf + retsize;
1e3eca9d 1057
c7a9fa36 1058 m_i_streambuf->Read(buf, size);
6d44bf31 1059
c7a9fa36 1060 return *this;
6d44bf31
GL
1061}
1062
fae05df5 1063off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
6d44bf31 1064{
c7a9fa36 1065 return m_i_streambuf->Seek(pos, mode);
6d44bf31
GL
1066}
1067
fae05df5 1068off_t wxBufferedInputStream::TellI() const
6d44bf31 1069{
c7a9fa36 1070 return m_i_streambuf->Tell();
38830220 1071}
6d44bf31 1072
fae05df5 1073size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
38830220 1074{
c7a9fa36 1075 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
38830220
RR
1076}
1077
fae05df5 1078off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode)
38830220 1079{
c7a9fa36 1080 return m_parent_i_stream->SeekI(seek, mode);
6d44bf31
GL
1081}
1082
fae05df5 1083off_t wxBufferedInputStream::OnSysTell() const
6d44bf31 1084{
c7a9fa36 1085 return m_parent_i_stream->TellI();
38830220 1086}
6d44bf31 1087
47fc03d2
VZ
1088void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1089{
1090 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1091
1092 delete m_i_streambuf;
1093 m_i_streambuf = buffer;
1094}
1095
fae05df5
GL
1096// ----------------------------------------------------------------------------
1097// wxBufferedOutputStream
1098// ----------------------------------------------------------------------------
6d44bf31 1099
47fc03d2
VZ
1100wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1101 wxStreamBuffer *buffer)
49e399d8 1102 : wxFilterOutputStream(s)
6d44bf31 1103{
47fc03d2
VZ
1104 if ( buffer )
1105 {
1106 m_o_streambuf = buffer;
1107 }
1108 else // create a default one
1109 {
1110 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1111
1112 m_o_streambuf->SetBufferIO(1024);
1113 }
6d44bf31
GL
1114}
1115
fae05df5 1116wxBufferedOutputStream::~wxBufferedOutputStream()
6d44bf31 1117{
c7a9fa36
RR
1118 Sync();
1119 delete m_o_streambuf;
3d4c6a21
GL
1120}
1121
fae05df5 1122wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
123a7fdd 1123{
c7a9fa36
RR
1124 m_lastcount = 0;
1125 m_o_streambuf->Write(buffer, size);
1126 return *this;
123a7fdd
GL
1127}
1128
fae05df5 1129off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode)
f4ada568 1130{
c7a9fa36
RR
1131 Sync();
1132 return m_o_streambuf->Seek(pos, mode);
f4ada568
GL
1133}
1134
fae05df5 1135off_t wxBufferedOutputStream::TellO() const
3d4c6a21 1136{
c7a9fa36 1137 return m_o_streambuf->Tell();
3d4c6a21
GL
1138}
1139
fae05df5 1140void wxBufferedOutputStream::Sync()
3d4c6a21 1141{
c7a9fa36
RR
1142 m_o_streambuf->FlushBuffer();
1143 m_parent_o_stream->Sync();
3d4c6a21 1144}
219f895a 1145
fae05df5 1146size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
f4ada568 1147{
c7a9fa36 1148 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
f4ada568
GL
1149}
1150
fae05df5 1151off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode)
219f895a 1152{
c7a9fa36 1153 return m_parent_o_stream->SeekO(seek, mode);
219f895a
RR
1154}
1155
fae05df5 1156off_t wxBufferedOutputStream::OnSysTell() const
219f895a 1157{
c7a9fa36
RR
1158 return m_parent_o_stream->TellO();
1159}
1160
1161size_t wxBufferedOutputStream::GetSize() const
1162{
1163 return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
219f895a 1164}
6d44bf31 1165
47fc03d2
VZ
1166void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1167{
1168 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1169
1170 delete m_o_streambuf;
1171 m_o_streambuf = buffer;
1172}
1173
6d44bf31
GL
1174// ----------------------------------------------------------------------------
1175// Some IOManip function
1176// ----------------------------------------------------------------------------
1177
1178wxOutputStream& wxEndL(wxOutputStream& stream)
1179{
733b8ed3
VZ
1180 static const wxChar *eol = wxTextFile::GetEOL();
1181
1182 return stream.Write(eol, wxStrlen(eol));
6d44bf31 1183}
ce4169a4
RR
1184
1185#endif
1186 // wxUSE_STREAMS