From d90cecc758d3c348f3aedf9c6e45a13ba6a0b0c3 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sun, 22 Sep 2024 16:09:14 +0200 Subject: --- .gitignore | 2 ++ .gitmodules | 5 ++++- CMakeLists.txt | 13 +++++++++++++ Exception.cpp | 34 ++++++++++++++++++++++++++++++++++ Exception.h | 17 +++++++++++++++++ File.cpp | 9 +++++++++ File.h | 25 +++++++++++++++++++++++++ FileReader.cpp | 32 ++++++++++++++++++++++++++++++++ FileReader.h | 26 ++++++++++++++++++++++++++ HTTPFile.cpp | 28 ++++++++++++++++++++++++++++ HTTPFile.h | 29 +++++++++++++++++++++++++++++ LocalFile.cpp | 36 ++++++++++++++++++++++++++++++++++++ LocalFile.h | 29 +++++++++++++++++++++++++++++ docs/class-diag.puml | 26 ++++++++++++++++++++++++++ lazy.mk | 33 --------------------------------- lib/cpr | 1 + main.cpp | 12 +++++++++++- 17 files changed, 322 insertions(+), 35 deletions(-) create mode 100644 .gitignore create mode 100644 Exception.cpp create mode 100644 Exception.h create mode 100644 File.cpp create mode 100644 File.h create mode 100644 FileReader.cpp create mode 100644 FileReader.h create mode 100644 HTTPFile.cpp create mode 100644 HTTPFile.h create mode 100644 LocalFile.cpp create mode 100644 LocalFile.h delete mode 100644 lazy.mk create mode 160000 lib/cpr diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7194ea7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.cache +build diff --git a/.gitmodules b/.gitmodules index 8c7dbb0..b260b07 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,8 @@ [submodule "lib/SDL"] path = lib/SDL url = https://github.com/libsdl-org/SDL - branch = release-2.30.x + shallow = true +[submodule "lib/cpr"] + path = lib/cpr + url = https://github.com/libcpr/cpr shallow = true diff --git a/CMakeLists.txt b/CMakeLists.txt index e4f76a5..67c5607 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,22 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) set(CMAKE_BUILD_TYPE Debug) +find_package(SDL2 REQUIRED) +find_package(cpr REQUIRED) + project(main C CXX) add_executable(main main.cpp + File.cpp + HTTPFile.cpp + LocalFile.cpp + Exception.cpp + FileReader.cpp +) + +target_link_libraries(main + SDL2 + cpr ) diff --git a/Exception.cpp b/Exception.cpp new file mode 100644 index 0000000..d9765da --- /dev/null +++ b/Exception.cpp @@ -0,0 +1,34 @@ +#include +#include +#include + +#include "Exception.h" + +Exception::~Exception() { + if (error != NULL) + free(error); +} + +const char * Exception::what() { + return error; +} + +void Exception::va_format(va_list args, const char * fmt) { + va_list args_copy; + va_copy(args_copy, args); + + size_t sz = vsnprintf(NULL, 0, fmt, args_copy) + 1; + if (error != NULL) free(error); + error = (char *) malloc(sz); + va_end(args_copy); + + vsnprintf(error, sz, fmt, args); +} + +Exception::Exception(const char * fmt, ...) { + va_list args; + va_start(args, fmt); + va_format(args, fmt); + va_end(args); +} + diff --git a/Exception.h b/Exception.h new file mode 100644 index 0000000..31c517b --- /dev/null +++ b/Exception.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +class Exception : public std::exception { +public: + Exception(const char * fmt, ...); + virtual ~Exception(); + virtual const char * what(); + +protected: + Exception() = default; + void va_format(va_list args, const char * fmt); + char * error = NULL; +}; + diff --git a/File.cpp b/File.cpp new file mode 100644 index 0000000..bc31b1c --- /dev/null +++ b/File.cpp @@ -0,0 +1,9 @@ +#include + +#include "File.h" +#include "FileReader.h" + +File::File(const std::string protocol) { + FileReader::assign(protocol, this); +} + diff --git a/File.h b/File.h new file mode 100644 index 0000000..71a96e0 --- /dev/null +++ b/File.h @@ -0,0 +1,25 @@ +#pragma once + +class FileReader; + +#include + +class File { +protected: + virtual void open(const std::string url) = 0; +public: + virtual void close() = 0; + virtual const std::string read() = 0; + +public: + virtual ~File() = default; + +protected: + File() = default; + virtual File * clone() const = 0; + +protected: + File(const std::string protocol); + friend FileReader; +}; + diff --git a/FileReader.cpp b/FileReader.cpp new file mode 100644 index 0000000..503aee5 --- /dev/null +++ b/FileReader.cpp @@ -0,0 +1,32 @@ +#include "FileReader.h" +#include "File.h" + +File & FileReader::open(const std::string url) { + File * reader = find_reader(url)->clone(); + reader->open(url); + return *reader; +} + +void FileReader::assign(const std::string type, const File * node) { + static FactoryMap & map = get_map(); + map[type] = node; +} + +FactoryMap & FileReader::get_map() { + static FactoryMap map; + return map; +} + +const File * FileReader::find_reader(const std::string type) { + static FactoryMap & map = get_map(); + + // try to find protocol by prefix + for (auto item : map) { + if (!type.starts_with(item.first)) continue; + return item.second; + } + + // fallback is local file + return map.find("file://")->second; +} + diff --git a/FileReader.h b/FileReader.h new file mode 100644 index 0000000..b2d8b37 --- /dev/null +++ b/FileReader.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "File.h" + +using FactoryMap = std::map; + +class FileReader { +public: + static File & open(const std::string url); + +private: + FileReader() = default; + virtual ~FileReader() = default; + +private: + static void assign(const std::string type, const File * node); + static FactoryMap & get_map(); + static const File * find_reader(const std::string type); + +private: + friend File; +}; + diff --git a/HTTPFile.cpp b/HTTPFile.cpp new file mode 100644 index 0000000..a1d9185 --- /dev/null +++ b/HTTPFile.cpp @@ -0,0 +1,28 @@ +#include + +#include "HTTPFile.h" +#include "Exception.h" + +HTTPFile HTTPFile::instance(protocol); + +void HTTPFile::open(const std::string url) { + _res = cpr::Get(cpr::Url{url}); + +} + +void HTTPFile::close() { } + +const std::string HTTPFile::read() { + return _res.text.data(); +} + +HTTPFile::~HTTPFile() { + close(); +} + +HTTPFile * HTTPFile::clone() const { + return new HTTPFile(this); +} + +HTTPFile::HTTPFile(const HTTPFile *) : File() { } + diff --git a/HTTPFile.h b/HTTPFile.h new file mode 100644 index 0000000..94207f2 --- /dev/null +++ b/HTTPFile.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "File.h" + +class HTTPFile : File { +protected: + virtual void open(const std::string url); +public: + virtual void close(); + virtual const std::string read(); + +public: + virtual ~HTTPFile(); + +private: + HTTPFile(const HTTPFile *); + virtual HTTPFile * clone() const; + +private: + using File::File; + constexpr static const std::string protocol = "https://"; + static HTTPFile instance; + +private: + cpr::Response _res; +}; + diff --git a/LocalFile.cpp b/LocalFile.cpp new file mode 100644 index 0000000..2f4140d --- /dev/null +++ b/LocalFile.cpp @@ -0,0 +1,36 @@ +#include +#include + +#include "LocalFile.h" +#include "Exception.h" + +LocalFile LocalFile::instance(protocol); + +void LocalFile::open(const std::string url) { + std::string path = url; + if (path.starts_with(protocol)) + path = path.substr(protocol.size()); + + std::ifstream _file(path); + if (!_file.is_open()) + throw Exception("Cannot open file://%s\n", path.c_str()); +} + +void LocalFile::close() { + if (_file.is_open()) _file.close(); +} + +const std::string LocalFile::read() { + return std::string(std::istreambuf_iterator(_file), std::istreambuf_iterator()); +} + +LocalFile::~LocalFile() { + close(); +} + +LocalFile * LocalFile::clone() const { + return new LocalFile(this); +} + +LocalFile::LocalFile(const LocalFile *) : File() { } + diff --git a/LocalFile.h b/LocalFile.h new file mode 100644 index 0000000..9529053 --- /dev/null +++ b/LocalFile.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "File.h" + +class LocalFile : File { +protected: + virtual void open(const std::string url); +public: + virtual void close(); + virtual const std::string read(); + +public: + virtual ~LocalFile(); + +private: + LocalFile(const LocalFile *); + virtual LocalFile * clone() const; + +private: + using File::File; + constexpr static const std::string protocol = "file://"; + static LocalFile instance; + +private: + std::ifstream _file; +}; + diff --git a/docs/class-diag.puml b/docs/class-diag.puml index 17e2b59..6de5851 100644 --- a/docs/class-diag.puml +++ b/docs/class-diag.puml @@ -3,11 +3,17 @@ !theme plain skinparam linetype ortho skinparam classAttributeIconSize 0 +' skinparam packageStyle rectangle + +class main as "main()" +hide main circle +hide main members class FileReader { + open(path) + read() + close() + - protocol } class LocalFile @@ -31,6 +37,20 @@ class YellowTileBehavior class Artist +class ArtistDeserializer +class CanvasDeserializer + +package CPR { } +package SDL2 { } + +interface Parser { + + parse(f: FileReader) +} + +class CSVParser +class XMLParser +class TXTParser + FileReader <|-- LocalFile FileReader <|-- HTTPFile Canvas "1" -> "*" Tile @@ -39,6 +59,12 @@ TileBehavior <|-- RedTileBehavior TileBehavior <|-- BlueTileBehavior TileBehavior <|-- YellowTileBehavior +Parser <|-- CSVParser +Parser <|-- TXTParser +Parser <|-- XMLParser + +HTTPFile ..> CPR + TileFactory --> Tile : create diff --git a/lazy.mk b/lazy.mk deleted file mode 100644 index a591fd5..0000000 --- a/lazy.mk +++ /dev/null @@ -1,33 +0,0 @@ -# NOTE: CMAKE IS THE PRIMARY BUILD SYSTEM FOR THIS PROJECT. THIS FILE IS -# PROVIDED PURELY FOR CONVENIENCE, AND SHOULD NOT BECOME AN ESSENTIAL PART OF -# THE BUILD SYSTEM! - -BUILD_DIR ?= build -TARGET ?= $(BUILD_DIR)/main - -# always generate fresh build rules when cmake is re-run -CMFLAGS += --fresh -# make cmake shut up -CMFLAGS += --log-level WARNING -CMFLAGS += -Wno-deprecated - -.PHONY: FORCE - -all: FORCE $(TARGET) - -$(BUILD_DIR)/build.ninja: CMakeLists.txt - @mkdir -p $(BUILD_DIR) - @cmake -B $(BUILD_DIR) -G Ninja $(CMFLAGS) - -$(TARGET): $(BUILD_DIR)/build.ninja FORCE - @ninja -C $(BUILD_DIR) - -clean: FORCE - $(RM) -r $(BUILD_DIR) - -# Forward any unknown targets to Ninja -ifneq ($(MAKECMDGOALS),) -%:: - @ninja -C $(BUILD_DIR) $@ -endif - diff --git a/lib/cpr b/lib/cpr new file mode 160000 index 0000000..99f044e --- /dev/null +++ b/lib/cpr @@ -0,0 +1 @@ +Subproject commit 99f044e386115194485ce77e326c31e9bd80bb00 diff --git a/main.cpp b/main.cpp index 1846bfb..3ee5b4c 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,14 @@ -int main() { +#include + +#include "FileReader.h" + +int main(int argc, char** argv) { + for (int i = 1; i < argc; i++) { + File & r = FileReader::open(argv[i]); + printf("-- %s --\n%s\n", argv[i], r.read().c_str()); + r.close(); + } + return 0; } -- cgit v1.2.3