/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/stream.cpp
ViewVC logotype

Annotation of /trunk/3rdparty/wxWidgets/src/common/stream.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22