home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / stream.cpp < prev    next >
C/C++ Source or Header  |  2002-08-30  |  31KB  |  1,242 lines

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