summaryrefslogtreecommitdiff
path: root/lib/compress
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compress')
-rwxr-xr-xlib/compress/Compress.h195
-rwxr-xr-xlib/compress/CompressException.h17
-rw-r--r--lib/compress/CompressException.txt12
-rw-r--r--lib/compress/CompressStream.cpp425
-rw-r--r--lib/compress/CompressStream.h62
-rwxr-xr-xlib/compress/Makefile.extra7
6 files changed, 718 insertions, 0 deletions
diff --git a/lib/compress/Compress.h b/lib/compress/Compress.h
new file mode 100755
index 00000000..9b609adb
--- /dev/null
+++ b/lib/compress/Compress.h
@@ -0,0 +1,195 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CompressContext.h
+// Purpose: Interface to zlib compression
+// Created: 5/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef COMPRESSCONTEXT__H
+#define COMPRESSCONTEXT__H
+
+#include <zlib.h>
+
+#include "CompressException.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: CompressContext
+// Purpose: Interface to zlib compression, only very slight wrapper.
+// (Use CompressStream for a more friendly interface.)
+// Created: 5/12/03
+//
+// --------------------------------------------------------------------------
+template<bool Compressing>
+class Compress
+{
+public:
+ Compress()
+ : mFinished(false),
+ mFlush(Z_NO_FLUSH)
+ {
+ // initialise stream
+ mStream.zalloc = Z_NULL;
+ mStream.zfree = Z_NULL;
+ mStream.opaque = Z_NULL;
+ mStream.data_type = Z_BINARY;
+
+ if((Compressing)?(deflateInit(&mStream, Z_DEFAULT_COMPRESSION))
+ :(inflateInit(&mStream)) != Z_OK)
+ {
+ THROW_EXCEPTION(CompressException, InitFailed)
+ }
+
+ mStream.avail_in = 0;
+ }
+
+ ~Compress()
+ {
+ int r = 0;
+ if((r = ((Compressing)?(deflateEnd(&mStream))
+ :(inflateEnd(&mStream)))) != Z_OK)
+ {
+ TRACE1("zlib error code = %d\n", r);
+ if(r == Z_DATA_ERROR)
+ {
+ TRACE0("WARNING: End of compress/decompress without all input being consumed -- possible corruption?\n");
+ }
+ else
+ {
+ THROW_EXCEPTION(CompressException, EndFailed)
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: Compress<Function>::InputRequired()
+ // Purpose: Input required yet?
+ // Created: 5/12/03
+ //
+ // --------------------------------------------------------------------------
+ bool InputRequired()
+ {
+ return mStream.avail_in <= 0;
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: Compress<Function>::Input(const void *, int)
+ // Purpose: Set the input buffer ready for next output call.
+ // Created: 5/12/03
+ //
+ // --------------------------------------------------------------------------
+ void Input(const void *pInBuffer, int InLength)
+ {
+ // Check usage
+ if(mStream.avail_in != 0)
+ {
+ THROW_EXCEPTION(CompressException, BadUsageInputNotRequired)
+ }
+
+ // Store info
+ mStream.next_in = (unsigned char *)pInBuffer;
+ mStream.avail_in = InLength;
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: Compress<Function>::FinishInput()
+ // Purpose: When compressing, no more input will be given.
+ // Created: 5/12/03
+ //
+ // --------------------------------------------------------------------------
+ void FinishInput()
+ {
+ mFlush = Z_FINISH;
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: Compress<Function>::Output(void *, int)
+ // Purpose: Get some output data
+ // Created: 5/12/03
+ //
+ // --------------------------------------------------------------------------
+ int Output(void *pOutBuffer, int OutLength, bool SyncFlush = false)
+ {
+ // need more input?
+ if(mStream.avail_in == 0 && mFlush != Z_FINISH && !SyncFlush)
+ {
+ return 0;
+ }
+
+ // Buffers
+ mStream.next_out = (unsigned char *)pOutBuffer;
+ mStream.avail_out = OutLength;
+
+ // Call one of the functions
+ int flush = mFlush;
+ if(SyncFlush && mFlush != Z_FINISH)
+ {
+ flush = Z_SYNC_FLUSH;
+ }
+ int ret = (Compressing)?(deflate(&mStream, flush)):(inflate(&mStream, flush));
+
+ if(SyncFlush && ret == Z_BUF_ERROR)
+ {
+ // No progress possible. Just return 0.
+ return 0;
+ }
+
+ // Check errors
+ if(ret < 0)
+ {
+ TRACE1("zlib error code = %d\n", ret);
+ THROW_EXCEPTION(CompressException, TransformFailed)
+ }
+
+ // Parse result
+ if(ret == Z_STREAM_END)
+ {
+ mFinished = true;
+ }
+
+ // Return how much data was output
+ return OutLength - mStream.avail_out;
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: Compress<Function>::OutputHasFinished()
+ // Purpose: No more output to be recieved
+ // Created: 5/12/03
+ //
+ // --------------------------------------------------------------------------
+ bool OutputHasFinished()
+ {
+ return mFinished;
+ }
+
+
+private:
+ z_stream mStream;
+ bool mFinished;
+ int mFlush;
+};
+
+template<typename Integer>
+Integer Compress_MaxSizeForCompressedData(Integer InLen)
+{
+ // Conservative rendition of the info found here: http://www.gzip.org/zlib/zlib_tech.html
+ int blocks = (InLen + 32*1024 - 1) / (32*1024);
+ return InLen + (blocks * 6) + 8;
+}
+
+
+#endif // COMPRESSCONTEXT__H
+
diff --git a/lib/compress/CompressException.h b/lib/compress/CompressException.h
new file mode 100755
index 00000000..7e8c9ca2
--- /dev/null
+++ b/lib/compress/CompressException.h
@@ -0,0 +1,17 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CipherException.h
+// Purpose: Exception
+// Created: 2003/07/08
+//
+// --------------------------------------------------------------------------
+
+#ifndef COMPRESSEXCEPTION__H
+#define COMPRESSEXCEPTION__H
+
+// Compatibility
+#include "autogen_CompressException.h"
+
+#endif // COMPRESSEXCEPTION__H
+
diff --git a/lib/compress/CompressException.txt b/lib/compress/CompressException.txt
new file mode 100644
index 00000000..278b76d3
--- /dev/null
+++ b/lib/compress/CompressException.txt
@@ -0,0 +1,12 @@
+EXCEPTION Compress 6
+
+Internal 0
+InitFailed 1
+EndFailed 2
+BadUsageInputNotRequired 3
+TransformFailed 4
+CopyCompressStreamNotAllowed 5
+NullPointerPassedToCompressStream 6
+CompressStreamReadSupportNotRequested 7 Specify read in the constructor
+CompressStreamWriteSupportNotRequested 8 Specify write in the constructor
+CannotWriteToClosedCompressStream 9
diff --git a/lib/compress/CompressStream.cpp b/lib/compress/CompressStream.cpp
new file mode 100644
index 00000000..2839b647
--- /dev/null
+++ b/lib/compress/CompressStream.cpp
@@ -0,0 +1,425 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CompressStream.h
+// Purpose: Compressing stream
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <stdlib.h>
+#include <memory>
+
+#include "CompressStream.h"
+#include "Compress.h"
+#include "autogen_CompressException.h"
+
+#include "MemLeakFindOn.h"
+
+// How big a buffer to use
+#ifndef NDEBUG
+ // debug!
+ #define BUFFER_SIZE 256
+#else
+ #define BUFFER_SIZE (32*1024)
+#endif
+
+#define USE_READ_COMPRESSOR \
+ CheckRead(); \
+ Compress<false> *pDecompress = (Compress<false> *)mpReadCompressor;
+
+#define USE_WRITE_COMPRESSOR \
+ CheckWrite(); \
+ Compress<true> *pCompress = (Compress<true> *)mpWriteCompressor;
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::CompressStream(IOStream *, bool, bool, bool, bool)
+// Purpose: Constructor
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+CompressStream::CompressStream(IOStream *pStream, bool TakeOwnership,
+ bool DecompressRead, bool CompressWrite, bool PassThroughWhenNotCompressed)
+ : mpStream(pStream),
+ mHaveOwnership(TakeOwnership),
+ mDecompressRead(DecompressRead),
+ mCompressWrite(CompressWrite),
+ mPassThroughWhenNotCompressed(PassThroughWhenNotCompressed),
+ mpReadCompressor(0),
+ mpWriteCompressor(0),
+ mpBuffer(0),
+ mIsClosed(false)
+{
+ if(mpStream == 0)
+ {
+ THROW_EXCEPTION(CompressException, NullPointerPassedToCompressStream)
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::~CompressStream()
+// Purpose: Destructor
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+CompressStream::~CompressStream()
+{
+ // Clean up compressors
+ if(mpReadCompressor)
+ {
+ delete ((Compress<false>*)mpReadCompressor);
+ mpReadCompressor = 0;
+ }
+ if(mpWriteCompressor)
+ {
+ delete ((Compress<true>*)mpWriteCompressor);
+ mpWriteCompressor = 0;
+ }
+
+ // Delete the stream, if we have ownership
+ if(mHaveOwnership)
+ {
+ delete mpStream;
+ mpStream = 0;
+ }
+
+ // Free any buffer
+ if(mpBuffer != 0)
+ {
+ ::free(mpBuffer);
+ mpBuffer = 0;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::CompressStream(const CompressStream &)
+// Purpose: Copy constructor, will exception
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+CompressStream::CompressStream(const CompressStream &)
+{
+ THROW_EXCEPTION(CompressException, CopyCompressStreamNotAllowed)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::operator=(const CompressStream &)
+// Purpose: Assignment operator, will exception
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+CompressStream &CompressStream::operator=(const CompressStream &)
+{
+ THROW_EXCEPTION(CompressException, CopyCompressStreamNotAllowed)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::Read(void *, int, int)
+// Purpose: As interface
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+int CompressStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ USE_READ_COMPRESSOR
+ if(pDecompress == 0)
+ {
+ return mpStream->Read(pBuffer, NBytes, Timeout);
+ }
+
+ // Where is the buffer? (note if writing as well, read buffer is second in a block of two buffer sizes)
+ void *pbuf = (mDecompressRead && mCompressWrite)?(((uint8_t*)mpBuffer) + BUFFER_SIZE):mpBuffer;
+
+ // Any data left to go?
+ if(!pDecompress->InputRequired())
+ {
+ // Output some data from the existing data read
+ return pDecompress->Output(pBuffer, NBytes, true /* write as much as possible */);
+ }
+
+ // Read data into the buffer -- read as much as possible in one go
+ int s = mpStream->Read(pbuf, BUFFER_SIZE, Timeout);
+ if(s == 0)
+ {
+ return 0;
+ }
+
+ // Give input to the compressor
+ pDecompress->Input(pbuf, s);
+
+ // Output as much as possible
+ return pDecompress->Output(pBuffer, NBytes, true /* write as much as possible */);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::Write(const void *, int)
+// Purpose: As interface
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+void CompressStream::Write(const void *pBuffer, int NBytes)
+{
+ USE_WRITE_COMPRESSOR
+ if(pCompress == 0)
+ {
+ mpStream->Write(pBuffer, NBytes);
+ return;
+ }
+
+ if(mIsClosed)
+ {
+ THROW_EXCEPTION(CompressException, CannotWriteToClosedCompressStream)
+ }
+
+ // Give the data to the compressor
+ pCompress->Input(pBuffer, NBytes);
+
+ // Write the data to the stream
+ WriteCompressedData();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::WriteAllBuffered()
+// Purpose: As interface
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+void CompressStream::WriteAllBuffered()
+{
+ if(mIsClosed)
+ {
+ THROW_EXCEPTION(CompressException, CannotWriteToClosedCompressStream)
+ }
+
+ // Just ask compressed data to be written out, but with the sync flag set
+ WriteCompressedData(true);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::Close()
+// Purpose: As interface
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+void CompressStream::Close()
+{
+ if(mCompressWrite)
+ {
+ USE_WRITE_COMPRESSOR
+ if(pCompress != 0)
+ {
+ // Flush anything from the write buffer
+ pCompress->FinishInput();
+ WriteCompressedData();
+
+ // Mark as definately closed
+ mIsClosed = true;
+ }
+ }
+
+ // Close
+ mpStream->Close();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::WriteCompressedData(bool)
+// Purpose: Private. Writes the output of the compressor to the stream,
+// optionally doing a sync flush.
+// Created: 28/5/04
+//
+// --------------------------------------------------------------------------
+void CompressStream::WriteCompressedData(bool SyncFlush)
+{
+ USE_WRITE_COMPRESSOR
+ if(pCompress == 0) {THROW_EXCEPTION(CompressException, Internal)}
+
+ int s = 0;
+ do
+ {
+ s = pCompress->Output(mpBuffer, BUFFER_SIZE, SyncFlush);
+ if(s > 0)
+ {
+ mpStream->Write(mpBuffer, s);
+ }
+ } while(s > 0);
+ // Check assumption -- all input has been consumed
+ if(!pCompress->InputRequired()) {THROW_EXCEPTION(CompressException, Internal)}
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::StreamDataLeft()
+// Purpose: As interface
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+bool CompressStream::StreamDataLeft()
+{
+ USE_READ_COMPRESSOR
+ if(pDecompress == 0)
+ {
+ return mpStream->StreamDataLeft();
+ }
+
+ // Any bytes left in our buffer?
+ if(!pDecompress->InputRequired())
+ {
+ // Still buffered data to decompress
+ return true;
+ }
+
+ // Otherwise ask the stream
+ return mpStream->StreamDataLeft();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::StreamClosed()
+// Purpose: As interface
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+bool CompressStream::StreamClosed()
+{
+ if(!mIsClosed && mpStream->StreamClosed())
+ {
+ mIsClosed = true;
+ }
+ return mIsClosed;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::CheckRead()
+// Purpose: Checks that everything is set up to read
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+void CompressStream::CheckRead()
+{
+ // Has the read compressor already been created?
+ if(mpReadCompressor != 0)
+ {
+ return;
+ }
+
+ // Need to create one?
+ if(mDecompressRead)
+ {
+ mpReadCompressor = new Compress<false>();
+ // And make sure there's a buffer
+ CheckBuffer();
+ }
+ else
+ {
+ // Not decompressing. Should be passing through data?
+ if(!mPassThroughWhenNotCompressed)
+ {
+ THROW_EXCEPTION(CompressException, CompressStreamReadSupportNotRequested)
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::CheckWrite()
+// Purpose: Checks that everything is set up to write
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+void CompressStream::CheckWrite()
+{
+ // Has the read compressor already been created?
+ if(mpWriteCompressor != 0)
+ {
+ return;
+ }
+
+ // Need to create one?
+ if(mCompressWrite)
+ {
+ mpWriteCompressor = new Compress<true>();
+ // And make sure there's a buffer
+ CheckBuffer();
+ }
+ else
+ {
+ // Not decompressing. Should be passing through data?
+ if(!mPassThroughWhenNotCompressed)
+ {
+ THROW_EXCEPTION(CompressException, CompressStreamWriteSupportNotRequested)
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CompressStream::CheckBuffer()
+// Purpose: Allocates the buffer for (de)compression operations
+// Created: 28/5/04
+//
+// --------------------------------------------------------------------------
+void CompressStream::CheckBuffer()
+{
+ // Already done
+ if(mpBuffer != 0)
+ {
+ return;
+ }
+
+ // Allocate the buffer -- which may actually be two buffers in one
+ // The temporary use buffer is first (used by write only, so only present if writing)
+ // and the read buffer follows.
+ int size = BUFFER_SIZE;
+ if(mDecompressRead && mCompressWrite)
+ {
+ size *= 2;
+ }
+ TRACE1("Allocating CompressStream buffer, size %d\n", size);
+ mpBuffer = ::malloc(size);
+ if(mpBuffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+}
+
+
diff --git a/lib/compress/CompressStream.h b/lib/compress/CompressStream.h
new file mode 100644
index 00000000..7959e3dc
--- /dev/null
+++ b/lib/compress/CompressStream.h
@@ -0,0 +1,62 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CompressStream.h
+// Purpose: Compressing stream
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef COMPRESSSTREAM__H
+#define COMPRESSSTREAM__H
+
+#include "IOStream.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: CompressStream
+// Purpose: Compressing stream
+// Created: 27/5/04
+//
+// --------------------------------------------------------------------------
+class CompressStream : public IOStream
+{
+public:
+ CompressStream(IOStream *pStream, bool TakeOwnership,
+ bool DecompressRead, bool CompressWrite, bool PassThroughWhenNotCompressed = false);
+ ~CompressStream();
+private:
+ // No copying (have implementations which exception)
+ CompressStream(const CompressStream &);
+ CompressStream &operator=(const CompressStream &);
+public:
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual void WriteAllBuffered();
+ virtual void Close();
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+protected:
+ void CheckRead();
+ void CheckWrite();
+ void CheckBuffer();
+ void WriteCompressedData(bool SyncFlush = false);
+
+private:
+ IOStream *mpStream;
+ bool mHaveOwnership;
+ bool mDecompressRead;
+ bool mCompressWrite;
+ bool mPassThroughWhenNotCompressed;
+ // Avoid having to include Compress.h
+ void *mpReadCompressor;
+ void *mpWriteCompressor;
+ void *mpBuffer;
+ bool mIsClosed;
+};
+
+#endif // COMPRESSSTREAM__H
+
diff --git a/lib/compress/Makefile.extra b/lib/compress/Makefile.extra
new file mode 100755
index 00000000..7ef9930c
--- /dev/null
+++ b/lib/compress/Makefile.extra
@@ -0,0 +1,7 @@
+
+MAKEEXCEPTION = ../../lib/common/makeexception.pl
+
+# AUTOGEN SEEDING
+autogen_CompressException.h autogen_CompressException.cpp: $(MAKEEXCEPTION) CompressException.txt
+ perl $(MAKEEXCEPTION) CompressException.txt
+