diff options
Diffstat (limited to 'nxcomp/StaticCompressor.cpp')
-rw-r--r-- | nxcomp/StaticCompressor.cpp | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/nxcomp/StaticCompressor.cpp b/nxcomp/StaticCompressor.cpp new file mode 100644 index 000000000..b30e61a80 --- /dev/null +++ b/nxcomp/StaticCompressor.cpp @@ -0,0 +1,420 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2010 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of Medialogic S.p.A. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#include "Z.h" +#include "Misc.h" +#include "Control.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "StaticCompressor.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +StaticCompressor::StaticCompressor(int compressionLevel, + int compressionThreshold) +{ + buffer_ = NULL; + bufferSize_ = 0; + + compressionStream_.zalloc = (alloc_func) 0; + compressionStream_.zfree = (free_func) 0; + compressionStream_.opaque = (voidpf) 0; + + decompressionStream_.zalloc = (alloc_func) 0; + decompressionStream_.zfree = (free_func) 0; + decompressionStream_.opaque = (void *) 0; + + decompressionStream_.next_in = (Bytef *) 0; + decompressionStream_.avail_in = 0; + + #ifdef TEST + *logofs << "StaticCompressor: Compression level is " + << compressionLevel << ".\n" << logofs_flush; + #endif + + int result = deflateInit2(&compressionStream_, compressionLevel, Z_DEFLATED, + 15, 9, Z_DEFAULT_STRATEGY); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot initialize the " + << "compression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot initialize the compression " + << "stream. Error is '" << zError(result) << "'.\n"; + + HandleAbort(); + } + + result = inflateInit2(&decompressionStream_, 15); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot initialize the " + << "decompression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot initialize the decompression " + << "stream. Error is '" << zError(result) << "'.\n"; + + HandleAbort(); + } + + #ifdef TEST + *logofs << "StaticCompressor: Compression threshold is " + << compressionThreshold << ".\n" << logofs_flush; + #endif + + threshold_ = compressionThreshold; +} + +StaticCompressor::~StaticCompressor() +{ + int result = deflateEnd(&compressionStream_); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot deinitialize the " + << "compression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot deinitialize the compression " + << "stream. Error is '" << zError(result) << "'.\n"; + } + + result = inflateEnd(&decompressionStream_); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot deinitialize the " + << "decompression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot deinitialize the decompression " + << "stream. Error is '" << zError(result) << "'.\n"; + } + + delete [] buffer_; +} + +// +// This function compresses and encodes the compressed +// buffer. It returns a pointer to the internal buffer +// where data was compressed. +// + +int StaticCompressor::compressBuffer(const unsigned char *plainBuffer, + const unsigned int plainSize, + unsigned char *&compressedBuffer, + unsigned int &compressedSize, + EncodeBuffer &encodeBuffer) +{ + if (control -> LocalDataCompression == 0 || + compressBuffer(plainBuffer, plainSize, + compressedBuffer, compressedSize) <= 0) + { + encodeBuffer.encodeBoolValue(0); + + encodeBuffer.encodeMemory(plainBuffer, plainSize); + + return 0; + } + else + { + encodeBuffer.encodeBoolValue(1); + + encodeBuffer.encodeValue(compressedSize, 32, 14); + encodeBuffer.encodeValue(plainSize, 32, 14); + + encodeBuffer.encodeMemory(compressedBuffer, compressedSize); + + return 1; + } +} + +// +// This function compresses data into a dynamically +// allocated buffer and returns a pointer to it, so +// application must copy data before the next call. +// + +int StaticCompressor::compressBuffer(const unsigned char *plainBuffer, + const unsigned int plainSize, + unsigned char *&compressedBuffer, + unsigned int &compressedSize) +{ + #ifdef DEBUG + *logofs << "StaticCompressor: Called for buffer at " + << (void *) plainBuffer << ".\n" + << logofs_flush; + #endif + + compressedSize = plainSize; + + if (plainSize < (unsigned int) threshold_) + { + #ifdef TEST + *logofs << "StaticCompressor: Leaving buffer unchanged. " + << "Plain size is " << plainSize << " with threshold " + << (unsigned int) threshold_ << ".\n" << logofs_flush; + #endif + + return 0; + } + + // + // Determine the size of the temporary + // buffer. + // + + unsigned int newSize = plainSize + (plainSize / 1000) + 12; + + // + // Allocate a new buffer if it grows + // beyond 64K. + // + + if (buffer_ == NULL || (bufferSize_ > 65536 && + newSize < bufferSize_ / 2) || newSize > bufferSize_) + { + delete [] buffer_; + + buffer_ = new unsigned char[newSize]; + + if (buffer_ == NULL) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Can't allocate compression " + << "buffer of " << newSize << " bytes. Error is " << EGET() + << " ' " << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Can't allocate compression buffer of " + << newSize << " bytes. Error is " << EGET() + << " '" << ESTR() << "'.\n"; + + bufferSize_ = 0; + + return 0; + } + + bufferSize_ = newSize; + } + + unsigned int resultingSize = newSize; + + int result = ZCompress(&compressionStream_, buffer_, &resultingSize, + plainBuffer, plainSize); + + if (result == Z_OK) + { + if (resultingSize > newSize) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Overflow in compression " + << "buffer size. " << "Expected size was " << newSize + << " while it is " << resultingSize << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Overflow in compress buffer size. " + << "Expected size was " << newSize << " while it is " + << resultingSize << ".\n"; + + return -1; + } + else if (resultingSize >= plainSize) + { + #ifdef TEST + *logofs << "StaticCompressor: Leaving buffer unchanged. " + << "Plain size is " << plainSize << " compressed " + << "size is " << resultingSize << ".\n" + << logofs_flush; + #endif + + return 0; + } + + compressedBuffer = buffer_; + compressedSize = resultingSize; + + #ifdef TEST + *logofs << "StaticCompressor: Compressed buffer from " + << plainSize << " to " << resultingSize + << " bytes.\n" << logofs_flush; + #endif + + return 1; + } + + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Failed compression of buffer. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed compression of buffer. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; +} + +int StaticCompressor::decompressBuffer(unsigned char *plainBuffer, + unsigned int plainSize, + const unsigned char *&compressedBuffer, + unsigned int &compressedSize, + DecodeBuffer &decodeBuffer) +{ + #ifdef DEBUG + *logofs << "StaticCompressor: Called for buffer at " + << (void *) plainBuffer << ".\n" + << logofs_flush; + #endif + + unsigned int value; + + decodeBuffer.decodeBoolValue(value); + + if (value == 0) + { + memcpy(plainBuffer, + decodeBuffer.decodeMemory(plainSize), + plainSize); + + return 0; + } + + unsigned int checkSize = plainSize; + + decodeBuffer.decodeValue(value, 32, 14); + compressedSize = value; + + decodeBuffer.decodeValue(value, 32, 14); + checkSize = value; + + // + // If caller needs the original compressed + // data it must copy this to its own buffer + // before using any further decode function. + // + + compressedBuffer = decodeBuffer.decodeMemory(compressedSize); + + int result = ZDecompress(&decompressionStream_, plainBuffer, &checkSize, + compressedBuffer, compressedSize); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Failure decompressing buffer. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decompressing buffer. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; + } + else if (plainSize != checkSize) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n"; + + return -1; + } + + return 1; +} + +// +// This is used to uncompress on-the-fly +// messages whose data has been stored +// in compressed format. +// + +int StaticCompressor::decompressBuffer(unsigned char *plainBuffer, + const unsigned int plainSize, + const unsigned char *compressedBuffer, + const unsigned int compressedSize) +{ + #ifdef TEST + *logofs << "StaticCompressor: Called for buffer at " + << (void *) plainBuffer << ".\n" + << logofs_flush; + #endif + + unsigned int checkSize = plainSize; + + int result = ZDecompress(&decompressionStream_, plainBuffer, &checkSize, + compressedBuffer, compressedSize); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Failure decompressing buffer. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + return -1; + } + + if (plainSize != checkSize) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n"; + + return -1; + } + + #ifdef TEST + *logofs << "StaticCompressor: Decompressed buffer from " + << compressedSize << " to " << plainSize + << " bytes.\n" << logofs_flush; + #endif + + return 1; +} |