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