]> git.saurik.com Git - wxWidgets.git/blame - src/common/stream.cpp
Halfway reasonable implementation of wxFont for wxCocoa.
[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 1158wxString::size_type wxFilterClassFactoryBase::FindExtension(
86501081 1159 const wxString& location) const
a8d2cf4e 1160{
489a164c 1161 for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++)
a8d2cf4e 1162 {
86501081
VS
1163 if ( location.EndsWith(*p) )
1164 return location.length() - wxStrlen(*p);
166c3ef0 1165 }
a8d2cf4e
MW
1166
1167 return wxString::npos;
1168}
1169
86501081 1170bool wxFilterClassFactoryBase::CanHandle(const wxString& protocol,
58211774 1171 wxStreamProtocolType type) const
a8d2cf4e 1172{
489a164c 1173 if (type == wxSTREAM_FILEEXT)
a8d2cf4e 1174 return FindExtension(protocol) != wxString::npos;
166c3ef0 1175 else
489a164c 1176 for (const wxChar *const *p = GetProtocols(type); *p; p++)
86501081 1177 if (protocol == *p)
166c3ef0 1178 return true;
166c3ef0
MW
1179
1180 return false;
1181}
1182
58211774
MW
1183// ----------------------------------------------------------------------------
1184// wxFilterClassFactory
1185// ----------------------------------------------------------------------------
1186
1187IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase)
1188
1189wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL;
1190
166c3ef0
MW
1191void wxFilterClassFactory::Remove()
1192{
1193 if (m_next != this)
1194 {
1195 wxFilterClassFactory **pp = &sm_first;
1196
1197 while (*pp != this)
1198 pp = &(*pp)->m_next;
1199
1200 *pp = m_next;
1201
1202 m_next = this;
1203 }
6d44bf31
GL
1204}
1205
fae05df5
GL
1206// ----------------------------------------------------------------------------
1207// wxBufferedInputStream
1208// ----------------------------------------------------------------------------
49e399d8 1209
47fc03d2
VZ
1210wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s,
1211 wxStreamBuffer *buffer)
49e399d8 1212 : wxFilterInputStream(s)
6d44bf31 1213{
47fc03d2
VZ
1214 if ( buffer )
1215 {
1216 // use the buffer provided by the user
1217 m_i_streambuf = buffer;
1218 }
1219 else // create a default buffer
1220 {
1221 m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read);
49e399d8 1222
47fc03d2
VZ
1223 m_i_streambuf->SetBufferIO(1024);
1224 }
6d44bf31
GL
1225}
1226
fae05df5 1227wxBufferedInputStream::~wxBufferedInputStream()
6d44bf31 1228{
4004775e 1229 m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(),
1fb45475 1230 wxFromCurrent);
672cedf8 1231
c7a9fa36 1232 delete m_i_streambuf;
6d44bf31
GL
1233}
1234
6319afe3
GL
1235char wxBufferedInputStream::Peek()
1236{
c7a9fa36 1237 return m_i_streambuf->Peek();
6319afe3
GL
1238}
1239
49e399d8 1240wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size)
1e3eca9d 1241{
e9f69291 1242 // reset the error flag
2b5f62a0 1243 Reset();
1e3eca9d 1244
e9f69291
VZ
1245 // first read from the already cached data
1246 m_lastcount = GetWBack(buf, size);
1247
1248 // do we have to read anything more?
1249 if ( m_lastcount < size )
c7a9fa36 1250 {
e9f69291
VZ
1251 size -= m_lastcount;
1252 buf = (char *)buf + m_lastcount;
1e3eca9d 1253
e9f69291
VZ
1254 // the call to wxStreamBuffer::Read() below will reset our m_lastcount,
1255 // so save it
1256 size_t countOld = m_lastcount;
1257
1258 m_i_streambuf->Read(buf, size);
1259
1260 m_lastcount += countOld;
1261 }
6d44bf31 1262
c7a9fa36 1263 return *this;
6d44bf31
GL
1264}
1265
4004775e 1266wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode)
6d44bf31 1267{
adc35078
RR
1268 // RR: Look at wxInputStream for comments.
1269
1270 if (m_lasterror==wxSTREAM_EOF)
2b5f62a0 1271 Reset();
adc35078
RR
1272
1273 if (m_wback)
1274 {
1275 wxLogDebug( wxT("Seeking in stream which has data written back to it.") );
2b5f62a0 1276
adc35078
RR
1277 free(m_wback);
1278 m_wback = NULL;
1279 m_wbacksize = 0;
1280 m_wbackcur = 0;
1281 }
2b5f62a0 1282
c7a9fa36 1283 return m_i_streambuf->Seek(pos, mode);
6d44bf31
GL
1284}
1285
4004775e 1286wxFileOffset wxBufferedInputStream::TellI() const
6d44bf31 1287{
30984dea 1288 wxFileOffset pos = m_i_streambuf->Tell();
adc35078
RR
1289
1290 if (pos != wxInvalidOffset)
1291 pos -= (m_wbacksize - m_wbackcur);
2b5f62a0 1292
adc35078 1293 return pos;
38830220 1294}
6d44bf31 1295
fae05df5 1296size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize)
38830220 1297{
c7a9fa36 1298 return m_parent_i_stream->Read(buffer, bufsize).LastRead();
38830220
RR
1299}
1300
4004775e 1301wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
38830220 1302{
c7a9fa36 1303 return m_parent_i_stream->SeekI(seek, mode);
6d44bf31
GL
1304}
1305
4004775e 1306wxFileOffset wxBufferedInputStream::OnSysTell() const
6d44bf31 1307{
c7a9fa36 1308 return m_parent_i_stream->TellI();
38830220 1309}
6d44bf31 1310
47fc03d2
VZ
1311void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer)
1312{
1313 wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") );
1314
1315 delete m_i_streambuf;
1316 m_i_streambuf = buffer;
1317}
1318
fae05df5
GL
1319// ----------------------------------------------------------------------------
1320// wxBufferedOutputStream
1321// ----------------------------------------------------------------------------
6d44bf31 1322
47fc03d2
VZ
1323wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s,
1324 wxStreamBuffer *buffer)
49e399d8 1325 : wxFilterOutputStream(s)
6d44bf31 1326{
47fc03d2
VZ
1327 if ( buffer )
1328 {
1329 m_o_streambuf = buffer;
1330 }
1331 else // create a default one
1332 {
1333 m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write);
1334
1335 m_o_streambuf->SetBufferIO(1024);
1336 }
6d44bf31
GL
1337}
1338
fae05df5 1339wxBufferedOutputStream::~wxBufferedOutputStream()
6d44bf31 1340{
c7a9fa36
RR
1341 Sync();
1342 delete m_o_streambuf;
3d4c6a21
GL
1343}
1344
8f0ff178
RN
1345bool wxBufferedOutputStream::Close()
1346{
1347 Sync();
1348 return IsOk();
1349}
1350
1351
fae05df5 1352wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size)
123a7fdd 1353{
c7a9fa36
RR
1354 m_lastcount = 0;
1355 m_o_streambuf->Write(buffer, size);
1356 return *this;
123a7fdd
GL
1357}
1358
4004775e 1359wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode)
f4ada568 1360{
c7a9fa36
RR
1361 Sync();
1362 return m_o_streambuf->Seek(pos, mode);
f4ada568
GL
1363}
1364
4004775e 1365wxFileOffset wxBufferedOutputStream::TellO() const
3d4c6a21 1366{
c7a9fa36 1367 return m_o_streambuf->Tell();
3d4c6a21
GL
1368}
1369
fae05df5 1370void wxBufferedOutputStream::Sync()
3d4c6a21 1371{
c7a9fa36
RR
1372 m_o_streambuf->FlushBuffer();
1373 m_parent_o_stream->Sync();
3d4c6a21 1374}
219f895a 1375
fae05df5 1376size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
f4ada568 1377{
c7a9fa36 1378 return m_parent_o_stream->Write(buffer, bufsize).LastWrite();
f4ada568
GL
1379}
1380
4004775e 1381wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
219f895a 1382{
c7a9fa36 1383 return m_parent_o_stream->SeekO(seek, mode);
219f895a
RR
1384}
1385
4004775e 1386wxFileOffset wxBufferedOutputStream::OnSysTell() const
219f895a 1387{
c7a9fa36
RR
1388 return m_parent_o_stream->TellO();
1389}
1390
588066b7 1391wxFileOffset wxBufferedOutputStream::GetLength() const
c7a9fa36 1392{
588066b7 1393 return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition();
219f895a 1394}
6d44bf31 1395
47fc03d2
VZ
1396void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer)
1397{
1398 wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") );
1399
1400 delete m_o_streambuf;
1401 m_o_streambuf = buffer;
1402}
1403
6d44bf31
GL
1404// ----------------------------------------------------------------------------
1405// Some IOManip function
1406// ----------------------------------------------------------------------------
1407
1408wxOutputStream& wxEndL(wxOutputStream& stream)
1409{
733b8ed3
VZ
1410 static const wxChar *eol = wxTextFile::GetEOL();
1411
1412 return stream.Write(eol, wxStrlen(eol));
6d44bf31 1413}
ce4169a4 1414
15dc68b6 1415#endif // wxUSE_STREAMS