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