home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 5257 / source.7z / x_zlib.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2012-02-19  |  7.7 KB  |  256 lines

  1. #include "xentax.h"
  2. #include "x_zlib.h"
  3.  
  4. bool CompressZLIB(std::ifstream& ifile, std::ofstream& ofile)
  5. {
  6.  return CompressZLIB(ifile, ofile, 0);
  7. }
  8.  
  9. bool CompressZLIB(std::ifstream& ifile, std::ofstream& ofile, int level)
  10. {
  11. /*
  12.  // allocate deflate state
  13.  z_stream strm;
  14.  ZeroMemory(&strm, sizeof(strm));
  15.  strm.zalloc = Z_NULL;
  16.  strm.zfree = Z_NULL;
  17.  strm.opaque = Z_NULL;
  18.  int ret = deflateInit(&strm, level);
  19.  if(ret != Z_OK) return ret;
  20.  
  21.  int flush;
  22.  
  23.  const uint32 CHUNKSIZE = 16384;
  24.  unsigned char out[CHUNKSIZE];
  25.  
  26.  // compress until end of file
  27.  do
  28.  {
  29.      unsigned char in[CHUNKSIZE];
  30.      strm.avail_in = fread(in, 1, CHUNKSIZE, source);
  31.      if(ferror(source)) {
  32.         deflateEnd(&strm);
  33.         return Z_ERRNO;
  34.        }
  35.  
  36.      flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
  37.      strm.next_in = in;
  38.  
  39.      // run deflate() on input until output buffer not full, finish compression if all of source has been read in
  40.      do {
  41.  
  42.          strm.avail_out = CHUNKSIZE;
  43.          strm.next_out = out;
  44.          ret = deflate(&strm, flush);    // no bad return value
  45.          assert(ret != Z_STREAM_ERROR);  // state not clobbered
  46.          unsigned int have = CHUNKSIZE - strm.avail_out;
  47.          if(fwrite(out, 1, have, dest) != have || ferror(dest)) {
  48.             deflateEnd(&strm);
  49.             return Z_ERRNO;
  50.            }
  51.  
  52.      } while(strm.avail_out == 0);
  53.      assert(strm.avail_in == 0); // all input will be used
  54.  
  55.  } while(flush != Z_FINISH);  // done when last data in file processed
  56.  assert(ret == Z_STREAM_END); // stream will be complete
  57.  
  58.  // clean up and return
  59.  deflateEnd(&strm);
  60.  return Z_OK;
  61. */
  62.  
  63.  return true;
  64. }
  65.  
  66. bool DecompressZLIB(std::ifstream& ifile, std::ofstream& ofile)
  67. {
  68.  return DecompressZLIB(ifile, ofile, 0);
  69. }
  70.  
  71. bool DecompressZLIB(std::ifstream& ifile, std::ofstream& ofile, int windowBits)
  72. {
  73.  // validate
  74.  if(!ifile.is_open()) return error("std::ifstream not open.");
  75.  if(!ofile.is_open()) return error("std::ofstream not open.");
  76.  
  77.  // save current position
  78.  std::ifstream::pos_type position = ifile.tellg();
  79.  if(ifile.fail()) return error("Failed to retrieve std::ifstream position.");
  80.  
  81.  // allocate inflate buffers
  82.  const uint32 MAXCHUNKSIZE = 65536;
  83.  boost::shared_array<char> idata(new char[MAXCHUNKSIZE]);
  84.  boost::shared_array<char> odata(new char[MAXCHUNKSIZE]);
  85.  
  86.  // while we have consecutive streams
  87.  std::ifstream::pos_type bytes_read = 0;
  88.  for(;;)
  89.     {
  90.      // allocate inflate state
  91.      z_stream strm;
  92.      ZeroMemory(&strm, sizeof(strm));
  93.      int ret = inflateInit2(&strm, windowBits);
  94.      if(ret != Z_OK) return error("ZLIB initialization failed.");
  95.  
  96.      // inflate until stream ends or end of file
  97.      for(;;)
  98.         {
  99.          // get remaining filesize
  100.          ifile.seekg(0, std::ios::end);
  101.          std::ifstream::pos_type endpos = ifile.tellg();
  102.          std::ifstream::pos_type distance = endpos - position;
  103.          ifile.seekg(position);
  104.  
  105.          // end of file
  106.          if(!distance) {
  107.             inflateEnd(&strm);
  108.             return true;
  109.            }
  110.  
  111.          // read a chunk of data
  112.          uint32 CHUNKSIZE = ((uint32)distance < MAXCHUNKSIZE ? (uint32)distance : MAXCHUNKSIZE);
  113.          ifile.read(idata.get(), CHUNKSIZE);
  114.          if(ifile.fail()) {
  115.             inflateEnd(&strm);
  116.             return error("ZLIB read error.");
  117.            }
  118.  
  119.          // check if any data was read
  120.          strm.avail_in = (uInt)ifile.gcount();
  121.          if(strm.avail_in == 0) break;
  122.  
  123.          // set next input pointer (to buffer)
  124.          strm.next_in = reinterpret_cast<Bytef*>(idata.get());
  125.  
  126.          // run inflate() on input until output buffer not full
  127.          for(;;)
  128.             {
  129.              strm.avail_out = CHUNKSIZE;
  130.              strm.next_out = reinterpret_cast<Bytef*>(odata.get());
  131.  
  132.              // decompress data
  133.              ret = inflate(&strm, Z_NO_FLUSH);
  134.              if(ret == Z_NEED_DICT) {                
  135.                 inflateEnd(&strm);
  136.                 return error("ZLIB need dictionary error.");;
  137.                }
  138.              else if(ret == Z_DATA_ERROR) {
  139.                 uLong total_out = strm.total_out;
  140.                 inflateEnd(&strm);
  141.                 if(!bytes_read || total_out) return error("ZLIB data error."); // error
  142.                 else return true; // no more consecutive zlib streams to read
  143.                }
  144.              else if(ret == Z_MEM_ERROR) {
  145.                 ret = Z_DATA_ERROR;
  146.                 inflateEnd(&strm);
  147.                 return error("ZLIB memory error.");
  148.                }
  149.              else if(ret == Z_STREAM_ERROR) {
  150.                 ret = Z_DATA_ERROR;
  151.                 inflateEnd(&strm);
  152.                 return error("ZLIB stream error.");
  153.                }
  154.  
  155.              // save decompressed data
  156.              unsigned int have = CHUNKSIZE - strm.avail_out;
  157.              ofile.write(odata.get(), have);
  158.              if(ofile.fail()) {
  159.                 inflateEnd(&strm);
  160.                 return error("ZLIB error writing data.");
  161.                }
  162.              bytes_read += have;
  163.     
  164.              // stop when buffer is not full
  165.              if(strm.avail_out != 0) break;
  166.             }
  167.  
  168.          // done when inflate() says it's done
  169.          if(ret == Z_STREAM_END) break;
  170.         }
  171.  
  172.      // clean up and move to end of stream
  173.      position += strm.total_in;
  174.      inflateEnd(&strm);
  175.      ifile.seekg(position);
  176.      if(ifile.fail()) break;
  177.     }
  178.  
  179.  return true;
  180. }
  181.  
  182. bool DecompressZLIB(std::ifstream& ifile, size_t n, std::ofstream& ofile, int windowBits)
  183. {
  184.  // validate
  185.  if(n < 2) return error("Unexpected number of ZLIB bytes to read.");
  186.  if(!ifile.is_open()) return error("std::ifstream not open.");
  187.  if(!ofile.is_open()) return error("std::ofstream not open.");
  188.  
  189.  // save current position
  190.  std::ifstream::pos_type position = ifile.tellg();
  191.  if(ifile.fail()) return error("Failed to retrieve std::ifstream position.");
  192.  
  193.  // read data
  194.  boost::shared_array<char> idata(new char[n]);
  195.  ifile.read(idata.get(), n);
  196.  if(ifile.fail()) return error("Read failure.");
  197.  
  198.  // allocate inflate buffers
  199.  const uint32 CHUNKSIZE = 65536;
  200.  boost::shared_array<char> odata(new char[CHUNKSIZE]);
  201.  
  202.  // allocate inflate state
  203.  z_stream strm;
  204.  ZeroMemory(&strm, sizeof(strm));
  205.  int ret = inflateInit2(&strm, windowBits);
  206.  if(ret != Z_OK) return error("ZLIB initialization failed.");
  207.  
  208.  // initialize inflate state
  209.  strm.avail_in = n;
  210.  strm.next_in = reinterpret_cast<Bytef*>(idata.get());
  211.  
  212.  // run inflate() on input until output buffer not full
  213.  std::ifstream::pos_type bytes_read = 0;
  214.  for(;;)
  215.     {
  216.      // initialize inflate state
  217.      strm.avail_out = CHUNKSIZE;
  218.      strm.next_out = reinterpret_cast<Bytef*>(odata.get());
  219.  
  220.      // decompress data
  221.      ret = inflate(&strm, Z_NO_FLUSH);
  222.      if(ret == Z_NEED_DICT) {                
  223.         inflateEnd(&strm);
  224.         return error("ZLIB need dictionary error.");;
  225.        }
  226.      else if(ret == Z_DATA_ERROR) {
  227.         inflateEnd(&strm);
  228.         return error("ZLIB data error.");
  229.        }
  230.      else if(ret == Z_MEM_ERROR) {
  231.         ret = Z_DATA_ERROR;
  232.         inflateEnd(&strm);
  233.         return error("ZLIB memory error.");
  234.        }
  235.      else if(ret == Z_STREAM_ERROR) {
  236.         ret = Z_DATA_ERROR;
  237.         inflateEnd(&strm);
  238.         return error("ZLIB stream error.");
  239.        }
  240.  
  241.      // save decompressed data
  242.      unsigned int have = CHUNKSIZE - strm.avail_out;
  243.      ofile.write(odata.get(), have);
  244.      if(ofile.fail()) {
  245.         inflateEnd(&strm);
  246.         return error("ZLIB error writing data.");
  247.        }
  248.      bytes_read += have;
  249.     
  250.      // stop when buffer is not full
  251.      if(strm.avail_out != 0) break;
  252.     }
  253.  
  254.  // done when inflate() says it's done
  255.  return (ret == Z_STREAM_END);
  256. }