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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: zlib.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/03 17:11:39  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.14
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: zlib.cpp,v 1000.3 2004/06/03 17:11:39 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.  *           Jean-loup Gailly, Mark Adler
  36.  *           (used a part of zlib library code from files gzio.c, uncompr.c)
  37.  *
  38.  * File Description:  ZLib Compression API
  39.  *
  40.  * NOTE: The zlib documentation can be found here: 
  41.  *           http://zlib.org,  
  42.  *           http://www.gzip.org/zlib/manual.html
  43.  */
  44. #include <ncbi_pch.hpp>
  45. #include <util/compress/zlib.hpp>
  46. #include <stdio.h>
  47. // Identify as Unix by default.
  48. #ifndef OS_CODE
  49. #define OS_CODE 0x03
  50. #endif
  51. BEGIN_NCBI_SCOPE
  52. // Macro to check bits
  53. #define F_ISSET(mask) ((GetFlags() & (mask)) == (mask))
  54. // Maximum size of memory buffer for data caching.
  55. const unsigned long kMaxCacheSize = 1024;
  56. //////////////////////////////////////////////////////////////////////////////
  57. //
  58. // CZipCompression
  59. //
  60. CZipCompression::CZipCompression(ELevel level,  int window_bits,
  61.                                  int mem_level, int strategy)
  62.     : CCompression(level), m_WindowBits(window_bits), m_MemLevel(mem_level),
  63.       m_Strategy(strategy)
  64. {
  65.     // Initialize the compressor stream structure
  66.     memset(&m_Stream, 0, sizeof(m_Stream));
  67.     return;
  68. }
  69. CZipCompression::~CZipCompression()
  70. {
  71.     return;
  72. }
  73. // gzip magic header
  74. const int gz_magic[2] = {0x1f, 0x8b};
  75. // gzip flag byte
  76. #define ASCII_FLAG   0x01 // bit 0 set: file probably ascii text
  77. #define HEAD_CRC     0x02 // bit 1 set: header CRC present
  78. #define EXTRA_FIELD  0x04 // bit 2 set: extra field present
  79. #define ORIG_NAME    0x08 // bit 3 set: original file name present
  80. #define COMMENT      0x10 // bit 4 set: file comment present
  81. #define RESERVED     0xE0 // bits 5..7: reserved/
  82. // Returns length of the .gz header if it exist or 0 otherwise.
  83. static
  84. unsigned int s_CheckGZipHeader(const void* src_buf, unsigned int src_len)
  85. {
  86.     unsigned char* buf = (unsigned char*)src_buf;
  87.     // .gz header cannot be less than 10 bytes
  88.     if (src_len < 10) {
  89.         return 0;
  90.     }
  91.     // Check the gzip magic header
  92.     if (buf[0] != gz_magic[0]  ||
  93.         buf[1] != gz_magic[1]) {
  94.         return 0;
  95.     }
  96.     int method = buf[2];
  97.     int flags  = buf[3];
  98.     if (method != Z_DEFLATED  ||  (flags & RESERVED) != 0) {
  99.         return 0;
  100.     }
  101.     // Header length: 
  102.     // gz_magic (2) + methos (1) + flags (1) + time, xflags and OS code (6)
  103.     unsigned int header_len = 10; 
  104.     // Skip the extra fields
  105.     if ((flags & EXTRA_FIELD) != 0) {
  106.         if (header_len + 2 > src_len) {
  107.             return 0;
  108.         }
  109.         unsigned int len = buf[header_len++];
  110.         len += ((unsigned int)buf[header_len++])<<8;
  111.         header_len += len;
  112.     }
  113.     // Skip the original file name
  114.     if ((flags & ORIG_NAME) != 0) {
  115.         while (header_len < src_len  &&  buf[header_len++] != 0);
  116.     }
  117.     // Skip the file comment
  118.     if ((flags & COMMENT) != 0) {
  119.         while (header_len < src_len  &&  buf[header_len++] != 0);
  120.     }
  121.     // Skip the header CRC
  122.     if ((flags & HEAD_CRC) != 0) {
  123.         header_len += 2;
  124.     }
  125.     if (header_len > src_len) {
  126.         return 0;
  127.     }
  128.     return header_len;
  129. }
  130. static size_t s_WriteGZipHeader(void* buf, unsigned int  buf_size)
  131. {
  132.     // .gz header cannot be less than 10 bytes
  133.     if (buf_size < 10) {
  134.         return 0;
  135.     }
  136.     sprintf((char*)buf, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
  137.             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
  138.     return 10;
  139. }
  140. static void s_StoreLong(unsigned char* buf, unsigned long value)
  141. {
  142.     for (int i = 0; i < 4; i++) {
  143.         buf[i] = (unsigned char)(value & 0xff);
  144.         value >>= 8;
  145.     }
  146. }
  147. static size_t s_WriteGZipFooter(void*         buf,
  148.                                 unsigned int  buf_size,
  149.                                 unsigned long total,
  150.                                 unsigned long crc)
  151. {
  152.     // .gz footer is 8 bytes length
  153.     if (buf_size < 8) {
  154.         return 0;
  155.     }
  156.     s_StoreLong((unsigned char*)buf, crc);
  157.     s_StoreLong((unsigned char*)buf+4, total);
  158.     return 8;
  159. }
  160. bool CZipCompression::CompressBuffer(
  161.                       const void* src_buf, unsigned int  src_len,
  162.                       void*       dst_buf, unsigned int  dst_size,
  163.                       /* out */            unsigned int* dst_len)
  164. {
  165.     // Check parameters
  166.     if ( !src_buf || !src_len ) {
  167.         *dst_len = 0;
  168.         SetError(Z_OK);
  169.         return true;
  170.     }
  171.     if ( !dst_buf || !dst_len ) {
  172.         SetError(Z_STREAM_ERROR, "bad argument");
  173.         ERR_POST(FormatErrorMessage("CZipCompression::CompressBuffer"));
  174.         return false;
  175.     }
  176.     unsigned long header_len = 0;
  177.     int           errcode    = Z_OK;
  178.     z_stream      stream;
  179.     
  180.     // Write gzip file header
  181.     if ( F_ISSET(fWriteGZipFormat) ) {
  182.         header_len = s_WriteGZipHeader(dst_buf, dst_size);
  183.         if (!header_len) {
  184.             ERR_POST(
  185.                 "CZipCompression::CompressBuffer:  Cannot write gzip header");
  186.             return false;
  187.         }
  188.     }
  189.     stream.next_in  = (unsigned char*)src_buf;
  190.     stream.avail_in = src_len;
  191. #ifdef MAXSEG_64K
  192.     // Check for source > 64K on 16-bit machine:
  193.     if ( stream.avail_in != src_len ) {
  194.         SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR));
  195.         ERR_POST(FormatErrorMessage("CZipCompression::CompressBuffer"));
  196.         return false;
  197.     }
  198. #endif
  199.     stream.next_out = (unsigned char*)dst_buf + header_len;
  200.     stream.avail_out = dst_size - header_len;
  201.     if ( stream.avail_out != dst_size - header_len ) {
  202.         SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR));
  203.         ERR_POST(FormatErrorMessage("CZipCompression::CompressBuffer"));
  204.         return false;
  205.     }
  206.     stream.zalloc = (alloc_func)0;
  207.     stream.zfree  = (free_func)0;
  208.     stream.opaque = (voidpf)0;
  209.     errcode = deflateInit2(&stream, GetLevel(), Z_DEFLATED,
  210.                            header_len ? -MAX_WBITS : MAX_WBITS,
  211.                            DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
  212.     if (errcode == Z_OK) {
  213.         errcode = deflate(&stream, Z_FINISH);
  214.         *dst_len = stream.total_out + header_len;
  215.         if (errcode == Z_STREAM_END) {
  216.             errcode = deflateEnd(&stream);
  217.         } else {
  218.             if ( errcode == Z_OK ) {
  219.                 errcode = Z_BUF_ERROR;
  220.             }
  221.             deflateEnd(&stream);
  222.         }
  223.     }
  224.     SetError(errcode, zError(errcode));
  225.     if ( errcode != Z_OK ) {
  226.         ERR_POST(FormatErrorMessage("CZipCompression::CompressBuffer"));
  227.         return false;
  228.     }
  229.     // Write gzip file footer
  230.     if ( F_ISSET(fWriteGZipFormat) ) {
  231.         unsigned long crc = crc32(0L, (unsigned char*)src_buf, src_len);
  232.         unsigned int footer_len = s_WriteGZipFooter(
  233.             (char*)dst_buf + *dst_len, dst_size, src_len, crc);
  234.         if (!footer_len) {
  235.             ERR_POST(
  236.                 "CZipCompression::CompressBuffer:  Cannot write gzip footer");
  237.             return false;
  238.         }
  239.         *dst_len += footer_len;
  240.     }
  241.     return true;
  242. }
  243. bool CZipCompression::DecompressBuffer(
  244.                       const void* src_buf, unsigned int  src_len,
  245.                       void*       dst_buf, unsigned int  dst_size,
  246.                       /* out */            unsigned int* dst_len)
  247. {
  248.     // Check parameters
  249.     if ( !src_buf || !src_len ) {
  250.         *dst_len = 0;
  251.         SetError(Z_OK);
  252.         return true;
  253.     }
  254.     if ( !dst_buf || !dst_len ) {
  255.         SetError(Z_STREAM_ERROR, "bad argument");
  256.         ERR_POST(FormatErrorMessage("CZipCompression::DecompressBuffer"));
  257.         return false;
  258.     }
  259.     unsigned long header_len = 0;
  260.     int           errcode    = Z_OK;
  261.     z_stream      stream;
  262.     
  263.     // Check file header
  264.     if ( F_ISSET(fCheckFileHeader) ) {
  265.         // Check gzip header in the buffer
  266.         header_len = s_CheckGZipHeader(src_buf, src_len);
  267.     }
  268.     stream.next_in  = (unsigned char*)src_buf + header_len;
  269.     stream.avail_in = src_len - header_len;
  270.     // Check for source > 64K on 16-bit machine:
  271.     if ( stream.avail_in != src_len - header_len ) {
  272.         SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR));
  273.         ERR_POST(FormatErrorMessage("CZipCompression::DecompressBuffer"));
  274.         return false;
  275.     }
  276.     stream.next_out = (unsigned char*)dst_buf;
  277.     stream.avail_out = dst_size;
  278.     if ( stream.avail_out != dst_size ) {
  279.         SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR));
  280.         ERR_POST(FormatErrorMessage("CZipCompression::DecompressBuffer"));
  281.         return false;
  282.     }
  283.     stream.zalloc = (alloc_func)0;
  284.     stream.zfree  = (free_func)0;
  285.     // "window bits" is passed < 0 to tell that there is no zlib header.
  286.     // Note that in this case inflate *requires* an extra "dummy" byte
  287.     // after the compressed stream in order to complete decompression and
  288.     // return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
  289.     // present after the compressed stream.
  290.         
  291.     errcode = inflateInit2(&stream, header_len ? -MAX_WBITS : MAX_WBITS);
  292.     if (errcode == Z_OK) {
  293.         errcode = inflate(&stream, Z_FINISH);
  294.         *dst_len = stream.total_out;
  295.         if (errcode == Z_STREAM_END) {
  296.             errcode = inflateEnd(&stream);
  297.         } else {
  298.             if ( errcode == Z_OK ) {
  299.                 errcode = Z_BUF_ERROR;
  300.             }
  301.             inflateEnd(&stream);
  302.         }
  303.     }
  304.     SetError(errcode, zError(errcode));
  305.     if ( errcode != Z_OK ) {
  306.         ERR_POST(FormatErrorMessage("CZipCompression::DecompressBuffer"));
  307.         return false;
  308.     }
  309.     return true;
  310. }
  311. bool CZipCompression::CompressFile(const string& src_file,
  312.                                    const string& dst_file,
  313.                                    size_t        buf_size)
  314. {
  315.     CZipCompressionFile cf(dst_file,
  316.                            CCompressionFile::eMode_Write, GetLevel(),
  317.                            m_WindowBits, m_MemLevel, m_Strategy);
  318.     if ( CCompression::x_CompressFile(src_file, cf, buf_size) ) {
  319.         return cf.Close();
  320.     }
  321.     // Save error info
  322.     int    errcode = cf.GetErrorCode();
  323.     string errmsg  = cf.GetErrorDescription();
  324.     // Close file
  325.     cf.Close();
  326.     // Restore previous error info
  327.     SetError(errcode, errmsg.c_str());
  328.     return false;
  329. }
  330. bool CZipCompression::DecompressFile(const string& src_file,
  331.                                      const string& dst_file,
  332.                                      size_t        buf_size)
  333. {
  334.     CZipCompressionFile cf(src_file,
  335.                            CCompressionFile::eMode_Read, GetLevel(),
  336.                            m_WindowBits, m_MemLevel, m_Strategy);
  337.     if ( CCompression::x_DecompressFile(cf, dst_file, buf_size) ) {
  338.         return cf.Close();
  339.     }
  340.     // Restore previous error info
  341.     int    errcode = cf.GetErrorCode();
  342.     string errmsg  = cf.GetErrorDescription();
  343.     // Restore previous error info
  344.     cf.Close();
  345.     // Restore previous error info
  346.     SetError(errcode, errmsg.c_str());
  347.     return false;
  348. }
  349. string CZipCompression::FormatErrorMessage(string where,
  350.                                            bool use_stream_data) const
  351. {
  352.     string str = "[" + where + "]  " + GetErrorDescription();
  353.     if ( use_stream_data ) {
  354.         str += ";  error code = " +
  355.                NStr::IntToString(GetErrorCode()) +
  356.                ", number of processed bytes = " +
  357.                NStr::UIntToString(m_Stream.total_in);
  358.     }
  359.     return str + ".";
  360. }
  361. //////////////////////////////////////////////////////////////////////////////
  362. //
  363. // CZipCompressionFile
  364. //
  365. CZipCompressionFile::CZipCompressionFile(
  366.     const string& file_name, EMode mode,
  367.     ELevel level, int window_bits, int mem_level, int strategy)
  368.     : CZipCompression(level, window_bits, mem_level, strategy)
  369. {
  370.     if ( !Open(file_name, mode) ) {
  371.         const string smode = (mode == eMode_Read) ? "reading" : "writing";
  372.         NCBI_THROW(CCompressionException, eCompressionFile, 
  373.                    "[CZipCompressionFile]  Cannot open file '" + file_name +
  374.                    "' for " + smode + ".");
  375.     }
  376.     return;
  377. }
  378. CZipCompressionFile::CZipCompressionFile(
  379.     ELevel level, int window_bits, int mem_level, int strategy)
  380.     : CZipCompression(level, window_bits, mem_level, strategy)
  381. {
  382.     return;
  383. }
  384. CZipCompressionFile::~CZipCompressionFile(void)
  385. {
  386.     Close();
  387.     return;
  388. }
  389. bool CZipCompressionFile::Open(const string& file_name, EMode mode)
  390. {
  391.     string open_mode;
  392.     // Form a string file mode using template" <r/w>b<level><strategy>"
  393.     if ( mode == eMode_Read ) {
  394.         open_mode = "rb";
  395.     } else {
  396.         open_mode = "wb";
  397.         // Add comression level
  398.         open_mode += NStr::IntToString((long)GetLevel());
  399.         // Add strategy 
  400.         switch (m_Strategy) {
  401.             case Z_FILTERED:
  402.                 open_mode += "f";
  403.                 break;
  404.             case Z_HUFFMAN_ONLY:
  405.                 open_mode += "h";
  406.             default:
  407.                 ; // Z_DEFAULT_STRATEGY
  408.         }
  409.     }
  410.     // Open file
  411.     m_File = gzopen(file_name.c_str(), open_mode.c_str()); 
  412.     m_Mode = mode;
  413.     if ( !m_File ) {
  414.         int err = errno;
  415.         Close();
  416.         if ( err == 0 ) {
  417.             SetError(Z_MEM_ERROR, zError(Z_MEM_ERROR));
  418.         } else {
  419.             SetError(Z_MEM_ERROR, strerror(errno));
  420.         }
  421.         ERR_POST(FormatErrorMessage("CZipCompressionFile::Open", false));
  422.         return false;
  423.     }; 
  424.     SetError(Z_OK);
  425.     return true;
  426. int CZipCompressionFile::Read(void* buf, int len)
  427. {
  428.     int nread = gzread(m_File, buf, len);
  429.     if ( nread == -1 ) {
  430.         int err_code;
  431.         const char* err_msg = gzerror(m_File, &err_code);
  432.         SetError(err_code, err_msg);
  433.         ERR_POST(FormatErrorMessage("CZipCompressionFile::Read", false));
  434.         return -1;
  435.     }
  436.     SetError(Z_OK);
  437.     return nread;
  438. }
  439. int CZipCompressionFile::Write(const void* buf, int len)
  440. {
  441.     // Redefine standart behaviour for case of writing zero bytes
  442.     if (len == 0) {
  443.         return true;
  444.     }
  445.     int nwrite = gzwrite(m_File, const_cast<void* const>(buf), len); 
  446.     if ( nwrite <= 0 ) {
  447.         int err_code;
  448.         const char* err_msg = gzerror(m_File, &err_code);
  449.         SetError(err_code, err_msg);
  450.         ERR_POST(FormatErrorMessage("CZipCompressionFile::Write", false));
  451.         return -1;
  452.     }
  453.     SetError(Z_OK);
  454.     return nwrite;
  455.  
  456. }
  457. bool CZipCompressionFile::Close(void)
  458. {
  459.     if ( m_File ) {
  460.         int errcode = gzclose(m_File); 
  461.         m_File = 0;
  462.         if ( errcode != Z_OK) {
  463.             int err_code;
  464.             const char* err_msg = gzerror(m_File, &err_code);
  465.             SetError(errcode, err_msg);
  466.             ERR_POST(FormatErrorMessage("CZipCompressionFile::Close", false));
  467.             return false;
  468.         }
  469.     }
  470.     SetError(Z_OK);
  471.     return true;
  472. }
  473. //////////////////////////////////////////////////////////////////////////////
  474. //
  475. // CZipCompressor
  476. //
  477. CZipCompressor::CZipCompressor(ELevel level,  int window_bits,
  478.                                int mem_level, int strategy, TFlags flags)
  479.     : CZipCompression(level, window_bits, mem_level, strategy),
  480.       m_CRC32(0), m_NeedWriteHeader(true)
  481. {
  482.     SetFlags(flags);
  483. }
  484. CZipCompressor::~CZipCompressor()
  485. {
  486. }
  487. CCompressionProcessor::EStatus CZipCompressor::Init(void)
  488. {
  489.     // Initialize members
  490.     Reset();
  491.     SetBusy();
  492.     m_CRC32 = 0;
  493.     m_NeedWriteHeader = true;
  494.     m_Cache.erase();
  495.     m_Cache.reserve(kMaxCacheSize);
  496.     // Initialize the compressor stream structure
  497.     memset(&m_Stream, 0, sizeof(m_Stream));
  498.     // Create a compressor stream
  499.     int errcode = deflateInit2(&m_Stream, GetLevel(), Z_DEFLATED,
  500.                                F_ISSET(fWriteGZipFormat) ? -m_WindowBits :
  501.                                                             m_WindowBits,
  502.                                m_MemLevel, m_Strategy); 
  503.     SetError(errcode, zError(errcode));
  504.     if ( errcode == Z_OK ) {
  505.         return eStatus_Success;
  506.     }
  507.     ERR_POST(FormatErrorMessage("CZipCompressor::Init"));
  508.     return eStatus_Error;
  509. }
  510. CCompressionProcessor::EStatus CZipCompressor::Process(
  511.                       const char* in_buf,  unsigned long  in_len,
  512.                       char*       out_buf, unsigned long  out_size,
  513.                       /* out */            unsigned long* in_avail,
  514.                       /* out */            unsigned long* out_avail)
  515. {
  516.     unsigned long header_len = 0;
  517.     // Write gzip file header
  518.     if ( F_ISSET(fWriteGZipFormat)  &&  m_NeedWriteHeader ) {
  519.         header_len = s_WriteGZipHeader(out_buf, out_size);
  520.         if (!header_len) {
  521.             ERR_POST("CZipCompressor::Process:  Cannot write gzip header");
  522.             return eStatus_Error;
  523.         }
  524.         m_NeedWriteHeader = false;
  525.     }
  526.     m_Stream.next_in   = (unsigned char*)const_cast<char*>(in_buf);
  527.     m_Stream.avail_in  = in_len;
  528.     m_Stream.next_out  = (unsigned char*)out_buf + header_len;
  529.     m_Stream.avail_out = out_size - header_len;
  530.     int errcode = deflate(&m_Stream, Z_NO_FLUSH);
  531.     SetError(errcode, zError(errcode));
  532.     *in_avail  = m_Stream.avail_in;
  533.     *out_avail = out_size - m_Stream.avail_out;
  534.     IncreaseProcessedSize(in_len - *in_avail);
  535.     IncreaseOutputSize(*out_avail);
  536.     // If we writing in gzip file format
  537.     if ( F_ISSET(fWriteGZipFormat) ) {
  538.         // Update the CRC32 for processed data
  539.         m_CRC32 = crc32(m_CRC32, (unsigned char*)in_buf, in_len - *in_avail);
  540.     }
  541.     if ( errcode == Z_OK ) {
  542.         return eStatus_Success;
  543.     }
  544.     ERR_POST(FormatErrorMessage("CZipCompressor::Process"));
  545.     return eStatus_Error;
  546. }
  547. CCompressionProcessor::EStatus CZipCompressor::Flush(
  548.                       char* out_buf, unsigned long  out_size,
  549.                       /* out */      unsigned long* out_avail)
  550. {
  551.     if ( !out_size ) {
  552.         return eStatus_Overflow;
  553.     }
  554.     m_Stream.next_in   = 0;
  555.     m_Stream.avail_in  = 0;
  556.     m_Stream.next_out  = (unsigned char*)out_buf;
  557.     m_Stream.avail_out = out_size;
  558.     int errcode = deflate(&m_Stream, Z_SYNC_FLUSH);
  559.     SetError(errcode, zError(errcode));
  560.     *out_avail = out_size - m_Stream.avail_out;
  561.     IncreaseOutputSize(*out_avail);
  562.     if ( errcode == Z_OK  ||  errcode == Z_BUF_ERROR ) {
  563.         if ( m_Stream.avail_out == 0) {
  564.             return eStatus_Overflow;
  565.         }
  566.         return eStatus_Success;
  567.     }
  568.     ERR_POST(FormatErrorMessage("CZipCompressor::Flush"));
  569.     return eStatus_Error;
  570. }
  571. CCompressionProcessor::EStatus CZipCompressor::Finish(
  572.                       char* out_buf, unsigned long  out_size,
  573.                       /* out */      unsigned long* out_avail)
  574. {
  575.     if ( !out_size ) {
  576.         return eStatus_Overflow;
  577.     }
  578.     m_Stream.next_in   = 0;
  579.     m_Stream.avail_in  = 0;
  580.     m_Stream.next_out  = (unsigned char*)out_buf;
  581.     m_Stream.avail_out = out_size;
  582.     int errcode = deflate(&m_Stream, Z_FINISH);
  583.     SetError(errcode, zError(errcode));
  584.     *out_avail = out_size - m_Stream.avail_out;
  585.     IncreaseOutputSize(*out_avail);
  586.     switch (errcode) {
  587.     case Z_OK:
  588.         return eStatus_Overflow;
  589.     case Z_STREAM_END:
  590.         // Write .gz file footer
  591.         if ( F_ISSET(fWriteGZipFormat) ) {
  592.             unsigned int footer_len = 
  593.                 s_WriteGZipFooter(out_buf + *out_avail, m_Stream.avail_out,
  594.                                   GetProcessedSize(), m_CRC32);
  595.             if ( !footer_len ) {
  596.                 ERR_POST("CZipCompressor::Finish: Cannot write gzip footer");
  597.                 return eStatus_Overflow;
  598.             }
  599.             *out_avail += footer_len;
  600.         }
  601.         return eStatus_EndOfData;
  602.     }
  603.     ERR_POST(FormatErrorMessage("CZipCompressor::Finish"));
  604.     return eStatus_Error;
  605. }
  606. CCompressionProcessor::EStatus CZipCompressor::End(void)
  607. {
  608.     int errcode = deflateEnd(&m_Stream);
  609.     SetError(errcode, zError(errcode));
  610.     SetBusy(false);
  611.     if ( errcode == Z_OK ) {
  612.         return eStatus_Success;
  613.     }
  614.     ERR_POST(FormatErrorMessage("CZipCompressor::End"));
  615.     return eStatus_Error;
  616. }
  617. //////////////////////////////////////////////////////////////////////////////
  618. //
  619. // CZipDecompressor
  620. //
  621. CZipDecompressor::CZipDecompressor(int window_bits, TFlags flags)
  622.     : CZipCompression(eLevel_Default, window_bits, 0, 0),
  623.       m_NeedCheckHeader(true)
  624. {
  625.     SetFlags(flags);
  626. }
  627. CZipDecompressor::~CZipDecompressor()
  628. {
  629. }
  630. CCompressionProcessor::EStatus CZipDecompressor::Init(void)
  631. {
  632.     // Initialize members
  633.     Reset();
  634.     SetBusy();
  635.     m_NeedCheckHeader = true;
  636.     m_Cache.erase();
  637.     m_Cache.reserve(kMaxCacheSize);
  638.     // Initialize the compressor stream structure
  639.     memset(&m_Stream, 0, sizeof(m_Stream));
  640.     // Create a compressor stream
  641.     int errcode = inflateInit2(&m_Stream, m_WindowBits);
  642.     SetError(errcode, zError(errcode));
  643.     if ( errcode == Z_OK ) {
  644.         return eStatus_Success;
  645.     }
  646.     ERR_POST(FormatErrorMessage("CZipDecompressor::Init"));
  647.     return eStatus_Error;
  648. }
  649. CCompressionProcessor::EStatus CZipDecompressor::Process(
  650.                       const char* in_buf,  unsigned long  in_len,
  651.                       char*       out_buf, unsigned long  out_size,
  652.                       /* out */            unsigned long* in_avail,
  653.                       /* out */            unsigned long* out_avail)
  654. {
  655.     if ( !out_size ) {
  656.         return eStatus_Overflow;
  657.     }
  658.     m_Stream.next_in   = (unsigned char*)const_cast<char*>(in_buf);
  659.     m_Stream.avail_in  = in_len;
  660.     m_Stream.next_out  = (unsigned char*)out_buf;
  661.     m_Stream.avail_out = out_size;
  662.     bool          from_cache   = false;
  663.     unsigned long avail_adj    = in_len;
  664.     unsigned long old_avail_in = 0;
  665.     // Check file header
  666.     if ( F_ISSET(fCheckFileHeader) ) {
  667.         unsigned int header_len = 0;
  668.         if ( m_NeedCheckHeader ) {
  669.             if (in_buf  &&  m_Cache.size() < kMaxCacheSize) {
  670.                 unsigned long n = min(kMaxCacheSize - m_Cache.size(), in_len);
  671.                 m_Cache.append(in_buf, n);
  672.                 avail_adj -= n;
  673.                 if (m_Cache.size() < kMaxCacheSize) {
  674.                     // Data block is very small and was cached.
  675.                     *in_avail  = 0;
  676.                     *out_avail = 0;
  677.                     return eStatus_Success;
  678.                 }
  679.             }
  680.             // Check gzip header in the buffer
  681.             header_len = s_CheckGZipHeader(m_Cache.c_str(), m_Cache.size());
  682.             _ASSERT(header_len < kMaxCacheSize);
  683.             // If gzip header found, skip it
  684.             if ( header_len ) {
  685.                 m_Cache.erase(0, header_len);
  686.                 int errcode = inflateInit2(&m_Stream,
  687.                                            header_len ? -MAX_WBITS :
  688.                                                         m_WindowBits);
  689.                 SetError(errcode, zError(errcode));
  690.                 if ( errcode != Z_OK ) {
  691.                     return eStatus_Error;
  692.                 }
  693.             }
  694.             // Already skipped or we don't have header here
  695.             if (header_len  ||  in_buf) {
  696.                 m_NeedCheckHeader = false;
  697.             }
  698.         }
  699.         // Have some cached unprocessed data
  700.         if ( m_Cache.size() ) {
  701.             m_Stream.next_in   = (unsigned char*)(m_Cache.c_str());
  702.             m_Stream.avail_in  = m_Cache.size();
  703.             m_Stream.next_out  = (unsigned char*)out_buf;
  704.             m_Stream.avail_out = out_size;
  705.             from_cache         = true;
  706.             old_avail_in       = m_Stream.avail_in;
  707.         }
  708.     }
  709.     int errcode = inflate(&m_Stream, Z_SYNC_FLUSH);
  710.     SetError(errcode, zError(errcode));
  711.     if ( from_cache ) {
  712.         m_Cache.erase(0, old_avail_in - m_Stream.avail_in);
  713.         *in_avail = avail_adj;
  714.         IncreaseProcessedSize(old_avail_in - m_Stream.avail_in);
  715.     } else {
  716.         *in_avail = m_Stream.avail_in;
  717.         IncreaseProcessedSize(in_len - *in_avail);
  718.     }
  719.     *out_avail = out_size - m_Stream.avail_out;
  720.     IncreaseOutputSize(*out_avail);
  721.     switch (errcode) {
  722.     case Z_OK:
  723.         return eStatus_Success;
  724.     case Z_STREAM_END:
  725.         return eStatus_EndOfData;
  726.     }
  727.     ERR_POST(FormatErrorMessage("CZipDecompressor::Process"));
  728.     return eStatus_Error;
  729. }
  730. CCompressionProcessor::EStatus CZipDecompressor::Flush(
  731.                       char*          out_buf,
  732.                       unsigned long  out_size,
  733.                       unsigned long* out_avail)
  734. {
  735.     // Process cached data
  736.     if (F_ISSET(fCheckFileHeader)  &&  m_Cache.size()) {
  737.         unsigned long in_avail;
  738.         return Process(0, 0, out_buf, out_size, &in_avail, out_avail);
  739.     }
  740.     return eStatus_Success;
  741. }
  742. CCompressionProcessor::EStatus CZipDecompressor::Finish(
  743.                       char*          out_buf,
  744.                       unsigned long  out_size,
  745.                       unsigned long* out_avail)
  746. {
  747.     // Process cached data
  748.     if (F_ISSET(fCheckFileHeader)  &&  m_Cache.size()) {
  749.         unsigned long in_avail;
  750.         return Process(0, 0, out_buf, out_size, &in_avail, out_avail);
  751.     }
  752.     return eStatus_Success;
  753. }
  754. CCompressionProcessor::EStatus CZipDecompressor::End(void)
  755. {
  756.     int errcode = inflateEnd(&m_Stream);
  757.     SetBusy(false);
  758.     if ( errcode == Z_OK ) {
  759.         return eStatus_Success;
  760.     }
  761.     ERR_POST(FormatErrorMessage("CZipDecompressor::End"));
  762.     return eStatus_Error;
  763. }
  764. END_NCBI_SCOPE
  765. /*
  766.  * ===========================================================================
  767.  * $Log: zlib.cpp,v $
  768.  * Revision 1000.3  2004/06/03 17:11:39  gouriano
  769.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.14
  770.  *
  771.  * Revision 1.14  2004/06/02 16:14:12  ivanov
  772.  * Fixed processed bytes counting in the CZipDecompressor::Process()
  773.  *
  774.  * Revision 1.13  2004/05/17 21:07:25  gorelenk
  775.  * Added include of PCH ncbi_pch.hpp
  776.  *
  777.  * Revision 1.12  2004/05/10 19:25:09  ucko
  778.  * +<stdio.h> for sprintf()
  779.  *
  780.  * Revision 1.11  2004/05/10 13:06:45  ucko
  781.  * Default OS_CODE to the Unix value (0x03).
  782.  *
  783.  * Revision 1.10  2004/05/10 12:57:03  ivanov
  784.  * Removed #include <zutil.h>
  785.  *
  786.  * Revision 1.9  2004/05/10 11:56:08  ivanov
  787.  * Added gzip file format support
  788.  *
  789.  * Revision 1.8  2004/04/19 14:17:15  ivanov
  790.  * Added gzip file format support into stream decompressor
  791.  *
  792.  * Revision 1.7  2004/04/01 14:14:03  lavr
  793.  * Spell "occurred", "occurrence", and "occurring"
  794.  *
  795.  * Revision 1.6  2003/07/15 15:46:31  ivanov
  796.  * Improved error diagnostics. Save status codes and it's description after
  797.  * each compression operation, and ERR_POST it if error occurred.
  798.  *
  799.  * Revision 1.5  2003/07/10 16:30:30  ivanov
  800.  * Implemented CompressFile/DecompressFile functions.
  801.  * Added ability to skip a gzip file headers into DecompressBuffer().
  802.  *
  803.  * Revision 1.4  2003/06/17 15:43:58  ivanov
  804.  * Minor cosmetics and comments changes
  805.  *
  806.  * Revision 1.3  2003/06/03 20:09:16  ivanov
  807.  * The Compression API redesign. Added some new classes, rewritten old.
  808.  *
  809.  * Revision 1.2  2003/04/15 16:49:33  ivanov
  810.  * Added processing zlib return code Z_BUF_ERROR to DeflateFlush()
  811.  *
  812.  * Revision 1.1  2003/04/07 20:21:35  ivanov
  813.  * Initial revision
  814.  *
  815.  * ===========================================================================
  816.  */