aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/botan/src/lib/filters
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib/filters')
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/aead_filt.h40
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/algo_filt.cpp96
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/basefilt.cpp70
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/basefilt.h124
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/buf_filt.cpp103
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/buf_filt.h93
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/cipher_filter.cpp103
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/cipher_filter.h58
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/comp_filter.cpp122
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/comp_filter.h71
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/data_snk.cpp75
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/data_snk.h76
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/filter.cpp129
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/filter.h183
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/filters.h227
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/info.txt24
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/key_filt.cpp39
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/key_filt.h109
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/out_buf.cpp121
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/out_buf.h44
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/pipe.cpp311
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/pipe.h379
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/pipe_io.cpp47
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/pipe_rw.cpp181
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/secqueue.cpp232
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/secqueue.h72
-rw-r--r--src/libs/3rdparty/botan/src/lib/filters/threaded_fork.cpp153
27 files changed, 3282 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/filters/aead_filt.h b/src/libs/3rdparty/botan/src/lib/filters/aead_filt.h
new file mode 100644
index 00000000000..f569423a69a
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/aead_filt.h
@@ -0,0 +1,40 @@
+/*
+* Filter interface for AEAD Modes
+* (C) 2013 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_AEAD_FILTER_H_
+#define BOTAN_AEAD_FILTER_H_
+
+#include <botan/cipher_filter.h>
+#include <botan/aead.h>
+
+namespace Botan {
+
+/**
+* Filter interface for AEAD Modes
+*/
+class AEAD_Filter final : public Cipher_Mode_Filter
+ {
+ public:
+ AEAD_Filter(AEAD_Mode* aead) : Cipher_Mode_Filter(aead) {}
+
+ /**
+ * Set associated data that is not included in the ciphertext but
+ * that should be authenticated. Must be called after set_key
+ * and before end_msg.
+ *
+ * @param ad the associated data
+ * @param ad_len length of add in bytes
+ */
+ void set_associated_data(const uint8_t ad[], size_t ad_len)
+ {
+ dynamic_cast<AEAD_Mode&>(get_transform()).set_associated_data(ad, ad_len);
+ }
+ };
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/algo_filt.cpp b/src/libs/3rdparty/botan/src/lib/filters/algo_filt.cpp
new file mode 100644
index 00000000000..c944b72e5be
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/algo_filt.cpp
@@ -0,0 +1,96 @@
+/*
+* Filters
+* (C) 1999-2007,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/filters.h>
+#include <algorithm>
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_STREAM_CIPHER)
+
+StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher) :
+ m_buffer(BOTAN_DEFAULT_BUFFER_SIZE),
+ m_cipher(cipher)
+ {
+ }
+
+StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher, const SymmetricKey& key) :
+ StreamCipher_Filter(cipher)
+ {
+ m_cipher->set_key(key);
+ }
+
+StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) :
+ m_buffer(BOTAN_DEFAULT_BUFFER_SIZE),
+ m_cipher(StreamCipher::create_or_throw(sc_name))
+ {
+ }
+
+StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name, const SymmetricKey& key) :
+ StreamCipher_Filter(sc_name)
+ {
+ m_cipher->set_key(key);
+ }
+
+void StreamCipher_Filter::write(const uint8_t input[], size_t length)
+ {
+ while(length)
+ {
+ size_t copied = std::min<size_t>(length, m_buffer.size());
+ m_cipher->cipher(input, m_buffer.data(), copied);
+ send(m_buffer, copied);
+ input += copied;
+ length -= copied;
+ }
+ }
+
+#endif
+
+#if defined(BOTAN_HAS_HASH)
+
+Hash_Filter::Hash_Filter(const std::string& hash_name, size_t len) :
+ m_hash(HashFunction::create_or_throw(hash_name)),
+ m_out_len(len)
+ {
+ }
+
+void Hash_Filter::end_msg()
+ {
+ secure_vector<uint8_t> output = m_hash->final();
+ if(m_out_len)
+ send(output, std::min<size_t>(m_out_len, output.size()));
+ else
+ send(output);
+ }
+#endif
+
+#if defined(BOTAN_HAS_MAC)
+
+MAC_Filter::MAC_Filter(const std::string& mac_name, size_t len) :
+ m_mac(MessageAuthenticationCode::create_or_throw(mac_name)),
+ m_out_len(len)
+ {
+ }
+
+MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, size_t len) :
+ MAC_Filter(mac_name, len)
+ {
+ m_mac->set_key(key);
+ }
+
+void MAC_Filter::end_msg()
+ {
+ secure_vector<uint8_t> output = m_mac->final();
+ if(m_out_len)
+ send(output, std::min<size_t>(m_out_len, output.size()));
+ else
+ send(output);
+ }
+
+#endif
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/basefilt.cpp b/src/libs/3rdparty/botan/src/lib/filters/basefilt.cpp
new file mode 100644
index 00000000000..89026f6005d
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/basefilt.cpp
@@ -0,0 +1,70 @@
+/*
+* Basic Filters
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/basefilt.h>
+#include <botan/key_filt.h>
+
+namespace Botan {
+
+void Keyed_Filter::set_iv(const InitializationVector& iv)
+ {
+ if(iv.length() != 0)
+ throw Invalid_IV_Length(name(), iv.length());
+ }
+
+/*
+* Chain Constructor
+*/
+Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4)
+ {
+ if(f1) { attach(f1); incr_owns(); }
+ if(f2) { attach(f2); incr_owns(); }
+ if(f3) { attach(f3); incr_owns(); }
+ if(f4) { attach(f4); incr_owns(); }
+ }
+
+/*
+* Chain Constructor
+*/
+Chain::Chain(Filter* filters[], size_t count)
+ {
+ for(size_t j = 0; j != count; ++j)
+ if(filters[j])
+ {
+ attach(filters[j]);
+ incr_owns();
+ }
+ }
+
+std::string Chain::name() const
+ {
+ return "Chain";
+ }
+
+/*
+* Fork Constructor
+*/
+Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4)
+ {
+ Filter* filters[4] = { f1, f2, f3, f4 };
+ set_next(filters, 4);
+ }
+
+/*
+* Fork Constructor
+*/
+Fork::Fork(Filter* filters[], size_t count)
+ {
+ set_next(filters, count);
+ }
+
+std::string Fork::name() const
+ {
+ return "Fork";
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/basefilt.h b/src/libs/3rdparty/botan/src/lib/filters/basefilt.h
new file mode 100644
index 00000000000..922d356693e
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/basefilt.h
@@ -0,0 +1,124 @@
+/*
+* Basic Filters
+* (C) 1999-2007 Jack Lloyd
+* (C) 2013 Joel Low
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_BASEFILT_H_
+#define BOTAN_BASEFILT_H_
+
+#include <botan/filter.h>
+
+#if defined(BOTAN_TARGET_OS_HAS_THREADS)
+ #include <thread>
+#endif
+
+namespace Botan {
+
+/**
+* BitBucket is a filter which simply discards all inputs
+*/
+class BOTAN_PUBLIC_API(2,0) BitBucket final : public Filter
+ {
+ public:
+ void write(const uint8_t[], size_t) override { /* discard */ }
+
+ std::string name() const override { return "BitBucket"; }
+ };
+
+/**
+* This class represents Filter chains. A Filter chain is an ordered
+* concatenation of Filters, the input to a Chain sequentially passes
+* through all the Filters contained in the Chain.
+*/
+
+class BOTAN_PUBLIC_API(2,0) Chain final : public Fanout_Filter
+ {
+ public:
+ void write(const uint8_t input[], size_t length) override { send(input, length); }
+
+ std::string name() const override;
+
+ /**
+ * Construct a chain of up to four filters. The filters are set
+ * up in the same order as the arguments.
+ */
+ Chain(Filter* = nullptr, Filter* = nullptr,
+ Filter* = nullptr, Filter* = nullptr);
+
+ /**
+ * Construct a chain from range of filters
+ * @param filter_arr the list of filters
+ * @param length how many filters
+ */
+ Chain(Filter* filter_arr[], size_t length);
+ };
+
+/**
+* This class represents a fork filter, whose purpose is to fork the
+* flow of data. It causes an input message to result in n messages at
+* the end of the filter, where n is the number of forks.
+*/
+class BOTAN_PUBLIC_API(2,0) Fork : public Fanout_Filter
+ {
+ public:
+ void write(const uint8_t input[], size_t length) override { send(input, length); }
+ void set_port(size_t n) { Fanout_Filter::set_port(n); }
+
+ std::string name() const override;
+
+ /**
+ * Construct a Fork filter with up to four forks.
+ */
+ Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr);
+
+ /**
+ * Construct a Fork from range of filters
+ * @param filter_arr the list of filters
+ * @param length how many filters
+ */
+ Fork(Filter* filter_arr[], size_t length);
+ };
+
+#if defined(BOTAN_HAS_THREAD_UTILS)
+
+/**
+* This class is a threaded version of the Fork filter. While this uses
+* threads, the class itself is NOT thread-safe. This is meant as a drop-
+* in replacement for Fork where performance gains are possible.
+*/
+class BOTAN_PUBLIC_API(2,0) Threaded_Fork final : public Fork
+ {
+ public:
+ std::string name() const override;
+
+ /**
+ * Construct a Threaded_Fork filter with up to four forks.
+ */
+ Threaded_Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr);
+
+ /**
+ * Construct a Threaded_Fork from range of filters
+ * @param filter_arr the list of filters
+ * @param length how many filters
+ */
+ Threaded_Fork(Filter* filter_arr[], size_t length);
+
+ ~Threaded_Fork();
+
+ private:
+ void set_next(Filter* f[], size_t n);
+ void send(const uint8_t in[], size_t length) override;
+ void thread_delegate_work(const uint8_t input[], size_t length);
+ void thread_entry(Filter* filter);
+
+ std::vector<std::shared_ptr<std::thread>> m_threads;
+ std::unique_ptr<struct Threaded_Fork_Data> m_thread_data;
+ };
+#endif
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/buf_filt.cpp b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.cpp
new file mode 100644
index 00000000000..8acc6c74f9c
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.cpp
@@ -0,0 +1,103 @@
+/*
+* Buffered Filter
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/buf_filt.h>
+#include <botan/mem_ops.h>
+#include <botan/internal/rounding.h>
+#include <botan/exceptn.h>
+
+namespace Botan {
+
+/*
+* Buffered_Filter Constructor
+*/
+Buffered_Filter::Buffered_Filter(size_t b, size_t f) :
+ m_main_block_mod(b), m_final_minimum(f)
+ {
+ if(m_main_block_mod == 0)
+ throw Invalid_Argument("m_main_block_mod == 0");
+
+ if(m_final_minimum > m_main_block_mod)
+ throw Invalid_Argument("m_final_minimum > m_main_block_mod");
+
+ m_buffer.resize(2 * m_main_block_mod);
+ m_buffer_pos = 0;
+ }
+
+/*
+* Buffer input into blocks, trying to minimize copying
+*/
+void Buffered_Filter::write(const uint8_t input[], size_t input_size)
+ {
+ if(!input_size)
+ return;
+
+ if(m_buffer_pos + input_size >= m_main_block_mod + m_final_minimum)
+ {
+ size_t to_copy = std::min<size_t>(m_buffer.size() - m_buffer_pos, input_size);
+
+ copy_mem(&m_buffer[m_buffer_pos], input, to_copy);
+ m_buffer_pos += to_copy;
+
+ input += to_copy;
+ input_size -= to_copy;
+
+ size_t total_to_consume =
+ round_down(std::min(m_buffer_pos,
+ m_buffer_pos + input_size - m_final_minimum),
+ m_main_block_mod);
+
+ buffered_block(m_buffer.data(), total_to_consume);
+
+ m_buffer_pos -= total_to_consume;
+
+ copy_mem(m_buffer.data(), m_buffer.data() + total_to_consume, m_buffer_pos);
+ }
+
+ if(input_size >= m_final_minimum)
+ {
+ size_t full_blocks = (input_size - m_final_minimum) / m_main_block_mod;
+ size_t to_copy = full_blocks * m_main_block_mod;
+
+ if(to_copy)
+ {
+ buffered_block(input, to_copy);
+
+ input += to_copy;
+ input_size -= to_copy;
+ }
+ }
+
+ copy_mem(&m_buffer[m_buffer_pos], input, input_size);
+ m_buffer_pos += input_size;
+ }
+
+/*
+* Finish/flush operation
+*/
+void Buffered_Filter::end_msg()
+ {
+ if(m_buffer_pos < m_final_minimum)
+ throw Exception("Buffered filter end_msg without enough input");
+
+ size_t spare_blocks = (m_buffer_pos - m_final_minimum) / m_main_block_mod;
+
+ if(spare_blocks)
+ {
+ size_t spare_bytes = m_main_block_mod * spare_blocks;
+ buffered_block(m_buffer.data(), spare_bytes);
+ buffered_final(&m_buffer[spare_bytes], m_buffer_pos - spare_bytes);
+ }
+ else
+ {
+ buffered_final(m_buffer.data(), m_buffer_pos);
+ }
+
+ m_buffer_pos = 0;
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/buf_filt.h b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.h
new file mode 100644
index 00000000000..b4cd8e68095
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.h
@@ -0,0 +1,93 @@
+/*
+* Buffered Filter
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_BUFFERED_FILTER_H_
+#define BOTAN_BUFFERED_FILTER_H_
+
+#include <botan/secmem.h>
+
+namespace Botan {
+
+/**
+* Filter mixin that breaks input into blocks, useful for
+* cipher modes
+*/
+class BOTAN_PUBLIC_API(2,0) Buffered_Filter
+ {
+ public:
+ /**
+ * Write bytes into the buffered filter, which will them emit them
+ * in calls to buffered_block in the subclass
+ * @param in the input bytes
+ * @param length of in in bytes
+ */
+ void write(const uint8_t in[], size_t length);
+
+ template<typename Alloc>
+ void write(const std::vector<uint8_t, Alloc>& in, size_t length)
+ {
+ write(in.data(), length);
+ }
+
+ /**
+ * Finish a message, emitting to buffered_block and buffered_final
+ * Will throw an exception if less than final_minimum bytes were
+ * written into the filter.
+ */
+ void end_msg();
+
+ /**
+ * Initialize a Buffered_Filter
+ * @param block_size the function buffered_block will be called
+ * with inputs which are a multiple of this size
+ * @param final_minimum the function buffered_final will be called
+ * with at least this many bytes.
+ */
+ Buffered_Filter(size_t block_size, size_t final_minimum);
+
+ virtual ~Buffered_Filter() = default;
+ protected:
+ /**
+ * The block processor, implemented by subclasses
+ * @param input some input bytes
+ * @param length the size of input, guaranteed to be a multiple
+ * of block_size
+ */
+ virtual void buffered_block(const uint8_t input[], size_t length) = 0;
+
+ /**
+ * The final block, implemented by subclasses
+ * @param input some input bytes
+ * @param length the size of input, guaranteed to be at least
+ * final_minimum bytes
+ */
+ virtual void buffered_final(const uint8_t input[], size_t length) = 0;
+
+ /**
+ * @return block size of inputs
+ */
+ size_t buffered_block_size() const { return m_main_block_mod; }
+
+ /**
+ * @return current position in the buffer
+ */
+ size_t current_position() const { return m_buffer_pos; }
+
+ /**
+ * Reset the buffer position
+ */
+ void buffer_reset() { m_buffer_pos = 0; }
+ private:
+ size_t m_main_block_mod, m_final_minimum;
+
+ secure_vector<uint8_t> m_buffer;
+ size_t m_buffer_pos;
+ };
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.cpp b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.cpp
new file mode 100644
index 00000000000..a3e7bd1c39b
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.cpp
@@ -0,0 +1,103 @@
+/*
+* Filter interface for Cipher_Modes
+* (C) 2013,2014,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cipher_filter.h>
+#include <botan/internal/rounding.h>
+
+namespace Botan {
+
+namespace {
+
+size_t choose_update_size(size_t update_granularity)
+ {
+ const size_t target_size = 1024;
+
+ if(update_granularity >= target_size)
+ return update_granularity;
+
+ return round_up(target_size, update_granularity);
+ }
+
+}
+
+Cipher_Mode_Filter::Cipher_Mode_Filter(Cipher_Mode* mode) :
+ Buffered_Filter(choose_update_size(mode->update_granularity()),
+ mode->minimum_final_size()),
+ m_mode(mode),
+ m_nonce(mode->default_nonce_length()),
+ m_buffer(m_mode->update_granularity())
+ {
+ }
+
+std::string Cipher_Mode_Filter::name() const
+ {
+ return m_mode->name();
+ }
+
+void Cipher_Mode_Filter::set_iv(const InitializationVector& iv)
+ {
+ m_nonce = unlock(iv.bits_of());
+ }
+
+void Cipher_Mode_Filter::set_key(const SymmetricKey& key)
+ {
+ m_mode->set_key(key);
+ }
+
+Key_Length_Specification Cipher_Mode_Filter::key_spec() const
+ {
+ return m_mode->key_spec();
+ }
+
+bool Cipher_Mode_Filter::valid_iv_length(size_t length) const
+ {
+ return m_mode->valid_nonce_length(length);
+ }
+
+void Cipher_Mode_Filter::write(const uint8_t input[], size_t input_length)
+ {
+ Buffered_Filter::write(input, input_length);
+ }
+
+void Cipher_Mode_Filter::end_msg()
+ {
+ Buffered_Filter::end_msg();
+ }
+
+void Cipher_Mode_Filter::start_msg()
+ {
+ if(m_nonce.empty() && !m_mode->valid_nonce_length(0))
+ throw Invalid_State("Cipher " + m_mode->name() + " requires a fresh nonce for each message");
+
+ m_mode->start(m_nonce);
+ m_nonce.clear();
+ }
+
+void Cipher_Mode_Filter::buffered_block(const uint8_t input[], size_t input_length)
+ {
+ while(input_length)
+ {
+ const size_t take = std::min(m_mode->update_granularity(), input_length);
+
+ m_buffer.assign(input, input + take);
+ m_mode->update(m_buffer);
+
+ send(m_buffer);
+
+ input += take;
+ input_length -= take;
+ }
+ }
+
+void Cipher_Mode_Filter::buffered_final(const uint8_t input[], size_t input_length)
+ {
+ secure_vector<uint8_t> buf(input, input + input_length);
+ m_mode->finish(buf);
+ send(buf);
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.h b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.h
new file mode 100644
index 00000000000..750385d152f
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.h
@@ -0,0 +1,58 @@
+/*
+* Filter interface for ciphers
+* (C) 2013,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_TRANSFORM_FILTER_H_
+#define BOTAN_TRANSFORM_FILTER_H_
+
+#include <botan/cipher_mode.h>
+#include <botan/key_filt.h>
+#include <botan/buf_filt.h>
+
+namespace Botan {
+
+/**
+* Filter interface for cipher modes
+*/
+class BOTAN_PUBLIC_API(2,0) Cipher_Mode_Filter final : public Keyed_Filter,
+ private Buffered_Filter
+ {
+ public:
+ explicit Cipher_Mode_Filter(Cipher_Mode* t);
+
+ explicit Cipher_Mode_Filter(std::unique_ptr<Cipher_Mode> t) :
+ Cipher_Mode_Filter(t.release()) {}
+
+ void set_iv(const InitializationVector& iv) override;
+
+ void set_key(const SymmetricKey& key) override;
+
+ Key_Length_Specification key_spec() const override;
+
+ bool valid_iv_length(size_t length) const override;
+
+ std::string name() const override;
+
+ private:
+ void write(const uint8_t input[], size_t input_length) override;
+ void start_msg() override;
+ void end_msg() override;
+
+ void buffered_block(const uint8_t input[], size_t input_length) override;
+ void buffered_final(const uint8_t input[], size_t input_length) override;
+
+ std::unique_ptr<Cipher_Mode> m_mode;
+ std::vector<uint8_t> m_nonce;
+ secure_vector<uint8_t> m_buffer;
+ };
+
+// deprecated aliases, will be removed before 2.0
+typedef Cipher_Mode_Filter Transform_Filter;
+typedef Transform_Filter Transformation_Filter;
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/comp_filter.cpp b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.cpp
new file mode 100644
index 00000000000..2563a49077b
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.cpp
@@ -0,0 +1,122 @@
+/*
+* Filter interface for compression
+* (C) 2014,2015,2016 Jack Lloyd
+* (C) 2015 Matej Kenda
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/comp_filter.h>
+#include <botan/exceptn.h>
+
+#if defined(BOTAN_HAS_COMPRESSION)
+ #include <botan/compression.h>
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_COMPRESSION)
+
+Compression_Filter::Compression_Filter(const std::string& type, size_t level, size_t bs) :
+ m_comp(make_compressor(type)),
+ m_buffersize(std::max<size_t>(bs, 256)),
+ m_level(level)
+ {
+ if(!m_comp)
+ {
+ throw Invalid_Argument("Compression type '" + type + "' not found");
+ }
+ }
+
+Compression_Filter::~Compression_Filter() { /* for unique_ptr */ }
+
+std::string Compression_Filter::name() const
+ {
+ return m_comp->name();
+ }
+
+void Compression_Filter::start_msg()
+ {
+ m_comp->start(m_level);
+ }
+
+void Compression_Filter::write(const uint8_t input[], size_t input_length)
+ {
+ while(input_length)
+ {
+ const size_t take = std::min(m_buffersize, input_length);
+ BOTAN_ASSERT(take > 0, "Consumed something");
+
+ m_buffer.assign(input, input + take);
+ m_comp->update(m_buffer);
+
+ send(m_buffer);
+
+ input += take;
+ input_length -= take;
+ }
+ }
+
+void Compression_Filter::flush()
+ {
+ m_buffer.clear();
+ m_comp->update(m_buffer, 0, true);
+ send(m_buffer);
+ }
+
+void Compression_Filter::end_msg()
+ {
+ m_buffer.clear();
+ m_comp->finish(m_buffer);
+ send(m_buffer);
+ }
+
+Decompression_Filter::Decompression_Filter(const std::string& type, size_t bs) :
+ m_comp(make_decompressor(type)),
+ m_buffersize(std::max<size_t>(bs, 256))
+ {
+ if(!m_comp)
+ {
+ throw Invalid_Argument("Compression type '" + type + "' not found");
+ }
+ }
+
+Decompression_Filter::~Decompression_Filter() { /* for unique_ptr */ }
+
+std::string Decompression_Filter::name() const
+ {
+ return m_comp->name();
+ }
+
+void Decompression_Filter::start_msg()
+ {
+ m_comp->start();
+ }
+
+void Decompression_Filter::write(const uint8_t input[], size_t input_length)
+ {
+ while(input_length)
+ {
+ const size_t take = std::min(m_buffersize, input_length);
+ BOTAN_ASSERT(take > 0, "Consumed something");
+
+ m_buffer.assign(input, input + take);
+ m_comp->update(m_buffer);
+
+ send(m_buffer);
+
+ input += take;
+ input_length -= take;
+ }
+ }
+
+void Decompression_Filter::end_msg()
+ {
+ m_buffer.clear();
+ m_comp->finish(m_buffer);
+ send(m_buffer);
+ }
+
+#endif
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/comp_filter.h b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.h
new file mode 100644
index 00000000000..d9cc00b6845
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.h
@@ -0,0 +1,71 @@
+/*
+* Filter interface for compression
+* (C) 2014,2015,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_COMPRESSION_FILTER_H_
+#define BOTAN_COMPRESSION_FILTER_H_
+
+#include <botan/filter.h>
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_COMPRESSION)
+
+class Compression_Algorithm;
+class Decompression_Algorithm;
+
+/**
+* Filter interface for compression
+*/
+class BOTAN_PUBLIC_API(2,0) Compression_Filter final : public Filter
+ {
+ public:
+ void start_msg() override;
+ void write(const uint8_t input[], size_t input_length) override;
+ void end_msg() override;
+
+ void flush();
+
+ std::string name() const override;
+
+ Compression_Filter(const std::string& type,
+ size_t compression_level,
+ size_t buffer_size = 4096);
+
+ ~Compression_Filter();
+ private:
+ std::unique_ptr<Compression_Algorithm> m_comp;
+ size_t m_buffersize, m_level;
+ secure_vector<uint8_t> m_buffer;
+ };
+
+/**
+* Filter interface for decompression
+*/
+class BOTAN_PUBLIC_API(2,0) Decompression_Filter final : public Filter
+ {
+ public:
+ void start_msg() override;
+ void write(const uint8_t input[], size_t input_length) override;
+ void end_msg() override;
+
+ std::string name() const override;
+
+ Decompression_Filter(const std::string& type,
+ size_t buffer_size = 4096);
+
+ ~Decompression_Filter();
+ private:
+ std::unique_ptr<Decompression_Algorithm> m_comp;
+ std::size_t m_buffersize;
+ secure_vector<uint8_t> m_buffer;
+ };
+
+#endif
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/data_snk.cpp b/src/libs/3rdparty/botan/src/lib/filters/data_snk.cpp
new file mode 100644
index 00000000000..9f0ddff96d5
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/data_snk.cpp
@@ -0,0 +1,75 @@
+/*
+* DataSink
+* (C) 1999-2007 Jack Lloyd
+* 2005 Matthew Gregan
+* 2017 Philippe Lieser
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/data_snk.h>
+#include <botan/exceptn.h>
+#include <ostream>
+
+#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+ #include <fstream>
+#endif
+
+namespace Botan {
+
+/*
+* Write to a stream
+*/
+void DataSink_Stream::write(const uint8_t out[], size_t length)
+ {
+ m_sink.write(cast_uint8_ptr_to_char(out), length);
+ if(!m_sink.good())
+ throw Stream_IO_Error("DataSink_Stream: Failure writing to " +
+ m_identifier);
+ }
+
+/*
+* Flush the stream
+*/
+void DataSink_Stream::end_msg()
+ {
+ m_sink.flush();
+ }
+
+/*
+* DataSink_Stream Constructor
+*/
+DataSink_Stream::DataSink_Stream(std::ostream& out,
+ const std::string& name) :
+ m_identifier(name),
+ m_sink(out)
+ {
+ }
+
+#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+
+/*
+* DataSink_Stream Constructor
+*/
+DataSink_Stream::DataSink_Stream(const std::string& path,
+ bool use_binary) :
+ m_identifier(path),
+ m_sink_memory(new std::ofstream(path, use_binary ? std::ios::binary : std::ios::out)),
+ m_sink(*m_sink_memory)
+ {
+ if(!m_sink.good())
+ {
+ throw Stream_IO_Error("DataSink_Stream: Failure opening " + path);
+ }
+ }
+#endif
+
+/*
+* DataSink_Stream Destructor
+*/
+DataSink_Stream::~DataSink_Stream()
+ {
+ // for ~unique_ptr
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/data_snk.h b/src/libs/3rdparty/botan/src/lib/filters/data_snk.h
new file mode 100644
index 00000000000..49484b1c1a6
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/data_snk.h
@@ -0,0 +1,76 @@
+/*
+* DataSink
+* (C) 1999-2007 Jack Lloyd
+* 2017 Philippe Lieser
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_DATA_SINK_H_
+#define BOTAN_DATA_SINK_H_
+
+#include <botan/filter.h>
+#include <memory>
+#include <iosfwd>
+
+namespace Botan {
+
+/**
+* This class represents abstract data sink objects.
+*/
+class BOTAN_PUBLIC_API(2,0) DataSink : public Filter
+ {
+ public:
+ bool attachable() override { return false; }
+ DataSink() = default;
+ virtual ~DataSink() = default;
+
+ DataSink& operator=(const DataSink&) = delete;
+ DataSink(const DataSink&) = delete;
+ };
+
+/**
+* This class represents a data sink which writes its output to a stream.
+*/
+class BOTAN_PUBLIC_API(2,0) DataSink_Stream final : public DataSink
+ {
+ public:
+ /**
+ * Construct a DataSink_Stream from a stream.
+ * @param stream the stream to write to
+ * @param name identifier
+ */
+ DataSink_Stream(std::ostream& stream,
+ const std::string& name = "<std::ostream>");
+
+#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+
+ /**
+ * Construct a DataSink_Stream from a filesystem path name.
+ * @param pathname the name of the file to open a stream to
+ * @param use_binary indicates whether to treat the file
+ * as a binary file or not
+ */
+ DataSink_Stream(const std::string& pathname,
+ bool use_binary = false);
+#endif
+
+ std::string name() const override { return m_identifier; }
+
+ void write(const uint8_t[], size_t) override;
+
+ void end_msg() override;
+
+ ~DataSink_Stream();
+
+ private:
+ const std::string m_identifier;
+
+ // May be null, if m_sink was an external reference
+ std::unique_ptr<std::ostream> m_sink_memory;
+ std::ostream& m_sink;
+ };
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/filter.cpp b/src/libs/3rdparty/botan/src/lib/filters/filter.cpp
new file mode 100644
index 00000000000..6653fc78153
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/filter.cpp
@@ -0,0 +1,129 @@
+/*
+* Filter
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/filter.h>
+#include <botan/exceptn.h>
+
+namespace Botan {
+
+/*
+* Filter Constructor
+*/
+Filter::Filter()
+ {
+ m_next.resize(1);
+ m_port_num = 0;
+ m_filter_owns = 0;
+ m_owned = false;
+ }
+
+/*
+* Send data to all ports
+*/
+void Filter::send(const uint8_t input[], size_t length)
+ {
+ if(!length)
+ return;
+
+ bool nothing_attached = true;
+ for(size_t j = 0; j != total_ports(); ++j)
+ if(m_next[j])
+ {
+ if(m_write_queue.size())
+ m_next[j]->write(m_write_queue.data(), m_write_queue.size());
+ m_next[j]->write(input, length);
+ nothing_attached = false;
+ }
+
+ if(nothing_attached)
+ m_write_queue += std::make_pair(input, length);
+ else
+ m_write_queue.clear();
+ }
+
+/*
+* Start a new message
+*/
+void Filter::new_msg()
+ {
+ start_msg();
+ for(size_t j = 0; j != total_ports(); ++j)
+ if(m_next[j])
+ m_next[j]->new_msg();
+ }
+
+/*
+* End the current message
+*/
+void Filter::finish_msg()
+ {
+ end_msg();
+ for(size_t j = 0; j != total_ports(); ++j)
+ if(m_next[j])
+ m_next[j]->finish_msg();
+ }
+
+/*
+* Attach a filter to the current port
+*/
+void Filter::attach(Filter* new_filter)
+ {
+ if(new_filter)
+ {
+ Filter* last = this;
+ while(last->get_next())
+ last = last->get_next();
+ last->m_next[last->current_port()] = new_filter;
+ }
+ }
+
+/*
+* Set the active port on a filter
+*/
+void Filter::set_port(size_t new_port)
+ {
+ if(new_port >= total_ports())
+ throw Invalid_Argument("Filter: Invalid port number");
+ m_port_num = new_port;
+ }
+
+/*
+* Return the next Filter in the logical chain
+*/
+Filter* Filter::get_next() const
+ {
+ if(m_port_num < m_next.size())
+ return m_next[m_port_num];
+ return nullptr;
+ }
+
+/*
+* Set the next Filters
+*/
+void Filter::set_next(Filter* filters[], size_t size)
+ {
+ m_next.clear();
+
+ m_port_num = 0;
+ m_filter_owns = 0;
+
+ while(size && filters && (filters[size-1] == nullptr))
+ --size;
+
+ if(filters && size)
+ m_next.assign(filters, filters + size);
+ }
+
+/*
+* Return the total number of ports
+*/
+size_t Filter::total_ports() const
+ {
+ return m_next.size();
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/filter.h b/src/libs/3rdparty/botan/src/lib/filters/filter.h
new file mode 100644
index 00000000000..a0857c589e5
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/filter.h
@@ -0,0 +1,183 @@
+/*
+* Filter
+* (C) 1999-2007 Jack Lloyd
+* (C) 2013 Joel Low
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_FILTER_H_
+#define BOTAN_FILTER_H_
+
+#include <botan/secmem.h>
+#include <vector>
+#include <string>
+
+namespace Botan {
+
+/**
+* This class represents general abstract filter objects.
+*/
+class BOTAN_PUBLIC_API(2,0) Filter
+ {
+ public:
+ /**
+ * @return descriptive name for this filter
+ */
+ virtual std::string name() const = 0;
+
+ /**
+ * Write a portion of a message to this filter.
+ * @param input the input as a byte array
+ * @param length the length of the byte array input
+ */
+ virtual void write(const uint8_t input[], size_t length) = 0;
+
+ /**
+ * Start a new message. Must be closed by end_msg() before another
+ * message can be started.
+ */
+ virtual void start_msg() { /* default empty */ }
+
+ /**
+ * Notify that the current message is finished; flush buffers and
+ * do end-of-message processing (if any).
+ */
+ virtual void end_msg() { /* default empty */ }
+
+ /**
+ * Check whether this filter is an attachable filter.
+ * @return true if this filter is attachable, false otherwise
+ */
+ virtual bool attachable() { return true; }
+
+ virtual ~Filter() = default;
+ protected:
+ /**
+ * @param in some input for the filter
+ * @param length the length of in
+ */
+ virtual void send(const uint8_t in[], size_t length);
+
+ /**
+ * @param in some input for the filter
+ */
+ void send(uint8_t in) { send(&in, 1); }
+
+ /**
+ * @param in some input for the filter
+ */
+ void send(const secure_vector<uint8_t>& in) { send(in.data(), in.size()); }
+
+ /**
+ * @param in some input for the filter
+ */
+ void send(const std::vector<uint8_t>& in) { send(in.data(), in.size()); }
+
+ /**
+ * @param in some input for the filter
+ * @param length the number of bytes of in to send
+ */
+ void send(const secure_vector<uint8_t>& in, size_t length)
+ {
+ send(in.data(), length);
+ }
+
+ /**
+ * @param in some input for the filter
+ * @param length the number of bytes of in to send
+ */
+ void send(const std::vector<uint8_t>& in, size_t length)
+ {
+ send(in.data(), length);
+ }
+
+ Filter();
+
+ Filter(const Filter&) = delete;
+
+ Filter& operator=(const Filter&) = delete;
+
+ private:
+ /**
+ * Start a new message in *this and all following filters. Only for
+ * internal use, not intended for use in client applications.
+ */
+ void new_msg();
+
+ /**
+ * End a new message in *this and all following filters. Only for
+ * internal use, not intended for use in client applications.
+ */
+ void finish_msg();
+
+ friend class Pipe;
+ friend class Fanout_Filter;
+
+ size_t total_ports() const;
+ size_t current_port() const { return m_port_num; }
+
+ /**
+ * Set the active port
+ * @param new_port the new value
+ */
+ void set_port(size_t new_port);
+
+ size_t owns() const { return m_filter_owns; }
+
+ /**
+ * Attach another filter to this one
+ * @param f filter to attach
+ */
+ void attach(Filter* f);
+
+ /**
+ * @param filters the filters to set
+ * @param count number of items in filters
+ */
+ void set_next(Filter* filters[], size_t count);
+ Filter* get_next() const;
+
+ secure_vector<uint8_t> m_write_queue;
+ std::vector<Filter*> m_next; // not owned
+ size_t m_port_num, m_filter_owns;
+
+ // true if filter belongs to a pipe --> prohibit filter sharing!
+ bool m_owned;
+ };
+
+/**
+* This is the abstract Fanout_Filter base class.
+**/
+class BOTAN_PUBLIC_API(2,0) Fanout_Filter : public Filter
+ {
+ protected:
+ /**
+ * Increment the number of filters past us that we own
+ */
+ void incr_owns() { ++m_filter_owns; }
+
+ void set_port(size_t n) { Filter::set_port(n); }
+
+ void set_next(Filter* f[], size_t n) { Filter::set_next(f, n); }
+
+ void attach(Filter* f) { Filter::attach(f); }
+
+ private:
+ friend class Threaded_Fork;
+ using Filter::m_write_queue;
+ using Filter::total_ports;
+ using Filter::m_next;
+ };
+
+/**
+* The type of checking to be performed by decoders:
+* NONE - no checks, IGNORE_WS - perform checks, but ignore
+* whitespaces, FULL_CHECK - perform checks, also complain
+* about white spaces.
+*/
+enum Decoder_Checking { NONE, IGNORE_WS, FULL_CHECK };
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/filters.h b/src/libs/3rdparty/botan/src/lib/filters/filters.h
new file mode 100644
index 00000000000..b4aee12078f
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/filters.h
@@ -0,0 +1,227 @@
+/*
+* Filters
+* (C) 1999-2007,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_FILTERS_H_
+#define BOTAN_FILTERS_H_
+
+#include <botan/basefilt.h>
+#include <botan/key_filt.h>
+#include <botan/data_snk.h>
+#include <botan/pipe.h>
+
+#if defined(BOTAN_HAS_STREAM_CIPHER)
+ #include <botan/stream_cipher.h>
+#endif
+
+#if defined(BOTAN_HAS_HASH)
+ #include <botan/hash.h>
+#endif
+
+#if defined(BOTAN_HAS_MAC)
+ #include <botan/mac.h>
+#endif
+
+#if defined(BOTAN_HAS_CODEC_FILTERS)
+ #include <botan/b64_filt.h>
+ #include <botan/hex_filt.h>
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_STREAM_CIPHER)
+
+/**
+* Stream Cipher Filter
+*/
+class BOTAN_PUBLIC_API(2,0) StreamCipher_Filter final : public Keyed_Filter
+ {
+ public:
+
+ std::string name() const override { return m_cipher->name(); }
+
+ /**
+ * Write input data
+ * @param input data
+ * @param input_len length of input in bytes
+ */
+ void write(const uint8_t input[], size_t input_len) override;
+
+ bool valid_iv_length(size_t iv_len) const override
+ { return m_cipher->valid_iv_length(iv_len); }
+
+ /**
+ * Set the initialization vector for this filter.
+ * @param iv the initialization vector to set
+ */
+ void set_iv(const InitializationVector& iv) override
+ {
+ m_cipher->set_iv(iv.begin(), iv.length());
+ }
+
+ /**
+ * Set the key of this filter.
+ * @param key the key to set
+ */
+ void set_key(const SymmetricKey& key) override { m_cipher->set_key(key); }
+
+ Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); }
+
+ /**
+ * Construct a stream cipher filter.
+ * @param cipher a cipher object to use
+ */
+ explicit StreamCipher_Filter(StreamCipher* cipher);
+
+ /**
+ * Construct a stream cipher filter.
+ * @param cipher a cipher object to use
+ * @param key the key to use inside this filter
+ */
+ StreamCipher_Filter(StreamCipher* cipher, const SymmetricKey& key);
+
+ /**
+ * Construct a stream cipher filter.
+ * @param cipher the name of the desired cipher
+ */
+ explicit StreamCipher_Filter(const std::string& cipher);
+
+ /**
+ * Construct a stream cipher filter.
+ * @param cipher the name of the desired cipher
+ * @param key the key to use inside this filter
+ */
+ StreamCipher_Filter(const std::string& cipher, const SymmetricKey& key);
+ private:
+ secure_vector<uint8_t> m_buffer;
+ std::unique_ptr<StreamCipher> m_cipher;
+ };
+#endif
+
+#if defined(BOTAN_HAS_HASH)
+
+/**
+* Hash Filter.
+*/
+class BOTAN_PUBLIC_API(2,0) Hash_Filter final : public Filter
+ {
+ public:
+ void write(const uint8_t input[], size_t len) override { m_hash->update(input, len); }
+ void end_msg() override;
+
+ std::string name() const override { return m_hash->name(); }
+
+ /**
+ * Construct a hash filter.
+ * @param hash the hash function to use
+ * @param len the output length of this filter. Leave the default
+ * value 0 if you want to use the full output of the hashfunction
+ * hash. Otherwise, specify a smaller value here so that the
+ * output of the hash algorithm will be cut off.
+ */
+ Hash_Filter(HashFunction* hash, size_t len = 0) :
+ m_hash(hash), m_out_len(len) {}
+
+ /**
+ * Construct a hash filter.
+ * @param request the name of the hash algorithm to use
+ * @param len the output length of this filter. Leave the default
+ * value 0 if you want to use the full output of the hashfunction
+ * hash. Otherwise, specify a smaller value here so that the
+ * output of the hash algorithm will be cut off.
+ */
+ Hash_Filter(const std::string& request, size_t len = 0);
+
+ private:
+ std::unique_ptr<HashFunction> m_hash;
+ const size_t m_out_len;
+ };
+#endif
+
+#if defined(BOTAN_HAS_MAC)
+
+/**
+* MessageAuthenticationCode Filter.
+*/
+class BOTAN_PUBLIC_API(2,0) MAC_Filter final : public Keyed_Filter
+ {
+ public:
+ void write(const uint8_t input[], size_t len) override { m_mac->update(input, len); }
+ void end_msg() override;
+
+ std::string name() const override { return m_mac->name(); }
+
+ /**
+ * Set the key of this filter.
+ * @param key the key to set
+ */
+ void set_key(const SymmetricKey& key) override { m_mac->set_key(key); }
+
+ Key_Length_Specification key_spec() const override { return m_mac->key_spec(); }
+
+ /**
+ * Construct a MAC filter. The MAC key will be left empty.
+ * @param mac the MAC to use
+ * @param out_len the output length of this filter. Leave the default
+ * value 0 if you want to use the full output of the
+ * MAC. Otherwise, specify a smaller value here so that the
+ * output of the MAC will be cut off.
+ */
+ MAC_Filter(MessageAuthenticationCode* mac,
+ size_t out_len = 0) :
+ m_mac(mac),
+ m_out_len(out_len)
+ {
+ }
+
+ /**
+ * Construct a MAC filter.
+ * @param mac the MAC to use
+ * @param key the MAC key to use
+ * @param out_len the output length of this filter. Leave the default
+ * value 0 if you want to use the full output of the
+ * MAC. Otherwise, specify a smaller value here so that the
+ * output of the MAC will be cut off.
+ */
+ MAC_Filter(MessageAuthenticationCode* mac,
+ const SymmetricKey& key,
+ size_t out_len = 0) :
+ m_mac(mac),
+ m_out_len(out_len)
+ {
+ m_mac->set_key(key);
+ }
+
+ /**
+ * Construct a MAC filter. The MAC key will be left empty.
+ * @param mac the name of the MAC to use
+ * @param len the output length of this filter. Leave the default
+ * value 0 if you want to use the full output of the
+ * MAC. Otherwise, specify a smaller value here so that the
+ * output of the MAC will be cut off.
+ */
+ MAC_Filter(const std::string& mac, size_t len = 0);
+
+ /**
+ * Construct a MAC filter.
+ * @param mac the name of the MAC to use
+ * @param key the MAC key to use
+ * @param len the output length of this filter. Leave the default
+ * value 0 if you want to use the full output of the
+ * MAC. Otherwise, specify a smaller value here so that the
+ * output of the MAC will be cut off.
+ */
+ MAC_Filter(const std::string& mac, const SymmetricKey& key,
+ size_t len = 0);
+ private:
+ std::unique_ptr<MessageAuthenticationCode> m_mac;
+ const size_t m_out_len;
+ };
+#endif
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/info.txt b/src/libs/3rdparty/botan/src/lib/filters/info.txt
new file mode 100644
index 00000000000..cfc11435369
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/info.txt
@@ -0,0 +1,24 @@
+<defines>
+FILTERS -> 20160415
+</defines>
+
+<header:public>
+basefilt.h
+buf_filt.h
+data_snk.h
+comp_filter.h
+filter.h
+filters.h
+key_filt.h
+pipe.h
+secqueue.h
+cipher_filter.h
+</header:public>
+
+<header:internal>
+out_buf.h
+</header:internal>
+
+<requires>
+modes
+</requires>
diff --git a/src/libs/3rdparty/botan/src/lib/filters/key_filt.cpp b/src/libs/3rdparty/botan/src/lib/filters/key_filt.cpp
new file mode 100644
index 00000000000..b87a8c87f33
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/key_filt.cpp
@@ -0,0 +1,39 @@
+/*
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/key_filt.h>
+#include <botan/cipher_filter.h>
+
+namespace Botan {
+
+Keyed_Filter* get_cipher(const std::string& algo_spec,
+ Cipher_Dir direction)
+ {
+ std::unique_ptr<Cipher_Mode> c(Cipher_Mode::create_or_throw(algo_spec, direction));
+ return new Cipher_Mode_Filter(c.release());
+ }
+
+Keyed_Filter* get_cipher(const std::string& algo_spec,
+ const SymmetricKey& key,
+ const InitializationVector& iv,
+ Cipher_Dir direction)
+ {
+ Keyed_Filter* cipher = get_cipher(algo_spec, key, direction);
+ if(iv.length())
+ cipher->set_iv(iv);
+ return cipher;
+ }
+
+Keyed_Filter* get_cipher(const std::string& algo_spec,
+ const SymmetricKey& key,
+ Cipher_Dir direction)
+ {
+ Keyed_Filter* cipher = get_cipher(algo_spec, direction);
+ cipher->set_key(key);
+ return cipher;
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/key_filt.h b/src/libs/3rdparty/botan/src/lib/filters/key_filt.h
new file mode 100644
index 00000000000..67b689f9984
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/key_filt.h
@@ -0,0 +1,109 @@
+/*
+* Keyed_Filter
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_KEYED_FILTER_H_
+#define BOTAN_KEYED_FILTER_H_
+
+#include <botan/symkey.h>
+#include <botan/filter.h>
+#include <botan/cipher_mode.h>
+
+namespace Botan {
+
+/**
+* This class represents keyed filters, i.e. filters that have to be
+* fed with a key in order to function.
+*/
+class BOTAN_PUBLIC_API(2,0) Keyed_Filter : public Filter
+ {
+ public:
+ /**
+ * Set the key of this filter
+ * @param key the key to use
+ */
+ virtual void set_key(const SymmetricKey& key) = 0;
+
+ /**
+ * Set the initialization vector of this filter. Note: you should
+ * call set_iv() only after you have called set_key()
+ * @param iv the initialization vector to use
+ */
+ virtual void set_iv(const InitializationVector& iv);
+
+ /**
+ * Check whether a key length is valid for this filter
+ * @param length the key length to be checked for validity
+ * @return true if the key length is valid, false otherwise
+ */
+ bool valid_keylength(size_t length) const
+ {
+ return key_spec().valid_keylength(length);
+ }
+
+ /**
+ * @return object describing limits on key size
+ */
+ virtual Key_Length_Specification key_spec() const = 0;
+
+ /**
+ * Check whether an IV length is valid for this filter
+ * @param length the IV length to be checked for validity
+ * @return true if the IV length is valid, false otherwise
+ */
+ virtual bool valid_iv_length(size_t length) const
+ { return (length == 0); }
+ };
+
+
+
+/*
+* Get a cipher object
+*/
+
+/**
+* Factory method for general symmetric cipher filters.
+* @param algo_spec the name of the desired cipher
+* @param key the key to be used for encryption/decryption performed by
+* the filter
+* @param iv the initialization vector to be used
+* @param direction determines whether the filter will be an encrypting
+* or decrypting filter
+* @return pointer to newly allocated encryption or decryption filter
+*/
+BOTAN_PUBLIC_API(2,0) Keyed_Filter* get_cipher(const std::string& algo_spec,
+ const SymmetricKey& key,
+ const InitializationVector& iv,
+ Cipher_Dir direction);
+
+/**
+* Factory method for general symmetric cipher filters.
+* @param algo_spec the name of the desired cipher
+* @param key the key to be used for encryption/decryption performed by
+* the filter
+* @param direction determines whether the filter will be an encrypting
+* or decrypting filter
+* @return pointer to the encryption or decryption filter
+*/
+BOTAN_PUBLIC_API(2,0) Keyed_Filter* get_cipher(const std::string& algo_spec,
+ const SymmetricKey& key,
+ Cipher_Dir direction);
+
+/**
+* Factory method for general symmetric cipher filters. No key will be
+* set in the filter.
+*
+* @param algo_spec the name of the desired cipher
+* @param direction determines whether the filter will be an encrypting or
+* decrypting filter
+* @return pointer to the encryption or decryption filter
+*/
+BOTAN_PUBLIC_API(2,0) Keyed_Filter* get_cipher(const std::string& algo_spec,
+ Cipher_Dir direction);
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/out_buf.cpp b/src/libs/3rdparty/botan/src/lib/filters/out_buf.cpp
new file mode 100644
index 00000000000..645cc082365
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/out_buf.cpp
@@ -0,0 +1,121 @@
+/*
+* Pipe Output Buffer
+* (C) 1999-2007,2011 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/out_buf.h>
+#include <botan/secqueue.h>
+
+namespace Botan {
+
+/*
+* Read data from a message
+*/
+size_t Output_Buffers::read(uint8_t output[], size_t length,
+ Pipe::message_id msg)
+ {
+ SecureQueue* q = get(msg);
+ if(q)
+ return q->read(output, length);
+ return 0;
+ }
+
+/*
+* Peek at data in a message
+*/
+size_t Output_Buffers::peek(uint8_t output[], size_t length,
+ size_t stream_offset,
+ Pipe::message_id msg) const
+ {
+ SecureQueue* q = get(msg);
+ if(q)
+ return q->peek(output, length, stream_offset);
+ return 0;
+ }
+
+/*
+* Check available bytes in a message
+*/
+size_t Output_Buffers::remaining(Pipe::message_id msg) const
+ {
+ SecureQueue* q = get(msg);
+ if(q)
+ return q->size();
+ return 0;
+ }
+
+/*
+* Return the total bytes of a message that have already been read.
+*/
+size_t Output_Buffers::get_bytes_read(Pipe::message_id msg) const
+ {
+ SecureQueue* q = get(msg);
+ if (q)
+ return q->get_bytes_read();
+ return 0;
+ }
+
+/*
+* Add a new output queue
+*/
+void Output_Buffers::add(SecureQueue* queue)
+ {
+ BOTAN_ASSERT(queue, "queue was provided");
+
+ BOTAN_ASSERT(m_buffers.size() < m_buffers.max_size(),
+ "Room was available in container");
+
+ m_buffers.push_back(std::unique_ptr<SecureQueue>(queue));
+ }
+
+/*
+* Retire old output queues
+*/
+void Output_Buffers::retire()
+ {
+ for(size_t i = 0; i != m_buffers.size(); ++i)
+ if(m_buffers[i] && m_buffers[i]->size() == 0)
+ {
+ m_buffers[i].reset();
+ }
+
+ while(m_buffers.size() && !m_buffers[0])
+ {
+ m_buffers.pop_front();
+ m_offset = m_offset + Pipe::message_id(1);
+ }
+ }
+
+/*
+* Get a particular output queue
+*/
+SecureQueue* Output_Buffers::get(Pipe::message_id msg) const
+ {
+ if(msg < m_offset)
+ return nullptr;
+
+ BOTAN_ASSERT(msg < message_count(), "Message number is in range");
+
+ return m_buffers[msg-m_offset].get();
+ }
+
+/*
+* Return the total number of messages
+*/
+Pipe::message_id Output_Buffers::message_count() const
+ {
+ return (m_offset + m_buffers.size());
+ }
+
+/*
+* Output_Buffers Constructor
+*/
+Output_Buffers::Output_Buffers()
+ {
+ m_offset = 0;
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/out_buf.h b/src/libs/3rdparty/botan/src/lib/filters/out_buf.h
new file mode 100644
index 00000000000..d6efbdaf270
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/out_buf.h
@@ -0,0 +1,44 @@
+/*
+* Output Buffer
+* (C) 1999-2007 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_OUTPUT_BUFFER_H_
+#define BOTAN_OUTPUT_BUFFER_H_
+
+#include <botan/types.h>
+#include <botan/pipe.h>
+#include <deque>
+
+namespace Botan {
+
+/**
+* Container of output buffers for Pipe
+*/
+class Output_Buffers final
+ {
+ public:
+ size_t read(uint8_t[], size_t, Pipe::message_id);
+ size_t peek(uint8_t[], size_t, size_t, Pipe::message_id) const;
+ size_t get_bytes_read(Pipe::message_id) const;
+ size_t remaining(Pipe::message_id) const;
+
+ void add(class SecureQueue*);
+ void retire();
+
+ Pipe::message_id message_count() const;
+
+ Output_Buffers();
+ private:
+ class SecureQueue* get(Pipe::message_id) const;
+
+ std::deque<std::unique_ptr<SecureQueue>> m_buffers;
+ Pipe::message_id m_offset;
+ };
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe.cpp b/src/libs/3rdparty/botan/src/lib/filters/pipe.cpp
new file mode 100644
index 00000000000..0bba81bf2d8
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/pipe.cpp
@@ -0,0 +1,311 @@
+/*
+* Pipe
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/pipe.h>
+#include <botan/internal/out_buf.h>
+#include <botan/secqueue.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* A Filter that does nothing
+*/
+class Null_Filter final : public Filter
+ {
+ public:
+ void write(const uint8_t input[], size_t length) override
+ { send(input, length); }
+
+ std::string name() const override { return "Null"; }
+ };
+
+}
+
+/*
+* Pipe Constructor
+*/
+Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) :
+ Pipe({f1,f2,f3,f4})
+ {
+ }
+
+/*
+* Pipe Constructor
+*/
+Pipe::Pipe(std::initializer_list<Filter*> args)
+ {
+ m_outputs.reset(new Output_Buffers);
+ m_pipe = nullptr;
+ m_default_read = 0;
+ m_inside_msg = false;
+
+ for(auto i = args.begin(); i != args.end(); ++i)
+ do_append(*i);
+ }
+
+/*
+* Pipe Destructor
+*/
+Pipe::~Pipe()
+ {
+ destruct(m_pipe);
+ }
+
+/*
+* Reset the Pipe
+*/
+void Pipe::reset()
+ {
+ destruct(m_pipe);
+ m_pipe = nullptr;
+ m_inside_msg = false;
+ }
+
+/*
+* Destroy the Pipe
+*/
+void Pipe::destruct(Filter* to_kill)
+ {
+ if(!to_kill || dynamic_cast<SecureQueue*>(to_kill))
+ return;
+ for(size_t j = 0; j != to_kill->total_ports(); ++j)
+ destruct(to_kill->m_next[j]);
+ delete to_kill;
+ }
+
+/*
+* Test if the Pipe has any data in it
+*/
+bool Pipe::end_of_data() const
+ {
+ return (remaining() == 0);
+ }
+
+/*
+* Set the default read message
+*/
+void Pipe::set_default_msg(message_id msg)
+ {
+ if(msg >= message_count())
+ throw Invalid_Argument("Pipe::set_default_msg: msg number is too high");
+ m_default_read = msg;
+ }
+
+/*
+* Process a full message at once
+*/
+void Pipe::process_msg(const uint8_t input[], size_t length)
+ {
+ start_msg();
+ write(input, length);
+ end_msg();
+ }
+
+/*
+* Process a full message at once
+*/
+void Pipe::process_msg(const secure_vector<uint8_t>& input)
+ {
+ process_msg(input.data(), input.size());
+ }
+
+void Pipe::process_msg(const std::vector<uint8_t>& input)
+ {
+ process_msg(input.data(), input.size());
+ }
+
+/*
+* Process a full message at once
+*/
+void Pipe::process_msg(const std::string& input)
+ {
+ process_msg(cast_char_ptr_to_uint8(input.data()), input.length());
+ }
+
+/*
+* Process a full message at once
+*/
+void Pipe::process_msg(DataSource& input)
+ {
+ start_msg();
+ write(input);
+ end_msg();
+ }
+
+/*
+* Start a new message
+*/
+void Pipe::start_msg()
+ {
+ if(m_inside_msg)
+ throw Invalid_State("Pipe::start_msg: Message was already started");
+ if(m_pipe == nullptr)
+ m_pipe = new Null_Filter;
+ find_endpoints(m_pipe);
+ m_pipe->new_msg();
+ m_inside_msg = true;
+ }
+
+/*
+* End the current message
+*/
+void Pipe::end_msg()
+ {
+ if(!m_inside_msg)
+ throw Invalid_State("Pipe::end_msg: Message was already ended");
+ m_pipe->finish_msg();
+ clear_endpoints(m_pipe);
+ if(dynamic_cast<Null_Filter*>(m_pipe))
+ {
+ delete m_pipe;
+ m_pipe = nullptr;
+ }
+ m_inside_msg = false;
+
+ m_outputs->retire();
+ }
+
+/*
+* Find the endpoints of the Pipe
+*/
+void Pipe::find_endpoints(Filter* f)
+ {
+ for(size_t j = 0; j != f->total_ports(); ++j)
+ if(f->m_next[j] && !dynamic_cast<SecureQueue*>(f->m_next[j]))
+ find_endpoints(f->m_next[j]);
+ else
+ {
+ SecureQueue* q = new SecureQueue;
+ f->m_next[j] = q;
+ m_outputs->add(q);
+ }
+ }
+
+/*
+* Remove the SecureQueues attached to the Filter
+*/
+void Pipe::clear_endpoints(Filter* f)
+ {
+ if(!f) return;
+ for(size_t j = 0; j != f->total_ports(); ++j)
+ {
+ if(f->m_next[j] && dynamic_cast<SecureQueue*>(f->m_next[j]))
+ f->m_next[j] = nullptr;
+ clear_endpoints(f->m_next[j]);
+ }
+ }
+
+void Pipe::append(Filter* filter)
+ {
+ do_append(filter);
+ }
+
+void Pipe::append_filter(Filter* filter)
+ {
+ if(m_outputs->message_count() != 0)
+ throw Invalid_State("Cannot call Pipe::append_filter after start_msg");
+
+ do_append(filter);
+ }
+
+void Pipe::prepend(Filter* filter)
+ {
+ do_prepend(filter);
+ }
+
+void Pipe::prepend_filter(Filter* filter)
+ {
+ if(m_outputs->message_count() != 0)
+ throw Invalid_State("Cannot call Pipe::prepend_filter after start_msg");
+
+ do_prepend(filter);
+ }
+
+/*
+* Append a Filter to the Pipe
+*/
+void Pipe::do_append(Filter* filter)
+ {
+ if(!filter)
+ return;
+ if(dynamic_cast<SecureQueue*>(filter))
+ throw Invalid_Argument("Pipe::append: SecureQueue cannot be used");
+ if(filter->m_owned)
+ throw Invalid_Argument("Filters cannot be shared among multiple Pipes");
+
+ if(m_inside_msg)
+ throw Invalid_State("Cannot append to a Pipe while it is processing");
+
+ filter->m_owned = true;
+
+ if(!m_pipe) m_pipe = filter;
+ else m_pipe->attach(filter);
+ }
+
+/*
+* Prepend a Filter to the Pipe
+*/
+void Pipe::do_prepend(Filter* filter)
+ {
+ if(m_inside_msg)
+ throw Invalid_State("Cannot prepend to a Pipe while it is processing");
+ if(!filter)
+ return;
+ if(dynamic_cast<SecureQueue*>(filter))
+ throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used");
+ if(filter->m_owned)
+ throw Invalid_Argument("Filters cannot be shared among multiple Pipes");
+
+ filter->m_owned = true;
+
+ if(m_pipe) filter->attach(m_pipe);
+ m_pipe = filter;
+ }
+
+/*
+* Pop a Filter off the Pipe
+*/
+void Pipe::pop()
+ {
+ if(m_inside_msg)
+ throw Invalid_State("Cannot pop off a Pipe while it is processing");
+
+ if(!m_pipe)
+ return;
+
+ if(m_pipe->total_ports() > 1)
+ throw Invalid_State("Cannot pop off a Filter with multiple ports");
+
+ size_t to_remove = m_pipe->owns() + 1;
+
+ while(to_remove--)
+ {
+ std::unique_ptr<Filter> to_destroy(m_pipe);
+ m_pipe = m_pipe->m_next[0];
+ }
+ }
+
+/*
+* Return the number of messages in this Pipe
+*/
+Pipe::message_id Pipe::message_count() const
+ {
+ return m_outputs->message_count();
+ }
+
+/*
+* Static Member Variables
+*/
+const Pipe::message_id Pipe::LAST_MESSAGE =
+ static_cast<Pipe::message_id>(-2);
+
+const Pipe::message_id Pipe::DEFAULT_MESSAGE =
+ static_cast<Pipe::message_id>(-1);
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe.h b/src/libs/3rdparty/botan/src/lib/filters/pipe.h
new file mode 100644
index 00000000000..03b5160835f
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/pipe.h
@@ -0,0 +1,379 @@
+/*
+* Pipe
+* (C) 1999-2007 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_PIPE_H_
+#define BOTAN_PIPE_H_
+
+#include <botan/data_src.h>
+#include <botan/exceptn.h>
+#include <initializer_list>
+#include <iosfwd>
+
+namespace Botan {
+
+class Filter;
+class Output_Buffers;
+
+/**
+* This class represents pipe objects.
+* A set of filters can be placed into a pipe, and information flows
+* through the pipe until it reaches the end, where the output is
+* collected for retrieval. If you're familiar with the Unix shell
+* environment, this design will sound quite familiar.
+*/
+class BOTAN_PUBLIC_API(2,0) Pipe final : public DataSource
+ {
+ public:
+ /**
+ * An opaque type that identifies a message in this Pipe
+ */
+ typedef size_t message_id;
+
+ /**
+ * Exception if you use an invalid message as an argument to
+ * read, remaining, etc
+ */
+ class BOTAN_PUBLIC_API(2,0) Invalid_Message_Number final : public Invalid_Argument
+ {
+ public:
+ /**
+ * @param where the error occurred
+ * @param msg the invalid message id that was used
+ */
+ Invalid_Message_Number(const std::string& where, message_id msg) :
+ Invalid_Argument("Pipe::" + where + ": Invalid message number " +
+ std::to_string(msg))
+ {}
+ };
+
+ /**
+ * A meta-id for whatever the last message is
+ */
+ static const message_id LAST_MESSAGE;
+
+ /**
+ * A meta-id for the default message (set with set_default_msg)
+ */
+ static const message_id DEFAULT_MESSAGE;
+
+ /**
+ * Write input to the pipe, i.e. to its first filter.
+ * @param in the byte array to write
+ * @param length the length of the byte array in
+ */
+ void write(const uint8_t in[], size_t length);
+
+ /**
+ * Write input to the pipe, i.e. to its first filter.
+ * @param in the secure_vector containing the data to write
+ */
+ void write(const secure_vector<uint8_t>& in)
+ { write(in.data(), in.size()); }
+
+ /**
+ * Write input to the pipe, i.e. to its first filter.
+ * @param in the std::vector containing the data to write
+ */
+ void write(const std::vector<uint8_t>& in)
+ { write(in.data(), in.size()); }
+
+ /**
+ * Write input to the pipe, i.e. to its first filter.
+ * @param in the string containing the data to write
+ */
+ void write(const std::string& in);
+
+ /**
+ * Write input to the pipe, i.e. to its first filter.
+ * @param in the DataSource to read the data from
+ */
+ void write(DataSource& in);
+
+ /**
+ * Write input to the pipe, i.e. to its first filter.
+ * @param in a single byte to be written
+ */
+ void write(uint8_t in);
+
+ /**
+ * Perform start_msg(), write() and end_msg() sequentially.
+ * @param in the byte array containing the data to write
+ * @param length the length of the byte array to write
+ */
+ void process_msg(const uint8_t in[], size_t length);
+
+ /**
+ * Perform start_msg(), write() and end_msg() sequentially.
+ * @param in the secure_vector containing the data to write
+ */
+ void process_msg(const secure_vector<uint8_t>& in);
+
+ /**
+ * Perform start_msg(), write() and end_msg() sequentially.
+ * @param in the secure_vector containing the data to write
+ */
+ void process_msg(const std::vector<uint8_t>& in);
+
+ /**
+ * Perform start_msg(), write() and end_msg() sequentially.
+ * @param in the string containing the data to write
+ */
+ void process_msg(const std::string& in);
+
+ /**
+ * Perform start_msg(), write() and end_msg() sequentially.
+ * @param in the DataSource providing the data to write
+ */
+ void process_msg(DataSource& in);
+
+ /**
+ * Find out how many bytes are ready to read.
+ * @param msg the number identifying the message
+ * for which the information is desired
+ * @return number of bytes that can still be read
+ */
+ size_t remaining(message_id msg = DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT;
+
+ /**
+ * Read the default message from the pipe. Moves the internal
+ * offset so that every call to read will return a new portion of
+ * the message.
+ *
+ * @param output the byte array to write the read bytes to
+ * @param length the length of the byte array output
+ * @return number of bytes actually read into output
+ */
+ size_t read(uint8_t output[], size_t length) override BOTAN_WARN_UNUSED_RESULT;
+
+ /**
+ * Read a specified message from the pipe. Moves the internal
+ * offset so that every call to read will return a new portion of
+ * the message.
+ * @param output the byte array to write the read bytes to
+ * @param length the length of the byte array output
+ * @param msg the number identifying the message to read from
+ * @return number of bytes actually read into output
+ */
+ size_t read(uint8_t output[], size_t length, message_id msg) BOTAN_WARN_UNUSED_RESULT;
+
+ /**
+ * Read a single byte from the pipe. Moves the internal offset so
+ * that every call to read will return a new portion of the
+ * message.
+ *
+ * @param output the byte to write the result to
+ * @param msg the message to read from
+ * @return number of bytes actually read into output
+ */
+ size_t read(uint8_t& output, message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT;
+
+ /**
+ * Read the full contents of the pipe.
+ * @param msg the number identifying the message to read from
+ * @return secure_vector holding the contents of the pipe
+ */
+ secure_vector<uint8_t> read_all(message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT;
+
+ /**
+ * Read the full contents of the pipe.
+ * @param msg the number identifying the message to read from
+ * @return string holding the contents of the pipe
+ */
+ std::string read_all_as_string(message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT;
+
+ /**
+ * Read from the default message but do not modify the internal
+ * offset. Consecutive calls to peek() will return portions of
+ * the message starting at the same position.
+ * @param output the byte array to write the peeked message part to
+ * @param length the length of the byte array output
+ * @param offset the offset from the current position in message
+ * @return number of bytes actually peeked and written into output
+ */
+ size_t peek(uint8_t output[], size_t length, size_t offset) const override BOTAN_WARN_UNUSED_RESULT;
+
+ /** Read from the specified message but do not modify the
+ * internal offset. Consecutive calls to peek() will return
+ * portions of the message starting at the same position.
+ * @param output the byte array to write the peeked message part to
+ * @param length the length of the byte array output
+ * @param offset the offset from the current position in message
+ * @param msg the number identifying the message to peek from
+ * @return number of bytes actually peeked and written into output
+ */
+ size_t peek(uint8_t output[], size_t length,
+ size_t offset, message_id msg) const BOTAN_WARN_UNUSED_RESULT;
+
+ /** Read a single byte from the specified message but do not
+ * modify the internal offset. Consecutive calls to peek() will
+ * return portions of the message starting at the same position.
+ * @param output the byte to write the peeked message byte to
+ * @param offset the offset from the current position in message
+ * @param msg the number identifying the message to peek from
+ * @return number of bytes actually peeked and written into output
+ */
+ size_t peek(uint8_t& output, size_t offset,
+ message_id msg = DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT;
+
+ /**
+ * @return the number of bytes read from the default message.
+ */
+ size_t get_bytes_read() const override;
+
+ /**
+ * @return the number of bytes read from the specified message.
+ */
+ size_t get_bytes_read(message_id msg) const;
+
+ bool check_available(size_t n) override;
+ bool check_available_msg(size_t n, message_id msg);
+
+ /**
+ * @return currently set default message
+ */
+ size_t default_msg() const { return m_default_read; }
+
+ /**
+ * Set the default message
+ * @param msg the number identifying the message which is going to
+ * be the new default message
+ */
+ void set_default_msg(message_id msg);
+
+ /**
+ * Get the number of messages the are in this pipe.
+ * @return number of messages the are in this pipe
+ */
+ message_id message_count() const;
+
+ /**
+ * Test whether this pipe has any data that can be read from.
+ * @return true if there is more data to read, false otherwise
+ */
+ bool end_of_data() const override;
+
+ /**
+ * Start a new message in the pipe. A potential other message in this pipe
+ * must be closed with end_msg() before this function may be called.
+ */
+ void start_msg();
+
+ /**
+ * End the current message.
+ */
+ void end_msg();
+
+ /**
+ * Insert a new filter at the front of the pipe
+ * Deprecated because runtime modification of Pipes is deprecated.
+ * You can instead use prepend_filter which only works before the first
+ * message is processed.
+ * @param filt the new filter to insert
+ */
+ BOTAN_DEPRECATED("Runtime modification of Pipe deprecated")
+ void prepend(Filter* filt);
+
+ /**
+ * Insert a new filter at the back of the pipe
+ * Deprecated because runtime modification of Pipes is deprecated.
+ * You can instead use append_filter which only works before the first
+ * message is processed.
+ * @param filt the new filter to insert
+ */
+ BOTAN_DEPRECATED("Runtime modification of Pipe deprecated")
+ void append(Filter* filt);
+
+ /**
+ * Remove the first filter at the front of the pipe.
+ */
+ BOTAN_DEPRECATED("Runtime modification of Pipe deprecated")
+ void pop();
+
+ /**
+ * Reset this pipe to an empty pipe.
+ */
+ BOTAN_DEPRECATED("Runtime modification of Pipe deprecated")
+ void reset();
+
+ /**
+ * Append a new filter onto the filter sequence. This may only be
+ * called immediately after initial construction, before _any_
+ * calls to start_msg have been made.
+ *
+ * This function (unlike append) is not deprecated, as it allows
+ * only modification of the pipe at initialization (before use)
+ * rather than after messages have been processed.
+ */
+ void append_filter(Filter* filt);
+
+ /**
+ * Prepend a new filter onto the filter sequence. This may only be
+ * called immediately after initial construction, before _any_
+ * calls to start_msg have been made.
+ *
+ * This function (unlike prepend) is not deprecated, as it allows
+ * only modification of the pipe at initialization (before use)
+ * rather than after messages have been processed.
+ */
+ void prepend_filter(Filter* filt);
+
+ /**
+ * Construct a Pipe of up to four filters. The filters are set up
+ * in the same order as the arguments.
+ */
+ Pipe(Filter* = nullptr, Filter* = nullptr,
+ Filter* = nullptr, Filter* = nullptr);
+
+ /**
+ * Construct a Pipe from a list of filters
+ * @param filters the set of filters to use
+ */
+ explicit Pipe(std::initializer_list<Filter*> filters);
+
+ Pipe(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&) = delete;
+
+ ~Pipe();
+ private:
+ void destruct(Filter*);
+ void do_append(Filter* filt);
+ void do_prepend(Filter* filt);
+ void find_endpoints(Filter*);
+ void clear_endpoints(Filter*);
+
+ message_id get_message_no(const std::string&, message_id) const;
+
+ Filter* m_pipe;
+ std::unique_ptr<Output_Buffers> m_outputs;
+ message_id m_default_read;
+ bool m_inside_msg;
+ };
+
+/**
+* Stream output operator; dumps the results from pipe's default
+* message to the output stream.
+* @param out an output stream
+* @param pipe the pipe
+*/
+BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& out, Pipe& pipe);
+
+/**
+* Stream input operator; dumps the remaining bytes of input
+* to the (assumed open) pipe message.
+* @param in the input stream
+* @param pipe the pipe
+*/
+BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream& in, Pipe& pipe);
+
+}
+
+#if defined(BOTAN_HAS_PIPE_UNIXFD_IO)
+ #include <botan/fd_unix.h>
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe_io.cpp b/src/libs/3rdparty/botan/src/lib/filters/pipe_io.cpp
new file mode 100644
index 00000000000..a909cba7259
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/pipe_io.cpp
@@ -0,0 +1,47 @@
+/*
+* Pipe I/O
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/pipe.h>
+#include <istream>
+#include <ostream>
+
+namespace Botan {
+
+/*
+* Write data from a pipe into an ostream
+*/
+std::ostream& operator<<(std::ostream& stream, Pipe& pipe)
+ {
+ secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE);
+ while(stream.good() && pipe.remaining())
+ {
+ const size_t got = pipe.read(buffer.data(), buffer.size());
+ stream.write(cast_uint8_ptr_to_char(buffer.data()), got);
+ }
+ if(!stream.good())
+ throw Stream_IO_Error("Pipe output operator (iostream) has failed");
+ return stream;
+ }
+
+/*
+* Read data from an istream into a pipe
+*/
+std::istream& operator>>(std::istream& stream, Pipe& pipe)
+ {
+ secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE);
+ while(stream.good())
+ {
+ stream.read(cast_uint8_ptr_to_char(buffer.data()), buffer.size());
+ const size_t got = static_cast<size_t>(stream.gcount());
+ pipe.write(buffer.data(), got);
+ }
+ if(stream.bad() || (stream.fail() && !stream.eof()))
+ throw Stream_IO_Error("Pipe input operator (iostream) has failed");
+ return stream;
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe_rw.cpp b/src/libs/3rdparty/botan/src/lib/filters/pipe_rw.cpp
new file mode 100644
index 00000000000..dc7b973727d
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/pipe_rw.cpp
@@ -0,0 +1,181 @@
+/*
+* Pipe Reading/Writing
+* (C) 1999-2007 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/pipe.h>
+#include <botan/filter.h>
+#include <botan/internal/out_buf.h>
+
+namespace Botan {
+
+/*
+* Look up the canonical ID for a queue
+*/
+Pipe::message_id Pipe::get_message_no(const std::string& func_name,
+ message_id msg) const
+ {
+ if(msg == DEFAULT_MESSAGE)
+ msg = default_msg();
+ else if(msg == LAST_MESSAGE)
+ msg = message_count() - 1;
+
+ if(msg >= message_count())
+ throw Invalid_Message_Number(func_name, msg);
+
+ return msg;
+ }
+
+/*
+* Write into a Pipe
+*/
+void Pipe::write(const uint8_t input[], size_t length)
+ {
+ if(!m_inside_msg)
+ throw Invalid_State("Cannot write to a Pipe while it is not processing");
+ m_pipe->write(input, length);
+ }
+
+/*
+* Write a string into a Pipe
+*/
+void Pipe::write(const std::string& str)
+ {
+ write(cast_char_ptr_to_uint8(str.data()), str.size());
+ }
+
+/*
+* Write a single byte into a Pipe
+*/
+void Pipe::write(uint8_t input)
+ {
+ write(&input, 1);
+ }
+
+/*
+* Write the contents of a DataSource into a Pipe
+*/
+void Pipe::write(DataSource& source)
+ {
+ secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE);
+ while(!source.end_of_data())
+ {
+ size_t got = source.read(buffer.data(), buffer.size());
+ write(buffer.data(), got);
+ }
+ }
+
+/*
+* Read some data from the pipe
+*/
+size_t Pipe::read(uint8_t output[], size_t length, message_id msg)
+ {
+ return m_outputs->read(output, length, get_message_no("read", msg));
+ }
+
+/*
+* Read some data from the pipe
+*/
+size_t Pipe::read(uint8_t output[], size_t length)
+ {
+ return read(output, length, DEFAULT_MESSAGE);
+ }
+
+/*
+* Read a single byte from the pipe
+*/
+size_t Pipe::read(uint8_t& out, message_id msg)
+ {
+ return read(&out, 1, msg);
+ }
+
+/*
+* Return all data in the pipe
+*/
+secure_vector<uint8_t> Pipe::read_all(message_id msg)
+ {
+ msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg());
+ secure_vector<uint8_t> buffer(remaining(msg));
+ size_t got = read(buffer.data(), buffer.size(), msg);
+ buffer.resize(got);
+ return buffer;
+ }
+
+/*
+* Return all data in the pipe as a string
+*/
+std::string Pipe::read_all_as_string(message_id msg)
+ {
+ msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg());
+ secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE);
+ std::string str;
+ str.reserve(remaining(msg));
+
+ while(true)
+ {
+ size_t got = read(buffer.data(), buffer.size(), msg);
+ if(got == 0)
+ break;
+ str.append(cast_uint8_ptr_to_char(buffer.data()), got);
+ }
+
+ return str;
+ }
+
+/*
+* Find out how many bytes are ready to read
+*/
+size_t Pipe::remaining(message_id msg) const
+ {
+ return m_outputs->remaining(get_message_no("remaining", msg));
+ }
+
+/*
+* Peek at some data in the pipe
+*/
+size_t Pipe::peek(uint8_t output[], size_t length,
+ size_t offset, message_id msg) const
+ {
+ return m_outputs->peek(output, length, offset, get_message_no("peek", msg));
+ }
+
+/*
+* Peek at some data in the pipe
+*/
+size_t Pipe::peek(uint8_t output[], size_t length, size_t offset) const
+ {
+ return peek(output, length, offset, DEFAULT_MESSAGE);
+ }
+
+/*
+* Peek at a byte in the pipe
+*/
+size_t Pipe::peek(uint8_t& out, size_t offset, message_id msg) const
+ {
+ return peek(&out, 1, offset, msg);
+ }
+
+size_t Pipe::get_bytes_read() const
+ {
+ return m_outputs->get_bytes_read(default_msg());
+ }
+
+size_t Pipe::get_bytes_read(message_id msg) const
+ {
+ return m_outputs->get_bytes_read(msg);
+ }
+
+bool Pipe::check_available(size_t n)
+ {
+ return (n <= remaining(default_msg()));
+ }
+
+bool Pipe::check_available_msg(size_t n, message_id msg)
+ {
+ return (n <= remaining(msg));
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/secqueue.cpp b/src/libs/3rdparty/botan/src/lib/filters/secqueue.cpp
new file mode 100644
index 00000000000..1c8d2814937
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/secqueue.cpp
@@ -0,0 +1,232 @@
+/*
+* SecureQueue
+* (C) 1999-2007 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/secqueue.h>
+#include <algorithm>
+
+namespace Botan {
+
+/**
+* A node in a SecureQueue
+*/
+class SecureQueueNode final
+ {
+ public:
+ SecureQueueNode() : m_buffer(BOTAN_DEFAULT_BUFFER_SIZE)
+ { m_next = nullptr; m_start = m_end = 0; }
+
+ ~SecureQueueNode() { m_next = nullptr; m_start = m_end = 0; }
+
+ size_t write(const uint8_t input[], size_t length)
+ {
+ size_t copied = std::min<size_t>(length, m_buffer.size() - m_end);
+ copy_mem(m_buffer.data() + m_end, input, copied);
+ m_end += copied;
+ return copied;
+ }
+
+ size_t read(uint8_t output[], size_t length)
+ {
+ size_t copied = std::min(length, m_end - m_start);
+ copy_mem(output, m_buffer.data() + m_start, copied);
+ m_start += copied;
+ return copied;
+ }
+
+ size_t peek(uint8_t output[], size_t length, size_t offset = 0)
+ {
+ const size_t left = m_end - m_start;
+ if(offset >= left) return 0;
+ size_t copied = std::min(length, left - offset);
+ copy_mem(output, m_buffer.data() + m_start + offset, copied);
+ return copied;
+ }
+
+ size_t size() const { return (m_end - m_start); }
+ private:
+ friend class SecureQueue;
+ SecureQueueNode* m_next;
+ secure_vector<uint8_t> m_buffer;
+ size_t m_start, m_end;
+ };
+
+/*
+* Create a SecureQueue
+*/
+SecureQueue::SecureQueue()
+ {
+ m_bytes_read = 0;
+ set_next(nullptr, 0);
+ m_head = m_tail = new SecureQueueNode;
+ }
+
+/*
+* Copy a SecureQueue
+*/
+SecureQueue::SecureQueue(const SecureQueue& input) :
+ Fanout_Filter(), DataSource()
+ {
+ m_bytes_read = 0;
+ set_next(nullptr, 0);
+
+ m_head = m_tail = new SecureQueueNode;
+ SecureQueueNode* temp = input.m_head;
+ while(temp)
+ {
+ write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start);
+ temp = temp->m_next;
+ }
+ }
+
+/*
+* Destroy this SecureQueue
+*/
+void SecureQueue::destroy()
+ {
+ SecureQueueNode* temp = m_head;
+ while(temp)
+ {
+ SecureQueueNode* holder = temp->m_next;
+ delete temp;
+ temp = holder;
+ }
+ m_head = m_tail = nullptr;
+ }
+
+/*
+* Copy a SecureQueue
+*/
+SecureQueue& SecureQueue::operator=(const SecureQueue& input)
+ {
+ if(this == &input)
+ return *this;
+
+ destroy();
+ m_bytes_read = input.get_bytes_read();
+ m_head = m_tail = new SecureQueueNode;
+ SecureQueueNode* temp = input.m_head;
+ while(temp)
+ {
+ write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start);
+ temp = temp->m_next;
+ }
+ return (*this);
+ }
+
+/*
+* Add some bytes to the queue
+*/
+void SecureQueue::write(const uint8_t input[], size_t length)
+ {
+ if(!m_head)
+ m_head = m_tail = new SecureQueueNode;
+ while(length)
+ {
+ const size_t n = m_tail->write(input, length);
+ input += n;
+ length -= n;
+ if(length)
+ {
+ m_tail->m_next = new SecureQueueNode;
+ m_tail = m_tail->m_next;
+ }
+ }
+ }
+
+/*
+* Read some bytes from the queue
+*/
+size_t SecureQueue::read(uint8_t output[], size_t length)
+ {
+ size_t got = 0;
+ while(length && m_head)
+ {
+ const size_t n = m_head->read(output, length);
+ output += n;
+ got += n;
+ length -= n;
+ if(m_head->size() == 0)
+ {
+ SecureQueueNode* holder = m_head->m_next;
+ delete m_head;
+ m_head = holder;
+ }
+ }
+ m_bytes_read += got;
+ return got;
+ }
+
+/*
+* Read data, but do not remove it from queue
+*/
+size_t SecureQueue::peek(uint8_t output[], size_t length, size_t offset) const
+ {
+ SecureQueueNode* current = m_head;
+
+ while(offset && current)
+ {
+ if(offset >= current->size())
+ {
+ offset -= current->size();
+ current = current->m_next;
+ }
+ else
+ break;
+ }
+
+ size_t got = 0;
+ while(length && current)
+ {
+ const size_t n = current->peek(output, length, offset);
+ offset = 0;
+ output += n;
+ got += n;
+ length -= n;
+ current = current->m_next;
+ }
+ return got;
+ }
+
+/**
+* Return how many bytes have been read so far.
+*/
+size_t SecureQueue::get_bytes_read() const
+ {
+ return m_bytes_read;
+ }
+
+/*
+* Return how many bytes the queue holds
+*/
+size_t SecureQueue::size() const
+ {
+ SecureQueueNode* current = m_head;
+ size_t count = 0;
+
+ while(current)
+ {
+ count += current->size();
+ current = current->m_next;
+ }
+ return count;
+ }
+
+/*
+* Test if the queue has any data in it
+*/
+bool SecureQueue::end_of_data() const
+ {
+ return (size() == 0);
+ }
+
+bool SecureQueue::empty() const
+ {
+ return (size() == 0);
+ }
+
+}
diff --git a/src/libs/3rdparty/botan/src/lib/filters/secqueue.h b/src/libs/3rdparty/botan/src/lib/filters/secqueue.h
new file mode 100644
index 00000000000..00616f5cf5a
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/secqueue.h
@@ -0,0 +1,72 @@
+/*
+* SecureQueue
+* (C) 1999-2007 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_SECURE_QUEUE_H_
+#define BOTAN_SECURE_QUEUE_H_
+
+#include <botan/data_src.h>
+#include <botan/filter.h>
+
+namespace Botan {
+
+/**
+* A queue that knows how to zeroize itself
+*/
+class BOTAN_PUBLIC_API(2,0) SecureQueue final : public Fanout_Filter, public DataSource
+ {
+ public:
+ std::string name() const override { return "Queue"; }
+
+ void write(const uint8_t[], size_t) override;
+
+ size_t read(uint8_t[], size_t) override;
+ size_t peek(uint8_t[], size_t, size_t = 0) const override;
+ size_t get_bytes_read() const override;
+
+ bool end_of_data() const override;
+
+ bool empty() const;
+
+ bool check_available(size_t n) override { return n <= size(); }
+
+ /**
+ * @return number of bytes available in the queue
+ */
+ size_t size() const;
+
+ bool attachable() override { return false; }
+
+ /**
+ * SecureQueue assignment
+ * @param other the queue to copy
+ */
+ SecureQueue& operator=(const SecureQueue& other);
+
+ /**
+ * SecureQueue default constructor (creates empty queue)
+ */
+ SecureQueue();
+
+ /**
+ * SecureQueue copy constructor
+ * @param other the queue to copy
+ */
+ SecureQueue(const SecureQueue& other);
+
+ ~SecureQueue() { destroy(); }
+
+ private:
+ void destroy();
+ size_t m_bytes_read;
+ class SecureQueueNode* m_head;
+ class SecureQueueNode* m_tail;
+ };
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/botan/src/lib/filters/threaded_fork.cpp b/src/libs/3rdparty/botan/src/lib/filters/threaded_fork.cpp
new file mode 100644
index 00000000000..35ea9410955
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/filters/threaded_fork.cpp
@@ -0,0 +1,153 @@
+/*
+* Threaded Fork
+* (C) 2013 Joel Low
+* 2013 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/basefilt.h>
+
+#if defined(BOTAN_HAS_THREAD_UTILS)
+
+#include <botan/internal/semaphore.h>
+#include <botan/internal/barrier.h>
+#include <functional>
+
+namespace Botan {
+
+struct Threaded_Fork_Data
+ {
+ /*
+ * Semaphore for indicating that there is work to be done (or to
+ * quit)
+ */
+ Semaphore m_input_ready_semaphore;
+
+ /*
+ * Synchronises all threads to complete processing data in lock-step.
+ */
+ Barrier m_input_complete_barrier;
+
+ /*
+ * The work that needs to be done. This should be only when the threads
+ * are NOT running (i.e. before notifying the work condition, after
+ * the input_complete_barrier has reset.)
+ */
+ const uint8_t* m_input = nullptr;
+
+ /*
+ * The length of the work that needs to be done.
+ */
+ size_t m_input_length = 0;
+ };
+
+/*
+* Threaded_Fork constructor
+*/
+Threaded_Fork::Threaded_Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) :
+ Fork(nullptr, static_cast<size_t>(0)),
+ m_thread_data(new Threaded_Fork_Data)
+ {
+ Filter* filters[4] = { f1, f2, f3, f4 };
+ set_next(filters, 4);
+ }
+
+/*
+* Threaded_Fork constructor
+*/
+Threaded_Fork::Threaded_Fork(Filter* filters[], size_t count) :
+ Fork(nullptr, static_cast<size_t>(0)),
+ m_thread_data(new Threaded_Fork_Data)
+ {
+ set_next(filters, count);
+ }
+
+Threaded_Fork::~Threaded_Fork()
+ {
+ m_thread_data->m_input = nullptr;
+ m_thread_data->m_input_length = 0;
+
+ m_thread_data->m_input_ready_semaphore.release(m_threads.size());
+
+ for(auto& thread : m_threads)
+ thread->join();
+ }
+
+std::string Threaded_Fork::name() const
+ {
+ return "Threaded Fork";
+ }
+
+void Threaded_Fork::set_next(Filter* f[], size_t n)
+ {
+ Fork::set_next(f, n);
+ n = m_next.size();
+
+ if(n < m_threads.size())
+ m_threads.resize(n);
+ else
+ {
+ m_threads.reserve(n);
+ for(size_t i = m_threads.size(); i != n; ++i)
+ {
+ m_threads.push_back(
+ std::shared_ptr<std::thread>(
+ new std::thread(
+ std::bind(&Threaded_Fork::thread_entry, this, m_next[i]))));
+ }
+ }
+ }
+
+void Threaded_Fork::send(const uint8_t input[], size_t length)
+ {
+ if(m_write_queue.size())
+ thread_delegate_work(m_write_queue.data(), m_write_queue.size());
+ thread_delegate_work(input, length);
+
+ bool nothing_attached = true;
+ for(size_t j = 0; j != total_ports(); ++j)
+ if(m_next[j])
+ nothing_attached = false;
+
+ if(nothing_attached)
+ m_write_queue += std::make_pair(input, length);
+ else
+ m_write_queue.clear();
+ }
+
+void Threaded_Fork::thread_delegate_work(const uint8_t input[], size_t length)
+ {
+ //Set the data to do.
+ m_thread_data->m_input = input;
+ m_thread_data->m_input_length = length;
+
+ //Let the workers start processing.
+ m_thread_data->m_input_complete_barrier.wait(total_ports() + 1);
+ m_thread_data->m_input_ready_semaphore.release(total_ports());
+
+ //Wait for all the filters to finish processing.
+ m_thread_data->m_input_complete_barrier.sync();
+
+ //Reset the thread data
+ m_thread_data->m_input = nullptr;
+ m_thread_data->m_input_length = 0;
+ }
+
+void Threaded_Fork::thread_entry(Filter* filter)
+ {
+ while(true)
+ {
+ m_thread_data->m_input_ready_semaphore.acquire();
+
+ if(!m_thread_data->m_input)
+ break;
+
+ filter->write(m_thread_data->m_input, m_thread_data->m_input_length);
+ m_thread_data->m_input_complete_barrier.sync();
+ }
+ }
+
+}
+
+#endif