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