aboutsummaryrefslogtreecommitdiffstats
path: root/modules/compression/zlib/zlib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/compression/zlib/zlib.cpp')
-rw-r--r--modules/compression/zlib/zlib.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/modules/compression/zlib/zlib.cpp b/modules/compression/zlib/zlib.cpp
new file mode 100644
index 000000000..36a9640e3
--- /dev/null
+++ b/modules/compression/zlib/zlib.cpp
@@ -0,0 +1,283 @@
+/*************************************************
+* Zlib Compressor Source File *
+* (C) 2001 Peter J Jones *
+* 2001-2007 Jack Lloyd *
+* 2006 Matt Johnston *
+*************************************************/
+
+#include <botan/zlib.h>
+#include <cstring>
+#include <map>
+#include <zlib.h>
+
+namespace Botan {
+
+namespace {
+
+/*************************************************
+* Allocation Information for Zlib *
+*************************************************/
+class Zlib_Alloc_Info
+ {
+ public:
+ std::map<void*, u32bit> current_allocs;
+ Allocator* alloc;
+
+ Zlib_Alloc_Info() { alloc = Allocator::get(false); }
+ };
+
+/*************************************************
+* Allocation Function for Zlib *
+*************************************************/
+void* zlib_malloc(void* info_ptr, unsigned int n, unsigned int size)
+ {
+ Zlib_Alloc_Info* info = static_cast<Zlib_Alloc_Info*>(info_ptr);
+ void* ptr = info->alloc->allocate(n * size);
+ info->current_allocs[ptr] = n * size;
+ return ptr;
+ }
+
+/*************************************************
+* Allocation Function for Zlib *
+*************************************************/
+void zlib_free(void* info_ptr, void* ptr)
+ {
+ Zlib_Alloc_Info* info = static_cast<Zlib_Alloc_Info*>(info_ptr);
+ std::map<void*, u32bit>::const_iterator i = info->current_allocs.find(ptr);
+ if(i == info->current_allocs.end())
+ throw Invalid_Argument("zlib_free: Got pointer not allocated by us");
+ info->alloc->deallocate(ptr, i->second);
+ }
+
+}
+
+/*************************************************
+* Wrapper Type for Zlib z_stream *
+*************************************************/
+class Zlib_Stream
+ {
+ public:
+ z_stream stream;
+
+ Zlib_Stream()
+ {
+ std::memset(&stream, 0, sizeof(z_stream));
+ stream.zalloc = zlib_malloc;
+ stream.zfree = zlib_free;
+ stream.opaque = new Zlib_Alloc_Info;
+ }
+ ~Zlib_Stream()
+ {
+ Zlib_Alloc_Info* info = static_cast<Zlib_Alloc_Info*>(stream.opaque);
+ delete info;
+ std::memset(&stream, 0, sizeof(z_stream));
+ }
+ };
+
+/*************************************************
+* Zlib_Compression Constructor *
+*************************************************/
+Zlib_Compression::Zlib_Compression(u32bit l) :
+ level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE)
+ {
+ zlib = 0;
+ }
+
+/*************************************************
+* Start Compressing with Zlib *
+*************************************************/
+void Zlib_Compression::start_msg()
+ {
+ clear();
+ zlib = new Zlib_Stream;
+ if(deflateInit(&(zlib->stream), level) != Z_OK)
+ throw Exception("Zlib_Compression: Memory allocation error");
+ }
+
+/*************************************************
+* Compress Input with Zlib *
+*************************************************/
+void Zlib_Compression::write(const byte input[], u32bit length)
+ {
+ zlib->stream.next_in = static_cast<Bytef*>(const_cast<byte*>(input));
+ zlib->stream.avail_in = length;
+
+ while(zlib->stream.avail_in != 0)
+ {
+ zlib->stream.next_out = static_cast<Bytef*>(buffer.begin());
+ zlib->stream.avail_out = buffer.size();
+ deflate(&(zlib->stream), Z_NO_FLUSH);
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+ }
+ }
+
+/*************************************************
+* Finish Compressing with Zlib *
+*************************************************/
+void Zlib_Compression::end_msg()
+ {
+ zlib->stream.next_in = 0;
+ zlib->stream.avail_in = 0;
+
+ int rc = Z_OK;
+ while(rc != Z_STREAM_END)
+ {
+ zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
+ zlib->stream.avail_out = buffer.size();
+ rc = deflate(&(zlib->stream), Z_FINISH);
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+ }
+ clear();
+ }
+
+/*************************************************
+* Flush the Zlib Compressor *
+*************************************************/
+void Zlib_Compression::flush()
+ {
+ zlib->stream.next_in = 0;
+ zlib->stream.avail_in = 0;
+
+ while(true)
+ {
+ zlib->stream.avail_out = buffer.size();
+
+ zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
+
+
+ deflate(&(zlib->stream), Z_FULL_FLUSH);
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+ if(zlib->stream.avail_out == buffer.size()) break;
+ }
+ }
+
+/*************************************************
+* Clean up Compression Context *
+*************************************************/
+void Zlib_Compression::clear()
+ {
+ if(zlib)
+ {
+ deflateEnd(&(zlib->stream));
+ delete zlib;
+ zlib = 0;
+ }
+
+ buffer.clear();
+ }
+
+/*************************************************
+* Zlib_Decompression Constructor *
+*************************************************/
+Zlib_Decompression::Zlib_Decompression() : buffer(DEFAULT_BUFFERSIZE)
+ {
+ zlib = 0;
+ no_writes = true;
+ }
+
+/*************************************************
+* Start Decompressing with Zlib *
+*************************************************/
+void Zlib_Decompression::start_msg()
+ {
+ clear();
+ zlib = new Zlib_Stream;
+ if(inflateInit(&(zlib->stream)) != Z_OK)
+ throw Exception("Zlib_Decompression: Memory allocation error");
+ }
+
+/*************************************************
+* Decompress Input with Zlib *
+*************************************************/
+void Zlib_Decompression::write(const byte input_arr[], u32bit length)
+ {
+ if(length) no_writes = false;
+
+ // non-const needed by zlib api :(
+ Bytef* input = reinterpret_cast<Bytef*>(const_cast<byte*>(input_arr));
+
+ zlib->stream.next_in = input;
+ zlib->stream.avail_in = length;
+
+ while(zlib->stream.avail_in != 0)
+ {
+ zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
+ zlib->stream.avail_out = buffer.size();
+
+ int rc = inflate(&(zlib->stream), Z_SYNC_FLUSH);
+
+ if(rc != Z_OK && rc != Z_STREAM_END)
+ {
+ clear();
+ if(rc == Z_DATA_ERROR)
+ throw Decoding_Error("Zlib_Decompression: Data integrity error");
+ if(rc == Z_NEED_DICT)
+ throw Decoding_Error("Zlib_Decompression: Need preset dictionary");
+ if(rc == Z_MEM_ERROR)
+ throw Exception("Zlib_Decompression: Memory allocation error");
+ throw Exception("Zlib_Decompression: Unknown decompress error");
+ }
+
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+
+ if(rc == Z_STREAM_END)
+ {
+ u32bit read_from_block = length - zlib->stream.avail_in;
+ start_msg();
+
+ zlib->stream.next_in = input + read_from_block;
+ zlib->stream.avail_in = length - read_from_block;
+
+ input += read_from_block;
+ length -= read_from_block;
+ }
+ }
+ }
+
+/*************************************************
+* Finish Decompressing with Zlib *
+*************************************************/
+void Zlib_Decompression::end_msg()
+ {
+ if(no_writes) return;
+ zlib->stream.next_in = 0;
+ zlib->stream.avail_in = 0;
+
+ int rc = Z_OK;
+
+ while(rc != Z_STREAM_END)
+ {
+ zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin());
+ zlib->stream.avail_out = buffer.size();
+ rc = inflate(&(zlib->stream), Z_SYNC_FLUSH);
+
+ if(rc != Z_OK && rc != Z_STREAM_END)
+ {
+ clear();
+ throw Exception("Zlib_Decompression: Error finalizing decompression");
+ }
+
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+ }
+
+ clear();
+ }
+
+/*************************************************
+* Clean up Decompression Context *
+*************************************************/
+void Zlib_Decompression::clear()
+ {
+ no_writes = true;
+
+ if(zlib)
+ {
+ inflateEnd(&(zlib->stream));
+ delete zlib;
+ zlib = 0;
+ }
+
+ buffer.clear();
+ }
+
+}