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