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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: bzip2.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 19:40:54  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: bzip2.cpp,v 1000.2 2004/06/01 19:40:54 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:  BZip2 Compression API
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <util/compress/bzip2.hpp>
  41. BEGIN_NCBI_SCOPE
  42. //////////////////////////////////////////////////////////////////////////////
  43. //
  44. // CBZip2Compression
  45. //
  46. CBZip2Compression::CBZip2Compression(ELevel level, int verbosity,
  47.                                      int work_factor, int small_decompress)
  48.     : CCompression(level), m_Verbosity(verbosity), m_WorkFactor(work_factor),
  49.       m_SmallDecompress(small_decompress)
  50. {
  51.     // Initialize the compressor stream structure
  52.     memset(&m_Stream, 0, sizeof(m_Stream));
  53.     return;
  54. }
  55. CBZip2Compression::~CBZip2Compression(void)
  56. {
  57.     return;
  58. }
  59. CCompression::ELevel CBZip2Compression::GetLevel(void) const
  60. {
  61.     CCompression::ELevel level = CCompression::GetLevel();
  62.     // BZip2 do not support a zero compression level -- make conversion 
  63.     if ( level == eLevel_NoCompression) {
  64.         return eLevel_Lowest;
  65.     }
  66.     return level;
  67. }
  68. bool CBZip2Compression::CompressBuffer(
  69.                         const void* src_buf, unsigned int  src_len,
  70.                         void*       dst_buf, unsigned int  dst_size,
  71.                         /* out */            unsigned int* dst_len)
  72. {
  73.     // Check parameters
  74.     if ( !src_buf || !src_len ) {
  75.         *dst_len = 0;
  76.         SetError(BZ_OK);
  77.         return true;
  78.     }
  79.     if ( !dst_buf || !dst_len ) {
  80.         SetError(BZ_PARAM_ERROR, "bad argument");
  81.         ERR_POST(FormatErrorMessage("CBZip2Compression::CompressBuffer"));
  82.         return false;
  83.     }
  84.     // Destination buffer size
  85.     *dst_len = dst_size;
  86.     // Compress buffer
  87.     int errcode = BZ2_bzBuffToBuffCompress((char*)dst_buf, dst_len,
  88.                                            (char*)src_buf, src_len,
  89.                                            GetLevel(), 0, 0 );
  90.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  91.     if ( errcode != BZ_OK) {
  92.         ERR_POST(FormatErrorMessage("CBZip2Compression::CompressBuffer"));
  93.         return false;
  94.     }
  95.     return true;
  96. }
  97. bool CBZip2Compression::DecompressBuffer(
  98.                         const void* src_buf, unsigned int  src_len,
  99.                         void*       dst_buf, unsigned int  dst_size,
  100.                         /* out */            unsigned int* dst_len)
  101. {
  102.     // Check parameters
  103.     if ( !src_buf || !src_len ) {
  104.         *dst_len = 0;
  105.         SetError(BZ_OK);
  106.         return true;
  107.     }
  108.     if ( !dst_buf || !dst_len ) {
  109.         SetError(BZ_PARAM_ERROR, "bad argument");
  110.         return false;
  111.     }
  112.     // Destination buffer size
  113.     *dst_len = dst_size;
  114.     // Decompress buffer
  115.     int errcode = BZ2_bzBuffToBuffDecompress((char*)dst_buf, dst_len,
  116.                                              (char*)src_buf, src_len, 0, 0 );
  117.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  118.     if ( errcode != BZ_OK ) {
  119.         ERR_POST(FormatErrorMessage("CBZip2Compression::DecompressBuffer"));
  120.         return false;
  121.     }
  122.     return true;
  123. }
  124. bool CBZip2Compression::CompressFile(const string& src_file,
  125.                                      const string& dst_file,
  126.                                      size_t        buf_size)
  127. {
  128.     CBZip2CompressionFile cf(dst_file,
  129.                              CCompressionFile::eMode_Write, GetLevel(),
  130.                              m_Verbosity, m_WorkFactor, m_SmallDecompress);
  131.     if ( CCompression::x_CompressFile(src_file, cf, buf_size) ) {
  132.         return cf.Close();
  133.     }
  134.     // Save error info
  135.     int    errcode = cf.GetErrorCode();
  136.     string errmsg  = cf.GetErrorDescription();
  137.     // Close file
  138.     cf.Close();
  139.     // Restore previous error info
  140.     SetError(errcode, errmsg.c_str());
  141.     return false;
  142. }
  143. bool CBZip2Compression::DecompressFile(const string& src_file,
  144.                                        const string& dst_file,
  145.                                        size_t        buf_size)
  146. {
  147.     CBZip2CompressionFile cf(src_file,
  148.                              CCompressionFile::eMode_Read, GetLevel(),
  149.                              m_Verbosity, m_WorkFactor, m_SmallDecompress);
  150.     if ( CCompression::x_DecompressFile(cf, dst_file, buf_size) ) {
  151.         return cf.Close();
  152.     }
  153.     // Save error info
  154.     int    errcode = cf.GetErrorCode();
  155.     string errmsg  = cf.GetErrorDescription();
  156.     // Close file
  157.     cf.Close();
  158.     // Restore previous error info
  159.     SetError(errcode, errmsg.c_str());
  160.     return false;
  161. }
  162. // Please, see a ftp://sources.redhat.com/pub/bzip2/docs/manual_3.html#SEC17
  163. // for detailed error descriptions.
  164. const char* CBZip2Compression::GetBZip2ErrorDescription(int errcode)
  165. {
  166.     const int kErrorCount = 9;
  167.     static const char* kErrorDesc[kErrorCount] = {
  168.         "SEQUENCE_ERROR",
  169.         "PARAM_ERROR",
  170.         "MEM_ERROR",
  171.         "DATA_ERROR",
  172.         "DATA_ERROR_MAGIC",
  173.         "IO_ERROR",
  174.         "UNEXPECTED_EOF",
  175.         "OUTBUFF_FULL",
  176.         "CONFIG_ERROR"
  177.     };
  178.     // errcode must be negative
  179.     if ( errcode >= 0  ||  errcode < -kErrorCount ) {
  180.         return 0;
  181.     }
  182.     return kErrorDesc[-errcode - 1];
  183. }
  184. string CBZip2Compression::FormatErrorMessage(string where,
  185.                                              bool   use_stream_data) const
  186. {
  187.     string str = "[" + where + "]  " + GetErrorDescription();
  188.     if ( use_stream_data ) {
  189.         str += ";  error code = " +
  190.             NStr::IntToString(GetErrorCode()) +
  191.             ", number of processed bytes = " +
  192.             NStr::UInt8ToString(((Uint8)m_Stream.total_in_hi32 << 32) +
  193.                                 (Uint8)m_Stream.total_in_lo32);
  194.     }
  195.     return str + ".";
  196. }
  197. //////////////////////////////////////////////////////////////////////////////
  198. //
  199. // CBZip2CompressionFile
  200. //
  201. CBZip2CompressionFile::CBZip2CompressionFile(
  202.     const string& file_name, EMode mode,
  203.     ELevel level, int verbosity, int work_factor, int small_decompress)
  204.     : CBZip2Compression(level, verbosity, work_factor, small_decompress), 
  205.       m_FileStream(0)
  206. {
  207.     if ( !Open(file_name, mode) ) {
  208.         const string smode = (mode == eMode_Read) ? "reading" : "writing";
  209.         NCBI_THROW(CCompressionException, eCompressionFile, 
  210.                    "[CBZip2CompressionFile]  Cannot open file '" + file_name +
  211.                    "' for " + smode + ".");
  212.     }
  213.     return;
  214. }
  215. CBZip2CompressionFile::CBZip2CompressionFile(
  216.     ELevel level, int verbosity, int work_factor, int small_decompress)
  217.     : CBZip2Compression(level, verbosity, work_factor, small_decompress), 
  218.       m_FileStream(0), m_EOF(true)
  219. {
  220.     return;
  221. }
  222. CBZip2CompressionFile::~CBZip2CompressionFile(void)
  223. {
  224.     Close();
  225.     return;
  226. }
  227. bool CBZip2CompressionFile::Open(const string& file_name, EMode mode)
  228. {
  229.     int errcode;
  230.    
  231.     if ( mode == eMode_Read ) {
  232.         m_FileStream = fopen(file_name.c_str(), "rb");
  233.         m_File = BZ2_bzReadOpen (&errcode, m_FileStream, m_SmallDecompress,
  234.                                  m_Verbosity, 0, 0);
  235.         m_EOF = false;
  236.     } else {
  237.         m_FileStream = fopen(file_name.c_str(), "wb");
  238.         m_File = BZ2_bzWriteOpen(&errcode, m_FileStream, GetLevel(),
  239.                                  m_Verbosity, m_WorkFactor);
  240.     }
  241.     m_Mode = mode;
  242.     if ( errcode != BZ_OK ) {
  243.         Close();
  244.         SetError(errcode, GetBZip2ErrorDescription(errcode));
  245.         ERR_POST(FormatErrorMessage("CBZip2CompressionFile::Open", false));
  246.         return false;
  247.     };
  248.     SetError(BZ_OK);
  249.     return true;
  250. int CBZip2CompressionFile::Read(void* buf, int len)
  251. {
  252.     if ( m_EOF ) {
  253.         return 0;
  254.     }
  255.     int errcode;
  256.     int nread = BZ2_bzRead(&errcode, m_File, buf, len);
  257.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  258.     if ( errcode != BZ_OK  &&  errcode != BZ_STREAM_END ) {
  259.         ERR_POST(FormatErrorMessage("CBZip2CompressionFile::Read", false));
  260.         return -1;
  261.     }; 
  262.     if ( errcode == BZ_STREAM_END ) {
  263.         m_EOF = true;
  264.     }; 
  265.     return nread;
  266. }
  267. int CBZip2CompressionFile::Write(const void* buf, int len)
  268. {
  269.     int errcode;
  270.     BZ2_bzWrite(&errcode, m_File, const_cast<void*>(buf), len);
  271.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  272.     if ( errcode != BZ_OK  &&  errcode != BZ_STREAM_END ) {
  273.         ERR_POST(FormatErrorMessage("CBZip2CompressionFile::Write", false));
  274.         return -1;
  275.     }; 
  276.     return len;
  277.  
  278. }
  279. bool CBZip2CompressionFile::Close(void)
  280. {
  281.     int errcode = BZ_OK;
  282.     if ( m_File ) {
  283.         if ( m_Mode == eMode_Read ) {
  284.             BZ2_bzReadClose(&errcode, m_File);
  285.             m_EOF = true;
  286.         } else {
  287.             BZ2_bzWriteClose(&errcode, m_File, 0, 0, 0);
  288.         }
  289.         m_File = 0;
  290.     }
  291.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  292.     if ( m_FileStream ) {
  293.         fclose(m_FileStream);
  294.         m_FileStream = 0;
  295.     }
  296.     if ( errcode != BZ_OK ) {
  297.         ERR_POST(FormatErrorMessage("CBZip2CompressionFile::Close", false));
  298.         return false;
  299.     }; 
  300.     return true;
  301. }
  302. //////////////////////////////////////////////////////////////////////////////
  303. //
  304. // CBZip2Compressor
  305. //
  306. CBZip2Compressor::CBZip2Compressor(
  307.                   ELevel level, int verbosity, int work_factor)
  308.     : CBZip2Compression(level, verbosity, work_factor, 0)
  309. {
  310. }
  311. CBZip2Compressor::~CBZip2Compressor()
  312. {
  313. }
  314. CCompressionProcessor::EStatus CBZip2Compressor::Init(void)
  315. {
  316.     // Initialize members
  317.     Reset();
  318.     SetBusy();
  319.     // Initialize the compressor stream structure
  320.     memset(&m_Stream, 0, sizeof(m_Stream));
  321.     // Create a compressor stream
  322.     int errcode = BZ2_bzCompressInit(&m_Stream, GetLevel(), m_Verbosity,
  323.                                      m_WorkFactor);
  324.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  325.     if ( errcode == BZ_OK ) {
  326.         return eStatus_Success;
  327.     }
  328.     ERR_POST(FormatErrorMessage("CBZip2Compressor::Init"));
  329.     return eStatus_Error;
  330. }
  331. CCompressionProcessor::EStatus CBZip2Compressor::Process(
  332.                       const char* in_buf,  unsigned long  in_len,
  333.                       char*       out_buf, unsigned long  out_size,
  334.                       /* out */            unsigned long* in_avail,
  335.                       /* out */            unsigned long* out_avail)
  336. {
  337.     m_Stream.next_in   = const_cast<char*>(in_buf);
  338.     m_Stream.avail_in  = in_len;
  339.     m_Stream.next_out  = out_buf;
  340.     m_Stream.avail_out = out_size;
  341.     int errcode = BZ2_bzCompress(&m_Stream, BZ_RUN);
  342.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  343.     *in_avail  = m_Stream.avail_in;
  344.     *out_avail = out_size - m_Stream.avail_out;
  345.     IncreaseProcessedSize(in_len - *in_avail);
  346.     IncreaseOutputSize(*out_avail);
  347.     if ( errcode == BZ_RUN_OK ) {
  348.         return eStatus_Success;
  349.     }
  350.     ERR_POST(FormatErrorMessage("CBZip2Compressor::Process"));
  351.     return eStatus_Error;
  352. }
  353. CCompressionProcessor::EStatus CBZip2Compressor::Flush(
  354.                       char* out_buf, unsigned long  out_size,
  355.                       /* out */      unsigned long* out_avail)
  356. {
  357.     if ( !out_size ) {
  358.         return eStatus_Overflow;
  359.     }
  360.     m_Stream.next_in   = 0;
  361.     m_Stream.avail_in  = 0;
  362.     m_Stream.next_out  = out_buf;
  363.     m_Stream.avail_out = out_size;
  364.     int errcode = BZ2_bzCompress(&m_Stream, BZ_FLUSH);
  365.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  366.     *out_avail = out_size - m_Stream.avail_out;
  367.     IncreaseOutputSize(*out_avail);
  368.     if ( errcode == BZ_RUN_OK ) {
  369.         return eStatus_Success;
  370.     } else 
  371.     if ( errcode == BZ_FLUSH_OK ) {
  372.         return eStatus_Overflow;
  373.     }
  374.     ERR_POST(FormatErrorMessage("CBZip2Compressor::Flush"));
  375.     return eStatus_Error;
  376. }
  377. CCompressionProcessor::EStatus CBZip2Compressor::Finish(
  378.                       char* out_buf, unsigned long  out_size,
  379.                       /* out */      unsigned long* out_avail)
  380. {
  381.     if ( !out_size ) {
  382.         return eStatus_Overflow;
  383.     }
  384.     m_Stream.next_in   = 0;
  385.     m_Stream.avail_in  = 0;
  386.     m_Stream.next_out  = out_buf;
  387.     m_Stream.avail_out = out_size;
  388.     int errcode = BZ2_bzCompress(&m_Stream, BZ_FINISH);
  389.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  390.     *out_avail = out_size - m_Stream.avail_out;
  391.     IncreaseOutputSize(*out_avail);
  392.     switch (errcode) {
  393.     case BZ_FINISH_OK:
  394.         return eStatus_Overflow;
  395.     case BZ_STREAM_END:
  396.         return eStatus_EndOfData;
  397.     }
  398.     ERR_POST(FormatErrorMessage("CBZip2Compressor::Finish"));
  399.     return eStatus_Error;
  400. }
  401. CCompressionProcessor::EStatus CBZip2Compressor::End(void)
  402. {
  403.     int errcode = BZ2_bzCompressEnd(&m_Stream);
  404.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  405.     SetBusy(false);
  406.     if ( errcode == BZ_OK ) {
  407.         return eStatus_Success;
  408.     }
  409.     ERR_POST(FormatErrorMessage("CBZip2Compressor::End"));
  410.     return eStatus_Error;
  411. }
  412. //////////////////////////////////////////////////////////////////////////////
  413. //
  414. // CBZip2Decompressor
  415. //
  416. CBZip2Decompressor::CBZip2Decompressor(int verbosity, int small_decompress)
  417.     : CBZip2Compression(eLevel_Default, verbosity, 0, small_decompress)
  418. {
  419. }
  420. CBZip2Decompressor::~CBZip2Decompressor()
  421. {
  422. }
  423. CCompressionProcessor::EStatus CBZip2Decompressor::Init(void)
  424. {
  425.     // Initialize members
  426.     Reset();
  427.     SetBusy();
  428.     // Initialize the decompressor stream structure
  429.     memset(&m_Stream, 0, sizeof(m_Stream));
  430.     // Create a compressor stream
  431.     int errcode = BZ2_bzDecompressInit(&m_Stream, m_Verbosity,
  432.                                        m_SmallDecompress);
  433.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  434.     if ( errcode == BZ_OK ) {
  435.         return eStatus_Success;
  436.     }
  437.     ERR_POST(FormatErrorMessage("CBZip2Decompressor::Init"));
  438.     return eStatus_Error;
  439. }
  440. CCompressionProcessor::EStatus CBZip2Decompressor::Process(
  441.                       const char* in_buf,  unsigned long  in_len,
  442.                       char*       out_buf, unsigned long  out_size,
  443.                       /* out */            unsigned long* in_avail,
  444.                       /* out */            unsigned long* out_avail)
  445. {
  446.     if ( !out_size ) {
  447.         return eStatus_Overflow;
  448.     }
  449.     m_Stream.next_in   = const_cast<char*>(in_buf);
  450.     m_Stream.avail_in  = in_len;
  451.     m_Stream.next_out  = out_buf;
  452.     m_Stream.avail_out = out_size;
  453.     int errcode = BZ2_bzDecompress(&m_Stream);
  454.     SetError(errcode, GetBZip2ErrorDescription(errcode));
  455.     *in_avail  = m_Stream.avail_in;
  456.     *out_avail = out_size - m_Stream.avail_out;
  457.     IncreaseProcessedSize(in_len - *in_avail);
  458.     IncreaseOutputSize(*out_avail);
  459.     switch (errcode) {
  460.     case BZ_OK:
  461.         return eStatus_Success;
  462.     case BZ_STREAM_END:
  463.         return eStatus_EndOfData;
  464.     }
  465.     ERR_POST(FormatErrorMessage("CBZip2Decompressor::Process"));
  466.     return eStatus_Error;
  467. }
  468. CCompressionProcessor::EStatus CBZip2Decompressor::Flush(
  469.                       char*, unsigned long, unsigned long*)
  470. {
  471.     return eStatus_Success;
  472. }
  473. CCompressionProcessor::EStatus CBZip2Decompressor::Finish(
  474.                       char*, unsigned long, unsigned long*)
  475. {
  476.     return eStatus_Success;
  477. }
  478. CCompressionProcessor::EStatus CBZip2Decompressor::End(void)
  479. {
  480.     int errcode = BZ2_bzDecompressEnd(&m_Stream);
  481.     SetBusy(false);
  482.     if ( errcode == BZ_OK ) {
  483.         return eStatus_Success;
  484.     }
  485.     ERR_POST(FormatErrorMessage("CBZip2Decompressor::End"));
  486.     return eStatus_Error;
  487. }
  488. END_NCBI_SCOPE
  489. /*
  490.  * ===========================================================================
  491.  * $Log: bzip2.cpp,v $
  492.  * Revision 1000.2  2004/06/01 19:40:54  gouriano
  493.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  494.  *
  495.  * Revision 1.9  2004/05/17 21:07:25  gorelenk
  496.  * Added include of PCH ncbi_pch.hpp
  497.  *
  498.  * Revision 1.8  2004/05/10 12:03:18  ivanov
  499.  * The real changes in R1.7 was:
  500.  *     Added calls to increase the number of processed/output bytes.
  501.  *
  502.  * Revision 1.7  2004/05/10 11:56:08  ivanov
  503.  * Added gzip file format support
  504.  *
  505.  * Revision 1.6  2004/04/01 14:14:03  lavr
  506.  * Spell "occurred", "occurrence", and "occurring"
  507.  *
  508.  * Revision 1.5  2003/07/15 15:46:31  ivanov
  509.  * Improved error diagnostics. Save status codes and it's description after
  510.  * each compression operation, and ERR_POST it if error occurred.
  511.  *
  512.  * Revision 1.4  2003/07/10 16:26:23  ivanov
  513.  * Implemented CompressFile/DecompressFile functions.
  514.  *
  515.  * Revision 1.3  2003/06/17 15:43:58  ivanov
  516.  * Minor cosmetics and comments changes
  517.  *
  518.  * Revision 1.2  2003/06/03 20:09:16  ivanov
  519.  * The Compression API redesign. Added some new classes, rewritten old.
  520.  *
  521.  * Revision 1.1  2003/04/07 20:21:35  ivanov
  522.  * Initial revision
  523.  *
  524.  * ===========================================================================
  525.  */