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