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