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