Botan
1.11.15
|
00001 /* 00002 * Compression Transform 00003 * (C) 2014 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/compression.h> 00009 #include <botan/internal/compress_utils.h> 00010 #include <botan/mem_ops.h> 00011 #include <cstdlib> 00012 00013 namespace Botan { 00014 00015 void* Compression_Alloc_Info::do_malloc(size_t n, size_t size) 00016 { 00017 const size_t total_sz = n * size; 00018 00019 void* ptr = std::malloc(total_sz); 00020 m_current_allocs[ptr] = total_sz; 00021 return ptr; 00022 } 00023 00024 void Compression_Alloc_Info::do_free(void* ptr) 00025 { 00026 if(ptr) 00027 { 00028 auto i = m_current_allocs.find(ptr); 00029 00030 if(i == m_current_allocs.end()) 00031 throw std::runtime_error("Compression_Alloc_Info::free got pointer not allocated by us"); 00032 00033 zero_mem(ptr, i->second); 00034 std::free(ptr); 00035 m_current_allocs.erase(i); 00036 } 00037 } 00038 00039 Transform* make_compressor(const std::string& type, size_t level) 00040 { 00041 const std::string comp_suffix = "_Compression(" + std::to_string(level) + ")"; 00042 00043 if(type == "zlib") 00044 return get_transform("Zlib" + comp_suffix); 00045 if(type == "deflate") 00046 return get_transform("Deflate" + comp_suffix); 00047 if(type == "gzip" || type == "gz") 00048 return get_transform("Gzip" + comp_suffix); 00049 if(type == "bzip2" || type == "bz2") 00050 return get_transform("Bzip2" + comp_suffix); 00051 if(type == "lzma" || type == "xz") 00052 return get_transform("LZMA" + comp_suffix); 00053 00054 return nullptr; 00055 } 00056 00057 Transform* make_decompressor(const std::string& type) 00058 { 00059 if(type == "zlib") 00060 return get_transform("Zlib_Decompression"); 00061 if(type == "deflate") 00062 return get_transform("Deflate_Decompression"); 00063 if(type == "gzip" || type == "gz") 00064 return get_transform("Gzip_Decompression"); 00065 if(type == "bzip2" || type == "bz2") 00066 return get_transform("Bzip2_Decompression"); 00067 if(type == "lzma" || type == "xz") 00068 return get_transform("LZMA_Decompression"); 00069 00070 return nullptr; 00071 } 00072 00073 void Stream_Compression::clear() 00074 { 00075 m_stream.reset(); 00076 } 00077 00078 secure_vector<byte> Stream_Compression::start_raw(const byte[], size_t nonce_len) 00079 { 00080 if(!valid_nonce_length(nonce_len)) 00081 throw Invalid_IV_Length(name(), nonce_len); 00082 00083 m_stream.reset(make_stream()); 00084 return secure_vector<byte>(); 00085 } 00086 00087 void Stream_Compression::process(secure_vector<byte>& buf, size_t offset, u32bit flags) 00088 { 00089 BOTAN_ASSERT(m_stream, "Initialized"); 00090 BOTAN_ASSERT(buf.size() >= offset, "Offset is sane"); 00091 00092 if(m_buffer.size() < buf.size() + offset) 00093 m_buffer.resize(buf.size() + offset); 00094 00095 m_stream->next_in(&buf[offset], buf.size() - offset); 00096 m_stream->next_out(&m_buffer[offset], m_buffer.size() - offset); 00097 00098 while(true) 00099 { 00100 m_stream->run(flags); 00101 00102 if(m_stream->avail_out() == 0) 00103 { 00104 const size_t added = 8 + m_buffer.size(); 00105 m_buffer.resize(m_buffer.size() + added); 00106 m_stream->next_out(&m_buffer[m_buffer.size() - added], added); 00107 } 00108 else if(m_stream->avail_in() == 0) 00109 { 00110 m_buffer.resize(m_buffer.size() - m_stream->avail_out()); 00111 break; 00112 } 00113 } 00114 00115 copy_mem(&m_buffer[0], &buf[0], offset); 00116 buf.swap(m_buffer); 00117 } 00118 00119 void Stream_Compression::update(secure_vector<byte>& buf, size_t offset) 00120 { 00121 process(buf, offset, m_stream->run_flag()); 00122 } 00123 00124 void Stream_Compression::flush(secure_vector<byte>& buf, size_t offset) 00125 { 00126 process(buf, offset, m_stream->flush_flag()); 00127 } 00128 00129 void Stream_Compression::finish(secure_vector<byte>& buf, size_t offset) 00130 { 00131 process(buf, offset, m_stream->finish_flag()); 00132 clear(); 00133 } 00134 00135 void Stream_Decompression::clear() 00136 { 00137 m_stream.reset(); 00138 } 00139 00140 secure_vector<byte> Stream_Decompression::start_raw(const byte[], size_t nonce_len) 00141 { 00142 if(!valid_nonce_length(nonce_len)) 00143 throw Invalid_IV_Length(name(), nonce_len); 00144 00145 m_stream.reset(make_stream()); 00146 00147 return secure_vector<byte>(); 00148 } 00149 00150 void Stream_Decompression::process(secure_vector<byte>& buf, size_t offset, u32bit flags) 00151 { 00152 BOTAN_ASSERT(m_stream, "Initialized"); 00153 BOTAN_ASSERT(buf.size() >= offset, "Offset is sane"); 00154 00155 if(m_buffer.size() < buf.size() + offset) 00156 m_buffer.resize(buf.size() + offset); 00157 00158 m_stream->next_in(&buf[offset], buf.size() - offset); 00159 m_stream->next_out(&m_buffer[offset], m_buffer.size() - offset); 00160 00161 while(true) 00162 { 00163 const bool stream_end = m_stream->run(flags); 00164 00165 if(stream_end) 00166 { 00167 if(m_stream->avail_in() == 0) // all data consumed? 00168 { 00169 m_buffer.resize(m_buffer.size() - m_stream->avail_out()); 00170 clear(); 00171 break; 00172 } 00173 00174 // More data follows: try to process as a following stream 00175 const size_t read = (buf.size() - offset) - m_stream->avail_in(); 00176 start(); 00177 m_stream->next_in(&buf[offset + read], buf.size() - offset - read); 00178 } 00179 00180 if(m_stream->avail_out() == 0) 00181 { 00182 const size_t added = 8 + m_buffer.size(); 00183 m_buffer.resize(m_buffer.size() + added); 00184 m_stream->next_out(&m_buffer[m_buffer.size() - added], added); 00185 } 00186 else if(m_stream->avail_in() == 0) 00187 { 00188 m_buffer.resize(m_buffer.size() - m_stream->avail_out()); 00189 break; 00190 } 00191 } 00192 00193 copy_mem(&m_buffer[0], &buf[0], offset); 00194 buf.swap(m_buffer); 00195 } 00196 00197 void Stream_Decompression::update(secure_vector<byte>& buf, size_t offset) 00198 { 00199 process(buf, offset, m_stream->run_flag()); 00200 } 00201 00202 void Stream_Decompression::finish(secure_vector<byte>& buf, size_t offset) 00203 { 00204 if(buf.size() != offset || m_stream.get()) 00205 process(buf, offset, m_stream->finish_flag()); 00206 00207 if(m_stream.get()) 00208 throw std::runtime_error(name() + " finished but not at stream end"); 00209 } 00210 00211 }