home *** CD-ROM | disk | FTP | other *** search
- #include "xentax.h"
- #include "x_zlib.h"
-
- bool CompressZLIB(std::ifstream& ifile, std::ofstream& ofile)
- {
- return CompressZLIB(ifile, ofile, 0);
- }
-
- bool CompressZLIB(std::ifstream& ifile, std::ofstream& ofile, int level)
- {
- /*
- // allocate deflate state
- z_stream strm;
- ZeroMemory(&strm, sizeof(strm));
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- int ret = deflateInit(&strm, level);
- if(ret != Z_OK) return ret;
-
- int flush;
-
- const uint32 CHUNKSIZE = 16384;
- unsigned char out[CHUNKSIZE];
-
- // compress until end of file
- do
- {
- unsigned char in[CHUNKSIZE];
- strm.avail_in = fread(in, 1, CHUNKSIZE, source);
- if(ferror(source)) {
- deflateEnd(&strm);
- return Z_ERRNO;
- }
-
- flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
- strm.next_in = in;
-
- // run deflate() on input until output buffer not full, finish compression if all of source has been read in
- do {
-
- strm.avail_out = CHUNKSIZE;
- strm.next_out = out;
- ret = deflate(&strm, flush); // no bad return value
- assert(ret != Z_STREAM_ERROR); // state not clobbered
- unsigned int have = CHUNKSIZE - strm.avail_out;
- if(fwrite(out, 1, have, dest) != have || ferror(dest)) {
- deflateEnd(&strm);
- return Z_ERRNO;
- }
-
- } while(strm.avail_out == 0);
- assert(strm.avail_in == 0); // all input will be used
-
- } while(flush != Z_FINISH); // done when last data in file processed
- assert(ret == Z_STREAM_END); // stream will be complete
-
- // clean up and return
- deflateEnd(&strm);
- return Z_OK;
- */
-
- return true;
- }
-
- bool DecompressZLIB(std::ifstream& ifile, std::ofstream& ofile)
- {
- return DecompressZLIB(ifile, ofile, 0);
- }
-
- bool DecompressZLIB(std::ifstream& ifile, std::ofstream& ofile, int windowBits)
- {
- // validate
- if(!ifile.is_open()) return error("std::ifstream not open.");
- if(!ofile.is_open()) return error("std::ofstream not open.");
-
- // save current position
- std::ifstream::pos_type position = ifile.tellg();
- if(ifile.fail()) return error("Failed to retrieve std::ifstream position.");
-
- // allocate inflate buffers
- const uint32 MAXCHUNKSIZE = 65536;
- boost::shared_array<char> idata(new char[MAXCHUNKSIZE]);
- boost::shared_array<char> odata(new char[MAXCHUNKSIZE]);
-
- // while we have consecutive streams
- std::ifstream::pos_type bytes_read = 0;
- for(;;)
- {
- // allocate inflate state
- z_stream strm;
- ZeroMemory(&strm, sizeof(strm));
- int ret = inflateInit2(&strm, windowBits);
- if(ret != Z_OK) return error("ZLIB initialization failed.");
-
- // inflate until stream ends or end of file
- for(;;)
- {
- // get remaining filesize
- ifile.seekg(0, std::ios::end);
- std::ifstream::pos_type endpos = ifile.tellg();
- std::ifstream::pos_type distance = endpos - position;
- ifile.seekg(position);
-
- // end of file
- if(!distance) {
- inflateEnd(&strm);
- return true;
- }
-
- // read a chunk of data
- uint32 CHUNKSIZE = ((uint32)distance < MAXCHUNKSIZE ? (uint32)distance : MAXCHUNKSIZE);
- ifile.read(idata.get(), CHUNKSIZE);
- if(ifile.fail()) {
- inflateEnd(&strm);
- return error("ZLIB read error.");
- }
-
- // check if any data was read
- strm.avail_in = (uInt)ifile.gcount();
- if(strm.avail_in == 0) break;
-
- // set next input pointer (to buffer)
- strm.next_in = reinterpret_cast<Bytef*>(idata.get());
-
- // run inflate() on input until output buffer not full
- for(;;)
- {
- strm.avail_out = CHUNKSIZE;
- strm.next_out = reinterpret_cast<Bytef*>(odata.get());
-
- // decompress data
- ret = inflate(&strm, Z_NO_FLUSH);
- if(ret == Z_NEED_DICT) {
- inflateEnd(&strm);
- return error("ZLIB need dictionary error.");;
- }
- else if(ret == Z_DATA_ERROR) {
- uLong total_out = strm.total_out;
- inflateEnd(&strm);
- if(!bytes_read || total_out) return error("ZLIB data error."); // error
- else return true; // no more consecutive zlib streams to read
- }
- else if(ret == Z_MEM_ERROR) {
- ret = Z_DATA_ERROR;
- inflateEnd(&strm);
- return error("ZLIB memory error.");
- }
- else if(ret == Z_STREAM_ERROR) {
- ret = Z_DATA_ERROR;
- inflateEnd(&strm);
- return error("ZLIB stream error.");
- }
-
- // save decompressed data
- unsigned int have = CHUNKSIZE - strm.avail_out;
- ofile.write(odata.get(), have);
- if(ofile.fail()) {
- inflateEnd(&strm);
- return error("ZLIB error writing data.");
- }
- bytes_read += have;
-
- // stop when buffer is not full
- if(strm.avail_out != 0) break;
- }
-
- // done when inflate() says it's done
- if(ret == Z_STREAM_END) break;
- }
-
- // clean up and move to end of stream
- position += strm.total_in;
- inflateEnd(&strm);
- ifile.seekg(position);
- if(ifile.fail()) break;
- }
-
- return true;
- }
-
- bool DecompressZLIB(std::ifstream& ifile, size_t n, std::ofstream& ofile, int windowBits)
- {
- // validate
- if(n < 2) return error("Unexpected number of ZLIB bytes to read.");
- if(!ifile.is_open()) return error("std::ifstream not open.");
- if(!ofile.is_open()) return error("std::ofstream not open.");
-
- // save current position
- std::ifstream::pos_type position = ifile.tellg();
- if(ifile.fail()) return error("Failed to retrieve std::ifstream position.");
-
- // read data
- boost::shared_array<char> idata(new char[n]);
- ifile.read(idata.get(), n);
- if(ifile.fail()) return error("Read failure.");
-
- // allocate inflate buffers
- const uint32 CHUNKSIZE = 65536;
- boost::shared_array<char> odata(new char[CHUNKSIZE]);
-
- // allocate inflate state
- z_stream strm;
- ZeroMemory(&strm, sizeof(strm));
- int ret = inflateInit2(&strm, windowBits);
- if(ret != Z_OK) return error("ZLIB initialization failed.");
-
- // initialize inflate state
- strm.avail_in = n;
- strm.next_in = reinterpret_cast<Bytef*>(idata.get());
-
- // run inflate() on input until output buffer not full
- std::ifstream::pos_type bytes_read = 0;
- for(;;)
- {
- // initialize inflate state
- strm.avail_out = CHUNKSIZE;
- strm.next_out = reinterpret_cast<Bytef*>(odata.get());
-
- // decompress data
- ret = inflate(&strm, Z_NO_FLUSH);
- if(ret == Z_NEED_DICT) {
- inflateEnd(&strm);
- return error("ZLIB need dictionary error.");;
- }
- else if(ret == Z_DATA_ERROR) {
- inflateEnd(&strm);
- return error("ZLIB data error.");
- }
- else if(ret == Z_MEM_ERROR) {
- ret = Z_DATA_ERROR;
- inflateEnd(&strm);
- return error("ZLIB memory error.");
- }
- else if(ret == Z_STREAM_ERROR) {
- ret = Z_DATA_ERROR;
- inflateEnd(&strm);
- return error("ZLIB stream error.");
- }
-
- // save decompressed data
- unsigned int have = CHUNKSIZE - strm.avail_out;
- ofile.write(odata.get(), have);
- if(ofile.fail()) {
- inflateEnd(&strm);
- return error("ZLIB error writing data.");
- }
- bytes_read += have;
-
- // stop when buffer is not full
- if(strm.avail_out != 0) break;
- }
-
- // done when inflate() says it's done
- return (ret == Z_STREAM_END);
- }