~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Externals/wxWidgets3/src/common/stream.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

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