// ZlibCompressor.cpp,v 1.2 2003/11/09 20:44:19 dhinton Exp // ZlibCompressor by Andrew Marlow. // This class is used to compress data sent via ACE sockets. // It uses the ACE_Stream ideas in chapter 9 of C++ Network Programming Vol 2. #include "ZlibCompressor.h" #include "ace/SOCK_Stream.h" #include "ace/OS_NS_string.h" #include <zlib.h> ZlibCompressor::ZlibCompressor() : isDeflateInitialised_(false) { } ZlibCompressor::~ZlibCompressor(void) { deflateEnd(&zstream_); } int ZlibCompressor::send(ACE_Message_Block *message, ACE_Time_Value *timeout, ACE_Message_Block*& compressed) { ACE_UNUSED_ARG(message); ACE_UNUSED_ARG(timeout); ACE_DEBUG ((LM_INFO, "(%P|%t) ZlibCompressor::send() compressing (%s)\n", message->rd_ptr() )); // Create a block to hold the compressed data. // I believe libz recommends a buffer about 10-20% larger // than the source. // Other libraries/algorithms may have their own quirks. int err; int mlen = ACE_OS::strlen(message->rd_ptr())+1; zstream_.next_in = (Bytef*)message->rd_ptr(); zstream_.avail_in = (uInt) mlen; zstream_.avail_out = (uInt) 5 * message->size(); compressed = new ACE_Message_Block(zstream_.avail_out); zstream_.next_out = (Bytef*)compressed->wr_ptr(); if (isDeflateInitialised_) { err = deflateReset(&zstream_); if (err != Z_OK) { return -1; } } else { zstream_.zalloc = (alloc_func)0; zstream_.zfree = (free_func)0; zstream_.opaque = (voidpf)0; err = deflateInit_(&zstream_, Z_BEST_SPEED, ZLIB_VERSION, sizeof(zstream_)); if (err != Z_OK) { return -1; } isDeflateInitialised_ = true; } // Perform the compression. err = deflate(&zstream_, Z_FINISH); if (err != Z_STREAM_END) { return (err == Z_OK) ? Z_BUF_ERROR : err; } compressed->wr_ptr(zstream_.total_out); return 0; } /* And here's the decompression side. We've written Xmit/Recv so that we're guaranteed to get an entire block of compressed data. If we'd used recv() in the Recv object then we might have gotten a partial block and that may not decompress very nicely. */ int ZlibCompressor::recv(ACE_Message_Block *message, ACE_Time_Value *timeout, ACE_Message_Block*& decompressed) { ACE_UNUSED_ARG(message); ACE_UNUSED_ARG(timeout); ACE_DEBUG ((LM_INFO, "(%P|%t) Compress::recv() decompressing.\n" )); // Room for the decompressed data. In the real world you // would probably want to send the original (uncompressed) // data size in the message. You can predict the maximum // possible decompression size but it's cheap and easy // just to send that along. Look again at how I do // exacly that between Xmit and Recv. int err; zstream_.avail_out = 5 * message->size(); decompressed = new ACE_Message_Block(zstream_.avail_out); zstream_.next_in = (Bytef*)message->rd_ptr(); zstream_.avail_in = message->size(); zstream_.next_out = (Bytef*)decompressed->wr_ptr(); zstream_.zalloc = (alloc_func)0; zstream_.zfree = (free_func)0; err = inflateInit(&zstream_); if (err != Z_OK) { return -1; } err = inflate(&zstream_, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&zstream_); return -1; } decompressed->wr_ptr(zstream_.total_out); return 0; }