aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-07-09 17:33:57 +0000
committerlloyd <[email protected]>2012-07-09 17:33:57 +0000
commit89f327ba20562edfb84dcad2dfc3a18c01e1d35f (patch)
treef0716dc1c255b968163995109b138e8db2480962 /src
parent3cc4f98327ac3ed5f1ceea1dc44c07bd80592c1b (diff)
Add a LZMA filter contributed by Vojtech Kral
Diffstat (limited to 'src')
-rw-r--r--src/filters/lzma/info.txt11
-rw-r--r--src/filters/lzma/lzma.cpp326
-rw-r--r--src/filters/lzma/lzma.h74
3 files changed, 411 insertions, 0 deletions
diff --git a/src/filters/lzma/info.txt b/src/filters/lzma/info.txt
new file mode 100644
index 000000000..d9e924eef
--- /dev/null
+++ b/src/filters/lzma/info.txt
@@ -0,0 +1,11 @@
+define COMPRESSOR_LZMA
+
+load_on request
+
+<libs>
+all -> lzma
+</libs>
+
+<requires>
+filters
+</requires>
diff --git a/src/filters/lzma/lzma.cpp b/src/filters/lzma/lzma.cpp
new file mode 100644
index 000000000..0bcda0343
--- /dev/null
+++ b/src/filters/lzma/lzma.cpp
@@ -0,0 +1,326 @@
+/*
+* Lzma Compressor
+* (C) 2001 Peter J Jones
+* 2001-2007 Jack Lloyd
+* 2006 Matt Johnston
+* 2012 Vojtech Kral
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/lzma.h>
+#include <botan/exceptn.h>
+
+#include <cstring>
+#include <map>
+#include <lzma.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* Allocation Information for Lzma
+*/
+class Lzma_Alloc_Info
+ {
+ public:
+ std::map<void*, size_t> current_allocs;
+ };
+
+/*
+* Allocation Function for Lzma
+*/
+void* lzma_malloc(void *opaque, size_t /*nmemb*/, size_t size)
+ {
+ Lzma_Alloc_Info* info = static_cast<Lzma_Alloc_Info*>(opaque);
+ void* ptr = std::malloc(size); // It is guaranteed by liblzma doc that nmemb is always set to 1
+ info->current_allocs[ptr] = size;
+ return ptr;
+ }
+
+/*
+* Allocation Function for Lzma
+*/
+void lzma_free(void *opaque, void *ptr)
+ {
+ if(!ptr) return; // liblzma sometimes does pass zero ptr
+
+ Lzma_Alloc_Info* info = static_cast<Lzma_Alloc_Info*>(opaque);
+ auto i = info->current_allocs.find(ptr);
+ if(i == info->current_allocs.end())
+ throw Invalid_Argument("lzma_free: Got pointer not allocated by us");
+
+ std::memset(ptr, 0, i->second);
+ std::free(ptr);
+ }
+
+}
+
+/**
+* Wrapper Type for lzma_stream
+*/
+class Lzma_Stream
+ {
+ public:
+ /**
+ * Underlying stream
+ */
+ lzma_stream stream;
+
+ /**
+ * Constructor
+ */
+ Lzma_Stream() :
+ stream(LZMA_STREAM_INIT)
+ {
+ stream.allocator = new lzma_allocator;
+ stream.allocator->alloc = lzma_malloc;
+ stream.allocator->free = lzma_free;
+ stream.allocator->opaque = new Lzma_Alloc_Info;
+ }
+
+ /**
+ * Destructor
+ */
+ ~Lzma_Stream()
+ {
+ Lzma_Alloc_Info* info = static_cast<Lzma_Alloc_Info*>(stream.allocator->opaque);
+ delete info;
+ delete stream.allocator;
+ std::memset(&stream, 0, sizeof(lzma_stream));
+ }
+ };
+
+/*
+* Lzma_Compression Constructor
+*/
+Lzma_Compression::Lzma_Compression(size_t l) :
+ level((l >= 9) ? 9 : l),
+ buffer(DEFAULT_BUFFERSIZE),
+ lzma(0)
+ {
+ }
+
+/*
+* Start Compressing with Lzma
+*/
+void Lzma_Compression::start_msg()
+ {
+ clear();
+ lzma = new Lzma_Stream;
+
+ lzma_ret ret = lzma_easy_encoder(&(lzma->stream), level, LZMA_CHECK_CRC64);
+
+ if(ret == LZMA_MEM_ERROR)
+ throw Memory_Exhaustion();
+ else if(ret != LZMA_OK)
+ throw Invalid_Argument("Bad setting in lzma_easy_encoder");
+ }
+
+/*
+* Compress Input with Lzma
+*/
+void Lzma_Compression::write(const byte input[], size_t length)
+ {
+ lzma->stream.next_in = static_cast<const uint8_t*>(input);
+ lzma->stream.avail_in = length;
+
+ while(lzma->stream.avail_in != 0)
+ {
+ lzma->stream.next_out = static_cast<uint8_t*>(&buffer[0]);
+ lzma->stream.avail_out = buffer.size();
+
+ lzma_ret ret = lzma_code(&(lzma->stream), LZMA_RUN);
+
+ if(ret == LZMA_MEM_ERROR)
+ throw Memory_Exhaustion();
+ else if (ret != LZMA_OK)
+ throw std::runtime_error("Lzma compression: Error writing");
+
+ send(&buffer[0], buffer.size() - lzma->stream.avail_out);
+ }
+ }
+
+/*
+* Finish Compressing with Lzma
+*/
+void Lzma_Compression::end_msg()
+ {
+ lzma->stream.next_in = 0;
+ lzma->stream.avail_in = 0;
+
+ int ret = LZMA_OK;
+ while(ret != LZMA_STREAM_END)
+ {
+ lzma->stream.next_out = reinterpret_cast<uint8_t*>(&buffer[0]);
+ lzma->stream.avail_out = buffer.size();
+
+ ret = lzma_code(&(lzma->stream), LZMA_FINISH);
+ send(&buffer[0], buffer.size() - lzma->stream.avail_out);
+ }
+
+ clear();
+ }
+
+/*
+* Flush the Lzma Compressor
+*/
+void Lzma_Compression::flush()
+ {
+ lzma->stream.next_in = 0;
+ lzma->stream.avail_in = 0;
+
+ while(true)
+ {
+ lzma->stream.next_out = reinterpret_cast<uint8_t*>(&buffer[0]);
+ lzma->stream.avail_out = buffer.size();
+
+ lzma_ret ret = lzma_code(&(lzma->stream), LZMA_FULL_FLUSH);
+
+ if(ret == LZMA_MEM_ERROR)
+ throw Memory_Exhaustion();
+ else if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+ throw std::runtime_error("Lzma compression: Error flushing");
+
+ send(&buffer[0], buffer.size() - lzma->stream.avail_out);
+
+ if(lzma->stream.avail_out == buffer.size())
+ break;
+ }
+ }
+
+/*
+* Clean up Compression Context
+*/
+void Lzma_Compression::clear()
+ {
+ zeroise(buffer);
+
+ if(lzma)
+ {
+ lzma_end(&(lzma->stream));
+ delete lzma;
+ lzma = 0;
+ }
+ }
+
+/*
+* Lzma_Decompression Constructor
+*/
+Lzma_Decompression::Lzma_Decompression() :
+ buffer(DEFAULT_BUFFERSIZE),
+ lzma(0),
+ no_writes(true)
+ {
+ }
+
+/*
+* Start Decompressing with Lzma
+*/
+void Lzma_Decompression::start_msg()
+ {
+ clear();
+ lzma = new Lzma_Stream;
+
+ lzma_ret ret = lzma_stream_decoder(&(lzma->stream), UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED);
+
+ if(ret == LZMA_MEM_ERROR)
+ throw Memory_Exhaustion();
+ else if(ret != LZMA_OK)
+ throw Invalid_Argument("Bad setting in lzma_stream_decoder");
+ }
+
+/*
+* Decompress Input with Lzma
+*/
+void Lzma_Decompression::write(const byte input_arr[], size_t length)
+ {
+ if(length) no_writes = false;
+
+ const uint8_t* input = reinterpret_cast<const uint8_t*>(input_arr);
+
+ lzma->stream.next_in = input;
+ lzma->stream.avail_in = length;
+
+ while(lzma->stream.avail_in != 0)
+ {
+ lzma->stream.next_out = reinterpret_cast<uint8_t*>(&buffer[0]);
+ lzma->stream.avail_out = buffer.size();
+
+ lzma_ret ret = lzma_code(&(lzma->stream), LZMA_RUN);
+
+ if(ret != LZMA_OK && ret != LZMA_STREAM_END)
+ {
+ clear();
+ if(ret == LZMA_DATA_ERROR)
+ throw Decoding_Error("Lzma_Decompression: Data integrity error");
+ else if(ret == LZMA_MEM_ERROR)
+ throw Memory_Exhaustion();
+ else
+ throw std::runtime_error("Lzma decompression: Unknown error");
+ }
+
+ send(&buffer[0], buffer.size() - lzma->stream.avail_out);
+
+ if(ret == LZMA_STREAM_END)
+ {
+ size_t read_from_block = length - lzma->stream.avail_in;
+ start_msg();
+
+ lzma->stream.next_in = input + read_from_block;
+ lzma->stream.avail_in = length - read_from_block;
+
+ input += read_from_block;
+ length -= read_from_block;
+ }
+ }
+ }
+
+/*
+* Finish Decompressing with Lzma
+*/
+void Lzma_Decompression::end_msg()
+ {
+ if(no_writes) return;
+ lzma->stream.next_in = 0;
+ lzma->stream.avail_in = 0;
+
+ int ret = LZMA_OK;
+
+ while(ret != LZMA_STREAM_END)
+ {
+ lzma->stream.next_out = reinterpret_cast<uint8_t*>(&buffer[0]);
+ lzma->stream.avail_out = buffer.size();
+ ret = lzma_code(&(lzma->stream), LZMA_FINISH);
+
+ if(ret != LZMA_OK && ret != LZMA_STREAM_END)
+ {
+ clear();
+ throw Decoding_Error("Lzma_Decompression: Error finalizing");
+ }
+
+ send(&buffer[0], buffer.size() - lzma->stream.avail_out);
+ }
+
+ clear();
+ }
+
+/*
+* Clean up Decompression Context
+*/
+void Lzma_Decompression::clear()
+ {
+ zeroise(buffer);
+
+ no_writes = true;
+
+ if(lzma)
+ {
+ lzma_end(&(lzma->stream));
+ delete lzma;
+ lzma = 0;
+ }
+ }
+
+}
diff --git a/src/filters/lzma/lzma.h b/src/filters/lzma/lzma.h
new file mode 100644
index 000000000..33e12d580
--- /dev/null
+++ b/src/filters/lzma/lzma.h
@@ -0,0 +1,74 @@
+/*
+* Lzma Compressor
+* (C) 2001 Peter J Jones
+* 2001-2007 Jack Lloyd
+* 2012 Vojtech Kral
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_LZMA_H__
+#define BOTAN_LZMA_H__
+
+#include <botan/filter.h>
+
+namespace Botan {
+
+/**
+* Lzma Compression Filter
+*/
+class BOTAN_DLL Lzma_Compression : public Filter
+ {
+ public:
+ std::string name() const { return "Lzma_Compression"; }
+
+ void write(const byte input[], size_t length);
+ void start_msg();
+ void end_msg();
+
+ /**
+ * Flush the compressor
+ */
+ void flush();
+
+ /**
+ * @param level how much effort to use on compressing (0 to 9);
+ * higher levels are slower but tend to give better
+ * compression
+ */
+ Lzma_Compression(size_t level = 6);
+
+ ~Lzma_Compression() { clear(); }
+ private:
+ void clear();
+ const size_t level;
+
+ secure_vector<byte> buffer;
+ class Lzma_Stream* lzma;
+ };
+
+/**
+* Lzma Decompression Filter
+*/
+class BOTAN_DLL Lzma_Decompression : public Filter
+ {
+ public:
+ std::string name() const { return "Lzma_Decompression"; }
+
+ void write(const byte input[], size_t length);
+ void start_msg();
+ void end_msg();
+
+ Lzma_Decompression();
+ ~Lzma_Decompression() { clear(); }
+ private:
+ void clear();
+
+ secure_vector<byte> buffer;
+ class Lzma_Stream* lzma;
+ bool no_writes;
+ };
+
+}
+
+#endif