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