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