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