diff --git a/.gitmodules b/.gitmodules
index 112d7c0..0eb91ee 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
[submodule "lib/boost"]
path = lib/boost
url = git://github.com/ryppl/boost-svn.git
+[submodule "lib/json-parser"]
+ path = lib/json-parser
+ url = git://github.com/udp/json-parser.git
diff --git a/build_clang_win.bat b/build_clang_win.bat
index 6d3fdc7..e738a8f 100644
--- a/build_clang_win.bat
+++ b/build_clang_win.bat
@@ -1,2 +1,2 @@
-clang++ -std=c++11 -o chesspp.exe -isystem lib/boost/boost/ -isystem lib/SFML/include/ -Llib/SFML/lib/ -lsfml-audio -lsfml-graphics -lsfml-main -lsfml-system -lsfml-window src/*.cpp src/board/*.cpp
+clang++ -std=c++11 -o chesspp.exe -isystem lib/boost/boost/ -isystem lib/SFML/include/ -isystem lib/json-parser/ -Llib/SFML/lib/ -lsfml-audio -lsfml-graphics -lsfml-main -lsfml-system -lsfml-window lib/json-parser/json.c src/*.cpp src/board/*.cpp
pause
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..5112e74
--- /dev/null
+++ b/config.json
@@ -0,0 +1,20 @@
+{
+ "chesspp":
+ {
+ "board":
+ {
+ "initial_layout": "res/games/new_game.txt",
+ "width": 8,
+ "height": 8,
+ "cell_width": 80,
+ "cell_height": 80,
+
+ "images":
+ {
+ "board": "res/img/chessboard_640x640.png",
+ "pieces": "res/img/chess_pieces_80x80_each.png",
+ "validMove": "res/img/valid_move.png"
+ }
+ }
+ }
+}
diff --git a/config.xml b/config.xml
deleted file mode 100644
index cf5ef1b..0000000
--- a/config.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- res/games/new_game.txt
- 8
- 8
- 80
- 80
-
-
-
- res/img/chessboard_640x640.png
- res/img/chess_pieces_80x80_each.png
- res/img/valid_move.png
-
-
diff --git a/lib/json-parser b/lib/json-parser
new file mode 160000
index 0000000..1e58690
--- /dev/null
+++ b/lib/json-parser
@@ -0,0 +1 @@
+Subproject commit 1e586904a1294576fd43a75cf186599acbbeea2a
diff --git a/src/AppStateGame.hpp b/src/AppStateGame.hpp
index fd40aa3..dea2413 100644
--- a/src/AppStateGame.hpp
+++ b/src/AppStateGame.hpp
@@ -20,7 +20,7 @@ namespace chesspp
Board* board;
graphics::GraphicsHandler graphics;
- configuration::BoardConfig boardConfig;
+ config::BoardConfig boardConfig;
public:
AppStateGame(Application* _app, sf::RenderWindow *_display);
diff --git a/src/Configuration.hpp b/src/Configuration.hpp
index 69051da..efb464d 100644
--- a/src/Configuration.hpp
+++ b/src/Configuration.hpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#if defined(__linux__)
#include
@@ -15,14 +16,14 @@
#include "Exception.hpp"
-#include "XMLReader.hpp"
+#include "JsonReader.hpp"
#include "board/logger.hpp"
namespace chesspp
{
- namespace configuration
+ namespace config
{
- class configuration
+ class Configuration
{
protected:
std::string res_path;
@@ -31,62 +32,67 @@ namespace chesspp
// /res/img/... should be where resources are stored.
//OS x, resource path is defined as the absolute path to the Resources folder of the .app structure.
// <.app>/Contents/Resources/res/img... should be where resources are stored.
- std::string getResourcePath()
+ static std::string getResourcePath()
{
char buf[1024];
- uint32_t size = sizeof(buf);
+ std::uint32_t size = sizeof(buf);
memset(buf, 0, size);
std::string ret;
#if defined(__linux__)
if(readlink("/proc/self/exe", buf, size) == -1)
- throw chesspp::exception("Unable to determine executable path on Linux.");
+ throw Exception("Unable to determine executable path on Linux.");
ret = buf;
ret = ret.substr(0, ret.find_last_of('/')+1);
#elif defined(_WIN32)
if(GetModuleFileNameA(NULL, buf, size) == 0)
- throw chesspp::exception("Unable to determine executable path on Windows.");
+ throw Exception("Unable to determine executable path on Windows.");
ret = buf;
boost::replace_all(ret, "\\", "/");
ret = ret.substr(0, ret.find_last_of('/')+1);
#elif defined(__APPLE__)
if (_NSGetExecutablePath(buf, &size) != 0)
- throw chesspp::exception("Unable to determine executable path on OS x. (Buffer size too small?)");
+ throw Exception("Unable to determine executable path on OS x. (Buffer size too small?)");
ret = buf;
ret = ret.substr(0, ret.find_last_of('/')+1) + "../Resources/";
//Need to go up one directory because the exe is stored in <.app>/Contents/MacOS/,
//And we need <.app>/Contents/Resources
#else
- throw chesspp::exception("Unknown OS. Unable to determine executable path.");
+ throw Exception("Unknown OS. Unable to determine executable path.");
#endif
return ret;
}
- XMLReader reader;
+ JsonReader reader;
public:
- configuration(const std::string &configFile) : res_path(getResourcePath()), reader(getResourcePath() + configFile) {}
- virtual ~configuration() {}
+ Configuration(const std::string &configFile) noexcept(false) : res_path(getResourcePath()), reader(std::ifstream(getResourcePath() + configFile))
+ {
+ }
+ virtual ~Configuration() noexcept
+ {
+ }
};
- class BoardConfig : public configuration
+ class BoardConfig : public Configuration
{
std::string initial_layout;
- uint8_t board_width, board_height;
- uint16_t cell_width, cell_height;
+ std::uint8_t board_width, board_height;
+ std::uint16_t cell_width, cell_height;
public:
- BoardConfig() : configuration("config.xml")
+ BoardConfig()
+ : Configuration("config.json")
+ , initial_layout (res_path + std::string(reader()["chesspp"]["board"]["initial_layout"]))
+ , board_width(reader()["chesspp"]["board"]["width"])
+ , board_height(reader()["chesspp"]["board"]["height"])
+ , cell_width(reader()["chesspp"]["board"]["cell_width"])
+ , cell_height(reader()["chesspp"]["board"]["cell_height"])
{
- initial_layout = res_path + reader.getProperty("chesspp.data.board.initial_layout");
- board_width = reader.getProperty("chesspp.data.board.width");
- board_height = reader.getProperty("chesspp.data.board.height");
- cell_width = reader.getProperty("chesspp.data.board.cell_width");
- cell_height = reader.getProperty("chesspp.data.board.cell_height");
}
std::string getInitialLayout() { return initial_layout; }
@@ -96,16 +102,17 @@ namespace chesspp
uint16_t getCellHeight() { return cell_height; }
};
- class GraphicsConfig : public configuration
+ class GraphicsConfig : public Configuration
{
std::string path_board, path_pieces, path_validMove;
public:
- GraphicsConfig() : configuration("config.xml")
+ GraphicsConfig()
+ : Configuration("config.json")
+ , path_board(res_path + std::string(reader()["chesspp"]["board"]["images"]["board"]))
+ , path_pieces(res_path + std::string(reader()["chesspp"]["board"]["images"]["pieces"]))
+ , path_validMove(res_path + std::string(reader()["chesspp"]["board"]["images"]["validMove"]))
{
- path_board = res_path + reader.getProperty("chesspp.images.board");
- path_pieces = res_path + reader.getProperty("chesspp.images.pieces");
- path_validMove = res_path + reader.getProperty("chesspp.images.validMove");
}
std::string getSpritePath_board() { return path_board; }
diff --git a/src/Exception.hpp b/src/Exception.hpp
index df13d43..c8ccc96 100644
--- a/src/Exception.hpp
+++ b/src/Exception.hpp
@@ -3,23 +3,72 @@
#include
#include
+#include
+#include
namespace chesspp
{
- class exception : public std::exception
+ class Exception : public std::exception
{
- using std::exception::what;
+ std::string e; //message
+ std::exception const&by; //caused by other exception, == *this otherwise
+
public:
- exception() {}
- virtual ~exception() {};
- exception(const exception &) {}
+ Exception(std::string const&e = "") noexcept(noexcept(std::string(std::string(""))))
+ : e(e), by(*this) //ignore benign warning about use of *this
+ {
+ }
+ Exception(std::string const&e, std::exception const&by) noexcept(noexcept(std::string(std::string(""))))
+ : e(e), by(by)
+ {
+ }
+ Exception(Exception const&) = default;
+ Exception(Exception &&) noexcept = default;
+ Exception &operator=(Exception const&) = default;
+ Exception &operator=(Exception &&) = default;
+ virtual ~Exception() noexcept = default;
- exception(const std::string &_e) : e(_e) {}
- virtual const char *what() { return e.c_str(); }
+ virtual bool operator==(std::exception const&other) const noexcept
+ {
+ return dynamic_cast(&other) == this;
+ }
+ friend bool operator==(std::exception const&e1, Exception const&e2) noexcept
+ {
+ return e2 == e1; //calls above operator==
+ }
- private:
- std::string e;
+ virtual const char *what() const noexcept
+ {
+ return e.c_str();
+ }
+ virtual operator std::string() const noexcept
+ {
+ return e;
+ }
+ virtual std::exception const&cause() const noexcept
+ {
+ return by;
+ }
+ std::string fullMessage() const noexcept
+ {
+ std::string full = std::string(typeid(*this).name()) + " (::chespp::Exception): message = {" + e + "}";
+ if(!(by == *this)) //cannot use !=, `using rel_ops` is below
+ {
+ full += ", caused by {";
+ if(typeid(by) == typeid(Exception))
+ {
+ full += dynamic_cast(by).fullMessage();
+ }
+ else
+ {
+ full += by.what();
+ }
+ full += "}";
+ }
+ return full;
+ }
};
+ using std::rel_ops::operator!=; //to avoid defining above
}
#endif
diff --git a/src/Graphics.cpp b/src/Graphics.cpp
index 7b62c5f..eca0b48 100644
--- a/src/Graphics.cpp
+++ b/src/Graphics.cpp
@@ -8,8 +8,8 @@ namespace chesspp
{
try
{
- configuration::BoardConfig boardConfig;
- configuration::GraphicsConfig graphicsConfig;
+ config::BoardConfig boardConfig;
+ config::GraphicsConfig graphicsConfig;
board = sf::Sprite(TextureManager::getInstance().Load(graphicsConfig.getSpritePath_board()));
pieces = sf::Sprite(TextureManager::getInstance().Load(graphicsConfig.getSpritePath_pieces()));
@@ -17,7 +17,7 @@ namespace chesspp
cell_size = boardConfig.getCellWidth();
}
- catch (chesspp::exception &e)
+ catch(Exception &e)
{
#ifdef _DEBUG
cout << "Error: " << e.what() << endl;
diff --git a/src/JsonReader.hpp b/src/JsonReader.hpp
new file mode 100644
index 0000000..1ece7d3
--- /dev/null
+++ b/src/JsonReader.hpp
@@ -0,0 +1,116 @@
+#ifndef __JavaScriptObjectNotation_Reader_HeaderPlusPlus__
+#define __JavaScriptObjectNotation_Reader_HeaderPlusPlus__
+
+#include
+#include
+#include
+#include
+#include
+
+#include "Exception.hpp"
+
+namespace chesspp
+{
+ class JsonReader
+ {
+ json_value *json {nullptr};
+ public:
+ JsonReader(std::istream &s) noexcept(false)
+ {
+ std::string str ((std::istreambuf_iterator(s)), std::istreambuf_iterator());
+ json_settings options {};
+ char error[128]; //128 from json.c implementation, subject to change
+ json = json_parse_ex(&options, str.c_str(), str.length(), error);
+ if(json == nullptr)
+ {
+ //no manual cleanup needed
+ throw Exception(std::string("Error loading JSON: ") + error, Exception(str)); //attached JSON as 'caused by'
+ }
+ }
+ JsonReader(std::istream &&s) noexcept(false) : JsonReader(s)
+ {
+ }
+ ~JsonReader() noexcept
+ {
+ json_value_free(json), json = nullptr;
+ }
+
+ class NestedValue
+ {
+ friend class ::chesspp::JsonReader;
+ json_value const&value;
+ NestedValue(json_value const&value) noexcept : value(value)
+ {
+ }
+ NestedValue &operator=(NestedValue const&) noexcept = delete;
+ public:
+ NestedValue(NestedValue const&) noexcept = default;
+ NestedValue(NestedValue &&) noexcept = default;
+ NestedValue &operator=(NestedValue &&) noexcept = default;
+ ~NestedValue() noexcept = default;
+
+ json_type type() const noexcept //may wish to add an abstraction layer between json-parser
+ {
+ return value.type;
+ }
+ NestedValue parent() const noexcept(false)
+ {
+ if(value.parent)
+ {
+ return *value.parent;
+ }
+ throw Exception("No parent json value");
+ }
+
+ NestedValue operator[](std::string const&name) const noexcept(noexcept(name.c_str()))
+ {
+ return value[name.c_str()];
+ }
+ NestedValue operator[](char const*name) //without this, ambiguity occurs
+ {
+ return value[name];
+ }
+ NestedValue operator[](std::size_t index) const noexcept
+ {
+ return value[static_cast(index)];
+ }
+ operator std::string() const noexcept(noexcept(std::string("")))
+ {
+ return static_cast(value);
+ }
+ //I tried an approach with templates, but the compiler was never able to deduce the corect template argument
+ operator std:: int8_t() const noexcept { return static_cast(static_cast(value)); }
+ operator std:: uint8_t() const noexcept { return static_cast(static_cast(value)); }
+ operator std:: int16_t() const noexcept { return static_cast(static_cast(value)); }
+ operator std::uint16_t() const noexcept { return static_cast(static_cast(value)); }
+ operator std:: int32_t() const noexcept { return static_cast(static_cast(value)); }
+ operator std::uint32_t() const noexcept { return static_cast(static_cast(value)); }
+ operator std:: int64_t() const noexcept { return static_cast(static_cast(value)); }
+ operator std::uint64_t() const noexcept { return static_cast(static_cast(value)); }
+ operator bool() const noexcept
+ {
+ return value;
+ }
+ operator double() const noexcept
+ {
+ return value;
+ }
+ };
+
+ NestedValue access() const noexcept
+ {
+ return *json;
+ }
+ NestedValue operator()() const noexcept
+ {
+ return access();
+ }
+
+ json_value *&implementation() noexcept //only for extreme-use cases
+ {
+ return json;
+ }
+ };
+}
+
+#endif
diff --git a/src/Main.cpp b/src/Main.cpp
index 008e5c1..94d51d0 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -1,16 +1,16 @@
+#include
+
#include "Application.hpp"
int main()
{
try
{
- chesspp::Application app;
- return app.Exec();
+ return chesspp::Application().Exec();
}
- catch (chesspp::exception& ex)
+ catch (chesspp::Exception &e)
{
- std::cout << "Caught in main: " << ex.what() << '\n';
+ std::clog << "Caught in main: " << e.fullMessage() << std::endl;
+ return -1;
}
-
- return 0;
}
diff --git a/src/ResourceManager.hpp b/src/ResourceManager.hpp
index b99eb21..d14eb83 100644
--- a/src/ResourceManager.hpp
+++ b/src/ResourceManager.hpp
@@ -65,7 +65,7 @@ namespace chesspp
//else, load resource
ptr_t p(onLoadResource(key));
if(p.get() == NULL)
- throw chesspp::exception("Error loading Image at " + key); //figure out better way to throw exceptions later
+ throw Exception("Error loading Image at " + key); //figure out better way to throw exceptions later
m_map.insert(std::make_pair(key, std::move(p)));
return *m_map[key].get();
diff --git a/src/XMLReader.hpp b/src/XMLReader.hpp
deleted file mode 100644
index b97a964..0000000
--- a/src/XMLReader.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _XMLREADER_H
-#define _XMLREADER_H
-
-#include "Exception.hpp"
-
-#include
-#include
-#include
-#include
-
-namespace chesspp
-{
- class XMLReader
- {
- class XMLReaderImpl
- {
- friend class XMLReader;
- boost::property_tree::ptree tree;
-
- public:
- XMLReaderImpl(const std::string &file)
- {
- try {
- boost::property_tree::read_xml(file, tree, boost::property_tree::xml_parser::no_comments | boost::property_tree::xml_parser::trim_whitespace);
- } catch(boost::property_tree::xml_parser_error &p) {
- throw chesspp::exception(p.what());
- }
- }
-
- ~XMLReaderImpl() {}
- };
-
- public:
- XMLReader(const std::string &file) : impl(new XMLReaderImpl(file)) {};
- ~XMLReader() {}
-
- template
- T getProperty(const std::string &key)
- {
- boost::optional ret = impl->tree.get_optional(key);
- if(ret == boost::optional())
- throw chesspp::exception("Error: XMLReader::getProperty failed.");
- return ret.get();
- }
-
- private:
- std::unique_ptr impl;
- };
-}
-
-#endif