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