]> git.saurik.com Git - wxWidgets.git/blame - src/common/stream.cpp
check for LVS_OWNERDATA availability at compile and run-time
[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
421db2ad 168 m_destroybuf = takeOwnership;
49e399d8
VZ
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);
4708a349
VZ
672
673 // some streams can know that they're at EOF before actually trying to
674 // read beyond the end of stream (e.g. files) while others have no way of
675 // knowing it, so to provide the same behaviour in all cases we only
676 // return TRUE from here if the character really couldn't be read
677 if ( !self->LastRead() && GetLastError() == wxSTREAM_EOF )
cd6ce4a9
VZ
678 {
679 return TRUE;
680 }
681
682 self->Ungetch(c);
683
684 return FALSE;
685}
686
fae05df5 687char *wxInputStream::AllocSpaceWBack(size_t needed_size)
3d4c6a21 688{
49e399d8 689 // get number of bytes left from previous wback buffer
c7a9fa36 690 size_t toget = m_wbacksize - m_wbackcur;
fae05df5 691
49e399d8
VZ
692 // allocate a buffer large enough to hold prev + new data
693 char *temp_b = (char *)malloc(needed_size + toget);
fae05df5 694
c7a9fa36
RR
695 if (!temp_b)
696 return NULL;
fae05df5 697
c7a9fa36
RR
698 /* copy previous data (and free old buffer) if needed */
699 if (m_wback)
700 {
701 memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
702 free(m_wback);
703 }
5ac8158a 704
c7a9fa36
RR
705 /* done */
706 m_wback = temp_b;
707 m_wbackcur = 0;
708 m_wbacksize = needed_size + toget;
783ff666 709
49e399d8 710 return m_wback;
6d44bf31
GL
711}
712
49e399d8 713size_t wxInputStream::GetWBack(void *buf, size_t bsize)
6d44bf31 714{
49e399d8 715 size_t toget = m_wbacksize-m_wbackcur;
fae05df5 716
c7a9fa36
RR
717 if (!m_wback)
718 return 0;
a324a7bc 719
49e399d8
VZ
720 if (bsize < toget)
721 toget = bsize;
fae05df5 722
49e399d8 723 memcpy(buf, (m_wback+m_wbackcur), toget);
fae05df5 724
49e399d8 725 m_wbackcur += toget;
cd6ce4a9 726 if (m_wbackcur == m_wbacksize)
c7a9fa36
RR
727 {
728 free(m_wback);
49e399d8 729 m_wback = NULL;
c7a9fa36
RR
730 m_wbacksize = 0;
731 m_wbackcur = 0;
732 }
cd6ce4a9 733
49e399d8 734 return toget;
6d44bf31
GL
735}
736
8f7173ab 737size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
fae05df5 738{
c7a9fa36
RR
739 char *ptrback = AllocSpaceWBack(bufsize);
740 if (!ptrback)
741 return 0;
cd6ce4a9 742
c7a9fa36
RR
743 memcpy(ptrback, buf, bufsize);
744 return bufsize;
fae05df5
GL
745}
746
747bool wxInputStream::Ungetch(char c)
1e3eca9d 748{
49e399d8 749 void *ptrback = AllocSpaceWBack(1);
c7a9fa36
RR
750 if (!ptrback)
751 return FALSE;
1e3eca9d 752
49e399d8 753 *(char *)ptrback = c;
c7a9fa36 754 return TRUE;
fae05df5
GL
755}
756
757char wxInputStream::GetC()
758{
c7a9fa36
RR
759 char c;
760 Read(&c, 1);
761 return c;
1e3eca9d
GL
762}
763
49e399d8 764wxInputStream& wxInputStream::Read(void *buf, size_t size)
6d44bf31 765{
c7a9fa36 766 size_t retsize = GetWBack(buf, size);
cd6ce4a9 767 if (retsize == size)
c7a9fa36
RR
768 {
769 m_lastcount = size;
770 m_lasterror = wxStream_NOERROR;
771 return *this;
772 }
773 size -= retsize;
49e399d8 774 buf = (char *)buf + retsize;
fae05df5 775
c7a9fa36
RR
776 m_lastcount = OnSysRead(buf, size) + retsize;
777 return *this;
3d4c6a21
GL
778}
779
75ed1d15
GL
780char wxInputStream::Peek()
781{
c7a9fa36
RR
782 char c;
783 Read(&c, 1);
cd6ce4a9 784 if (m_lasterror == wxStream_NOERROR)
c7a9fa36
RR
785 {
786 Ungetch(c);
787 return c;
788 }
cd6ce4a9 789
c7a9fa36 790 return 0;
75ed1d15
GL
791}
792
3d4c6a21
GL
793wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
794{
cd6ce4a9 795 char buf[BUF_TEMP_SIZE];
c7a9fa36 796 size_t bytes_read = BUF_TEMP_SIZE;
3d4c6a21 797
cd6ce4a9 798 while (bytes_read == BUF_TEMP_SIZE)
c7a9fa36
RR
799 {
800 bytes_read = Read(buf, bytes_read).LastRead();
801 bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
802 }
803 return *this;
3d4c6a21
GL
804}
805
75ed1d15
GL
806off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
807{
c7a9fa36
RR
808 /* Should be check and improve, just to remove a slight bug !
809 I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
cd6ce4a9 810 if (m_lasterror==wxSTREAM_EOF)
c7a9fa36
RR
811 m_lasterror=wxSTREAM_NOERROR;
812
813 /* A call to SeekI() will automatically invalidate any previous call
814 to Ungetch(), otherwise it would be possible to SeekI() to one
815 one position, unread some bytes there, SeekI() to another position
19da7237
GRG
816 and the data would be corrupted.
817
818 GRG: Could add code here to try to navigate within the wback
819 buffer if possible, but is it really needed? It would only work
820 when seeking in wxFromCurrent mode, else it would invalidate
821 anyway...
822 */
cd6ce4a9 823 if (m_wback)
c7a9fa36
RR
824 {
825 free(m_wback);
49e399d8 826 m_wback = NULL;
c7a9fa36
RR
827 m_wbacksize = 0;
828 m_wbackcur = 0;
829 }
fe8aa971 830
c7a9fa36 831 return OnSysSeek(pos, mode);
75ed1d15
GL
832}
833
834off_t wxInputStream::TellI() const
835{
19da7237
GRG
836 /* GRG: Changed to make it compatible with the wback buffer */
837 off_t pos = OnSysTell();
838
839 if (pos != wxInvalidOffset)
840 pos -= (m_wbacksize - m_wbackcur);
841
842 return pos;
75ed1d15
GL
843}
844
845// --------------------
846// Overloaded operators
847// --------------------
848
fae05df5
GL
849#if wxUSE_SERIAL
850wxInputStream& wxInputStream::operator>>(wxObject *& obj)
1678ad78 851{
c7a9fa36
RR
852 wxObjectInputStream obj_s(*this);
853 obj = obj_s.LoadObject();
854 return *this;
1678ad78 855}
49e399d8 856#endif // wxUSE_SERIAL
1678ad78 857
1678ad78 858
fae05df5
GL
859// ----------------------------------------------------------------------------
860// wxOutputStream
861// ----------------------------------------------------------------------------
49e399d8 862
fae05df5 863wxOutputStream::wxOutputStream()
1678ad78 864{
1678ad78
GL
865}
866
fae05df5 867wxOutputStream::~wxOutputStream()
123a7fdd 868{
123a7fdd
GL
869}
870
47fc03d2
VZ
871size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
872 size_t WXUNUSED(bufsize))
873{
874 return 0;
875}
876
7513f9ff
GRG
877void wxOutputStream::PutC(char c)
878{
49e399d8 879 Write(&c, 1);
7513f9ff
GRG
880}
881
fae05df5 882wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
1678ad78 883{
c7a9fa36
RR
884 m_lastcount = OnSysWrite(buffer, size);
885 return *this;
1678ad78
GL
886}
887
fae05df5 888wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
38830220 889{
c7a9fa36
RR
890 stream_in.Read(*this);
891 return *this;
38830220
RR
892}
893
fae05df5 894off_t wxOutputStream::TellO() const
38830220 895{
c7a9fa36 896 return OnSysTell();
38830220
RR
897}
898
fae05df5 899off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
38830220 900{
c7a9fa36 901 return OnSysSeek(pos, mode);
38830220
RR
902}
903
fae05df5 904void wxOutputStream::Sync()
1678ad78 905{
1678ad78
GL
906}
907
47d67540 908#if wxUSE_SERIAL
fae05df5 909wxOutputStream& wxOutputStream::operator<<(wxObject& obj)
123a7fdd 910{
c7a9fa36
RR
911 wxObjectOutputStream obj_s(*this);
912 obj_s.SaveObject(obj);
913 return *this;
123a7fdd 914}
49e399d8 915#endif // wxUSE_SERIAL
123a7fdd 916
e2acb9ae
RR
917// ----------------------------------------------------------------------------
918// wxCountingOutputStream
919// ----------------------------------------------------------------------------
920
921wxCountingOutputStream::wxCountingOutputStream ()
e2acb9ae 922{
c7a9fa36 923 m_currentPos = 0;
e2acb9ae
RR
924}
925
926size_t wxCountingOutputStream::GetSize() const
927{
c7a9fa36 928 return m_lastcount;
e2acb9ae
RR
929}
930
49e399d8
VZ
931size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
932 size_t size)
e2acb9ae 933{
c7a9fa36 934 m_currentPos += size;
49e399d8
VZ
935 if (m_currentPos > m_lastcount)
936 m_lastcount = m_currentPos;
937
c7a9fa36 938 return m_currentPos;
e2acb9ae
RR
939}
940
941off_t wxCountingOutputStream::OnSysSeek(off_t pos, wxSeekMode mode)
942{
49e399d8
VZ
943 switch ( mode )
944 {
945 case wxFromStart:
946 m_currentPos = pos;
947 break;
948
949 case wxFromEnd:
950 m_currentPos = m_lastcount + pos;
951 break;
952
953 case wxFromCurrent:
954 m_currentPos += pos;
955 break;
956
957 default:
958 wxFAIL_MSG( _T("invalid seek mode") );
959 return wxInvalidOffset;
960 }
cd6ce4a9 961
49e399d8
VZ
962 if (m_currentPos > m_lastcount)
963 m_lastcount = m_currentPos;
cd6ce4a9 964
c7a9fa36 965 return m_currentPos;
e2acb9ae
RR
966}
967
968off_t wxCountingOutputStream::OnSysTell() const
969{
c7a9fa36 970 return m_currentPos;
e2acb9ae 971}
cd6ce4a9 972
1678ad78 973// ----------------------------------------------------------------------------
fae05df5 974// wxFilterInputStream
1678ad78 975// ----------------------------------------------------------------------------
e2acb9ae 976
fae05df5 977wxFilterInputStream::wxFilterInputStream()
3d4c6a21 978{
47fc03d2 979 m_parent_i_stream = NULL;
6d44bf31
GL
980}
981
fae05df5 982wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
6d44bf31 983{
c7a9fa36 984 m_parent_i_stream = &stream;
3d4c6a21
GL
985}
986
fae05df5 987wxFilterInputStream::~wxFilterInputStream()
3d4c6a21 988{
6d44bf31
GL
989}
990
fae05df5
GL
991// ----------------------------------------------------------------------------
992// wxFilterOutputStream
993// ----------------------------------------------------------------------------
49e399d8 994
fae05df5 995wxFilterOutputStream::wxFilterOutputStream()
6d44bf31 996{
47fc03d2 997 m_parent_o_stream = NULL;
3d4c6a21
GL
998}
999
fae05df5 1000wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
3d4c6a21 1001{
c7a9fa36 1002 m_parent_o_stream = &stream;
6d44bf31
GL
1003}
1004
fae05df5 1005wxFilterOutputStream::~wxFilterOutputStream()
6d44bf31 1006{
6d44bf31
GL
1007}
1008
fae05df5
GL
1009// ----------------------------------------------------------------------------
1010// wxBufferedInputStream
1011// ----------------------------------------------------------------------------
49e399d8 1012
47fc03d2
VZ
1013wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1014 wxStreamBuffer *buffer)
49e399d8 1015 : wxFilterInputStream(s)
6d44bf31 1016{
47fc03d2
VZ
1017 if ( buffer )
1018 {
1019 // use the buffer provided by the user
1020 m_i_streambuf = buffer;
1021 }
1022 else // create a default buffer
1023 {
1024 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
49e399d8 1025
47fc03d2
VZ
1026 m_i_streambuf->SetBufferIO(1024);
1027 }
6d44bf31
GL
1028}
1029
fae05df5 1030wxBufferedInputStream::~wxBufferedInputStream()
6d44bf31 1031{
1fb45475
VZ
1032 m_parent_i_stream->SeekI(-(off_t)m_i_streambuf->GetBytesLeft(),
1033 wxFromCurrent);
672cedf8 1034
c7a9fa36 1035 delete m_i_streambuf;
6d44bf31
GL
1036}
1037
6319afe3
GL
1038char wxBufferedInputStream::Peek()
1039{
c7a9fa36 1040 return m_i_streambuf->Peek();
6319afe3
GL
1041}
1042
49e399d8 1043wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1e3eca9d 1044{
c7a9fa36 1045 size_t retsize;
1e3eca9d 1046
c7a9fa36
RR
1047 retsize = GetWBack(buf, size);
1048 m_lastcount = retsize;
47fc03d2 1049 if ( retsize == size )
c7a9fa36
RR
1050 {
1051 m_lasterror = wxStream_NOERROR;
1052 return *this;
1053 }
1054 size -= retsize;
49e399d8 1055 buf = (char *)buf + retsize;
1e3eca9d 1056
c7a9fa36 1057 m_i_streambuf->Read(buf, size);
6d44bf31 1058
c7a9fa36 1059 return *this;
6d44bf31
GL
1060}
1061
fae05df5 1062off_t wxBufferedInputStream::SeekI(off_t pos, wxSeekMode mode)
6d44bf31 1063{
c7a9fa36 1064 return m_i_streambuf->Seek(pos, mode);
6d44bf31
GL
1065}
1066
fae05df5 1067off_t wxBufferedInputStream::TellI() const
6d44bf31 1068{
c7a9fa36 1069 return m_i_streambuf->Tell();
38830220 1070}
6d44bf31 1071
fae05df5 1072size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
38830220 1073{
c7a9fa36 1074 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
38830220
RR
1075}
1076
fae05df5 1077off_t wxBufferedInputStream::OnSysSeek(off_t seek, wxSeekMode mode)
38830220 1078{
c7a9fa36 1079 return m_parent_i_stream->SeekI(seek, mode);
6d44bf31
GL
1080}
1081
fae05df5 1082off_t wxBufferedInputStream::OnSysTell() const
6d44bf31 1083{
c7a9fa36 1084 return m_parent_i_stream->TellI();
38830220 1085}
6d44bf31 1086
47fc03d2
VZ
1087void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1088{
1089 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1090
1091 delete m_i_streambuf;
1092 m_i_streambuf = buffer;
1093}
1094
fae05df5
GL
1095// ----------------------------------------------------------------------------
1096// wxBufferedOutputStream
1097// ----------------------------------------------------------------------------
6d44bf31 1098
47fc03d2
VZ
1099wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1100 wxStreamBuffer *buffer)
49e399d8 1101 : wxFilterOutputStream(s)
6d44bf31 1102{
47fc03d2
VZ
1103 if ( buffer )
1104 {
1105 m_o_streambuf = buffer;
1106 }
1107 else // create a default one
1108 {
1109 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1110
1111 m_o_streambuf->SetBufferIO(1024);
1112 }
6d44bf31
GL
1113}
1114
fae05df5 1115wxBufferedOutputStream::~wxBufferedOutputStream()
6d44bf31 1116{
c7a9fa36
RR
1117 Sync();
1118 delete m_o_streambuf;
3d4c6a21
GL
1119}
1120
fae05df5 1121wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
123a7fdd 1122{
c7a9fa36
RR
1123 m_lastcount = 0;
1124 m_o_streambuf->Write(buffer, size);
1125 return *this;
123a7fdd
GL
1126}
1127
fae05df5 1128off_t wxBufferedOutputStream::SeekO(off_t pos, wxSeekMode mode)
f4ada568 1129{
c7a9fa36
RR
1130 Sync();
1131 return m_o_streambuf->Seek(pos, mode);
f4ada568
GL
1132}
1133
fae05df5 1134off_t wxBufferedOutputStream::TellO() const
3d4c6a21 1135{
c7a9fa36 1136 return m_o_streambuf->Tell();
3d4c6a21
GL
1137}
1138
fae05df5 1139void wxBufferedOutputStream::Sync()
3d4c6a21 1140{
c7a9fa36
RR
1141 m_o_streambuf->FlushBuffer();
1142 m_parent_o_stream->Sync();
3d4c6a21 1143}
219f895a 1144
fae05df5 1145size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
f4ada568 1146{
c7a9fa36 1147 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
f4ada568
GL
1148}
1149
fae05df5 1150off_t wxBufferedOutputStream::OnSysSeek(off_t seek, wxSeekMode mode)
219f895a 1151{
c7a9fa36 1152 return m_parent_o_stream->SeekO(seek, mode);
219f895a
RR
1153}
1154
fae05df5 1155off_t wxBufferedOutputStream::OnSysTell() const
219f895a 1156{
c7a9fa36
RR
1157 return m_parent_o_stream->TellO();
1158}
1159
1160size_t wxBufferedOutputStream::GetSize() const
1161{
1162 return m_parent_o_stream->GetSize() + m_o_streambuf->GetIntPosition();
219f895a 1163}
6d44bf31 1164
47fc03d2
VZ
1165void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1166{
1167 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1168
1169 delete m_o_streambuf;
1170 m_o_streambuf = buffer;
1171}
1172
6d44bf31
GL
1173// ----------------------------------------------------------------------------
1174// Some IOManip function
1175// ----------------------------------------------------------------------------
1176
1177wxOutputStream& wxEndL(wxOutputStream& stream)
1178{
1179#ifdef __MSW__
1180 return stream.Write("\r\n", 2);
1e3eca9d
GL
1181#else
1182#ifdef __WXMAC__
1183 return stream.Write("\r", 1);
6d44bf31
GL
1184#else
1185 return stream.Write("\n", 1);
1186#endif
1e3eca9d 1187#endif
6d44bf31 1188}
ce4169a4
RR
1189
1190#endif
1191 // wxUSE_STREAMS