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