diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index 70ca2e5..f3d0b0b 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -84,13 +84,15 @@ public: * @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE... * @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] apVfs UTF-8 name of custom VFS to use, or nullptr for sqlite3 default + * @param[in] apPass Key to decrypt (end encrypt) the database, or nullptr for unencrypted databases * * @throw SQLite::Exception in case of error */ Database(const char* apFilename, const int aFlags = SQLite::OPEN_READONLY, const int aBusyTimeoutMs = 0, - const char* apVfs = NULL); + const char* apVfs = NULL, + const char* apPass = NULL); /** * @brief Open the provided database UTF-8 filename. @@ -106,13 +108,15 @@ public: * @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE... * @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] aVfs UTF-8 name of custom VFS to use, or empty string for sqlite3 default + * @param[in] aPass Key to decrypt (end encrypt) the database, or empty string for unencrypted databases * * @throw SQLite::Exception in case of error */ Database(const std::string& aFilename, const int aFlags = SQLite::OPEN_READONLY, const int aBusyTimeoutMs = 0, - const std::string& aVfs = ""); + const std::string& aVfs = "", + const std::string& aPass = ""); /** * @brief Close the SQLite database connection. diff --git a/src/Database.cpp b/src/Database.cpp index f640218..417a83c 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -51,18 +51,37 @@ int getLibVersionNumber() noexcept // nothrow Database::Database(const char* apFilename, const int aFlags /* = SQLite::OPEN_READONLY*/, const int aBusyTimeoutMs /* = 0 */, - const char* apVfs /* = NULL*/) : + const char* apVfs /* = NULL*/, + const char* apPass /* = NULL*/) : mpSQLite(NULL), mFilename(apFilename) { - const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); + int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); if (SQLITE_OK != ret) { const SQLite::Exception exception(mpSQLite, ret); // must create before closing sqlite3_close(mpSQLite); // close is required even in case of error on opening throw exception; } - +#ifdef SQLITE_HAS_CODEC + if (apPass != NULL) + { + ret = sqlite3_key(mpSQLite, apPass, strlen(apPass)); + if (SQLITE_OK != ret) + { + const SQLite::Exception exception(mpSQLite, ret); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } + } +#else + if (apPass != NULL) + { + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC or remove the password from the constructor."); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } +#endif if (aBusyTimeoutMs > 0) { setBusyTimeout(aBusyTimeoutMs); @@ -73,18 +92,37 @@ Database::Database(const char* apFilename, Database::Database(const std::string& aFilename, const int aFlags /* = SQLite::OPEN_READONLY*/, const int aBusyTimeoutMs /* = 0 */, - const std::string& aVfs /* = "" */) : + const std::string& aVfs /* = "" */, + const std::string& aPass /* = "" */) : mpSQLite(NULL), mFilename(aFilename) { - const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str()); + int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str()); if (SQLITE_OK != ret) { const SQLite::Exception exception(mpSQLite, ret); // must create before closing sqlite3_close(mpSQLite); // close is required even in case of error on opening throw exception; } - +#ifdef SQLITE_HAS_CODEC + if (!aPass.empty()) + { + ret = sqlite3_key(mpSQLite, aPass.data(), aPass.size()); + if (SQLITE_OK != ret) + { + const SQLite::Exception exception(mpSQLite, ret); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } + } +#else + if (!aPass.empty()) + { + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC or remove the password from the constructor."); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } +#endif if (aBusyTimeoutMs > 0) { setBusyTimeout(aBusyTimeoutMs);