aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/vendor
diff options
context:
space:
mode:
authorlloyd <[email protected]>2015-02-05 04:44:06 +0000
committerlloyd <[email protected]>2015-02-05 04:44:06 +0000
commit9d8f4cf1e81322ca7290b6551b82d4943dfa62a0 (patch)
tree89bb62a0e4dbc58dea425ea634bedf1d6eab7a65 /src/lib/vendor
parentfde85db0ec7b31d3d8a2cb1c13b2ef1e3a3205a4 (diff)
Enable OpenSSL for providing ciphers and hashes again.
Diffstat (limited to 'src/lib/vendor')
-rw-r--r--src/lib/vendor/boost/info.txt8
-rw-r--r--src/lib/vendor/openssl/openssl_block.cpp212
-rw-r--r--src/lib/vendor/openssl/openssl_hash.cpp115
-rw-r--r--src/lib/vendor/openssl/openssl_rc4.cpp49
-rw-r--r--src/lib/vendor/sqlite3/info.txt10
-rw-r--r--src/lib/vendor/sqlite3/sqlite3.cpp143
-rw-r--r--src/lib/vendor/sqlite3/sqlite3.h56
7 files changed, 593 insertions, 0 deletions
diff --git a/src/lib/vendor/boost/info.txt b/src/lib/vendor/boost/info.txt
new file mode 100644
index 000000000..119a54175
--- /dev/null
+++ b/src/lib/vendor/boost/info.txt
@@ -0,0 +1,8 @@
+define BOOST_FILESYSTEM 20131228
+define BOOST_ASIO 20131228
+
+<libs>
+all -> boost_system,boost_filesystem
+</libs>
+
+load_on request
diff --git a/src/lib/vendor/openssl/openssl_block.cpp b/src/lib/vendor/openssl/openssl_block.cpp
new file mode 100644
index 000000000..34f0e5607
--- /dev/null
+++ b/src/lib/vendor/openssl/openssl_block.cpp
@@ -0,0 +1,212 @@
+/*
+* OpenSSL Block Cipher
+* (C) 1999-2010,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/block_utils.h>
+#include <openssl/evp.h>
+
+namespace Botan {
+
+namespace {
+
+class OpenSSL_BlockCipher : public BlockCipher
+ {
+ public:
+ void clear();
+ std::string name() const { return cipher_name; }
+ BlockCipher* clone() const;
+
+ size_t block_size() const { return block_sz; }
+
+ OpenSSL_BlockCipher(const EVP_CIPHER*, const std::string&);
+
+ OpenSSL_BlockCipher(const EVP_CIPHER*, const std::string&,
+ size_t, size_t, size_t);
+
+ Key_Length_Specification key_spec() const { return cipher_key_spec; }
+
+ ~OpenSSL_BlockCipher();
+ private:
+ void encrypt_n(const byte in[], byte out[], size_t blocks) const
+ {
+ int out_len = 0;
+ EVP_EncryptUpdate(&encrypt, out, &out_len, in, blocks * block_sz);
+ }
+
+ void decrypt_n(const byte in[], byte out[], size_t blocks) const
+ {
+ int out_len = 0;
+ EVP_DecryptUpdate(&decrypt, out, &out_len, in, blocks * block_sz);
+ }
+
+ void key_schedule(const byte[], size_t);
+
+ size_t block_sz;
+ Key_Length_Specification cipher_key_spec;
+ std::string cipher_name;
+ mutable EVP_CIPHER_CTX encrypt, decrypt;
+ };
+
+OpenSSL_BlockCipher::OpenSSL_BlockCipher(const EVP_CIPHER* algo,
+ const std::string& algo_name) :
+ block_sz(EVP_CIPHER_block_size(algo)),
+ cipher_key_spec(EVP_CIPHER_key_length(algo)),
+ cipher_name(algo_name)
+ {
+ if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
+ throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");
+
+ EVP_CIPHER_CTX_init(&encrypt);
+ EVP_CIPHER_CTX_init(&decrypt);
+
+ EVP_EncryptInit_ex(&encrypt, algo, nullptr, nullptr, nullptr);
+ EVP_DecryptInit_ex(&decrypt, algo, nullptr, nullptr, nullptr);
+
+ EVP_CIPHER_CTX_set_padding(&encrypt, 0);
+ EVP_CIPHER_CTX_set_padding(&decrypt, 0);
+ }
+
+OpenSSL_BlockCipher::OpenSSL_BlockCipher(const EVP_CIPHER* algo,
+ const std::string& algo_name,
+ size_t key_min, size_t key_max,
+ size_t key_mod) :
+ block_sz(EVP_CIPHER_block_size(algo)),
+ cipher_key_spec(key_min, key_max, key_mod),
+ cipher_name(algo_name)
+ {
+ if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
+ throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");
+
+ EVP_CIPHER_CTX_init(&encrypt);
+ EVP_CIPHER_CTX_init(&decrypt);
+
+ EVP_EncryptInit_ex(&encrypt, algo, nullptr, nullptr, nullptr);
+ EVP_DecryptInit_ex(&decrypt, algo, nullptr, nullptr, nullptr);
+
+ EVP_CIPHER_CTX_set_padding(&encrypt, 0);
+ EVP_CIPHER_CTX_set_padding(&decrypt, 0);
+ }
+
+OpenSSL_BlockCipher::~OpenSSL_BlockCipher()
+ {
+ EVP_CIPHER_CTX_cleanup(&encrypt);
+ EVP_CIPHER_CTX_cleanup(&decrypt);
+ }
+
+/*
+* Set the key
+*/
+void OpenSSL_BlockCipher::key_schedule(const byte key[], size_t length)
+ {
+ secure_vector<byte> full_key(key, key + length);
+
+ if(cipher_name == "TripleDES" && length == 16)
+ {
+ full_key += std::make_pair(key, 8);
+ }
+ else
+ if(EVP_CIPHER_CTX_set_key_length(&encrypt, length) == 0 ||
+ EVP_CIPHER_CTX_set_key_length(&decrypt, length) == 0)
+ throw Invalid_Argument("OpenSSL_BlockCipher: Bad key length for " +
+ cipher_name);
+
+ EVP_EncryptInit_ex(&encrypt, nullptr, nullptr, &full_key[0], nullptr);
+ EVP_DecryptInit_ex(&decrypt, nullptr, nullptr, &full_key[0], nullptr);
+ }
+
+/*
+* Return a clone of this object
+*/
+BlockCipher* OpenSSL_BlockCipher::clone() const
+ {
+ return new OpenSSL_BlockCipher(EVP_CIPHER_CTX_cipher(&encrypt),
+ cipher_name,
+ cipher_key_spec.minimum_keylength(),
+ cipher_key_spec.maximum_keylength(),
+ cipher_key_spec.keylength_multiple());
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void OpenSSL_BlockCipher::clear()
+ {
+ const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(&encrypt);
+
+ EVP_CIPHER_CTX_cleanup(&encrypt);
+ EVP_CIPHER_CTX_cleanup(&decrypt);
+ EVP_CIPHER_CTX_init(&encrypt);
+ EVP_CIPHER_CTX_init(&decrypt);
+ EVP_EncryptInit_ex(&encrypt, algo, nullptr, nullptr, nullptr);
+ EVP_DecryptInit_ex(&decrypt, algo, nullptr, nullptr, nullptr);
+ EVP_CIPHER_CTX_set_padding(&encrypt, 0);
+ EVP_CIPHER_CTX_set_padding(&decrypt, 0);
+ }
+
+std::function<BlockCipher* (const BlockCipher::Spec&)>
+make_evp_block_maker(const EVP_CIPHER* cipher, const char* algo)
+ {
+ return [cipher,algo](const BlockCipher::Spec&)
+ {
+ return new OpenSSL_BlockCipher(cipher, algo);
+ };
+ }
+
+std::function<BlockCipher* (const BlockCipher::Spec&)>
+make_evp_block_maker_keylen(const EVP_CIPHER* cipher, const char* algo,
+ size_t kmin, size_t kmax, size_t kmod)
+ {
+ return [cipher,algo,kmin,kmax,kmod](const BlockCipher::Spec&)
+ {
+ return new OpenSSL_BlockCipher(cipher, algo, kmin, kmax, kmod);
+ };
+ }
+
+#define BOTAN_REGISTER_OPENSSL_EVP_BLOCK(NAME, EVP) \
+ BOTAN_REGISTER_TYPE(BlockCipher, EVP_BlockCipher ## EVP, NAME, \
+ make_evp_block_maker(EVP(), NAME), "openssl", 96);
+
+#define BOTAN_REGISTER_OPENSSL_EVP_BLOCK_KEYLEN(NAME, EVP, KMIN, KMAX, KMOD) \
+ BOTAN_REGISTER_TYPE(BlockCipher, OpenSSL_BlockCipher ## EVP, NAME, \
+ make_evp_block_maker_keylen(EVP(), NAME, KMIN, KMAX, KMOD), \
+ "openssl", 96);
+
+#if !defined(OPENSSL_NO_AES)
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("AES-128", EVP_aes_128_ecb);
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("AES-192", EVP_aes_192_ecb);
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("AES-256", EVP_aes_256_ecb);
+#endif
+
+#if !defined(OPENSSL_NO_DES)
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("DES", EVP_des_ecb);
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK_KEYLEN("TripleDES", EVP_des_ede3_ecb, 16, 24, 8);
+#endif
+
+#if !defined(OPENSSL_NO_BF)
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK_KEYLEN("Blowfish", EVP_bf_ecb, 1, 56, 1);
+#endif
+
+#if !defined(OPENSSL_NO_CAST)
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK_KEYLEN("CAST-128", EVP_cast5_ecb, 1, 16, 1);
+#endif
+
+#if !defined(OPENSSL_NO_CAMELLIA)
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("Camellia-128", EVP_camellia_128_ecb);
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("Camellia-192", EVP_camellia_192_ecb);
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("Camellia-256", EVP_camellia_256_ecb);
+#endif
+
+#if !defined(OPENSSL_NO_IDEA)
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("IDEA", EVP_idea_ecb);
+#endif
+
+#if !defined(OPENSSL_NO_SEED)
+ BOTAN_REGISTER_OPENSSL_EVP_BLOCK("SEED", EVP_seed_ecb);
+#endif
+
+}
+
+}
diff --git a/src/lib/vendor/openssl/openssl_hash.cpp b/src/lib/vendor/openssl/openssl_hash.cpp
new file mode 100644
index 000000000..6133e36a4
--- /dev/null
+++ b/src/lib/vendor/openssl/openssl_hash.cpp
@@ -0,0 +1,115 @@
+/*
+* OpenSSL Hash Functions
+* (C) 1999-2007,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/hash_utils.h>
+#include <openssl/evp.h>
+
+namespace Botan {
+
+namespace {
+
+class OpenSSL_HashFunction : public HashFunction
+ {
+ public:
+ void clear()
+ {
+ const EVP_MD* algo = EVP_MD_CTX_md(&m_md);
+ EVP_DigestInit_ex(&m_md, algo, nullptr);
+ }
+
+ std::string name() const { return m_name; }
+
+ HashFunction* clone() const
+ {
+ const EVP_MD* algo = EVP_MD_CTX_md(&m_md);
+ return new OpenSSL_HashFunction(algo, name());
+ }
+
+ size_t output_length() const
+ {
+ return EVP_MD_size(EVP_MD_CTX_md(&m_md));
+ }
+
+ size_t hash_block_size() const
+ {
+ return EVP_MD_block_size(EVP_MD_CTX_md(&m_md));
+ }
+
+ OpenSSL_HashFunction(const EVP_MD* md, const std::string& name) : m_name(name)
+ {
+ EVP_MD_CTX_init(&m_md);
+ EVP_DigestInit_ex(&m_md, md, nullptr);
+ }
+
+ ~OpenSSL_HashFunction()
+ {
+ EVP_MD_CTX_cleanup(&m_md);
+ }
+
+ private:
+ void add_data(const byte input[], size_t length)
+ {
+ EVP_DigestUpdate(&m_md, input, length);
+ }
+
+ void final_result(byte output[])
+ {
+ EVP_DigestFinal_ex(&m_md, output, nullptr);
+ const EVP_MD* algo = EVP_MD_CTX_md(&m_md);
+ EVP_DigestInit_ex(&m_md, algo, nullptr);
+ }
+
+ std::string m_name;
+ EVP_MD_CTX m_md;
+ };
+
+std::function<HashFunction* (const HashFunction::Spec&)>
+make_evp_hash_maker(const EVP_MD* md, const char* algo)
+ {
+ return [md,algo](const HashFunction::Spec&)
+ {
+ return new OpenSSL_HashFunction(md, algo);
+ };
+ }
+
+#define BOTAN_REGISTER_OPENSSL_EVP_HASH(NAME, EVP) \
+ BOTAN_REGISTER_TYPE(HashFunction, OpenSSL_HashFunction ## EVP, NAME, \
+ make_evp_hash_maker(EVP(), NAME), "openssl", 32);
+
+#if !defined(OPENSSL_NO_SHA)
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("SHA-160", EVP_sha1);
+#endif
+
+#if !defined(OPENSSL_NO_SHA256)
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("SHA-224", EVP_sha224);
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("SHA-256", EVP_sha256);
+#endif
+
+#if !defined(OPENSSL_NO_SHA512)
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("SHA-384", EVP_sha384);
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("SHA-512", EVP_sha512);
+#endif
+
+#if !defined(OPENSSL_NO_MD2)
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("MD2", EVP_md2);
+#endif
+
+#if !defined(OPENSSL_NO_MD4)
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("MD4", EVP_md4);
+#endif
+
+#if !defined(OPENSSL_NO_MD5)
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("MD5", EVP_md5);
+#endif
+
+#if !defined(OPENSSL_NO_RIPEMD)
+ BOTAN_REGISTER_OPENSSL_EVP_HASH("RIPEMD-160", EVP_ripemd160);
+#endif
+
+}
+
+}
diff --git a/src/lib/vendor/openssl/openssl_rc4.cpp b/src/lib/vendor/openssl/openssl_rc4.cpp
new file mode 100644
index 000000000..966aecd66
--- /dev/null
+++ b/src/lib/vendor/openssl/openssl_rc4.cpp
@@ -0,0 +1,49 @@
+/*
+* OpenSSL RC4
+* (C) 1999-2007,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/stream_utils.h>
+#include <botan/parsing.h>
+#include <openssl/rc4.h>
+
+namespace Botan {
+
+namespace {
+
+class OpenSSL_RC4 : public StreamCipher
+ {
+ public:
+ void clear() { clear_mem(&m_rc4, 1); }
+
+ std::string name() const { return "RC4"; }
+ StreamCipher* clone() const { return new OpenSSL_RC4; }
+
+ Key_Length_Specification key_spec() const
+ {
+ return Key_Length_Specification(1, 32);
+ }
+
+ OpenSSL_RC4() { clear(); }
+ ~OpenSSL_RC4() { clear(); }
+ private:
+ void cipher(const byte in[], byte out[], size_t length)
+ {
+ RC4(&m_rc4, length, in, out);
+ }
+
+ void key_schedule(const byte key[], size_t length)
+ {
+ RC4_set_key(&m_rc4, length, key);
+ }
+
+ RC4_KEY m_rc4;
+ };
+
+}
+
+BOTAN_REGISTER_TYPE(StreamCipher, OpenSSL_RC4, "RC4", make_new_T<OpenSSL_RC4>, "openssl", 64);
+
+}
diff --git a/src/lib/vendor/sqlite3/info.txt b/src/lib/vendor/sqlite3/info.txt
new file mode 100644
index 000000000..6370f4b2b
--- /dev/null
+++ b/src/lib/vendor/sqlite3/info.txt
@@ -0,0 +1,10 @@
+
+load_on request
+
+<libs>
+all -> sqlite3
+</libs>
+
+<header:public>
+sqlite3.h
+</header:public>
diff --git a/src/lib/vendor/sqlite3/sqlite3.cpp b/src/lib/vendor/sqlite3/sqlite3.cpp
new file mode 100644
index 000000000..61c7f15bc
--- /dev/null
+++ b/src/lib/vendor/sqlite3/sqlite3.cpp
@@ -0,0 +1,143 @@
+/*
+* SQLite wrapper
+* (C) 2012 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/sqlite3.h>
+#include <stdexcept>
+#include <sqlite3.h>
+
+namespace Botan {
+
+Sqlite3_Database::Sqlite3_Database(const std::string& db_filename)
+ {
+ int rc = ::sqlite3_open(db_filename.c_str(), &m_db);
+
+ if(rc)
+ {
+ const std::string err_msg = ::sqlite3_errmsg(m_db);
+ ::sqlite3_close(m_db);
+ m_db = nullptr;
+ throw std::runtime_error("sqlite3_open failed - " + err_msg);
+ }
+ }
+
+Sqlite3_Database::~Sqlite3_Database()
+ {
+ if(m_db)
+ ::sqlite3_close(m_db);
+ m_db = nullptr;
+ }
+
+std::shared_ptr<SQL_Database::Statement> Sqlite3_Database::new_statement(const std::string& base_sql) const
+ {
+ return std::make_shared<Sqlite3_Statement>(m_db, base_sql);
+ }
+
+size_t Sqlite3_Database::row_count(const std::string& table_name)
+ {
+ auto stmt = new_statement("select count(*) from " + table_name);
+
+ if(stmt->step())
+ return stmt->get_size_t(0);
+ else
+ throw std::runtime_error("Querying size of table " + table_name + " failed");
+ }
+
+void Sqlite3_Database::create_table(const std::string& table_schema)
+ {
+ char* errmsg = nullptr;
+ int rc = ::sqlite3_exec(m_db, table_schema.c_str(), nullptr, nullptr, &errmsg);
+
+ if(rc != SQLITE_OK)
+ {
+ const std::string err_msg = errmsg;
+ ::sqlite3_free(errmsg);
+ ::sqlite3_close(m_db);
+ m_db = nullptr;
+ throw std::runtime_error("sqlite3_exec for table failed - " + err_msg);
+ }
+ }
+
+Sqlite3_Database::Sqlite3_Statement::Sqlite3_Statement(sqlite3* db, const std::string& base_sql)
+ {
+ int rc = ::sqlite3_prepare_v2(db, base_sql.c_str(), -1, &m_stmt, nullptr);
+
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_prepare failed " + base_sql +
+ ", code " + std::to_string(rc));
+ }
+
+void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::string& val)
+ {
+ int rc = ::sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc));
+ }
+
+void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val)
+ {
+ if(val != static_cast<size_t>(static_cast<int>(val))) // is this legit?
+ throw std::runtime_error("sqlite3 cannot store " + std::to_string(val) + " without truncation");
+ int rc = ::sqlite3_bind_int(m_stmt, column, val);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_int failed, code " + std::to_string(rc));
+ }
+
+void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::chrono::system_clock::time_point time)
+ {
+ const int timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count();
+ bind(column, timeval);
+ }
+
+void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector<byte>& val)
+ {
+ int rc = ::sqlite3_bind_blob(m_stmt, column, &val[0], val.size(), SQLITE_TRANSIENT);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc));
+ }
+
+std::pair<const byte*, size_t> Sqlite3_Database::Sqlite3_Statement::get_blob(int column)
+ {
+ BOTAN_ASSERT(::sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB,
+ "Return value is a blob");
+
+ const void* session_blob = ::sqlite3_column_blob(m_stmt, column);
+ const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column);
+
+ BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
+
+ return std::make_pair(static_cast<const byte*>(session_blob),
+ static_cast<size_t>(session_blob_size));
+ }
+
+size_t Sqlite3_Database::Sqlite3_Statement::get_size_t(int column)
+ {
+ BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER,
+ "Return count is an integer");
+
+ const int sessions_int = ::sqlite3_column_int(m_stmt, column);
+
+ BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative");
+
+ return static_cast<size_t>(sessions_int);
+ }
+
+void Sqlite3_Database::Sqlite3_Statement::spin()
+ {
+ while(step()) {}
+ }
+
+bool Sqlite3_Database::Sqlite3_Statement::step()
+ {
+ return (::sqlite3_step(m_stmt) == SQLITE_ROW);
+ }
+
+Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement()
+ {
+ ::sqlite3_finalize(m_stmt);
+ }
+
+}
diff --git a/src/lib/vendor/sqlite3/sqlite3.h b/src/lib/vendor/sqlite3/sqlite3.h
new file mode 100644
index 000000000..8495a1d1b
--- /dev/null
+++ b/src/lib/vendor/sqlite3/sqlite3.h
@@ -0,0 +1,56 @@
+/*
+* SQLite3 wrapper
+* (C) 2012,2014 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_UTILS_SQLITE3_H__
+#define BOTAN_UTILS_SQLITE3_H__
+
+#include <botan/database.h>
+
+class sqlite3;
+class sqlite3_stmt;
+
+namespace Botan {
+
+class BOTAN_DLL Sqlite3_Database : public SQL_Database
+ {
+ public:
+ Sqlite3_Database(const std::string& file);
+
+ ~Sqlite3_Database();
+
+ size_t row_count(const std::string& table_name) override;
+
+ void create_table(const std::string& table_schema) override;
+
+ std::shared_ptr<Statement> new_statement(const std::string& sql) const override;
+ private:
+ class Sqlite3_Statement : public Statement
+ {
+ public:
+ void bind(int column, const std::string& val) override;
+ void bind(int column, size_t val) override;
+ void bind(int column, std::chrono::system_clock::time_point time) override;
+ void bind(int column, const std::vector<byte>& val) override;
+
+ std::pair<const byte*, size_t> get_blob(int column) override;
+ size_t get_size_t(int column) override;
+
+ void spin() override;
+ bool step() override;
+
+ Sqlite3_Statement(sqlite3* db, const std::string& base_sql);
+ ~Sqlite3_Statement();
+ private:
+ sqlite3_stmt* m_stmt;
+ };
+
+ sqlite3* m_db;
+ };
+
+}
+
+#endif