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

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