]> git.saurik.com Git - wxWidgets.git/blame - src/common/stream.cpp
corrected signed/unsigned comparison warning
[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
6ea48c51 812int wxInputStream::GetC()
fae05df5 813{
6ea48c51 814 unsigned char c;
2b5f62a0 815 Read(&c, sizeof(c));
6ea48c51 816 return LastRead() ? c : wxEOF;
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{
68f14620 872 size_t lastcount = 0;
cd6ce4a9 873 char buf[BUF_TEMP_SIZE];
3d4c6a21 874
2b5f62a0 875 for ( ;; )
c7a9fa36 876 {
2b5f62a0
VZ
877 size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead();
878 if ( !bytes_read )
879 break;
880
881 if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read )
882 break;
68f14620
VZ
883
884 lastcount += bytes_read;
c7a9fa36 885 }
2b5f62a0 886
68f14620
VZ
887 m_lastcount = lastcount;
888
c7a9fa36 889 return *this;
3d4c6a21
GL
890}
891
4004775e 892wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
75ed1d15 893{
adc35078
RR
894 // RR: This code is duplicated in wxBufferedInputStream. This is
895 // not really a good design, but buffered stream are different
896 // from all other in that they handle two stream-related objects,
897 // the stream buffer and parent stream.
898
899 // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek
cd6ce4a9 900 if (m_lasterror==wxSTREAM_EOF)
2b5f62a0 901 m_lasterror=wxSTREAM_NO_ERROR;
c7a9fa36 902
adc35078
RR
903 /* RR: A call to SeekI() will automatically invalidate any previous
904 call to Ungetch(), otherwise it would be possible to SeekI() to
c7a9fa36 905 one position, unread some bytes there, SeekI() to another position
19da7237
GRG
906 and the data would be corrupted.
907
908 GRG: Could add code here to try to navigate within the wback
909 buffer if possible, but is it really needed? It would only work
910 when seeking in wxFromCurrent mode, else it would invalidate
adc35078 911 anyway... */
2b5f62a0 912
cd6ce4a9 913 if (m_wback)
c7a9fa36 914 {
adc35078 915 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
2b5f62a0 916
c7a9fa36 917 free(m_wback);
49e399d8 918 m_wback = NULL;
c7a9fa36
RR
919 m_wbacksize = 0;
920 m_wbackcur = 0;
921 }
fe8aa971 922
c7a9fa36 923 return OnSysSeek(pos, mode);
75ed1d15
GL
924}
925
4004775e 926wxFileOffset wxInputStream::TellI() const
75ed1d15 927{
30984dea 928 wxFileOffset pos = OnSysTell();
19da7237
GRG
929
930 if (pos != wxInvalidOffset)
931 pos -= (m_wbacksize - m_wbackcur);
932
933 return pos;
75ed1d15
GL
934}
935
1678ad78 936
fae05df5
GL
937// ----------------------------------------------------------------------------
938// wxOutputStream
939// ----------------------------------------------------------------------------
49e399d8 940
fae05df5 941wxOutputStream::wxOutputStream()
1678ad78 942{
1678ad78
GL
943}
944
fae05df5 945wxOutputStream::~wxOutputStream()
123a7fdd 946{
123a7fdd
GL
947}
948
47fc03d2
VZ
949size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer),
950 size_t WXUNUSED(bufsize))
951{
952 return 0;
953}
954
7513f9ff
GRG
955void wxOutputStream::PutC(char c)
956{
2b5f62a0 957 Write(&c, sizeof(c));
7513f9ff
GRG
958}
959
fae05df5 960wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
1678ad78 961{
c7a9fa36
RR
962 m_lastcount = OnSysWrite(buffer, size);
963 return *this;
1678ad78
GL
964}
965
fae05df5 966wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
38830220 967{
c7a9fa36
RR
968 stream_in.Read(*this);
969 return *this;
38830220
RR
970}
971
4004775e 972wxFileOffset wxOutputStream::TellO() const
38830220 973{
c7a9fa36 974 return OnSysTell();
38830220
RR
975}
976
4004775e 977wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
38830220 978{
c7a9fa36 979 return OnSysSeek(pos, mode);
38830220
RR
980}
981
fae05df5 982void wxOutputStream::Sync()
1678ad78 983{
1678ad78
GL
984}
985
123a7fdd 986
e2acb9ae
RR
987// ----------------------------------------------------------------------------
988// wxCountingOutputStream
989// ----------------------------------------------------------------------------
990
991wxCountingOutputStream::wxCountingOutputStream ()
e2acb9ae 992{
c7a9fa36 993 m_currentPos = 0;
e2acb9ae
RR
994}
995
588066b7 996wxFileOffset wxCountingOutputStream::GetLength() const
e2acb9ae 997{
c7a9fa36 998 return m_lastcount;
e2acb9ae
RR
999}
1000
49e399d8
VZ
1001size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer),
1002 size_t size)
e2acb9ae 1003{
c7a9fa36 1004 m_currentPos += size;
49e399d8
VZ
1005 if (m_currentPos > m_lastcount)
1006 m_lastcount = m_currentPos;
1007
c7a9fa36 1008 return m_currentPos;
e2acb9ae
RR
1009}
1010
4004775e 1011wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
e2acb9ae 1012{
17a1ebd1 1013 ssize_t new_pos = wx_truncate_cast(ssize_t, pos);
287d71d9 1014
49e399d8
VZ
1015 switch ( mode )
1016 {
1017 case wxFromStart:
287d71d9 1018 wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") );
49e399d8
VZ
1019 break;
1020
1021 case wxFromEnd:
287d71d9
WS
1022 new_pos = m_lastcount + new_pos;
1023 wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") );
49e399d8
VZ
1024 break;
1025
1026 case wxFromCurrent:
287d71d9
WS
1027 new_pos = m_currentPos + new_pos;
1028 wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") );
49e399d8
VZ
1029 break;
1030
1031 default:
1032 wxFAIL_MSG( _T("invalid seek mode") );
30984dea 1033 return wxInvalidOffset;
49e399d8 1034 }
cd6ce4a9 1035
287d71d9
WS
1036 m_currentPos = new_pos;
1037
49e399d8
VZ
1038 if (m_currentPos > m_lastcount)
1039 m_lastcount = m_currentPos;
cd6ce4a9 1040
c7a9fa36 1041 return m_currentPos;
e2acb9ae
RR
1042}
1043
4004775e 1044wxFileOffset wxCountingOutputStream::OnSysTell() const
e2acb9ae 1045{
c7a9fa36 1046 return m_currentPos;
e2acb9ae 1047}
cd6ce4a9 1048
1678ad78 1049// ----------------------------------------------------------------------------
fae05df5 1050// wxFilterInputStream
1678ad78 1051// ----------------------------------------------------------------------------
e2acb9ae 1052
fae05df5 1053wxFilterInputStream::wxFilterInputStream()
166c3ef0
MW
1054 : m_parent_i_stream(NULL),
1055 m_owns(false)
3d4c6a21 1056{
6d44bf31
GL
1057}
1058
fae05df5 1059wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
166c3ef0
MW
1060 : m_parent_i_stream(&stream),
1061 m_owns(false)
1062{
1063}
1064
1065wxFilterInputStream::wxFilterInputStream(wxInputStream *stream)
1066 : m_parent_i_stream(stream),
1067 m_owns(true)
6d44bf31 1068{
3d4c6a21
GL
1069}
1070
fae05df5 1071wxFilterInputStream::~wxFilterInputStream()
3d4c6a21 1072{
166c3ef0
MW
1073 if (m_owns)
1074 delete m_parent_i_stream;
6d44bf31
GL
1075}
1076
fae05df5
GL
1077// ----------------------------------------------------------------------------
1078// wxFilterOutputStream
1079// ----------------------------------------------------------------------------
49e399d8 1080
fae05df5 1081wxFilterOutputStream::wxFilterOutputStream()
166c3ef0
MW
1082 : m_parent_o_stream(NULL),
1083 m_owns(false)
6d44bf31 1084{
3d4c6a21
GL
1085}
1086
fae05df5 1087wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
166c3ef0
MW
1088 : m_parent_o_stream(&stream),
1089 m_owns(false)
1090{
1091}
1092
1093wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream)
1094 : m_parent_o_stream(stream),
1095 m_owns(true)
1096{
1097}
1098
1099bool wxFilterOutputStream::Close()
3d4c6a21 1100{
166c3ef0
MW
1101 if (m_parent_o_stream && m_owns)
1102 return m_parent_o_stream->Close();
1103 else
1104 return true;
6d44bf31
GL
1105}
1106
fae05df5 1107wxFilterOutputStream::~wxFilterOutputStream()
6d44bf31 1108{
166c3ef0
MW
1109 if (m_owns)
1110 delete m_parent_o_stream;
1111}
1112
1113// ----------------------------------------------------------------------------
58211774 1114// wxFilterClassFactoryBase
166c3ef0
MW
1115// ----------------------------------------------------------------------------
1116
58211774 1117IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject)
166c3ef0 1118
58211774 1119wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const
166c3ef0 1120{
a8d2cf4e
MW
1121 return location.substr(0, FindExtension(location));
1122}
166c3ef0 1123
58211774
MW
1124wxString::size_type wxFilterClassFactoryBase::FindExtension(
1125 const wxChar *location) const
a8d2cf4e
MW
1126{
1127 size_t len = wxStrlen(location);
166c3ef0 1128
489a164c 1129 for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++)
a8d2cf4e
MW
1130 {
1131 size_t l = wxStrlen(*p);
1132
1133 if (l <= len && wxStrcmp(*p, location + len - l) == 0)
1134 return len - l;
166c3ef0 1135 }
a8d2cf4e
MW
1136
1137 return wxString::npos;
1138}
1139
58211774
MW
1140bool wxFilterClassFactoryBase::CanHandle(const wxChar *protocol,
1141 wxStreamProtocolType type) const
a8d2cf4e 1142{
489a164c 1143 if (type == wxSTREAM_FILEEXT)
a8d2cf4e 1144 return FindExtension(protocol) != wxString::npos;
166c3ef0 1145 else
489a164c 1146 for (const wxChar *const *p = GetProtocols(type); *p; p++)
166c3ef0
MW
1147 if (wxStrcmp(*p, protocol) == 0)
1148 return true;
166c3ef0
MW
1149
1150 return false;
1151}
1152
58211774
MW
1153// ----------------------------------------------------------------------------
1154// wxFilterClassFactory
1155// ----------------------------------------------------------------------------
1156
1157IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase)
1158
1159wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL;
1160
166c3ef0
MW
1161void wxFilterClassFactory::Remove()
1162{
1163 if (m_next != this)
1164 {
1165 wxFilterClassFactory **pp = &sm_first;
1166
1167 while (*pp != this)
1168 pp = &(*pp)->m_next;
1169
1170 *pp = m_next;
1171
1172 m_next = this;
1173 }
6d44bf31
GL
1174}
1175
fae05df5
GL
1176// ----------------------------------------------------------------------------
1177// wxBufferedInputStream
1178// ----------------------------------------------------------------------------
49e399d8 1179
47fc03d2
VZ
1180wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1181 wxStreamBuffer *buffer)
49e399d8 1182 : wxFilterInputStream(s)
6d44bf31 1183{
47fc03d2
VZ
1184 if ( buffer )
1185 {
1186 // use the buffer provided by the user
1187 m_i_streambuf = buffer;
1188 }
1189 else // create a default buffer
1190 {
1191 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
49e399d8 1192
47fc03d2
VZ
1193 m_i_streambuf->SetBufferIO(1024);
1194 }
6d44bf31
GL
1195}
1196
fae05df5 1197wxBufferedInputStream::~wxBufferedInputStream()
6d44bf31 1198{
4004775e 1199 m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(),
1fb45475 1200 wxFromCurrent);
672cedf8 1201
c7a9fa36 1202 delete m_i_streambuf;
6d44bf31
GL
1203}
1204
6319afe3
GL
1205char wxBufferedInputStream::Peek()
1206{
c7a9fa36 1207 return m_i_streambuf->Peek();
6319afe3
GL
1208}
1209
49e399d8 1210wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1e3eca9d 1211{
e9f69291 1212 // reset the error flag
2b5f62a0 1213 Reset();
1e3eca9d 1214
e9f69291
VZ
1215 // first read from the already cached data
1216 m_lastcount = GetWBack(buf, size);
1217
1218 // do we have to read anything more?
1219 if ( m_lastcount < size )
c7a9fa36 1220 {
e9f69291
VZ
1221 size -= m_lastcount;
1222 buf = (char *)buf + m_lastcount;
1e3eca9d 1223
e9f69291
VZ
1224 // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
1225 // so save it
1226 size_t countOld = m_lastcount;
1227
1228 m_i_streambuf->Read(buf, size);
1229
1230 m_lastcount += countOld;
1231 }
6d44bf31 1232
c7a9fa36 1233 return *this;
6d44bf31
GL
1234}
1235
4004775e 1236wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
6d44bf31 1237{
adc35078
RR
1238 // RR: Look at wxInputStream for comments.
1239
1240 if (m_lasterror==wxSTREAM_EOF)
2b5f62a0 1241 Reset();
adc35078
RR
1242
1243 if (m_wback)
1244 {
1245 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
2b5f62a0 1246
adc35078
RR
1247 free(m_wback);
1248 m_wback = NULL;
1249 m_wbacksize = 0;
1250 m_wbackcur = 0;
1251 }
2b5f62a0 1252
c7a9fa36 1253 return m_i_streambuf->Seek(pos, mode);
6d44bf31
GL
1254}
1255
4004775e 1256wxFileOffset wxBufferedInputStream::TellI() const
6d44bf31 1257{
30984dea 1258 wxFileOffset pos = m_i_streambuf->Tell();
adc35078
RR
1259
1260 if (pos != wxInvalidOffset)
1261 pos -= (m_wbacksize - m_wbackcur);
2b5f62a0 1262
adc35078 1263 return pos;
38830220 1264}
6d44bf31 1265
fae05df5 1266size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
38830220 1267{
c7a9fa36 1268 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
38830220
RR
1269}
1270
4004775e 1271wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
38830220 1272{
c7a9fa36 1273 return m_parent_i_stream->SeekI(seek, mode);
6d44bf31
GL
1274}
1275
4004775e 1276wxFileOffset wxBufferedInputStream::OnSysTell() const
6d44bf31 1277{
c7a9fa36 1278 return m_parent_i_stream->TellI();
38830220 1279}
6d44bf31 1280
47fc03d2
VZ
1281void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1282{
1283 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1284
1285 delete m_i_streambuf;
1286 m_i_streambuf = buffer;
1287}
1288
fae05df5
GL
1289// ----------------------------------------------------------------------------
1290// wxBufferedOutputStream
1291// ----------------------------------------------------------------------------
6d44bf31 1292
47fc03d2
VZ
1293wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1294 wxStreamBuffer *buffer)
49e399d8 1295 : wxFilterOutputStream(s)
6d44bf31 1296{
47fc03d2
VZ
1297 if ( buffer )
1298 {
1299 m_o_streambuf = buffer;
1300 }
1301 else // create a default one
1302 {
1303 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1304
1305 m_o_streambuf->SetBufferIO(1024);
1306 }
6d44bf31
GL
1307}
1308
fae05df5 1309wxBufferedOutputStream::~wxBufferedOutputStream()
6d44bf31 1310{
c7a9fa36
RR
1311 Sync();
1312 delete m_o_streambuf;
3d4c6a21
GL
1313}
1314
8f0ff178
RN
1315bool wxBufferedOutputStream::Close()
1316{
1317 Sync();
1318 return IsOk();
1319}
1320
1321
fae05df5 1322wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
123a7fdd 1323{
c7a9fa36
RR
1324 m_lastcount = 0;
1325 m_o_streambuf->Write(buffer, size);
1326 return *this;
123a7fdd
GL
1327}
1328
4004775e 1329wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
f4ada568 1330{
c7a9fa36
RR
1331 Sync();
1332 return m_o_streambuf->Seek(pos, mode);
f4ada568
GL
1333}
1334
4004775e 1335wxFileOffset wxBufferedOutputStream::TellO() const
3d4c6a21 1336{
c7a9fa36 1337 return m_o_streambuf->Tell();
3d4c6a21
GL
1338}
1339
fae05df5 1340void wxBufferedOutputStream::Sync()
3d4c6a21 1341{
c7a9fa36
RR
1342 m_o_streambuf->FlushBuffer();
1343 m_parent_o_stream->Sync();
3d4c6a21 1344}
219f895a 1345
fae05df5 1346size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
f4ada568 1347{
c7a9fa36 1348 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
f4ada568
GL
1349}
1350
4004775e 1351wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
219f895a 1352{
c7a9fa36 1353 return m_parent_o_stream->SeekO(seek, mode);
219f895a
RR
1354}
1355
4004775e 1356wxFileOffset wxBufferedOutputStream::OnSysTell() const
219f895a 1357{
c7a9fa36
RR
1358 return m_parent_o_stream->TellO();
1359}
1360
588066b7 1361wxFileOffset wxBufferedOutputStream::GetLength() const
c7a9fa36 1362{
588066b7 1363 return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition();
219f895a 1364}
6d44bf31 1365
47fc03d2
VZ
1366void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1367{
1368 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1369
1370 delete m_o_streambuf;
1371 m_o_streambuf = buffer;
1372}
1373
6d44bf31
GL
1374// ----------------------------------------------------------------------------
1375// Some IOManip function
1376// ----------------------------------------------------------------------------
1377
1378wxOutputStream& wxEndL(wxOutputStream& stream)
1379{
733b8ed3
VZ
1380 static const wxChar *eol = wxTextFile::GetEOL();
1381
1382 return stream.Write(eol, wxStrlen(eol));
6d44bf31 1383}
ce4169a4 1384
15dc68b6 1385#endif // wxUSE_STREAMS