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