1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/common/stream.cpp
3
// Purpose: wxStream base classes
4
// Author: Guilhem Lavaux
5
// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory,
8
// Copyright: (c) Guilhem Lavaux
9
// Licence: wxWindows licence
10
/////////////////////////////////////////////////////////////////////////////
12
// ============================================================================
14
// ============================================================================
16
// ----------------------------------------------------------------------------
18
// ----------------------------------------------------------------------------
20
// For compilers that support precompilation, includes "wx.h".
21
#include "wx/wxprec.h"
29
#include "wx/stream.h"
36
#include "wx/datstrm.h"
37
#include "wx/textfile.h"
38
#include "wx/scopeguard.h"
40
// ----------------------------------------------------------------------------
42
// ----------------------------------------------------------------------------
44
// the temporary buffer size used when copying from stream to stream
45
#define BUF_TEMP_SIZE 4096
47
// ============================================================================
49
// ============================================================================
51
// ----------------------------------------------------------------------------
53
// ----------------------------------------------------------------------------
55
void wxStreamBuffer::SetError(wxStreamError err)
57
if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR )
58
m_stream->m_lasterror = err;
61
void wxStreamBuffer::InitBuffer()
67
// if we are going to allocate the buffer, we should free it later as well
71
void wxStreamBuffer::Init()
78
void wxStreamBuffer::InitWithStream(wxStreamBase& stream, BufMode mode)
88
wxStreamBuffer::wxStreamBuffer(BufMode mode)
98
wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
100
// doing this has big chances to lead to a crash when the source buffer is
101
// destroyed (otherwise assume the caller knows what he does)
102
wxASSERT_MSG( !buffer.m_destroybuf,
103
wxT("it's a bad idea to copy this buffer") );
105
m_buffer_start = buffer.m_buffer_start;
106
m_buffer_end = buffer.m_buffer_end;
107
m_buffer_pos = buffer.m_buffer_pos;
108
m_fixed = buffer.m_fixed;
109
m_flushable = buffer.m_flushable;
110
m_stream = buffer.m_stream;
111
m_mode = buffer.m_mode;
112
m_destroybuf = false;
115
void wxStreamBuffer::FreeBuffer()
119
free(m_buffer_start);
120
m_buffer_start = NULL;
124
wxStreamBuffer::~wxStreamBuffer()
129
wxInputStream *wxStreamBuffer::GetInputStream() const
131
return m_mode == write ? NULL : (wxInputStream *)m_stream;
134
wxOutputStream *wxStreamBuffer::GetOutputStream() const
136
return m_mode == read ? NULL : (wxOutputStream *)m_stream;
139
void wxStreamBuffer::SetBufferIO(void *buffer_start,
143
SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start,
147
void wxStreamBuffer::SetBufferIO(void *start,
151
// start by freeing the old buffer
154
m_buffer_start = (char *)start;
155
m_buffer_end = m_buffer_start + len;
157
// if we own it, we free it
158
m_destroybuf = takeOwnership;
163
void wxStreamBuffer::SetBufferIO(size_t bufsize)
167
// this will free the old buffer and allocate the new one
168
SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */);
170
else // no buffer size => no buffer
172
// still free the old one
178
void wxStreamBuffer::ResetBuffer()
183
m_stream->m_lastcount = 0;
186
m_buffer_pos = m_mode == read && m_flushable
191
void wxStreamBuffer::Truncate()
193
size_t new_size = m_buffer_pos - m_buffer_start;
194
if ( m_buffer_pos == m_buffer_end )
204
char *new_start = (char *)realloc(m_buffer_start, new_size);
205
wxCHECK_RET( new_size, wxT("shrinking buffer shouldn't fail") );
207
m_buffer_start = new_start;
208
m_buffer_end = m_buffer_start + new_size;
209
m_buffer_pos = m_buffer_end;
212
// fill the buffer with as much data as possible (only for read buffers)
213
bool wxStreamBuffer::FillBuffer()
215
wxInputStream *inStream = GetInputStream();
217
// It's legal to have no stream, so we don't complain about it just return false
221
size_t count = inStream->OnSysRead(GetBufferStart(), GetBufferSize());
225
m_buffer_end = m_buffer_start + count;
226
m_buffer_pos = m_buffer_start;
231
// write the buffer contents to the stream (only for write buffers)
232
bool wxStreamBuffer::FlushBuffer()
234
wxCHECK_MSG( m_flushable, false, wxT("can't flush this buffer") );
236
// FIXME: what is this check for? (VZ)
237
if ( m_buffer_pos == m_buffer_start )
240
wxOutputStream *outStream = GetOutputStream();
242
wxCHECK_MSG( outStream, false, wxT("should have a stream in wxStreamBuffer") );
244
size_t current = m_buffer_pos - m_buffer_start;
245
size_t count = outStream->OnSysWrite(m_buffer_start, current);
246
if ( count != current )
249
m_buffer_pos = m_buffer_start;
254
size_t wxStreamBuffer::GetDataLeft()
256
/* Why is this done? RR. */
257
if ( m_buffer_pos == m_buffer_end && m_flushable)
260
return GetBytesLeft();
263
// copy up to size bytes from our buffer into the provided one
264
void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
266
// don't get more bytes than left in the buffer
267
size_t left = GetBytesLeft();
272
memcpy(buffer, m_buffer_pos, size);
273
m_buffer_pos += size;
276
// copy the contents of the provided buffer into this one
277
void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
279
size_t left = GetBytesLeft();
285
// we can't realloc the buffer, so just copy what we can
290
// realloc the buffer to have enough space for the data
291
if ( m_buffer_pos + size > m_buffer_end )
293
size_t delta = m_buffer_pos - m_buffer_start;
294
size_t new_size = delta + size;
296
char *startOld = m_buffer_start;
297
m_buffer_start = (char *)realloc(m_buffer_start, new_size);
298
if ( !m_buffer_start )
300
// don't leak memory if realloc() failed
301
m_buffer_start = startOld;
303
// what else can we do?
307
// adjust the pointers invalidated by realloc()
308
m_buffer_pos = m_buffer_start + delta;
309
m_buffer_end = m_buffer_start + new_size;
310
} // else: the buffer is big enough
314
memcpy(m_buffer_pos, buffer, size);
315
m_buffer_pos += size;
318
void wxStreamBuffer::PutChar(char c)
320
wxOutputStream *outStream = GetOutputStream();
322
wxCHECK_RET( outStream, wxT("should have a stream in wxStreamBuffer") );
324
// if we don't have buffer at all, just forward this call to the stream,
327
outStream->OnSysWrite(&c, sizeof(c));
331
// otherwise check we have enough space left
332
if ( !GetDataLeft() && !FlushBuffer() )
335
SetError(wxSTREAM_WRITE_ERROR);
339
PutToBuffer(&c, sizeof(c));
340
m_stream->m_lastcount = 1;
345
char wxStreamBuffer::Peek()
347
wxCHECK_MSG( m_stream && HasBuffer(), 0,
348
wxT("should have the stream and the buffer in wxStreamBuffer") );
350
if ( !GetDataLeft() )
352
SetError(wxSTREAM_READ_ERROR);
357
GetFromBuffer(&c, sizeof(c));
363
char wxStreamBuffer::GetChar()
365
wxInputStream *inStream = GetInputStream();
367
wxCHECK_MSG( inStream, 0, wxT("should have a stream in wxStreamBuffer") );
372
inStream->OnSysRead(&c, sizeof(c));
376
if ( !GetDataLeft() )
378
SetError(wxSTREAM_READ_ERROR);
383
GetFromBuffer(&c, sizeof(c));
384
m_stream->m_lastcount = 1;
391
size_t wxStreamBuffer::Read(void *buffer, size_t size)
393
wxASSERT_MSG( buffer, wxT("Warning: Null pointer is about to be used") );
395
/* Clear buffer first */
396
memset(buffer, 0x00, size);
398
// lasterror is reset before all new IO calls
405
wxInputStream *inStream = GetInputStream();
407
wxCHECK_MSG( inStream, 0, wxT("should have a stream in wxStreamBuffer") );
409
readBytes = inStream->OnSysRead(buffer, size);
411
else // we have a buffer, use it
413
size_t orig_size = size;
417
size_t left = GetDataLeft();
419
// if the requested number of bytes if greater than the buffer
420
// size, read data in chunks
423
GetFromBuffer(buffer, left);
425
buffer = (char *)buffer + left;
429
SetError(wxSTREAM_EOF);
433
else // otherwise just do it in one gulp
435
GetFromBuffer(buffer, size);
440
readBytes = orig_size - size;
444
m_stream->m_lastcount = readBytes;
449
// this should really be called "Copy()"
450
size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
452
wxCHECK_MSG( m_mode != write, 0, wxT("can't read from this buffer") );
454
char buf[BUF_TEMP_SIZE];
460
nRead = Read(buf, WXSIZEOF(buf));
463
nRead = dbuf->Write(buf, nRead);
472
size_t wxStreamBuffer::Write(const void *buffer, size_t size)
474
wxASSERT_MSG( buffer, wxT("Warning: Null pointer is about to be send") );
478
// lasterror is reset before all new IO calls
484
if ( !HasBuffer() && m_fixed )
486
wxOutputStream *outStream = GetOutputStream();
488
wxCHECK_MSG( outStream, 0, wxT("should have a stream in wxStreamBuffer") );
490
// no buffer, just forward the call to the stream
491
ret = outStream->OnSysWrite(buffer, size);
493
else // we [may] have a buffer, use it
495
size_t orig_size = size;
499
size_t left = GetBytesLeft();
501
// if the buffer is too large to fit in the stream buffer, split
502
// it in smaller parts
504
// NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
505
// we always go to the second case.
507
// FIXME: fine, but if it fails we should (re)try writing it by
508
// chunks as this will (hopefully) always work (VZ)
510
if ( size > left && m_fixed )
512
PutToBuffer(buffer, left);
514
buffer = (char *)buffer + left;
516
if ( !FlushBuffer() )
518
SetError(wxSTREAM_WRITE_ERROR);
523
m_buffer_pos = m_buffer_start;
525
else // we can do it in one gulp
527
PutToBuffer(buffer, size);
532
ret = orig_size - size;
537
// i am not entirely sure what we do this for
538
m_stream->m_lastcount = ret;
544
size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
546
wxCHECK_MSG( m_mode != read, 0, wxT("can't write to this buffer") );
547
wxCHECK_MSG( sbuf->m_mode != write, 0, wxT("can't read from that buffer") );
549
char buf[BUF_TEMP_SIZE];
555
size_t nRead = sbuf->Read(buf, WXSIZEOF(buf));
558
nWrite = Write(buf, nRead);
559
if ( nWrite < nRead )
561
// put back data we couldn't copy
562
wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream();
564
in_stream->Ungetch(buf + nWrite, nRead - nWrite);
574
while ( nWrite == WXSIZEOF(buf) );
579
wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode)
581
wxFileOffset ret_off, diff;
583
wxFileOffset last_access = GetLastAccess();
594
diff = pos + GetIntPosition();
598
diff = pos + last_access;
602
wxFAIL_MSG( wxT("invalid seek mode") );
604
return wxInvalidOffset;
606
if (diff < 0 || diff > last_access)
607
return wxInvalidOffset;
608
size_t int_diff = wx_truncate_cast(size_t, diff);
609
wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
610
SetIntPosition(int_diff);
617
// We'll try to compute an internal position later ...
618
ret_off = m_stream->OnSysSeek(pos, wxFromStart);
623
diff = pos + GetIntPosition();
625
if ( (diff > last_access) || (diff < 0) )
627
// We must take into account the fact that we have read
628
// something previously.
629
ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
635
size_t int_diff = wx_truncate_cast(size_t, diff);
636
wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
637
SetIntPosition(int_diff);
642
// Hard to compute: always seek to the requested position.
643
ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
648
return wxInvalidOffset;
651
wxFileOffset wxStreamBuffer::Tell() const
655
// ask the stream for position if we have a real one
658
pos = m_stream->OnSysTell();
659
if ( pos == wxInvalidOffset )
660
return wxInvalidOffset;
662
else // no associated stream
667
pos += GetIntPosition();
669
if ( m_mode == read && m_flushable )
670
pos -= GetLastAccess();
675
// ----------------------------------------------------------------------------
677
// ----------------------------------------------------------------------------
679
IMPLEMENT_ABSTRACT_CLASS(wxStreamBase, wxObject)
681
wxStreamBase::wxStreamBase()
683
m_lasterror = wxSTREAM_NO_ERROR;
687
wxStreamBase::~wxStreamBase()
691
size_t wxStreamBase::GetSize() const
693
wxFileOffset length = GetLength();
694
if ( length == (wxFileOffset)wxInvalidOffset )
697
const size_t len = wx_truncate_cast(size_t, length);
698
wxASSERT_MSG( len == length + size_t(0), wxT("large files not supported") );
703
wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
705
return wxInvalidOffset;
708
wxFileOffset wxStreamBase::OnSysTell() const
710
return wxInvalidOffset;
713
// ----------------------------------------------------------------------------
715
// ----------------------------------------------------------------------------
717
IMPLEMENT_ABSTRACT_CLASS(wxInputStream, wxStreamBase)
719
wxInputStream::wxInputStream()
726
wxInputStream::~wxInputStream()
731
bool wxInputStream::CanRead() const
733
// we don't know if there is anything to read or not and by default we
734
// prefer to be optimistic and try to read data unless we know for sure
735
// there is no more of it
736
return m_lasterror != wxSTREAM_EOF;
739
bool wxInputStream::Eof() const
741
// the only way the base class can know we're at EOF is when we'd already
742
// tried to read beyond it in which case last error is set accordingly
743
return GetLastError() == wxSTREAM_EOF;
746
char *wxInputStream::AllocSpaceWBack(size_t needed_size)
748
// get number of bytes left from previous wback buffer
749
size_t toget = m_wbacksize - m_wbackcur;
751
// allocate a buffer large enough to hold prev + new data
752
char *temp_b = (char *)malloc(needed_size + toget);
757
// copy previous data (and free old buffer) if needed
760
memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
767
m_wbacksize = needed_size + toget;
772
size_t wxInputStream::GetWBack(void *buf, size_t size)
774
wxASSERT_MSG( buf, wxT("Warning: Null pointer is about to be used") );
776
/* Clear buffer first */
777
memset(buf, 0x00, size);
782
// how many bytes do we have in the buffer?
783
size_t toget = m_wbacksize - m_wbackcur;
787
// we won't read everything
791
// copy the data from the cache
792
memcpy(buf, m_wback + m_wbackcur, toget);
795
if ( m_wbackcur == m_wbacksize )
797
// TODO: should we really free it here all the time? maybe keep it?
804
// return the number of bytes copied
808
size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
810
wxASSERT_MSG( buf, wxT("Warning: Null pointer is about to be used in Ungetch()") );
812
if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF )
814
// can't operate on this stream until the error is cleared
818
char *ptrback = AllocSpaceWBack(bufsize);
822
// Eof() shouldn't return true any longer
823
if ( m_lasterror == wxSTREAM_EOF )
824
m_lasterror = wxSTREAM_NO_ERROR;
826
memcpy(ptrback, buf, bufsize);
830
bool wxInputStream::Ungetch(char c)
832
return Ungetch(&c, sizeof(c)) != 0;
835
int wxInputStream::GetC()
839
return LastRead() ? c : wxEOF;
842
wxInputStream& wxInputStream::Read(void *buf, size_t size)
844
wxASSERT_MSG( buf, wxT("Warning: Null pointer is about to be read") );
846
char *p = (char *)buf;
849
size_t read = GetWBack(buf, size);
858
// we read the requested amount of data
862
if ( p != buf && !CanRead() )
864
// we have already read something and we would block in OnSysRead()
865
// now: don't do it but return immediately
869
read = OnSysRead(p, size);
872
// no more data available
880
char wxInputStream::Peek()
884
if (m_lasterror == wxSTREAM_NO_ERROR)
893
wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
895
size_t lastcount = 0;
896
char buf[BUF_TEMP_SIZE];
900
size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
904
if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read )
907
lastcount += bytes_read;
910
m_lastcount = lastcount;
915
bool wxInputStream::ReadAll(void *buffer_, size_t size)
917
char* buffer = static_cast<char*>(buffer_);
919
size_t totalCount = 0;
923
const size_t lastCount = Read(buffer, size).LastRead();
925
// There is no point in continuing looping if we can't read anything at
930
totalCount += lastCount;
932
// ... Or if an error occurred on the stream.
936
// Return successfully if we read exactly the requested number of
937
// bytes (normally the ">" case should never occur and so we could use
938
// "==" test, but be safe and avoid overflowing size even in case of
939
// bugs in LastRead()).
940
if ( lastCount >= size )
946
// Advance the buffer before trying to read the rest of data.
951
m_lastcount = totalCount;
956
wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
958
// RR: This code is duplicated in wxBufferedInputStream. This is
959
// not really a good design, but buffered stream are different
960
// from all others in that they handle two stream-related objects:
961
// the stream buffer and parent stream.
963
// I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
964
if (m_lasterror==wxSTREAM_EOF)
965
m_lasterror=wxSTREAM_NO_ERROR;
967
// avoid unnecessary seek operations (optimization)
968
wxFileOffset currentPos = TellI(), size = GetLength();
969
if ((mode == wxFromStart && currentPos == pos) ||
970
(mode == wxFromCurrent && pos == 0) ||
971
(mode == wxFromEnd && size != wxInvalidOffset && currentPos == size-pos))
974
if (!IsSeekable() && mode == wxFromCurrent && pos > 0)
976
// rather than seeking, we can just read data and discard it;
977
// this allows to forward-seek also non-seekable streams!
978
char buf[BUF_TEMP_SIZE];
981
// read chunks of BUF_TEMP_SIZE bytes until we reach the new position
982
for ( ; pos >= BUF_TEMP_SIZE; pos -= bytes_read)
984
bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
985
if ( m_lasterror != wxSTREAM_NO_ERROR )
986
return wxInvalidOffset;
988
wxASSERT(bytes_read == WXSIZEOF(buf));
991
// read the last 'pos' bytes
992
bytes_read = Read(buf, (size_t)pos).LastRead();
993
if ( m_lasterror != wxSTREAM_NO_ERROR )
994
return wxInvalidOffset;
996
wxASSERT(bytes_read == (size_t)pos);
998
// we should now have sought to the right position...
1002
/* RR: A call to SeekI() will automatically invalidate any previous
1003
call to Ungetch(), otherwise it would be possible to SeekI() to
1004
one position, unread some bytes there, SeekI() to another position
1005
and the data would be corrupted.
1007
GRG: Could add code here to try to navigate within the wback
1008
buffer if possible, but is it really needed? It would only work
1009
when seeking in wxFromCurrent mode, else it would invalidate
1014
wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1022
return OnSysSeek(pos, mode);
1025
wxFileOffset wxInputStream::TellI() const
1027
wxFileOffset pos = OnSysTell();
1029
if (pos != wxInvalidOffset)
1030
pos -= (m_wbacksize - m_wbackcur);
1036
// ----------------------------------------------------------------------------
1038
// ----------------------------------------------------------------------------
1040
IMPLEMENT_ABSTRACT_CLASS(wxOutputStream, wxStreamBase)
1042
wxOutputStream::wxOutputStream()
1046
wxOutputStream::~wxOutputStream()
1050
size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
1051
size_t WXUNUSED(bufsize))
1056
void wxOutputStream::PutC(char c)
1058
Write(&c, sizeof(c));
1061
wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
1063
m_lastcount = OnSysWrite(buffer, size);
1067
wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
1069
stream_in.Read(*this);
1073
bool wxOutputStream::WriteAll(const void *buffer_, size_t size)
1075
// This exactly mirrors ReadAll(), see there for more comments.
1076
const char* buffer = static_cast<const char*>(buffer_);
1078
size_t totalCount = 0;
1082
const size_t lastCount = Write(buffer, size).LastWrite();
1086
totalCount += lastCount;
1091
if ( lastCount >= size )
1098
buffer += lastCount;
1101
m_lastcount = totalCount;
1105
wxFileOffset wxOutputStream::TellO() const
1110
wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
1112
return OnSysSeek(pos, mode);
1115
void wxOutputStream::Sync()
1120
// ----------------------------------------------------------------------------
1121
// wxCountingOutputStream
1122
// ----------------------------------------------------------------------------
1124
IMPLEMENT_DYNAMIC_CLASS(wxCountingOutputStream, wxOutputStream)
1126
wxCountingOutputStream::wxCountingOutputStream ()
1132
wxFileOffset wxCountingOutputStream::GetLength() const
1137
size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
1140
m_currentPos += size;
1141
if ( m_currentPos > m_lastPos )
1142
m_lastPos = m_currentPos;
1147
wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
1149
ssize_t new_pos = wx_truncate_cast(ssize_t, pos);
1154
wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") );
1158
new_pos += m_lastPos;
1159
wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastPos + pos), wxInvalidOffset, wxT("huge position not supported") );
1163
new_pos += m_currentPos;
1164
wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") );
1168
wxFAIL_MSG( wxT("invalid seek mode") );
1169
return wxInvalidOffset;
1172
m_currentPos = new_pos;
1174
if ( m_currentPos > m_lastPos )
1175
m_lastPos = m_currentPos;
1177
return m_currentPos;
1180
wxFileOffset wxCountingOutputStream::OnSysTell() const
1182
return m_currentPos;
1185
// ----------------------------------------------------------------------------
1186
// wxFilterInputStream
1187
// ----------------------------------------------------------------------------
1189
IMPLEMENT_ABSTRACT_CLASS(wxFilterInputStream, wxInputStream)
1191
wxFilterInputStream::wxFilterInputStream()
1192
: m_parent_i_stream(NULL),
1197
wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
1198
: m_parent_i_stream(&stream),
1203
wxFilterInputStream::wxFilterInputStream(wxInputStream *stream)
1204
: m_parent_i_stream(stream),
1209
wxFilterInputStream::~wxFilterInputStream()
1212
delete m_parent_i_stream;
1215
// ----------------------------------------------------------------------------
1216
// wxFilterOutputStream
1217
// ----------------------------------------------------------------------------
1219
IMPLEMENT_ABSTRACT_CLASS(wxFilterOutputStream, wxOutputStream)
1221
wxFilterOutputStream::wxFilterOutputStream()
1222
: m_parent_o_stream(NULL),
1227
wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
1228
: m_parent_o_stream(&stream),
1233
wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream)
1234
: m_parent_o_stream(stream),
1239
bool wxFilterOutputStream::Close()
1241
if (m_parent_o_stream && m_owns)
1242
return m_parent_o_stream->Close();
1247
wxFilterOutputStream::~wxFilterOutputStream()
1250
delete m_parent_o_stream;
1253
// ----------------------------------------------------------------------------
1254
// wxFilterClassFactoryBase
1255
// ----------------------------------------------------------------------------
1257
IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject)
1259
wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const
1261
return location.substr(0, FindExtension(location));
1264
wxString::size_type wxFilterClassFactoryBase::FindExtension(
1265
const wxString& location) const
1267
for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++)
1269
if ( location.EndsWith(*p) )
1270
return location.length() - wxStrlen(*p);
1273
return wxString::npos;
1276
bool wxFilterClassFactoryBase::CanHandle(const wxString& protocol,
1277
wxStreamProtocolType type) const
1279
if (type == wxSTREAM_FILEEXT)
1280
return FindExtension(protocol) != wxString::npos;
1282
for (const wxChar *const *p = GetProtocols(type); *p; p++)
1289
// ----------------------------------------------------------------------------
1290
// wxFilterClassFactory
1291
// ----------------------------------------------------------------------------
1293
IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase)
1295
wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL;
1297
void wxFilterClassFactory::Remove()
1301
wxFilterClassFactory **pp = &sm_first;
1304
pp = &(*pp)->m_next;
1312
// ----------------------------------------------------------------------------
1313
// wxBufferedInputStream
1314
// ----------------------------------------------------------------------------
1319
// helper function used for initializing the buffer used by
1320
// wxBufferedInput/OutputStream: it simply returns the provided buffer if it's
1321
// not NULL or creates a buffer of the given size otherwise
1322
template <typename T>
1324
CreateBufferIfNeeded(T& stream, wxStreamBuffer *buffer, size_t bufsize = 1024)
1326
return buffer ? buffer : new wxStreamBuffer(bufsize, stream);
1329
} // anonymous namespace
1331
wxBufferedInputStream::wxBufferedInputStream(wxInputStream& stream,
1332
wxStreamBuffer *buffer)
1333
: wxFilterInputStream(stream)
1335
m_i_streambuf = CreateBufferIfNeeded(*this, buffer);
1338
wxBufferedInputStream::wxBufferedInputStream(wxInputStream& stream,
1340
: wxFilterInputStream(stream)
1342
m_i_streambuf = CreateBufferIfNeeded(*this, NULL, bufsize);
1345
wxBufferedInputStream::~wxBufferedInputStream()
1347
m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(),
1350
delete m_i_streambuf;
1353
char wxBufferedInputStream::Peek()
1355
return m_i_streambuf->Peek();
1358
wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1360
// reset the error flag
1363
// first read from the already cached data
1364
m_lastcount = GetWBack(buf, size);
1366
// do we have to read anything more?
1367
if ( m_lastcount < size )
1369
size -= m_lastcount;
1370
buf = (char *)buf + m_lastcount;
1372
// the call to wxStreamBuffer::Read() below may reset our m_lastcount
1373
// (but it also may not do it if the buffer is associated to another
1374
// existing stream and wasn't created by us), so save it
1375
size_t countOld = m_lastcount;
1377
// the new count of the bytes read is the count of bytes read this time
1378
m_lastcount = m_i_streambuf->Read(buf, size);
1380
// plus those we had read before
1381
m_lastcount += countOld;
1387
wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
1389
// RR: Look at wxInputStream for comments.
1391
if (m_lasterror==wxSTREAM_EOF)
1396
wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
1404
return m_i_streambuf->Seek(pos, mode);
1407
wxFileOffset wxBufferedInputStream::TellI() const
1409
wxFileOffset pos = m_i_streambuf->Tell();
1411
if (pos != wxInvalidOffset)
1412
pos -= (m_wbacksize - m_wbackcur);
1417
size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
1419
return m_parent_i_stream->Read(buffer, bufsize).LastRead();
1422
wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1424
return m_parent_i_stream->SeekI(seek, mode);
1427
wxFileOffset wxBufferedInputStream::OnSysTell() const
1429
return m_parent_i_stream->TellI();
1432
void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1434
wxCHECK_RET( buffer, wxT("wxBufferedInputStream needs buffer") );
1436
delete m_i_streambuf;
1437
m_i_streambuf = buffer;
1440
// ----------------------------------------------------------------------------
1441
// wxBufferedOutputStream
1442
// ----------------------------------------------------------------------------
1444
wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& stream,
1445
wxStreamBuffer *buffer)
1446
: wxFilterOutputStream(stream)
1448
m_o_streambuf = CreateBufferIfNeeded(*this, buffer);
1451
wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& stream,
1453
: wxFilterOutputStream(stream)
1455
m_o_streambuf = CreateBufferIfNeeded(*this, NULL, bufsize);
1458
wxBufferedOutputStream::~wxBufferedOutputStream()
1461
delete m_o_streambuf;
1464
bool wxBufferedOutputStream::Close()
1471
wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
1474
m_o_streambuf->Write(buffer, size);
1478
wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
1481
return m_o_streambuf->Seek(pos, mode);
1484
wxFileOffset wxBufferedOutputStream::TellO() const
1486
return m_o_streambuf->Tell();
1489
void wxBufferedOutputStream::Sync()
1491
m_o_streambuf->FlushBuffer();
1492
m_parent_o_stream->Sync();
1495
size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
1497
return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
1500
wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
1502
return m_parent_o_stream->SeekO(seek, mode);
1505
wxFileOffset wxBufferedOutputStream::OnSysTell() const
1507
return m_parent_o_stream->TellO();
1510
wxFileOffset wxBufferedOutputStream::GetLength() const
1512
return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition();
1515
void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1517
wxCHECK_RET( buffer, wxT("wxBufferedOutputStream needs buffer") );
1519
delete m_o_streambuf;
1520
m_o_streambuf = buffer;
1523
// ---------------------------------------------------------------------------
1524
// wxWrapperInputStream implementation
1525
// ---------------------------------------------------------------------------
1527
wxWrapperInputStream::wxWrapperInputStream()
1529
m_lasterror = wxSTREAM_READ_ERROR;
1532
wxWrapperInputStream::wxWrapperInputStream(wxInputStream& stream)
1533
: wxFilterInputStream(stream)
1535
SynchronizeLastError();
1538
wxWrapperInputStream::wxWrapperInputStream(wxInputStream *stream)
1539
: wxFilterInputStream(stream)
1541
if ( m_parent_i_stream )
1542
SynchronizeLastError();
1544
m_lasterror = wxSTREAM_READ_ERROR;
1547
void wxWrapperInputStream::InitParentStream(wxInputStream& stream)
1549
wxCHECK_RET( !m_parent_i_stream, "Can't init parent stream twice" );
1551
m_parent_i_stream = &stream;
1553
SynchronizeLastError();
1556
void wxWrapperInputStream::InitParentStream(wxInputStream* stream)
1558
wxCHECK_RET( !m_parent_i_stream, "Can't init parent stream twice" );
1560
m_parent_i_stream = stream;
1562
if ( m_parent_i_stream )
1566
SynchronizeLastError();
1570
wxFileOffset wxWrapperInputStream::GetLength() const
1572
wxCHECK_MSG(m_parent_i_stream, wxInvalidOffset, "Stream not valid");
1574
wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
1575
return m_parent_i_stream->GetLength();
1578
bool wxWrapperInputStream::IsSeekable() const
1580
wxCHECK_MSG(m_parent_i_stream, false, "Stream not valid");
1581
return m_parent_i_stream->IsSeekable();
1584
size_t wxWrapperInputStream::OnSysRead(void *buffer, size_t size)
1586
wxCHECK_MSG(m_parent_i_stream, false, "Stream not valid");
1588
wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
1590
m_parent_i_stream->Read(buffer, size);
1591
return m_parent_i_stream->LastRead();
1594
wxFileOffset wxWrapperInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
1596
wxCHECK_MSG(IsSeekable(), false, "Stream not seekable");
1598
wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
1599
return m_parent_i_stream->SeekI (pos, mode);
1602
wxFileOffset wxWrapperInputStream::OnSysTell() const
1604
wxCHECK_MSG(m_parent_i_stream, false, "Stream not valid");
1606
wxON_BLOCK_EXIT_THIS0(wxWrapperInputStream::SynchronizeLastError);
1607
return m_parent_i_stream->TellI();
1610
// ----------------------------------------------------------------------------
1611
// Some IOManip function
1612
// ----------------------------------------------------------------------------
1614
wxOutputStream& wxEndL(wxOutputStream& stream)
1616
static const wxChar *eol = wxTextFile::GetEOL();
1618
return stream.Write(eol, wxStrlen(eol));
1621
#endif // wxUSE_STREAMS