diff options
author | Janusz Kozerski <j.kozerski@samsung.com> | 2015-05-22 11:14:52 +0200 |
---|---|---|
committer | Janusz Kozerski <j.kozerski@samsung.com> | 2015-05-27 16:00:20 +0200 |
commit | 0cad75f144c2ef178d2bc7cced6cf4c4b0e57409 (patch) | |
tree | bafda22bd800b6ebd3519d3353d069bcf967f360 /src | |
parent | e1301082a4c40852dde8500b18bb2f3df88fac8f (diff) | |
download | cert-checker-0cad75f144c2ef178d2bc7cced6cf4c4b0e57409.tar.gz cert-checker-0cad75f144c2ef178d2bc7cced6cf4c4b0e57409.tar.bz2 cert-checker-0cad75f144c2ef178d2bc7cced6cf4c4b0e57409.zip |
Add DPL code (needed for database support)
Changes:
* change namespace from DPL to CCHECKER.
* change LogPenantic -> LogDebug (journal doesn't support pedantic)
* naiveSynchronizationObject() uses STL thread and chrono instead of DPL/thread
Change-Id: I553a71dd5befbe4bc4d18f7582955af6ea329db7
Diffstat (limited to 'src')
23 files changed, 3100 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 94a8b74..ec7e710 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,11 +2,14 @@ PKG_CHECK_MODULES(CERT_CHECKER_DEP REQUIRED dbus-1 dbus-glib-1 + db-util glib-2.0 gio-2.0 + icu-i18n capi-appfw-package-manager notification libsystemd-journal + sqlite3 ) SET(CERT_CHECKER_SRC_PATH ${PROJECT_SOURCE_DIR}/src) @@ -17,12 +20,24 @@ SET(CERT_CHECKER_SOURCES ${CERT_CHECKER_SRC_PATH}/logic.cpp # logs ${CERT_CHECKER_SRC_PATH}/log/log.cpp + # dpl + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/assert.cpp + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/char_traits.cpp + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/errno_string.cpp + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/exception.cpp + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/noncopyable.cpp + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/string.cpp + # dpl DB + ${CERT_CHECKER_SRC_PATH}/dpl/db/src/sql_connection.cpp + ${CERT_CHECKER_SRC_PATH}/dpl/db/src/naive_synchronization_object.cpp ) INCLUDE_DIRECTORIES(SYSTEM ${CERT_CHECKER_DEP_INCLUDE_DIRS} ${CERT_CHECKER_SRC_PATH}/include/ ${CERT_CHECKER_SRC_PATH}/log/ + ${CERT_CHECKER_SRC_PATH}/dpl/core/include/ + ${CERT_CHECKER_SRC_PATH}/dpl/db/include/ ) ADD_EXECUTABLE(${TARGET_CERT_CHECKER} ${CERT_CHECKER_SOURCES}) diff --git a/src/dpl/core/include/dpl/assert.h b/src/dpl/core/include/dpl/assert.h new file mode 100644 index 0000000..936c71e --- /dev/null +++ b/src/dpl/core/include/dpl/assert.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#ifndef CCHECKER_ASSERT_H +#define CCHECKER_ASSERT_H + +#include <dpl/noreturn.h> + +namespace CCHECKER { +// Assertion handler procedure +// Do not call directly +// Always use Assert macro +CCHECKER_NORETURN void AssertProc(const char *condition, + const char *file, + int line, + const char *function); +} // namespace CCHECKER + +#define Assert(Condition) do { if (!(Condition)) { CCHECKER::AssertProc(#Condition, \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + } } while (0) + +#endif // CCHECKER_ASSERT_H diff --git a/src/dpl/core/include/dpl/availability.h b/src/dpl/core/include/dpl/availability.h new file mode 100644 index 0000000..b1cb894 --- /dev/null +++ b/src/dpl/core/include/dpl/availability.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file availability.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + */ +#ifndef CCHECKER_AVAILABILITY_H +#define CCHECKER_AVAILABILITY_H + +#define CCHECKER_DEPRECATED __attribute__((deprecated)) +#define CCHECKER_DEPRECATED_WITH_MESSAGE(msg) __attribute__((deprecated(msg))) + +#define CCHECKER_UNUSED __attribute__((unused)) +#define CCHECKER_UNUSED_PARAM(variable) (void)variable + +#endif // CCHECKER_AVAILABILITY_H diff --git a/src/dpl/core/include/dpl/char_traits.h b/src/dpl/core/include/dpl/char_traits.h new file mode 100644 index 0000000..e76f48b --- /dev/null +++ b/src/dpl/core/include/dpl/char_traits.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file char_traits.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief Char traits are used to create basic_string extended with + * additional features + * Current char traits could be extended in feature to boost + * performance + */ +#ifndef CCHECKER_CHAR_TRAITS +#define CCHECKER_CHAR_TRAITS + +#include <cstring> +#include <string> +#include <ostream> +#include <algorithm> +#include <dpl/exception.h> + +namespace CCHECKER { +typedef std::char_traits<wchar_t> CharTraits; +} // namespace CCHECKER + +#endif // CCHECKER_CHAR_TRAITS diff --git a/src/dpl/core/include/dpl/errno_string.h b/src/dpl/core/include/dpl/errno_string.h new file mode 100644 index 0000000..498b2af --- /dev/null +++ b/src/dpl/core/include/dpl/errno_string.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file errno_string.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of errno string + */ +#ifndef CCHECKER_ERRNO_STRING_H +#define CCHECKER_ERRNO_STRING_H + +#include <dpl/exception.h> +#include <string> +#include <cerrno> + +namespace CCHECKER { +DECLARE_EXCEPTION_TYPE(CCHECKER::Exception, InvalidErrnoValue) + +std::string GetErrnoString(int error = errno); +} // namespace CCHECKER + +#endif // CCHECKER_ERRNO_STRING_H diff --git a/src/dpl/core/include/dpl/exception.h b/src/dpl/core/include/dpl/exception.h new file mode 100644 index 0000000..f7b9afc --- /dev/null +++ b/src/dpl/core/include/dpl/exception.h @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for base exception + */ +#ifndef CCHECKER_EXCEPTION_H +#define CCHECKER_EXCEPTION_H + +#include <string> +#include <cstring> +#include <cstdio> +#include <exception> +#include <cstdlib> +#include <sstream> + +namespace CCHECKER { +void LogUnhandledException(const std::string &str); +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function); +} + +namespace CCHECKER { +class Exception +{ + private: + static unsigned int m_exceptionCount; + static Exception* m_lastException; + static void (*m_terminateHandler)(); + + static void AddRef(Exception* exception) + { + if (!m_exceptionCount) { + m_terminateHandler = std::set_terminate(&TerminateHandler); + } + + ++m_exceptionCount; + m_lastException = exception; + } + + static void UnRef(Exception* e) + { + if (m_lastException == e) { + m_lastException = NULL; + } + + --m_exceptionCount; + + if (!m_exceptionCount) { + std::set_terminate(m_terminateHandler); + m_terminateHandler = NULL; + } + } + + static void TerminateHandler() + { + if (m_lastException != NULL) { + DisplayKnownException(*m_lastException); + abort(); + } else { + DisplayUnknownException(); + abort(); + } + } + + Exception *m_reason; + std::string m_path; + std::string m_function; + int m_line; + + protected: + std::string m_message; + std::string m_className; + + public: + static std::string KnownExceptionToString(const Exception &e) + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled CCHECKER exception occurred ===\033[m\n\n"; + message << "\033[1;33mException trace:\033[m\n\n"; + message << e.DumpToString(); + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static std::string UnknownExceptionToString() + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled non-CCHECKER exception occurred ===\033[m\n\n"; + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static void DisplayKnownException(const Exception& e) + { + LogUnhandledException(KnownExceptionToString(e).c_str()); + } + + static void DisplayUnknownException() + { + LogUnhandledException(UnknownExceptionToString().c_str()); + } + + Exception(const Exception &other) + { + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + } + + const Exception &operator =(const Exception &other) + { + if (this == &other) { + return *this; + } + + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + + return *this; + } + + Exception(const char *path, + const char *function, + int line, + const std::string &message) : + m_reason(NULL), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + Exception(const char *path, + const char *function, + int line, + const Exception &reason, + const std::string &message) : + m_reason(new Exception(reason)), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + virtual ~Exception() throw() + { + if (m_reason != NULL) { + delete m_reason; + m_reason = NULL; + } + + UnRef(this); + } + + void Dump() const + { + // Show reason first + if (m_reason != NULL) { + m_reason->Dump(); + } + + // Afterward, dump exception + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + printf("\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "<EMPTY>" : m_message.c_str()); + } + + std::string DumpToString() const + { + std::string ret; + if (m_reason != NULL) { + ret = m_reason->DumpToString(); + } + + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + char buf[1024]; + snprintf(buf, + sizeof(buf), + "\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, + m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "<EMPTY>" : m_message.c_str()); + + buf[sizeof(buf) - 1] = '\n'; + ret += buf; + + return ret; + } + + Exception *GetReason() const + { + return m_reason; + } + + std::string GetPath() const + { + return m_path; + } + + std::string GetFunction() const + { + return m_function; + } + + int GetLine() const + { + return m_line; + } + + std::string GetMessage() const + { + return m_message; + } + + std::string GetClassName() const + { + return m_className; + } +}; +} // namespace CCHECKER + +#define Try try + +#define Throw(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__) + +#define ThrowMsg(ClassName, Message) \ + do \ + { \ + std::ostringstream dplLoggingStream; \ + dplLoggingStream << Message; \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, dplLoggingStream.str()); \ + } while (0) + +#define ReThrow(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception) + +#define ReThrowMsg(ClassName, Message) \ + throw ClassName(__FILE__, \ + __FUNCTION__, \ + __LINE__, \ + _rethrown_exception, \ + Message) + +#define Catch(ClassName) \ + catch (const ClassName &_rethrown_exception) + +#define DECLARE_EXCEPTION_TYPE(BaseClass, Class) \ + class Class : \ + public BaseClass \ + { \ + public: \ + Class(const char *path, \ + const char *function, \ + int line, \ + const std::string & message = std::string()) : \ + BaseClass(path, function, line, message) \ + { \ + BaseClass::m_className = #Class; \ + } \ + \ + Class(const char *path, \ + const char *function, \ + int line, \ + const CCHECKER::Exception & reason, \ + const std::string & message = std::string()) : \ + BaseClass(path, function, line, reason, message) \ + { \ + BaseClass::m_className = #Class; \ + } \ + }; + +#define UNHANDLED_EXCEPTION_HANDLER_BEGIN try + +#define UNHANDLED_EXCEPTION_HANDLER_END \ + catch (const CCHECKER::Exception &exception) \ + { \ + std::ostringstream msg; \ + msg << CCHECKER::Exception::KnownExceptionToString(exception); \ + CCHECKER::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + catch (std::exception& e) \ + { \ + std::ostringstream msg; \ + msg << e.what(); \ + msg << "\n"; \ + msg << CCHECKER::Exception::UnknownExceptionToString(); \ + CCHECKER::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + catch (...) \ + { \ + std::ostringstream msg; \ + msg << CCHECKER::Exception::UnknownExceptionToString(); \ + CCHECKER::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } + +namespace CCHECKER { +namespace CommonException { +/** + * Internal exception definitions + * + * These should normally not happen. + * Usually, exception trace with internal error includes + * important messages. + */ +DECLARE_EXCEPTION_TYPE(Exception, InternalError) ///< Unexpected error from + // underlying libraries or + // kernel +} +} + +#endif // CCHECKER_EXCEPTION_H diff --git a/src/dpl/core/include/dpl/noncopyable.h b/src/dpl/core/include/dpl/noncopyable.h new file mode 100644 index 0000000..747299c --- /dev/null +++ b/src/dpl/core/include/dpl/noncopyable.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#ifndef CCHECKER_NONCOPYABLE_H +#define CCHECKER_NONCOPYABLE_H + +namespace CCHECKER { +class Noncopyable +{ + private: + Noncopyable(const Noncopyable &); + const Noncopyable &operator=(const Noncopyable &); + + public: + Noncopyable(); + virtual ~Noncopyable(); +}; +} // namespace CCHECKER + +#endif // CCHECKER_NONCOPYABLE_H diff --git a/src/dpl/core/include/dpl/noreturn.h b/src/dpl/core/include/dpl/noreturn.h new file mode 100644 index 0000000..6eaaa64 --- /dev/null +++ b/src/dpl/core/include/dpl/noreturn.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noreturn.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noreturn + */ +#ifndef CCHECKER_NORETURN_H +#define CCHECKER_NORETURN_H + +#define CCHECKER_NORETURN __attribute__((__noreturn__)) + +#endif // CCHECKER_NORETURN_H diff --git a/src/dpl/core/include/dpl/optional.h b/src/dpl/core/include/dpl/optional.h new file mode 100644 index 0000000..6aca7bd --- /dev/null +++ b/src/dpl/core/include/dpl/optional.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file optional_value.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + */ + +#ifndef CCHECKER_OPTIONAL_H +#define CCHECKER_OPTIONAL_H + +#include <dpl/exception.h> + +namespace CCHECKER { +template <typename Type> +class Optional +{ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(CCHECKER::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, NullReference) + }; + + public: + Optional() : + m_null(true), + m_value() + {} + + Optional(const Type& t) : + m_null(false), + m_value(t) + {} + + bool IsNull() const + { + return m_null; + } + + Type& operator*() + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return m_value; + } + + const Type& operator*() const + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return m_value; + } + + const Type* operator->() const + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return &m_value; + } + + Type* operator->() + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return &m_value; + } + + bool operator!() const + { + return m_null; + } + + Optional<Type>& operator=(const Type& other) + { + m_null = false; + m_value = other; + return *this; + } + + bool operator==(const Optional<Type>& aSecond) const + { + return LogicalOperator<true>(*this, aSecond, + std::equal_to<Type>(), std::equal_to<bool>()); + } + + bool operator==(const Type& aSecond) const + { + return Optional<Type>(aSecond) == *this; + } + + bool operator!=(const Optional<Type>& aSecond) const + { + return !(*this == aSecond); + } + + bool operator<(const Optional<Type>& aSecond) const + { + return LogicalOperator<false>(*this, aSecond, + std::less<Type>(), std::less<bool>()); + } + + bool operator>(const Optional<Type>& aSecond) const + { + return LogicalOperator<false>(*this, aSecond, + std::greater<Type>(), std::greater<bool>()); + } + + bool operator<=(const Optional<Type>& aSecond) const + { + return *this == aSecond || *this < aSecond; + } + + bool operator>=(const Optional<Type>& aSecond) const + { + return *this == aSecond || *this > aSecond; + } + + static Optional<Type> Null; + + private: + bool m_null; + Type m_value; + + template <bool taEquality, typename taComparator, typename taNullComparator> + static bool LogicalOperator(const Optional<Type>& aFirst, + const Optional<Type>& aSecond, + taComparator aComparator, + taNullComparator aNullComparator) + { + if (aFirst.m_null == aSecond.m_null) { + if (aFirst.m_null) { + return taEquality; + } else { + return aComparator(aFirst.m_value, aSecond.m_value); + } + } else { + return aNullComparator(aFirst.m_null, aSecond.m_null); + } + } +}; + +template<typename Type> +Optional<Type> Optional<Type>::Null = Optional<Type>(); +} //namespace CCHECKER + +template<typename Type> +std::ostream& operator<<(std::ostream& aStream, + const CCHECKER::Optional<Type>& aOptional) +{ + if (aOptional.IsNull()) { + return aStream << "null optional"; + } else { + return aStream << *aOptional; + } +} + +#endif // CCHECKER_OPTIONAL_VALUE_H diff --git a/src/dpl/core/include/dpl/scoped_array.h b/src/dpl/core/include/dpl/scoped_array.h new file mode 100644 index 0000000..ca6a02b --- /dev/null +++ b/src/dpl/core/include/dpl/scoped_array.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_ptr.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped array RAII + */ +#ifndef CCHECKER_SCOPED_ARRAY_H +#define CCHECKER_SCOPED_ARRAY_H + +#include <cstddef> + +#include <dpl/assert.h> +#include <dpl/scoped_resource.h> + +namespace CCHECKER { +template<typename Class> +struct ScopedArrayPolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + delete[] ptr; + } +}; + +template<typename Class> +class ScopedArray : public ScopedResource<ScopedArrayPolicy<Class> > +{ + typedef ScopedArrayPolicy<Class> Policy; + typedef ScopedResource<Policy> BaseType; + + public: + explicit ScopedArray(Class *ptr = Policy::NullValue()) : BaseType(ptr) { } + + Class &operator [](std::ptrdiff_t k) const + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL array!"); + Assert(k >= 0 && "Negative array index"); + + return this->m_value[k]; + } +}; +} // namespace CCHECKER + +#endif // CCHECKER_SCOPED_PTR_H diff --git a/src/dpl/core/include/dpl/scoped_free.h b/src/dpl/core/include/dpl/scoped_free.h new file mode 100644 index 0000000..9be17b7 --- /dev/null +++ b/src/dpl/core/include/dpl/scoped_free.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_free.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped free RAII + */ + +#ifndef CCHECKER_SCOPED_FREE_H +#define CCHECKER_SCOPED_FREE_H + +#include <malloc.h> +#include <cstddef> + +#include <dpl/scoped_resource.h> + +namespace CCHECKER { +template<typename Class> +struct ScopedFreePolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + free(ptr); + } +}; + +template<typename Memory> +class ScopedFree : public ScopedResource<ScopedFreePolicy<Memory> > +{ + typedef ScopedFreePolicy<Memory> Policy; + typedef ScopedResource<Policy> BaseType; + + public: + explicit ScopedFree(Memory *ptr = Policy::NullValue()) : BaseType(ptr) { } +}; +} // namespace CCHECKER + +#endif // CCHECKER_SCOPED_FREE_H diff --git a/src/dpl/core/include/dpl/scoped_resource.h b/src/dpl/core/include/dpl/scoped_resource.h new file mode 100644 index 0000000..c024684 --- /dev/null +++ b/src/dpl/core/include/dpl/scoped_resource.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file scoped_resource.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped resource pattern + */ +#ifndef CCHECKER_SCOPED_RESOURCE_H +#define CCHECKER_SCOPED_RESOURCE_H + +#include <dpl/noncopyable.h> + +namespace CCHECKER { +template<typename ClassPolicy> +class ScopedResource : + private Noncopyable +{ + public: + typedef typename ClassPolicy::Type ValueType; + typedef ScopedResource<ClassPolicy> ThisType; + + protected: + ValueType m_value; + + public: + explicit ScopedResource(ValueType value) : m_value(value) { } + + ~ScopedResource() + { + ClassPolicy::Destroy(m_value); + } + + ValueType Get() const + { + return m_value; + } + + void Reset(ValueType value = ClassPolicy::NullValue()) + { + ClassPolicy::Destroy(m_value); + m_value = value; + } + + ValueType Release() + { + ValueType value = m_value; + m_value = ClassPolicy::NullValue(); + return value; + } + typedef ValueType ThisType::*UnknownBoolType; + + operator UnknownBoolType() const + { + return m_value == ClassPolicy::NullValue() ? + 0 : //0 is valid here because it converts to false + &ThisType::m_value; //it converts to true + } + + bool operator !() const + { + return m_value == ClassPolicy::NullValue(); + } +}; +} // namespace CCHECKER + +#endif // CCHECKER_SCOPED_RESOURCE_H diff --git a/src/dpl/core/include/dpl/string.h b/src/dpl/core/include/dpl/string.h new file mode 100644 index 0000000..a271e5a --- /dev/null +++ b/src/dpl/core/include/dpl/string.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file string.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + */ +#ifndef CCHECKER_STRING +#define CCHECKER_STRING + +#include <dpl/exception.h> +#include <dpl/char_traits.h> +#include <string> +#include <ostream> +#include <numeric> + +namespace CCHECKER { +// @brief CCHECKER string +typedef std::basic_string<wchar_t, CharTraits> String; + +// @brief String exception class +class StringException +{ + public: + DECLARE_EXCEPTION_TYPE(CCHECKER::Exception, Base) + + // @brief Invalid init for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF8ToUTF32) + + // @brief Invalid taStdContainerinit for UTF32 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF32ToUTF8) + + // @brief Invalid conversion for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF8ToUTF32) + + // @brief Invalid conversion for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF32ToUTF8) + + // @brief Invalid ASCII character detected in FromASCII + DECLARE_EXCEPTION_TYPE(Base, InvalidASCIICharacter) + + // @brief Invalid ASCII character detected in FromASCII + DECLARE_EXCEPTION_TYPE(Base, ICUInvalidCharacterFound) +}; + +//!\brief convert ASCII string to CCHECKER::String +String FromASCIIString(const std::string& aString); + +//!\brief convert UTF32 string to CCHECKER::String +String FromUTF32String(const std::wstring& aString); + +//@brief Returns String object created from UTF8 string +//@param[in] aString input UTF-8 string +String FromUTF8String(const std::string& aString); + +//@brief Returns String content as std::string +std::string ToUTF8String(const String& aString); + +//@brief Compare two unicode strings +int StringCompare(const String &left, + const String &right, + bool caseInsensitive = false); + +//@brief Splits the string into substrings. +//@param[in] str Input string +//@param[in] delimiters array or string containing a sequence of substring +// delimiters. Can be also a single delimiter character. +//@param[in] it InserterIterator that is used to save the generated substrings. +template<typename StringType, typename Delimiters, typename InserterIterator> +void Tokenize(const StringType& str, + const Delimiters& delimiters, + InserterIterator it, + bool ignoreEmpty = false) +{ + typename StringType::size_type nextSearchStart = 0; + typename StringType::size_type pos; + typename StringType::size_type length; + + while (true) { + pos = str.find_first_of(delimiters, nextSearchStart); + length = + ((pos == StringType::npos) ? str.length() : pos) - nextSearchStart; + + if (!ignoreEmpty || length > 0) { + *it = str.substr(nextSearchStart, length); + it++; + } + + if (pos == StringType::npos) { + return; + } + + nextSearchStart = pos + 1; + } +} + +namespace Utils { + +template<typename T> class ConcatFunc : public std::binary_function<T, T, T> +{ +public: + explicit ConcatFunc(const T & val) : m_delim(val) {} + T operator()(const T & arg1, const T & arg2) const + { + return arg1 + m_delim + arg2; + } +private: + T m_delim; +}; + +} + +template<typename ForwardIterator> +typename ForwardIterator::value_type Join(ForwardIterator begin, ForwardIterator end, typename ForwardIterator::value_type delim) +{ + typedef typename ForwardIterator::value_type value; + if(begin == end) return value(); + Utils::ConcatFunc<value> func(delim); + ForwardIterator init = begin; + return std::accumulate(++begin, end, *init, func); +} + +} //namespace CCHECKER + +std::ostream& operator<<(std::ostream& aStream, const CCHECKER::String& aString); + +#endif // CCHECKER_STRING diff --git a/src/dpl/core/src/assert.cpp b/src/dpl/core/src/assert.cpp new file mode 100644 index 0000000..f317dd6 --- /dev/null +++ b/src/dpl/core/src/assert.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#include <stddef.h> +#include <dpl/assert.h> +#include <cstdlib> +#include <dpl/exception.h> + +#include <log.h> + +namespace CCHECKER { +void AssertProc(const char *condition, + const char *file, + int line, + const char *function) +{ +#define INTERNAL_LOG(message) \ + do \ + { \ + std::ostringstream platformLog; \ + platformLog << message; \ + JournalLog(LOG_DEBUG, \ + platformLog.str().c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + while (0) + + // Try to log failed assertion to log system + Try + { + INTERNAL_LOG( + "################################################################################"); + INTERNAL_LOG( + "### cert-checker assertion failed! ###"); + INTERNAL_LOG( + "################################################################################"); + INTERNAL_LOG("### Condition: " << condition); + INTERNAL_LOG("### File: " << file); + INTERNAL_LOG("### Line: " << line); + INTERNAL_LOG("### Function: " << function); + INTERNAL_LOG( + "################################################################################"); + } catch (Exception) { + // Just ignore possible double errors + } + + // Fail with c-library abort + abort(); +} +} // namespace CCHECKER diff --git a/src/dpl/core/src/char_traits.cpp b/src/dpl/core/src/char_traits.cpp new file mode 100644 index 0000000..32b9197 --- /dev/null +++ b/src/dpl/core/src/char_traits.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file char_traits.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @biref Char traits are used to create basic_string extended with + * additional features + * Current char traits could be extended in feature to boost + * performance + */ +#include <stddef.h> +#include <dpl/char_traits.h> + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/src/dpl/core/src/errno_string.cpp b/src/dpl/core/src/errno_string.cpp new file mode 100644 index 0000000..e481a02 --- /dev/null +++ b/src/dpl/core/src/errno_string.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file errno_string.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of errno string + */ +#include <stddef.h> +#include <dpl/errno_string.h> +#include <dpl/assert.h> +#include <dpl/exception.h> +#include <dpl/assert.h> +#include <dpl/scoped_free.h> +#include <string> +#include <cstddef> +#include <cstring> +#include <malloc.h> +#include <cerrno> +#include <stdexcept> + +namespace CCHECKER { +namespace // anonymous +{ +const size_t DEFAULT_ERRNO_STRING_SIZE = 32; +} // namespace anonymous + +std::string GetErrnoString(int error) +{ + size_t size = DEFAULT_ERRNO_STRING_SIZE; + char *buffer = NULL; + + for (;;) { + // Add one extra characted for end of string null value + char *newBuffer = static_cast<char *>(::realloc(buffer, size + 1)); + + if (!newBuffer) { + // Failed to realloc + ::free(buffer); + throw std::bad_alloc(); + } + + // Setup reallocated buffer + buffer = newBuffer; + ::memset(buffer, 0, size + 1); + + // Try to retrieve error string +#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE + // The XSI-compliant version of strerror_r() is provided if: + int result = ::strerror_r(error, buffer, size); + + if (result == 0) { + ScopedFree<char> scopedBufferFree(buffer); + return std::string(buffer); + } +#else + errno = 0; + + // Otherwise, the GNU-specific version is provided. + char *result = ::strerror_r(error, buffer, size); + + if (result != NULL) { + ScopedFree<char> scopedBufferFree(buffer); + return std::string(result); + } +#endif + + // Interpret errors + switch (errno) { + case EINVAL: + // We got an invalid errno value + ::free(buffer); + ThrowMsg(InvalidErrnoValue, "Invalid errno value: " << error); + + case ERANGE: + // Incease buffer size and retry + size <<= 1; + continue; + + default: + Assert(0 && "Invalid errno value after call to strerror_r!"); + } + } +} +} // namespace CCHECKER diff --git a/src/dpl/core/src/exception.cpp b/src/dpl/core/src/exception.cpp new file mode 100644 index 0000000..7b936fe --- /dev/null +++ b/src/dpl/core/src/exception.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation of exception system + */ +#include <stddef.h> +#include <dpl/exception.h> +#include <cstdio> + +#include <log.h> + +namespace CCHECKER { +Exception* Exception::m_lastException = NULL; +unsigned int Exception::m_exceptionCount = 0; +void (*Exception::m_terminateHandler)() = NULL; + +void LogUnhandledException(const std::string &str) +{ + // Logging to console + printf("%s\n", str.c_str()); + + // Logging to dlog + LogDebug(str); +} + +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function) +{ + // Logging to console + std::ostringstream msg; + msg << "\033[1;5;31m\n=== [" << filename << ":" << line << "] " << + function << " ===\033[m"; + msg << str; + printf("%s\n", msg.str().c_str()); + + // Logging to dlog + LogError(str.c_str() << filename << line << function); +} +} // namespace CCHECKER diff --git a/src/dpl/core/src/noncopyable.cpp b/src/dpl/core/src/noncopyable.cpp new file mode 100644 index 0000000..1ae80e9 --- /dev/null +++ b/src/dpl/core/src/noncopyable.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#include <stddef.h> +#include <dpl/noncopyable.h> + +namespace CCHECKER { +Noncopyable::Noncopyable() +{} + +Noncopyable::~Noncopyable() +{} +} // namespace CCHECKER diff --git a/src/dpl/core/src/string.cpp b/src/dpl/core/src/string.cpp new file mode 100644 index 0000000..5d33ba8 --- /dev/null +++ b/src/dpl/core/src/string.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file string.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + */ +#include <stddef.h> +#include <dpl/string.h> +#include <dpl/char_traits.h> +#include <dpl/errno_string.h> +#include <dpl/exception.h> +#include <dpl/scoped_array.h> +#include <string> +#include <vector> +#include <algorithm> +#include <cstring> +#include <errno.h> +#include <iconv.h> +#include <unicode/ustring.h> + +#include <log.h> + +// TODO: Completely move to ICU +namespace CCHECKER { +namespace //anonymous +{ +class ASCIIValidator +{ + const std::string& m_TestedString; + + public: + ASCIIValidator(const std::string& aTestedString); + + void operator()(char aCharacter) const; +}; + +ASCIIValidator::ASCIIValidator(const std::string& aTestedString) : + m_TestedString(aTestedString) +{} + +void ASCIIValidator::operator()(char aCharacter) const +{ + // Check for ASCII data range + if (aCharacter <= 0) { + ThrowMsg( + StringException::InvalidASCIICharacter, + "invalid character code " << static_cast<int>(aCharacter) + << " from string [" << + m_TestedString + << "] passed as ASCII"); + } +} + +const iconv_t gc_IconvOperError = reinterpret_cast<iconv_t>(-1); +const size_t gc_IconvConvertError = static_cast<size_t>(-1); +} // namespace anonymous + +String FromUTF8String(const std::string& aIn) +{ + if (aIn.empty()) { + return String(); + } + + size_t inbytes = aIn.size(); + + // Default iconv UTF-32 module adds BOM (4 bytes) in from of string + // The worst case is when 8bit UTF-8 char converts to 32bit UTF-32 + // newsize = oldsize * 4 + end + bom + // newsize - bytes for UTF-32 string + // oldsize - letters in UTF-8 string + // end - end character for UTF-32 (\0) + // bom - Unicode header in front of string (0xfeff) + size_t outbytes = sizeof(wchar_t) * (inbytes + 2); + std::vector<wchar_t> output(inbytes + 2, 0); + + size_t outbytesleft = outbytes; + char* inbuf = const_cast<char*>(aIn.c_str()); + + // vector is used to provide buffer for iconv which expects char* buffer + // but during conversion from UTF32 uses internaly wchar_t + char* outbuf = reinterpret_cast<char*>(&output[0]); + + iconv_t iconvHandle = iconv_open("UTF-32", "UTF-8"); + + if (gc_IconvOperError == iconvHandle) { + int error = errno; + + ThrowMsg(StringException::IconvInitErrorUTF8ToUTF32, + "iconv_open failed for " << "UTF-32 <- UTF-8" << + "error: " << GetErrnoString(error)); + } + + size_t iconvRet = iconv(iconvHandle, + &inbuf, + &inbytes, + &outbuf, + &outbytesleft); + + iconv_close(iconvHandle); + + if (gc_IconvConvertError == iconvRet) { + ThrowMsg(StringException::IconvConvertErrorUTF8ToUTF32, + "iconv failed for " << "UTF-32 <- UTF-8" << "error: " + << GetErrnoString()); + } + + // Ignore BOM in front of UTF-32 + return &output[1]; +} + +std::string ToUTF8String(const CCHECKER::String& aIn) +{ + if (aIn.empty()) { + return std::string(); + } + + size_t inbytes = aIn.size() * sizeof(wchar_t); + size_t outbytes = inbytes + sizeof(char); + + // wstring returns wchar_t but iconv expects char* + // iconv internally is processing input as wchar_t + char* inbuf = reinterpret_cast<char*>(const_cast<wchar_t*>(aIn.c_str())); + std::vector<char> output(inbytes, 0); + char* outbuf = &output[0]; + + size_t outbytesleft = outbytes; + + iconv_t iconvHandle = iconv_open("UTF-8", "UTF-32"); + + if (gc_IconvOperError == iconvHandle) { + ThrowMsg(StringException::IconvInitErrorUTF32ToUTF8, + "iconv_open failed for " << "UTF-8 <- UTF-32" + << "error: " << GetErrnoString()); + } + + size_t iconvRet = iconv(iconvHandle, + &inbuf, + &inbytes, + &outbuf, + &outbytesleft); + + iconv_close(iconvHandle); + + if (gc_IconvConvertError == iconvRet) { + ThrowMsg(StringException::IconvConvertErrorUTF32ToUTF8, + "iconv failed for " << "UTF-8 <- UTF-32" + << "error: " << GetErrnoString()); + } + + return &output[0]; +} + +String FromASCIIString(const std::string& aString) +{ + String output; + + std::for_each(aString.begin(), aString.end(), ASCIIValidator(aString)); + std::copy(aString.begin(), aString.end(), std::back_inserter<String>(output)); + + return output; +} + +String FromUTF32String(const std::wstring& aString) +{ + return String(&aString[0]); +} + +static UChar *ConvertToICU(const String &inputString) +{ + ScopedArray<UChar> outputString; + int32_t size = 0; + int32_t convertedSize = 0; + UErrorCode error = U_ZERO_ERROR; + + // Calculate size of output string + ::u_strFromWCS(NULL, + 0, + &size, + inputString.c_str(), + -1, + &error); + + if (error == U_ZERO_ERROR || + error == U_BUFFER_OVERFLOW_ERROR) + { + // What buffer size is ok ? + LogDebug("ICU: Output buffer size: " << size); + } else { + ThrowMsg(StringException::ICUInvalidCharacterFound, + "ICU: Failed to retrieve output string size. Error: " + << error); + } + + // Allocate proper buffer + outputString.Reset(new UChar[size + 1]); + ::memset(outputString.Get(), 0, sizeof(UChar) * (size + 1)); + + error = U_ZERO_ERROR; + + // Do conversion + ::u_strFromWCS(outputString.Get(), + size + 1, + &convertedSize, + inputString.c_str(), + -1, + &error); + + if (!U_SUCCESS(error)) { + ThrowMsg(StringException::ICUInvalidCharacterFound, + "ICU: Failed to convert string. Error: " << error); + } + + // Done + return outputString.Release(); +} + +int StringCompare(const String &left, + const String &right, + bool caseInsensitive) +{ + // Convert input strings + ScopedArray<UChar> leftICU(ConvertToICU(left)); + ScopedArray<UChar> rightICU(ConvertToICU(right)); + + if (caseInsensitive) { + return static_cast<int>(u_strcasecmp(leftICU.Get(), rightICU.Get(), 0)); + } else { + return static_cast<int>(u_strcmp(leftICU.Get(), rightICU.Get())); + } +} +} //namespace CCHECKER + +std::ostream& operator<<(std::ostream& aStream, const CCHECKER::String& aString) +{ + return aStream << CCHECKER::ToUTF8String(aString); +} diff --git a/src/dpl/db/include/dpl/db/naive_synchronization_object.h b/src/dpl/db/include/dpl/db/naive_synchronization_object.h new file mode 100644 index 0000000..687d666 --- /dev/null +++ b/src/dpl/db/include/dpl/db/naive_synchronization_object.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file naive_synchronization_object.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL naive + * synchronization object + */ +#ifndef CCHECKER_NAIVE_SYNCHRONIZATION_OBJECT_H +#define CCHECKER_NAIVE_SYNCHRONIZATION_OBJECT_H + +#include <dpl/db/sql_connection.h> + +namespace CCHECKER { +namespace DB { +/** + * Naive synchronization object used to synchronize SQL connection + * to the same database across different threads and processes + */ +class NaiveSynchronizationObject : + public SqlConnection::SynchronizationObject +{ + public: + // [SqlConnection::SynchronizationObject] + virtual void Synchronize(); + virtual void NotifyAll(); +}; +} // namespace DB +} // namespace CCHECKER + +#endif // CCHECKER_NAIVE_SYNCHRONIZATION_OBJECT_H diff --git a/src/dpl/db/include/dpl/db/sql_connection.h b/src/dpl/db/include/dpl/db/sql_connection.h new file mode 100644 index 0000000..07cfe13 --- /dev/null +++ b/src/dpl/db/include/dpl/db/sql_connection.h @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file sql_connection.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL connection + */ +#ifndef CCHECKER_SQL_CONNECTION_H +#define CCHECKER_SQL_CONNECTION_H + +#include <dpl/noncopyable.h> +#include <dpl/exception.h> +#include <dpl/optional.h> +#include <memory> +#include <dpl/string.h> +#include <sqlite3.h> +#include <string> +#include <dpl/assert.h> +#include <memory> +#include <stdint.h> + +#include <log.h> + +namespace CCHECKER { +namespace DB { +/** + * SQL connection class + */ +class SqlConnection +{ + public: + /** + * SQL Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(CCHECKER::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, SyntaxError) + DECLARE_EXCEPTION_TYPE(Base, ConnectionBroken) + DECLARE_EXCEPTION_TYPE(Base, InternalError) + DECLARE_EXCEPTION_TYPE(Base, InvalidColumn) + }; + + typedef int ColumnIndex; + typedef int ArgumentIndex; + + /* + * SQL processed data command + */ + class DataCommand : + private Noncopyable + { + private: + SqlConnection *m_masterConnection; + sqlite3_stmt *m_stmt; + + void CheckBindResult(int result); + void CheckColumnIndex(SqlConnection::ColumnIndex column); + + DataCommand(SqlConnection *connection, const char *buffer); + + friend class SqlConnection; + + public: + virtual ~DataCommand(); + + /** + * Bind null to the prepared statement argument + * + * @param position Index of argument to bind value to + */ + void BindNull(ArgumentIndex position); + + /** + * Bind int to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInteger(ArgumentIndex position, int value); + + /** + * Bind int8_t to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt8(ArgumentIndex position, int8_t value); + + /** + * Bind int16 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt16(ArgumentIndex position, int16_t value); + + /** + * Bind int32 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt32(ArgumentIndex position, int32_t value); + + /** + * Bind int64 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt64(ArgumentIndex position, int64_t value); + + /** + * Bind float to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindFloat(ArgumentIndex position, float value); + + /** + * Bind double to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindDouble(ArgumentIndex position, double value); + + /** + * Bind string to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const char *value); + + /** + * Bind string to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const String& value); + + /** + * Bind optional int to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInteger(ArgumentIndex position, const Optional<int> &value); + + /** + * Bind optional int8 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt8(ArgumentIndex position, const Optional<int8_t> &value); + + /** + * Bind optional int16 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt16(ArgumentIndex position, const Optional<int16_t> &value); + + /** + * Bind optional int32 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt32(ArgumentIndex position, const Optional<int32_t> &value); + + /** + * Bind optional int64 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt64(ArgumentIndex position, const Optional<int64_t> &value); + + /** + * Bind optional float to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindFloat(ArgumentIndex position, const Optional<float> &value); + + /** + * Bind optional double to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindDouble(ArgumentIndex position, const Optional<double> &value); + + /** + * Bind optional string to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const Optional<String> &value); + + /** + * Execute the prepared statement and/or move + * to the next row of the result + * + * @return True when there was a row returned + */ + bool Step(); + + /** + * Reset prepared statement's arguments + * All parameters will become null + */ + void Reset(); + + /** + * Checks whether column value is null + * + * @throw Exception::InvalidColumn + */ + bool IsColumnNull(ColumnIndex column); + + /** + * Get integer value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int GetColumnInteger(ColumnIndex column); + + /** + * Get int8 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int8_t GetColumnInt8(ColumnIndex column); + + /** + * Get int16 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int16_t GetColumnInt16(ColumnIndex column); + /** + * Get int32 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int32_t GetColumnInt32(ColumnIndex column); + + /** + * Get int64 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int64_t GetColumnInt64(ColumnIndex column); + + /** + * Get float value from column in current row. + * + * @throw Exception::InvalidColumn + */ + float GetColumnFloat(ColumnIndex column); + + /** + * Get double value from column in current row. + * + * @throw Exception::InvalidColumn + */ + double GetColumnDouble(ColumnIndex column); + + /** + * Get string value from column in current row. + * + * @throw Exception::InvalidColumn + */ + std::string GetColumnString(ColumnIndex column); + + /** + * Get optional integer value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<int> GetColumnOptionalInteger(ColumnIndex column); + + /** + * Get optional int8 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<int8_t> GetColumnOptionalInt8(ColumnIndex column); + + /** + * Get optional int16value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<int16_t> GetColumnOptionalInt16(ColumnIndex column); + + /** + * Get optional int32 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<int32_t> GetColumnOptionalInt32(ColumnIndex column); + + /** + * Get optional int64 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<int64_t> GetColumnOptionalInt64(ColumnIndex column); + + /** + * Get optional float value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<float> GetColumnOptionalFloat(ColumnIndex column); + + /** + * Get optional double value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<double> GetColumnOptionalDouble(ColumnIndex column); + + /** + * Get optional string value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional<String> GetColumnOptionalString(ColumnIndex column); + }; + + // Move on copy semantics + typedef std::auto_ptr<DataCommand> DataCommandAutoPtr; + + // Open flags + class Flag + { + public: + enum Type + { + None = 1 << 0, + UseLucene = 1 << 1 + }; + + enum Option + { + RO = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY, + /** + * *TODO: please remove CREATE option from RW flag when all places + * that need that switched do CRW + */ + RW = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE, + CRW = RW | SQLITE_OPEN_CREATE + }; + }; + + // RowID + typedef sqlite3_int64 RowID; + + /** + * Synchronization object used to synchronize SQL connection + * to the same database across different threads and processes + */ + class SynchronizationObject + { + public: + virtual ~SynchronizationObject() {} + + /** + * Synchronizes SQL connection for multiple clients. + */ + virtual void Synchronize() = 0; + + /** + * Notify all waiting clients that the connection is no longer locked. + */ + virtual void NotifyAll() = 0; + }; + + protected: + sqlite3 *m_connection; + + // Options + bool m_usingLucene; + + // Stored data procedures + int m_dataCommandsCount; + + // Synchronization object + std::unique_ptr<SynchronizationObject> m_synchronizationObject; + + virtual void Connect(const std::string &address, + Flag::Type = Flag::None, Flag::Option = Flag::RO); + virtual void Disconnect(); + + void TurnOnForeignKeys(); + + static SynchronizationObject *AllocDefaultSynchronizationObject(); + + public: + /** + * Open SQL connection + * + * Synchronization is archieved by using provided asynchronization object. + * If synchronizationObject is set to NULL, so synchronization is performed. + * Ownership of the synchronization object is transfered to sql connection + * object. + * + * @param address Database file name + * @param flags Open flags + * @param synchronizationObject A synchronization object to use. + */ + explicit SqlConnection(const std::string &address = std::string(), + Flag::Type flags = Flag::None, + Flag::Option options = Flag::RO, + SynchronizationObject *synchronizationObject = + AllocDefaultSynchronizationObject()); + + /** + * Destructor + */ + virtual ~SqlConnection(); + + /** + * Execute SQL command without result + * + * @param format + * @param ... + */ + void ExecCommand(const char *format, ...); + + /** + * Prepare stored procedure + * + * @param format SQL statement + * @return Data command representing stored procedure + */ + DataCommandAutoPtr PrepareDataCommand(const char *format, ...); + + /** + * Check whether given table exists + * + * @param tableName Name of the table to check + * @return True if given table name exists + */ + bool CheckTableExist(const char *tableName); + + /** + * Get last insert operation new row id + * + * @return Row ID + */ + RowID GetLastInsertRowID() const; +}; +} // namespace DB +} // namespace CCHECKER + +#endif // CCHECKER_SQL_CONNECTION_H diff --git a/src/dpl/db/src/naive_synchronization_object.cpp b/src/dpl/db/src/naive_synchronization_object.cpp new file mode 100644 index 0000000..2592c3c --- /dev/null +++ b/src/dpl/db/src/naive_synchronization_object.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file naive_synchronization_object.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL naive + * synchronization object + */ +#include <stddef.h> +#include <dpl/db/naive_synchronization_object.h> +#include <chrono> +#include <thread> + +namespace { + unsigned int seed = time(NULL); +} + +namespace CCHECKER { +namespace DB { +void NaiveSynchronizationObject::Synchronize() +{ + // Sleep for about 10ms - 30ms + std::this_thread::sleep_for(std::chrono::milliseconds(10 + rand_r(&seed) % 20)); +} + +void NaiveSynchronizationObject::NotifyAll() +{ + // No need to inform about anything +} +} // namespace DB +} // namespace CCHECKER diff --git a/src/dpl/db/src/sql_connection.cpp b/src/dpl/db/src/sql_connection.cpp new file mode 100644 index 0000000..0680a58 --- /dev/null +++ b/src/dpl/db/src/sql_connection.cpp @@ -0,0 +1,850 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file sql_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL connection + */ +#include <stddef.h> +#include <dpl/db/sql_connection.h> +#include <dpl/db/naive_synchronization_object.h> +#include <dpl/scoped_free.h> +#include <dpl/noncopyable.h> +#include <dpl/assert.h> +#include <db-util.h> +#include <unistd.h> +#include <cstdio> +#include <cstdarg> + +namespace CCHECKER { +namespace DB { +namespace // anonymous +{ +class ScopedNotifyAll : + public Noncopyable +{ + private: + SqlConnection::SynchronizationObject *m_synchronizationObject; + + public: + explicit ScopedNotifyAll( + SqlConnection::SynchronizationObject *synchronizationObject) : + m_synchronizationObject(synchronizationObject) + {} + + ~ScopedNotifyAll() + { + if (!m_synchronizationObject) { + return; + } + + LogDebug("Notifying after successful synchronize"); + m_synchronizationObject->NotifyAll(); + } +}; +} // namespace anonymous + +SqlConnection::DataCommand::DataCommand(SqlConnection *connection, + const char *buffer) : + m_masterConnection(connection), + m_stmt(NULL) +{ + Assert(connection != NULL); + + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get()); + + for (;;) { + int ret = sqlite3_prepare_v2(connection->m_connection, + buffer, strlen(buffer), + &m_stmt, NULL); + + if (ret == SQLITE_OK) { + LogDebug("Data command prepared successfuly"); + break; + } else if (ret == SQLITE_BUSY) { + LogDebug("Collision occurred while preparing SQL command"); + + // Synchronize if synchronization object is available + if (connection->m_synchronizationObject) { + LogDebug("Performing synchronization"); + connection->m_synchronizationObject->Synchronize(); + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + const char *error = sqlite3_errmsg(m_masterConnection->m_connection); + + LogDebug("SQL prepare data command failed"); + LogDebug(" Statement: " << buffer); + LogDebug(" Error: " << error); + + ThrowMsg(Exception::SyntaxError, error); + } + + LogDebug("Prepared data command: " << buffer); + + // Increment stored data command count + ++m_masterConnection->m_dataCommandsCount; +} + +SqlConnection::DataCommand::~DataCommand() +{ + LogDebug("SQL data command finalizing"); + + if (sqlite3_finalize(m_stmt) != SQLITE_OK) { + LogDebug("Failed to finalize data command"); + } + + // Decrement stored data command count + --m_masterConnection->m_dataCommandsCount; +} + +void SqlConnection::DataCommand::CheckBindResult(int result) +{ + if (result != SQLITE_OK) { + const char *error = sqlite3_errmsg( + m_masterConnection->m_connection); + + LogDebug("Failed to bind SQL statement parameter"); + LogDebug(" Error: " << error); + + ThrowMsg(Exception::SyntaxError, error); + } +} + +void SqlConnection::DataCommand::BindNull( + SqlConnection::ArgumentIndex position) +{ + CheckBindResult(sqlite3_bind_null(m_stmt, position)); + LogDebug("SQL data command bind null: [" + << position << "]"); +} + +void SqlConnection::DataCommand::BindInteger( + SqlConnection::ArgumentIndex position, + int value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, value)); + LogDebug("SQL data command bind integer: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt8( + SqlConnection::ArgumentIndex position, + int8_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast<int>(value))); + LogDebug("SQL data command bind int8: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt16( + SqlConnection::ArgumentIndex position, + int16_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast<int>(value))); + LogDebug("SQL data command bind int16: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt32( + SqlConnection::ArgumentIndex position, + int32_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast<int>(value))); + LogDebug("SQL data command bind int32: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt64( + SqlConnection::ArgumentIndex position, + int64_t value) +{ + CheckBindResult(sqlite3_bind_int64(m_stmt, position, + static_cast<sqlite3_int64>(value))); + LogDebug("SQL data command bind int64: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindFloat( + SqlConnection::ArgumentIndex position, + float value) +{ + CheckBindResult(sqlite3_bind_double(m_stmt, position, + static_cast<double>(value))); + LogDebug("SQL data command bind float: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindDouble( + SqlConnection::ArgumentIndex position, + double value) +{ + CheckBindResult(sqlite3_bind_double(m_stmt, position, value)); + LogDebug("SQL data command bind double: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const char *value) +{ + if (!value) { + BindNull(position); + return; + } + + // Assume that text may disappear + CheckBindResult(sqlite3_bind_text(m_stmt, position, + value, strlen(value), + SQLITE_TRANSIENT)); + + LogDebug("SQL data command bind string: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const String &value) +{ + BindString(position, ToUTF8String(value).c_str()); +} + +void SqlConnection::DataCommand::BindInteger( + SqlConnection::ArgumentIndex position, + const Optional<int> &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInteger(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt8( + SqlConnection::ArgumentIndex position, + const Optional<int8_t> &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt8(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt16( + SqlConnection::ArgumentIndex position, + const Optional<int16_t> &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt16(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt32( + SqlConnection::ArgumentIndex position, + const Optional<int32_t> &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt32(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt64( + SqlConnection::ArgumentIndex position, + const Optional<int64_t> &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt64(position, *value); + } +} + +void SqlConnection::DataCommand::BindFloat( + SqlConnection::ArgumentIndex position, + const Optional<float> &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindFloat(position, *value); + } +} + +void SqlConnection::DataCommand::BindDouble( + SqlConnection::ArgumentIndex position, + const Optional<double> &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindDouble(position, *value); + } +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const Optional<String> &value) +{ + if (!!value) { + BindString(position, ToUTF8String(*value).c_str()); + } else { + BindNull(position); + } +} + +bool SqlConnection::DataCommand::Step() +{ + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll( + m_masterConnection->m_synchronizationObject.get()); + + for (;;) { + int ret = sqlite3_step(m_stmt); + + if (ret == SQLITE_ROW) { + LogDebug("SQL data command step ROW"); + return true; + } else if (ret == SQLITE_DONE) { + LogDebug("SQL data command step DONE"); + return false; + } else if (ret == SQLITE_BUSY) { + LogDebug("Collision occurred while executing SQL command"); + + // Synchronize if synchronization object is available + if (m_masterConnection->m_synchronizationObject) { + LogDebug("Performing synchronization"); + + m_masterConnection-> + m_synchronizationObject->Synchronize(); + + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + const char *error = sqlite3_errmsg(m_masterConnection->m_connection); + + LogDebug("SQL step data command failed"); + LogDebug(" Error: " << error); + + ThrowMsg(Exception::InternalError, error); + } +} + +void SqlConnection::DataCommand::Reset() +{ + /* + * According to: + * http://www.sqlite.org/c3ref/stmt.html + * + * if last sqlite3_step command on this stmt returned an error, + * then sqlite3_reset will return that error, althought it is not an error. + * So sqlite3_reset allways succedes. + */ + sqlite3_reset(m_stmt); + + LogDebug("SQL data command reset"); +} + +void SqlConnection::DataCommand::CheckColumnIndex( + SqlConnection::ColumnIndex column) +{ + if (column < 0 || column >= sqlite3_column_count(m_stmt)) { + ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds"); + } +} + +bool SqlConnection::DataCommand::IsColumnNull( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column type: [" << column << "]"); + CheckColumnIndex(column); + return sqlite3_column_type(m_stmt, column) == SQLITE_NULL; +} + +int SqlConnection::DataCommand::GetColumnInteger( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column integer: [" << column << "]"); + CheckColumnIndex(column); + int value = sqlite3_column_int(m_stmt, column); + LogDebug(" Value: " << value); + return value; +} + +int8_t SqlConnection::DataCommand::GetColumnInt8( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column int8: [" << column << "]"); + CheckColumnIndex(column); + int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column)); + LogDebug(" Value: " << value); + return value; +} + +int16_t SqlConnection::DataCommand::GetColumnInt16( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column int16: [" << column << "]"); + CheckColumnIndex(column); + int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column)); + LogDebug(" Value: " << value); + return value; +} + +int32_t SqlConnection::DataCommand::GetColumnInt32( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column int32: [" << column << "]"); + CheckColumnIndex(column); + int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column)); + LogDebug(" Value: " << value); + return value; +} + +int64_t SqlConnection::DataCommand::GetColumnInt64( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column int64: [" << column << "]"); + CheckColumnIndex(column); + int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column)); + LogDebug(" Value: " << value); + return value; +} + +float SqlConnection::DataCommand::GetColumnFloat( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column float: [" << column << "]"); + CheckColumnIndex(column); + float value = static_cast<float>(sqlite3_column_double(m_stmt, column)); + LogDebug(" Value: " << value); + return value; +} + +double SqlConnection::DataCommand::GetColumnDouble( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column double: [" << column << "]"); + CheckColumnIndex(column); + double value = sqlite3_column_double(m_stmt, column); + LogDebug(" Value: " << value); + return value; +} + +std::string SqlConnection::DataCommand::GetColumnString( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column string: [" << column << "]"); + CheckColumnIndex(column); + + const char *value = reinterpret_cast<const char *>( + sqlite3_column_text(m_stmt, column)); + + LogDebug("Value: " << (value ? value : "NULL")); + + if (value == NULL) { + return std::string(); + } + + return std::string(value); +} + +Optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional integer: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<int>::Null; + } + int value = sqlite3_column_int(m_stmt, column); + LogDebug(" Value: " << value); + return Optional<int>(value); +} + +Optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional int8: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<int8_t>::Null; + } + int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column)); + LogDebug(" Value: " << value); + return Optional<int8_t>(value); +} + +Optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional int16: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<int16_t>::Null; + } + int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column)); + LogDebug(" Value: " << value); + return Optional<int16_t>(value); +} + +Optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional int32: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<int32_t>::Null; + } + int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column)); + LogDebug(" Value: " << value); + return Optional<int32_t>(value); +} + +Optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional int64: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<int64_t>::Null; + } + int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column)); + LogDebug(" Value: " << value); + return Optional<int64_t>(value); +} + +Optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional float: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<float>::Null; + } + float value = static_cast<float>(sqlite3_column_double(m_stmt, column)); + LogDebug(" Value: " << value); + return Optional<float>(value); +} + +Optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional double: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<double>::Null; + } + double value = sqlite3_column_double(m_stmt, column); + LogDebug(" Value: " << value); + return Optional<double>(value); +} + +Optional<String> SqlConnection::DataCommand::GetColumnOptionalString( + SqlConnection::ColumnIndex column) +{ + LogDebug("SQL data command get column optional string: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional<String>::Null; + } + const char *value = reinterpret_cast<const char *>( + sqlite3_column_text(m_stmt, column)); + LogDebug("Value: " << value); + String s = FromUTF8String(value); + return Optional<String>(s); +} + +void SqlConnection::Connect(const std::string &address, + Flag::Type type, + Flag::Option flag) +{ + if (m_connection != NULL) { + LogDebug("Already connected."); + return; + } + LogDebug("Connecting to DB: " << address << "..."); + + // Connect to database + int result; + if (type & Flag::UseLucene) { + result = db_util_open_with_options( + address.c_str(), + &m_connection, + flag, + NULL); + + m_usingLucene = true; + LogDebug("Lucene index enabled"); + } else { + result = sqlite3_open_v2( + address.c_str(), + &m_connection, + flag, + NULL); + + m_usingLucene = false; + LogDebug("Lucene index disabled"); + } + + if (result == SQLITE_OK) { + LogDebug("Connected to DB"); + } else { + LogDebug("Failed to connect to DB!"); + ThrowMsg(Exception::ConnectionBroken, address); + } + + // Enable foreign keys + TurnOnForeignKeys(); +} + +void SqlConnection::Disconnect() +{ + if (m_connection == NULL) { + LogDebug("Already disconnected."); + return; + } + + LogDebug("Disconnecting from DB..."); + + // All stored data commands must be deleted before disconnect + Assert(m_dataCommandsCount == 0 && + "All stored procedures must be deleted" + " before disconnecting SqlConnection"); + + int result; + + if (m_usingLucene) { + result = db_util_close(m_connection); + } else { + result = sqlite3_close(m_connection); + } + + if (result != SQLITE_OK) { + const char *error = sqlite3_errmsg(m_connection); + LogDebug("SQL close failed"); + LogDebug(" Error: " << error); + Throw(Exception::InternalError); + } + + m_connection = NULL; + + LogDebug("Disconnected from DB"); +} + +bool SqlConnection::CheckTableExist(const char *tableName) +{ + if (m_connection == NULL) { + LogDebug("Cannot execute command. Not connected to DB!"); + return false; + } + + DataCommandAutoPtr command = + PrepareDataCommand("select tbl_name from sqlite_master where name=?;"); + + command->BindString(1, tableName); + + if (!command->Step()) { + LogDebug("No matching records in table"); + return false; + } + + return command->GetColumnString(0) == tableName; +} + +SqlConnection::SqlConnection(const std::string &address, + Flag::Type flag, + Flag::Option option, + SynchronizationObject *synchronizationObject) : + m_connection(NULL), + m_usingLucene(false), + m_dataCommandsCount(0), + m_synchronizationObject(synchronizationObject) +{ + LogDebug("Opening database connection to: " << address); + + // Connect to DB + SqlConnection::Connect(address, flag, option); + + if (!m_synchronizationObject) { + LogDebug("No synchronization object defined"); + } +} + +SqlConnection::~SqlConnection() +{ + LogDebug("Closing database connection"); + + // Disconnect from DB + Try + { + SqlConnection::Disconnect(); + } + Catch(Exception::Base) + { + LogDebug("Failed to disconnect from database"); + } +} + +void SqlConnection::ExecCommand(const char *format, ...) +{ + if (m_connection == NULL) { + LogDebug("Cannot execute command. Not connected to DB!"); + return; + } + + if (format == NULL) { + LogDebug("Null query!"); + ThrowMsg(Exception::SyntaxError, "Null statement"); + } + + char *rawBuffer; + + va_list args; + va_start(args, format); + + if (vasprintf(&rawBuffer, format, args) == -1) { + rawBuffer = NULL; + } + + va_end(args); + + ScopedFree<char> buffer(rawBuffer); + + if (!buffer) { + LogDebug("Failed to allocate statement string"); + return; + } + + LogDebug("Executing SQL command: " << buffer.Get()); + + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll(m_synchronizationObject.get()); + + for (;;) { + char *errorBuffer; + + int ret = sqlite3_exec(m_connection, + buffer.Get(), + NULL, + NULL, + &errorBuffer); + + std::string errorMsg; + + // Take allocated error buffer + if (errorBuffer != NULL) { + errorMsg = errorBuffer; + sqlite3_free(errorBuffer); + } + + if (ret == SQLITE_OK) { + return; + } + + if (ret == SQLITE_BUSY) { + LogDebug("Collision occurred while executing SQL command"); + + // Synchronize if synchronization object is available + if (m_synchronizationObject) { + LogDebug("Performing synchronization"); + m_synchronizationObject->Synchronize(); + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + LogDebug("Failed to execute SQL command. Error: " << errorMsg); + ThrowMsg(Exception::SyntaxError, errorMsg); + } +} + +SqlConnection::DataCommandAutoPtr SqlConnection::PrepareDataCommand( + const char *format, + ...) +{ + if (m_connection == NULL) { + LogDebug("Cannot execute data command. Not connected to DB!"); + return DataCommandAutoPtr(); + } + + char *rawBuffer; + + va_list args; + va_start(args, format); + + if (vasprintf(&rawBuffer, format, args) == -1) { + rawBuffer = NULL; + } + + va_end(args); + + ScopedFree<char> buffer(rawBuffer); + + if (!buffer) { + LogDebug("Failed to allocate statement string"); + return DataCommandAutoPtr(); + } + + LogDebug("Executing SQL data command: " << buffer.Get()); + + return DataCommandAutoPtr(new DataCommand(this, buffer.Get())); +} + +SqlConnection::RowID SqlConnection::GetLastInsertRowID() const +{ + return static_cast<RowID>(sqlite3_last_insert_rowid(m_connection)); +} + +void SqlConnection::TurnOnForeignKeys() +{ + ExecCommand("PRAGMA foreign_keys = ON;"); +} + +SqlConnection::SynchronizationObject * +SqlConnection::AllocDefaultSynchronizationObject() +{ + return new NaiveSynchronizationObject(); +} +} // namespace DB +} // namespace CCHECKER |