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