diff options
Diffstat (limited to 'xbmc/commons')
-rw-r--r-- | xbmc/commons/Buffer.h | 254 | ||||
-rw-r--r-- | xbmc/commons/CMakeLists.txt | 7 | ||||
-rw-r--r-- | xbmc/commons/Exception.cpp | 22 | ||||
-rw-r--r-- | xbmc/commons/Exception.h | 113 | ||||
-rw-r--r-- | xbmc/commons/ilog.h | 46 |
5 files changed, 442 insertions, 0 deletions
diff --git a/xbmc/commons/Buffer.h b/xbmc/commons/Buffer.h new file mode 100644 index 0000000..98085ea --- /dev/null +++ b/xbmc/commons/Buffer.h @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include <memory> +#include <string.h> +#include <string> + +namespace XbmcCommons +{ + class BufferException final + { + std::string message; + + public: + explicit BufferException(const char* message_) : message(message_) {} + }; + + /** + * This class is based on the java java.nio.Buffer class however, it + * does not implement the 'mark' functionality. + * + * [ the following is borrowed from the javadocs for java.nio.Buffer + * where it applies to this class]: + * + * A buffer is a linear, finite sequence of elements of a unspecified types. + * Aside from its content, the essential properties of a buffer are its capacity, + * limit, and position: + * A buffer's capacity is the number of elements it contains. The capacity + * of a buffer is never negative and never changes. + * + * A buffer's limit is the index of the first element that should not be + * read or written. A buffer's limit is never negative and is never greater + * than its capacity. + * + * A buffer's position is the index of the next element to be read or written. + * A buffer's position is never negative and is never greater than its limit. + * + * Invariants: + * + * The following invariant holds for the mark, position, limit, and capacity values: + * + * 0 <= mark <= position <= limit <= capacity + * + * A newly-created buffer always has a position of zero and a limit set to the + * capacity. The initial content of a buffer is, in general, undefined. + * + * Example: + * Buffer buffer(1024); + * buffer.putInt(1).putString("hello there").putLongLong( ((long long)2)^40 ); + * buffer.flip(); + * std::cout << "buffer contents:" << buffer.getInt() << ", "; + * std::cout << buffer.getCharPointerDirect() << ", "; + * std::cout << buffer.getLongLong() << std::endl; + * + * Note: the 'gets' are sensitive to the order-of-operations. Therefore, while + * the above is correct, it would be wrong to chain the output as follows: + * + * std::cout << "buffer contents:" << buffer.getInt() << ", " << std::cout + * << buffer.getCharPointerDirect() << ", " << buffer.getLongLong() + * << std::endl; + * + * This would result in the get's executing from right to left and therefore would + * produce totally erroneous results. This is also a problem when the values are + * passed to a method as in: + * + * printf("buffer contents: %d, \"%s\", %ll\n", buffer.getInt(), + * buffer.getCharPointerDirect(), buffer.getLongLong()); + * + * This would also produce erroneous results as they get's will be evaluated + * from right to left in the parameter list of printf. + */ + class Buffer + { + std::shared_ptr<unsigned char> bufferRef; + unsigned char* buffer = nullptr; + size_t mposition = 0; + size_t mcapacity = 0; + size_t mlimit = 0; + + inline void check(size_t count) const + { + if ((mposition + count) > mlimit) + throw BufferException("Buffer buffer overflow: Cannot add more data to the Buffer's buffer."); + } + + public: + /** + * Construct an uninitialized buffer instance, perhaps as an lvalue. + */ + inline Buffer() { clear(); } + + /** + * Construct a buffer given an externally managed memory buffer. + * The ownership of the buffer is assumed to be the code that called + * this constructor, therefore the Buffer destructor will not free it. + * + * The newly constructed buffer is considered empty and is ready to + * have data written into it. + * + * If you want to read from the buffer you just created, you can use: + * + * Buffer b = Buffer(buf,bufSize).forward(bufSize).flip(); + */ + inline Buffer(void* buffer_, size_t bufferSize) : buffer((unsigned char*)buffer_), mcapacity(bufferSize) + { + clear(); + } + + /** + * Construct a buffer buffer using the size buffer provided. The + * buffer will be internally managed and potentially shared with + * other Buffer instances. It will be freed upon destruction of + * the last Buffer that references it. + */ + inline explicit Buffer(size_t bufferSize) : buffer(bufferSize ? new unsigned char[bufferSize] : NULL), mcapacity(bufferSize) + { + clear(); + bufferRef.reset(buffer, std::default_delete<unsigned char[]>()); + } + + /** + * Copy another buffer. This is a "shallow copy" and therefore + * shares the underlying data buffer with the Buffer it is a copy + * of. Changes made to the data through this buffer will be seen + * in the source buffer and vice/vrs. However, each buffer maintains + * its own indexing. + */ + inline Buffer(const Buffer& buf) = default; + + /** + * Copy another buffer. This is a "shallow copy" and therefore + * shares the underlying data buffer with the Buffer it is a copy + * of. Changes made to the data through this buffer will be seen + * in the source buffer and vice/vrs. However, each buffer maintains + * its own indexing. + */ + inline Buffer& operator=(const Buffer& buf) + { + buffer = buf.buffer; + bufferRef = buf.bufferRef; + mcapacity = buf.mcapacity; + mlimit = buf.mlimit; + return *this; + } + + inline Buffer& allocate(size_t bufferSize) + { + buffer = bufferSize ? new unsigned char[bufferSize] : NULL; + bufferRef.reset(buffer, std::default_delete<unsigned char[]>()); + mcapacity = bufferSize; + clear(); + return *this; + } + + /** + * Flips this buffer. The limit is set to the current position + * and then the position is set to zero. + * + * After a sequence of channel-read or put operations, invoke this + * method to prepare for a sequence of channel-write or relative + * get operations. For example: + * + * buf.put(magic); // Prepend header + * in.read(buf); // Read data into rest of buffer + * buf.flip(); // Flip buffer + * out.write(buf); // Write header + data to channel + * + * This is used to prepare the Buffer for reading from after + * it has been written to. + */ + inline Buffer& flip() { mlimit = mposition; mposition = 0; return *this; } + + /** + *Clears this buffer. The position is set to zero, the limit + * is set to the capacity. + * + * Invoke this method before using a sequence of channel-read + * or put operations to fill this buffer. For example: + * + * buf.clear(); // Prepare buffer for reading + * in.read(buf); // Read data + * + * This method does not actually erase the data in the buffer, + * but it is named as if it did because it will most often be used + * in situations in which that might as well be the case. + */ + inline Buffer& clear() { mlimit = mcapacity; mposition = 0; return *this; } + + /** + * This method resets the position to the beginning of the buffer + * so that it can be either reread or written to all over again. + */ + inline Buffer& rewind() { mposition = 0; return *this; } + + /** + * This method provides for the remaining number of bytes + * that can be read out of the buffer or written into the + * buffer before it's finished. + */ + inline size_t remaining() const { return mlimit - mposition; } + + inline Buffer& put(const void* src, size_t bytes) + { check(bytes); memcpy( buffer + mposition, src, bytes); mposition += bytes; return *this; } + inline Buffer& get(void* dest, size_t bytes) + { check(bytes); memcpy( dest, buffer + mposition, bytes); mposition += bytes; return *this; } + + inline unsigned char* data() const { return buffer; } + inline unsigned char* curPosition() const { return buffer + mposition; } + inline Buffer& setPosition(size_t position) { mposition = position; return *this; } + inline Buffer& forward(size_t positionIncrement) + { check(positionIncrement); mposition += positionIncrement; return *this; } + + inline size_t limit() const { return mlimit; } + inline size_t capacity() const { return mcapacity; } + inline size_t position() const { return mposition; } + +#define DEFAULTBUFFERRELATIVERW(name,type) \ + inline Buffer& put##name(const type & val) { return put(&val, sizeof(type)); } \ + inline type get##name() { type ret; get(&ret, sizeof(type)); return ret; } + + DEFAULTBUFFERRELATIVERW(Bool,bool); + DEFAULTBUFFERRELATIVERW(Int,int); + DEFAULTBUFFERRELATIVERW(Char,char); + DEFAULTBUFFERRELATIVERW(Long,long); + DEFAULTBUFFERRELATIVERW(Float,float); + DEFAULTBUFFERRELATIVERW(Double,double); + DEFAULTBUFFERRELATIVERW(Pointer,void*); + DEFAULTBUFFERRELATIVERW(LongLong,long long); +#undef DEFAULTBUFFERRELATIVERW + + inline Buffer& putString(const char* str) { size_t len = strlen(str) + 1; check(len); put(str, len); return (*this); } + inline Buffer& putString(const std::string& str) { size_t len = str.length() + 1; check(len); put(str.c_str(), len); return (*this); } + + inline std::string getString() { std::string ret((const char*)(buffer + mposition)); size_t len = ret.length() + 1; check(len); mposition += len; return ret; } + inline std::string getString(size_t length) + { + check(length); + std::string ret((const char*)(buffer + mposition),length); + mposition += length; + return ret; + } + inline char* getCharPointerDirect() { char* ret = (char*)(buffer + mposition); size_t len = strlen(ret) + 1; check(len); mposition += len; return ret; } + + }; + +} + diff --git a/xbmc/commons/CMakeLists.txt b/xbmc/commons/CMakeLists.txt new file mode 100644 index 0000000..ff6245d --- /dev/null +++ b/xbmc/commons/CMakeLists.txt @@ -0,0 +1,7 @@ +set(SOURCES Exception.cpp) + +set(HEADERS Buffer.h + Exception.h + ilog.h) + +core_add_library(commons) diff --git a/xbmc/commons/Exception.cpp b/xbmc/commons/Exception.cpp new file mode 100644 index 0000000..b9bd2e5 --- /dev/null +++ b/xbmc/commons/Exception.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "Exception.h" + +#include "utils/log.h" + +namespace XbmcCommons +{ + Exception::~Exception() = default; + + void Exception::LogThrowMessage(const char* prefix) const + { + CLog::Log(LOGERROR, "EXCEPTION Thrown ({}) : {}", classname, message); + } +} + diff --git a/xbmc/commons/Exception.h b/xbmc/commons/Exception.h new file mode 100644 index 0000000..ea2c9bc --- /dev/null +++ b/xbmc/commons/Exception.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +//--------------------------------------------------------- +// This include should be moved to commons but even as it is, +// it wont cause a linker circular dependency since it's just +// a header. +#include "utils/StringUtils.h" +//--------------------------------------------------------- +#include <stdarg.h> + + +#ifdef __GNUC__ +// The 'this' pointer counts as a parameter on member methods. +#define XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT __attribute__((format(printf,2,3))) +#else +#define XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT +#endif + +#define XBMCCOMMONS_COPYVARARGS(fmt) va_list argList; va_start(argList, fmt); Set(fmt, argList); va_end(argList) +#define XBMCCOMMONS_STANDARD_EXCEPTION(E) \ + class E : public XbmcCommons::Exception \ + { \ + public: \ + inline E(const char* message,...) XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT : Exception(#E) { XBMCCOMMONS_COPYVARARGS(message); } \ + \ + inline E(const E& other) : Exception(other) {} \ + } + +namespace XbmcCommons +{ + /** + * This class a superclass for exceptions that want to utilize some + * utility functionality including autologging with the specific + * exception name. + */ + class Exception + { + private: + + std::string classname; + std::string message; + + protected: + + inline explicit Exception(const char* classname_) : classname(classname_) { } + inline Exception(const char* classname_, const char* message_) : classname(classname_), message(message_) { } + inline Exception(const Exception& other) = default; + + /** + * This method is called from the constructor of subclasses. It + * will set the message from varargs as well as call log message + */ + inline void Set(const char* fmt, va_list& argList) + { + message = StringUtils::FormatV(fmt, argList); + } + + /** + * This message can be called from the constructor of subclasses. + * It will set the message and log the throwing. + */ + inline void SetMessage(const char* fmt, ...) XBMCCOMMONS_ATTRIB_EXCEPTION_FORMAT + { + // calls 'set' + XBMCCOMMONS_COPYVARARGS(fmt); + } + + inline void setClassname(const char* cn) { classname = cn; } + + public: + virtual ~Exception(); + + virtual void LogThrowMessage(const char* prefix = NULL) const; + + inline virtual const char* GetExMessage() const { return message.c_str(); } + }; + + /** + * This class forms the base class for unchecked exceptions. Unchecked exceptions + * are those that really shouldn't be handled explicitly. For example, on windows + * when a access violation is converted to a win32_exception, there's nothing + * that can be done in most code. The outer most stack frame might try to + * do some error logging prior to shutting down, but that's really it. + */ + XBMCCOMMONS_STANDARD_EXCEPTION(UncheckedException); + +/** + * In cases where you catch(...){} you will (may) inadvertently be + * catching UncheckedException's. Therefore this macro will allow + * you to do something equivalent to: + * catch (anything except UncheckedException) {} + * + * In order to avoid catching UncheckedException, use the macro as follows: + * + * try { ... } + * XBMCCOMMONS_HANDLE_UNCHECKED + * catch(...){ ... } + */ +// Yes. I recognize that the name of this macro is an oxymoron. +#define XBMCCOMMONS_HANDLE_UNCHECKED \ + catch (const XbmcCommons::UncheckedException& ) { throw; } \ + catch (const XbmcCommons::UncheckedException* ) { throw; } + +} + diff --git a/xbmc/commons/ilog.h b/xbmc/commons/ilog.h new file mode 100644 index 0000000..10b3880 --- /dev/null +++ b/xbmc/commons/ilog.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#define LOG_LEVEL_NONE -1 // nothing at all is logged +#define LOG_LEVEL_NORMAL 0 // shows notice, error, severe and fatal +#define LOG_LEVEL_DEBUG 1 // shows all +#define LOG_LEVEL_DEBUG_FREEMEM 2 // shows all + shows freemem on screen +#define LOG_LEVEL_MAX LOG_LEVEL_DEBUG_FREEMEM + +// ones we use in the code +#define LOGDEBUG 0 +#define LOGINFO 1 +#define LOGWARNING 2 +#define LOGERROR 3 +#define LOGFATAL 4 +#define LOGNONE 5 + +// extra masks - from bit 5 +#define LOGMASKBIT 5 +#define LOGMASK ((1 << LOGMASKBIT) - 1) + +#define LOGSAMBA (1 << (LOGMASKBIT + 0)) +#define LOGCURL (1 << (LOGMASKBIT + 1)) +#define LOGFFMPEG (1 << (LOGMASKBIT + 2)) +#define LOGDBUS (1 << (LOGMASKBIT + 4)) +#define LOGJSONRPC (1 << (LOGMASKBIT + 5)) +#define LOGAUDIO (1 << (LOGMASKBIT + 6)) +#define LOGAIRTUNES (1 << (LOGMASKBIT + 7)) +#define LOGUPNP (1 << (LOGMASKBIT + 8)) +#define LOGCEC (1 << (LOGMASKBIT + 9)) +#define LOGVIDEO (1 << (LOGMASKBIT + 10)) +#define LOGWEBSERVER (1 << (LOGMASKBIT + 11)) +#define LOGDATABASE (1 << (LOGMASKBIT + 12)) +#define LOGAVTIMING (1 << (LOGMASKBIT + 13)) +#define LOGWINDOWING (1 << (LOGMASKBIT + 14)) +#define LOGPVR (1 << (LOGMASKBIT + 15)) +#define LOGEPG (1 << (LOGMASKBIT + 16)) +#define LOGANNOUNCE (1 << (LOGMASKBIT + 17)) +#define LOGWSDISCOVERY (1 << (LOGMASKBIT + 18)) |