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