From b1296f2c97c6fdc1c6a9922dc09c951b5cafdc12 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 29 Oct 2018 21:49:54 +0100 Subject: Initial commit --- include/FileUtil.hpp | 21 ++++++++ include/dchat/Cache.hpp | 102 +++++++++++++++++++++++++++++++++++++++ include/dchat/Clock.hpp | 16 ++++++ include/dchat/Color.hpp | 24 +++++++++ include/dchat/Gif.hpp | 52 ++++++++++++++++++++ include/dchat/StringView.hpp | 95 ++++++++++++++++++++++++++++++++++++ include/dchat/Vec2.hpp | 32 ++++++++++++ include/dchat/WebPagePreview.hpp | 13 +++++ include/dchat/types.hpp | 22 +++++++++ include/env.hpp | 59 ++++++++++++++++++++++ 10 files changed, 436 insertions(+) create mode 100644 include/FileUtil.hpp create mode 100644 include/dchat/Cache.hpp create mode 100644 include/dchat/Clock.hpp create mode 100644 include/dchat/Color.hpp create mode 100644 include/dchat/Gif.hpp create mode 100644 include/dchat/StringView.hpp create mode 100644 include/dchat/Vec2.hpp create mode 100644 include/dchat/WebPagePreview.hpp create mode 100644 include/dchat/types.hpp create mode 100644 include/env.hpp (limited to 'include') diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp new file mode 100644 index 0000000..cb4e308 --- /dev/null +++ b/include/FileUtil.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "dchat/StringView.hpp" +#include +#include + +namespace dchat +{ + class FileException : public std::runtime_error + { + public: + FileException(const std::string &errMsg) : std::runtime_error(errMsg) {} + }; + + // Throws FileException on error. + // Returned value is allocated with malloc and should be free'd by caller. + StringView getFileContent(const boost::filesystem::path &filepath); + + // Throws FileException on error + void fileReplace(const boost::filesystem::path &filepath, const StringView data); +} diff --git a/include/dchat/Cache.hpp b/include/dchat/Cache.hpp new file mode 100644 index 0000000..debcd5b --- /dev/null +++ b/include/dchat/Cache.hpp @@ -0,0 +1,102 @@ +#pragma once + +#include "types.hpp" +#include "WebPagePreview.hpp" +#include "StringView.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace TinyProcessLib +{ + class Process; +} + +namespace dchat +{ + class Gif; + class WebPagePreview; + + struct ContentByUrlResult + { + enum class Type + { + CACHED, + DOWNLOADING, + FAILED_DOWNLOAD + }; + + enum class CachedType + { + NONE, + TEXTURE_FILEPATH, + GIF, + WEB_PAGE_PREVIEW + }; + + ContentByUrlResult() : textureFilePath(nullptr), type(Type::DOWNLOADING), cachedType(CachedType::NONE) {} + ContentByUrlResult(boost::filesystem::path *_textureFilePath, Type _type) : textureFilePath(_textureFilePath), type(_type), cachedType(CachedType::TEXTURE_FILEPATH) {} + ContentByUrlResult(Gif *_gif, Type _type) : gif(_gif), type(_type), cachedType(CachedType::GIF) {} + ContentByUrlResult(WebPagePreview *_webPagePreview, Type _type) : webPagePreview(_webPagePreview), type(_type), cachedType(CachedType::WEB_PAGE_PREVIEW) {} + + // @texture is null if @type is DOWNLOADING or FAILED_DOWNLOAD + union + { + boost::filesystem::path *textureFilePath; + Gif *gif; + WebPagePreview *webPagePreview; + }; + + Type type; + CachedType cachedType; + i64 lastAccessed; + }; + + using LoadBindsCallbackFunc = std::function; + // @fileContent contains data allocated with new[], deallocate it with delete[] fileContent.data; + // Returned gif should be allocated with @new + using CreateGifFunc = std::function; + + class Cache + { + public: + // @createGifFunc can't be nullptr + Cache(CreateGifFunc createGifFunc); + ~Cache(); + + // Creates directory if it doesn't exist (recursively). Throws boost exception on failure + static boost::filesystem::path getDchatDir(); + + // Creates directory if it doesn't exist (recursively). Throws boost exception on failure + static boost::filesystem::path getImagesDir(); + + // @callbackFunc can't be nullptr + static void loadBindsFromFile(LoadBindsCallbackFunc callbackFunc); + static void replaceBindsInFile(const std::unordered_map &binds); + + // Get cached content or download it. + // Default download file limit is 12MB + // Returns ContentByUrlResult describing texture status. + const ContentByUrlResult getContentByUrl(const std::string &url, int downloadLimitBytes = 12582912); + private: + struct ImageDownloadInfo + { + TinyProcessLib::Process *process; + std::string url; + }; + + std::thread downloadWaitThread; + std::thread checkContentAccessTimeThread; + std::vector imageDownloadProcesses; + std::vector imageDownloadProcessesQueue; + std::mutex imageDownloadMutex; + bool alive; + std::unordered_map contentUrlCache; + CreateGifFunc createGifFunc; + }; +} diff --git a/include/dchat/Clock.hpp b/include/dchat/Clock.hpp new file mode 100644 index 0000000..97f78a8 --- /dev/null +++ b/include/dchat/Clock.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "types.hpp" + +namespace dchat +{ + class Clock + { + public: + Clock(); + void restart(); + i64 getElapsedTimeMillis() const; + private: + i64 startTime; + }; +} \ No newline at end of file diff --git a/include/dchat/Color.hpp b/include/dchat/Color.hpp new file mode 100644 index 0000000..2a5d121 --- /dev/null +++ b/include/dchat/Color.hpp @@ -0,0 +1,24 @@ +#pragma once + +namespace dchat +{ + class Color + { + public: + Color() : Color(255, 255, 255, 255) {} + Color(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha = 255) + { + data[0] = red; + data[1] = green; + data[2] = blue; + data[3] = alpha; + } + + unsigned char red() const { return data[0]; } + unsigned char green() const { return data[1]; } + unsigned char blue() const { return data[2]; } + unsigned char alpha() const { return data[3]; } + + unsigned char data[4]; + }; +} \ No newline at end of file diff --git a/include/dchat/Gif.hpp b/include/dchat/Gif.hpp new file mode 100644 index 0000000..f97ff2f --- /dev/null +++ b/include/dchat/Gif.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "StringView.hpp" +#include "Vec2.hpp" +#include "Color.hpp" +#include "Clock.hpp" +#include +#include +extern "C" +{ +#include +} + +namespace dchat +{ + class GifLoadException : public std::runtime_error + { + public: + GifLoadException(const std::string &errMsg) : std::runtime_error(errMsg) {} + }; + + class Gif + { + public: + // Throws GifLoadException on error + Gif(const boost::filesystem::path &filepath); + Gif(StringView fileContent); + virtual ~Gif(); + + Vec2u getSize() const; + void update(); + + static bool isDataGif(const StringView &data); + protected: + // Return false if texture creation failed + virtual bool createTexture(int width, int height) = 0; + virtual void setPosition(const Vec2f &position) = 0; + virtual Vec2f getPosition() const = 0; + virtual void setScale(const Vec2f &scale) = 0; + virtual void setColor(Color color) = 0; + // Size of texture data is same as the size that the texture was created with (also same size returned by @getSize function) + virtual void updateTexture(void *textureData) = 0; + private: + void init(); + private: + gif_animation gif; + StringView fileContent; + unsigned int currentFrame; + double timeElapsedCs; + Clock frameTimer; + }; +} diff --git a/include/dchat/StringView.hpp b/include/dchat/StringView.hpp new file mode 100644 index 0000000..659610a --- /dev/null +++ b/include/dchat/StringView.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "types.hpp" +#include +#include + +namespace dchat +{ + template + class BasicStringView + { + public: + BasicStringView() : data(nullptr), size(0) + { + + } + + BasicStringView(const BasicStringView &other) : data(other.data), size(other.size) + { + + } + + BasicStringView(const CharType *_data) : data(_data), size(strlen(_data)) + { + + } + + BasicStringView(const CharType *_data, usize _size) : data(_data), size(_size) + { + + } + + BasicStringView& operator = (const BasicStringView &other) + { + data = other.data; + size = other.size; + return *this; + } + + BasicStringView(BasicStringView &&other) + { + data = other.data; + size = other.size; + + other.data = nullptr; + other.size = 0; + } + + bool equals(const BasicStringView &other) const + { + if(size != other.size) return false; + return memcmp(data, other.data, size * sizeof(CharType)) == 0; + } + + bool operator == (const BasicStringView &other) const + { + return equals(other); + } + + bool operator != (const BasicStringView &other) const + { + return !equals(other); + } + + CharType operator [] (usize index) const + { + assert(index < size); + return data[index]; + } + + // Returns -1 if substr not found. + // TODO: Make this more efficient + usize find(const BasicStringView &substr, usize offset = 0) const + { + if(substr.size == 0) + return -1; + + if(offset + substr.size > size) + return -1; + + for(usize i = offset; i < size - (substr.size - 1); ++i) + { + if(memcmp(data + i, substr.data, substr.size * sizeof(CharType)) == 0) + return i; + } + return -1; + } + + const CharType *data; + usize size; + }; + + using StringView = BasicStringView; + using StringViewUtf32 = BasicStringView; +} diff --git a/include/dchat/Vec2.hpp b/include/dchat/Vec2.hpp new file mode 100644 index 0000000..cb5f8c0 --- /dev/null +++ b/include/dchat/Vec2.hpp @@ -0,0 +1,32 @@ +#pragma once + +namespace dchat +{ + template + struct Vec2 + { + T x, y; + + Vec2() : x(), y() {} + Vec2(T _x, T _y) : x(_x), y(_y) {} +/* + Vec2(const Vec2 &other) + { + x = other.x; + y = other.y; + } + + Vec2& operator = (const Vec2 &other) + { + x = other.x; + y = other.y; + return *this; + } +*/ + }; + + using Vec2f = Vec2; + using Vec2d = Vec2; + using Vec2i = Vec2; + using Vec2u = Vec2; +} \ No newline at end of file diff --git a/include/dchat/WebPagePreview.hpp b/include/dchat/WebPagePreview.hpp new file mode 100644 index 0000000..df75419 --- /dev/null +++ b/include/dchat/WebPagePreview.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace dchat +{ + class WebPagePreview + { + public: + std::string title; + std::string description; + }; +} diff --git a/include/dchat/types.hpp b/include/dchat/types.hpp new file mode 100644 index 0000000..97bfc96 --- /dev/null +++ b/include/dchat/types.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace dchat +{ + typedef int8_t i8; + typedef int16_t i16; + typedef int32_t i32; + typedef int64_t i64; + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + typedef float f32; + typedef double f64; + + typedef intptr_t ssize; + typedef uintptr_t usize; +} diff --git a/include/env.hpp b/include/env.hpp new file mode 100644 index 0000000..4061518 --- /dev/null +++ b/include/env.hpp @@ -0,0 +1,59 @@ +#pragma once + +#define OS_FAMILY_WINDOWS 0 +#define OS_FAMILY_POSIX 1 + +#define OS_TYPE_WINDOWS 0 +#define OS_TYPE_LINUX 1 + +#if defined(_WIN32) || defined(_WIN64) + #if defined(_WIN64) + #define SYS_ENV_64BIT + #else + #define SYS_ENV_32BIT + #endif + #define OS_FAMILY OS_FAMILY_WINDOWS + #define OS_TYPE OS_TYPE_WINDOWS + + #ifndef UNICODE + #define UNICODE + #endif + + #ifndef _UNICODE + #define _UNICODE + #endif + + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + + #include +#endif + +#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(_POSIX_VERSION) + #define OS_FAMILY OS_FAMILY_POSIX +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + #define OS_TYPE OS_TYPE_LINUX +#endif + +#if defined(__GNUC__) + #if defined(__x86_64__) || defined(__pc64__) + #define SYS_ENV_64BIT + #else + #define SYS_ENV_32BIT + #endif +#endif + +#if !defined(SYS_ENV_32BIT) && !defined(SYS_ENV_64BIT) + #error "System is not detected as either 32-bit or 64-bit" +#endif + +#if !defined(OS_FAMILY) + #error "System not supported. Only Windows and Posix systems supported right now" +#endif + +#if !defined(OS_TYPE) + #error "System not supported. Only Windows and linux systems supported right now" +#endif -- cgit v1.2.3