diff options
author | lloyd <[email protected]> | 2012-07-09 17:33:57 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-07-09 17:33:57 +0000 |
commit | 89f327ba20562edfb84dcad2dfc3a18c01e1d35f (patch) | |
tree | f0716dc1c255b968163995109b138e8db2480962 /src | |
parent | 3cc4f98327ac3ed5f1ceea1dc44c07bd80592c1b (diff) |
Add a LZMA filter contributed by Vojtech Kral
Diffstat (limited to 'src')
-rw-r--r-- | src/filters/lzma/info.txt | 11 | ||||
-rw-r--r-- | src/filters/lzma/lzma.cpp | 326 | ||||
-rw-r--r-- | src/filters/lzma/lzma.h | 74 |
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 |