streambuf.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:16k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: streambuf.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/03 17:11:36  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: streambuf.cpp,v 1000.3 2004/06/03 17:11:36 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Vladimir Ivanov
  35.  *
  36.  * File Description:  CCompression based C++ streambuf
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include "streambuf.hpp"
  41. #include <util/compress/stream.hpp>
  42. #include <memory>
  43. BEGIN_NCBI_SCOPE
  44. #define CP CCompressionProcessor
  45. //////////////////////////////////////////////////////////////////////////////
  46. //
  47. // CCompressionStreambuf
  48. //
  49. CCompressionStreambuf::CCompressionStreambuf(
  50.     CNcbiIos*                    stream,
  51.     CCompressionStreamProcessor* read_sp,
  52.     CCompressionStreamProcessor* write_sp)
  53.     :  m_Stream(stream), m_Reader(read_sp), m_Writer(write_sp), m_Buf(0)
  54. {
  55.     // Check parameters
  56.     if ( !stream  ||  
  57.          !((read_sp   &&  read_sp->m_Processor) ||
  58.            (write_sp  &&  write_sp->m_Processor))) {
  59.         return;
  60.     }
  61.     // Get buffers sizes
  62.     streamsize read_bufsize = 0, write_bufsize = 0;
  63.     if ( m_Reader ) {
  64.         read_bufsize = m_Reader->m_InBufSize + m_Reader->m_OutBufSize;
  65.     }
  66.     if ( m_Writer ) {
  67.         write_bufsize = m_Writer->m_InBufSize + m_Writer->m_OutBufSize;
  68.     }
  69.     // Allocate memory for all buffers at one time
  70.     auto_ptr<CT_CHAR_TYPE> bp(new CT_CHAR_TYPE[read_bufsize + write_bufsize]);
  71.     m_Buf = bp.get();
  72.     if ( !m_Buf ) {
  73.         return;
  74.     }
  75.     // Init processors and set the buffer pointers
  76.     if ( m_Reader ) {
  77.         m_Reader->m_InBuf  = m_Buf;
  78.         m_Reader->m_OutBuf = m_Buf + m_Reader->m_InBufSize;
  79.         m_Reader->m_Begin  = m_Reader->m_InBuf;
  80.         m_Reader->m_End    = m_Reader->m_InBuf;
  81.         // We wish to have underflow() called at the first read
  82.         setg(m_Reader->m_OutBuf, m_Reader->m_OutBuf, m_Reader->m_OutBuf);
  83.         m_Reader->m_Processor->Init();
  84.     } else {
  85.         setg(0,0,0);
  86.     }
  87.     if ( m_Writer ) {
  88.         m_Writer->m_InBuf  = m_Buf + read_bufsize;
  89.         m_Writer->m_OutBuf = m_Writer->m_InBuf + m_Writer->m_InBufSize;
  90.         m_Writer->m_Begin  = m_Writer->m_OutBuf;
  91.         m_Writer->m_End    = m_Writer->m_OutBuf;
  92.         // Use one character less for the input buffer than the really
  93.         // available one (see overflow())
  94.         setp(m_Writer->m_InBuf, m_Writer->m_InBuf + m_Writer->m_InBufSize - 1);
  95.         m_Writer->m_Processor->Init();
  96.     } else {
  97.         setp(0,0);
  98.     }
  99.     bp.release();
  100. }
  101. CCompressionStreambuf::~CCompressionStreambuf()
  102. {
  103.     Finalize();
  104.     delete[] m_Buf;
  105. }
  106. void CCompressionStreambuf::Finalize(CCompressionStream::EDirection dir)
  107. {
  108.     // Finalize read and write processors
  109.     if (dir == CCompressionStream::eReadWrite ) {
  110.         Finalize(CCompressionStream::eRead);
  111.         Finalize(CCompressionStream::eWrite);
  112.         return;
  113.     }
  114.     if ( !IsOkay() ) {
  115.         return;
  116.     }
  117.     // Check processor status
  118.     if ( !IsStreamProcessorOkay(dir) ) {
  119.         return;
  120.     }
  121.     // Sync buffers
  122.     Sync(dir);
  123.     // Finish
  124.     CCompressionStreamProcessor* sp = GetStreamProcessor(dir);
  125.     if ( sp->m_LastStatus == CP::eStatus_EndOfData ) {
  126.         return;
  127.     }
  128.     CT_CHAR_TYPE* buf = sp->m_OutBuf;
  129.     unsigned long out_size = sp->m_OutBufSize, out_avail = 0;
  130.     do {
  131.         if ( dir == CCompressionStream::eRead ) {
  132.             buf = egptr();
  133.             out_size = sp->m_OutBuf + sp->m_OutBufSize - egptr();
  134.         }
  135.         sp->m_LastStatus = sp->m_Processor->Finish(buf, out_size, &out_avail);
  136.         if ( sp->m_LastStatus == CP::eStatus_Error ) {
  137.            break;
  138.         }
  139.         if ( dir == CCompressionStream::eRead ) {
  140.             // Update the get's pointers
  141.             setg(sp->m_OutBuf, gptr(), egptr() + out_avail);
  142.         } else {
  143.             // Write the data to the underlying stream
  144.             if ( out_avail  &&
  145.                  m_Stream->rdbuf()->sputn(sp->m_OutBuf, out_avail) !=
  146.                  (streamsize)out_avail) {
  147.                 break;
  148.             }
  149.         }
  150.     } while ( out_avail  &&  sp->m_LastStatus == CP::eStatus_Overflow);
  151.     // Cleanup
  152.     sp->m_Processor->End();
  153.     sp->m_Finalized = true;
  154. }
  155. int CCompressionStreambuf::sync()
  156. {
  157.     if ( !IsOkay() ) {
  158.         return -1;
  159.     }
  160.     // Sync write processor buffers
  161.     if ( Sync(CCompressionStream::eWrite) != 0 ) {
  162.         return -1;
  163.     }
  164.     // Sync the underlying stream
  165.     return m_Stream->rdbuf()->PUBSYNC();
  166. }
  167. int CCompressionStreambuf::Sync(CCompressionStream::EDirection dir)
  168. {
  169.     // Check processor status
  170.     if ( !IsStreamProcessorOkay(dir) ) {
  171.         return -1;
  172.     }
  173.     // Process remaining data in the preprocessing buffer
  174.     if ( !Process(dir) ) {
  175.         return -1;
  176.     }
  177.     // Flush
  178.     CCompressionStreamProcessor* sp = GetStreamProcessor(dir);
  179.     CT_CHAR_TYPE* buf = sp->m_OutBuf;
  180.     unsigned long out_size = sp->m_OutBufSize, out_avail = 0;
  181.     do {
  182.         if ( dir == CCompressionStream::eRead ) {
  183.             buf = egptr();
  184.             out_size = sp->m_OutBuf + sp->m_OutBufSize - egptr();
  185.         }
  186.         sp->m_LastStatus = sp->m_Processor->Flush(buf, out_size, &out_avail);
  187.         if ( sp->m_LastStatus == CP::eStatus_Error  ||
  188.              sp->m_LastStatus == CP::eStatus_EndOfData ) {
  189.            break;
  190.         }
  191.         if ( dir == CCompressionStream::eRead ) {
  192.             // Update the get's pointers
  193.             setg(sp->m_OutBuf, gptr(), egptr() + out_avail);
  194.         } else {
  195.             // Write the data to the underlying stream
  196.             if ( out_avail  &&
  197.                  m_Stream->rdbuf()->sputn(sp->m_OutBuf, out_avail) !=
  198.                  (streamsize)out_avail) {
  199.                 return -1;
  200.             }
  201.         }
  202.     } while ( out_avail  &&  sp->m_LastStatus == CP::eStatus_Overflow );
  203.     // Check status
  204.     if ( sp->m_LastStatus != CP::eStatus_Success ) {
  205.         return -1;
  206.     }
  207.     return 0;
  208. }
  209. CT_INT_TYPE CCompressionStreambuf::overflow(CT_INT_TYPE c)
  210. {
  211.     // Check processor status
  212.     if ( !IsStreamProcessorOkay(CCompressionStream::eWrite) ) {
  213.         return CT_EOF;
  214.     }
  215.     if ( !CT_EQ_INT_TYPE(c, CT_EOF) ) {
  216.         // Put this character in the last position
  217.         // (this function is called when pptr() == eptr() but we
  218.         // have reserved one byte more in the constructor, thus
  219.         // *epptr() and now *pptr() point to valid positions)
  220.         *pptr() = c;
  221.         // Increment put pointer
  222.         pbump(1);
  223.     }
  224.     if ( ProcessStreamWrite() ) {
  225.         return CT_NOT_EOF(CT_EOF);
  226.     }
  227.     return CT_EOF;
  228. }
  229. CT_INT_TYPE CCompressionStreambuf::underflow(void)
  230. {
  231.     // Here we don't make a check for the streambuf finalization because
  232.     // underflow() can be called after Finalize() to read a rest of
  233.     // produced data.
  234.     if ( !IsOkay()  ||  !m_Reader  ||  !m_Reader->m_Processor ) {
  235.         return CT_EOF;
  236.     }
  237.     // Reset pointer to the processed data
  238.     setg(m_Reader->m_OutBuf, m_Reader->m_OutBuf, m_Reader->m_OutBuf);
  239.     // Try to process next data
  240.     if ( !ProcessStreamRead()  ||  gptr() == egptr() ) {
  241.         return CT_EOF;
  242.     }
  243.     return CT_TO_INT_TYPE(*gptr());
  244. }
  245. bool CCompressionStreambuf::ProcessStreamRead()
  246. {
  247.     unsigned long in_len, in_avail, out_size, out_avail;
  248.     streamsize    n_read;
  249.     // End of stream has been detected
  250.     if ( m_Reader->m_LastStatus == CP::eStatus_EndOfData ) {
  251.         return false;
  252.     }
  253.     // Put data into the compressor until there is something
  254.     // in the output buffer
  255.     do {
  256.         in_avail  = 0;
  257.         out_avail = 0;
  258.         out_size  = m_Reader->m_OutBuf + m_Reader->m_OutBufSize - egptr();
  259.         
  260.         // Refill the output buffer if necessary
  261.         if ( m_Reader->m_LastStatus != CP::eStatus_Overflow ) {
  262.             // Refill the input buffer if necessary
  263.             if ( m_Reader->m_Begin == m_Reader->m_End  ||
  264.                  !m_Reader->m_LastOutAvail) {
  265.                 n_read = m_Stream->rdbuf()->sgetn(m_Reader->m_InBuf,
  266.                                                   m_Reader->m_InBufSize);
  267.                 if ( !n_read ) {
  268.                     // We can't read more of data
  269.                     return false;
  270.                 }
  271.                 // Update the input buffer pointers
  272.                 m_Reader->m_Begin = m_Reader->m_InBuf;
  273.                 m_Reader->m_End   = m_Reader->m_InBuf + n_read;
  274.             }
  275.             // Process next data portion
  276.             in_len = m_Reader->m_End - m_Reader->m_Begin;
  277.             m_Reader->m_LastStatus = m_Reader->m_Processor->Process(
  278. m_Reader->m_Begin, in_len, egptr(), out_size,
  279. &in_avail, &out_avail);
  280.             if ( m_Reader->m_LastStatus != CP::eStatus_Success  &&
  281.                  m_Reader->m_LastStatus != CP::eStatus_EndOfData ) {
  282.                 return false;
  283.             }
  284.             m_Reader->m_LastOutAvail = out_avail;
  285.         } else {
  286.             // Get unprocessed data size
  287.             in_len = m_Reader->m_End - m_Reader->m_Begin;
  288.         }
  289.         
  290.         // Try to flush the compressor if it has not produced a data
  291.         // via Process()
  292.         if ( !out_avail ) { 
  293.             m_Reader->m_LastStatus = m_Reader->m_Processor->Flush(
  294. egptr(), out_size, &out_avail);
  295.             if ( m_Reader->m_LastStatus == CP::eStatus_Error ) {
  296.                 return false;
  297.             }
  298.             m_Reader->m_LastOutAvail = out_avail;
  299.         }
  300.         // Update pointer to an unprocessed data
  301.         m_Reader->m_Begin += (in_len - in_avail);
  302.         // Update the get's pointers
  303.         setg(m_Reader->m_OutBuf, gptr(), egptr() + out_avail);
  304.     } while ( !out_avail );
  305.     return true;
  306. }
  307. bool CCompressionStreambuf::ProcessStreamWrite()
  308. {
  309.     const char*      in_buf    = pbase();
  310.     const streamsize count     = pptr() - pbase();
  311.     unsigned long    in_avail  = count;
  312.     // End of stream has been detected
  313.     if ( m_Writer->m_LastStatus == CP::eStatus_EndOfData ) {
  314.         return false;
  315.     }
  316.     // Loop until no data is left
  317.     while ( in_avail ) {
  318.         // Process next data piece
  319.         unsigned long out_avail = 0;
  320.         m_Writer->m_LastStatus = m_Writer->m_Processor->Process(
  321.             in_buf + count - in_avail, in_avail,
  322.             m_Writer->m_OutBuf, m_Writer->m_OutBufSize,
  323.             &in_avail, &out_avail);
  324.         if ( m_Writer->m_LastStatus != CP::eStatus_Success  &&
  325.              m_Writer->m_LastStatus != CP::eStatus_EndOfData ) {
  326.            return false;
  327.         }
  328.         // Write the data to the underlying stream
  329.         if ( out_avail  &&
  330.              m_Stream->rdbuf()->sputn(m_Writer->m_OutBuf, out_avail) !=
  331.              (streamsize)out_avail) {
  332.             return false;
  333.         }
  334.     }
  335.     // Decrease the put pointer
  336.     pbump(-count);
  337.     return true;
  338. }
  339. streamsize CCompressionStreambuf::xsputn(const CT_CHAR_TYPE* buf,
  340.                                          streamsize count)
  341. {
  342.     // Check processor status
  343.     if ( !IsStreamProcessorOkay(CCompressionStream::eWrite) ) {
  344.         return CT_EOF;
  345.     }
  346.     // Check parameters
  347.     if ( !buf  ||  count <= 0 ) {
  348.         return 0;
  349.     }
  350.     // The number of chars copied
  351.     streamsize done = 0;
  352.     // Loop until no data is left
  353.     while ( done < count ) {
  354.         // Get the number of chars to write in this iteration
  355.         // (we've got one more char than epptr thinks)
  356.         size_t block_size = min(size_t(count-done), size_t(epptr()-pptr()+1));
  357.         // Write them
  358.         memcpy(pptr(), buf + done, block_size);
  359.         // Update the write pointer
  360.         pbump(block_size);
  361.         // Process block if necessary
  362.         if ( pptr() >= epptr()  &&  !ProcessStreamWrite() ) {
  363.             break;
  364.         }
  365.         done += block_size;
  366.     }
  367.     return done;
  368. };
  369. streamsize CCompressionStreambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize count)
  370. {
  371.     // We don't doing here a check for the streambuf finalization because
  372.     // underflow() can be called after Finalize() to read a rest of
  373.     // produced data.
  374.     if ( !IsOkay()  ||  !m_Reader->m_Processor ) {
  375.         return 0;
  376.     }
  377.     // Check parameters
  378.     if ( !buf  ||  count <= 0 ) {
  379.         return 0;
  380.     }
  381.     // The number of chars copied
  382.     streamsize done = 0;
  383.     // Loop until all data are not read yet
  384.     for (;;) {
  385.         // Get the number of chars to write in this iteration
  386.         size_t block_size = min(size_t(count-done), size_t(egptr()-gptr()));
  387.         // Copy them
  388.         if ( block_size ) {
  389.             memcpy(buf + done, gptr(), block_size);
  390.             done += block_size;
  391.             // Update get pointers.
  392.             // Satisfy "usual backup condition", see standard: 27.5.2.4.3.13
  393.             if ( block_size == egptr() - gptr() ) {
  394.                 *m_Reader->m_OutBuf = buf[done - 1];
  395.                 setg(m_Reader->m_OutBuf, m_Reader->m_OutBuf + 1,
  396.                      m_Reader->m_OutBuf + 1);
  397.             } else {
  398.                 // Update the read pointer
  399.                 gbump(block_size);
  400.             }
  401.         }
  402.         // Process block if necessary
  403.         if ( done == count  ||  !ProcessStreamRead() ) {
  404.             break;
  405.         }
  406.     }
  407.     return done;
  408. }
  409. END_NCBI_SCOPE
  410. /*
  411.  * ===========================================================================
  412.  * $Log: streambuf.cpp,v $
  413.  * Revision 1000.3  2004/06/03 17:11:36  gouriano
  414.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  415.  *
  416.  * Revision 1.12  2004/06/02 16:15:46  ivanov
  417.  * Fixed updating get pointers in the xsgetn()
  418.  *
  419.  * Revision 1.11  2004/05/17 21:07:25  gorelenk
  420.  * Added include of PCH ncbi_pch.hpp
  421.  *
  422.  * Revision 1.10  2004/05/10 11:56:08  ivanov
  423.  * Added gzip file format support
  424.  *
  425.  * Revision 1.9  2004/01/20 20:37:35  lavr
  426.  * Fix "Okay" spelling
  427.  *
  428.  * Revision 1.8  2003/09/25 17:51:08  dicuccio
  429.  * Reordered headers to avoid compilation warning on MSVC
  430.  *
  431.  * Revision 1.7  2003/07/15 15:52:50  ivanov
  432.  * Added correct handling end of stream state.
  433.  *
  434.  * Revision 1.6  2003/06/17 15:47:31  ivanov
  435.  * The second Compression API redesign. Rewritten CCompressionStreambuf to use
  436.  * I/O stream processors of class CCompressionStreamProcessor.
  437.  *
  438.  * Revision 1.5  2003/06/04 21:11:11  ivanov
  439.  * Get rid of non-initialized variables in the ProcessStream[Read|Write]
  440.  *
  441.  * Revision 1.4  2003/06/03 20:09:16  ivanov
  442.  * The Compression API redesign. Added some new classes, rewritten old.
  443.  *
  444.  * Revision 1.3  2003/04/15 16:51:12  ivanov
  445.  * Fixed error with flushing the streambuf after it finalizaton
  446.  *
  447.  * Revision 1.2  2003/04/11 19:55:28  ivanov
  448.  * Move streambuf.hpp from 'include/...' to 'src/...'
  449.  *
  450.  * Revision 1.1  2003/04/07 20:21:35  ivanov
  451.  * Initial revision
  452.  *
  453.  * ===========================================================================
  454.  */