Mercurial > malikania
changeset 189:f28cb6d04731
Misc: extreme refactoring
line wrap: on
line diff
--- a/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ b/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -48,12 +48,12 @@ add_subdirectory(examples) add_subdirectory(extern) add_subdirectory(docs) -add_subdirectory(libdb) -add_subdirectory(libcommon) -add_subdirectory(libcommon-js) -add_subdirectory(libclient) -add_subdirectory(libclient-js) -add_subdirectory(libserver) +add_subdirectory(libmlk) +add_subdirectory(libmlk-client) +add_subdirectory(libmlk-client-js) +add_subdirectory(libmlk-db) +add_subdirectory(libmlk-js) +add_subdirectory(libmlk-server) add_subdirectory(client) add_subdirectory(server)
--- a/examples/js-animation/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/examples/js-animation/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -22,19 +22,21 @@ #include <boost/timer/timer.hpp> +#include <malikania/locator.hpp> + #include <malikania/client/loader.hpp> -#include <malikania/js_client_resources_loader.hpp> -#include <malikania/js_animation.hpp> -#include <malikania/js_animator.hpp> -#include <malikania/js_window.hpp> -#include <malikania/locator.hpp> +#include <malikania/client/js/loader_js_api.hpp> +#include <malikania/client/js/animation_js_api.hpp> +#include <malikania/client/js/animator_js_api.hpp> +#include <malikania/client/js/window_js_api.hpp> using namespace std::chrono_literals; -using namespace mlk; +using namespace mlk::client::js; using namespace mlk::client; -using namespace mlk::duk; +using namespace mlk::js::duk; +using namespace mlk; int main() {
--- a/examples/js-font/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/examples/js-font/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -24,15 +24,16 @@ #include <malikania/client/loader.hpp> -#include <malikania/js_client_resources_loader.hpp> -#include <malikania/js_font.hpp> -#include <malikania/js_window.hpp> +#include <malikania/client/js/font_js_api.hpp> +#include <malikania/client/js/loader_js_api.hpp> +#include <malikania/client/js/window_js_api.hpp> using namespace std::chrono_literals; using namespace mlk; +using namespace mlk::client::js; using namespace mlk::client; -using namespace mlk::duk; +using namespace mlk::js::duk; void basic(duk_context* ctx) {
--- a/examples/js-image/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/examples/js-image/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -24,15 +24,16 @@ #include <malikania/client/loader.hpp> -#include <malikania/js_client_resources_loader.hpp> -#include <malikania/js_image.hpp> -#include <malikania/js_window.hpp> +#include <malikania/client/js/image_js_api.hpp> +#include <malikania/client/js/loader_js_api.hpp> +#include <malikania/client/js/window_js_api.hpp> using namespace std::chrono_literals; using namespace mlk; +using namespace mlk::client::js; using namespace mlk::client; -using namespace mlk::duk; +using namespace mlk::js::duk; void basic(duk_context* ctx) {
--- a/examples/js-sprite/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/examples/js-sprite/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -24,16 +24,17 @@ #include <malikania/client/loader.hpp> -#include <malikania/js_client_resources_loader.hpp> -#include <malikania/js_image.hpp> -#include <malikania/js_sprite.hpp> -#include <malikania/js_window.hpp> +#include <malikania/client/js/loader_js_api.hpp> +#include <malikania/client/js/image_js_api.hpp> +#include <malikania/client/js/sprite_js_api.hpp> +#include <malikania/client/js/window_js_api.hpp> using namespace std::chrono_literals; using namespace mlk; +using namespace mlk::client::js; using namespace mlk::client; -using namespace mlk::duk; +using namespace mlk::js::duk; void basic(duk_context* ctx) {
--- a/examples/js-window/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/examples/js-window/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -20,13 +20,14 @@ #include <iostream> #include <thread> -#include <malikania/js_window.hpp> +#include <malikania/client/js/window_js_api.hpp> using namespace std::chrono_literals; using namespace mlk; +using namespace mlk::client::js; using namespace mlk::client; -using namespace mlk::duk; +using namespace mlk::js::duk; void basic(duk_context* ctx) {
--- a/libclient-js/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -# -# CMakeLists.txt -- CMake build system for malikania -# -# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(libmlk-client-js) - -set( - HEADERS - ${libmlk-client-js_SOURCE_DIR}/malikania/js_animation.hpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_animator.hpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_client_resources_loader.hpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_color.hpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_font.hpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_image.hpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_sprite.hpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_window.hpp -) - -set( - SOURCES - ${libmlk-client-js_SOURCE_DIR}/malikania/js_animation.cpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_animator.cpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_client_resources_loader.cpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_color.cpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_font.cpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_image.cpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_sprite.cpp - ${libmlk-client-js_SOURCE_DIR}/malikania/js_window.cpp -) - -malikania_define_library( - PROJECT libmlk-client-js - TARGET libmlk-client-js - SOURCES ${HEADERS} ${SOURCES} - LIBRARIES libmlk-client libmlk-common-js - PUBLIC_INCLUDES - $<BUILD_INTERFACE:${libmlk-client-js_SOURCE_DIR}/malikania> -)
--- a/libclient-js/malikania/js_animation.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * js_animation.cpp -- animation description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/client/animation.hpp> -#include <malikania/client/loader.hpp> - -#include "js_client_resources_loader.hpp" -#include "js_animation.hpp" - -namespace mlk { - -namespace client { - -namespace { - -const std::string_view signature("\xff""\xff""Malikania.Animation.self"); - -auto Animation_constructor(duk_context* ctx) -> duk_ret_t -{ - if (!duk_is_constructor_call(ctx)) - duk_error(ctx, DUK_ERR_ERROR, "animation must be new-constructed"); - - try { - auto anim = duk::require<client::loader>(ctx, 0).load_animation(duk::require<std::string_view>(ctx, 0)); - - duk_push_this(ctx); - duk_push_pointer(ctx, new animation(std::move(anim))); - duk_put_prop_string(ctx, -2, signature.data()); - duk_pop(ctx); - } catch (const std::exception &ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Animation_destructor(duk_context* ctx) -> duk_ret_t -{ - duk_get_prop_string(ctx, 0, signature.data()); - delete static_cast<animation*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_del_prop_string(ctx, 0, signature.data()); - - return 0; -} - -} // !namespace - -void load_animation_api(duk_context* ctx) -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Animation_constructor, 1); - duk_push_object(ctx); - duk_push_c_function(ctx, Animation_destructor, 1); - duk_set_finalizer(ctx, -2); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Animation"); - duk_pop(ctx); -} - -} // !client - -namespace duk { - -using namespace client; - -auto type_traits<animation>::require(duk_context* ctx, duk_idx_t index) -> animation& -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_get_prop_string(ctx, index, signature.data()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animation object"); - - return *static_cast<animation*>(ptr); -} - -} // !duk - -} // !mlk
--- a/libclient-js/malikania/js_animation.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * js_animation.hpp -- animation description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_ANIMATION_HPP -#define MALIKANIA_JS_ANIMATION_HPP - -#include "duk.hpp" - -namespace mlk { - -namespace client { - -struct animation; - -/** - * Load Malikania.Animation API into the context. - * - * \warning you need to put a mlk::client::loader before use - * \param ctx the context - */ -void load_animation_api(duk_context* ctx); - -} // !client - -namespace duk { - -template <> -struct type_traits<client::animation> { - /** - * Get an animation object at the given index or raise a Javascript - * error. - * - * \pre ctx != nullptr - * \param ctx the context - * \param index the value index - * \return the Animation object - */ - static auto require(duk_context* ctx, duk_idx_t index) -> client::animation&; -}; - -} // !duk - -} // !mlk - -#endif // !MALIKANIA_JS_ANIMATION_HPP
--- a/libclient-js/malikania/js_animator.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * js_animator.cpp -- animation drawing object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> -#include <string> - -#include <malikania/client/animator.hpp> - -#include "js_animation.hpp" -#include "js_animator.hpp" -#include "js_point.hpp" -#include "js_window.hpp" - -namespace mlk { - -namespace client { - -namespace { - -const std::string_view signature("\xff""\xff""Malikania.Animator.self"); - -auto self(duk_context* ctx) -> animator& -{ - duk::stack_guard sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature.data()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animator object"); - - return *static_cast<client::animator*>(ptr); -} - -auto Animator_constructor(duk_context* ctx) -> duk_ret_t -{ - if (!duk_is_constructor_call(ctx)) - duk_error(ctx, DUK_ERR_ERROR, "Animator must be new-constructed"); - - duk_push_this(ctx); - duk_push_pointer(ctx, new animator(duk::require<animation>(ctx, 0))); - duk_put_prop_string(ctx, -2, signature.data()); - - // Be sure animation get not collected before. - duk_dup(ctx, 0); - duk_put_prop_string(ctx, -2, "\xff""\xff""animation"); - duk_pop(ctx); - - return 0; -} - -auto Animator_destructor(duk_context* ctx) -> duk_ret_t -{ - duk_get_prop_string(ctx, 0, signature.data()); - delete static_cast<animator*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_del_prop_string(ctx, 0, signature.data()); - - return 0; -} - -auto Animator_draw(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).draw(duk::require<window>(ctx, 0), duk::get<point>(ctx, 1)); - } catch (const std::exception &ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Animator_update(duk_context* ctx) -> duk_ret_t -{ - self(ctx).update(); - - return 0; -} - -const duk_function_list_entry methods[] = { - { "draw", Animator_draw, 2 }, - { "update", Animator_update, 0 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -void load_animator_api(duk_context* ctx) -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Animator_constructor, 1); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_push_c_function(ctx, Animator_destructor, 1); - duk_set_finalizer(ctx, -2); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Animator"); - duk_pop(ctx); -} - -} // !client - -} // !mlk
--- a/libclient-js/malikania/js_animator.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * js_animator.hpp -- animation drawing object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_ANIMATOR_HPP -#define MALIKANIA_JS_ANIMATOR_HPP - -#include "duk.hpp" - -namespace mlk::client { - -/** - * Load Malikania.ElapsedTimer API into the context. - * - * \param ctx the context - */ -void load_animator_api(duk_context* ctx); - -} // !mlk::client - -#endif // !MALIKANIA_JS_ANIMATOR_HPP
--- a/libclient-js/malikania/js_client_resources_loader.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * js_client_resources_loader.cpp -- client resources loader (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/client/loader.hpp> - -#include "js_client_resources_loader.hpp" -#include "js_resources_loader.hpp" - -namespace mlk { - -namespace { - -const std::string_view variable("\xff""\xff""Malikania.ClientLoader"); - -} // !namespace - -namespace duk { - -using namespace client; - -void type_traits<client::loader>::put(duk_context* ctx, client::loader& loader) -{ - assert(ctx); - - // Also store as parent. - type_traits<mlk::loader>::put(ctx, loader); - - duk::stack_guard sa(ctx); - - duk_push_pointer(ctx, &loader); - duk_put_global_string(ctx, variable.data()); -} - -auto type_traits<client::loader>::require(duk_context* ctx, duk_idx_t) -> client::loader& -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, variable.data()); - auto ptr = static_cast<client::loader*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return *static_cast<client::loader*>(ptr); -} - -} // !duk - -} // !mlk
--- a/libclient-js/malikania/js_client_resources_loader.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * js_client_resources_loader.hpp -- client resources loader (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_CLIENT_RESOURCES_LOADER_H -#define MALIKANIA_JS_CLIENT_RESOURCES_LOADER_H - -#include "duk.hpp" - -namespace mlk { - -namespace client { - -class loader; - -} // !client - -namespace duk { - -template <> -struct type_traits<client::loader> { - static void put(duk_context* ctx, client::loader& loader); - - static auto require(duk_context* ctx, duk_idx_t) -> client::loader&; -}; - -} // !duk - -} // !mlk - -#endif // !MALIKANIA_JS_CLIENT_RESOURCES_LOADER_H
--- a/libclient-js/malikania/js_color.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +0,0 @@ -/* - * js_color.cpp -- color description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/client/color.hpp> - -#include "js_color.hpp" - -namespace mlk { - -namespace client { - -namespace { - -auto parse_string(duk_context* ctx, duk_idx_t index, bool required) -> color -{ - assert(duk_is_string(ctx, index)); - - color ret; - - try { - ret = color::from_name(duk_get_string(ctx, index)); - } catch (const std::exception &ex) { - if (required) - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return ret; -} - -auto parse_object(duk_context* ctx, duk_idx_t index, bool required) -> color -{ - assert(duk_is_object(ctx, index)); - - duk_get_prop_string(ctx, index, "red"); - const auto red = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "green"); - const auto green = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "blue"); - const auto blue = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "alpha"); - auto alpha = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - - if (required) { - if (!red) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'red' property"); - if (!green) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'green' property"); - if (!blue) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'blue' property"); - } - - if (!alpha) - alpha = 255; - - return { - static_cast<std::uint8_t>(*red), - static_cast<std::uint8_t>(*green), - static_cast<std::uint8_t>(*blue), - static_cast<std::uint8_t>(*alpha) - }; -} - -auto parse(duk_context* ctx, duk_idx_t index, bool required, color ret = {}) -> color -{ - switch (duk_get_type(ctx, index)) { - case DUK_TYPE_STRING: - ret = parse_string(ctx, index, required); - break; - case DUK_TYPE_OBJECT: - ret = parse_object(ctx, index, required); - break; - default: - if (required) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "Color (string, object) expected"); - - break; - } - - return ret; -} - -auto Color_constructor(duk_context* ctx) -> duk_ret_t -{ - color obj; - - /* - * The constructor allows an additional signature that takes 4 number - * arguments, otherwise use the literal parsing functions. - */ - if (duk_get_top(ctx) >= 3) { - // Alpha is optional. - obj.red = duk::require<unsigned>(ctx, 0); - obj.green = duk::require<unsigned>(ctx, 1); - obj.blue = duk::require<unsigned>(ctx, 2); - obj.alpha = duk_is_number(ctx, 3) ? duk::get<unsigned>(ctx, 3) : 255; - } else if (duk_get_top(ctx) == 1) - obj = duk::require<color>(ctx, 0); - - duk_ret_t ret; - - // Allow both constructor and non constructor calls. - if (duk_is_constructor_call(ctx)) { - duk_push_this(ctx); - duk::put(ctx, obj); - duk_pop(ctx); - ret = 0; - } else { - duk::push(ctx, obj); - ret = 1; - } - - return ret; -} - -} // !namespace - -void load_color_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx, 0); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Color_constructor, DUK_VARARGS); - duk_put_prop_string(ctx, -2, "Color"); - duk_pop(ctx); -} - -} // !client - -namespace duk { - -using namespace client; - -auto type_traits<color>::get(duk_context* ctx, duk_idx_t index) -> color -{ - return parse(ctx, index, false); -} - -auto type_traits<color>::require(duk_context* ctx, duk_idx_t index) -> color -{ - return parse(ctx, index, true); -} - -auto type_traits<color>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<color> -{ - try { - return parse(ctx, index, false); - } catch (...) { - return color(); - } -} - -void type_traits<color>::push(duk_context* ctx, const color& color) -{ - duk::stack_guard sa(ctx, 1); - - duk_push_object(ctx); - put(ctx, color); -} - -void type_traits<color>::put(duk_context* ctx, const color& color) -{ - assert(duk_is_object(ctx, -1)); - - duk::stack_guard sa(ctx, 0); - - duk::push<unsigned>(ctx, color.red); - duk_put_prop_string(ctx, -2, "red"); - duk::push<unsigned>(ctx, color.green); - duk_put_prop_string(ctx, -2, "green"); - duk::push<unsigned>(ctx, color.blue); - duk_put_prop_string(ctx, -2, "blue"); - duk::push<unsigned>(ctx, color.alpha); - duk_put_prop_string(ctx, -2, "alpha"); -} - -} // !duk - -} // !mlk
--- a/libclient-js/malikania/js_color.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * js_color.hpp -- color description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_COLOR_HPP -#define MALIKANIA_JS_COLOR_HPP - -/** - * \file js_color.hpp - * \brief JavaScript binding for color. - * - * Colors can be created from plain JavaScript object. - * - * ```` - * { - * red: 0, - * green: 255, - * blue: 255, - * alpha: 255 - * } - * ```` - * - * It can also takes strings like "#rrggbbaa" and SVG names. - */ - -#include "duk.hpp" - -namespace mlk { - -namespace client { - -struct color; - -/** - * Load Malikania.ElapsedTimer API into the context. - * - * \param ctx the context - */ -void load_color_api(duk_context* ctx); - -} // !client - -namespace duk { - -template <> -struct type_traits<client::color> { - /** - * Get a color. - * - * May return a default value or a color with adjusted components. - * - * \param ctx the context - * \param index the index - */ - static auto get(duk_context* ctx, duk_idx_t index) -> client::color; - - /** - * Require a color. - * - * If the color has any invalid component, raise a JavaScript error. - * - * \param ctx the context - * \param index the index - */ - static auto require(duk_context* ctx, duk_idx_t index) -> client::color; - - /** - * Like get, but return the default value only if the value at the given - * index is not an object or not a string, otherwise, adjust invalid values. - * - * \param ctx the context - * \param index the index - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<client::color>; - - /** - * Push the color as object. - * - * \param ctx the context - * \param color the color - */ - static void push(duk_context* ctx, const client::color& color); - - /** - * Put the color properties into the object at the top of the stack. - * - * \pre the top value must be an object - * \param ctx the context - * \param color the color - */ - static void put(duk_context* ctx, const client::color& color); -}; - -} // !duk - -} // !mlk - -#endif // !MALIKANIA_JS_COLOR_HPP
--- a/libclient-js/malikania/js_font.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - * js_font.cpp -- font object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/size.hpp> - -#include <malikania/client/loader.hpp> -#include <malikania/client/font.hpp> - -#include "js_client_resources_loader.hpp" -#include "js_font.hpp" -#include "js_size.hpp" - -namespace mlk { - -namespace client { - -namespace { - -const std::string signature("\xff""\xff""Malikania.Font.self"); - -auto self(duk_context* ctx) -> font& -{ - duk::stack_guard sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature.c_str()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a font object"); - - return *static_cast<font*>(ptr); -} - -auto Font_constructor(duk_context* ctx) -> duk_ret_t -{ - duk::stack_guard sa(ctx); - - if (!duk_is_constructor_call(ctx)) - duk_error(ctx, DUK_ERR_ERROR, "font must be new-constructed"); - - try { - auto id = duk::require<std::string_view>(ctx, 0); - auto size = duk::require<unsigned>(ctx, 1); - - duk_push_this(ctx); - duk_push_pointer(ctx, new font(duk::require<loader>(ctx, 0).load_font(id, size))); - duk_put_prop_string(ctx, -2, signature.c_str()); - duk_pop(ctx); - } catch (const std::exception &ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Font_prototype_clip(duk_context* ctx) -> duk_ret_t -{ - try { - duk::push(ctx, self(ctx).clip(duk::require<std::string>(ctx, 0))); - } catch (const std::exception &ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 1; -} - -const duk_function_list_entry methods[] = { - { "clip", Font_prototype_clip, 1 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -void load_font_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Font_constructor, 2); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Font"); - duk_pop(ctx); -} - -} // !client - -namespace duk { - -using namespace client; - -auto type_traits<font>::require(duk_context* ctx, duk_idx_t index) -> font& -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_get_prop_string(ctx, index, signature.data()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Font object"); - - return *static_cast<font*>(ptr); -} - -} // !duk - -} // !mlk
--- a/libclient-js/malikania/js_font.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_font.hpp -- font object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_FONT_HPP -#define MALIKANIA_JS_FONT_HPP - -#include "duk.hpp" - -namespace mlk { - -namespace client { - -class font; - -/** - * Load Malikania.Font API into the context. - * - * \param ctx the context - */ -void load_font_api(duk_context* ctx); - -} // !client - -namespace duk { - -template <> -struct type_traits<client::font> { - static auto require(duk_context* ctx, duk_idx_t index) -> client::font&; -}; - -} // !duk - -} // !mlk: - -#endif // !MALIKANIA_JS_FONT_HPP
--- a/libclient-js/malikania/js_image.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * js_image.cpp -- image object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/client/loader.hpp> -#include <malikania/client/image.hpp> -#include <malikania/client/window.hpp> - -#include "js_client_resources_loader.hpp" -#include "js_image.hpp" -#include "js_point.hpp" -#include "js_rectangle.hpp" -#include "js_size.hpp" -#include "js_window.hpp" - -namespace mlk::client { - -namespace { - -const std::string_view signature("\xff""\xff""Malikania.Image.self"); - -auto self(duk_context* ctx) -> image& -{ - duk::stack_guard sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature.data()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Image object"); - - return *static_cast<image*>(ptr); -} - -auto Image_property_get_size(duk_context* ctx) -> duk_ret_t -{ - try { - duk::push(ctx, self(ctx).get_size()); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 1; -} - -auto Image_prototype_draw(duk_context* ctx) -> duk_ret_t -{ - try { - auto& image = self(ctx); - auto& win= duk::require<window>(ctx, 0); - - if (duk_get_top(ctx) == 2) - image.draw(win, duk::get<point>(ctx, 1)); - else if (duk_get_top(ctx) == 3) - image.draw(win, duk::get<rectangle>(ctx, 1), duk::get<rectangle>(ctx, 2)); - else - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid number of arguments: #%d", duk_get_top(ctx)); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Image_constructor(duk_context* ctx) -> duk_ret_t -{ - if (!duk_is_constructor_call(ctx)) - duk_error(ctx, DUK_ERR_ERROR, "Image must be new-constructed"); - - try { - duk_push_this(ctx); - duk_push_pointer(ctx, new image(duk::require<loader>(ctx, 0) - .load_image(duk::require<std::string_view>(ctx, 0)))); - duk_put_prop_string(ctx, -2, signature.data()); - duk_push_string(ctx, "size"); - duk_push_c_function(ctx, Image_property_get_size, 0); - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - duk_pop(ctx); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -const duk_function_list_entry methods[] = { - { "draw", Image_prototype_draw, DUK_VARARGS }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -void load_image_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Image_constructor, 1); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Image"); - duk_pop(ctx); -} - -} // !mlk::client
--- a/libclient-js/malikania/js_image.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * js_image.hpp -- image object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_IMAGE_HPP -#define MALIKANIA_JS_IMAGE_HPP - -#include "duk.hpp" - -namespace mlk::client { - -/** - * Load Malikania.Image API into the context. - * - * \param ctx the context - */ -void load_image_api(duk_context* ctx); - -} // !mlk::client - -#endif // !MALIKANIA_JS_IMAGE_HPP
--- a/libclient-js/malikania/js_sprite.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * js_sprite.cpp -- sprite object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <malikania/client/loader.hpp> -#include <malikania/client/sprite.hpp> -#include <malikania/client/window.hpp> - -#include "js_client_resources_loader.hpp" -#include "js_point.hpp" -#include "js_size.hpp" -#include "js_sprite.hpp" -#include "js_window.hpp" - -namespace mlk::client { - -namespace { - -const std::string signature("\xff""\xff""Malikania.Sprite.self"); - -auto self(duk_context *ctx) -> sprite& -{ - duk::stack_guard sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature.c_str()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Sprite object"); - - return *static_cast<sprite*>(ptr); -} - -auto Sprite_property_get_cell(duk_context* ctx) -> duk_ret_t -{ - return duk::push(ctx, self(ctx).get_cell()); -} - -auto Sprite_property_get_columns(duk_context* ctx) -> duk_ret_t -{ - return duk::push(ctx, self(ctx).get_columns()); -} - -auto Sprite_property_get_margins(duk_context* ctx) -> duk_ret_t -{ - return duk::push(ctx, self(ctx).get_margin()); -} - -auto Sprite_property_get_rows(duk_context* ctx) -> duk_ret_t -{ - return duk::push(ctx, self(ctx).get_rows()); -} - -auto Sprite_property_get_space(duk_context *ctx) -> duk_ret_t -{ - return duk::push(ctx, self(ctx).get_space()); -} - -auto Sprite_constructor(duk_context *ctx) -> duk_ret_t -{ - if (!duk_is_constructor_call(ctx)) - duk_error(ctx, DUK_ERR_ERROR, "Sprite must be new-constructed"); - - try { - auto sp = duk::require<loader>(ctx, 0).load_sprite(duk_require_string(ctx, 0)); - - duk_push_this(ctx); - duk_push_pointer(ctx, new sprite(std::move(sp))); - duk_put_prop_string(ctx, -2, signature.data()); - - // Cell. - duk_push_string(ctx, "cell"); - duk_push_c_function(ctx, Sprite_property_get_cell, 0); - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - - // Columns. - duk_push_string(ctx, "columns"); - duk_push_c_function(ctx, Sprite_property_get_columns, 0); - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - - // Margins. - duk_push_string(ctx, "margins"); - duk_push_c_function(ctx, Sprite_property_get_margins, 0); - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - - // Rows. - duk_push_string(ctx, "rows"); - duk_push_c_function(ctx, Sprite_property_get_rows, 0); - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - - // Space. - duk_push_string(ctx, "space"); - duk_push_c_function(ctx, Sprite_property_get_space, 0); - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - - duk_pop(ctx); - } catch (const std::exception &ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Sprite_prototype_draw(duk_context *ctx) -> duk_ret_t -{ - try { - auto& sprite = self(ctx); - auto& win = duk::require<window>(ctx, 0); - auto cell = duk::require<unsigned>(ctx, 1); - auto position = duk::require<point>(ctx, 2); - - if (cell >= sprite.get_total()) - duk_error(ctx, DUK_ERR_RANGE_ERROR, "cell %d is out of range", cell); - - sprite.draw(win, cell, position); - } catch (const std::exception &ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -const duk_function_list_entry methods[] = { - { "draw", Sprite_prototype_draw, 3 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -void load_sprite_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Sprite_constructor, 1); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Sprite"); - duk_pop(ctx); -} - -} // !mlk::client
--- a/libclient-js/malikania/js_sprite.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * js_sprite.hpp -- sprite object (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_SPRITE_HPP -#define MALIKANIA_JS_SPRITE_HPP - -#include "duk.hpp" - -namespace mlk::client { - -/** - * Load Malikania.Sprite API into the context. - * - * \param ctx the context - */ -void load_sprite_api(duk_context* ctx); - -} // !mlk::client - -#endif // !MALIKANIA_JS_SPRITE_HPP
--- a/libclient-js/malikania/js_window.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* - * js_window.cpp -- window management (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/line.hpp> -#include <malikania/rectangle.hpp> - -#include <malikania/client/color.hpp> -#include <malikania/client/window.hpp> - -#include "js_color.hpp" -#include "js_font.hpp" -#include "js_line.hpp" -#include "js_point.hpp" -#include "js_rectangle.hpp" -#include "js_window.hpp" - -namespace mlk { - -namespace client { - -namespace { - -const std::string_view signature("\xff""\xff""Malikania.Window.self"); -const std::string_view prototype("\xff""\xff""Malikania.Window.prototype"); - -auto self(duk_context* ctx) -> window& -{ - duk::stack_guard sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature.data()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Window object"); - - return *static_cast<window*>(ptr); -} - -auto Window_constructor(duk_context* ctx) -> duk_ret_t -{ - duk::stack_guard sa(ctx); - - if (!duk_is_constructor_call(ctx)) - duk_error(ctx, DUK_ERR_ERROR, "window must be new-constructed"); - - // TODO: add parameters. - try { - duk_push_this(ctx); - duk_push_pointer(ctx, new window); - duk_put_prop_string(ctx, -2, signature.data()); - duk_pop(ctx); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_clear(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).clear(); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_present(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).present(); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_drawingColor(duk_context* ctx) -> duk_ret_t -{ - try { - duk::push(ctx, self(ctx).get_drawing_color()); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 1; -} - -auto Window_prototype_drawLine(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).draw_line(duk::get<line>(ctx, 0)); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_drawPoint(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).draw_point(duk::get<point>(ctx, 0)); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_drawRectangle(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).draw_rectangle(duk::get<rectangle>(ctx, 0)); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_drawText(duk_context* ctx) -> duk_ret_t -{ - try { - auto& win = self(ctx); - auto text = duk::require<std::string>(ctx, 0); - auto& fnt = duk::require<font>(ctx, 1); - auto rect = duk::get<rectangle>(ctx, 2); - - if (!rect.is_null()) - win.draw_text(text, fnt, rect); - else - win.draw_text(text, fnt, point{rect.x, rect.y}); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_fillRectangle(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).fill_rectangle(duk::get<rectangle>(ctx, 0)); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -auto Window_prototype_setDrawingColor(duk_context* ctx) -> duk_ret_t -{ - try { - self(ctx).set_drawing_color(duk::get<color>(ctx, 0)); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -const duk_function_list_entry methods[] = { - { "clear", Window_prototype_clear, 0 }, - { "drawingColor", Window_prototype_drawingColor, 0 }, - { "drawLine", Window_prototype_drawLine, 1 }, - { "drawPoint", Window_prototype_drawPoint, 1 }, - { "drawRectangle", Window_prototype_drawRectangle, 1 }, - { "drawText", Window_prototype_drawText, 3 }, - { "fillRectangle", Window_prototype_fillRectangle, 1 }, - { "present", Window_prototype_present, 0 }, - { "setDrawingColor", Window_prototype_setDrawingColor, 1 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -void load_window_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Window_constructor, 0); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Window"); - duk_pop(ctx); -} - -} // !client - -namespace duk { - -using namespace client; - -auto type_traits<window>::require(duk_context* ctx, duk_idx_t index) -> window& -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_get_prop_string(ctx, index, signature.data()); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Window object"); - - return *static_cast<window*>(ptr); -} - -} // !duk - -} // !mlk
--- a/libclient-js/malikania/js_window.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_window.hpp -- window management (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_WINDOW_HPP -#define MALIKANIA_JS_WINDOW_HPP - -#include "duk.hpp" - -namespace mlk { - -namespace client { - -class window; - -/** - * Load Malikania.Window API into the context. - * - * \param ctx the context - */ -void load_window_api(duk_context* ctx); - -} // !client - -namespace duk { - -template <> -struct type_traits<client::window> { - static auto require(duk_context* ctx, duk_idx_t index) -> client::window&; -}; - -} // !duk - -} // !mlk - -#endif // !MALIKANIA_JS_WINDOW_HPP
--- a/libclient/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -# -# CMakeLists.txt -- CMake build system for malikania -# -# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(libmlk-client) - -find_package(Boost REQUIRED COMPONENTS timer) - -set( - HEADERS - ${libmlk-client_SOURCE_DIR}/malikania/client/animation.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/animator.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/button.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/client.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/color.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/connection.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/dispatcher.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/font.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/image.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/key.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/label.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/loader.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/mouse.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/sdl_util.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/sprite.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/lobby_state.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/login_state.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/map_state.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/theme.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/widget.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/window.hpp -) - -set( - SOURCES - ${libmlk-client_SOURCE_DIR}/malikania/client/animator.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/button.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/client.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/color.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/connection.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/font.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/image.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/label.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/loader.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/sdl_util.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/sprite.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/lobby_state.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/login_state.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/map_state.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/theme.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/widget.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/window.cpp -) - -find_package(OpenSSL REQUIRED) -find_package(SDL2 REQUIRED) -find_package(SDL2_image REQUIRED) -find_package(SDL2_ttf REQUIRED) - -list( - APPEND - INCLUDES - ${SDL2_INCLUDE_DIRS} - ${SDL2_IMAGE_INCLUDE_DIRS} - ${SDL2_TTF_INCLUDE_DIRS} -) -list( - APPEND - LIBRARIES - ${SDL2_LIBRARIES} - ${SDL2_IMAGE_LIBRARIES} - ${SDL2_TTF_LIBRARIES} -) - -malikania_define_library( - PROJECT libmlk-client - TARGET libmlk-client - SOURCES ${HEADERS} ${SOURCES} - ASSETS ${libmlk-client_SOURCE_DIR}/assets/dejavu_sans.ttf - PRIVATE_INCLUDES - $<BUILD_INTERFACE:${libmlk-client_SOURCE_DIR}/malikania/client> - PUBLIC_INCLUDES - $<BUILD_INTERFACE:${libmlk-client_SOURCE_DIR}/malikania/client/${WITH_BACKEND_DIR}> - $<BUILD_INTERFACE:${libmlk-client_SOURCE_DIR}/malikania> - ${INCLUDES} - LIBRARIES - libmlk-common - Boost::boost - Boost::timer - OpenSSL::SSL - OpenSSL::Crypto - ${LIBRARIES} -)
--- a/libclient/malikania/client/animation.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * animation.hpp -- animation description - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_ANIMATION_HPP -#define MALIKANIA_CLIENT_ANIMATION_HPP - -/** - * \file animation.hpp - * \brief Describe an animation. - */ - -#include <cstdint> -#include <vector> -#include <utility> - -#include "sprite.hpp" - -namespace mlk::client { - -/** - * \brief Animation description. - * - * An animation is composed of a sprite and a set of frames. For example, if - * your sprite has several images, you can select only the one you want by - * specifying the index in each frame. - * - * \see animator - */ -struct animation { - /** - * \brief Delay between each frames. - */ - struct frame { - std::uint64_t cell{0U}; //!< sprite cell index - std::uint64_t delay{50U}; //!< delay in milliseconds - }; - - /** - * \brief List of frames. - */ - using frame_list = std::vector<frame>; - - mlk::client::sprite sprite; //!< sprite used - mlk::client::animation::frame_list frames; //!< list of frames -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_ANIMATION_HPP
--- a/libclient/malikania/client/animator.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * animator.cpp -- animation drawing object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include "animation.hpp" -#include "animator.hpp" - -namespace mlk::client { - -animator::animator(animation& animation) noexcept - : animation_(animation) - , current_(animation_.frames.begin()) -{ -} - -void animator::reset() noexcept -{ - timer_.start(); - current_ = animation_.frames.begin(); -} - -void animator::update() noexcept -{ - if (current_ == animation_.frames.end()) - return; - - if (timer_.elapsed().wall / 1000000LL >= static_cast<long long>(current_->delay)) { - current_ ++; - timer_.start(); - } -} - -void animator::draw(window& window, const point& point) -{ - if (current_ != animation_.frames.end()) - animation_.sprite.draw(window, current_->cell, point); -} - -} // !mlk::client
--- a/libclient/malikania/client/animator.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * animator.hpp -- animation drawing object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_ANIMATOR_HPP -#define MALIKANIA_CLIENT_ANIMATOR_HPP - -/** - * \file animator.hpp - * \brief Draw animations. - */ - -#include <boost/timer/timer.hpp> - -#include "animation.hpp" - -namespace mlk { - -struct point; - -namespace client { - -class window; - -/** - * \brief Object for drawing animations. - * - * The animator contains an animation and a state. - */ -class animator { -private: - boost::timer::cpu_timer timer_; - animation& animation_; - animation::frame_list::const_iterator current_; - -public: - /** - * Construct an animator. - * - * \pre animation must not be null - * \param animation the animation - */ - animator(animation& animation) noexcept; - - /** - * Reset the animator to the beginning. - */ - void reset() noexcept; - - /** - * Update the animator state. - * - * This function should be called in the main loop to update the cell - * to draw before calling draw(). - */ - void update() noexcept; - - /** - * Draw the animation. - * - * \param window the window - * \param position the position in the window - */ - void draw(window& window, const point& position); -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_ANIMATOR_HPP
--- a/libclient/malikania/client/button.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * button.cpp -- GUI button element - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "button.hpp" -#include "theme.hpp" -#include "window.hpp" - -namespace mlk::client { - -button::button(std::string text) - : text_(std::move(text)) -{ -} - -auto button::get_text() const noexcept -> const std::string& -{ - return text_; -} - -void button::set_text(std::string text) noexcept -{ - text_ = std::move(text); -} - -void button::handle_mouse_down(const mouse_click_event& ev) -{ - if (ev.button == mouse::left && on_press_) - on_press_(); - - // TODO: implement release. -} - -void button::draw(window& w, const size& size) -{ - (void)w; - (void)size; -} - -} // !mlk::client
--- a/libclient/malikania/client/button.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * button.hpp -- GUI button element - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_BUTTON_HPP -#define MALIKANIA_CLIENT_BUTTON_HPP - -/** - * \file button.hpp - * \brief GUI button element. - */ - -#include <functional> -#include <string> - -#include "widget.hpp" - -namespace mlk::client { - -/** - * \brief Basic button element. - */ -class button : public widget { -public: - using on_press_func = std::function<void ()>; - using on_release_func = std::function<void ()>; - -private: - on_press_func on_press_; - on_release_func on_released_; - - std::string text_; - -public: - /** - * Default constructor with optional text. - * - * \param text the text - */ - button(std::string text = ""); - - /** - * Get the button text. - * - * \return the text - */ - auto get_text() const noexcept -> const std::string&; - - /** - * Set the button text. - * - * \param text the text - */ - void set_text(std::string text) noexcept; - - /** - * \copydoc widget::handle_mouse_down - */ - void handle_mouse_down(const mouse_click_event& ev) override; - - /** - * Bring back other functions. - */ - using widget::draw; - - /** - * \copydoc widget::draw - */ - void draw(window& w, const size& size) override; -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_BUTTON_HPP
--- a/libclient/malikania/client/client.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * client.cpp -- main client game clas - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <iostream> -#include <thread> - -#include "client.hpp" -#include "connection.hpp" -#include "state.hpp" -#include "window.hpp" - -namespace mlk { - -namespace client { - -client::client(boost::asio::io_service& service, - mlk::client::connection& connection, - mlk::client::window& window) noexcept - : service_(service) - , connection_(connection) - , window_(window) -{ -} - -client::~client() noexcept = default; - -void client::recv() -{ - // Network thread space. - connection_.recv([this] (auto code, auto message) { - if (!code) - recv(); - - std::lock_guard<std::mutex> lock(nmutex_); - - nqueue_.push_back(std::bind(&client::handle_message, this, code, message)); - }); -} - -void client::connect(std::string host, std::uint16_t port) -{ - service_.post([this, host, port] () { - connection_.connect(host, port, [this] (auto code) { - // Start receiveing on success. - if (!code) - recv(); - - // Push the result to the main loop queue. - std::lock_guard<std::mutex> lock(nmutex_); - - nqueue_.push_back(std::bind(&client::handle_connect, this, code)); - }); - }); -} - -void client::send(nlohmann::json message) -{ - service_.post([this, message] () { - // TODO: error checking. - connection_.send(std::move(message), nullptr); - }); -} - -void client::set_state(std::unique_ptr<state> state) -{ - state_next_ = std::move(state); -} - -void client::handle_connect(const std::error_code& code) -{ - if (state_) - state_->handle_connect(code); -} - -void client::handle_message(const std::error_code& code, const nlohmann::json& msg) -{ - if (state_) - state_->handle_message(code, msg); -} - -void client::handle_key_down(const key_event& ev) -{ - if (state_) - state_->handle_key_down(ev); -} - -void client::handle_key_up(const key_event& ev) -{ - if (state_) - state_->handle_key_up(ev); -} - -void client::handle_mouse_down(const mouse_click_event& ev) -{ - if (state_) - state_->handle_mouse_down(ev); -} - -void client::handle_mouse_up(const mouse_click_event& ev) -{ - if (state_) - state_->handle_mouse_up(ev); -} - -void client::handle_mouse_wheel(const mouse_wheel_event& ev) -{ - if (state_) - state_->handle_mouse_wheel(ev); -} - -void client::handle_text(const text_event& ev) -{ - if (state_) - state_->handle_text(ev); -} - -void client::handle_quit() -{ - window_.close(); - service_.stop(); -} - -void client::run() -{ - std::thread t([this] () { - // TODO: change to an atomic member variable. - while (window_.is_open()) { - service_.reset(); - service_.run(); - } - }); - - while (window_.is_open()) { - // Network events. - { - std::lock_guard<std::mutex> lock(nmutex_); - - for (auto& ev : nqueue_) - ev(); - - nqueue_.clear(); - } - - // State and input events. - if (state_next_) - state_ = std::move(state_next_); - - window_.poll(*this); - - if (state_) { - state_->update(*this); - state_->draw(*this); - } - } - - t.join(); -} - -} // !client - -} // !mlk
--- a/libclient/malikania/client/client.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ -/* - * client.hpp -- main client game clas - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_CLIENT_HPP -#define MALIKANIA_CLIENT_CLIENT_HPP - -/** - * \file client.hpp - * \brief Main client game class. - */ - -#include <functional> -#include <memory> -#include <mutex> -#include <vector> -#include <system_error> - -#include <boost/asio.hpp> - -#include <json.hpp> - -#include "dispatcher.hpp" - -namespace mlk { - -namespace client { - -class connection; -class state; -class window; - -/** - * \brief Main client game class - */ -class client : public dispatcher { -private: - boost::asio::io_service& service_; - - mlk::client::connection& connection_; - mlk::client::window& window_; - - std::unique_ptr<state> state_; - std::unique_ptr<state> state_next_; - std::mutex nmutex_; - std::vector<std::function<void ()>> nqueue_; - - void recv(); - -public: - /** - * Construct the client, no connection attempt will be made yet. - * - * \param service the I/O service - * \param connection the connection object - * \param window the window - */ - client(boost::asio::io_service& service, - mlk::client::connection& connection, - mlk::client::window& window) noexcept; - - /** - * Virtual destructor defaulted. - */ - virtual ~client() noexcept; - - /** - * Get the window. - * - * \return the window - */ - inline const mlk::client::window& window() const noexcept - { - return window_; - } - - /** - * Overloaded function. - * - * \return the window - */ - inline mlk::client::window& window() noexcept - { - return window_; - } - - /** - * Connect to the server. - * - * This is an alias of connection_.connect(*this, host, port); - * - * \param host the hostname - * \param port the port number - */ - void connect(std::string host, std::uint16_t port); - - /** - * Send a message. - * - * \param message the message - */ - void send(nlohmann::json message); - - /** - * Set the client state. - * - * \param state the state - */ - void set_state(std::unique_ptr<state>); - - /** - * Run the client until the game window is closed. - */ - void run(); - - /** - * \copydoc dispatcher::handle_connect - */ - void handle_connect(const std::error_code& code) override; - - /** - * \copydoc dispatcher::handle_message - */ - void handle_message(const std::error_code& code, const nlohmann::json& msg) override; - - /** - * \copydoc dispatcher::handle_key_down - */ - void handle_key_down(const key_event& ev) override; - - /** - * \copydoc dispatcher::handle_key_up - */ - void handle_key_up(const key_event& ev) override; - - /** - * \copydoc dispatcher::handle_mouse_down - */ - void handle_mouse_down(const mouse_click_event& ev) override; - - /** - * \copydoc dispatcher::handle_mouse_up - */ - void handle_mouse_up(const mouse_click_event& ev) override; - - /** - * \copydoc dispatcher::handle_mouse_wheel - */ - void handle_mouse_wheel(const mouse_wheel_event& ev) override; - - /** - * \copydoc dispatcher::handle_text - */ - void handle_text(const text_event& ev) override; - - /** - * \copydoc dispatcher::handle_quit - */ - void handle_quit() override; -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_CLIENT_HPP
--- a/libclient/malikania/client/color.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -/* - * color.cpp -- color description - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cctype> -#include <locale> -#include <unordered_map> - -#include "color.hpp" - -namespace mlk::client { - -namespace { - -constexpr auto rgb(std::uint8_t r, std::uint8_t g, std::uint8_t b) noexcept -> unsigned -{ - return (0xff000000 | (r << 16) | (g << 8) | b); -} - -/* - * Convert hexadecimal value to the correct number. - */ -auto value(char digit) -> std::uint8_t -{ - if (std::isdigit(digit, {})) - return digit - '0'; - if ((digit = std::toupper(digit, {})) < 'A' || digit > 'F') - throw std::invalid_argument("invalid hexadecimal value: " + std::to_string(digit)); - - return digit - 55; -} - -auto value(char digit1, char digit2) -> std::uint8_t -{ - return ((value(digit1) << 4) & 0xf0) | value(digit2); -} - -const std::unordered_map<std::string_view, std::uint32_t> colors{ - { "aliceblue", rgb(240, 248, 255) }, - { "antiquewhite", rgb(250, 235, 215) }, - { "aqua", rgb( 0, 255, 255) }, - { "aquamarine", rgb(127, 255, 212) }, - { "azure", rgb(240, 255, 255) }, - { "beige", rgb(245, 245, 220) }, - { "bisque", rgb(255, 228, 196) }, - { "black", rgb( 0, 0, 0) }, - { "blanchedalmond", rgb(255, 235, 205) }, - { "blue", rgb( 0, 0, 255) }, - { "blueviolet", rgb(138, 43, 226) }, - { "brown", rgb(165, 42, 42) }, - { "burlywood", rgb(222, 184, 135) }, - { "cadetblue", rgb( 95, 158, 160) }, - { "chartreuse", rgb(127, 255, 0) }, - { "chocolate", rgb(210, 105, 30) }, - { "coral", rgb(255, 127, 80) }, - { "cornflowerblue", rgb(100, 149, 237) }, - { "cornsilk", rgb(255, 248, 220) }, - { "crimson", rgb(220, 20, 60) }, - { "cyan", rgb( 0, 255, 255) }, - { "darkblue", rgb( 0, 0, 139) }, - { "darkcyan", rgb( 0, 139, 139) }, - { "darkgoldenrod", rgb(184, 134, 11) }, - { "darkgray", rgb(169, 169, 169) }, - { "darkgreen", rgb( 0, 100, 0) }, - { "darkgrey", rgb(169, 169, 169) }, - { "darkkhaki", rgb(189, 183, 107) }, - { "darkmagenta", rgb(139, 0, 139) }, - { "darkolivegreen", rgb( 85, 107, 47) }, - { "darkorange", rgb(255, 140, 0) }, - { "darkorchid", rgb(153, 50, 204) }, - { "darkred", rgb(139, 0, 0) }, - { "darksalmon", rgb(233, 150, 122) }, - { "darkseagreen", rgb(143, 188, 143) }, - { "darkslateblue", rgb( 72, 61, 139) }, - { "darkslategray", rgb( 47, 79, 79) }, - { "darkslategrey", rgb( 47, 79, 79) }, - { "darkturquoise", rgb( 0, 206, 209) }, - { "darkviolet", rgb(148, 0, 211) }, - { "deeppink", rgb(255, 20, 147) }, - { "deepskyblue", rgb( 0, 191, 255) }, - { "dimgray", rgb(105, 105, 105) }, - { "dimgrey", rgb(105, 105, 105) }, - { "dodgerblue", rgb( 30, 144, 255) }, - { "firebrick", rgb(178, 34, 34) }, - { "floralwhite", rgb(255, 250, 240) }, - { "forestgreen", rgb( 34, 139, 34) }, - { "fuchsia", rgb(255, 0, 255) }, - { "gainsboro", rgb(220, 220, 220) }, - { "ghostwhite", rgb(248, 248, 255) }, - { "gold", rgb(255, 215, 0) }, - { "goldenrod", rgb(218, 165, 32) }, - { "gray", rgb(128, 128, 128) }, - { "green", rgb( 0, 128, 0) }, - { "greenyellow", rgb(173, 255, 47) }, - { "grey", rgb(128, 128, 128) }, - { "honeydew", rgb(240, 255, 240) }, - { "hotpink", rgb(255, 105, 180) }, - { "indianred", rgb(205, 92, 92) }, - { "indigo", rgb( 75, 0, 130) }, - { "ivory", rgb(255, 255, 240) }, - { "khaki", rgb(240, 230, 140) }, - { "lavender", rgb(230, 230, 250) }, - { "lavenderblush", rgb(255, 240, 245) }, - { "lawngreen", rgb(124, 252, 0) }, - { "lemonchiffon", rgb(255, 250, 205) }, - { "lightblue", rgb(173, 216, 230) }, - { "lightcoral", rgb(240, 128, 128) }, - { "lightcyan", rgb(224, 255, 255) }, - { "lightgoldenrodyellow", rgb(250, 250, 210) }, - { "lightgray", rgb(211, 211, 211) }, - { "lightgreen", rgb(144, 238, 144) }, - { "lightgrey", rgb(211, 211, 211) }, - { "lightpink", rgb(255, 182, 193) }, - { "lightsalmon", rgb(255, 160, 122) }, - { "lightseagreen", rgb( 32, 178, 170) }, - { "lightskyblue", rgb(135, 206, 250) }, - { "lightslategray", rgb(119, 136, 153) }, - { "lightslategrey", rgb(119, 136, 153) }, - { "lightsteelblue", rgb(176, 196, 222) }, - { "lightyellow", rgb(255, 255, 224) }, - { "lime", rgb( 0, 255, 0) }, - { "limegreen", rgb( 50, 205, 50) }, - { "linen", rgb(250, 240, 230) }, - { "magenta", rgb(255, 0, 255) }, - { "maroon", rgb(128, 0, 0) }, - { "mediumaquamarine", rgb(102, 205, 170) }, - { "mediumblue", rgb( 0, 0, 205) }, - { "mediumorchid", rgb(186, 85, 211) }, - { "mediumpurple", rgb(147, 112, 219) }, - { "mediumseagreen", rgb( 60, 179, 113) }, - { "mediumslateblue", rgb(123, 104, 238) }, - { "mediumspringgreen", rgb( 0, 250, 154) }, - { "mediumturquoise", rgb( 72, 209, 204) }, - { "mediumvioletred", rgb(199, 21, 133) }, - { "midnightblue", rgb( 25, 25, 112) }, - { "mintcream", rgb(245, 255, 250) }, - { "mistyrose", rgb(255, 228, 225) }, - { "moccasin", rgb(255, 228, 181) }, - { "navajowhite", rgb(255, 222, 173) }, - { "navy", rgb( 0, 0, 128) }, - { "oldlace", rgb(253, 245, 230) }, - { "olive", rgb(128, 128, 0) }, - { "olivedrab", rgb(107, 142, 35) }, - { "orange", rgb(255, 165, 0) }, - { "orangered", rgb(255, 69, 0) }, - { "orchid", rgb(218, 112, 214) }, - { "palegoldenrod", rgb(238, 232, 170) }, - { "palegreen", rgb(152, 251, 152) }, - { "paleturquoise", rgb(175, 238, 238) }, - { "palevioletred", rgb(219, 112, 147) }, - { "papayawhip", rgb(255, 239, 213) }, - { "peachpuff", rgb(255, 218, 185) }, - { "peru", rgb(205, 133, 63) }, - { "pink", rgb(255, 192, 203) }, - { "plum", rgb(221, 160, 221) }, - { "powderblue", rgb(176, 224, 230) }, - { "purple", rgb(128, 0, 128) }, - { "red", rgb(255, 0, 0) }, - { "rosybrown", rgb(188, 143, 143) }, - { "royalblue", rgb( 65, 105, 225) }, - { "saddlebrown", rgb(139, 69, 19) }, - { "salmon", rgb(250, 128, 114) }, - { "sandybrown", rgb(244, 164, 96) }, - { "seagreen", rgb( 46, 139, 87) }, - { "seashell", rgb(255, 245, 238) }, - { "sienna", rgb(160, 82, 45) }, - { "silver", rgb(192, 192, 192) }, - { "skyblue", rgb(135, 206, 235) }, - { "slateblue", rgb(106, 90, 205) }, - { "slategray", rgb(112, 128, 144) }, - { "slategrey", rgb(112, 128, 144) }, - { "snow", rgb(255, 250, 250) }, - { "springgreen", rgb( 0, 255, 127) }, - { "steelblue", rgb( 70, 130, 180) }, - { "tan", rgb(210, 180, 140) }, - { "teal", rgb( 0, 128, 128) }, - { "thistle", rgb(216, 191, 216) }, - { "tomato", rgb(255, 99, 71) }, - { "transparent", 0 }, - { "turquoise", rgb( 64, 224, 208) }, - { "violet", rgb(238, 130, 238) }, - { "wheat", rgb(245, 222, 179) }, - { "white", rgb(255, 255, 255) }, - { "whitesmoke", rgb(245, 245, 245) }, - { "yellow", rgb(255, 255, 0) }, - { "yellowgreen", rgb(154, 205, 50) } -}; - -} // !namespace - -auto color::from_hex(std::uint32_t hex) noexcept -> color -{ - return { - static_cast<std::uint8_t>((hex >> 16) & 0xff), - static_cast<std::uint8_t>((hex >> 8) & 0xff), - static_cast<std::uint8_t>((hex & 0xff)), - static_cast<std::uint8_t>((hex >> 24) & 0xff) - }; -} - -auto color::from_name(std::string_view name) -> color -{ - if (name.empty()) - return color(); - - color result; - - // Parse #rrggbb or #rgb. - if (name[0] == '#') { - if (name.length() == 7) { - result.red = value(name[1], name[2]); - result.green = value(name[3], name[4]); - result.blue = value(name[5], name[6]); - } else if (name.length() == 4) { - result.red = value(name[1], name[1]); - result.green = value(name[2], name[2]); - result.blue = value(name[3], name[3]); - } else - throw std::invalid_argument("invalid format"); - } else { - // Name lookup. - const auto it = colors.find(name); - - if (it == colors.end()) - throw std::invalid_argument("invalid color"); - - result = from_hex(it->second); - } - - return result; -} - -} // !mlk::client
--- a/libclient/malikania/client/color.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * color.hpp -- color description - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_COLOR_HPP -#define MALIKANIA_CLIENT_COLOR_HPP - -/** - * \file color.hpp - * \brief Colors. - */ - -#include <cstdint> -#include <string_view> - -namespace mlk::client { - -/** - * \brief color description - */ -struct color { - std::uint8_t red{0}; - std::uint8_t green{0}; - std::uint8_t blue{0}; - std::uint8_t alpha{255}; - - /** - * Constructor with an hexadecimal value. - * - * \param hex the color - */ - static auto from_hex(std::uint32_t hex) noexcept -> color; - - /** - * Construct a color from #rrggbb or name. - * - * See the SVG this [list](http://www.december.com/html/spec/colorsvg.html) for supported names. - * - * \param name the color name - * \throw std::invalid_argument if the color does not exist or is invalid - */ - static auto from_name(std::string_view name) -> color; -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_COLOR_HPP
--- a/libclient/malikania/client/connection.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * connection.hpp -- connection to server - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "connection.hpp" - -namespace mlk { - -namespace client { - -/* - * connection::connection - * ------------------------------------------------------------------ - */ -connection::connection(boost::asio::io_service& service) - : service_(service) - , context_(boost::asio::ssl::context::sslv23) - , resolver_(service_) -{ -} - -/* - * connection::handshake - * ------------------------------------------------------------------ - */ -void connection::handshake(connect_t handler) -{ - socket_->async_handshake(boost::asio::ssl::stream_base::client, std::move(handler)); -} - -/* - * connection::flush - * ------------------------------------------------------------------ - */ -void connection::flush() -{ - if (output_.empty()) - return; - - auto buffer = boost::asio::buffer(std::get<1>(output_[0])); - - boost::asio::async_write(*socket_, buffer, [this] (auto code, auto xfer) { - auto handler = std::get<2>(output_[0]); - - output_.pop_front(); - - if (handler) - handler(std::move(code), std::get<0>(output_[0])); - - // TODO: precise error code. - if (!code && xfer != 0) - flush(); - }); -} - -/* - * connection::connect - * ------------------------------------------------------------------ - */ -void connection::connect(const std::string& host, std::uint16_t port, connect_t handler) -{ - socket_ = std::make_unique<socket_t>(service_, context_); - - using tcp = boost::asio::ip::tcp; - - auto str = std::to_string(port); - - resolver_.async_resolve(tcp::resolver::query(host, str), [this, handler] (auto code, auto ep) { - if (code) - handler(std::move(code)); - else { - boost::asio::async_connect(socket_->lowest_layer(), ep, [this, handler] (auto code, auto) { - if (code) - handler(std::move(code)); - else - handshake(std::move(handler)); - }); - } - }); -} - -/* - * connection::send - * ------------------------------------------------------------------ - */ -void connection::send(nlohmann::json message, send_t handler) -{ - assert(socket_); - assert(message.is_object()); - - auto in_progress = !output_.empty(); - auto str = message.dump() + "\r\n\r\n"; - - output_.push_back(std::make_tuple(std::move(message), std::move(str), std::move(handler))); - - if (!in_progress) - flush(); -} - -/* - * connection::recv - * ------------------------------------------------------------------ - */ -void connection::recv(recv_t handler) -{ - assert(socket_); - -#if !defined(NDEBUG) - assert(!is_reading); - - is_reading = true; -#endif - - boost::asio::async_read_until(*socket_, input_, "\r\n\r\n", [this, handler] (auto code, auto xfer) { -#if !defined(NDEBUG) - is_reading = false; -#endif - if (code) - handler(std::move(code), nullptr); - else if (xfer == 0) - handler(make_error_code(boost::system::errc::network_down), nullptr); - else { - std::string command{ - boost::asio::buffers_begin(input_.data()), - boost::asio::buffers_begin(input_.data()) + xfer - /* \r\n\r\n */ 4 - }; - - input_.consume(xfer); - - nlohmann::json msg; - - try { - msg = nlohmann::json::parse(command); - } catch (const std::exception&) { - // TODO: add custom error code. - } - - handler(std::move(code), std::move(msg)); - } - }); -} - -} // !client - -} // !mlk
--- a/libclient/malikania/client/connection.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * connection.hpp -- connection to server - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_CONNECTION_HPP -#define MALIKANIA_CLIENT_CONNECTION_HPP - -/** - * \file connection.hpp - * \brief Connection to server. - */ - -#include <deque> -#include <functional> -#include <utility> - -#include <boost/asio.hpp> -#include <boost/asio/ssl.hpp> - -#include <json.hpp> - -namespace mlk { - -namespace client { - -class client; - -/** - * \brief connection to server. - */ -class connection { -public: - /** - * Connection handler. - */ - using connect_t = std::function<void (boost::system::error_code)>; - - /** - * Receive handler. - */ - using recv_t = std::function<void (boost::system::error_code, nlohmann::json)>; - - /** - * Send handler. - */ - using send_t = std::function<void (boost::system::error_code, nlohmann::json)>; - -private: - /** - * Wrap an handler, the JSON message and its dump string. - */ - using output_item_t = std::tuple<nlohmann::json, std::string, send_t>; - - using socket_t = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>; - - boost::asio::io_service& service_; - boost::asio::ssl::context context_; - boost::asio::ip::tcp::resolver resolver_; - std::unique_ptr<socket_t> socket_; - boost::asio::streambuf input_; - std::deque<output_item_t> output_; - -#if !defined(NDEBUG) - bool is_reading{false}; -#endif - - void handshake(connect_t); - void flush(); - -public: - /** - * Create a connection object. - */ - connection(boost::asio::io_service& service); - - /** - * Connect to the given end point. - * - * \pre handler != nullptr - * \param host the hostname - * \param port the port number - * \param handler the handler - */ - virtual void connect(const std::string& host, std::uint16_t port, connect_t handler); - - /** - * Send the given message to the server. - * - * \pre message.is_object() - * \param message the message object - * \param handler the handler (may be null) - */ - virtual void send(nlohmann::json message, send_t handler); - - /** - * Request for a recv operation. - * - * \pre no reading operation must be pending - * \pre handler != nullptr - * \param handler the handler - */ - virtual void recv(recv_t handler); -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_CONNECTION_HPP
--- a/libclient/malikania/client/dispatcher.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -/* - * dispatcher.hpp -- client event dispatcher - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_DISPATCHER_HPP -#define MALIKANIA_CLIENT_DISPATCHER_HPP - -/** - * \file dispatcher.hpp - * \brief Client event dispatcher. - */ - -#include <system_error> - -#include <json.hpp> - -#include "mouse.hpp" -#include "key.hpp" -#include "point.hpp" - -namespace mlk::client { - -/** - * \brief Describe key event. - */ -struct key_event { - key keycode{key::unknown}; //!< layout-dependant key - key scancode{key::unknown}; //!< physical key - mod modifiers{mod::none}; //!< optional modifiers -}; - -/** - * \brief Describe mouse click event. - */ -struct mouse_click_event { - mouse button{mouse::none}; //!< which mouse button - point pos; //!< current mouse position -}; - -/** - * \brief Describe a mouse motion event. - */ -struct mouse_motion_event { - point pos; //!< current mouse position -}; - -/** - * \brief Describe mouse wheel (up/down) event. - */ -struct mouse_wheel_event { - point pos; //!< current mouse position -}; - -/** - * \brief Describe text edition event. - */ -struct text_event { - std::u32string text; //!< text added from this event -}; - -/** - * \brief Client event dispatcher. - */ -class dispatcher { -public: - /** - * Default constructor. - */ - dispatcher() noexcept = default; - - /** - * Virtual destructor defaulted. - */ - virtual ~dispatcher() noexcept = default; - - /** - * Connection event. - * - * \param code the result code - */ - virtual void handle_connect(const std::error_code& code) - { - (void)code; - } - - /** - * Message event. - * - * \param code the result code - * \param msg the network message - */ - virtual void handle_message(const std::error_code& code, const nlohmann::json& msg) - { - (void)code; - (void)msg; - } - - /** - * Key down event. - * - * \param ev the event - */ - virtual void handle_key_down(const key_event& ev) - { - (void)ev; - } - - /** - * Key released event. - * - * \param ev the event - */ - virtual void handle_key_up(const key_event& ev) - { - (void)ev; - } - - /** - * Mouse click event. - * - * \param ev the event - */ - virtual void handle_mouse_down(const mouse_click_event& ev) - { - (void)ev; - } - - /** - * Mouse click release event. - * - * \param ev the event - */ - virtual void handle_mouse_up(const mouse_click_event& ev) - { - (void)ev; - } - - /** - * Mouse wheel event. - * - * \param ev the event - */ - virtual void handle_mouse_wheel(const mouse_wheel_event& ev) - { - (void)ev; - } - - /** - * Text editing event. - * - * \param ev the event - */ - virtual void handle_text(const text_event& ev) - { - (void)ev; - } - - /** - * Quit request. - */ - virtual void handle_quit() - { - } -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_DISPATCHER_HPP
--- a/libclient/malikania/client/font.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * font.cpp -- font object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include "font.hpp" -#include "sdl_util.hpp" -#include "size.hpp" - -namespace mlk::client { - -font::font(std::string data, std::size_t size) - : size_(size) -{ - assert(size > 0); - - auto rw = SDLx_RWFromBinary(std::move(data)); - - if (rw == nullptr) - throw std::runtime_error(SDL_GetError()); - - font_ = { TTF_OpenFontRW(rw, true, size), TTF_CloseFont }; - - if (font_ == nullptr) - throw std::runtime_error(TTF_GetError()); -} - -auto font::get_handle() const -> TTF_Font* -{ - return font_.get(); -} - -auto font::get_handle() -> TTF_Font* -{ - return font_.get(); -} - -auto font::get_size() const noexcept -> std::size_t -{ - return size_; -} - -auto font::clip(const std::string& text) const -> size -{ - int width, height; - - if (TTF_SizeUTF8(font_.get(), text.c_str(), &width, &height) != 0) - throw std::runtime_error(SDL_GetError()); - - return { - static_cast<unsigned>(width), - static_cast<unsigned>(height) - }; -} - -} // !mlk::client
--- a/libclient/malikania/client/font.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * font.hpp -- font object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_FONT_HPP -#define MALIKANIA_CLIENT_FONT_HPP - -/** - * \file font.hpp - * \brief fonts. - */ - -#include <memory> -#include <string> - -#include <SDL.h> -#include <SDL_ttf.h> - -namespace mlk { - -struct size; - -namespace client { - -/** - * \brief font object. - */ -class font { -private: - std::unique_ptr<TTF_Font, void (*)(TTF_Font*)> font_{nullptr, nullptr}; - std::size_t size_; - -public: - /** - * Construct a font from binary data. - * - * \pre size > 0 - * \param data the raw data - * \param size the size - */ - font(std::string data, std::size_t size); - - /** - * Get the underlying SDL TTF_Font. - * - * \return the font - */ - auto get_handle() const -> TTF_Font*; - - /** - * Overloaded function. - * - * \return the font - */ - auto get_handle() -> TTF_Font*; - - /** - * Get the font size. - * - * \return the font size - */ - auto get_size() const noexcept -> std::size_t; - - /** - * Get the clipping size required to draw the given text. - * - * \param text the text to clip - * \return the required size - */ - auto clip(const std::string& text) const -> size; -}; - -} // !client - -} // !mlk - -#endif // MALIKANIA_CLIENT_FONT_HPP
--- a/libclient/malikania/client/image.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * image.cpp -- image object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <SDL_image.h> - -#include "image.hpp" -#include "sdl_util.hpp" -#include "window.hpp" - -namespace mlk::client { - -void image::create_texture(window& w) -{ - texture_ = { - SDL_CreateTextureFromSurface(w.get_renderer(), surface_.get()), - SDL_DestroyTexture - }; - - if (texture_ == nullptr) - throw std::runtime_error(SDL_GetError()); -} - -image::image(std::string data) -{ - auto rw = SDLx_RWFromBinary(std::move(data)); - - if (rw == nullptr) - throw std::runtime_error(SDL_GetError()); - - surface_ = { IMG_Load_RW(rw, true), SDL_FreeSurface }; - - if (!surface_) - throw std::runtime_error(SDL_GetError()); - - size_ = { - static_cast<unsigned>(surface_->w), - static_cast<unsigned>(surface_->h) - }; -} - -auto image::get_size() const noexcept -> const mlk::size& -{ - return size_; -} - -void image::draw(window& window, const point& point) -{ - /* - * Create texture at this step so the image constructor does not need the - * window. - */ - if (!texture_) - create_texture(window); - - SDL_Rect target; - - target.x = static_cast<int>(point.x); - target.y = static_cast<int>(point.y); - target.w = static_cast<int>(size_.width); - target.h = static_cast<int>(size_.height); - - if (SDL_RenderCopy(window.get_renderer(), texture_.get(), nullptr, &target) < 0) - throw std::runtime_error(SDL_GetError()); -} - -void image::draw(window& window, const rectangle& source, const rectangle& target) -{ - if (!texture_) - create_texture(window); - - SDL_Rect sr, st; - - sr.x = source.x; - sr.y = source.y; - sr.w = static_cast<int>(source.width); - sr.h = static_cast<int>(source.height); - - st.x = target.x; - st.y = target.y; - st.w = static_cast<int>(target.width); - st.h = static_cast<int>(target.height); - - // Readjust .w, .h if null. - if (source.is_null()) { - sr.w = static_cast<int>(size_.width); - sr.h = static_cast<int>(size_.height); - } - if (target.is_null()) { - st.w = static_cast<int>(size_.width); - st.h = static_cast<int>(size_.height); - } - - if (SDL_RenderCopy(window.get_renderer(), texture_.get(), &sr, &st) < 0) - throw std::runtime_error(SDL_GetError()); -} - -} // !mlk::client
--- a/libclient/malikania/client/image.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * image.hpp -- image object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_IMAGE_HPP -#define MALIKANIA_CLIENT_IMAGE_HPP - -/** - * \file image.hpp - * \brief Images. - */ - -#include <memory> -#include <string> - -#include <SDL.h> - -#include "point.hpp" -#include "rectangle.hpp" -#include "size.hpp" - -namespace mlk::client { - -class window; - -/** - * \brief Image object. - */ -class image { -private: - std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> surface_{nullptr, nullptr}; - std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)> texture_{nullptr, nullptr}; - - size size_; - - void create_texture(window& window); - -public: - /** - * Construct an image from the binary data. - * - * \param window the window - * \param data the data - */ - image(std::string data); - - /** - * Get the image size. - * - * \return the size - */ - auto get_size() const noexcept -> const mlk::size&; - - /** - * Draw the image to the window. - * - * \param window the window - * \param position the position - */ - void draw(window& window, const point& position = {0, 0}); - - /** - * Overloaded function. - * - * \param window the window - * \param source the source to clip - * \param target the target destination - */ - void draw(window& window, const rectangle& source, const rectangle& target); -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_IMAGE_HPP
--- a/libclient/malikania/client/key.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,256 +0,0 @@ -/* - * key.hpp -- key definitions - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_KEY_HPP -#define MALIKANIA_CLIENT_KEY_HPP - -namespace mlk::client { - -/** - * \brief Describe keyboard modifiers - * - * This enumeration is a satisfied the Bitmask concept. - */ -enum class mod { - none = 0, //!< no modifiers - left_control = (1 << 1), //!< left control - left_alt = (1 << 2), //!< left alt - left_shift = (1 << 3), //!< left shift - left_super = (1 << 4), //!< left logo - right_control = (1 << 5), //!< right control - right_alt = (1 << 6), //!< right alt - right_shift = (1 << 7), //!< right shift - right_super = (1 << 8), //!< right logo - num_lock = (1 << 9), //!< num lock is on - caps_lock = (1 << 10), //!< caps lock is on - - /** - * Left or right control. - */ - control = left_control | right_control, - - /** - * Left or right shift. - */ - shift = left_shift | right_shift, - - /** - * Left or right alt. - */ - alt = left_alt | right_alt, - - /** - * Left or right super. - */ - super = left_super | right_super -}; - -/** - * \cond ENUM_HIDDEN_SYMBOLS - */ - -inline auto operator^(mod v1, mod v2) noexcept -> mod -{ - return static_cast<mod>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2)); -} - -inline auto operator&(mod v1, mod v2) noexcept -> mod -{ - return static_cast<mod>(static_cast<unsigned>(v1)& static_cast<unsigned>(v2)); -} - -inline auto operator|(mod v1, mod v2) noexcept -> mod -{ - return static_cast<mod>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2)); -} - -inline auto operator~(mod v) noexcept -> mod -{ - return static_cast<mod>(~static_cast<unsigned>(v)); -} - -inline auto operator|=(mod& v1, mod v2) noexcept -> mod& -{ - v1 = static_cast<mod>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2)); - - return v1; -} - -inline auto operator&=(mod& v1, mod v2) noexcept -> mod& -{ - v1 = static_cast<mod>(static_cast<unsigned>(v1)& static_cast<unsigned>(v2)); - - return v1; -} - -inline auto operator^=(mod& v1, mod v2) noexcept -> mod& -{ - v1 = static_cast<mod>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2)); - - return v1; -} - -/** - * \endcond - */ - -/** - * \brief Key description. - */ -enum class key { - unknown, - a, - b, - c, - d, - e, - f, - g, - h, - i, - j, - k, - l, - m, - n, - o, - p, - q, - r, - s, - t, - u, - v, - w, - x, - y, - z, - exclaim, - double_quote, - percent, - dollar, - ampersand, - left_parenthese, - right_parenthese, - asterisk, - plus, - colon, - less, - greater, - question, - at, - caret, - underscore, - back_quote, - quote, - one, - two, - three, - four, - five, - six, - seven, - eight, - nine, - zero, - enter, - escape, - backspace, - tab, - space, - minus, - equals, - left_bracket, - right_bracket, - backslash, - hash, - semicolon, - apostrophe, - grave, - comma, - period, - slash, - caps_lock, - f1, - f2, - f3, - f4, - f5, - f6, - f7, - f8, - f9, - f10, - f11, - f12, - f13, - f14, - f15, - f16, - f17, - f18, - f19, - f20, - f21, - f22, - f23, - f24, - print_screen, - scroll_lock, - pause, - insert, - home, - page_up, - page_down, - del, - end, - right, - left, - down, - up, - kp_divide, - kp_multiply, - kp_minus, - kp_plus, - kp_enter, - kp_one, - kp_two, - kp_three, - kp_four, - kp_five, - kp_six, - kp_seven, - kp_eight, - kp_nine, - kp_zero, - mute, - volume_up, - volume_down, - left_control, - left_alt, - left_shift, - left_super, - right_control, - right_alt, - right_shift, - right_super -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_KEY_HPP
--- a/libclient/malikania/client/label.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * label.cpp -- GUI label element - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "label.hpp" -#include "size.hpp" -#include "theme.hpp" -#include "window.hpp" - -namespace mlk::client { - -label::label(std::string text) noexcept - : text_(std::move(text)) -{ -} - -auto label::get_text() const noexcept -> const std::string& -{ - return text_; -} - -void label::set_text(std::string text) noexcept -{ - text_ = std::move(text); -} - -void label::draw(window& w, const size& size) -{ - // TODO: implement. - (void)w; - (void)size; -} - -} // !mlk::client
--- a/libclient/malikania/client/label.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * label.hpp -- GUI label element - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_LABEL_HPP -#define MALIKANIA_CLIENT_LABEL_HPP - -/** - * \file label.hpp - * \brief GUI label element. - */ - -#include <string> - -#include "widget.hpp" - -namespace mlk::client { - -/** - * \brief Basic label for displaying test. - */ -class label : public widget { -private: - std::string text_; - -public: - /** - * Create a label with an optional text. - * - * \param text the text - */ - label(std::string text = "") noexcept; - - /** - * Get the text. - * - * \return the label text - */ - auto get_text() const noexcept -> const std::string&; - - /** - * Set the label text. - * - * \param text the text - */ - void set_text(std::string text) noexcept; - - /** - * \copydoc widget::draw - */ - void draw(window& w, const size& size) override; -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_LABEL_HPP
--- a/libclient/malikania/client/loader.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * client_resources_loader.cpp -- load shared resources files for the client - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <json.hpp> - -#include "animation.hpp" -#include "font.hpp" -#include "image.hpp" -#include "loader.hpp" -#include "locator.hpp" -#include "size.hpp" -#include "sprite.hpp" -#include "util.hpp" - -using namespace nlohmann; - -namespace mlk::client { - -namespace { - -auto load_animation_frames(const json& value) -{ - animation::frame_list frames; - - for (const auto& v : value) { - if (!v.is_object()) - throw std::runtime_error("not a JSON object"); - - const auto cell = v.find("cell"); - const auto delay = v.find("delay"); - - if (cell == v.end() || !cell->is_number_unsigned()) - throw std::runtime_error("invalid cell"); - if (delay == v.end() || !delay->is_number_unsigned()) - throw std::runtime_error("invalid delay"); - - // TODO: range check. - frames.push_back({cell->get<unsigned>(), delay->get<unsigned>()}); - } - - return frames; -} - -} // !namespace - -loader::loader(locator& locator) noexcept - : mlk::loader(locator) -{ -} - -auto loader::load_font(std::string_view id, unsigned size) -> font -{ - return font(get_locator().read(id), size); -} - -auto loader::load_image(std::string_view id) -> image -{ - return image(get_locator().read(id)); -} - -auto loader::load_sprite(std::string_view id) -> sprite -{ - auto value = json::parse(get_locator().read(id)); - - if (!value.is_object()) - throw std::runtime_error(": not a JSON object"); - - return sprite( - load_image(util::json::require_string(value, "/image"_json_pointer)), - util::json::require_size(value, "/cell"_json_pointer), - util::json::get_size(value, "/margin"_json_pointer), - util::json::get_size(value, "/space"_json_pointer), - util::json::get_size(value, "/size"_json_pointer) - ); -} - -auto loader::load_animation(std::string_view id) -> animation -{ - const auto value = json::parse(get_locator().read(id)); - - if (!value.is_object()) - throw std::runtime_error("not a JSON object"); - - const auto s = load_sprite(util::json::require_string(value, "/sprite"_json_pointer)); - - return { - load_sprite(util::json::require_string(value, "/sprite"_json_pointer)), - load_animation_frames(util::json::require_array(value, "/frames"_json_pointer)) - }; -} - -} // !mlk::client
--- a/libclient/malikania/client/loader.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * client_resources_loader.hpp -- load shared resources files for the client - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_LOADER_HPP -#define MALIKANIA_CLIENT_LOADER_HPP - -/* - * \file loader.hpp - * \brief Load client assets. - */ - -#include <malikania/loader.hpp> - -#include <string> - -namespace mlk { - -struct size; - -namespace client { - -struct animation; - -class font; -class image; -class sprite; - -/** - * \brief Load client resources. - */ -class loader : public mlk::loader { -public: - /** - * Client resources loader constructor. - * - * The window is required because some of the resources require it. - * - * \param locator the resources locator - */ - loader(locator& locator) noexcept; - - /** - * Load a font. - * - * \param id the resource id - * \param size the desired size - * \return the font - * \throw std::runtime_error on errors - */ - virtual auto load_font(std::string_view id, unsigned size) -> font; - - /** - * Load an image. - * - * \param id the resource id - * \return the image - * \throw std::runtime_error on errors - */ - virtual auto load_image(std::string_view id) -> image; - - /** - * Load a sprite. - * - * \param id the resource id - * \return the sprite - * \throw std::runtime_error on errors - */ - virtual auto load_sprite(std::string_view id) -> sprite; - - /** - * Load an animation. - * - * \param id the resource id - * \return the animation - * \throw std::runtime_error on errors - */ - virtual auto load_animation(std::string_view id) -> animation; -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_LOADER_HPP
--- a/libclient/malikania/client/mouse.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * mouse.hpp -- mouse definitions - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_MOUSE_HPP -#define MALIKANIA_CLIENT_MOUSE_HPP - -/** - * \file mouse.hpp - * \brief Mouse definitions. - */ - -namespace mlk::client { - -/** - * \brief Describe mouse button - */ -enum class mouse { - none, //!< no buttons are pressed - left, //!< left click is pressed - right, //!< right click is pressed - middle //!< middle click is pressed -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_MOUSE_HPP
--- a/libclient/malikania/client/sdl_util.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * sdl_util.cpp -- common SDL2 related code - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cerrno> -#include <cstdint> -#include <cstring> -#include <new> - -#include "sdl_util.hpp" - -namespace mlk::client { - -namespace { - -/* - * RWFromBinary implementation - * ------------------------------------------------------------------ - * - * A little bit inspired by official SDL_RWFromMem implementation, largely - * modified to match our conventions and the C++ code. - */ - -struct buffer { - std::string data; - std::uint64_t position; - std::uint64_t length; - - buffer(std::string input) noexcept - : data(std::move(input)) - , position(0ULL) - , length(data.length()) - { - } -}; - -auto size(SDL_RWops* ops) noexcept -> Sint64 -{ - return reinterpret_cast<buffer*>(ops->hidden.unknown.data1)->length; -} - -auto seek(SDL_RWops* ops, Sint64 offset, int whence) noexcept -> Sint64 -{ - auto data = reinterpret_cast<buffer*>(ops->hidden.unknown.data1); - auto position = data->position; - - switch (whence) { - case RW_SEEK_SET: - position = offset; - break; - case RW_SEEK_CUR: - position = data->position + offset; - break; - case RW_SEEK_END: - position = data->length + offset; - break; - default: - break; - } - - if (static_cast<std::uint64_t>(position) > data->length) - position = data->length; - - return (data->position = position); -} - -auto read(SDL_RWops* ops, void* dst, std::size_t size, std::size_t number) noexcept -> std::size_t -{ - auto data = reinterpret_cast<buffer*>(ops->hidden.unknown.data1); - auto total = number * size; - auto avail = data->length - data->position; - - if (number <= 0U || size <= 0U || ((total / number) != static_cast<std::size_t>(size))) - return 0; - if (total > avail) - total = avail; - - SDL_memcpy(dst, &data->data[data->position], total); - data->position += total; - - return total / size; -} - -auto write(SDL_RWops*, const void*, std::size_t, std::size_t) noexcept -> std::size_t -{ - SDL_SetError("write not supported"); - return -1; -} - -auto close(SDL_RWops* ops) noexcept -> int -{ - if (ops != nullptr) { - delete reinterpret_cast<buffer*>(ops->hidden.unknown.data1); - SDL_FreeRW(ops); - } - - return 0; -} - -} // !namespace - -auto SDLx_RWFromBinary(std::string data) noexcept -> SDL_RWops* -{ - SDL_RWops* ops = SDL_AllocRW(); - - if (ops == nullptr) - return nullptr; - - ops->hidden.unknown.data1 = new (std::nothrow) buffer(std::move(data)); - - if (ops->hidden.unknown.data1 == nullptr) { - SDL_SetError("%s", std::strerror(errno)); - SDL_FreeRW(ops); - - return nullptr; - } - - ops->type = SDL_RWOPS_UNKNOWN; - ops->seek = seek; - ops->size = size; - ops->read = read; - ops->write = write; - ops->close = close; - - return ops; -} - -} // !mlk::client
--- a/libclient/malikania/client/sdl_util.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * sdl_util.hpp -- common SDL2 related code - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_SDL_UTIL_HPP -#define MALIKANIA_SDL_UTIL_HPP - -/** - * \file sdl_util.hpp - * \brief Utilities for SDL backend. - */ - -#include <SDL.h> - -#include <string> - -namespace mlk::client { - -/** - * Create a SDL_RWops that owns the binary data. - * - * This is a safe alternative to SDL_RWFromMem because it owns the memory - * pointed by data until it is closed. The data is moved so there are no copies. - * - * The stream has read-only support and can not write. - * - * Seeking past-the-end or past-the-begin readjust the position to the end or - * begin respectively. - * - * \param data the data - * \return the object or nullptr on errors - */ -auto SDLx_RWFromBinary(std::string data) noexcept -> SDL_RWops*; - -} // !mlk::client - -#endif // !MALIKANIA_SDL_UTIL_HPP
--- a/libclient/malikania/client/sprite.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * sprite.cpp -- image sprite - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include "sprite.hpp" - -namespace mlk::client { - -sprite::sprite(image image, - size cell, - size margin, - size space, - size dimension) noexcept - : image_(std::move(image)) - , cell_(std::move(cell)) - , margin_(std::move(margin)) - , space_(std::move(space)) - , size_(std::move(dimension)) -{ - assert(cell_.width > 0); - assert(cell_.height > 0); - - // If size is not specified, take from image. - if (size_.is_null()) - size_ = image_.get_size(); - - // Compute number of cells. - rows_ = (size_.height - (margin_.height * 2) + space_.height) / (cell_.height + space_.height); - columns_ = (size_.width - (margin_.width * 2) + space_.width) / (cell_.width + space_.width); -} - -auto sprite::get_image() const noexcept -> const image& -{ - return image_; -} - -auto sprite::get_image() noexcept -> image& -{ - return image_; -} - -auto sprite::get_cell() const noexcept -> const size& -{ - return cell_; -} - -auto sprite::get_margin() const noexcept -> const size& -{ - return margin_; -} - -auto sprite::get_space() const noexcept -> const size& -{ - return space_; -} - -auto sprite::get_rows() const noexcept -> unsigned -{ - return rows_; -} - -auto sprite::get_columns() const noexcept -> unsigned -{ - return columns_; -} - -auto sprite::get_total() const noexcept -> unsigned -{ - return columns_ * rows_; -} - -void sprite::draw(window& window, unsigned cell, const point& point) -{ - assert(cell < rows_ * columns_); - - // Compute index in the grid. - unsigned hindex = (cell % columns_); - unsigned vindex = (cell / columns_); - - // Compute the pixel boundaries. - int x = margin_.width + (hindex * space_.width) + (hindex * cell_.width); - int y = margin_.height + (vindex * space_.height) + (vindex * cell_.height); - - rectangle source{x, y, cell_.width, cell_.height}; - rectangle target{point.x, point.y, cell_.width, cell_.height}; - - image_.draw(window, source, target); -} - -} // !mlk::client
--- a/libclient/malikania/client/sprite.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * sprite.hpp -- image sprite - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_SPRITE_HPP -#define MALIKANIA_CLIENT_SPRITE_HPP - -/** - * \file sprite.hpp - * \brief Sprite description. - */ - -#include "image.hpp" - -namespace mlk { - -struct point; - -namespace client { - -/** - * \brief A Sprite is an image divided into cells. - */ -class sprite { -private: - image image_; - size cell_; - size margin_; - size space_; - size size_; - unsigned rows_; - unsigned columns_; - -public: - /** - * Construct a sprite. - * - * \pre cell must not have height or width null - * \param image the image to use - * \param cell size of cell in the image - * \param margin the optional space from borders - * \param space the optional space between cells - * \param dimension the sprite size (if 0, taken from the image) - */ - sprite(image image, - size cell, - size margin = { 0, 0 }, - size space = { 0, 0 }, - size dimension = { 0, 0 }) noexcept; - - /** - * Get the underlying image. - * - * \return the image - */ - auto get_image() const noexcept -> const image&; - - /** - * Overloaded function. - * - * \return the image - */ - auto get_image() noexcept -> image&; - - /** - * Get the cell size. - * - * \return the cell size - */ - auto get_cell() const noexcept -> const size&; - - /** - * Get the margin size. - * - * \return the margin size - */ - auto get_margin() const noexcept -> const size&; - - /** - * Get the space size. - * - * \return the space size - */ - auto get_space() const noexcept -> const size&; - - /** - * Get the number of rows in the grid. - * - * \return the number of rows - */ - auto get_rows() const noexcept -> unsigned; - - /** - * Get the number of columns in the grid. - * - * \return the number of columns - */ - auto get_columns() const noexcept -> unsigned; - - /** - * Get the max number of image in the sprite. - * - * \return the total - */ - auto get_total() const noexcept -> unsigned; - - /** - * Draw the sprite into the window at the specified position. - * - * \pre cell < rows() * columns() - * \param window the window - * \param cell the cell index - * \param position the position in the window - */ - void draw(window& window, unsigned cell, const point& position); -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_SPRITE_HPP
--- a/libclient/malikania/client/state.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * state.hpp -- game client state - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_STATE_HPP -#define MALIKANIA_CLIENT_STATE_HPP - -/** - * \file state.hpp - * \brief Game client state. - */ - -#include "dispatcher.hpp" - -namespace mlk::client { - -class client; - -/** - * \brief Game client state. - */ -class state : public dispatcher { -public: - /** - * Default constructor. - */ - state() noexcept = default; - - /** - * Virtual destructor defaulted. - */ - virtual ~state() noexcept = default; - - /** - * Update the state. - * - * \param clt the client - */ - virtual void update(client& clt) - { - (void)clt; - } - - /** - * Draw the state. - * - * \param clt the client - */ - virtual void draw(client& clt) - { - (void)clt; - } -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_STATE_HPP
--- a/libclient/malikania/client/state/lobby_state.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * lobby_state.cpp -- character management state - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "client.hpp" -#include "color.hpp" -#include "lobby_state.hpp" -#include "map_state.hpp" -#include "theme.hpp" -#include "window.hpp" - -namespace mlk { - -namespace client { - -lobby_state::lobby_state(client& client) - : client_(client) - , names_{"erekin", "luna"} -{ -} - -void lobby_state::handle_key_down(const key_event& ev) -{ - if (ev.keycode == key::down) - index_ = index_ == names_.size() - 1 ? 0 : index_ + 1; - else if (ev.keycode == key::up) - index_ = index_ == 0 ? names_.size() - 1 : index_ - 1; - else - client_.set_state(std::make_unique<map_state>()); -} - -void lobby_state::update(client&) -{ -} - -void lobby_state::draw(client& clt) -{ - // TODO: lobby_window. - auto& win = clt.window(); - - win.set_drawing_color(color::from_hex(0xffffffff)); - win.clear(); - win.set_drawing_color(color::from_hex(0xff000000)); - win.draw_text("Select your player", theme::get_default().get_font(), {20, 10}); - - std::size_t i = 0U; - for (const auto& n : names_) { - int y = 30 + (10 * i); - - if (i++ == index_) - win.draw_text("»", theme::get_default().get_font(), {10, y}); - - win.draw_text(n, theme::get_default().get_font(), {20, y}); - } - - win.present(); -} - -} // !client - -} // !mlk
--- a/libclient/malikania/client/state/lobby_state.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * lobby_state.hpp -- character management state - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_LOBBY_STATE_HPP -#define MALIKANIA_CLIENT_LOBBY_STATE_HPP - -/** - * \file lobby_state.hpp - * \brief Character management state. - */ - -#include <string> -#include <vector> - -#include "state.hpp" - -namespace mlk::client { - -/** - * \brief Character management state. - */ -class lobby_state : public state { -private: - client& client_; - std::vector<std::string> names_; - std::size_t index_{0}; - -public: - lobby_state(client& client); - - void handle_key_down(const key_event& ev) override; - - void update(client&) override; - - void draw(client& clt) override; -}; - -} // !mlk::client - -#endif // !MALIKANIA_CLIENT_LOBBY_STATE_HPP
--- a/libclient/malikania/client/state/login_state.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * login_state.cpp -- login state - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "color.hpp" -#include "client.hpp" -#include "login_state.hpp" -#include "lobby_state.hpp" -#include "theme.hpp" -#include "unicode.hpp" -#include "window.hpp" - -namespace mlk { - -namespace client { - -void login_state::do_connect() -{ - state_ = state_t::connecting; - status_ = "Connecting..."; - client_.connect("localhost", 3320); -} - -void login_state::do_auth() -{ - status_ = "Authenticating"; - state_ = state_t::authenticating; - client_.send({ - { "command", "auth" }, - { "login", unicode::to_utf8(login_) }, - { "password", unicode::to_utf8(password_) } - }); -} - -login_state::login_state(client& clt) - : client_(clt) -{ - client_.window().start_edit(); -} - -void login_state::handle_text(const text_event& ev) -{ - if (index_ == 0) - login_ += ev.text; - else - password_ += ev.text; -} - -void login_state::update(client&) -{ -} - -void login_state::handle_connect(const std::error_code& code) -{ - if (code) - status_ = code.message(); - else - do_auth(); -} - -void login_state::handle_message(const std::error_code& code, const nlohmann::json& msg) -{ - if (code) - status_ = code.message(); - else - status_ = msg["error"].get<std::string>(); -} - -void login_state::handle_key_down(const key_event& ev) -{ - switch (ev.keycode) { - case key::tab: - index_ ++; - - if (index_ == 2) - index_ = 0; - break; - case key::backspace: - if (index_ == 0) - login_.pop_back(); - else - password_.pop_back(); - break; - case key::enter: - if (index_ == 1 && state_ == state_t::disconnected) - do_connect(); - break; - default: - break; - } -} - -void login_state::draw(client& clt) -{ - auto& win = clt.window(); - const auto& font = theme::get_default().get_font(); - - win.set_drawing_color(color::from_hex(0xffffffff)); - win.clear(); - win.set_drawing_color(color::from_hex(0xff000000)); - win.draw_text("Please log in", font, {10, 10}); - win.draw_text("login: ", font, {10, 50}); - win.draw_text("password: ", font, {10, 70}); - - if (!login_.empty()) - win.draw_text(unicode::to_utf8(login_), font, {70, 50}); - if (!password_.empty()) - win.draw_text(std::string(password_.length(), '*'), font, {70, 70}); - if (!status_.empty()) - win.draw_text(status_, font, {70, 90}); - - win.present(); -} - -} // !client - -} // !mlk
--- a/libclient/malikania/client/state/login_state.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * login_state.cpp -- login state - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_LOGIN_STATE_HPP -#define MALIKANIA_CLIENT_LOGIN_STATE_HPP - -/** - * \file login_state.hpp - * \brief Login state. - */ - -#include <malikania/client/state.hpp> - -namespace mlk { - -namespace client { - -/** - * \brief Login state. - */ -class login_state : public state { -private: - enum class state_t { - disconnected, - connecting, - authenticating - }; - - client& client_; - state_t state_{state_t::disconnected}; - std::size_t index_{0}; - std::u32string login_; - std::u32string password_; - std::string status_; - - void do_connect(); - void do_auth(); - -public: - login_state(client& clt); - - void update(client&) override; - void draw(client& clt) override; - void handle_connect(const std::error_code& code) override; - void handle_message(const std::error_code& code, const nlohmann::json& msg) override; - void handle_key_down(const key_event& ev) override; - void handle_text(const text_event& ev) override; -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_LOGIN_STATE_HPP
--- a/libclient/malikania/client/state/map_state.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -#include "client.hpp" -#include "color.hpp" -#include "map_state.hpp" -#include "point.hpp" -#include "rectangle.hpp" -#include "theme.hpp" -#include "window.hpp" - -namespace mlk { - -namespace client { - -void map_state::handle_key_down(const key_event& ev) -{ - if (ev.keycode == key::down) - delta_ = {delta_.x, 1}; - else if (ev.keycode == key::up) - delta_ = {delta_.x, -1}; - else if (ev.keycode == key::left) - delta_ = {-1, delta_.y}; - else if (ev.keycode == key::right) - delta_ = {1, delta_.y}; -} - -void map_state::handle_key_up(const key_event& ev) -{ - if (ev.keycode == key::down || ev.keycode == key::up) - delta_ = {delta_.x, 0}; - else if (ev.keycode == key::left || ev.keycode == key::right) - delta_ = {0, delta_.y}; -} - -void map_state::update(client&) -{ - position_ = { - position_.x + delta_.x, - position_.y + delta_.y - }; -} - -void map_state::draw(client& clt) -{ - auto& win = clt.window(); - - win.set_drawing_color(color::from_hex(0xffffffff)); - win.clear(); - win.set_drawing_color(color::from_hex(0xff000000)); - - // Draw a little square as user position. - win.fill_rectangle({ position_.x, position_.y, 10, 10 }); - - // Draw nickname on top of it. - auto clip = theme::get_default().get_font().clip("molko"); - - win.draw_text("molko", theme::get_default().get_font(), point{ - static_cast<int>(position_.x - (clip.width / 2)), - static_cast<int>(position_.y - clip.height - 10) - }); - win.present(); -} - -} // !client - -} // !mlk
--- a/libclient/malikania/client/state/map_state.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * map_state.hpp -- main game state - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_MAP_STATE_HPP -#define MALIKANIA_CLIENT_MAP_STATE_HPP - -/** - * \file map_state.hpp - * \brief Main game state. - */ - -#include "point.hpp" -#include "state.hpp" - -namespace mlk { - -namespace client { - -/** - * \brief Main game state. - */ -class map_state : public state { -private: - point position_{320, 240}; - point delta_; - -public: - void update(client&) override; - void draw(client& clt) override; - void handle_key_down(const key_event& ev) override; - void handle_key_up(const key_event& ev) override; -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_MAP_STATE_HPP
--- a/libclient/malikania/client/theme.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * theme.cpp -- theming support for gui elements - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "button.hpp" -#include "color.hpp" -#include "label.hpp" -#include "point.hpp" -#include "rectangle.hpp" -#include "theme.hpp" -#include "window.hpp" - -namespace mlk::client { - -namespace { - -#include <dejavu_sans.hpp> - -} // !namespace - -std::unique_ptr<theme> theme::global; - -auto theme::get_default() noexcept -> theme& -{ - if (!global) - global = std::make_unique<theme>(); - - return *global; -} - -void theme::set_default(std::unique_ptr<theme> theme) noexcept -{ - global = std::move(theme); -} - -theme::theme() - : font_(std::string(dejavu_sans, sizeof (dejavu_sans)), 10) - , background_color_{228, 228, 228, 255} - , border_color_{102, 102, 102, 255} - , text_color_{50, 50, 50, 255} -{ -} - -auto theme::get_font() const noexcept -> const font& -{ - return font_; -} - -auto theme::get_font() noexcept -> font& -{ - return font_; -} - -auto theme::get_background_color() const noexcept -> const color& -{ - return background_color_; -} - -auto theme::get_border_color() const noexcept -> const color& -{ - return border_color_; -} - -auto theme::get_text_color() const noexcept -> const color& -{ - return text_color_; -} - -void theme::draw_button(window& w, const button& b, const rectangle& rect) -{ - // Border. - w.set_drawing_color(border_color_); - w.draw_rectangle({ rect.x, rect.y, rect.width, rect.height }); - - // Box content. - w.set_drawing_color(background_color_); - w.fill_rectangle({ rect.x + 2, rect.y + 2, rect.width - 2, rect.height - 2 }); - - // Text. - // TODO: alignment. - w.set_drawing_color(text_color_); - w.draw_text(b.get_text(), font_, point{rect.x + 5, rect.y + 5}); -} - -void theme::draw_label(window& w, const label& label, const rectangle& rect) -{ - w.set_drawing_color(text_color_); - w.draw_text(label.get_text(), font_, point{rect.x, rect.y}); -} - -} // !mlk::client
--- a/libclient/malikania/client/theme.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * theme.hpp -- theming support for gui elements - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_THEME_HPP -#define MALIKANIA_CLIENT_THEME_HPP - -/** - * \file theme.hpp - * \brief Theming support for gui elements. - */ - -#include <memory> - -#include "color.hpp" -#include "font.hpp" -#include "size.hpp" - -namespace mlk { - -struct rectangle; - -namespace client { - -class button; -class label; -class window; - -/** - * \brief Reimplement this class to provide your own theme. - */ -class theme { -private: - static std::unique_ptr<theme> global; - - font font_; - color background_color_; - color border_color_; - color text_color_; - -public: - static auto get_default() noexcept -> theme&; - - static void set_default(std::unique_ptr<theme> theme) noexcept; - - /** - * Default constructor. - */ - theme(); - - /** - * Virtual destructor defaulted. - */ - virtual ~theme() noexcept = default; - - /** - * Get the font. - * - * \return the font - */ - virtual auto get_font() const noexcept -> const font&; - - /** - * Overloaded function. - * - * \return the font - */ - virtual auto get_font() noexcept -> font&; - - /** - * Get the background color for basic widgets. - * - * \return the color - */ - virtual auto get_background_color() const noexcept -> const color&; - - /** - * Get the border color for basic widgets. - * - * \return the color - */ - virtual auto get_border_color() const noexcept -> const color&; - - /** - * Get the text color for basic widgets. - * - * \return the color - */ - virtual auto get_text_color() const noexcept -> const color&; - - /** - * Draw a button. - * - * \param w the main window - * \param b the button - */ - virtual void draw_button(window& w, const button& b, const rectangle& rect); - - /** - * Draw a label. - * - * \param w the main window - * \param l the label - * \param rect the bounding rectangle. - */ - virtual void draw_label(window& w, const label& l, const rectangle& rect); -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_THEME_HPP
--- a/libclient/malikania/client/widget.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * widget.cpp -- basic abstract widget for GUI - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "theme.hpp" -#include "widget.hpp" - -namespace mlk::client { - -widget::widget() noexcept - : theme_(std::addressof(theme::get_default())) -{ -} - -auto widget::get_position() const noexcept -> const point& -{ - return position_; -} - -void widget::set_position(point position) noexcept -{ - position_ = std::move(position); -} - -auto widget::get_theme() const noexcept -> const theme& -{ - return *theme_; -} - -auto widget::get_theme() noexcept -> theme& -{ - return *theme_; -} - -void widget::set_theme(theme& theme) noexcept -{ - theme_ = std::addressof(theme); -} - -} // !mlk::client
--- a/libclient/malikania/client/widget.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * widget.hpp -- basic abstract widget for GUI - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_WIDGET_HPP -#define MALIKANIA_CLIENT_WIDGET_HPP - -/** - * \file widget.hpp - * \brief Basic abstract widget for GUI - */ - -#include "dispatcher.hpp" -#include "point.hpp" - -namespace mlk { - -struct rectangle; -struct size; - -namespace client { - -class window; -class theme; - -/** - * \brief Abstract widget - */ -class widget : public dispatcher { -protected: - theme* theme_; //!< widget theme - point position_; //!< widget position - -public: - /** - * Constructor. - * - * Initialize the theme with the global one. - */ - widget() noexcept; - - /** - * Default destructor. - */ - virtual ~widget() noexcept = default; - - /** - * Get the widget position. - * - * \return the position - */ - auto get_position() const noexcept -> const point&; - - /** - * Set the widget position. - * - * \param position the new position - */ - void set_position(point position) noexcept; - - /** - * Get the theme. - * - * \return the theme - */ - auto get_theme() const noexcept -> const theme&; - - /** - * Overloaded function. - * - * \return the theme - */ - auto get_theme() noexcept -> theme&; - - /** - * Change the widget theme. - * - * \param theme the new theme - */ - void set_theme(theme& theme) noexcept; - - /** - * Draw the widget at the specified position. - * - * \param w the window - * \param size the maximum size allowed - */ - virtual void draw(window& w, const size& size) = 0; -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_WIDGET_HPP
--- a/libclient/malikania/client/window.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,588 +0,0 @@ -/* - * window.cpp -- main window and basic drawing - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <iostream> -#include <stdexcept> - -#include <malikania/unicode.hpp> - -#include "color.hpp" -#include "line.hpp" -#include "rectangle.hpp" -#include "theme.hpp" -#include "widget.hpp" -#include "window.hpp" - -namespace mlk::client { - -namespace { - -/* - * conversion maps - * ------------------------------------------------------------------ - * - * There is a difference between scancode and key codes. The scancode is the - * key located on the keyboard which is always the same, the key code is the - * translated to the user layout. - * - * For example, on azerty, hitting the 'a' key makes a key code of 'a' but a - * scancode of 'q'. - * - * - scancodes_map : convert SDL scancode do key - * - keycodes_map : convert SDL key code to key - * - modifiers_map : convert masks - * - button_map : convert SDL mouse buttons - */ - -const std::unordered_map<SDL_Keycode, key> scancodes_map{ - { SDL_SCANCODE_A, key::a }, - { SDL_SCANCODE_B, key::b }, - { SDL_SCANCODE_C, key::c }, - { SDL_SCANCODE_D, key::d }, - { SDL_SCANCODE_E, key::e }, - { SDL_SCANCODE_F, key::f }, - { SDL_SCANCODE_G, key::g }, - { SDL_SCANCODE_H, key::h }, - { SDL_SCANCODE_I, key::i }, - { SDL_SCANCODE_J, key::j }, - { SDL_SCANCODE_K, key::k }, - { SDL_SCANCODE_L, key::l }, - { SDL_SCANCODE_M, key::m }, - { SDL_SCANCODE_N, key::n }, - { SDL_SCANCODE_O, key::o }, - { SDL_SCANCODE_P, key::p }, - { SDL_SCANCODE_Q, key::q }, - { SDL_SCANCODE_R, key::r }, - { SDL_SCANCODE_S, key::s }, - { SDL_SCANCODE_T, key::t }, - { SDL_SCANCODE_U, key::u }, - { SDL_SCANCODE_V, key::v }, - { SDL_SCANCODE_W, key::w }, - { SDL_SCANCODE_X, key::x }, - { SDL_SCANCODE_Y, key::y }, - { SDL_SCANCODE_Z, key::z }, - { SDL_SCANCODE_1, key::one }, - { SDL_SCANCODE_2, key::two }, - { SDL_SCANCODE_3, key::three }, - { SDL_SCANCODE_4, key::four }, - { SDL_SCANCODE_5, key::five }, - { SDL_SCANCODE_6, key::six }, - { SDL_SCANCODE_7, key::seven }, - { SDL_SCANCODE_8, key::eight }, - { SDL_SCANCODE_9, key::nine }, - { SDL_SCANCODE_0, key::zero }, - { SDL_SCANCODE_RETURN, key::enter }, - { SDL_SCANCODE_ESCAPE, key::escape }, - { SDL_SCANCODE_BACKSPACE, key::backspace }, - { SDL_SCANCODE_TAB, key::tab }, - { SDL_SCANCODE_SPACE, key::space }, - { SDL_SCANCODE_MINUS, key::minus }, - { SDL_SCANCODE_EQUALS, key::equals }, - { SDL_SCANCODE_LEFTBRACKET, key::left_bracket }, - { SDL_SCANCODE_RIGHTBRACKET, key::right_bracket }, - { SDL_SCANCODE_BACKSLASH, key::backslash }, - { SDL_SCANCODE_NONUSHASH, key::hash }, - { SDL_SCANCODE_SEMICOLON, key::semicolon }, - { SDL_SCANCODE_APOSTROPHE, key::apostrophe }, - { SDL_SCANCODE_GRAVE, key::grave }, - { SDL_SCANCODE_COMMA, key::comma }, - { SDL_SCANCODE_PERIOD, key::period }, - { SDL_SCANCODE_SLASH, key::slash }, - { SDL_SCANCODE_CAPSLOCK, key::caps_lock }, - { SDL_SCANCODE_F1, key::f1 }, - { SDL_SCANCODE_F2, key::f2 }, - { SDL_SCANCODE_F3, key::f3 }, - { SDL_SCANCODE_F4, key::f4 }, - { SDL_SCANCODE_F5, key::f5 }, - { SDL_SCANCODE_F6, key::f6 }, - { SDL_SCANCODE_F7, key::f7 }, - { SDL_SCANCODE_F8, key::f8 }, - { SDL_SCANCODE_F9, key::f9 }, - { SDL_SCANCODE_F10, key::f10 }, - { SDL_SCANCODE_F11, key::f11 }, - { SDL_SCANCODE_F12, key::f12 }, - { SDL_SCANCODE_F13, key::f13 }, - { SDL_SCANCODE_F14, key::f14 }, - { SDL_SCANCODE_F15, key::f15 }, - { SDL_SCANCODE_F16, key::f16 }, - { SDL_SCANCODE_F17, key::f17 }, - { SDL_SCANCODE_F18, key::f18 }, - { SDL_SCANCODE_F19, key::f19 }, - { SDL_SCANCODE_F20, key::f20 }, - { SDL_SCANCODE_F21, key::f21 }, - { SDL_SCANCODE_F22, key::f22 }, - { SDL_SCANCODE_F23, key::f23 }, - { SDL_SCANCODE_F24, key::f24 }, - { SDL_SCANCODE_PRINTSCREEN, key::print_screen }, - { SDL_SCANCODE_SCROLLLOCK, key::scroll_lock }, - { SDL_SCANCODE_PAUSE, key::pause }, - { SDL_SCANCODE_INSERT, key::insert }, - { SDL_SCANCODE_HOME, key::home }, - { SDL_SCANCODE_PAGEUP, key::page_up }, - { SDL_SCANCODE_PAGEDOWN, key::page_down }, - { SDL_SCANCODE_DELETE, key::del }, - { SDL_SCANCODE_END, key::end }, - { SDL_SCANCODE_RIGHT, key::right }, - { SDL_SCANCODE_LEFT, key::left }, - { SDL_SCANCODE_DOWN, key::down }, - { SDL_SCANCODE_UP, key::up }, - { SDL_SCANCODE_KP_DIVIDE, key::kp_divide }, - { SDL_SCANCODE_KP_MULTIPLY, key::kp_multiply }, - { SDL_SCANCODE_KP_MINUS, key::kp_minus }, - { SDL_SCANCODE_KP_PLUS, key::kp_plus }, - { SDL_SCANCODE_KP_ENTER, key::kp_enter }, - { SDL_SCANCODE_KP_1, key::kp_one }, - { SDL_SCANCODE_KP_2, key::kp_two }, - { SDL_SCANCODE_KP_3, key::kp_three }, - { SDL_SCANCODE_KP_4, key::kp_four }, - { SDL_SCANCODE_KP_5, key::kp_five }, - { SDL_SCANCODE_KP_6, key::kp_six }, - { SDL_SCANCODE_KP_7, key::kp_seven }, - { SDL_SCANCODE_KP_8, key::kp_eight }, - { SDL_SCANCODE_KP_9, key::kp_nine }, - { SDL_SCANCODE_KP_0, key::kp_zero }, - { SDL_SCANCODE_MUTE, key::mute }, - { SDL_SCANCODE_VOLUMEUP, key::volume_up }, - { SDL_SCANCODE_VOLUMEDOWN, key::volume_down }, - { SDL_SCANCODE_LCTRL, key::left_control }, - { SDL_SCANCODE_LALT, key::left_alt }, - { SDL_SCANCODE_LSHIFT, key::left_shift }, - { SDL_SCANCODE_LGUI, key::left_super }, - { SDL_SCANCODE_RCTRL, key::right_control }, - { SDL_SCANCODE_RALT, key::right_alt }, - { SDL_SCANCODE_RSHIFT, key::right_shift }, - { SDL_SCANCODE_RGUI, key::right_super } -}; - -const std::unordered_map<SDL_Keycode, key> keycodes_map{ - { SDLK_RETURN, key::enter }, - { SDLK_ESCAPE, key::escape }, - { SDLK_BACKSPACE, key::backspace }, - { SDLK_TAB, key::tab }, - { SDLK_SPACE, key::space }, - { SDLK_EXCLAIM, key::exclaim }, - { SDLK_QUOTEDBL, key::double_quote }, - { SDLK_HASH, key::hash }, - { SDLK_PERCENT, key::percent }, - { SDLK_DOLLAR, key::dollar }, - { SDLK_AMPERSAND, key::ampersand }, - { SDLK_QUOTE, key::quote }, - { SDLK_LEFTPAREN, key::left_parenthese }, - { SDLK_RIGHTPAREN, key::right_parenthese }, - { SDLK_ASTERISK, key::asterisk }, - { SDLK_PLUS, key::plus }, - { SDLK_COMMA, key::comma }, - { SDLK_MINUS, key::minus }, - { SDLK_PERIOD, key::period }, - { SDLK_SLASH, key::slash }, - { SDLK_0, key::zero }, - { SDLK_1, key::one }, - { SDLK_2, key::two }, - { SDLK_3, key::three }, - { SDLK_4, key::four }, - { SDLK_5, key::five }, - { SDLK_6, key::six }, - { SDLK_7, key::seven }, - { SDLK_8, key::eight }, - { SDLK_9, key::nine }, - { SDLK_COLON, key::colon }, - { SDLK_SEMICOLON, key::semicolon }, - { SDLK_LESS, key::less }, - { SDLK_EQUALS, key::equals }, - { SDLK_GREATER, key::greater }, - { SDLK_QUESTION, key::question }, - { SDLK_AT, key::at }, - { SDLK_LEFTBRACKET, key::left_bracket }, - { SDLK_BACKSLASH, key::backslash }, - { SDLK_RIGHTBRACKET, key::right_bracket }, - { SDLK_CARET, key::caret }, - { SDLK_UNDERSCORE, key::underscore }, - { SDLK_BACKQUOTE, key::back_quote }, - { SDLK_a, key::a }, - { SDLK_b, key::b }, - { SDLK_c, key::c }, - { SDLK_d, key::d }, - { SDLK_e, key::e }, - { SDLK_f, key::f }, - { SDLK_g, key::g }, - { SDLK_h, key::h }, - { SDLK_i, key::i }, - { SDLK_j, key::j }, - { SDLK_k, key::k }, - { SDLK_l, key::l }, - { SDLK_m, key::m }, - { SDLK_n, key::n }, - { SDLK_o, key::o }, - { SDLK_p, key::p }, - { SDLK_q, key::q }, - { SDLK_r, key::r }, - { SDLK_s, key::s }, - { SDLK_t, key::t }, - { SDLK_u, key::u }, - { SDLK_v, key::v }, - { SDLK_w, key::w }, - { SDLK_x, key::x }, - { SDLK_y, key::y }, - { SDLK_z, key::z }, - { SDLK_CAPSLOCK, key::caps_lock }, - { SDLK_F1, key::f1 }, - { SDLK_F2, key::f2 }, - { SDLK_F3, key::f3 }, - { SDLK_F4, key::f4 }, - { SDLK_F5, key::f5 }, - { SDLK_F6, key::f6 }, - { SDLK_F7, key::f7 }, - { SDLK_F8, key::f8 }, - { SDLK_F9, key::f9 }, - { SDLK_F10, key::f10 }, - { SDLK_F11, key::f11 }, - { SDLK_F12, key::f12 }, - { SDLK_F13, key::f13 }, - { SDLK_F14, key::f14 }, - { SDLK_F15, key::f15 }, - { SDLK_F16, key::f16 }, - { SDLK_F17, key::f17 }, - { SDLK_F18, key::f18 }, - { SDLK_F19, key::f19 }, - { SDLK_F20, key::f20 }, - { SDLK_F21, key::f21 }, - { SDLK_F22, key::f22 }, - { SDLK_F23, key::f23 }, - { SDLK_F24, key::f24 }, - { SDLK_PRINTSCREEN, key::print_screen }, - { SDLK_SCROLLLOCK, key::scroll_lock }, - { SDLK_PAUSE, key::pause }, - { SDLK_INSERT, key::insert }, - { SDLK_HOME, key::home }, - { SDLK_PAGEUP, key::page_up }, - { SDLK_PAGEDOWN, key::page_down }, - { SDLK_DELETE, key::del }, - { SDLK_END, key::end }, - { SDLK_RIGHT, key::right }, - { SDLK_LEFT, key::left }, - { SDLK_DOWN, key::down }, - { SDLK_UP, key::up }, - { SDLK_KP_DIVIDE, key::kp_divide }, - { SDLK_KP_MULTIPLY, key::kp_multiply }, - { SDLK_KP_MINUS, key::kp_minus }, - { SDLK_KP_PLUS, key::kp_plus }, - { SDLK_KP_ENTER, key::kp_enter }, - { SDLK_KP_1, key::kp_one }, - { SDLK_KP_2, key::kp_two }, - { SDLK_KP_3, key::kp_three }, - { SDLK_KP_4, key::kp_four }, - { SDLK_KP_5, key::kp_five }, - { SDLK_KP_6, key::kp_six }, - { SDLK_KP_7, key::kp_seven }, - { SDLK_KP_8, key::kp_eight }, - { SDLK_KP_9, key::kp_nine }, - { SDLK_KP_0, key::kp_zero }, - { SDLK_MUTE, key::mute }, - { SDLK_VOLUMEUP, key::volume_up }, - { SDLK_VOLUMEDOWN, key::volume_down }, - { SDLK_LCTRL, key::left_control }, - { SDLK_LALT, key::left_alt }, - { SDLK_LSHIFT, key::left_shift }, - { SDLK_LGUI, key::left_super }, - { SDLK_RCTRL, key::right_control }, - { SDLK_RALT, key::right_alt }, - { SDLK_RSHIFT, key::right_shift }, - { SDLK_RGUI, key::right_super } -}; - -const std::unordered_map<SDL_Keymod, mod> modifiers_map{ - { KMOD_LCTRL, mod::left_control }, - { KMOD_LALT, mod::left_alt }, - { KMOD_LSHIFT, mod::left_shift }, - { KMOD_LGUI, mod::left_super }, - { KMOD_RCTRL, mod::right_control }, - { KMOD_RALT, mod::right_alt }, - { KMOD_RSHIFT, mod::right_shift }, - { KMOD_RGUI, mod::right_super }, - { KMOD_NUM, mod::num_lock }, - { KMOD_CAPS, mod::caps_lock } -}; - -const std::unordered_map<Uint32, mouse> button_map{ - { SDL_BUTTON_LEFT, mouse::left }, - { SDL_BUTTON_RIGHT, mouse::right }, - { SDL_BUTTON_MIDDLE, mouse::middle } -}; - -} // !namespace - -void window::dispatch_key_event(dispatcher& dp, const SDL_Event& ev) const -{ - assert(ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP); - - // Key and scan code. - const auto kc = keycodes_map.find(ev.key.keysym.sym); - const auto sc = scancodes_map.find(ev.key.keysym.scancode); - - if (kc == keycodes_map.end() || sc == scancodes_map.end()) - return; - - key_event kev{kc->second, sc->second, mod::none}; - - // Modifier is a mask. - for (const auto& pair : modifiers_map) - if (ev.key.keysym.mod & pair.first) - kev.modifiers |= pair.second; - - if (ev.type == SDL_KEYDOWN) - dp.handle_key_down(kev); - else - dp.handle_key_up(kev); -} - -void window::dispatch_mouse_event(dispatcher& dp, const SDL_Event& ev) const -{ - assert(ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP); - - const auto which = button_map.find(ev.button.button); - - if (which == button_map.end()) - return; - - mouse_click_event mev{ - which->second, - point{ev.button.x, ev.button.y} - }; - - if (ev.type == SDL_MOUSEBUTTONDOWN) - dp.handle_mouse_down(mev); - else - dp.handle_mouse_up(mev); -} - -void window::dispatch_mouse_wheel_event(dispatcher& dp, const SDL_Event& ev) const -{ - assert(ev.type == SDL_MOUSEWHEEL); - - dp.handle_mouse_wheel({{ev.wheel.x, ev.wheel.y}}); -} - -void window::dispatch_text_event(dispatcher& dp, const SDL_Event& ev) const -{ - assert(ev.type == SDL_TEXTINPUT); - - dp.handle_text({unicode::to_utf32(ev.text.text)}); -} - - -void window::init() -{ - static bool is_initialized{false}; - - if (!is_initialized) { - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) - throw std::runtime_error(SDL_GetError()); - if (TTF_Init() < 0) - throw std::runtime_error(TTF_GetError()); - - is_initialized = true; - } -} - -window::window(unsigned width, unsigned height, const std::string& title) -{ - init(); - - window_ = { - SDL_CreateWindow( - title.c_str(), - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - width, height, - SDL_WINDOW_OPENGL - ), - SDL_DestroyWindow - }; - - if (window_ == nullptr) - throw std::runtime_error(SDL_GetError()); - - // Create renderer. - renderer_ = { - SDL_CreateRenderer(window_.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), - SDL_DestroyRenderer - }; - - if (renderer_ == nullptr) - throw std::runtime_error(SDL_GetError()); -} - -auto window::get_renderer() const noexcept -> const SDL_Renderer* -{ - assert(is_open_); - - return renderer_.get(); -} - -auto window::get_renderer() noexcept -> SDL_Renderer* -{ - assert(is_open_); - - return renderer_.get(); -} - -auto window::is_open() const noexcept -> bool -{ - return is_open_; -} - -void window::start_edit() -{ - if (!is_editing_) { - SDL_StartTextInput(); - is_editing_ = true; - } -} - -void window::stop_edit() -{ - if (is_editing_) { - SDL_StopTextInput(); - is_editing_ = false; - } -} - -void window::clear() -{ - SDL_RenderClear(renderer_.get()); -} - -void window::present() -{ - SDL_RenderPresent(renderer_.get()); -} - -void window::close() noexcept -{ - is_open_ = false; - renderer_ = nullptr; - window_ = nullptr; -} - -auto window::get_drawing_color() const -> color -{ - SDL_Color color; - - if (SDL_GetRenderDrawColor(renderer_.get(), &color.r, &color.g, &color.b, &color.a) < 0) - throw std::runtime_error(SDL_GetError()); - - return { color.r, color.g, color.b, color.a }; -} - -void window::set_drawing_color(const color& color) -{ - if (SDL_SetRenderDrawColor(renderer_.get(), color.red, color.green, color.blue, color.alpha) < 0) - throw std::runtime_error(SDL_GetError()); -} - -void window::draw_line(const line& line) -{ - if (SDL_RenderDrawLine(renderer_.get(), line.x1, line.y1, line.x2, line.y2) != 0) - throw std::runtime_error(SDL_GetError()); -} - -void window::draw_point(const point& point) -{ - if (SDL_RenderDrawPoint(renderer_.get(), point.x, point.y) != 0) - throw std::runtime_error(SDL_GetError()); -} - -void window::draw_rectangle(const rectangle& rectangle) -{ - SDL_Rect rect{ - rectangle.x, - rectangle.y, - static_cast<int>(rectangle.width), - static_cast<int>(rectangle.height) - }; - - if (SDL_RenderDrawRect(renderer_.get(), &rect) < 0) - throw std::runtime_error(SDL_GetError()); -} - -void window::fill_rectangle(const rectangle& rectangle) -{ - SDL_Rect rect{ - rectangle.x, - rectangle.y, - static_cast<int>(rectangle.width), - static_cast<int>(rectangle.height) - }; - - if (SDL_RenderFillRect(renderer_.get(), &rect) < 0) - throw std::runtime_error(SDL_GetError()); -} - -void window::draw_text(const std::string& text, const font& font, const rectangle& rectangle) -{ - SDL_Color color = { 0, 0, 0, 255 }; - SDL_Surface* message = TTF_RenderUTF8_Blended(font.get_handle(), text.c_str(), color); - SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer_.get(), message); - SDL_Rect rect = { rectangle.x, rectangle.y, (int)rectangle.width, (int)rectangle.height }; - SDL_RenderCopy(renderer_.get(), texture, nullptr, &rect); - SDL_FreeSurface(message); - SDL_DestroyTexture(texture); -} - -void window::draw_text(const std::string& text, const font& font, const point& point) -{ - SDL_Color color = { 0, 0, 0, 0 }; - SDL_GetRenderDrawColor(renderer_.get(), &color.r, &color.g, &color.b, &color.a); - SDL_Surface* message = TTF_RenderUTF8_Blended(font.get_handle(), text.c_str(), color); - SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer_.get(), message); - SDL_Rect rect = { point.x, point.y, message->w, message->h }; - SDL_RenderCopy(renderer_.get(), texture, nullptr, &rect); - SDL_FreeSurface(message); - SDL_DestroyTexture(texture); -} - -void window::poll(dispatcher& dp) -{ - SDL_Event event; - - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYUP: - case SDL_KEYDOWN: - dispatch_key_event(dp, event); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - dispatch_mouse_event(dp, event); - break; - case SDL_MOUSEWHEEL: - dispatch_mouse_wheel_event(dp, event); - break; - case SDL_TEXTINPUT: - dispatch_text_event(dp, event); - break; - case SDL_QUIT: - dp.handle_quit(); - break; - default: - break; - } - } -} - -} // !mlk::client
--- a/libclient/malikania/client/window.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -/* - * window.hpp -- main window and basic drawing - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_CLIENT_WINDOW_HPP -#define MALIKANIA_CLIENT_WINDOW_HPP - -/** - * \file window.hpp - * \brief Window and drawing. - */ - -#include <memory> -#include <string> - -#include <SDL.h> - -#include "dispatcher.hpp" - -namespace mlk { - -struct line; -struct point; -struct rectangle; - -namespace client { - -struct color; - -class font; - -/** - * \brief Main window class and drawing. - */ -class window { -private: - std::unique_ptr<SDL_Window, void (*)(SDL_Window *)> window_{nullptr, nullptr}; - std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer *)> renderer_{nullptr, nullptr}; - - bool is_open_{true}; - bool is_editing_{false}; - - void dispatch_key_event(dispatcher&, const SDL_Event&) const; - void dispatch_mouse_event(dispatcher&, const SDL_Event&) const; - void dispatch_mouse_wheel_event(dispatcher&, const SDL_Event&) const; - void dispatch_text_event(dispatcher&, const SDL_Event&) const; - - void init(); - -public: - /** - * Create a window. - * - * \param width the initial width - * \param height the initial height - * \param title the optional title - * \throw std::runtime_error on errors - */ - window(unsigned width = 640, unsigned height = 480, const std::string& title = "Game"); - - /** - * Virtual destructor defaulted. - */ - virtual ~window() noexcept = default; - - /** - * Get the renderer. - * - * \pre is_open() - * \return the renderer - */ - auto get_renderer() const noexcept -> const SDL_Renderer*; - - /** - * Overloaded function. - * - * \pre is_open() - * \return the renderer - */ - auto get_renderer() noexcept -> SDL_Renderer*; - - /** - * Tells if the window is open. - * - * \return true if open - */ - auto is_open() const noexcept -> bool; - - /** - * Start editing input. - * - * \note may open a visual keyboard on some platforms - * \note can safely be called multiple times - */ - void start_edit(); - - /** - * Stop editing input. - * - * \note may close the visual keyboard on some platforms - * \note can safely be called multiple times - */ - void stop_edit(); - - /** - * Clear the window content with the current drawing color. - */ - void clear(); - - /** - * Render the content of the window to the screen. - */ - void present(); - - /** - * Close the window. - */ - void close() noexcept; - - /** - * Get the current drawing color. - * - * \return the color - */ - auto get_drawing_color() const -> color; - - /** - * Set the drawing color. - * - * \param color the color - */ - void set_drawing_color(const color& color); - - /** - * Draw a line. - * - * \param line the line - */ - void draw_line(const line& line); - - /** - * Draw a point. - * - * \param point the point - */ - void draw_point(const point& point); - - /** - * Draw a rectangle (only borders). - * - * \param rect the rectangle - * \see fillRectangle - */ - void draw_rectangle(const rectangle& rect); - - /** - * Fill the given rectangle with the current color. - * - * \param rect the rectangle - * \see drawRectangle - */ - void fill_rectangle(const rectangle& rect); - - /** - * Draw some text. - * - * This function may stretch the text texture. - * - * \param text the text (UTF-8) - * \param font the font - * \param rectangle the rectangle target - */ - void draw_text(const std::string& text, const font& font, const rectangle& rectangle); - - /** - * Overloaded function. - * - * Draw the text at the given position. - * - * \param text the text (UTF-8) - * \param font the font - * \param point the text position - */ - void draw_text(const std::string& text, const font& font, const point& point); - - /** - * Poll all pending events and call appropriate functions. - * - * \param dispatcher the event dispatcher - */ - void poll(dispatcher& dp); -}; - -} // !client - -} // !mlk - -#endif // !MALIKANIA_CLIENT_WINDOW_HPP
--- a/libcommon-js/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -# -# CMakeLists.txt -- CMake build system for malikania -# -# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(libmlk-common-js) - -set( - HEADERS - ${libmlk-common-js_SOURCE_DIR}/malikania/duktape.hpp - ${libmlk-common-js_SOURCE_DIR}/malikania/duk.hpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_elapsed_timer.hpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_line.hpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_point.hpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_rectangle.hpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_resources_loader.hpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_size.hpp -) - -set( - SOURCES - ${libmlk-common-js_SOURCE_DIR}/malikania/duk.cpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_elapsed_timer.cpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_line.cpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_point.cpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_rectangle.cpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_resources_loader.cpp - ${libmlk-common-js_SOURCE_DIR}/malikania/js_size.cpp -) - -malikania_define_library( - PROJECT libmlk-common-js - TARGET libmlk-common-js - SOURCES ${HEADERS} ${SOURCES} - FLAGS "MALIKANIA_COMMON_BUILD" - PUBLIC_INCLUDES - $<BUILD_INTERFACE:${libmlk-common-js_SOURCE_DIR}/malikania> - LIBRARIES duktape json libmlk-common -)
--- a/libcommon-js/malikania/duk.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,447 +0,0 @@ -/* - * duk.cpp -- miscellaneous Duktape extras - * - * Copyright (c) 2017-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> -#include <cstdio> - -#include "duk.hpp" - -namespace mlk::duk { - -// {{{ stack_guard - -stack_guard::stack_guard(duk_context* ctx, unsigned expected) noexcept -#if !defined(NDEBUG) - : context_(ctx) - , expected_(expected) - , at_start_(duk_get_top(ctx)) -#endif -{ -#if defined(NDEBUG) - (void)ctx; - (void)expected; -#endif -} - -stack_guard::~stack_guard() noexcept -{ -#if !defined(NDEBUG) - auto result = duk_get_top(context_) - at_start_; - - if (result != static_cast<int>(expected_)) { - std::fprintf(stderr, "Corrupt stack detection in stack_guard:\n"); - std::fprintf(stderr, " Size at start: %d\n", at_start_); - std::fprintf(stderr, " Size at end: %d\n", duk_get_top(context_)); - std::fprintf(stderr, " Expected (user): %u\n", expected_); - std::fprintf(stderr, " Expected (adjusted): %u\n", expected_ + at_start_); - std::fprintf(stderr, " Difference count: %+d\n", result - expected_); - std::abort(); - } -#endif -} - -// }}} - -// {{{ context - -context::context() noexcept - : handle_(duk_create_heap_default(), duk_destroy_heap) -{ - duk_push_object(handle_.get()); - duk_put_global_string(handle_.get(), "Malikania"); -} - -context::operator duk_context*() noexcept -{ - return handle_.get(); -} - -context::operator duk_context*() const noexcept -{ - return handle_.get(); -} - -// }}} - -// {{{ stack_info - -stack_info::stack_info(std::string name, - std::string message, - std::string stack, - std::string file_name, - unsigned line_number) noexcept - : name_(std::move(name)) - , message_(std::move(message)) - , stack_(std::move(stack)) - , file_name_(std::move(file_name)) - , line_number_(line_number) -{ -} - -auto stack_info::get_name() const noexcept -> const std::string& -{ - return name_; -} - -auto stack_info::get_message() const noexcept -> const std::string& -{ - return message_; -} - -auto stack_info::get_stack() const noexcept -> const std::string& -{ - return stack_; -} - -auto stack_info::get_file_name() const noexcept -> const std::string& -{ - return file_name_; -} - -auto stack_info::get_line_number() const noexcept -> unsigned -{ - return line_number_; -} - -auto stack_info::what() const noexcept -> const char* -{ - return message_.c_str(); -} - -// }}} - -// {{{ error - -error::error(int type, std::string message) noexcept - : type_(type) - , message_(std::move(message)) -{ -} - -error::error(std::string message) noexcept - : message_(std::move(message)) -{ -} - -void error::create(duk_context* ctx) const -{ - duk_push_error_object(ctx, type_, "%s", message_.c_str()); -} - -// }}} - -// {{{ eval_error - -eval_error::eval_error(std::string message) noexcept - : error(DUK_ERR_EVAL_ERROR, std::move(message)) -{ -} - -// }}} - -// {{{ range_error - -range_error::range_error(std::string message) noexcept - : error(DUK_ERR_RANGE_ERROR, std::move(message)) -{ -} - -// }}} - -// {{{ reference_error - -reference_error::reference_error(std::string message) noexcept - : error(DUK_ERR_REFERENCE_ERROR, std::move(message)) -{ -} - -// }}} - -// {{{ syntax_error - -syntax_error::syntax_error(std::string message) noexcept - : error(DUK_ERR_SYNTAX_ERROR, std::move(message)) -{ -} - -// }}} - -// {{{ type_error - -type_error::type_error(std::string message) noexcept - : error(DUK_ERR_TYPE_ERROR, std::move(message)) -{ -} - -// }}} - -// {{{ uri_error - -uri_error::uri_error(std::string message) noexcept - : error(DUK_ERR_URI_ERROR, std::move(message)) -{ -} - -// }}} - -// {{{ get_stack - -auto get_stack(duk_context* ctx, int index, bool pop) -> stack_info -{ - index = duk_normalize_index(ctx, index); - - duk_get_prop_string(ctx, index, "name"); - auto name = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "message"); - auto message = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "fileName"); - auto file_name = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "lineNumber"); - auto line_number = duk_to_uint(ctx, -1); - duk_get_prop_string(ctx, index, "stack"); - auto stack = duk_to_string(ctx, -1); - duk_pop_n(ctx, 5); - - if (pop) - duk_remove(ctx, index); - - return { - std::move(name), - std::move(message), - std::move(stack), - std::move(file_name), - line_number - }; -} - -// }}} - -// {{{ type_traits<std::exception> - -void type_traits<std::exception>::raise(duk_context* ctx, const std::exception& ex) -{ - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); -} - -// }}} - -// {{{ type_traits<std::system_error> - -void type_traits<std::system_error>::raise(duk_context* ctx, const std::system_error& ex) -{ - duk_push_error_object(ctx, DUK_ERR_ERROR, ex.what()); - duk_push_int(ctx, ex.code().value()); - duk_put_prop_string(ctx, -2, "code"); - duk_push_string(ctx, ex.code().category().name()); - duk_put_prop_string(ctx, -2, "category"); - duk_throw(ctx); -} - -// }}} - -// {{{ type_traits<error> - -void type_traits<error>::raise(duk_context* ctx, const error& ex) -{ - ex.create(ctx); - duk_throw(ctx); -} - -// }}} - -// {{{ type_traits<bool> - -void type_traits<bool>::push(duk_context* ctx, bool value) -{ - duk_push_boolean(ctx, value); -} - -auto type_traits<bool>::get(duk_context* ctx, duk_idx_t index) -> bool -{ - return duk_get_boolean(ctx, index); -} - -auto type_traits<bool>::require(duk_context* ctx, duk_idx_t index) -> bool -{ - return duk_require_boolean(ctx, index); -} - -auto type_traits<bool>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<bool> -{ - return duk_is_boolean(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -// }}} - -// {{{ type_traits<duk_double_t> - -void type_traits<duk_double_t>::push(duk_context* ctx, duk_double_t value) -{ - duk_push_number(ctx, value); -} - -auto type_traits<duk_double_t>::get(duk_context* ctx, duk_idx_t index) -> duk_double_t -{ - return duk_get_number(ctx, index); -} - -auto type_traits<duk_double_t>::require(duk_context* ctx, duk_idx_t index) -> duk_double_t -{ - return duk_require_number(ctx, index); -} - -auto type_traits<duk_double_t>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_double_t> -{ - return duk_is_number(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -// }}} - -// {{{ type_traits<duk_int_t> - -void type_traits<duk_int_t>::push(duk_context* ctx, duk_int_t value) -{ - duk_push_int(ctx, value); -} - -auto type_traits<duk_int_t>::get(duk_context* ctx, duk_idx_t index) -> duk_int_t -{ - return duk_get_int(ctx, index); -} - -auto type_traits<duk_int_t>::require(duk_context* ctx, duk_idx_t index) -> duk_int_t -{ - return duk_require_int(ctx, index); -} - -auto type_traits<duk_int_t>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_int_t> -{ - return duk_is_number(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -// }}} - -// {{{ type_traits<duk_uint_t> - -void type_traits<duk_uint_t>::push(duk_context* ctx, duk_uint_t value) -{ - duk_push_uint(ctx, value); -} - -auto type_traits<duk_uint_t>::get(duk_context* ctx, duk_idx_t index) -> duk_uint_t -{ - return duk_get_uint(ctx, index); -} - -auto type_traits<duk_uint_t>::require(duk_context* ctx, duk_idx_t index) -> duk_uint_t -{ - return duk_require_uint(ctx, index); -} - -auto type_traits<duk_uint_t>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_uint_t> -{ - return duk_is_number(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -// }}} - -// {{{ type_traits<const char*> - -void type_traits<const char*>::push(duk_context* ctx, const char* value) -{ - duk_push_string(ctx, value); -} - -auto type_traits<const char*>::get(duk_context* ctx, duk_idx_t index) -> const char* -{ - return duk_get_string(ctx, index); -} - -auto type_traits<const char*>::require(duk_context* ctx, duk_idx_t index) -> const char* -{ - return duk_require_string(ctx, index); -} - -auto type_traits<const char*>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<const char*> -{ - return duk_is_string(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -// }}} - -// {{{ type_traits<std::string> - -void type_traits<std::string>::push(duk_context* ctx, const std::string& value) -{ - duk_push_lstring(ctx, value.data(), value.size()); -} - -auto type_traits<std::string>::get(duk_context* ctx, duk_idx_t index) -> std::string -{ - duk_size_t length; - const char* str = duk_get_lstring(ctx, index, &length); - - return { str, length }; -} - -auto type_traits<std::string>::require(duk_context* ctx, duk_idx_t index) -> std::string -{ - duk_size_t length; - const char* str = duk_require_lstring(ctx, index, &length); - - return { str, length }; -} - -auto type_traits<std::string>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string> -{ - return duk_is_string(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -// }}} - -// {{{ type_traits<std::string_view> - -void type_traits<std::string_view>::push(duk_context* ctx, std::string_view value) -{ - duk_push_lstring(ctx, value.data(), value.size()); -} - -auto type_traits<std::string_view>::get(duk_context* ctx, duk_idx_t index) -> std::string_view -{ - duk_size_t length; - const char* str = duk_get_lstring(ctx, index, &length); - - return { str, length }; -} - -auto type_traits<std::string_view>::require(duk_context* ctx, duk_idx_t index) -> std::string_view -{ - duk_size_t length; - const char* str = duk_require_lstring(ctx, index, &length); - - return { str, length }; -} - -auto type_traits<std::string_view>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string_view> -{ - return duk_is_string(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -// }}} - -} // !mlk::duk
--- a/libcommon-js/malikania/duk.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,988 +0,0 @@ -/* - * duk.hpp -- miscellaneous Duktape extras - * - * Copyright (c) 2017-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_DUK_HPP -#define MALIKANIA_JS_DUK_HPP - -/** - * \file duk.hpp - * \brief Miscellaneous Duktape extras - * \author David Demelier <markand@malikania.fr> - * \version 0.2.0 - */ - -#include <exception> -#include <memory> -#include <optional> -#include <string> -#include <string_view> -#include <system_error> - -#include "duktape.h" - -/** - * \brief Miscellaneous Duktape extras. - */ -namespace mlk::duk { - -// {{{ stack_guard - -/** - * \brief Stack sanity checker. - * - * Instanciate this class where you need to manipulate the Duktape stack outside - * a Duktape/C function, its destructor will examinate if the stack size matches - * the user expected size. - * - * When compiled with NDEBUG, this class does nothing. - * - * To use it, just declare an lvalue at the beginning of your function. - */ -class stack_guard { -#if !defined(NDEBUG) -private: - duk_context* context_; - unsigned expected_; - int at_start_; -#endif - -public: - /** - * Create the stack checker. - * - * No-op if NDEBUG is set. - * - * \param ctx the context - * \param expected the size expected relative to the already existing values - */ - stack_guard(duk_context* ctx, unsigned expected = 0) noexcept; - - /** - * Verify the expected size. - * - * No-op if NDEBUG is set. - */ - ~stack_guard() noexcept; -}; - -// }}} - -// {{{ context - -/** - * \brief RAII based Duktape handler. - * - * This class is implicitly convertible to duk_context for convenience. - */ -class context { -private: - std::unique_ptr<duk_context, void (*)(duk_context*)> handle_; - - context(const context&) = delete; - void operator=(const context&) = delete; - -public: - /** - * Create default context. - */ - context() noexcept; - - /** - * Default move constructor. - */ - context(context&&) noexcept = default; - - /** - * Convert the context to the native Duktape/C type. - * - * \return the duk_context - */ - operator duk_context*() noexcept; - - /** - * Convert the context to the native Duktape/C type. - * - * \return the duk_context - */ - operator duk_context*() const noexcept; - - /** - * Default move assignment operator. - * - * \return this - */ - auto operator=(context&&) noexcept -> context& = default; -}; - -// }}} - -// {{{ stack_info - -/** - * \brief Error description. - * - * This class fills the fields got in an Error object. - */ -class stack_info : public std::exception { -private: - std::string name_; - std::string message_; - std::string stack_; - std::string file_name_; - unsigned line_number_; - -public: - /** - * Construct the stack information. - * - * \param name the exception name (e.g. ReferenceError) - * \param message the error message - * \param stack the stack trace - * \param file_name the optional filename - * \param line_number the optional line number - */ - stack_info(std::string name, - std::string message, - std::string stack, - std::string file_name, - unsigned line_number = 0) noexcept; - - /** - * Get the exception name. - * - * \return the exception name (e.g. ReferenceError) - */ - auto get_name() const noexcept -> const std::string&; - - /** - * Get the error message. - * - * \return the message - */ - auto get_message() const noexcept -> const std::string&; - - /** - * Get the stack trace. - * - * \return the stack - */ - auto get_stack() const noexcept -> const std::string&; - - /** - * Get the optional file name. - * - * \return the file name - */ - auto get_file_name() const noexcept -> const std::string&; - - /** - * Get the line number. - * - * \return the line number - */ - auto get_line_number() const noexcept -> unsigned; - - /** - * Get the error message. This effectively returns message field. - * - * \return the message - */ - auto what() const noexcept -> const char* override; -}; - -// }}} - -// {{{ type_traits - -/** - * \brief Operations on different types. - * - * This class provides some functions for the given type, depending on the - * nature of the function. - * - * For example, push will call type_traits<T>::push static function - * if the type_traits is implemented for that given T type. - * - * This helps passing/getting function between Javascript and C++ code. - * - * Example: - * - * ```cpp - * push(ctx, 123); // Uses type_traits<int> - * push(ctx, true); // Uses type_traits<bool> - * ``` - * - * This class is specialized for the following types: - * - * - `bool`, - * - `duk_int_t`, - * - `duk_uint_t`, - * - `duk_double_t`, - * - `const char*`, - * - `std::string`, - * - `std::string_view`. - * - * Regarding exceptions, this class is specialized for the following types: - * - * - error, - * - std::exception, - * - std::system_error. - * - * \see push - * \see get - * \see require - * \see raise - */ -template <typename T> -struct type_traits; - -// }}} - -// {{{ push - -/** - * Generic push function. - * - * This function calls type_traits<T>::push if specialized. - * - * \param ctx the Duktape context - * \param value the forwarded value - * \return 1 for convenience - */ -template <typename T> -auto push(duk_context* ctx, T&& value) -> int -{ - using Type = typename std::decay<T>::type; - - type_traits<Type>::push(ctx, std::forward<T>(value)); - - return 1; -} - -// }}} - -// {{{ put - -/** - * Generic put function. - * - * This function calls type_traits<T>::put if specialized. - * - * The purpose of this function is to inject the argument through the value at - * the top of the stack. - * - * \param ctx the Duktape context - * \param value the forwarded value - * \return 1 for convenience - */ -template <typename T> -auto put(duk_context* ctx, T&& value) -> int -{ - using Type = typename std::decay<T>::type; - - type_traits<Type>::put(ctx, std::forward<T>(value)); - - return 1; -} - -// }}} - -// {{{ get - -/** - * Generic get function. - * - * This functions calls type_traits<T>::get if specialized. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ -template <typename T> -auto get(duk_context* ctx, duk_idx_t index) -> decltype(auto) -{ - using Type = typename std::decay<T>::type; - - return type_traits<Type>::get(ctx, index); -} - -// }}} - -// {{{ optional - -/** - * Generic optional function. - * - * This functions calls type_traits<T>::optional if specialized. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ -template <typename T> -auto optional(duk_context* ctx, duk_idx_t index) -> decltype(auto) -{ - using Type = typename std::decay<T>::type; - - return type_traits<Type>::optional(ctx, index); -} - -// }}} - -// {{{ require - -/** - * Generic require function. - * - * This functions calls type_traits<T>::require if specialized. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ -template <typename T> -auto require(duk_context* ctx, duk_idx_t index) -> decltype(auto) -{ - using Type = typename std::decay<T>::type; - - return type_traits<Type>::require(ctx, index); -} - -// }}} - -// {{{ error - -/** - * \brief Base ECMAScript error class. - * \warning Override the function create for your own exceptions - */ -class error { -private: - int type_{DUK_ERR_ERROR}; - std::string message_; - -protected: - /** - * Constructor with a type of error specified, specially designed for - * derived errors. - * - * \param type of error (e.g. DUK_ERR_ERROR) - * \param message the message - */ - error(int type, std::string message) noexcept; - -public: - /** - * Constructor with a message. - * - * \param message the message - */ - error(std::string message) noexcept; - - /** - * Virtual destructor defaulted. - */ - ~error() = default; - - /** - * Create the exception on the stack. - * - * \note the default implementation search for the global variables - * \param ctx the context - */ - void create(duk_context* ctx) const; -}; - -// }}} - -// {{{ eval_error - -/** - * \brief Error in eval() function. - */ -class eval_error : public error { -public: - /** - * Construct an EvalError. - * - * \param message the message - */ - eval_error(std::string message) noexcept; -}; - -// }}} - -// {{{ range_error - -/** - * \brief Value is out of range. - */ -class range_error : public error { -public: - /** - * Construct an RangeError. - * - * \param message the message - */ - range_error(std::string message) noexcept; -}; - -// }}} - -// {{{ reference_error - -/** - * \brief Trying to use a variable that does not exist. - */ -class reference_error : public error { -public: - /** - * Construct an ReferenceError. - * - * \param message the message - */ - reference_error(std::string message) noexcept; -}; - -// }}} - -// {{{ syntax_error - -/** - * \brief Syntax error in the script. - */ -class syntax_error : public error { -public: - /** - * Construct an SyntaxError. - * - * \param message the message - */ - syntax_error(std::string message) noexcept; -}; - -// }}} - -// {{{ type_error - -/** - * \brief Invalid type given. - */ -class type_error : public error { -public: - /** - * Construct an TypeError. - * - * \param message the message - */ - type_error(std::string message) noexcept; -}; - -// }}} - -// {{{ uri_error - -/** - * \brief URI manipulation failure. - */ -class uri_error : public error { -public: - /** - * Construct an URIError. - * - * \param message the message - */ - uri_error(std::string message) noexcept; -}; - -// }}} - -// {{{ raise - -/** - * Create an exception into the stack and throws it. - * - * This function needs the following requirements in type_traits - * - * ```cpp - * static void raise(duk_context*, Error); - * ``` - * - * Error can be any kind of value, it is forwarded. - * - * \param ctx the Duktape context - * \param error the error object - */ -template <typename Error> -void raise(duk_context* ctx, Error&& error) -{ - using type = std::decay_t<Error>; - - type_traits<type>::raise(ctx, std::forward<Error>(error)); -} - -// }}} - -// {{{ get_stack - -/** - * Get the error object when a JavaScript error has been thrown (e.g. eval - * failure). - * - * \param ctx the context - * \param index the index - * \param pop if true, also remove the exception from the stack - * \return the information - */ -auto get_stack(duk_context* ctx, int index, bool pop = true) -> stack_info; - -// }}} - -// {{{ type_traits<std::exception> - -/** - * \brief Specialization for std::exception. - */ -template <> -struct type_traits<std::exception> { - /** - * Raise a Error object. - * - * \param ctx the Duktape context - * \param ex the exception - */ - static void raise(duk_context* ctx, const std::exception& ex); -}; - -// }}} - -// {{{ type_traits<std::system_error> - -/** - * \brief Specialization for std::system_error. - */ -template <> -struct type_traits<std::system_error> { - /** - * Raise a Error object. - * - * The error object has the following properties defined in it: - * - * - code: (int) error code, - * - category: (string) error category string. - * - * \param ctx the Duktape context - * \param ex the exception - */ - static void raise(duk_context* ctx, const std::system_error& ex); -}; - -// }}} - -// {{{ type_traits<error> - -/** - * \brief Specialization for error. - */ -template <> -struct type_traits<error> { - /** - * Raise a error. - * - * \param ctx the Duktape context - * \param ex the exception - */ - static void raise(duk_context* ctx, const error& ex); -}; - -// }}} - -// {{{ type_traits<bool> - -/** - * \brief Specialization for bool. - */ -template <> -struct type_traits<bool> { - /** - * Push a boolean. - * - * Uses duk_push_boolean - * - * \param ctx the Duktape context - * \param value the value - */ - static void push(duk_context* ctx, bool value); - - /** - * Get a boolean. - * - * Uses duk_get_boolean. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto get(duk_context* ctx, duk_idx_t index) -> bool; - - /** - * Require a boolean. - * - * Uses duk_require_boolean. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto require(duk_context* ctx, duk_idx_t index) -> bool; - - /** - * Get a boolean if convertible. - * - * Uses duk_get_boolean. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<bool>; -}; - -// }}} - -// {{{ type_traits<duk_double_t> - -/** - * \brief Specialization for duk_double_t. - */ -template <> -struct type_traits<duk_double_t> { - /** - * Push a double. - * - * Uses duk_push_number - * - * \param ctx the Duktape context - * \param value the value - */ - static void push(duk_context* ctx, duk_double_t value); - - /** - * Get a double. - * - * Uses duk_get_number. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto get(duk_context* ctx, duk_idx_t index) -> duk_double_t; - - /** - * Require a double. - * - * Uses duk_require_double. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto require(duk_context* ctx, duk_idx_t index) -> duk_double_t; - - /** - * Get a double if convertible - * - * Uses duk_get_number. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_double_t>; -}; - -// }}} - -// {{{ type_traits<duk_int_t> - -/** - * \brief Specialization for duk_int_t. - */ -template <> -struct type_traits<duk_int_t> { - /** - * Push an int. - * - * Uses duk_push_int - * - * \param ctx the Duktape context - * \param value the value - */ - static void push(duk_context* ctx, duk_int_t value); - - /** - * Get an int. - * - * Uses duk_get_int. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto get(duk_context* ctx, duk_idx_t index) -> duk_int_t; - - /** - * Require an int. - * - * Uses duk_require_int. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto require(duk_context* ctx, duk_idx_t index) -> duk_int_t; - - /** - * Get an int if convertible. - * - * Uses duk_get_int. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_int_t>; -}; - -// }}} - -// {{{ type_traits<duk_uint_t> - -/** - * \brief Specialization for duk_uint_t. - */ -template <> -struct type_traits<duk_uint_t> { - /** - * Push an unsigned int. - * - * Uses duk_push_uint - * - * \param ctx the Duktape context - * \param value the value - */ - static void push(duk_context* ctx, duk_uint_t value); - - /** - * Get an unsigned int. - * - * Uses duk_get_uint. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto get(duk_context* ctx, duk_idx_t index) -> duk_uint_t; - - /** - * Require an unsigned int. - * - * Uses duk_require_uint. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto require(duk_context* ctx, duk_idx_t index) -> duk_uint_t; - - /** - * Get an unsigned int if convertible. - * - * Uses duk_get_uint. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_uint_t>; -}; - -// }}} - -// {{{ type_traits<const char*> - -/** - * \brief Specialization for C strings. - */ -template <> -struct type_traits<const char*> { - /** - * Push a C string. - * - * Uses duk_push_string - * - * \param ctx the Duktape context - * \param value the value - */ - static void push(duk_context* ctx, const char* value); - - /** - * Get a C string. - * - * Uses duk_get_string. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto get(duk_context* ctx, duk_idx_t index) -> const char*; - - /** - * Require a C string. - * - * Uses duk_require_string. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto require(duk_context* ctx, duk_idx_t index) -> const char*; - - /** - * Get a C string if convertible. - * - * Uses duk_get_string. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<const char*>; -}; - -// }}} - -// {{{ type_traits<std::string> - -/** - * \brief Specialization for C++ std::strings. - */ -template <> -struct type_traits<std::string> { - /** - * Push a C++ std::string. - * - * Uses duk_push_lstring - * - * \param ctx the Duktape context - * \param value the value - */ - static void push(duk_context* ctx, const std::string& value); - - /** - * Get a C++ std::string. - * - * Uses duk_get_lstring. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto get(duk_context* ctx, duk_idx_t index) -> std::string; - - /** - * Require a C++ std::string. - * - * Uses duk_require_lstring. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto require(duk_context* ctx, duk_idx_t index) -> std::string; - - /** - * Get a C++ std::string if convertible. - * - * Uses duk_get_lstring. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string>; -}; - -// }}} - -// {{{ type_traits<std::string_view> - -/** - * \brief Specialization for C++ std::string_views. - */ -template <> -struct type_traits<std::string_view> : public std::true_type { - /** - * Push a C++ std::string_view. - * - * Uses duk_push_lstring - * - * \param ctx the Duktape context - * \param value the value - */ - static void push(duk_context* ctx, std::string_view value); - - /** - * Get a C++ std::string_view. - * - * Uses duk_get_lstring. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto get(duk_context* ctx, duk_idx_t index) -> std::string_view; - - /** - * Require a C++ std::string_view. - * - * Uses duk_require_lstring. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto require(duk_context* ctx, duk_idx_t index) -> std::string_view; - - /** - * Get a C++ std::string_view if convertible. - * - * Uses duk_get_lstring. - * - * \param ctx the Duktape context - * \param index the value index - * \return the converted value - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string_view>; -}; - -// }}} - -} // !mlk::duk - -#endif // !MALIKANIA_JS_DUK_HPP
--- a/libcommon-js/malikania/duktape.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,342 +0,0 @@ -/* - * duktape.hpp -- Duktape extras - * - * Copyright (c) 2016-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_COMMON_DUKTAPE_HPP -#define MALIKANIA_COMMON_DUKTAPE_HPP - -/** - * \file duktape.hpp - * \brief Bring some extras to Duktape C library. - * \author David Demelier <markand@malikania.fr> - */ - -#include <cstdio> -#include <cstdlib> -#include <memory> -#include <string> -#include <unordered_map> -#include <utility> -#include <vector> - -#include <duktape.h> - -/** - * \brief Stack sanity checker. - * - * Instanciate this class where you need to manipulate the Duktape stack outside - * a Duktape/C function, its destructor will examinate if the stack size matches - * the user expected size. - * - * When compiled with NDEBUG, this class does nothing. - * - * To use it, just declare an lvalue at the beginning of your function. - */ -class dukx_stack_assert { -#if !defined(NDEBUG) -private: - duk_context* m_context; - unsigned m_expected; - int m_at_start; -#endif - -public: - /** - * Create the stack checker. - * - * No-op if NDEBUG is set. - * - * \param ctx the context - * \param expected the size expected relative to the already existing values - */ - inline dukx_stack_assert(duk_context *ctx, unsigned expected = 0) noexcept -#if !defined(NDEBUG) - : m_context(ctx) - , m_expected(expected) - , m_at_start(duk_get_top(ctx)) -#endif - { -#if defined(NDEBUG) - (void)ctx; - (void)expected; -#endif - } - - /** - * Verify the expected size. - * - * No-op if NDEBUG is set. - */ - inline ~dukx_stack_assert() noexcept - { -#if !defined(NDEBUG) - auto result = duk_get_top(m_context) - m_at_start; - - if (result != static_cast<int>(m_expected)) { - std::fprintf(stderr, "Corrupt stack detection in dukx_stack_assert:\n"); - std::fprintf(stderr, " Size at start: %d\n", m_at_start); - std::fprintf(stderr, " Size at end: %d\n", duk_get_top(m_context)); - std::fprintf(stderr, " Expected (user): %u\n", m_expected); - std::fprintf(stderr, " Expected (adjusted): %u\n", m_expected + m_at_start); - std::fprintf(stderr, " Difference count: %+d\n", result - m_expected); - std::abort(); - } -#endif - } -}; - -/** - * \brief Error description. - * - * This class fills the fields got in an Error object. - */ -class dukx_exception : public std::exception { -public: - std::string name; //!< name of error - std::string message; //!< error message - std::string stack; //!< stack if available - std::string fileName; //!< filename if applicable - int lineNumber{0}; //!< line number if applicable - - /** - * Get the error message. This effectively returns message field. - * - * \return the message - */ - const char *what() const noexcept override - { - return message.c_str(); - } -}; - -/** - * \brief RAII based Duktape handler. - * - * This class is implicitly convertible to duk_context for convenience. - */ -class dukx_context { -private: - std::unique_ptr<duk_context, void (*)(duk_context*)> m_handle; - - dukx_context(const dukx_context&) = delete; - dukx_context &operator=(const dukx_context&) = delete; - -public: - /** - * Create default context. - */ - inline dukx_context() noexcept - : m_handle(duk_create_heap_default(), duk_destroy_heap) - { - } - - /** - * Default move constructor. - */ - dukx_context(dukx_context&&) noexcept = default; - - /** - * Convert the context to the native Duktape/C type. - * - * \return the duk_context - */ - inline operator duk_context*() noexcept - { - return m_handle.get(); - } - - /** - * Convert the context to the native Duktape/C type. - * - * \return the duk_context - */ - inline operator duk_context*() const noexcept - { - return m_handle.get(); - } - - /** - * Default move assignment operator. - * - * \return this - */ - dukx_context& operator=(dukx_context&&) noexcept = delete; -}; - -/** - * Get the error object when a JavaScript error has been thrown (e.g. eval - * failure). - * - * \param ctx the context - * \param index the index - * \param pop if true, also remove the exception from the stack - * \return the information - */ -inline dukx_exception dukx_get_exception(duk_context* ctx, int index, bool pop = true) -{ - dukx_exception ex; - - index = duk_normalize_index(ctx, index); - - duk_get_prop_string(ctx, index, "name"); - ex.name = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "message"); - ex.message = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "fileName"); - ex.fileName = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "lineNumber"); - ex.lineNumber = duk_to_int(ctx, -1); - duk_get_prop_string(ctx, index, "stack"); - ex.stack = duk_to_string(ctx, -1); - duk_pop_n(ctx, 5); - - if (pop) { - duk_remove(ctx, index); - } - - return ex; -} - -/** - * Get a string, return 0 if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ -inline std::string dukx_get_std_string(duk_context* ctx, int index) -{ - duk_size_t size; - const char* text = duk_get_lstring(ctx, index, &size); - - return std::string(text, size); -} - -/** - * Require a string, throws a JavaScript exception if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ -inline std::string dukx_require_std_string(duk_context* ctx, int index) -{ - duk_size_t size; - const char* text = duk_require_lstring(ctx, index, &size); - - return std::string(text, size); -} - -/** - * Push a C++ string. - * - * \param ctx the context - * \param str the string - */ -inline void dukx_push_std_string(duk_context* ctx, const std::string& str) -{ - duk_push_lstring(ctx, str.data(), str.length()); -} - -/** - * Get an array. - * - * \param ctx the context - * \param index the array index - * \param get the conversion function (e.g. duk_get_int) - */ -template <typename Getter> -auto dukx_get_array(duk_context* ctx, duk_idx_t index, Getter&& get) -{ - using T = decltype(get(ctx, 0)); - - std::vector<T> result; - std::size_t length = duk_get_length(ctx, index); - - for (std::size_t i = 0; i < length; ++i) { - duk_get_prop_index(ctx, -1, i); - result.push_back(get(ctx, -1)); - duk_pop(ctx); - } - - return result; -} - -/** - * Push an array. - * - * \param ctx the context - * \param values the values - * \param push the function to push values - */ -template <typename T, typename Pusher> -void dukx_push_array(duk_context* ctx, const std::vector<T>& values, Pusher&& push) -{ - duk_push_array(ctx); - - int i = 0; - for (auto x : values) { - push(ctx, x); - duk_put_prop_index(ctx, -2, i++); - } -} - -/** - * Get an object. - * - * \param ctx the context - * \param index the object index - * \param get the conversion function (e.g. duk_get_int) - */ -template <typename Getter> -auto dukx_get_object(duk_context* ctx, duk_idx_t index, Getter&& get) -{ - using T = decltype(get(ctx, 0)); - - std::unordered_map<std::string, T> result; - - duk_enum(ctx, index, 0); - - while (duk_next(ctx, -1, true)) { - result.emplace(dukx_get_std_string(ctx, -2), get(ctx, -1)); - duk_pop_2(ctx); - } - - duk_pop(ctx); - - return result; -} - -/** - * Push an object. - * - * \param ctx the context - * \param values the values - * \param push the function to push values - */ -template <typename T, typename Pusher> -void dukx_push_object(duk_context* ctx, const std::unordered_map<std::string, T>& values, Pusher&& push) -{ - duk_push_object(ctx); - - for (const auto& pair : values) { - push(ctx, pair.second); - duk_put_prop_string(ctx, -2, pair.first.c_str()); - } -} - -#endif // !MALIKANIA_COMMON_DUKTAPE_HPP
--- a/libcommon-js/malikania/js_elapsed_timer.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/* - * js_elapsed_timer.cpp -- Malikania.ElapsedTimer API - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <boost/timer/timer.hpp> - -#include "js_elapsed_timer.hpp" - -namespace mlk { - -namespace { - -const std::string_view signature("\xff""\xff""Malikania.ElapsedTimer"); - -// {{{ self - -auto self(duk_context* ctx) -> boost::timer::cpu_timer* -{ - duk::stack_guard sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature.data()); - const auto ptr = static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1)); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object"); - - return ptr; -} - -// }}} - -// {{{ Irccd.ElapsedTimer.prototype.pause - -/* - * Method: ElapsedTimer.prototype.pause - * ------------------------------------------------------------------ - * - * Pause the timer, without resetting the current elapsed time stored. - */ -auto ElapsedTimer_prototype_pause(duk_context* ctx) -> duk_ret_t -{ - self(ctx)->stop(); - - return 0; -} - -// }}} - -// {{{ Irccd.ElapsedTimer.prototype.restart - -/* - * Method: Irccd.ElapsedTimer.prototype.restart - * ------------------------------------------------------------------ - * - * Restart the timer without resetting the current elapsed time. - */ -auto ElapsedTimer_prototype_restart(duk_context* ctx) -> duk_ret_t -{ - self(ctx)->resume(); - - return 0; -} - -// }}} - -// {{{ Irccd.ElapsedTimer.prototype.elapsed - -/* - * Method: ElapsedTimer.prototype.elapsed - * ------------------------------------------------------------------ - * - * Get the number of elapsed milliseconds. - * - * Returns: - * The time elapsed. - */ -auto ElapsedTimer_prototype_elapsed(duk_context* ctx) -> duk_ret_t -{ - duk_push_uint(ctx, self(ctx)->elapsed().wall / 1000000LL); - - return 1; -} - -// }}} - -// {{{ Irccd.ElapsedTimer [constructor] - -/* - * Function: Irccd.ElapsedTimer [constructor] - * ------------------------------------------------------------------ - * - * Construct a new ElapsedTimer object. - */ -auto ElapsedTimer_constructor(duk_context* ctx) -> duk_ret_t -{ - duk_push_this(ctx); - duk_push_pointer(ctx, new boost::timer::cpu_timer); - duk_put_prop_string(ctx, -2, signature.data()); - duk_pop(ctx); - - return 0; -} - -// }}} - -// {{{ Irccd.ElapsedTimer [destructor] - -/* - * Function: Irccd.ElapsedTimer [destructor] - * ------------------------------------------------------------------ - * - * Delete the property. - */ -auto ElapsedTimer_destructor(duk_context* ctx) -> duk_ret_t -{ - duk_get_prop_string(ctx, 0, signature.data()); - delete static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_del_prop_string(ctx, 0, signature.data()); - - return 0; -} - -// }}} - -// {{{ definitions - -const duk_function_list_entry methods[] = { - { "elapsed", ElapsedTimer_prototype_elapsed, 0 }, - { "pause", ElapsedTimer_prototype_pause, 0 }, - { "restart", ElapsedTimer_prototype_restart, 0 }, - { nullptr, nullptr, 0 } -}; - -// }}} - -} // !namespace - -void load_elapsed_timer_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, ElapsedTimer_constructor, 0); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_push_c_function(ctx, ElapsedTimer_destructor, 1); - duk_set_finalizer(ctx, -2); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "ElapsedTimer"); - duk_pop(ctx); -} - -} // !mlk
--- a/libcommon-js/malikania/js_elapsed_timer.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * js_elapsed_timer.hpp -- Malikania.ElapsedTimer API - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_ELAPSED_TIMER_HPP -#define MALIKANIA_JS_ELAPSED_TIMER_HPP - -/** - * \file js_elapsed_timer.hpp - * \brief Malikania.ElapsedTimer Javascript API. - */ - -#include "duk.hpp" - -namespace mlk { - -/** - * Load Malikania.ElapsedTimer API into the context. - * - * \param ctx the context - */ -void load_elapsed_timer_api(duk_context* ctx); - -} // !mlk - -#endif // !MALIKANIA_JS_ELAPSED_TIMER_HPP
--- a/libcommon-js/malikania/js_line.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * js_line.cpp -- line description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/line.hpp> - -#include "js_line.hpp" - -namespace mlk { - -namespace { - -auto Line_constructor(duk_context* ctx) -> duk_ret_t -{ - line obj; - - if (duk_get_top(ctx) == 4) - obj = line{ - duk::require<int>(ctx, 0), - duk::require<int>(ctx, 1), - duk::require<int>(ctx, 2), - duk::require<int>(ctx, 3) - }; - else if (duk_get_top(ctx) == 1) - obj = duk::require<line>(ctx, 0); - - duk_ret_t ret; - - // Allow both constructor and non constructor calls. - if (duk_is_constructor_call(ctx)) { - duk_push_this(ctx); - duk::put(ctx, obj); - duk_pop(ctx); - ret = 0; - } else { - duk::push(ctx, obj); - ret = 1; - } - - return ret; -} - -} // !namespace - -namespace duk { - -auto type_traits<line>::get(duk_context* ctx, duk_idx_t index) -> line -{ - duk::stack_guard sa(ctx); - - line ret; - - duk_get_prop_string(ctx, index, "x1"); - ret.x1 = duk::get<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y1"); - ret.y1 = duk::get<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "x2"); - ret.x2 = duk::get<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y2"); - ret.y2 = duk::get<int>(ctx, -1); - duk_pop(ctx); - - return ret; -} - -auto type_traits<line>::require(duk_context* ctx, duk_idx_t index) -> line -{ - duk::stack_guard sa(ctx); - - duk_get_prop_string(ctx, index, "x1"); - const auto x1 = duk::optional<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y1"); - const auto y1 = duk::optional<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "x2"); - const auto x2 = duk::optional<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y2"); - const auto y2 = duk::optional<int>(ctx, -1); - duk_pop(ctx); - - if (!x1) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x1' property"); - if (!y1) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y1' property"); - if (!x2) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x2' property"); - if (!y2) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y2' property"); - - return { *x1, *y1, *x2, *y2 }; -} - -auto type_traits<line>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<line> -{ - return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -void type_traits<line>::push(duk_context* ctx, const line& line) -{ - duk::stack_guard sa(ctx, 1); - - duk_push_object(ctx); - put(ctx, line); -} - -void type_traits<line>::put(duk_context* ctx, const line& line) -{ - assert(duk_is_object(ctx, -1)); - - duk::stack_guard sa(ctx); - - duk::push(ctx, line.x1); - duk_put_prop_string(ctx, -2, "x1"); - duk::push(ctx, line.y1); - duk_put_prop_string(ctx, -2, "y1"); - duk::push(ctx, line.x2); - duk_put_prop_string(ctx, -2, "x2"); - duk::push(ctx, line.y2); - duk_put_prop_string(ctx, -2, "y2"); -} - -} // !duk - -void load_line_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx, 0); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Line_constructor, DUK_VARARGS); - duk_put_prop_string(ctx, -2, "Line"); - duk_pop(ctx); -} - -} // !mlk
--- a/libcommon-js/malikania/js_line.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * js_line.hpp -- line description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_LINE_HPP -#define MALIKANIA_JS_LINE_HPP - -/** - * \file js_line.hpp - * \brief JavaScript binding for line. - * - * Lines are plain objects. - * - * ```` - * { - * x1: 10, - * y1: 10, - * x2: 50, - * y2: 50 - * } - * ```` - */ - -#include "duk.hpp" - -namespace mlk { - -struct line; - -namespace duk { - -template <> -struct type_traits<line> { - /** - * Get a line. - * - * \param ctx the context - * \param index the index - * \return the line - */ - static auto get(duk_context* ctx, duk_idx_t index) -> line; - - /** - * Require a line. - * - * If value is not an object or any property is invalid, raise a - * JavaScript error. - * - * \param ctx the context - * \param index the index - * \return the line - */ - static auto require(duk_context* ctx, duk_idx_t index) -> line; - - /** - * Like get but return def if the value at the given index is not an object. - * - * \param ctx the context - * \param index the index - * \return the line - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<line>; - - /** - * Push the line as object. - * - * \param ctx the context - * \param line the line - */ - static void push(duk_context* ctx, const line& line); - - /** - * Put the line properties into the object at the top of the stack. - * - * \param ctx the context - * \param line the line - */ - static void put(duk_context* ctx, const line& line); -}; - -} // !duk - -/** - * Load Malikania.Line API into the context. - * - * \param ctx the context - */ -void load_line_api(duk_context* ctx); - -} // !mlk - -#endif // !MALIKANIA_JS_LINE_HPP
--- a/libcommon-js/malikania/js_point.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * js_point.cpp -- point description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/point.hpp> - -#include "js_point.hpp" - -namespace mlk { - -namespace { - -auto Point_constructor(duk_context* ctx) -> duk_ret_t -{ - point obj; - - if (duk_get_top(ctx) == 2) - obj = point{ - duk::require<int>(ctx, 0), - duk::require<int>(ctx, 1) - }; - else if (duk_get_top(ctx) == 1) - obj = duk::require<point>(ctx, 0); - - duk_ret_t ret; - - // Allow both constructor and non constructor calls. - if (duk_is_constructor_call(ctx)) { - duk_push_this(ctx); - duk::put(ctx, obj); - duk_pop(ctx); - ret = 0; - } else { - duk::push(ctx, obj); - ret = 1; - } - - return ret; -} - -} // !namespace - -namespace duk { - -auto type_traits<point>::get(duk_context* ctx, duk_idx_t index) -> point -{ - duk::stack_guard sa(ctx); - - point ret; - - duk_get_prop_string(ctx, index, "x"); - ret.x = duk::get<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y"); - ret.y = duk::get<int>(ctx, -1); - duk_pop(ctx); - - return ret; -} - -auto type_traits<point>::require(duk_context* ctx, duk_idx_t index) -> point -{ - duk::stack_guard sa(ctx); - - duk_get_prop_string(ctx, index, "x"); - const auto x = duk::optional<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y"); - const auto y = duk::optional<int>(ctx, -1); - duk_pop(ctx); - - if (!x) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x' property"); - if (!y) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y' property"); - - return { *x, *y }; -} - -auto type_traits<point>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<point> -{ - return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -void type_traits<point>::push(duk_context* ctx, const point &point) -{ - duk::stack_guard sa(ctx, 1); - - duk_push_object(ctx); - put(ctx, point); -} - -void type_traits<point>::put(duk_context* ctx, const point& point) -{ - assert(duk_is_object(ctx, -1)); - - duk::stack_guard sa(ctx); - - duk::push(ctx, point.x); - duk_put_prop_string(ctx, -2, "x"); - duk::push(ctx, point.y); - duk_put_prop_string(ctx, -2, "y"); -} - -} // !duk - -void load_point_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx, 0); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Point_constructor, DUK_VARARGS); - duk_put_prop_string(ctx, -2, "Point"); - duk_pop(ctx); -} - -} // !mlk
--- a/libcommon-js/malikania/js_point.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * js_point.hpp -- point description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_POINT_HPP -#define MALIKANIA_JS_POINT_HPP - -/** - * \file js_point.hpp - * \brief JavaScript binding for line. - * - * Points are plain objects. - * - * ```` - * { - * x: 10, - * y: 10, - * } - * ```` - */ - -#include "duk.hpp" - -namespace mlk { - -struct point; - -namespace duk { - -template <> -struct type_traits<point> { - static auto require(duk_context* ctx, duk_idx_t index) -> point; - - static auto get(duk_context* ctx, duk_idx_t index) -> point; - - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<point>; - - static void push(duk_context* ctx, const point& point); - - static void put(duk_context* ctx, const point& point); -}; - -} // !duk - -/** - * Load Malikania.Point API into the context. - * - * \param ctx the context - */ -void load_point_api(duk_context* ctx); - -} // !mlk - -#endif // !MALIKANIA_JS_POINT_HPP
--- a/libcommon-js/malikania/js_rectangle.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * js_rectangle.cpp -- rectangle description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/rectangle.hpp> - -#include "js_rectangle.hpp" - -namespace mlk { - -namespace { - -auto Rectangle_constructor(duk_context* ctx) -> duk_ret_t -{ - rectangle rect; - - if (duk_get_top(ctx) == 4) { - rect = rectangle{ - duk::require<int>(ctx, 0), - duk::require<int>(ctx, 1), - duk::require<unsigned>(ctx, 2), - duk::require<unsigned>(ctx, 3) - }; - } else if (duk_get_top(ctx) == 1) - rect = duk::require<rectangle>(ctx, 0); - - duk_ret_t ret; - - // Allow both constructor and non constructor calls. - if (duk_is_constructor_call(ctx)) { - duk_push_this(ctx); - duk::put(ctx, rect); - duk_pop(ctx); - ret = 0; - } else { - duk::push(ctx, rect); - ret = 1; - } - - return ret; -} - -} // !namespace - -namespace duk { - -auto type_traits<rectangle>::get(duk_context* ctx, duk_idx_t index) -> rectangle -{ - duk::stack_guard sa(ctx); - - rectangle ret; - - if (!duk_is_object(ctx, index)) - return ret; - - duk_get_prop_string(ctx, index, "x"); - ret.x = duk::get<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y"); - ret.y = duk::get<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "width"); - ret.width = duk::get<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "height"); - ret.height = duk::get<int>(ctx, -1); - duk_pop(ctx); - - return ret; -} - -auto type_traits<rectangle>::require(duk_context* ctx, duk_idx_t index) -> rectangle -{ - duk::stack_guard sa(ctx); - - duk_get_prop_string(ctx, index, "x"); - const auto x = duk::optional<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "y"); - const auto y = duk::optional<int>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "width"); - const auto width = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "height"); - const auto height = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - - if (!x) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x' property"); - if (!y) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y' property"); - if (!width) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'width' property"); - if (!height) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'height' property"); - - return { *x, *y, *width, *height }; -} - -auto type_traits<rectangle>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<rectangle> -{ - return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt;; -} - -void type_traits<rectangle>::push(duk_context* ctx, const rectangle& rect) -{ - duk::stack_guard sa(ctx, 1); - - duk_push_object(ctx); - put(ctx, rect); -} - -void type_traits<rectangle>::put(duk_context* ctx, const rectangle& rect) -{ - assert(duk_is_object(ctx, -1)); - - duk::stack_guard sa(ctx); - - duk::push(ctx, rect.x); - duk_put_prop_string(ctx, -2, "x"); - duk::push(ctx, rect.y); - duk_put_prop_string(ctx, -2, "y"); - duk::push(ctx, rect.width); - duk_put_prop_string(ctx, -2, "width"); - duk::push(ctx, rect.height); - duk_put_prop_string(ctx, -2, "height"); -} - -} // !duk - -void load_rectangle_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx, 0); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Rectangle_constructor, DUK_VARARGS); - duk_put_prop_string(ctx, -2, "Rectangle"); - duk_pop(ctx); -} - -} // !mlk
--- a/libcommon-js/malikania/js_rectangle.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * js_rectangle.hpp -- rectangle description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_RECTANGLE_HPP -#define MALIKANIA_JS_RECTANGLE_HPP - -/** - * \file js_rectangle.hpp - * \brief JavaScript binding for rectangle. - * - * Rectangles are plain objects. - * - * ```` - * { - * x: 10, - * y: 20, - * width: 100, - * height: 200 - * } - * ```` - */ - -#include "duk.hpp" - -namespace mlk { - -struct rectangle; - -namespace duk { - -template <> -struct type_traits<rectangle> { - /** - * Get a rectangle. - * - * The rectangle may be adjusted if any values are incorrect. - * - * \param ctx the context - * \param index the value index - * \return the rectangle - */ - static auto get(duk_context* ctx, duk_idx_t index) -> rectangle; - - /** - * Require a rectangle. - * - * If the object is not a rectangle or if width, height are invalid, raise a JavaScript error. - * - * \param ctx the context - * \param index the index - * \return the rectangle - */ - static auto require(duk_context* ctx, duk_idx_t index) -> rectangle; - - /** - * Like get but return the default value if the value at the given index is not an object or invalid - * - * \param ctx the context - * \param index the idnex - * \return the rectangle - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<rectangle>; - - /** - * Push the rectangle as object. - * - * \param ctx the context - * \param rect the rectangle - */ - static void push(duk_context* ctx, const rectangle &rect); - - /** - * Put the rectangle properties into the object at the top of the stack. - * - * \param ctx the context - * \param rect the rectangle - */ - static void put(duk_context* ctx, const rectangle& rect); -}; - -} // !duk - -/** - * Load Malikania.Rectangle API into the context. - * - * \param ctx the context - */ -void load_rectangle_api(duk_context* ctx); - -} // !mlk - -#endif // !MALIKANIA_JS_RECTANGLE_HPP
--- a/libcommon-js/malikania/js_resources_loader.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * js_resources_loader.cpp -- resources loader (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/loader.hpp> - -#include "js_resources_loader.hpp" - -namespace mlk::duk { - -namespace { - -const std::string_view variable("\xff""\xff""Malikania.Loader"); - -} // !namespace - -void type_traits<loader>::put(duk_context *ctx, loader& loader) -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_push_pointer(ctx, &loader); - duk_put_global_string(ctx, variable.data()); -} - -auto type_traits<loader>::require(duk_context* ctx, duk_idx_t) -> loader& -{ - assert(ctx); - - duk::stack_guard sa(ctx); - - duk_get_global_string(ctx, variable.data()); - auto ptr = static_cast<loader*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return *static_cast<loader*>(ptr); -} - -} // !mlk::duk
--- a/libcommon-js/malikania/js_resources_loader.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * js_resources_loader.hpp -- resources loader (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_RESOURCES_LOADER_H -#define MALIKANIA_JS_RESOURCES_LOADER_H - -#include "duk.hpp" - -namespace mlk { - -class loader; - -namespace duk { - -template <> -struct type_traits<loader> { - static void put(duk_context* ctx, loader& loader); - - static auto require(duk_context* ctx, duk_idx_t index) -> loader&; -}; - -} // !duk - -} // !mlk - -#endif // !MALIKANIA_JS_RESOURCES_LOADER_H
--- a/libcommon-js/malikania/js_size.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * js_size.cpp -- size description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include <malikania/size.hpp> - -#include "js_size.hpp" - -namespace mlk { - -namespace { - -auto Size_constructor(duk_context* ctx) -> duk_ret_t -{ - size obj; - - if (duk_get_top(ctx) == 2) { - obj = size{ - duk::require<unsigned>(ctx, 0), - duk::require<unsigned>(ctx, 1) - }; - } else if (duk_get_top(ctx) == 1) - obj = duk::require<size>(ctx, 0); - - duk_ret_t ret; - - // Allow both constructor and non constructor calls. - if (duk_is_constructor_call(ctx)) { - duk_push_this(ctx); - duk::put(ctx, obj); - duk_pop(ctx); - ret = 0; - } else { - duk::push(ctx, obj); - ret = 1; - } - - return ret; -} - -} // !namespace - -namespace duk { - -auto type_traits<size>::get(duk_context* ctx, duk_idx_t index) -> size -{ - duk::stack_guard sa(ctx); - - size ret; - - duk_get_prop_string(ctx, index, "width"); - ret.width = duk::get<unsigned>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "height"); - ret.height = duk::get<unsigned>(ctx, -1); - duk_pop(ctx); - - return ret; -} - -auto type_traits<size>::require(duk_context* ctx, duk_idx_t index) -> size -{ - duk::stack_guard sa(ctx); - - duk_get_prop_string(ctx, index, "width"); - const auto width = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, index, "height"); - const auto height = duk::optional<unsigned>(ctx, -1); - duk_pop(ctx); - - if (!width) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'width' property"); - if (!height) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'height' property"); - - return { *width, *height }; -} - -auto type_traits<size>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<size> -{ - return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; -} - -void type_traits<size>::push(duk_context* ctx, const size& size) -{ - duk::stack_guard sa(ctx, 1); - - duk_push_object(ctx); - put(ctx, size); -} - -void type_traits<size>::put(duk_context* ctx, const size& size) -{ - assert(duk_is_object(ctx, -1)); - - duk::stack_guard sa(ctx, 0); - - duk::push(ctx, size.width); - duk_put_prop_string(ctx, -2, "width"); - duk::push(ctx, size.height); - duk_put_prop_string(ctx, -2, "height"); -} - -} // !duk - -void load_size_api(duk_context* ctx) -{ - duk::stack_guard sa(ctx, 0); - - duk_get_global_string(ctx, "Malikania"); - duk_push_c_function(ctx, Size_constructor, DUK_VARARGS); - duk_put_prop_string(ctx, -2, "Size"); - duk_pop(ctx); -} - -} // !mlk
--- a/libcommon-js/malikania/js_size.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * js_size.hpp -- size description (JavaScript binding) - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_JS_SIZE_HPP -#define MALIKANIA_JS_SIZE_HPP - -/** - * \file js_size.hpp - * \brief JavaScript binding for size. - * - * Sizes are plain objects. - * - * ```` - * { - * width: 1000, - * height: 2000 - * } - * ```` - */ - -#include "duk.hpp" - -namespace mlk { - -struct size; - -namespace duk { - -template <> -struct type_traits<size> { - /** - * Get a size. - * - * The size may be adjusted if any values are incorrect. - * - * \param ctx the context - * \param index the value index - * \return the size - */ - static auto get(duk_context* ctx, duk_idx_t index) -> size; - - /** - * Require a size - * - * If the object is not a size, raise a JavaScript error. - * - * \param ctx the context - * \param index the index - * \return the size - */ - static auto require(duk_context* ctx, duk_idx_t index) -> size; - - /** - * \param ctx the context - * \param index the idnex - * \param def the default value - * \return the size - */ - static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<size>; - - /** - * Push the size as object. - * - * \param ctx the context - * \param size the size - */ - static void push(duk_context* ctx, const size& size); - - /** - * Put the size properties into the object at the top of the stack. - * - * \param ctx the context - * \param size the size - */ - static void put(duk_context* ctx, const size& size); -}; - -} // !duk - -/** - * Load Malikania.Size API into the context. - * - * \param ctx the context - */ -void load_size_api(duk_context* ctx); - -} // !mlk - -#endif // !MALIKANIA_JS_SIZE_HPP
--- a/libcommon/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -# -# CMakeLists.txt -- CMake build system for malikania -# -# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(libmlk-common) - -find_package(Boost REQUIRED filesystem system) -find_package(OpenSSL REQUIRED) - -set( - HEADERS - ${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.hpp - ${libmlk-common_SOURCE_DIR}/malikania/error/error.hpp - ${libmlk-common_SOURCE_DIR}/malikania/game.hpp - ${libmlk-common_SOURCE_DIR}/malikania/line.hpp - ${libmlk-common_SOURCE_DIR}/malikania/loader.hpp - ${libmlk-common_SOURCE_DIR}/malikania/locator.hpp - ${libmlk-common_SOURCE_DIR}/malikania/point.hpp - ${libmlk-common_SOURCE_DIR}/malikania/rectangle.hpp - ${libmlk-common_SOURCE_DIR}/malikania/size.hpp - ${libmlk-common_SOURCE_DIR}/malikania/socket.hpp - ${libmlk-common_SOURCE_DIR}/malikania/tileset.hpp - ${libmlk-common_SOURCE_DIR}/malikania/unicode.hpp - ${libmlk-common_SOURCE_DIR}/malikania/util.hpp -) - -set( - SOURCES - ${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.cpp - ${libmlk-common_SOURCE_DIR}/malikania/loader.cpp - ${libmlk-common_SOURCE_DIR}/malikania/locator.cpp - ${libmlk-common_SOURCE_DIR}/malikania/socket.cpp - ${libmlk-common_SOURCE_DIR}/malikania/unicode.cpp - ${libmlk-common_SOURCE_DIR}/malikania/util.cpp -) - -malikania_define_library( - PROJECT libmlk-common - TARGET libmlk-common - SOURCES ${HEADERS} ${SOURCES} - PUBLIC_INCLUDES - ${INCLUDES} - $<BUILD_INTERFACE:${libmlk-common_SOURCE_DIR}/malikania> - $<BUILD_INTERFACE:${libmlk-common_SOURCE_DIR}> - LIBRARIES - Boost::boost - Boost::filesystem - Boost::system - OpenSSL::Crypto - OpenSSL::SSL - json - ${LIBRARIES} -)
--- a/libcommon/malikania/error/auth_error.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * auth_error.hpp -- auth command error - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "auth_error.hpp" - -namespace mlk { - -auto auth_error::error_category() -> std::string -{ - return "auth"; -} - -auto auth_error::error_message(error code) -> std::string -{ - switch (code) { - case invalid_credentials: - return "invalid credentials"; - case already_connected: - return "already connected"; - default: - return "no error"; - } -} - -} // !mlk
--- a/libcommon/malikania/error/auth_error.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * auth_error.hpp -- auth command error - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_AUTH_ERROR_HPP -#define MALIKANIA_AUTH_ERROR_HPP - -/** - * \file auth_error.hpp - * \brief Auth command error. - */ - -#include "error.hpp" - -namespace mlk { - -/** - * \brief Auth command error. - */ -struct auth_error { - /** - * \brief Error description - */ - enum error { - /** - * \brief No error. - */ - no_error = 0, - - /** - * \brief Invalid password or login. - */ - invalid_credentials, - - /** - * \brief User is already connected. - */ - already_connected - }; - - static auto error_category() -> std::string; - - /** - * Convert the code to a human message. - * - * \param code the code - */ - static auto error_message(error code) -> std::string; -}; - -} // !mlk - -MALIKANIA_ERROR_CODE( - mlk::auth_error::error, - mlk::auth_error::error_category, - mlk::auth_error::error_message -) - -#endif // !MALIKANIA_AUTH_ERROR_HPP
--- a/libcommon/malikania/error/error.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * error.hpp -- error code creation - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_ERROR_HPP -#define MALIKANIA_ERROR_HPP - -/** - * \file error.hpp - * \brief Error code creation. - */ - -#include <string> -#include <system_error> -#include <type_traits> - -/** - * Generate a custom std::error_code with the given type. The macro must be - * called outside mlk namespace. - * - * See the following example. - * - * ```cpp - * namespace mlk { - * - * class foo { - * public: - * enum class error { - * no_error = 0, - * error_kind_foo, - * error_kind_bar - * }; - * - * static auto error_category() -> std::string - * { - * return "sometext"; - * } - * - * static auto error_message(error code) -> std::string - * { - * // convert code to a string. - * } - * }; - * - * } // !mlk - * - * MALIKANIA_ERROR_CODE( - * my_error::error, - * my_error::error_category, - * my_error::error_message - * ) - * ``` - */ -#define MALIKANIA_ERROR_CODE(Enum, Category, Message) \ -namespace std { \ - \ -template <> \ -struct is_error_code_enum<Enum> : public std::true_type { \ -}; \ - \ -} \ - \ -namespace mlk { \ - \ -inline auto make_error_code(Enum code) noexcept -> std::error_code \ -{ \ - static const class : public std::error_category { \ - public: \ - auto name() const noexcept -> const char* override \ - { \ - return Category().c_str(); \ - } \ - \ - auto message(int e) const -> std::string override \ - { \ - return Message(static_cast<Enum>(e)); \ - } \ - } category; \ - \ - return { static_cast<int>(code), category }; \ -} \ - \ -} - -#endif // !MALIKANIA_ERROR_HPP
--- a/libcommon/malikania/game.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * game.hpp -- basic game class - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_GAME_HPP -#define MALIKANIA_GAME_HPP - -/** - * \file game.hpp - * \brief Game description. - */ - -#include <string> - -namespace mlk { - -/** - * \brief Basic game description. - */ -struct game { - std::string name; - std::string version; - std::string requires; - std::string license; - std::string author; -}; - -} // !mlk - -#endif // !MALIKANIA_GAME_HPP
--- a/libcommon/malikania/line.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * line.hpp -- line description - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_LINE_HPP -#define MALIKANIA_LINE_HPP - -/** - * \file line.hpp - * \brief line description. - */ - -namespace mlk { - -/** - * \brief line description. - * - * A line has an origin (x, y) and a destination (x, y). - */ -struct line { - int x1{0}; - int y1{0}; - int x2{0}; - int y2{0}; -}; - -/** - * Compare equality. - * - * \param l1 the first line - * \param l2 the second line - * \return true if they equal - */ -inline auto operator==(const line& l1, const line& l2) noexcept -> bool -{ - return l1.x1 == l2.x1 && l1.x2 == l2.x2 && - l1.y1 == l2.y1 && l1.y2 == l2.y2; -} - -/** - * Compare equality. - * - * \param l1 the first line - * \param l2 the second line - * \return false if they equal - */ -inline auto operator!=(const line& l1, const line& l2) noexcept -> bool -{ - return !(l1 == l2); -} - -} // !mlk - -#endif // !MALIKANIA_LINE_HPP
--- a/libcommon/malikania/loader.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * loader.cpp -- load shared resources files - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "game.hpp" -#include "loader.hpp" -#include "locator.hpp" -#include "tileset.hpp" -#include "util.hpp" - -namespace mlk { - -namespace { - -auto load_tileset_tile_properties(const nlohmann::json& json) -> tileset::properties_map -{ - auto it = json.find("properties"); - - if (it == json.end()) - return {}; - - tileset::properties_map props; - - for (auto pair = it->begin(); pair != it->end(); ++pair) { - // TODO: maxi convert - if (!pair->is_string()) - continue; - - props.emplace(pair.key(), pair->get<std::string>()); - } - - return props; -} - -auto load_tileset_tiles_properties(const nlohmann::json& json) -> tileset::tile_properties_map -{ - auto tiles = json.find("tiles"); - - if (tiles == json.end()) - return {}; - - tileset::tile_properties_map props; - - for (auto it = tiles->begin(); it != tiles->end(); ++it) - props.emplace(std::stoi(it.key()), load_tileset_tile_properties(*it)); - - return props; -} - -} // !namespace - -loader::loader(mlk::locator& locator) - : locator_(locator) -{ -} - -auto loader::get_locator() noexcept -> locator& -{ - return locator_; -} - -auto loader::load_game() const -> game -{ - auto value = nlohmann::json::parse(locator_.read("game.json")); - - if (!value.is_object()) - throw std::runtime_error("game.json: not a JSON object"); - - return game{ - util::json::require_string(value, "/name"_json_pointer), - util::json::require_string(value, "/version"_json_pointer), - util::json::require_string(value, "/requires"_json_pointer), - value.count("license") > 0 ? value["license"] : "", - value.count("author") > 0 ? value["author"] : "" - }; -} - -auto loader::load_tileset(std::string_view id) const -> tileset -{ - auto value = nlohmann::json::parse(locator_.read(id)); - - if (!value.is_object()) - throw std::runtime_error("not a valid tileset"); - - tileset tileset; - - tileset.image = util::json::require_string(value, "/image"_json_pointer); - tileset.cell = util::json::require_size(value, "/cell"_json_pointer); - tileset.tile_properties = load_tileset_tiles_properties(value); - - return tileset; -} - -} // !mlk
--- a/libcommon/malikania/loader.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * loader.hpp -- load shared resources files - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_LOADER_HPP -#define MALIKANIA_LOADER_HPP - -#include <string> - -namespace mlk { - -struct game; -struct tileset; - -class locator; - -/** - * \brief Open resources files using a locator. - * - * This class is used to load resources files that are common to the server and - * the client. - * - * \see client_loader - */ -class loader { -private: - locator& locator_; - -public: - /** - * Construct the resources loader. - * - * \param locator the locator - */ - loader(locator& locator); - - /** - * Virtual destructor defaulted. - */ - virtual ~loader() noexcept = default; - - /** - * Get the underlying locator. - * - * \return the locator - */ - auto get_locator() noexcept -> locator&; - - /** - * Load a game. - * - * \return the game - * \throw std::runtime_error on errors - */ - virtual auto load_game() const -> game; - - /** - * Load a tileset. - * - * \param id the tileset id - * \return a tileset ready to use - * \throw std::runtime_error on errors - */ - virtual auto load_tileset(std::string_view id) const -> tileset; -}; - -} // !mlk - -#endif // !MALIKANIA_LOADER_HPP
--- a/libcommon/malikania/locator.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * locator.cpp -- file and stream loader - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cerrno> -#include <cstring> -#include <fstream> -#include <iterator> -#include <sstream> -#include <stdexcept> - -#include "locator.hpp" - -namespace mlk { - -auto directory_locator::make_path(std::string_view id) -> std::string -{ - std::ostringstream oss; - - oss << path_; - oss << "/"; - oss << id; - - return oss.str(); -} - -directory_locator::directory_locator(std::string path) noexcept - : path_(std::move(path)) -{ -} - -auto directory_locator::read(std::string_view id) -> std::string -{ - std::ifstream in(make_path(id), std::ifstream::in | std::ifstream::binary); - - if (!in) - throw std::runtime_error(std::strerror(errno)); - - return std::string( - std::istreambuf_iterator<char>(in.rdbuf()), - std::istreambuf_iterator<char>() - ); -} - -auto directory_locator::open(std::string_view id) -> std::unique_ptr<std::istream> -{ - auto ptr = std::make_unique<std::ifstream>(make_path(id)); - - if (!(*ptr)) - throw std::runtime_error(std::strerror(errno)); - - return std::move(ptr); -} - -} // !mlk
--- a/libcommon/malikania/locator.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * locator.hpp -- file and stream loader - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_LOCATOR_HPP -#define MALIKANIA_LOCATOR_HPP - -#include <istream> -#include <memory> -#include <string> -#include <string_view> - -namespace mlk { - -/** - * \brief Abstract assets locator. - */ -class locator { -public: - /** - * Default destructor. - */ - virtual ~locator() = default; - - /** - * Read a whole resource as a string. - * - * \param id the resource id - * \return the string - * \throw std::runtime_error on any errors - */ - virtual auto read(std::string_view id) -> std::string = 0; - - /** - * Open a resource as a stream. - * - * \param id the resource id - * \return the stream - * \throw std::runtime_error on any errors - */ - virtual auto open(std::string_view id) -> std::unique_ptr<std::istream> = 0; -}; - -/** - * \brief Load a game from a directory. - */ -class directory_locator : public locator { -private: - std::string path_; - - auto make_path(std::string_view) -> std::string; - -public: - /** - * Load the game from the directory. - * - * \param path the base directory - */ - directory_locator(std::string path) noexcept; - - /** - * \copydoc locator::read - */ - auto read(std::string_view id) -> std::string override; - - /** - * \copydoc locator::open - */ - auto open(std::string_view id) -> std::unique_ptr<std::istream> override; -}; - -} // !mlk - -#endif // !MALIKANIA_LOCATOR_HPP
--- a/libcommon/malikania/point.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * point.hpp -- point description - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_POINT_HPP -#define MALIKANIA_POINT_HPP - -/** - * \file point.hpp - * \brief point description. - */ - -namespace mlk { - -/** - * \brief point coordinate. - */ -struct point { - int x{0}; - int y{0}; -}; - -/** - * Compare equality. - * - * \param p1 the first point - * \param p2 the second point - * \return true if they equal - */ -inline auto operator==(const point& p1, const point& p2) noexcept -> bool -{ - return p1.x == p2.x && p1.y == p2.y; -} - -/** - * Compare equality. - * - * \param p1 the first point - * \param p2 the second point - * \return false if they equal - */ -inline auto operator!=(const point& p1, const point& p2) noexcept -> bool -{ - return !(p1 == p2); -} - -} // !mlk - -#endif // !MALIKANIA_POINT_HPP
--- a/libcommon/malikania/rectangle.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * rectangle.hpp -- rectangle description - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_RECTANGLE_HPP -#define MALIKANIA_RECTANGLE_HPP - -/** - * \file rectangle.hpp - * \brief rectangle description. - */ - -namespace mlk { - -/** - * \brief rectangle description. - * - * A rectangle has coordinates (x, y) and dimensions (width, height). - * - * They are commonly used for clipping images into the window. - */ -struct rectangle { - int x{0}; //!< x coordinate - int y{0}; //!< y coordinate - unsigned width{0}; //!< width - unsigned height{0}; //!< height - - /** - * Check if the rectangle has null dimensions. - * - * \return true if weight and height are 0 - */ - inline auto is_null() const noexcept -> bool - { - return width == 0 && height == 0; - } -}; - -/** - * Compare equality. - * - * \param r1 the first rectangle - * \param r2 the second rectangle - * \return true if they equal - */ -inline auto operator==(const rectangle& r1, const rectangle& r2) noexcept -> bool -{ - return r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height == r2.height; -} - -/** - * Compare equality. - * - * \param r1 the first rectangle - * \param r2 the second rectangle - * \return false if they equal - */ -inline auto operator!=(const rectangle& r1, const rectangle& r2) noexcept -> bool -{ - return !(r1 == r2); -} - -} // !mlk - -#endif // !MALIKANIA_RECTANGLE_HPP
--- a/libcommon/malikania/size.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * size.hpp -- size description - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_SIZE_HPP -#define MALIKANIA_SIZE_HPP - -#include <ostream> - -namespace mlk { - -/** - * \brief size description. - */ -struct size { - /** - * \brief Width. - */ - unsigned width{0}; - - /** - * \brief Height. - */ - unsigned height{0}; - - /** - * Check if the size is 0, 0. - * - * \return true if height and width are 0 - */ - inline auto is_null() const noexcept -> bool - { - return height == 0 && width == 0; - } -}; - -/** - * Compare equality. - * - * \param s1 the first size - * \param s2 the second size - * \return true if they equal - */ -inline auto operator==(const size& s1, const size& s2) noexcept -> bool -{ - return s1.width == s2.width && s1.height == s2.height; -} - -/** - * Compare equality. - * - * \param s1 the first size - * \param s2 the second size - * \return false if they equal - */ -inline auto operator!=(const size& s1, const size& s2) noexcept -> bool -{ - return !(s1 == s2); -} - -/** - * Prints the size object. - * - * \param out the output - * \param size the size object - * \return out - */ -inline auto operator<<(std::ostream& out, const size& size) -> std::ostream& -{ - out << "{" << size.width << ", " << size.height << "}"; - - return out; -} - -} // !mlk - -#endif // !MALIKANIA_SIZE_HPP
--- a/libcommon/malikania/socket.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * socket.cpp -- SSL socket using JSON messages - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include "socket.hpp" - -namespace mlk { - -void socket::do_recv(recv_handler handler) -{ - boost::asio::async_read_until(socket_, rbuffer_, "\r\n\r\n", [this, handler] (auto code, auto xfer) { - if (code) - handler(std::move(code), nullptr); - else if (xfer == 0U) - handler(make_error_code(boost::system::errc::network_down), nullptr); - else { - std::string str( - boost::asio::buffers_begin(rbuffer_.data()), - boost::asio::buffers_begin(rbuffer_.data()) + xfer - 4 - ); - - // Remove early in case of errors. - rbuffer_.consume(xfer); - - // TODO: catch nlohmann::json::parse_error when 3.0.0 is released. - nlohmann::json message; - - try { - message = nlohmann::json::parse(str); - } catch (...) {} - - if (!message.is_object()) - handler(make_error_code(boost::system::errc::invalid_argument), nullptr); - else - handler(code, std::move(message)); - } - }); -} - -void socket::do_send(const std::string& str, send_handler handler) -{ - boost::asio::async_write(socket_, boost::asio::buffer(str), [handler] (auto code, auto xfer) { - if (xfer == 0U) - handler(make_error_code(boost::system::errc::network_down)); - else - handler(code); - }); -} - -socket::socket(boost::asio::io_service& service, - boost::asio::ssl::context& ctx) - : socket_(service, ctx) -{ -} - -auto socket::get_socket() const noexcept -> const socket_t& -{ - return socket_; -} - -auto socket::get_socket() noexcept -> socket_t& -{ - return socket_; -} - -auto socket::is_receiving() const noexcept -> bool -{ - return !rqueue_.empty(); -} - -auto socket::is_sending() const noexcept -> bool -{ - return !squeue_.empty(); -} - -auto socket::is_active() const noexcept -> bool -{ - return is_receiving() || is_sending(); -} - -void socket::rflush() -{ - if (rqueue_.empty()) - return; - - do_recv([this] (auto code, auto json) { - auto handler = rqueue_.front(); - - rqueue_.pop_front(); - handler(code, std::move(json)); - - if (!code) - rflush(); - }); -} - -void socket::sflush() -{ - if (squeue_.empty()) - return; - - do_send(squeue_.front().first, [this] (auto code) { - auto handler = squeue_.front().second; - - squeue_.pop_front(); - - if (handler) - handler(code); - if (!code) - sflush(); - }); -} - -void socket::recv(recv_handler handler) -{ - assert(handler); - - auto in_progress = !rqueue_.empty(); - - rqueue_.push_back(std::move(handler)); - - if (!in_progress) - rflush(); -} - -void socket::send(nlohmann::json json, send_handler handler) -{ - assert(json.is_object()); - - auto in_progress = !squeue_.empty(); - - squeue_.emplace_back(json.dump(0) + "\r\n\r\n", std::move(handler)); - - if (!in_progress) - sflush(); -} - -} // !mlk
--- a/libcommon/malikania/socket.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * socket.hpp -- SSL socket using JSON messages - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_COMMON_SOCKET_HPP -#define MALIKANIA_COMMON_SOCKET_HPP - -/** - * \file socket.hpp - * \brief SSL socket using JSON messages - */ - -#include "sysconfig.hpp" - -#include <deque> -#include <functional> -#include <string> -#include <system_error> -#include <utility> - -#include <boost/asio.hpp> -#include <boost/asio/ssl.hpp> - -#include <json.hpp> - -namespace mlk { - -/** - * \brief SSL socket using JSON messages - * - * This class can be used to perform I/O over a networking socket, it is - * implemented as asynchronous operations over Boost.Asio. - * - * All recv/send operations are placed in a queue and performed when possible. - */ -class socket { -public: - /** - * Read handler. - * - * Call this function when a receive operation has finished on success or - * failure. - */ - using recv_handler = std::function<void (std::error_code, nlohmann::json)>; - - /** - * Send handler. - * - * Call this function when a send operation has finished on success or failure. - */ - using send_handler = std::function<void (std::error_code)>; - -private: - using socket_t = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>; - using rbuffer_t = boost::asio::streambuf; - using rqueue_t = std::deque<recv_handler>; - using squeue_t = std::deque<std::pair<std::string, send_handler>>; - - socket_t socket_; - rbuffer_t rbuffer_; - rqueue_t rqueue_; - squeue_t squeue_; - - void rflush(); - void sflush(); - void do_recv(recv_handler); - void do_send(const std::string&, send_handler); - -public: - /** - * Construct the socket. - * - * \param service the IO service - * \param ctx the SSL context - */ - socket(boost::asio::io_service& service, - boost::asio::ssl::context& ctx); - - /** - * Get the underlying socket. - * - * \return the socket - */ - auto get_socket() const noexcept -> const socket_t&; - - /** - * Overloaded function. - * - * \return the socket - */ - auto get_socket() noexcept -> socket_t&; - - /** - * Tells if receive operations are pending. - * - * \return true if receiving is in progress - */ - auto is_receiving() const noexcept -> bool; - - /** - * Tells if send operations are pending. - * - * \return true if sending is in progress - */ - auto is_sending() const noexcept -> bool; - - /** - * Tells if there are any I/O pending. - * - * \return true if sending is in progress - */ - auto is_active() const noexcept -> bool; - - /** - * Request a receive operation. - * - * \pre handler != nullptr - * \param handler the handler - */ - void recv(recv_handler); - - /** - * Request a send operation. - * - * \pre json.is_object() - * \param json the json message - * \param handler the optional handler - */ - void send(nlohmann::json json, send_handler = nullptr); -}; - -} // !mlk - -#endif // MALIKANIA_COMMON_SOCKET_HPP
--- a/libcommon/malikania/tileset.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * tileset.hpp -- map tileset definition - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_COMMON_TILESET_HPP -#define MALIKANIA_COMMON_TILESET_HPP - -/** - * \file tileset.hpp - * \brief Map tileset definition. - */ - -#include <boost/variant.hpp> - -#include <string> -#include <unordered_map> - -#include "size.hpp" - -namespace mlk { - -/** - * \brief Map tileset definition. - */ -struct tileset { - /** - * Map of general properties. - */ - using properties_map = std::unordered_map<std::string, std::string>; - - /** - * Per tile properties. - */ - using tile_properties_map = std::unordered_map<int, properties_map>; - - std::string image; - size cell; - properties_map properties; - tile_properties_map tile_properties; -}; - -} // !mlk - -#endif // !MALIKANIA_COMMON_TILESET_HPP
--- a/libcommon/malikania/unicode.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4796 +0,0 @@ -/* - * unicode.cpp -- UTF-8 to UTF-32 conversions and various operations - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "unicode.hpp" - -/* - * The following code has been generated from Go mkrunetype adapted to our - * needs. - */ - -namespace mlk { - -namespace unicode { - -#define nelem(x) (sizeof (x) / sizeof ((x)[0])) - -namespace { - -const char32_t *rbsearch(char32_t c, const char32_t* t, int n, int ne) noexcept -{ - const char32_t* p; - int m; - - while (n > 1) { - m = n >> 1; - p = t + m * ne; - - if (c >= p[0]) { - t = p; - n = n - m; - } else - n = m; - } - - if (n && c >= t[0]) - return t; - - return nullptr; -} - -} // !namespace - -namespace { - -const char32_t isspacer[] = { - 0x0009, 0x000d, - 0x0020, 0x0020, - 0x0085, 0x0085, - 0x00a0, 0x00a0, - 0x1680, 0x1680, - 0x2000, 0x200a, - 0x2028, 0x2029, - 0x202f, 0x202f, - 0x205f, 0x205f, - 0x3000, 0x3000, - 0xfeff, 0xfeff, -}; - -} // !namespace - -bool isspace(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, isspacer, nelem (isspacer) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - return false; -} - -namespace { - -const char32_t isdigitr[] = { - 0x0030, 0x0039, - 0x0660, 0x0669, - 0x06f0, 0x06f9, - 0x07c0, 0x07c9, - 0x0966, 0x096f, - 0x09e6, 0x09ef, - 0x0a66, 0x0a6f, - 0x0ae6, 0x0aef, - 0x0b66, 0x0b6f, - 0x0be6, 0x0bef, - 0x0c66, 0x0c6f, - 0x0ce6, 0x0cef, - 0x0d66, 0x0d6f, - 0x0de6, 0x0def, - 0x0e50, 0x0e59, - 0x0ed0, 0x0ed9, - 0x0f20, 0x0f29, - 0x1040, 0x1049, - 0x1090, 0x1099, - 0x17e0, 0x17e9, - 0x1810, 0x1819, - 0x1946, 0x194f, - 0x19d0, 0x19d9, - 0x1a80, 0x1a89, - 0x1a90, 0x1a99, - 0x1b50, 0x1b59, - 0x1bb0, 0x1bb9, - 0x1c40, 0x1c49, - 0x1c50, 0x1c59, - 0xa620, 0xa629, - 0xa8d0, 0xa8d9, - 0xa900, 0xa909, - 0xa9d0, 0xa9d9, - 0xa9f0, 0xa9f9, - 0xaa50, 0xaa59, - 0xabf0, 0xabf9, - 0xff10, 0xff19, - 0x104a0, 0x104a9, - 0x11066, 0x1106f, - 0x110f0, 0x110f9, - 0x11136, 0x1113f, - 0x111d0, 0x111d9, - 0x112f0, 0x112f9, - 0x114d0, 0x114d9, - 0x11650, 0x11659, - 0x116c0, 0x116c9, - 0x118e0, 0x118e9, - 0x16a60, 0x16a69, - 0x16b50, 0x16b59, - 0x1d7ce, 0x1d7ff, -}; - -} // !namespace - -bool isdigit(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, isdigitr, nelem (isdigitr) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - return false; -} - -namespace { - -const char32_t isalphar[] = { - 0x0041, 0x005a, - 0x0061, 0x007a, - 0x00c0, 0x00d6, - 0x00d8, 0x00f6, - 0x00f8, 0x02c1, - 0x02c6, 0x02d1, - 0x02e0, 0x02e4, - 0x0370, 0x0374, - 0x0376, 0x0377, - 0x037a, 0x037d, - 0x0388, 0x038a, - 0x038e, 0x03a1, - 0x03a3, 0x03f5, - 0x03f7, 0x0481, - 0x048a, 0x052f, - 0x0531, 0x0556, - 0x0561, 0x0587, - 0x05d0, 0x05ea, - 0x05f0, 0x05f2, - 0x0620, 0x064a, - 0x066e, 0x066f, - 0x0671, 0x06d3, - 0x06e5, 0x06e6, - 0x06ee, 0x06ef, - 0x06fa, 0x06fc, - 0x0712, 0x072f, - 0x074d, 0x07a5, - 0x07ca, 0x07ea, - 0x07f4, 0x07f5, - 0x0800, 0x0815, - 0x0840, 0x0858, - 0x08a0, 0x08b2, - 0x0904, 0x0939, - 0x0958, 0x0961, - 0x0971, 0x0980, - 0x0985, 0x098c, - 0x098f, 0x0990, - 0x0993, 0x09a8, - 0x09aa, 0x09b0, - 0x09b6, 0x09b9, - 0x09dc, 0x09dd, - 0x09df, 0x09e1, - 0x09f0, 0x09f1, - 0x0a05, 0x0a0a, - 0x0a0f, 0x0a10, - 0x0a13, 0x0a28, - 0x0a2a, 0x0a30, - 0x0a32, 0x0a33, - 0x0a35, 0x0a36, - 0x0a38, 0x0a39, - 0x0a59, 0x0a5c, - 0x0a72, 0x0a74, - 0x0a85, 0x0a8d, - 0x0a8f, 0x0a91, - 0x0a93, 0x0aa8, - 0x0aaa, 0x0ab0, - 0x0ab2, 0x0ab3, - 0x0ab5, 0x0ab9, - 0x0ae0, 0x0ae1, - 0x0b05, 0x0b0c, - 0x0b0f, 0x0b10, - 0x0b13, 0x0b28, - 0x0b2a, 0x0b30, - 0x0b32, 0x0b33, - 0x0b35, 0x0b39, - 0x0b5c, 0x0b5d, - 0x0b5f, 0x0b61, - 0x0b85, 0x0b8a, - 0x0b8e, 0x0b90, - 0x0b92, 0x0b95, - 0x0b99, 0x0b9a, - 0x0b9e, 0x0b9f, - 0x0ba3, 0x0ba4, - 0x0ba8, 0x0baa, - 0x0bae, 0x0bb9, - 0x0c05, 0x0c0c, - 0x0c0e, 0x0c10, - 0x0c12, 0x0c28, - 0x0c2a, 0x0c39, - 0x0c58, 0x0c59, - 0x0c60, 0x0c61, - 0x0c85, 0x0c8c, - 0x0c8e, 0x0c90, - 0x0c92, 0x0ca8, - 0x0caa, 0x0cb3, - 0x0cb5, 0x0cb9, - 0x0ce0, 0x0ce1, - 0x0cf1, 0x0cf2, - 0x0d05, 0x0d0c, - 0x0d0e, 0x0d10, - 0x0d12, 0x0d3a, - 0x0d60, 0x0d61, - 0x0d7a, 0x0d7f, - 0x0d85, 0x0d96, - 0x0d9a, 0x0db1, - 0x0db3, 0x0dbb, - 0x0dc0, 0x0dc6, - 0x0e01, 0x0e30, - 0x0e32, 0x0e33, - 0x0e40, 0x0e46, - 0x0e81, 0x0e82, - 0x0e87, 0x0e88, - 0x0e94, 0x0e97, - 0x0e99, 0x0e9f, - 0x0ea1, 0x0ea3, - 0x0eaa, 0x0eab, - 0x0ead, 0x0eb0, - 0x0eb2, 0x0eb3, - 0x0ec0, 0x0ec4, - 0x0edc, 0x0edf, - 0x0f40, 0x0f47, - 0x0f49, 0x0f6c, - 0x0f88, 0x0f8c, - 0x1000, 0x102a, - 0x1050, 0x1055, - 0x105a, 0x105d, - 0x1065, 0x1066, - 0x106e, 0x1070, - 0x1075, 0x1081, - 0x10a0, 0x10c5, - 0x10d0, 0x10fa, - 0x10fc, 0x1248, - 0x124a, 0x124d, - 0x1250, 0x1256, - 0x125a, 0x125d, - 0x1260, 0x1288, - 0x128a, 0x128d, - 0x1290, 0x12b0, - 0x12b2, 0x12b5, - 0x12b8, 0x12be, - 0x12c2, 0x12c5, - 0x12c8, 0x12d6, - 0x12d8, 0x1310, - 0x1312, 0x1315, - 0x1318, 0x135a, - 0x1380, 0x138f, - 0x13a0, 0x13f4, - 0x1401, 0x166c, - 0x166f, 0x167f, - 0x1681, 0x169a, - 0x16a0, 0x16ea, - 0x16f1, 0x16f8, - 0x1700, 0x170c, - 0x170e, 0x1711, - 0x1720, 0x1731, - 0x1740, 0x1751, - 0x1760, 0x176c, - 0x176e, 0x1770, - 0x1780, 0x17b3, - 0x1820, 0x1877, - 0x1880, 0x18a8, - 0x18b0, 0x18f5, - 0x1900, 0x191e, - 0x1950, 0x196d, - 0x1970, 0x1974, - 0x1980, 0x19ab, - 0x19c1, 0x19c7, - 0x1a00, 0x1a16, - 0x1a20, 0x1a54, - 0x1b05, 0x1b33, - 0x1b45, 0x1b4b, - 0x1b83, 0x1ba0, - 0x1bae, 0x1baf, - 0x1bba, 0x1be5, - 0x1c00, 0x1c23, - 0x1c4d, 0x1c4f, - 0x1c5a, 0x1c7d, - 0x1ce9, 0x1cec, - 0x1cee, 0x1cf1, - 0x1cf5, 0x1cf6, - 0x1d00, 0x1dbf, - 0x1e00, 0x1f15, - 0x1f18, 0x1f1d, - 0x1f20, 0x1f45, - 0x1f48, 0x1f4d, - 0x1f50, 0x1f57, - 0x1f5f, 0x1f7d, - 0x1f80, 0x1fb4, - 0x1fb6, 0x1fbc, - 0x1fc2, 0x1fc4, - 0x1fc6, 0x1fcc, - 0x1fd0, 0x1fd3, - 0x1fd6, 0x1fdb, - 0x1fe0, 0x1fec, - 0x1ff2, 0x1ff4, - 0x1ff6, 0x1ffc, - 0x2090, 0x209c, - 0x210a, 0x2113, - 0x2119, 0x211d, - 0x212a, 0x212d, - 0x212f, 0x2139, - 0x213c, 0x213f, - 0x2145, 0x2149, - 0x2183, 0x2184, - 0x2c00, 0x2c2e, - 0x2c30, 0x2c5e, - 0x2c60, 0x2ce4, - 0x2ceb, 0x2cee, - 0x2cf2, 0x2cf3, - 0x2d00, 0x2d25, - 0x2d30, 0x2d67, - 0x2d80, 0x2d96, - 0x2da0, 0x2da6, - 0x2da8, 0x2dae, - 0x2db0, 0x2db6, - 0x2db8, 0x2dbe, - 0x2dc0, 0x2dc6, - 0x2dc8, 0x2dce, - 0x2dd0, 0x2dd6, - 0x2dd8, 0x2dde, - 0x3005, 0x3006, - 0x3031, 0x3035, - 0x303b, 0x303c, - 0x3041, 0x3096, - 0x309d, 0x309f, - 0x30a1, 0x30fa, - 0x30fc, 0x30ff, - 0x3105, 0x312d, - 0x3131, 0x318e, - 0x31a0, 0x31ba, - 0x31f0, 0x31ff, - 0x3400, 0x4db5, - 0x4e00, 0x9fcc, - 0xa000, 0xa48c, - 0xa4d0, 0xa4fd, - 0xa500, 0xa60c, - 0xa610, 0xa61f, - 0xa62a, 0xa62b, - 0xa640, 0xa66e, - 0xa67f, 0xa69d, - 0xa6a0, 0xa6e5, - 0xa717, 0xa71f, - 0xa722, 0xa788, - 0xa78b, 0xa78e, - 0xa790, 0xa7ad, - 0xa7b0, 0xa7b1, - 0xa7f7, 0xa801, - 0xa803, 0xa805, - 0xa807, 0xa80a, - 0xa80c, 0xa822, - 0xa840, 0xa873, - 0xa882, 0xa8b3, - 0xa8f2, 0xa8f7, - 0xa90a, 0xa925, - 0xa930, 0xa946, - 0xa960, 0xa97c, - 0xa984, 0xa9b2, - 0xa9e0, 0xa9e4, - 0xa9e6, 0xa9ef, - 0xa9fa, 0xa9fe, - 0xaa00, 0xaa28, - 0xaa40, 0xaa42, - 0xaa44, 0xaa4b, - 0xaa60, 0xaa76, - 0xaa7e, 0xaaaf, - 0xaab5, 0xaab6, - 0xaab9, 0xaabd, - 0xaadb, 0xaadd, - 0xaae0, 0xaaea, - 0xaaf2, 0xaaf4, - 0xab01, 0xab06, - 0xab09, 0xab0e, - 0xab11, 0xab16, - 0xab20, 0xab26, - 0xab28, 0xab2e, - 0xab30, 0xab5a, - 0xab5c, 0xab5f, - 0xab64, 0xab65, - 0xabc0, 0xabe2, - 0xac00, 0xd7a3, - 0xd7b0, 0xd7c6, - 0xd7cb, 0xd7fb, - 0xf900, 0xfa6d, - 0xfa70, 0xfad9, - 0xfb00, 0xfb06, - 0xfb13, 0xfb17, - 0xfb1f, 0xfb28, - 0xfb2a, 0xfb36, - 0xfb38, 0xfb3c, - 0xfb40, 0xfb41, - 0xfb43, 0xfb44, - 0xfb46, 0xfbb1, - 0xfbd3, 0xfd3d, - 0xfd50, 0xfd8f, - 0xfd92, 0xfdc7, - 0xfdf0, 0xfdfb, - 0xfe70, 0xfe74, - 0xfe76, 0xfefc, - 0xff21, 0xff3a, - 0xff41, 0xff5a, - 0xff66, 0xffbe, - 0xffc2, 0xffc7, - 0xffca, 0xffcf, - 0xffd2, 0xffd7, - 0xffda, 0xffdc, - 0x10000, 0x1000b, - 0x1000d, 0x10026, - 0x10028, 0x1003a, - 0x1003c, 0x1003d, - 0x1003f, 0x1004d, - 0x10050, 0x1005d, - 0x10080, 0x100fa, - 0x10280, 0x1029c, - 0x102a0, 0x102d0, - 0x10300, 0x1031f, - 0x10330, 0x10340, - 0x10342, 0x10349, - 0x10350, 0x10375, - 0x10380, 0x1039d, - 0x103a0, 0x103c3, - 0x103c8, 0x103cf, - 0x10400, 0x1049d, - 0x10500, 0x10527, - 0x10530, 0x10563, - 0x10600, 0x10736, - 0x10740, 0x10755, - 0x10760, 0x10767, - 0x10800, 0x10805, - 0x1080a, 0x10835, - 0x10837, 0x10838, - 0x1083f, 0x10855, - 0x10860, 0x10876, - 0x10880, 0x1089e, - 0x10900, 0x10915, - 0x10920, 0x10939, - 0x10980, 0x109b7, - 0x109be, 0x109bf, - 0x10a10, 0x10a13, - 0x10a15, 0x10a17, - 0x10a19, 0x10a33, - 0x10a60, 0x10a7c, - 0x10a80, 0x10a9c, - 0x10ac0, 0x10ac7, - 0x10ac9, 0x10ae4, - 0x10b00, 0x10b35, - 0x10b40, 0x10b55, - 0x10b60, 0x10b72, - 0x10b80, 0x10b91, - 0x10c00, 0x10c48, - 0x11003, 0x11037, - 0x11083, 0x110af, - 0x110d0, 0x110e8, - 0x11103, 0x11126, - 0x11150, 0x11172, - 0x11183, 0x111b2, - 0x111c1, 0x111c4, - 0x11200, 0x11211, - 0x11213, 0x1122b, - 0x112b0, 0x112de, - 0x11305, 0x1130c, - 0x1130f, 0x11310, - 0x11313, 0x11328, - 0x1132a, 0x11330, - 0x11332, 0x11333, - 0x11335, 0x11339, - 0x1135d, 0x11361, - 0x11480, 0x114af, - 0x114c4, 0x114c5, - 0x11580, 0x115ae, - 0x11600, 0x1162f, - 0x11680, 0x116aa, - 0x118a0, 0x118df, - 0x11ac0, 0x11af8, - 0x12000, 0x12398, - 0x13000, 0x1342e, - 0x16800, 0x16a38, - 0x16a40, 0x16a5e, - 0x16ad0, 0x16aed, - 0x16b00, 0x16b2f, - 0x16b40, 0x16b43, - 0x16b63, 0x16b77, - 0x16b7d, 0x16b8f, - 0x16f00, 0x16f44, - 0x16f93, 0x16f9f, - 0x1b000, 0x1b001, - 0x1bc00, 0x1bc6a, - 0x1bc70, 0x1bc7c, - 0x1bc80, 0x1bc88, - 0x1bc90, 0x1bc99, - 0x1d400, 0x1d454, - 0x1d456, 0x1d49c, - 0x1d49e, 0x1d49f, - 0x1d4a5, 0x1d4a6, - 0x1d4a9, 0x1d4ac, - 0x1d4ae, 0x1d4b9, - 0x1d4bd, 0x1d4c3, - 0x1d4c5, 0x1d505, - 0x1d507, 0x1d50a, - 0x1d50d, 0x1d514, - 0x1d516, 0x1d51c, - 0x1d51e, 0x1d539, - 0x1d53b, 0x1d53e, - 0x1d540, 0x1d544, - 0x1d54a, 0x1d550, - 0x1d552, 0x1d6a5, - 0x1d6a8, 0x1d6c0, - 0x1d6c2, 0x1d6da, - 0x1d6dc, 0x1d6fa, - 0x1d6fc, 0x1d714, - 0x1d716, 0x1d734, - 0x1d736, 0x1d74e, - 0x1d750, 0x1d76e, - 0x1d770, 0x1d788, - 0x1d78a, 0x1d7a8, - 0x1d7aa, 0x1d7c2, - 0x1d7c4, 0x1d7cb, - 0x1e800, 0x1e8c4, - 0x1ee00, 0x1ee03, - 0x1ee05, 0x1ee1f, - 0x1ee21, 0x1ee22, - 0x1ee29, 0x1ee32, - 0x1ee34, 0x1ee37, - 0x1ee4d, 0x1ee4f, - 0x1ee51, 0x1ee52, - 0x1ee61, 0x1ee62, - 0x1ee67, 0x1ee6a, - 0x1ee6c, 0x1ee72, - 0x1ee74, 0x1ee77, - 0x1ee79, 0x1ee7c, - 0x1ee80, 0x1ee89, - 0x1ee8b, 0x1ee9b, - 0x1eea1, 0x1eea3, - 0x1eea5, 0x1eea9, - 0x1eeab, 0x1eebb, - 0x20000, 0x2a6d6, - 0x2a700, 0x2b734, - 0x2b740, 0x2b81d, - 0x2f800, 0x2fa1d, -}; - -} // !namespace - -namespace { - -const char32_t isalphas[] = { - 0x00aa, - 0x00b5, - 0x00ba, - 0x02ec, - 0x02ee, - 0x037f, - 0x0386, - 0x038c, - 0x0559, - 0x06d5, - 0x06ff, - 0x0710, - 0x07b1, - 0x07fa, - 0x081a, - 0x0824, - 0x0828, - 0x093d, - 0x0950, - 0x09b2, - 0x09bd, - 0x09ce, - 0x0a5e, - 0x0abd, - 0x0ad0, - 0x0b3d, - 0x0b71, - 0x0b83, - 0x0b9c, - 0x0bd0, - 0x0c3d, - 0x0cbd, - 0x0cde, - 0x0d3d, - 0x0d4e, - 0x0dbd, - 0x0e84, - 0x0e8a, - 0x0e8d, - 0x0ea5, - 0x0ea7, - 0x0ebd, - 0x0ec6, - 0x0f00, - 0x103f, - 0x1061, - 0x108e, - 0x10c7, - 0x10cd, - 0x1258, - 0x12c0, - 0x17d7, - 0x17dc, - 0x18aa, - 0x1aa7, - 0x1f59, - 0x1f5b, - 0x1f5d, - 0x1fbe, - 0x2071, - 0x207f, - 0x2102, - 0x2107, - 0x2115, - 0x2124, - 0x2126, - 0x2128, - 0x214e, - 0x2d27, - 0x2d2d, - 0x2d6f, - 0x2e2f, - 0xa8fb, - 0xa9cf, - 0xaa7a, - 0xaab1, - 0xaac0, - 0xaac2, - 0xfb1d, - 0xfb3e, - 0x10808, - 0x1083c, - 0x10a00, - 0x11176, - 0x111da, - 0x1133d, - 0x114c7, - 0x11644, - 0x118ff, - 0x16f50, - 0x1d4a2, - 0x1d4bb, - 0x1d546, - 0x1ee24, - 0x1ee27, - 0x1ee39, - 0x1ee3b, - 0x1ee42, - 0x1ee47, - 0x1ee49, - 0x1ee4b, - 0x1ee54, - 0x1ee57, - 0x1ee59, - 0x1ee5b, - 0x1ee5d, - 0x1ee5f, - 0x1ee64, - 0x1ee7e, -}; - -} // !namespace - -bool isalpha(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, isalphar, nelem (isalphar) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, isalphas, nelem (isalphas), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t isupperr[] = { - 0x0041, 0x005a, - 0x00c0, 0x00d6, - 0x00d8, 0x00de, - 0x0178, 0x0179, - 0x0181, 0x0182, - 0x0186, 0x0187, - 0x0189, 0x018b, - 0x018e, 0x0191, - 0x0193, 0x0194, - 0x0196, 0x0198, - 0x019c, 0x019d, - 0x019f, 0x01a0, - 0x01a6, 0x01a7, - 0x01ae, 0x01af, - 0x01b1, 0x01b3, - 0x01b7, 0x01b8, - 0x01f6, 0x01f8, - 0x023a, 0x023b, - 0x023d, 0x023e, - 0x0243, 0x0246, - 0x0388, 0x038a, - 0x038e, 0x038f, - 0x0391, 0x03a1, - 0x03a3, 0x03ab, - 0x03d2, 0x03d4, - 0x03f9, 0x03fa, - 0x03fd, 0x042f, - 0x04c0, 0x04c1, - 0x0531, 0x0556, - 0x10a0, 0x10c5, - 0x1f08, 0x1f0f, - 0x1f18, 0x1f1d, - 0x1f28, 0x1f2f, - 0x1f38, 0x1f3f, - 0x1f48, 0x1f4d, - 0x1f68, 0x1f6f, - 0x1f88, 0x1f8f, - 0x1f98, 0x1f9f, - 0x1fa8, 0x1faf, - 0x1fb8, 0x1fbc, - 0x1fc8, 0x1fcc, - 0x1fd8, 0x1fdb, - 0x1fe8, 0x1fec, - 0x1ff8, 0x1ffc, - 0x210b, 0x210d, - 0x2110, 0x2112, - 0x2119, 0x211d, - 0x212a, 0x212d, - 0x2130, 0x2133, - 0x213e, 0x213f, - 0x2160, 0x216f, - 0x24b6, 0x24cf, - 0x2c00, 0x2c2e, - 0x2c62, 0x2c64, - 0x2c6d, 0x2c70, - 0x2c7e, 0x2c80, - 0xa77d, 0xa77e, - 0xa7aa, 0xa7ad, - 0xa7b0, 0xa7b1, - 0xff21, 0xff3a, - 0x10400, 0x10427, - 0x118a0, 0x118bf, - 0x1d400, 0x1d419, - 0x1d434, 0x1d44d, - 0x1d468, 0x1d481, - 0x1d49e, 0x1d49f, - 0x1d4a5, 0x1d4a6, - 0x1d4a9, 0x1d4ac, - 0x1d4ae, 0x1d4b5, - 0x1d4d0, 0x1d4e9, - 0x1d504, 0x1d505, - 0x1d507, 0x1d50a, - 0x1d50d, 0x1d514, - 0x1d516, 0x1d51c, - 0x1d538, 0x1d539, - 0x1d53b, 0x1d53e, - 0x1d540, 0x1d544, - 0x1d54a, 0x1d550, - 0x1d56c, 0x1d585, - 0x1d5a0, 0x1d5b9, - 0x1d5d4, 0x1d5ed, - 0x1d608, 0x1d621, - 0x1d63c, 0x1d655, - 0x1d670, 0x1d689, - 0x1d6a8, 0x1d6c0, - 0x1d6e2, 0x1d6fa, - 0x1d71c, 0x1d734, - 0x1d756, 0x1d76e, - 0x1d790, 0x1d7a8, -}; - -} // !namespace - -namespace { - -const char32_t isuppers[] = { - 0x0100, - 0x0102, - 0x0104, - 0x0106, - 0x0108, - 0x010a, - 0x010c, - 0x010e, - 0x0110, - 0x0112, - 0x0114, - 0x0116, - 0x0118, - 0x011a, - 0x011c, - 0x011e, - 0x0120, - 0x0122, - 0x0124, - 0x0126, - 0x0128, - 0x012a, - 0x012c, - 0x012e, - 0x0130, - 0x0132, - 0x0134, - 0x0136, - 0x0139, - 0x013b, - 0x013d, - 0x013f, - 0x0141, - 0x0143, - 0x0145, - 0x0147, - 0x014a, - 0x014c, - 0x014e, - 0x0150, - 0x0152, - 0x0154, - 0x0156, - 0x0158, - 0x015a, - 0x015c, - 0x015e, - 0x0160, - 0x0162, - 0x0164, - 0x0166, - 0x0168, - 0x016a, - 0x016c, - 0x016e, - 0x0170, - 0x0172, - 0x0174, - 0x0176, - 0x017b, - 0x017d, - 0x0184, - 0x01a2, - 0x01a4, - 0x01a9, - 0x01ac, - 0x01b5, - 0x01bc, - 0x01c4, - 0x01c7, - 0x01ca, - 0x01cd, - 0x01cf, - 0x01d1, - 0x01d3, - 0x01d5, - 0x01d7, - 0x01d9, - 0x01db, - 0x01de, - 0x01e0, - 0x01e2, - 0x01e4, - 0x01e6, - 0x01e8, - 0x01ea, - 0x01ec, - 0x01ee, - 0x01f1, - 0x01f4, - 0x01fa, - 0x01fc, - 0x01fe, - 0x0200, - 0x0202, - 0x0204, - 0x0206, - 0x0208, - 0x020a, - 0x020c, - 0x020e, - 0x0210, - 0x0212, - 0x0214, - 0x0216, - 0x0218, - 0x021a, - 0x021c, - 0x021e, - 0x0220, - 0x0222, - 0x0224, - 0x0226, - 0x0228, - 0x022a, - 0x022c, - 0x022e, - 0x0230, - 0x0232, - 0x0241, - 0x0248, - 0x024a, - 0x024c, - 0x024e, - 0x0370, - 0x0372, - 0x0376, - 0x037f, - 0x0386, - 0x038c, - 0x03cf, - 0x03d8, - 0x03da, - 0x03dc, - 0x03de, - 0x03e0, - 0x03e2, - 0x03e4, - 0x03e6, - 0x03e8, - 0x03ea, - 0x03ec, - 0x03ee, - 0x03f4, - 0x03f7, - 0x0460, - 0x0462, - 0x0464, - 0x0466, - 0x0468, - 0x046a, - 0x046c, - 0x046e, - 0x0470, - 0x0472, - 0x0474, - 0x0476, - 0x0478, - 0x047a, - 0x047c, - 0x047e, - 0x0480, - 0x048a, - 0x048c, - 0x048e, - 0x0490, - 0x0492, - 0x0494, - 0x0496, - 0x0498, - 0x049a, - 0x049c, - 0x049e, - 0x04a0, - 0x04a2, - 0x04a4, - 0x04a6, - 0x04a8, - 0x04aa, - 0x04ac, - 0x04ae, - 0x04b0, - 0x04b2, - 0x04b4, - 0x04b6, - 0x04b8, - 0x04ba, - 0x04bc, - 0x04be, - 0x04c3, - 0x04c5, - 0x04c7, - 0x04c9, - 0x04cb, - 0x04cd, - 0x04d0, - 0x04d2, - 0x04d4, - 0x04d6, - 0x04d8, - 0x04da, - 0x04dc, - 0x04de, - 0x04e0, - 0x04e2, - 0x04e4, - 0x04e6, - 0x04e8, - 0x04ea, - 0x04ec, - 0x04ee, - 0x04f0, - 0x04f2, - 0x04f4, - 0x04f6, - 0x04f8, - 0x04fa, - 0x04fc, - 0x04fe, - 0x0500, - 0x0502, - 0x0504, - 0x0506, - 0x0508, - 0x050a, - 0x050c, - 0x050e, - 0x0510, - 0x0512, - 0x0514, - 0x0516, - 0x0518, - 0x051a, - 0x051c, - 0x051e, - 0x0520, - 0x0522, - 0x0524, - 0x0526, - 0x0528, - 0x052a, - 0x052c, - 0x052e, - 0x10c7, - 0x10cd, - 0x1e00, - 0x1e02, - 0x1e04, - 0x1e06, - 0x1e08, - 0x1e0a, - 0x1e0c, - 0x1e0e, - 0x1e10, - 0x1e12, - 0x1e14, - 0x1e16, - 0x1e18, - 0x1e1a, - 0x1e1c, - 0x1e1e, - 0x1e20, - 0x1e22, - 0x1e24, - 0x1e26, - 0x1e28, - 0x1e2a, - 0x1e2c, - 0x1e2e, - 0x1e30, - 0x1e32, - 0x1e34, - 0x1e36, - 0x1e38, - 0x1e3a, - 0x1e3c, - 0x1e3e, - 0x1e40, - 0x1e42, - 0x1e44, - 0x1e46, - 0x1e48, - 0x1e4a, - 0x1e4c, - 0x1e4e, - 0x1e50, - 0x1e52, - 0x1e54, - 0x1e56, - 0x1e58, - 0x1e5a, - 0x1e5c, - 0x1e5e, - 0x1e60, - 0x1e62, - 0x1e64, - 0x1e66, - 0x1e68, - 0x1e6a, - 0x1e6c, - 0x1e6e, - 0x1e70, - 0x1e72, - 0x1e74, - 0x1e76, - 0x1e78, - 0x1e7a, - 0x1e7c, - 0x1e7e, - 0x1e80, - 0x1e82, - 0x1e84, - 0x1e86, - 0x1e88, - 0x1e8a, - 0x1e8c, - 0x1e8e, - 0x1e90, - 0x1e92, - 0x1e94, - 0x1e9e, - 0x1ea0, - 0x1ea2, - 0x1ea4, - 0x1ea6, - 0x1ea8, - 0x1eaa, - 0x1eac, - 0x1eae, - 0x1eb0, - 0x1eb2, - 0x1eb4, - 0x1eb6, - 0x1eb8, - 0x1eba, - 0x1ebc, - 0x1ebe, - 0x1ec0, - 0x1ec2, - 0x1ec4, - 0x1ec6, - 0x1ec8, - 0x1eca, - 0x1ecc, - 0x1ece, - 0x1ed0, - 0x1ed2, - 0x1ed4, - 0x1ed6, - 0x1ed8, - 0x1eda, - 0x1edc, - 0x1ede, - 0x1ee0, - 0x1ee2, - 0x1ee4, - 0x1ee6, - 0x1ee8, - 0x1eea, - 0x1eec, - 0x1eee, - 0x1ef0, - 0x1ef2, - 0x1ef4, - 0x1ef6, - 0x1ef8, - 0x1efa, - 0x1efc, - 0x1efe, - 0x1f59, - 0x1f5b, - 0x1f5d, - 0x1f5f, - 0x2102, - 0x2107, - 0x2115, - 0x2124, - 0x2126, - 0x2128, - 0x2145, - 0x2183, - 0x2c60, - 0x2c67, - 0x2c69, - 0x2c6b, - 0x2c72, - 0x2c75, - 0x2c82, - 0x2c84, - 0x2c86, - 0x2c88, - 0x2c8a, - 0x2c8c, - 0x2c8e, - 0x2c90, - 0x2c92, - 0x2c94, - 0x2c96, - 0x2c98, - 0x2c9a, - 0x2c9c, - 0x2c9e, - 0x2ca0, - 0x2ca2, - 0x2ca4, - 0x2ca6, - 0x2ca8, - 0x2caa, - 0x2cac, - 0x2cae, - 0x2cb0, - 0x2cb2, - 0x2cb4, - 0x2cb6, - 0x2cb8, - 0x2cba, - 0x2cbc, - 0x2cbe, - 0x2cc0, - 0x2cc2, - 0x2cc4, - 0x2cc6, - 0x2cc8, - 0x2cca, - 0x2ccc, - 0x2cce, - 0x2cd0, - 0x2cd2, - 0x2cd4, - 0x2cd6, - 0x2cd8, - 0x2cda, - 0x2cdc, - 0x2cde, - 0x2ce0, - 0x2ce2, - 0x2ceb, - 0x2ced, - 0x2cf2, - 0xa640, - 0xa642, - 0xa644, - 0xa646, - 0xa648, - 0xa64a, - 0xa64c, - 0xa64e, - 0xa650, - 0xa652, - 0xa654, - 0xa656, - 0xa658, - 0xa65a, - 0xa65c, - 0xa65e, - 0xa660, - 0xa662, - 0xa664, - 0xa666, - 0xa668, - 0xa66a, - 0xa66c, - 0xa680, - 0xa682, - 0xa684, - 0xa686, - 0xa688, - 0xa68a, - 0xa68c, - 0xa68e, - 0xa690, - 0xa692, - 0xa694, - 0xa696, - 0xa698, - 0xa69a, - 0xa722, - 0xa724, - 0xa726, - 0xa728, - 0xa72a, - 0xa72c, - 0xa72e, - 0xa732, - 0xa734, - 0xa736, - 0xa738, - 0xa73a, - 0xa73c, - 0xa73e, - 0xa740, - 0xa742, - 0xa744, - 0xa746, - 0xa748, - 0xa74a, - 0xa74c, - 0xa74e, - 0xa750, - 0xa752, - 0xa754, - 0xa756, - 0xa758, - 0xa75a, - 0xa75c, - 0xa75e, - 0xa760, - 0xa762, - 0xa764, - 0xa766, - 0xa768, - 0xa76a, - 0xa76c, - 0xa76e, - 0xa779, - 0xa77b, - 0xa780, - 0xa782, - 0xa784, - 0xa786, - 0xa78b, - 0xa78d, - 0xa790, - 0xa792, - 0xa796, - 0xa798, - 0xa79a, - 0xa79c, - 0xa79e, - 0xa7a0, - 0xa7a2, - 0xa7a4, - 0xa7a6, - 0xa7a8, - 0x1d49c, - 0x1d4a2, - 0x1d546, - 0x1d7ca, -}; - -} // !namespace - -bool isupper(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, isupperr, nelem (isupperr) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, isuppers, nelem (isuppers), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t islowerr[] = { - 0x0061, 0x007a, - 0x00df, 0x00f6, - 0x00f8, 0x00ff, - 0x0137, 0x0138, - 0x0148, 0x0149, - 0x017e, 0x0180, - 0x018c, 0x018d, - 0x0199, 0x019b, - 0x01aa, 0x01ab, - 0x01b9, 0x01ba, - 0x01bd, 0x01bf, - 0x01dc, 0x01dd, - 0x01ef, 0x01f0, - 0x0233, 0x0239, - 0x023f, 0x0240, - 0x024f, 0x0293, - 0x0295, 0x02af, - 0x037b, 0x037d, - 0x03ac, 0x03ce, - 0x03d0, 0x03d1, - 0x03d5, 0x03d7, - 0x03ef, 0x03f3, - 0x03fb, 0x03fc, - 0x0430, 0x045f, - 0x04ce, 0x04cf, - 0x0561, 0x0587, - 0x1d00, 0x1d2b, - 0x1d6b, 0x1d77, - 0x1d79, 0x1d9a, - 0x1e95, 0x1e9d, - 0x1eff, 0x1f07, - 0x1f10, 0x1f15, - 0x1f20, 0x1f27, - 0x1f30, 0x1f37, - 0x1f40, 0x1f45, - 0x1f50, 0x1f57, - 0x1f60, 0x1f67, - 0x1f70, 0x1f7d, - 0x1f80, 0x1f87, - 0x1f90, 0x1f97, - 0x1fa0, 0x1fa7, - 0x1fb0, 0x1fb4, - 0x1fb6, 0x1fb7, - 0x1fc2, 0x1fc4, - 0x1fc6, 0x1fc7, - 0x1fd0, 0x1fd3, - 0x1fd6, 0x1fd7, - 0x1fe0, 0x1fe7, - 0x1ff2, 0x1ff4, - 0x1ff6, 0x1ff7, - 0x210e, 0x210f, - 0x213c, 0x213d, - 0x2146, 0x2149, - 0x2170, 0x217f, - 0x24d0, 0x24e9, - 0x2c30, 0x2c5e, - 0x2c65, 0x2c66, - 0x2c73, 0x2c74, - 0x2c76, 0x2c7b, - 0x2ce3, 0x2ce4, - 0x2d00, 0x2d25, - 0xa72f, 0xa731, - 0xa771, 0xa778, - 0xa793, 0xa795, - 0xab30, 0xab5a, - 0xab64, 0xab65, - 0xfb00, 0xfb06, - 0xfb13, 0xfb17, - 0xff41, 0xff5a, - 0x10428, 0x1044f, - 0x118c0, 0x118df, - 0x1d41a, 0x1d433, - 0x1d44e, 0x1d454, - 0x1d456, 0x1d467, - 0x1d482, 0x1d49b, - 0x1d4b6, 0x1d4b9, - 0x1d4bd, 0x1d4c3, - 0x1d4c5, 0x1d4cf, - 0x1d4ea, 0x1d503, - 0x1d51e, 0x1d537, - 0x1d552, 0x1d56b, - 0x1d586, 0x1d59f, - 0x1d5ba, 0x1d5d3, - 0x1d5ee, 0x1d607, - 0x1d622, 0x1d63b, - 0x1d656, 0x1d66f, - 0x1d68a, 0x1d6a5, - 0x1d6c2, 0x1d6da, - 0x1d6dc, 0x1d6e1, - 0x1d6fc, 0x1d714, - 0x1d716, 0x1d71b, - 0x1d736, 0x1d74e, - 0x1d750, 0x1d755, - 0x1d770, 0x1d788, - 0x1d78a, 0x1d78f, - 0x1d7aa, 0x1d7c2, - 0x1d7c4, 0x1d7c9, -}; - -} // !namespace - -namespace { - -const char32_t islowers[] = { - 0x00b5, - 0x0101, - 0x0103, - 0x0105, - 0x0107, - 0x0109, - 0x010b, - 0x010d, - 0x010f, - 0x0111, - 0x0113, - 0x0115, - 0x0117, - 0x0119, - 0x011b, - 0x011d, - 0x011f, - 0x0121, - 0x0123, - 0x0125, - 0x0127, - 0x0129, - 0x012b, - 0x012d, - 0x012f, - 0x0131, - 0x0133, - 0x0135, - 0x013a, - 0x013c, - 0x013e, - 0x0140, - 0x0142, - 0x0144, - 0x0146, - 0x014b, - 0x014d, - 0x014f, - 0x0151, - 0x0153, - 0x0155, - 0x0157, - 0x0159, - 0x015b, - 0x015d, - 0x015f, - 0x0161, - 0x0163, - 0x0165, - 0x0167, - 0x0169, - 0x016b, - 0x016d, - 0x016f, - 0x0171, - 0x0173, - 0x0175, - 0x0177, - 0x017a, - 0x017c, - 0x0183, - 0x0185, - 0x0188, - 0x0192, - 0x0195, - 0x019e, - 0x01a1, - 0x01a3, - 0x01a5, - 0x01a8, - 0x01ad, - 0x01b0, - 0x01b4, - 0x01b6, - 0x01c6, - 0x01c9, - 0x01cc, - 0x01ce, - 0x01d0, - 0x01d2, - 0x01d4, - 0x01d6, - 0x01d8, - 0x01da, - 0x01df, - 0x01e1, - 0x01e3, - 0x01e5, - 0x01e7, - 0x01e9, - 0x01eb, - 0x01ed, - 0x01f3, - 0x01f5, - 0x01f9, - 0x01fb, - 0x01fd, - 0x01ff, - 0x0201, - 0x0203, - 0x0205, - 0x0207, - 0x0209, - 0x020b, - 0x020d, - 0x020f, - 0x0211, - 0x0213, - 0x0215, - 0x0217, - 0x0219, - 0x021b, - 0x021d, - 0x021f, - 0x0221, - 0x0223, - 0x0225, - 0x0227, - 0x0229, - 0x022b, - 0x022d, - 0x022f, - 0x0231, - 0x023c, - 0x0242, - 0x0247, - 0x0249, - 0x024b, - 0x024d, - 0x0371, - 0x0373, - 0x0377, - 0x0390, - 0x03d9, - 0x03db, - 0x03dd, - 0x03df, - 0x03e1, - 0x03e3, - 0x03e5, - 0x03e7, - 0x03e9, - 0x03eb, - 0x03ed, - 0x03f5, - 0x03f8, - 0x0461, - 0x0463, - 0x0465, - 0x0467, - 0x0469, - 0x046b, - 0x046d, - 0x046f, - 0x0471, - 0x0473, - 0x0475, - 0x0477, - 0x0479, - 0x047b, - 0x047d, - 0x047f, - 0x0481, - 0x048b, - 0x048d, - 0x048f, - 0x0491, - 0x0493, - 0x0495, - 0x0497, - 0x0499, - 0x049b, - 0x049d, - 0x049f, - 0x04a1, - 0x04a3, - 0x04a5, - 0x04a7, - 0x04a9, - 0x04ab, - 0x04ad, - 0x04af, - 0x04b1, - 0x04b3, - 0x04b5, - 0x04b7, - 0x04b9, - 0x04bb, - 0x04bd, - 0x04bf, - 0x04c2, - 0x04c4, - 0x04c6, - 0x04c8, - 0x04ca, - 0x04cc, - 0x04d1, - 0x04d3, - 0x04d5, - 0x04d7, - 0x04d9, - 0x04db, - 0x04dd, - 0x04df, - 0x04e1, - 0x04e3, - 0x04e5, - 0x04e7, - 0x04e9, - 0x04eb, - 0x04ed, - 0x04ef, - 0x04f1, - 0x04f3, - 0x04f5, - 0x04f7, - 0x04f9, - 0x04fb, - 0x04fd, - 0x04ff, - 0x0501, - 0x0503, - 0x0505, - 0x0507, - 0x0509, - 0x050b, - 0x050d, - 0x050f, - 0x0511, - 0x0513, - 0x0515, - 0x0517, - 0x0519, - 0x051b, - 0x051d, - 0x051f, - 0x0521, - 0x0523, - 0x0525, - 0x0527, - 0x0529, - 0x052b, - 0x052d, - 0x052f, - 0x1e01, - 0x1e03, - 0x1e05, - 0x1e07, - 0x1e09, - 0x1e0b, - 0x1e0d, - 0x1e0f, - 0x1e11, - 0x1e13, - 0x1e15, - 0x1e17, - 0x1e19, - 0x1e1b, - 0x1e1d, - 0x1e1f, - 0x1e21, - 0x1e23, - 0x1e25, - 0x1e27, - 0x1e29, - 0x1e2b, - 0x1e2d, - 0x1e2f, - 0x1e31, - 0x1e33, - 0x1e35, - 0x1e37, - 0x1e39, - 0x1e3b, - 0x1e3d, - 0x1e3f, - 0x1e41, - 0x1e43, - 0x1e45, - 0x1e47, - 0x1e49, - 0x1e4b, - 0x1e4d, - 0x1e4f, - 0x1e51, - 0x1e53, - 0x1e55, - 0x1e57, - 0x1e59, - 0x1e5b, - 0x1e5d, - 0x1e5f, - 0x1e61, - 0x1e63, - 0x1e65, - 0x1e67, - 0x1e69, - 0x1e6b, - 0x1e6d, - 0x1e6f, - 0x1e71, - 0x1e73, - 0x1e75, - 0x1e77, - 0x1e79, - 0x1e7b, - 0x1e7d, - 0x1e7f, - 0x1e81, - 0x1e83, - 0x1e85, - 0x1e87, - 0x1e89, - 0x1e8b, - 0x1e8d, - 0x1e8f, - 0x1e91, - 0x1e93, - 0x1e9f, - 0x1ea1, - 0x1ea3, - 0x1ea5, - 0x1ea7, - 0x1ea9, - 0x1eab, - 0x1ead, - 0x1eaf, - 0x1eb1, - 0x1eb3, - 0x1eb5, - 0x1eb7, - 0x1eb9, - 0x1ebb, - 0x1ebd, - 0x1ebf, - 0x1ec1, - 0x1ec3, - 0x1ec5, - 0x1ec7, - 0x1ec9, - 0x1ecb, - 0x1ecd, - 0x1ecf, - 0x1ed1, - 0x1ed3, - 0x1ed5, - 0x1ed7, - 0x1ed9, - 0x1edb, - 0x1edd, - 0x1edf, - 0x1ee1, - 0x1ee3, - 0x1ee5, - 0x1ee7, - 0x1ee9, - 0x1eeb, - 0x1eed, - 0x1eef, - 0x1ef1, - 0x1ef3, - 0x1ef5, - 0x1ef7, - 0x1ef9, - 0x1efb, - 0x1efd, - 0x1fbe, - 0x210a, - 0x2113, - 0x212f, - 0x2134, - 0x2139, - 0x214e, - 0x2184, - 0x2c61, - 0x2c68, - 0x2c6a, - 0x2c6c, - 0x2c71, - 0x2c81, - 0x2c83, - 0x2c85, - 0x2c87, - 0x2c89, - 0x2c8b, - 0x2c8d, - 0x2c8f, - 0x2c91, - 0x2c93, - 0x2c95, - 0x2c97, - 0x2c99, - 0x2c9b, - 0x2c9d, - 0x2c9f, - 0x2ca1, - 0x2ca3, - 0x2ca5, - 0x2ca7, - 0x2ca9, - 0x2cab, - 0x2cad, - 0x2caf, - 0x2cb1, - 0x2cb3, - 0x2cb5, - 0x2cb7, - 0x2cb9, - 0x2cbb, - 0x2cbd, - 0x2cbf, - 0x2cc1, - 0x2cc3, - 0x2cc5, - 0x2cc7, - 0x2cc9, - 0x2ccb, - 0x2ccd, - 0x2ccf, - 0x2cd1, - 0x2cd3, - 0x2cd5, - 0x2cd7, - 0x2cd9, - 0x2cdb, - 0x2cdd, - 0x2cdf, - 0x2ce1, - 0x2cec, - 0x2cee, - 0x2cf3, - 0x2d27, - 0x2d2d, - 0xa641, - 0xa643, - 0xa645, - 0xa647, - 0xa649, - 0xa64b, - 0xa64d, - 0xa64f, - 0xa651, - 0xa653, - 0xa655, - 0xa657, - 0xa659, - 0xa65b, - 0xa65d, - 0xa65f, - 0xa661, - 0xa663, - 0xa665, - 0xa667, - 0xa669, - 0xa66b, - 0xa66d, - 0xa681, - 0xa683, - 0xa685, - 0xa687, - 0xa689, - 0xa68b, - 0xa68d, - 0xa68f, - 0xa691, - 0xa693, - 0xa695, - 0xa697, - 0xa699, - 0xa69b, - 0xa723, - 0xa725, - 0xa727, - 0xa729, - 0xa72b, - 0xa72d, - 0xa733, - 0xa735, - 0xa737, - 0xa739, - 0xa73b, - 0xa73d, - 0xa73f, - 0xa741, - 0xa743, - 0xa745, - 0xa747, - 0xa749, - 0xa74b, - 0xa74d, - 0xa74f, - 0xa751, - 0xa753, - 0xa755, - 0xa757, - 0xa759, - 0xa75b, - 0xa75d, - 0xa75f, - 0xa761, - 0xa763, - 0xa765, - 0xa767, - 0xa769, - 0xa76b, - 0xa76d, - 0xa76f, - 0xa77a, - 0xa77c, - 0xa77f, - 0xa781, - 0xa783, - 0xa785, - 0xa787, - 0xa78c, - 0xa78e, - 0xa791, - 0xa797, - 0xa799, - 0xa79b, - 0xa79d, - 0xa79f, - 0xa7a1, - 0xa7a3, - 0xa7a5, - 0xa7a7, - 0xa7a9, - 0xa7fa, - 0x1d4bb, - 0x1d7cb, -}; - -} // !namespace - -bool islower(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, islowerr, nelem (islowerr) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, islowers, nelem (islowers), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t istitler[] = { - 0x0041, 0x005a, - 0x00c0, 0x00d6, - 0x00d8, 0x00de, - 0x0178, 0x0179, - 0x0181, 0x0182, - 0x0186, 0x0187, - 0x0189, 0x018b, - 0x018e, 0x0191, - 0x0193, 0x0194, - 0x0196, 0x0198, - 0x019c, 0x019d, - 0x019f, 0x01a0, - 0x01a6, 0x01a7, - 0x01ae, 0x01af, - 0x01b1, 0x01b3, - 0x01b7, 0x01b8, - 0x01f6, 0x01f8, - 0x023a, 0x023b, - 0x023d, 0x023e, - 0x0243, 0x0246, - 0x0388, 0x038a, - 0x038e, 0x038f, - 0x0391, 0x03a1, - 0x03a3, 0x03ab, - 0x03f9, 0x03fa, - 0x03fd, 0x042f, - 0x04c0, 0x04c1, - 0x0531, 0x0556, - 0x10a0, 0x10c5, - 0x1f08, 0x1f0f, - 0x1f18, 0x1f1d, - 0x1f28, 0x1f2f, - 0x1f38, 0x1f3f, - 0x1f48, 0x1f4d, - 0x1f68, 0x1f6f, - 0x1f88, 0x1f8f, - 0x1f98, 0x1f9f, - 0x1fa8, 0x1faf, - 0x1fb8, 0x1fbc, - 0x1fc8, 0x1fcc, - 0x1fd8, 0x1fdb, - 0x1fe8, 0x1fec, - 0x1ff8, 0x1ffc, - 0x2160, 0x216f, - 0x24b6, 0x24cf, - 0x2c00, 0x2c2e, - 0x2c62, 0x2c64, - 0x2c6d, 0x2c70, - 0x2c7e, 0x2c80, - 0xa77d, 0xa77e, - 0xa7aa, 0xa7ad, - 0xa7b0, 0xa7b1, - 0xff21, 0xff3a, - 0x10400, 0x10427, - 0x118a0, 0x118bf, -}; - -} // !namespace - -namespace { - -const char32_t istitles[] = { - 0x0100, - 0x0102, - 0x0104, - 0x0106, - 0x0108, - 0x010a, - 0x010c, - 0x010e, - 0x0110, - 0x0112, - 0x0114, - 0x0116, - 0x0118, - 0x011a, - 0x011c, - 0x011e, - 0x0120, - 0x0122, - 0x0124, - 0x0126, - 0x0128, - 0x012a, - 0x012c, - 0x012e, - 0x0132, - 0x0134, - 0x0136, - 0x0139, - 0x013b, - 0x013d, - 0x013f, - 0x0141, - 0x0143, - 0x0145, - 0x0147, - 0x014a, - 0x014c, - 0x014e, - 0x0150, - 0x0152, - 0x0154, - 0x0156, - 0x0158, - 0x015a, - 0x015c, - 0x015e, - 0x0160, - 0x0162, - 0x0164, - 0x0166, - 0x0168, - 0x016a, - 0x016c, - 0x016e, - 0x0170, - 0x0172, - 0x0174, - 0x0176, - 0x017b, - 0x017d, - 0x0184, - 0x01a2, - 0x01a4, - 0x01a9, - 0x01ac, - 0x01b5, - 0x01bc, - 0x01c5, - 0x01c8, - 0x01cb, - 0x01cd, - 0x01cf, - 0x01d1, - 0x01d3, - 0x01d5, - 0x01d7, - 0x01d9, - 0x01db, - 0x01de, - 0x01e0, - 0x01e2, - 0x01e4, - 0x01e6, - 0x01e8, - 0x01ea, - 0x01ec, - 0x01ee, - 0x01f2, - 0x01f4, - 0x01fa, - 0x01fc, - 0x01fe, - 0x0200, - 0x0202, - 0x0204, - 0x0206, - 0x0208, - 0x020a, - 0x020c, - 0x020e, - 0x0210, - 0x0212, - 0x0214, - 0x0216, - 0x0218, - 0x021a, - 0x021c, - 0x021e, - 0x0220, - 0x0222, - 0x0224, - 0x0226, - 0x0228, - 0x022a, - 0x022c, - 0x022e, - 0x0230, - 0x0232, - 0x0241, - 0x0248, - 0x024a, - 0x024c, - 0x024e, - 0x0370, - 0x0372, - 0x0376, - 0x037f, - 0x0386, - 0x038c, - 0x03cf, - 0x03d8, - 0x03da, - 0x03dc, - 0x03de, - 0x03e0, - 0x03e2, - 0x03e4, - 0x03e6, - 0x03e8, - 0x03ea, - 0x03ec, - 0x03ee, - 0x03f7, - 0x0460, - 0x0462, - 0x0464, - 0x0466, - 0x0468, - 0x046a, - 0x046c, - 0x046e, - 0x0470, - 0x0472, - 0x0474, - 0x0476, - 0x0478, - 0x047a, - 0x047c, - 0x047e, - 0x0480, - 0x048a, - 0x048c, - 0x048e, - 0x0490, - 0x0492, - 0x0494, - 0x0496, - 0x0498, - 0x049a, - 0x049c, - 0x049e, - 0x04a0, - 0x04a2, - 0x04a4, - 0x04a6, - 0x04a8, - 0x04aa, - 0x04ac, - 0x04ae, - 0x04b0, - 0x04b2, - 0x04b4, - 0x04b6, - 0x04b8, - 0x04ba, - 0x04bc, - 0x04be, - 0x04c3, - 0x04c5, - 0x04c7, - 0x04c9, - 0x04cb, - 0x04cd, - 0x04d0, - 0x04d2, - 0x04d4, - 0x04d6, - 0x04d8, - 0x04da, - 0x04dc, - 0x04de, - 0x04e0, - 0x04e2, - 0x04e4, - 0x04e6, - 0x04e8, - 0x04ea, - 0x04ec, - 0x04ee, - 0x04f0, - 0x04f2, - 0x04f4, - 0x04f6, - 0x04f8, - 0x04fa, - 0x04fc, - 0x04fe, - 0x0500, - 0x0502, - 0x0504, - 0x0506, - 0x0508, - 0x050a, - 0x050c, - 0x050e, - 0x0510, - 0x0512, - 0x0514, - 0x0516, - 0x0518, - 0x051a, - 0x051c, - 0x051e, - 0x0520, - 0x0522, - 0x0524, - 0x0526, - 0x0528, - 0x052a, - 0x052c, - 0x052e, - 0x10c7, - 0x10cd, - 0x1e00, - 0x1e02, - 0x1e04, - 0x1e06, - 0x1e08, - 0x1e0a, - 0x1e0c, - 0x1e0e, - 0x1e10, - 0x1e12, - 0x1e14, - 0x1e16, - 0x1e18, - 0x1e1a, - 0x1e1c, - 0x1e1e, - 0x1e20, - 0x1e22, - 0x1e24, - 0x1e26, - 0x1e28, - 0x1e2a, - 0x1e2c, - 0x1e2e, - 0x1e30, - 0x1e32, - 0x1e34, - 0x1e36, - 0x1e38, - 0x1e3a, - 0x1e3c, - 0x1e3e, - 0x1e40, - 0x1e42, - 0x1e44, - 0x1e46, - 0x1e48, - 0x1e4a, - 0x1e4c, - 0x1e4e, - 0x1e50, - 0x1e52, - 0x1e54, - 0x1e56, - 0x1e58, - 0x1e5a, - 0x1e5c, - 0x1e5e, - 0x1e60, - 0x1e62, - 0x1e64, - 0x1e66, - 0x1e68, - 0x1e6a, - 0x1e6c, - 0x1e6e, - 0x1e70, - 0x1e72, - 0x1e74, - 0x1e76, - 0x1e78, - 0x1e7a, - 0x1e7c, - 0x1e7e, - 0x1e80, - 0x1e82, - 0x1e84, - 0x1e86, - 0x1e88, - 0x1e8a, - 0x1e8c, - 0x1e8e, - 0x1e90, - 0x1e92, - 0x1e94, - 0x1ea0, - 0x1ea2, - 0x1ea4, - 0x1ea6, - 0x1ea8, - 0x1eaa, - 0x1eac, - 0x1eae, - 0x1eb0, - 0x1eb2, - 0x1eb4, - 0x1eb6, - 0x1eb8, - 0x1eba, - 0x1ebc, - 0x1ebe, - 0x1ec0, - 0x1ec2, - 0x1ec4, - 0x1ec6, - 0x1ec8, - 0x1eca, - 0x1ecc, - 0x1ece, - 0x1ed0, - 0x1ed2, - 0x1ed4, - 0x1ed6, - 0x1ed8, - 0x1eda, - 0x1edc, - 0x1ede, - 0x1ee0, - 0x1ee2, - 0x1ee4, - 0x1ee6, - 0x1ee8, - 0x1eea, - 0x1eec, - 0x1eee, - 0x1ef0, - 0x1ef2, - 0x1ef4, - 0x1ef6, - 0x1ef8, - 0x1efa, - 0x1efc, - 0x1efe, - 0x1f59, - 0x1f5b, - 0x1f5d, - 0x1f5f, - 0x2132, - 0x2183, - 0x2c60, - 0x2c67, - 0x2c69, - 0x2c6b, - 0x2c72, - 0x2c75, - 0x2c82, - 0x2c84, - 0x2c86, - 0x2c88, - 0x2c8a, - 0x2c8c, - 0x2c8e, - 0x2c90, - 0x2c92, - 0x2c94, - 0x2c96, - 0x2c98, - 0x2c9a, - 0x2c9c, - 0x2c9e, - 0x2ca0, - 0x2ca2, - 0x2ca4, - 0x2ca6, - 0x2ca8, - 0x2caa, - 0x2cac, - 0x2cae, - 0x2cb0, - 0x2cb2, - 0x2cb4, - 0x2cb6, - 0x2cb8, - 0x2cba, - 0x2cbc, - 0x2cbe, - 0x2cc0, - 0x2cc2, - 0x2cc4, - 0x2cc6, - 0x2cc8, - 0x2cca, - 0x2ccc, - 0x2cce, - 0x2cd0, - 0x2cd2, - 0x2cd4, - 0x2cd6, - 0x2cd8, - 0x2cda, - 0x2cdc, - 0x2cde, - 0x2ce0, - 0x2ce2, - 0x2ceb, - 0x2ced, - 0x2cf2, - 0xa640, - 0xa642, - 0xa644, - 0xa646, - 0xa648, - 0xa64a, - 0xa64c, - 0xa64e, - 0xa650, - 0xa652, - 0xa654, - 0xa656, - 0xa658, - 0xa65a, - 0xa65c, - 0xa65e, - 0xa660, - 0xa662, - 0xa664, - 0xa666, - 0xa668, - 0xa66a, - 0xa66c, - 0xa680, - 0xa682, - 0xa684, - 0xa686, - 0xa688, - 0xa68a, - 0xa68c, - 0xa68e, - 0xa690, - 0xa692, - 0xa694, - 0xa696, - 0xa698, - 0xa69a, - 0xa722, - 0xa724, - 0xa726, - 0xa728, - 0xa72a, - 0xa72c, - 0xa72e, - 0xa732, - 0xa734, - 0xa736, - 0xa738, - 0xa73a, - 0xa73c, - 0xa73e, - 0xa740, - 0xa742, - 0xa744, - 0xa746, - 0xa748, - 0xa74a, - 0xa74c, - 0xa74e, - 0xa750, - 0xa752, - 0xa754, - 0xa756, - 0xa758, - 0xa75a, - 0xa75c, - 0xa75e, - 0xa760, - 0xa762, - 0xa764, - 0xa766, - 0xa768, - 0xa76a, - 0xa76c, - 0xa76e, - 0xa779, - 0xa77b, - 0xa780, - 0xa782, - 0xa784, - 0xa786, - 0xa78b, - 0xa78d, - 0xa790, - 0xa792, - 0xa796, - 0xa798, - 0xa79a, - 0xa79c, - 0xa79e, - 0xa7a0, - 0xa7a2, - 0xa7a4, - 0xa7a6, - 0xa7a8, -}; - -} // !namespace - -bool istitle(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, istitler, nelem (istitler) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, istitles, nelem (istitles), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t toupperr[] = { - 0x0061, 0x007a, 1048544, - 0x00e0, 0x00f6, 1048544, - 0x00f8, 0x00fe, 1048544, - 0x023f, 0x0240, 1059391, - 0x0256, 0x0257, 1048371, - 0x028a, 0x028b, 1048359, - 0x037b, 0x037d, 1048706, - 0x03ad, 0x03af, 1048539, - 0x03b1, 0x03c1, 1048544, - 0x03c3, 0x03cb, 1048544, - 0x03cd, 0x03ce, 1048513, - 0x0430, 0x044f, 1048544, - 0x0450, 0x045f, 1048496, - 0x0561, 0x0586, 1048528, - 0x1f00, 0x1f07, 1048584, - 0x1f10, 0x1f15, 1048584, - 0x1f20, 0x1f27, 1048584, - 0x1f30, 0x1f37, 1048584, - 0x1f40, 0x1f45, 1048584, - 0x1f60, 0x1f67, 1048584, - 0x1f70, 0x1f71, 1048650, - 0x1f72, 0x1f75, 1048662, - 0x1f76, 0x1f77, 1048676, - 0x1f78, 0x1f79, 1048704, - 0x1f7a, 0x1f7b, 1048688, - 0x1f7c, 0x1f7d, 1048702, - 0x1f80, 0x1f87, 1048584, - 0x1f90, 0x1f97, 1048584, - 0x1fa0, 0x1fa7, 1048584, - 0x1fb0, 0x1fb1, 1048584, - 0x1fd0, 0x1fd1, 1048584, - 0x1fe0, 0x1fe1, 1048584, - 0x2170, 0x217f, 1048560, - 0x24d0, 0x24e9, 1048550, - 0x2c30, 0x2c5e, 1048528, - 0x2d00, 0x2d25, 1041312, - 0xff41, 0xff5a, 1048544, - 0x10428, 0x1044f, 1048536, - 0x118c0, 0x118df, 1048544, -}; - -} // !namespace - -namespace { - -const char32_t touppers[] = { - 0x00b5, 1049319, - 0x00ff, 1048697, - 0x0101, 1048575, - 0x0103, 1048575, - 0x0105, 1048575, - 0x0107, 1048575, - 0x0109, 1048575, - 0x010b, 1048575, - 0x010d, 1048575, - 0x010f, 1048575, - 0x0111, 1048575, - 0x0113, 1048575, - 0x0115, 1048575, - 0x0117, 1048575, - 0x0119, 1048575, - 0x011b, 1048575, - 0x011d, 1048575, - 0x011f, 1048575, - 0x0121, 1048575, - 0x0123, 1048575, - 0x0125, 1048575, - 0x0127, 1048575, - 0x0129, 1048575, - 0x012b, 1048575, - 0x012d, 1048575, - 0x012f, 1048575, - 0x0131, 1048344, - 0x0133, 1048575, - 0x0135, 1048575, - 0x0137, 1048575, - 0x013a, 1048575, - 0x013c, 1048575, - 0x013e, 1048575, - 0x0140, 1048575, - 0x0142, 1048575, - 0x0144, 1048575, - 0x0146, 1048575, - 0x0148, 1048575, - 0x014b, 1048575, - 0x014d, 1048575, - 0x014f, 1048575, - 0x0151, 1048575, - 0x0153, 1048575, - 0x0155, 1048575, - 0x0157, 1048575, - 0x0159, 1048575, - 0x015b, 1048575, - 0x015d, 1048575, - 0x015f, 1048575, - 0x0161, 1048575, - 0x0163, 1048575, - 0x0165, 1048575, - 0x0167, 1048575, - 0x0169, 1048575, - 0x016b, 1048575, - 0x016d, 1048575, - 0x016f, 1048575, - 0x0171, 1048575, - 0x0173, 1048575, - 0x0175, 1048575, - 0x0177, 1048575, - 0x017a, 1048575, - 0x017c, 1048575, - 0x017e, 1048575, - 0x017f, 1048276, - 0x0180, 1048771, - 0x0183, 1048575, - 0x0185, 1048575, - 0x0188, 1048575, - 0x018c, 1048575, - 0x0192, 1048575, - 0x0195, 1048673, - 0x0199, 1048575, - 0x019a, 1048739, - 0x019e, 1048706, - 0x01a1, 1048575, - 0x01a3, 1048575, - 0x01a5, 1048575, - 0x01a8, 1048575, - 0x01ad, 1048575, - 0x01b0, 1048575, - 0x01b4, 1048575, - 0x01b6, 1048575, - 0x01b9, 1048575, - 0x01bd, 1048575, - 0x01bf, 1048632, - 0x01c5, 1048575, - 0x01c6, 1048574, - 0x01c8, 1048575, - 0x01c9, 1048574, - 0x01cb, 1048575, - 0x01cc, 1048574, - 0x01ce, 1048575, - 0x01d0, 1048575, - 0x01d2, 1048575, - 0x01d4, 1048575, - 0x01d6, 1048575, - 0x01d8, 1048575, - 0x01da, 1048575, - 0x01dc, 1048575, - 0x01dd, 1048497, - 0x01df, 1048575, - 0x01e1, 1048575, - 0x01e3, 1048575, - 0x01e5, 1048575, - 0x01e7, 1048575, - 0x01e9, 1048575, - 0x01eb, 1048575, - 0x01ed, 1048575, - 0x01ef, 1048575, - 0x01f2, 1048575, - 0x01f3, 1048574, - 0x01f5, 1048575, - 0x01f9, 1048575, - 0x01fb, 1048575, - 0x01fd, 1048575, - 0x01ff, 1048575, - 0x0201, 1048575, - 0x0203, 1048575, - 0x0205, 1048575, - 0x0207, 1048575, - 0x0209, 1048575, - 0x020b, 1048575, - 0x020d, 1048575, - 0x020f, 1048575, - 0x0211, 1048575, - 0x0213, 1048575, - 0x0215, 1048575, - 0x0217, 1048575, - 0x0219, 1048575, - 0x021b, 1048575, - 0x021d, 1048575, - 0x021f, 1048575, - 0x0223, 1048575, - 0x0225, 1048575, - 0x0227, 1048575, - 0x0229, 1048575, - 0x022b, 1048575, - 0x022d, 1048575, - 0x022f, 1048575, - 0x0231, 1048575, - 0x0233, 1048575, - 0x023c, 1048575, - 0x0242, 1048575, - 0x0247, 1048575, - 0x0249, 1048575, - 0x024b, 1048575, - 0x024d, 1048575, - 0x024f, 1048575, - 0x0250, 1059359, - 0x0251, 1059356, - 0x0252, 1059358, - 0x0253, 1048366, - 0x0254, 1048370, - 0x0259, 1048374, - 0x025b, 1048373, - 0x025c, 1090895, - 0x0260, 1048371, - 0x0261, 1090891, - 0x0263, 1048369, - 0x0265, 1090856, - 0x0266, 1090884, - 0x0268, 1048367, - 0x0269, 1048365, - 0x026b, 1059319, - 0x026c, 1090881, - 0x026f, 1048365, - 0x0271, 1059325, - 0x0272, 1048363, - 0x0275, 1048362, - 0x027d, 1059303, - 0x0280, 1048358, - 0x0283, 1048358, - 0x0287, 1090858, - 0x0288, 1048358, - 0x0289, 1048507, - 0x028c, 1048505, - 0x0292, 1048357, - 0x029e, 1090834, - 0x0345, 1048660, - 0x0371, 1048575, - 0x0373, 1048575, - 0x0377, 1048575, - 0x03ac, 1048538, - 0x03c2, 1048545, - 0x03cc, 1048512, - 0x03d0, 1048514, - 0x03d1, 1048519, - 0x03d5, 1048529, - 0x03d6, 1048522, - 0x03d7, 1048568, - 0x03d9, 1048575, - 0x03db, 1048575, - 0x03dd, 1048575, - 0x03df, 1048575, - 0x03e1, 1048575, - 0x03e3, 1048575, - 0x03e5, 1048575, - 0x03e7, 1048575, - 0x03e9, 1048575, - 0x03eb, 1048575, - 0x03ed, 1048575, - 0x03ef, 1048575, - 0x03f0, 1048490, - 0x03f1, 1048496, - 0x03f2, 1048583, - 0x03f3, 1048460, - 0x03f5, 1048480, - 0x03f8, 1048575, - 0x03fb, 1048575, - 0x0461, 1048575, - 0x0463, 1048575, - 0x0465, 1048575, - 0x0467, 1048575, - 0x0469, 1048575, - 0x046b, 1048575, - 0x046d, 1048575, - 0x046f, 1048575, - 0x0471, 1048575, - 0x0473, 1048575, - 0x0475, 1048575, - 0x0477, 1048575, - 0x0479, 1048575, - 0x047b, 1048575, - 0x047d, 1048575, - 0x047f, 1048575, - 0x0481, 1048575, - 0x048b, 1048575, - 0x048d, 1048575, - 0x048f, 1048575, - 0x0491, 1048575, - 0x0493, 1048575, - 0x0495, 1048575, - 0x0497, 1048575, - 0x0499, 1048575, - 0x049b, 1048575, - 0x049d, 1048575, - 0x049f, 1048575, - 0x04a1, 1048575, - 0x04a3, 1048575, - 0x04a5, 1048575, - 0x04a7, 1048575, - 0x04a9, 1048575, - 0x04ab, 1048575, - 0x04ad, 1048575, - 0x04af, 1048575, - 0x04b1, 1048575, - 0x04b3, 1048575, - 0x04b5, 1048575, - 0x04b7, 1048575, - 0x04b9, 1048575, - 0x04bb, 1048575, - 0x04bd, 1048575, - 0x04bf, 1048575, - 0x04c2, 1048575, - 0x04c4, 1048575, - 0x04c6, 1048575, - 0x04c8, 1048575, - 0x04ca, 1048575, - 0x04cc, 1048575, - 0x04ce, 1048575, - 0x04cf, 1048561, - 0x04d1, 1048575, - 0x04d3, 1048575, - 0x04d5, 1048575, - 0x04d7, 1048575, - 0x04d9, 1048575, - 0x04db, 1048575, - 0x04dd, 1048575, - 0x04df, 1048575, - 0x04e1, 1048575, - 0x04e3, 1048575, - 0x04e5, 1048575, - 0x04e7, 1048575, - 0x04e9, 1048575, - 0x04eb, 1048575, - 0x04ed, 1048575, - 0x04ef, 1048575, - 0x04f1, 1048575, - 0x04f3, 1048575, - 0x04f5, 1048575, - 0x04f7, 1048575, - 0x04f9, 1048575, - 0x04fb, 1048575, - 0x04fd, 1048575, - 0x04ff, 1048575, - 0x0501, 1048575, - 0x0503, 1048575, - 0x0505, 1048575, - 0x0507, 1048575, - 0x0509, 1048575, - 0x050b, 1048575, - 0x050d, 1048575, - 0x050f, 1048575, - 0x0511, 1048575, - 0x0513, 1048575, - 0x0515, 1048575, - 0x0517, 1048575, - 0x0519, 1048575, - 0x051b, 1048575, - 0x051d, 1048575, - 0x051f, 1048575, - 0x0521, 1048575, - 0x0523, 1048575, - 0x0525, 1048575, - 0x0527, 1048575, - 0x0529, 1048575, - 0x052b, 1048575, - 0x052d, 1048575, - 0x052f, 1048575, - 0x1d79, 1083908, - 0x1d7d, 1052390, - 0x1e01, 1048575, - 0x1e03, 1048575, - 0x1e05, 1048575, - 0x1e07, 1048575, - 0x1e09, 1048575, - 0x1e0b, 1048575, - 0x1e0d, 1048575, - 0x1e0f, 1048575, - 0x1e11, 1048575, - 0x1e13, 1048575, - 0x1e15, 1048575, - 0x1e17, 1048575, - 0x1e19, 1048575, - 0x1e1b, 1048575, - 0x1e1d, 1048575, - 0x1e1f, 1048575, - 0x1e21, 1048575, - 0x1e23, 1048575, - 0x1e25, 1048575, - 0x1e27, 1048575, - 0x1e29, 1048575, - 0x1e2b, 1048575, - 0x1e2d, 1048575, - 0x1e2f, 1048575, - 0x1e31, 1048575, - 0x1e33, 1048575, - 0x1e35, 1048575, - 0x1e37, 1048575, - 0x1e39, 1048575, - 0x1e3b, 1048575, - 0x1e3d, 1048575, - 0x1e3f, 1048575, - 0x1e41, 1048575, - 0x1e43, 1048575, - 0x1e45, 1048575, - 0x1e47, 1048575, - 0x1e49, 1048575, - 0x1e4b, 1048575, - 0x1e4d, 1048575, - 0x1e4f, 1048575, - 0x1e51, 1048575, - 0x1e53, 1048575, - 0x1e55, 1048575, - 0x1e57, 1048575, - 0x1e59, 1048575, - 0x1e5b, 1048575, - 0x1e5d, 1048575, - 0x1e5f, 1048575, - 0x1e61, 1048575, - 0x1e63, 1048575, - 0x1e65, 1048575, - 0x1e67, 1048575, - 0x1e69, 1048575, - 0x1e6b, 1048575, - 0x1e6d, 1048575, - 0x1e6f, 1048575, - 0x1e71, 1048575, - 0x1e73, 1048575, - 0x1e75, 1048575, - 0x1e77, 1048575, - 0x1e79, 1048575, - 0x1e7b, 1048575, - 0x1e7d, 1048575, - 0x1e7f, 1048575, - 0x1e81, 1048575, - 0x1e83, 1048575, - 0x1e85, 1048575, - 0x1e87, 1048575, - 0x1e89, 1048575, - 0x1e8b, 1048575, - 0x1e8d, 1048575, - 0x1e8f, 1048575, - 0x1e91, 1048575, - 0x1e93, 1048575, - 0x1e95, 1048575, - 0x1e9b, 1048517, - 0x1ea1, 1048575, - 0x1ea3, 1048575, - 0x1ea5, 1048575, - 0x1ea7, 1048575, - 0x1ea9, 1048575, - 0x1eab, 1048575, - 0x1ead, 1048575, - 0x1eaf, 1048575, - 0x1eb1, 1048575, - 0x1eb3, 1048575, - 0x1eb5, 1048575, - 0x1eb7, 1048575, - 0x1eb9, 1048575, - 0x1ebb, 1048575, - 0x1ebd, 1048575, - 0x1ebf, 1048575, - 0x1ec1, 1048575, - 0x1ec3, 1048575, - 0x1ec5, 1048575, - 0x1ec7, 1048575, - 0x1ec9, 1048575, - 0x1ecb, 1048575, - 0x1ecd, 1048575, - 0x1ecf, 1048575, - 0x1ed1, 1048575, - 0x1ed3, 1048575, - 0x1ed5, 1048575, - 0x1ed7, 1048575, - 0x1ed9, 1048575, - 0x1edb, 1048575, - 0x1edd, 1048575, - 0x1edf, 1048575, - 0x1ee1, 1048575, - 0x1ee3, 1048575, - 0x1ee5, 1048575, - 0x1ee7, 1048575, - 0x1ee9, 1048575, - 0x1eeb, 1048575, - 0x1eed, 1048575, - 0x1eef, 1048575, - 0x1ef1, 1048575, - 0x1ef3, 1048575, - 0x1ef5, 1048575, - 0x1ef7, 1048575, - 0x1ef9, 1048575, - 0x1efb, 1048575, - 0x1efd, 1048575, - 0x1eff, 1048575, - 0x1f51, 1048584, - 0x1f53, 1048584, - 0x1f55, 1048584, - 0x1f57, 1048584, - 0x1fb3, 1048585, - 0x1fbe, 1041371, - 0x1fc3, 1048585, - 0x1fe5, 1048583, - 0x1ff3, 1048585, - 0x214e, 1048548, - 0x2184, 1048575, - 0x2c61, 1048575, - 0x2c65, 1037781, - 0x2c66, 1037784, - 0x2c68, 1048575, - 0x2c6a, 1048575, - 0x2c6c, 1048575, - 0x2c73, 1048575, - 0x2c76, 1048575, - 0x2c81, 1048575, - 0x2c83, 1048575, - 0x2c85, 1048575, - 0x2c87, 1048575, - 0x2c89, 1048575, - 0x2c8b, 1048575, - 0x2c8d, 1048575, - 0x2c8f, 1048575, - 0x2c91, 1048575, - 0x2c93, 1048575, - 0x2c95, 1048575, - 0x2c97, 1048575, - 0x2c99, 1048575, - 0x2c9b, 1048575, - 0x2c9d, 1048575, - 0x2c9f, 1048575, - 0x2ca1, 1048575, - 0x2ca3, 1048575, - 0x2ca5, 1048575, - 0x2ca7, 1048575, - 0x2ca9, 1048575, - 0x2cab, 1048575, - 0x2cad, 1048575, - 0x2caf, 1048575, - 0x2cb1, 1048575, - 0x2cb3, 1048575, - 0x2cb5, 1048575, - 0x2cb7, 1048575, - 0x2cb9, 1048575, - 0x2cbb, 1048575, - 0x2cbd, 1048575, - 0x2cbf, 1048575, - 0x2cc1, 1048575, - 0x2cc3, 1048575, - 0x2cc5, 1048575, - 0x2cc7, 1048575, - 0x2cc9, 1048575, - 0x2ccb, 1048575, - 0x2ccd, 1048575, - 0x2ccf, 1048575, - 0x2cd1, 1048575, - 0x2cd3, 1048575, - 0x2cd5, 1048575, - 0x2cd7, 1048575, - 0x2cd9, 1048575, - 0x2cdb, 1048575, - 0x2cdd, 1048575, - 0x2cdf, 1048575, - 0x2ce1, 1048575, - 0x2ce3, 1048575, - 0x2cec, 1048575, - 0x2cee, 1048575, - 0x2cf3, 1048575, - 0x2d27, 1041312, - 0x2d2d, 1041312, - 0xa641, 1048575, - 0xa643, 1048575, - 0xa645, 1048575, - 0xa647, 1048575, - 0xa649, 1048575, - 0xa64b, 1048575, - 0xa64d, 1048575, - 0xa64f, 1048575, - 0xa651, 1048575, - 0xa653, 1048575, - 0xa655, 1048575, - 0xa657, 1048575, - 0xa659, 1048575, - 0xa65b, 1048575, - 0xa65d, 1048575, - 0xa65f, 1048575, - 0xa661, 1048575, - 0xa663, 1048575, - 0xa665, 1048575, - 0xa667, 1048575, - 0xa669, 1048575, - 0xa66b, 1048575, - 0xa66d, 1048575, - 0xa681, 1048575, - 0xa683, 1048575, - 0xa685, 1048575, - 0xa687, 1048575, - 0xa689, 1048575, - 0xa68b, 1048575, - 0xa68d, 1048575, - 0xa68f, 1048575, - 0xa691, 1048575, - 0xa693, 1048575, - 0xa695, 1048575, - 0xa697, 1048575, - 0xa699, 1048575, - 0xa69b, 1048575, - 0xa723, 1048575, - 0xa725, 1048575, - 0xa727, 1048575, - 0xa729, 1048575, - 0xa72b, 1048575, - 0xa72d, 1048575, - 0xa72f, 1048575, - 0xa733, 1048575, - 0xa735, 1048575, - 0xa737, 1048575, - 0xa739, 1048575, - 0xa73b, 1048575, - 0xa73d, 1048575, - 0xa73f, 1048575, - 0xa741, 1048575, - 0xa743, 1048575, - 0xa745, 1048575, - 0xa747, 1048575, - 0xa749, 1048575, - 0xa74b, 1048575, - 0xa74d, 1048575, - 0xa74f, 1048575, - 0xa751, 1048575, - 0xa753, 1048575, - 0xa755, 1048575, - 0xa757, 1048575, - 0xa759, 1048575, - 0xa75b, 1048575, - 0xa75d, 1048575, - 0xa75f, 1048575, - 0xa761, 1048575, - 0xa763, 1048575, - 0xa765, 1048575, - 0xa767, 1048575, - 0xa769, 1048575, - 0xa76b, 1048575, - 0xa76d, 1048575, - 0xa76f, 1048575, - 0xa77a, 1048575, - 0xa77c, 1048575, - 0xa77f, 1048575, - 0xa781, 1048575, - 0xa783, 1048575, - 0xa785, 1048575, - 0xa787, 1048575, - 0xa78c, 1048575, - 0xa791, 1048575, - 0xa793, 1048575, - 0xa797, 1048575, - 0xa799, 1048575, - 0xa79b, 1048575, - 0xa79d, 1048575, - 0xa79f, 1048575, - 0xa7a1, 1048575, - 0xa7a3, 1048575, - 0xa7a5, 1048575, - 0xa7a7, 1048575, - 0xa7a9, 1048575, -}; - -} // !namespace - -char32_t toupper(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, toupperr, nelem (toupperr) / 3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = rbsearch(c, touppers, nelem (touppers) / 2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -namespace { - -const char32_t tolowerr[] = { - 0x0041, 0x005a, 1048608, - 0x00c0, 0x00d6, 1048608, - 0x00d8, 0x00de, 1048608, - 0x0189, 0x018a, 1048781, - 0x01b1, 0x01b2, 1048793, - 0x0388, 0x038a, 1048613, - 0x038e, 0x038f, 1048639, - 0x0391, 0x03a1, 1048608, - 0x03a3, 0x03ab, 1048608, - 0x03fd, 0x03ff, 1048446, - 0x0400, 0x040f, 1048656, - 0x0410, 0x042f, 1048608, - 0x0531, 0x0556, 1048624, - 0x10a0, 0x10c5, 1055840, - 0x1f08, 0x1f0f, 1048568, - 0x1f18, 0x1f1d, 1048568, - 0x1f28, 0x1f2f, 1048568, - 0x1f38, 0x1f3f, 1048568, - 0x1f48, 0x1f4d, 1048568, - 0x1f68, 0x1f6f, 1048568, - 0x1f88, 0x1f8f, 1048568, - 0x1f98, 0x1f9f, 1048568, - 0x1fa8, 0x1faf, 1048568, - 0x1fb8, 0x1fb9, 1048568, - 0x1fba, 0x1fbb, 1048502, - 0x1fc8, 0x1fcb, 1048490, - 0x1fd8, 0x1fd9, 1048568, - 0x1fda, 0x1fdb, 1048476, - 0x1fe8, 0x1fe9, 1048568, - 0x1fea, 0x1feb, 1048464, - 0x1ff8, 0x1ff9, 1048448, - 0x1ffa, 0x1ffb, 1048450, - 0x2160, 0x216f, 1048592, - 0x24b6, 0x24cf, 1048602, - 0x2c00, 0x2c2e, 1048624, - 0x2c7e, 0x2c7f, 1037761, - 0xff21, 0xff3a, 1048608, - 0x10400, 0x10427, 1048616, - 0x118a0, 0x118bf, 1048608, -}; - -} // !namespace - -namespace { - -const char32_t tolowers[] = { - 0x0100, 1048577, - 0x0102, 1048577, - 0x0104, 1048577, - 0x0106, 1048577, - 0x0108, 1048577, - 0x010a, 1048577, - 0x010c, 1048577, - 0x010e, 1048577, - 0x0110, 1048577, - 0x0112, 1048577, - 0x0114, 1048577, - 0x0116, 1048577, - 0x0118, 1048577, - 0x011a, 1048577, - 0x011c, 1048577, - 0x011e, 1048577, - 0x0120, 1048577, - 0x0122, 1048577, - 0x0124, 1048577, - 0x0126, 1048577, - 0x0128, 1048577, - 0x012a, 1048577, - 0x012c, 1048577, - 0x012e, 1048577, - 0x0130, 1048377, - 0x0132, 1048577, - 0x0134, 1048577, - 0x0136, 1048577, - 0x0139, 1048577, - 0x013b, 1048577, - 0x013d, 1048577, - 0x013f, 1048577, - 0x0141, 1048577, - 0x0143, 1048577, - 0x0145, 1048577, - 0x0147, 1048577, - 0x014a, 1048577, - 0x014c, 1048577, - 0x014e, 1048577, - 0x0150, 1048577, - 0x0152, 1048577, - 0x0154, 1048577, - 0x0156, 1048577, - 0x0158, 1048577, - 0x015a, 1048577, - 0x015c, 1048577, - 0x015e, 1048577, - 0x0160, 1048577, - 0x0162, 1048577, - 0x0164, 1048577, - 0x0166, 1048577, - 0x0168, 1048577, - 0x016a, 1048577, - 0x016c, 1048577, - 0x016e, 1048577, - 0x0170, 1048577, - 0x0172, 1048577, - 0x0174, 1048577, - 0x0176, 1048577, - 0x0178, 1048455, - 0x0179, 1048577, - 0x017b, 1048577, - 0x017d, 1048577, - 0x0181, 1048786, - 0x0182, 1048577, - 0x0184, 1048577, - 0x0186, 1048782, - 0x0187, 1048577, - 0x018b, 1048577, - 0x018e, 1048655, - 0x018f, 1048778, - 0x0190, 1048779, - 0x0191, 1048577, - 0x0193, 1048781, - 0x0194, 1048783, - 0x0196, 1048787, - 0x0197, 1048785, - 0x0198, 1048577, - 0x019c, 1048787, - 0x019d, 1048789, - 0x019f, 1048790, - 0x01a0, 1048577, - 0x01a2, 1048577, - 0x01a4, 1048577, - 0x01a6, 1048794, - 0x01a7, 1048577, - 0x01a9, 1048794, - 0x01ac, 1048577, - 0x01ae, 1048794, - 0x01af, 1048577, - 0x01b3, 1048577, - 0x01b5, 1048577, - 0x01b7, 1048795, - 0x01b8, 1048577, - 0x01bc, 1048577, - 0x01c4, 1048578, - 0x01c5, 1048577, - 0x01c7, 1048578, - 0x01c8, 1048577, - 0x01ca, 1048578, - 0x01cb, 1048577, - 0x01cd, 1048577, - 0x01cf, 1048577, - 0x01d1, 1048577, - 0x01d3, 1048577, - 0x01d5, 1048577, - 0x01d7, 1048577, - 0x01d9, 1048577, - 0x01db, 1048577, - 0x01de, 1048577, - 0x01e0, 1048577, - 0x01e2, 1048577, - 0x01e4, 1048577, - 0x01e6, 1048577, - 0x01e8, 1048577, - 0x01ea, 1048577, - 0x01ec, 1048577, - 0x01ee, 1048577, - 0x01f1, 1048578, - 0x01f2, 1048577, - 0x01f4, 1048577, - 0x01f6, 1048479, - 0x01f7, 1048520, - 0x01f8, 1048577, - 0x01fa, 1048577, - 0x01fc, 1048577, - 0x01fe, 1048577, - 0x0200, 1048577, - 0x0202, 1048577, - 0x0204, 1048577, - 0x0206, 1048577, - 0x0208, 1048577, - 0x020a, 1048577, - 0x020c, 1048577, - 0x020e, 1048577, - 0x0210, 1048577, - 0x0212, 1048577, - 0x0214, 1048577, - 0x0216, 1048577, - 0x0218, 1048577, - 0x021a, 1048577, - 0x021c, 1048577, - 0x021e, 1048577, - 0x0220, 1048446, - 0x0222, 1048577, - 0x0224, 1048577, - 0x0226, 1048577, - 0x0228, 1048577, - 0x022a, 1048577, - 0x022c, 1048577, - 0x022e, 1048577, - 0x0230, 1048577, - 0x0232, 1048577, - 0x023a, 1059371, - 0x023b, 1048577, - 0x023d, 1048413, - 0x023e, 1059368, - 0x0241, 1048577, - 0x0243, 1048381, - 0x0244, 1048645, - 0x0245, 1048647, - 0x0246, 1048577, - 0x0248, 1048577, - 0x024a, 1048577, - 0x024c, 1048577, - 0x024e, 1048577, - 0x0370, 1048577, - 0x0372, 1048577, - 0x0376, 1048577, - 0x037f, 1048692, - 0x0386, 1048614, - 0x038c, 1048640, - 0x03cf, 1048584, - 0x03d8, 1048577, - 0x03da, 1048577, - 0x03dc, 1048577, - 0x03de, 1048577, - 0x03e0, 1048577, - 0x03e2, 1048577, - 0x03e4, 1048577, - 0x03e6, 1048577, - 0x03e8, 1048577, - 0x03ea, 1048577, - 0x03ec, 1048577, - 0x03ee, 1048577, - 0x03f4, 1048516, - 0x03f7, 1048577, - 0x03f9, 1048569, - 0x03fa, 1048577, - 0x0460, 1048577, - 0x0462, 1048577, - 0x0464, 1048577, - 0x0466, 1048577, - 0x0468, 1048577, - 0x046a, 1048577, - 0x046c, 1048577, - 0x046e, 1048577, - 0x0470, 1048577, - 0x0472, 1048577, - 0x0474, 1048577, - 0x0476, 1048577, - 0x0478, 1048577, - 0x047a, 1048577, - 0x047c, 1048577, - 0x047e, 1048577, - 0x0480, 1048577, - 0x048a, 1048577, - 0x048c, 1048577, - 0x048e, 1048577, - 0x0490, 1048577, - 0x0492, 1048577, - 0x0494, 1048577, - 0x0496, 1048577, - 0x0498, 1048577, - 0x049a, 1048577, - 0x049c, 1048577, - 0x049e, 1048577, - 0x04a0, 1048577, - 0x04a2, 1048577, - 0x04a4, 1048577, - 0x04a6, 1048577, - 0x04a8, 1048577, - 0x04aa, 1048577, - 0x04ac, 1048577, - 0x04ae, 1048577, - 0x04b0, 1048577, - 0x04b2, 1048577, - 0x04b4, 1048577, - 0x04b6, 1048577, - 0x04b8, 1048577, - 0x04ba, 1048577, - 0x04bc, 1048577, - 0x04be, 1048577, - 0x04c0, 1048591, - 0x04c1, 1048577, - 0x04c3, 1048577, - 0x04c5, 1048577, - 0x04c7, 1048577, - 0x04c9, 1048577, - 0x04cb, 1048577, - 0x04cd, 1048577, - 0x04d0, 1048577, - 0x04d2, 1048577, - 0x04d4, 1048577, - 0x04d6, 1048577, - 0x04d8, 1048577, - 0x04da, 1048577, - 0x04dc, 1048577, - 0x04de, 1048577, - 0x04e0, 1048577, - 0x04e2, 1048577, - 0x04e4, 1048577, - 0x04e6, 1048577, - 0x04e8, 1048577, - 0x04ea, 1048577, - 0x04ec, 1048577, - 0x04ee, 1048577, - 0x04f0, 1048577, - 0x04f2, 1048577, - 0x04f4, 1048577, - 0x04f6, 1048577, - 0x04f8, 1048577, - 0x04fa, 1048577, - 0x04fc, 1048577, - 0x04fe, 1048577, - 0x0500, 1048577, - 0x0502, 1048577, - 0x0504, 1048577, - 0x0506, 1048577, - 0x0508, 1048577, - 0x050a, 1048577, - 0x050c, 1048577, - 0x050e, 1048577, - 0x0510, 1048577, - 0x0512, 1048577, - 0x0514, 1048577, - 0x0516, 1048577, - 0x0518, 1048577, - 0x051a, 1048577, - 0x051c, 1048577, - 0x051e, 1048577, - 0x0520, 1048577, - 0x0522, 1048577, - 0x0524, 1048577, - 0x0526, 1048577, - 0x0528, 1048577, - 0x052a, 1048577, - 0x052c, 1048577, - 0x052e, 1048577, - 0x10c7, 1055840, - 0x10cd, 1055840, - 0x1e00, 1048577, - 0x1e02, 1048577, - 0x1e04, 1048577, - 0x1e06, 1048577, - 0x1e08, 1048577, - 0x1e0a, 1048577, - 0x1e0c, 1048577, - 0x1e0e, 1048577, - 0x1e10, 1048577, - 0x1e12, 1048577, - 0x1e14, 1048577, - 0x1e16, 1048577, - 0x1e18, 1048577, - 0x1e1a, 1048577, - 0x1e1c, 1048577, - 0x1e1e, 1048577, - 0x1e20, 1048577, - 0x1e22, 1048577, - 0x1e24, 1048577, - 0x1e26, 1048577, - 0x1e28, 1048577, - 0x1e2a, 1048577, - 0x1e2c, 1048577, - 0x1e2e, 1048577, - 0x1e30, 1048577, - 0x1e32, 1048577, - 0x1e34, 1048577, - 0x1e36, 1048577, - 0x1e38, 1048577, - 0x1e3a, 1048577, - 0x1e3c, 1048577, - 0x1e3e, 1048577, - 0x1e40, 1048577, - 0x1e42, 1048577, - 0x1e44, 1048577, - 0x1e46, 1048577, - 0x1e48, 1048577, - 0x1e4a, 1048577, - 0x1e4c, 1048577, - 0x1e4e, 1048577, - 0x1e50, 1048577, - 0x1e52, 1048577, - 0x1e54, 1048577, - 0x1e56, 1048577, - 0x1e58, 1048577, - 0x1e5a, 1048577, - 0x1e5c, 1048577, - 0x1e5e, 1048577, - 0x1e60, 1048577, - 0x1e62, 1048577, - 0x1e64, 1048577, - 0x1e66, 1048577, - 0x1e68, 1048577, - 0x1e6a, 1048577, - 0x1e6c, 1048577, - 0x1e6e, 1048577, - 0x1e70, 1048577, - 0x1e72, 1048577, - 0x1e74, 1048577, - 0x1e76, 1048577, - 0x1e78, 1048577, - 0x1e7a, 1048577, - 0x1e7c, 1048577, - 0x1e7e, 1048577, - 0x1e80, 1048577, - 0x1e82, 1048577, - 0x1e84, 1048577, - 0x1e86, 1048577, - 0x1e88, 1048577, - 0x1e8a, 1048577, - 0x1e8c, 1048577, - 0x1e8e, 1048577, - 0x1e90, 1048577, - 0x1e92, 1048577, - 0x1e94, 1048577, - 0x1e9e, 1040961, - 0x1ea0, 1048577, - 0x1ea2, 1048577, - 0x1ea4, 1048577, - 0x1ea6, 1048577, - 0x1ea8, 1048577, - 0x1eaa, 1048577, - 0x1eac, 1048577, - 0x1eae, 1048577, - 0x1eb0, 1048577, - 0x1eb2, 1048577, - 0x1eb4, 1048577, - 0x1eb6, 1048577, - 0x1eb8, 1048577, - 0x1eba, 1048577, - 0x1ebc, 1048577, - 0x1ebe, 1048577, - 0x1ec0, 1048577, - 0x1ec2, 1048577, - 0x1ec4, 1048577, - 0x1ec6, 1048577, - 0x1ec8, 1048577, - 0x1eca, 1048577, - 0x1ecc, 1048577, - 0x1ece, 1048577, - 0x1ed0, 1048577, - 0x1ed2, 1048577, - 0x1ed4, 1048577, - 0x1ed6, 1048577, - 0x1ed8, 1048577, - 0x1eda, 1048577, - 0x1edc, 1048577, - 0x1ede, 1048577, - 0x1ee0, 1048577, - 0x1ee2, 1048577, - 0x1ee4, 1048577, - 0x1ee6, 1048577, - 0x1ee8, 1048577, - 0x1eea, 1048577, - 0x1eec, 1048577, - 0x1eee, 1048577, - 0x1ef0, 1048577, - 0x1ef2, 1048577, - 0x1ef4, 1048577, - 0x1ef6, 1048577, - 0x1ef8, 1048577, - 0x1efa, 1048577, - 0x1efc, 1048577, - 0x1efe, 1048577, - 0x1f59, 1048568, - 0x1f5b, 1048568, - 0x1f5d, 1048568, - 0x1f5f, 1048568, - 0x1fbc, 1048567, - 0x1fcc, 1048567, - 0x1fec, 1048569, - 0x1ffc, 1048567, - 0x2126, 1041059, - 0x212a, 1040193, - 0x212b, 1040314, - 0x2132, 1048604, - 0x2183, 1048577, - 0x2c60, 1048577, - 0x2c62, 1037833, - 0x2c63, 1044762, - 0x2c64, 1037849, - 0x2c67, 1048577, - 0x2c69, 1048577, - 0x2c6b, 1048577, - 0x2c6d, 1037796, - 0x2c6e, 1037827, - 0x2c6f, 1037793, - 0x2c70, 1037794, - 0x2c72, 1048577, - 0x2c75, 1048577, - 0x2c80, 1048577, - 0x2c82, 1048577, - 0x2c84, 1048577, - 0x2c86, 1048577, - 0x2c88, 1048577, - 0x2c8a, 1048577, - 0x2c8c, 1048577, - 0x2c8e, 1048577, - 0x2c90, 1048577, - 0x2c92, 1048577, - 0x2c94, 1048577, - 0x2c96, 1048577, - 0x2c98, 1048577, - 0x2c9a, 1048577, - 0x2c9c, 1048577, - 0x2c9e, 1048577, - 0x2ca0, 1048577, - 0x2ca2, 1048577, - 0x2ca4, 1048577, - 0x2ca6, 1048577, - 0x2ca8, 1048577, - 0x2caa, 1048577, - 0x2cac, 1048577, - 0x2cae, 1048577, - 0x2cb0, 1048577, - 0x2cb2, 1048577, - 0x2cb4, 1048577, - 0x2cb6, 1048577, - 0x2cb8, 1048577, - 0x2cba, 1048577, - 0x2cbc, 1048577, - 0x2cbe, 1048577, - 0x2cc0, 1048577, - 0x2cc2, 1048577, - 0x2cc4, 1048577, - 0x2cc6, 1048577, - 0x2cc8, 1048577, - 0x2cca, 1048577, - 0x2ccc, 1048577, - 0x2cce, 1048577, - 0x2cd0, 1048577, - 0x2cd2, 1048577, - 0x2cd4, 1048577, - 0x2cd6, 1048577, - 0x2cd8, 1048577, - 0x2cda, 1048577, - 0x2cdc, 1048577, - 0x2cde, 1048577, - 0x2ce0, 1048577, - 0x2ce2, 1048577, - 0x2ceb, 1048577, - 0x2ced, 1048577, - 0x2cf2, 1048577, - 0xa640, 1048577, - 0xa642, 1048577, - 0xa644, 1048577, - 0xa646, 1048577, - 0xa648, 1048577, - 0xa64a, 1048577, - 0xa64c, 1048577, - 0xa64e, 1048577, - 0xa650, 1048577, - 0xa652, 1048577, - 0xa654, 1048577, - 0xa656, 1048577, - 0xa658, 1048577, - 0xa65a, 1048577, - 0xa65c, 1048577, - 0xa65e, 1048577, - 0xa660, 1048577, - 0xa662, 1048577, - 0xa664, 1048577, - 0xa666, 1048577, - 0xa668, 1048577, - 0xa66a, 1048577, - 0xa66c, 1048577, - 0xa680, 1048577, - 0xa682, 1048577, - 0xa684, 1048577, - 0xa686, 1048577, - 0xa688, 1048577, - 0xa68a, 1048577, - 0xa68c, 1048577, - 0xa68e, 1048577, - 0xa690, 1048577, - 0xa692, 1048577, - 0xa694, 1048577, - 0xa696, 1048577, - 0xa698, 1048577, - 0xa69a, 1048577, - 0xa722, 1048577, - 0xa724, 1048577, - 0xa726, 1048577, - 0xa728, 1048577, - 0xa72a, 1048577, - 0xa72c, 1048577, - 0xa72e, 1048577, - 0xa732, 1048577, - 0xa734, 1048577, - 0xa736, 1048577, - 0xa738, 1048577, - 0xa73a, 1048577, - 0xa73c, 1048577, - 0xa73e, 1048577, - 0xa740, 1048577, - 0xa742, 1048577, - 0xa744, 1048577, - 0xa746, 1048577, - 0xa748, 1048577, - 0xa74a, 1048577, - 0xa74c, 1048577, - 0xa74e, 1048577, - 0xa750, 1048577, - 0xa752, 1048577, - 0xa754, 1048577, - 0xa756, 1048577, - 0xa758, 1048577, - 0xa75a, 1048577, - 0xa75c, 1048577, - 0xa75e, 1048577, - 0xa760, 1048577, - 0xa762, 1048577, - 0xa764, 1048577, - 0xa766, 1048577, - 0xa768, 1048577, - 0xa76a, 1048577, - 0xa76c, 1048577, - 0xa76e, 1048577, - 0xa779, 1048577, - 0xa77b, 1048577, - 0xa77d, 1013244, - 0xa77e, 1048577, - 0xa780, 1048577, - 0xa782, 1048577, - 0xa784, 1048577, - 0xa786, 1048577, - 0xa78b, 1048577, - 0xa78d, 1006296, - 0xa790, 1048577, - 0xa792, 1048577, - 0xa796, 1048577, - 0xa798, 1048577, - 0xa79a, 1048577, - 0xa79c, 1048577, - 0xa79e, 1048577, - 0xa7a0, 1048577, - 0xa7a2, 1048577, - 0xa7a4, 1048577, - 0xa7a6, 1048577, - 0xa7a8, 1048577, - 0xa7aa, 1006268, - 0xa7ab, 1006257, - 0xa7ac, 1006261, - 0xa7ad, 1006271, - 0xa7b0, 1006318, - 0xa7b1, 1006294, -}; - -} // !namespace - -char32_t tolower(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, tolowerr, nelem (tolowerr) / 3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = rbsearch(c, tolowers, nelem (tolowers) / 2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -namespace { - -const char32_t totitler[] = { - 0x0061, 0x007a, 1048544, - 0x00e0, 0x00f6, 1048544, - 0x00f8, 0x00fe, 1048544, - 0x023f, 0x0240, 1059391, - 0x0256, 0x0257, 1048371, - 0x028a, 0x028b, 1048359, - 0x037b, 0x037d, 1048706, - 0x03ad, 0x03af, 1048539, - 0x03b1, 0x03c1, 1048544, - 0x03c3, 0x03cb, 1048544, - 0x03cd, 0x03ce, 1048513, - 0x0430, 0x044f, 1048544, - 0x0450, 0x045f, 1048496, - 0x0561, 0x0586, 1048528, - 0x1f00, 0x1f07, 1048584, - 0x1f10, 0x1f15, 1048584, - 0x1f20, 0x1f27, 1048584, - 0x1f30, 0x1f37, 1048584, - 0x1f40, 0x1f45, 1048584, - 0x1f60, 0x1f67, 1048584, - 0x1f70, 0x1f71, 1048650, - 0x1f72, 0x1f75, 1048662, - 0x1f76, 0x1f77, 1048676, - 0x1f78, 0x1f79, 1048704, - 0x1f7a, 0x1f7b, 1048688, - 0x1f7c, 0x1f7d, 1048702, - 0x1f80, 0x1f87, 1048584, - 0x1f90, 0x1f97, 1048584, - 0x1fa0, 0x1fa7, 1048584, - 0x1fb0, 0x1fb1, 1048584, - 0x1fd0, 0x1fd1, 1048584, - 0x1fe0, 0x1fe1, 1048584, - 0x2170, 0x217f, 1048560, - 0x24d0, 0x24e9, 1048550, - 0x2c30, 0x2c5e, 1048528, - 0x2d00, 0x2d25, 1041312, - 0xff41, 0xff5a, 1048544, - 0x10428, 0x1044f, 1048536, - 0x118c0, 0x118df, 1048544, -}; - -} // !namespace - -namespace { - -const char32_t totitles[] = { - 0x00b5, 1049319, - 0x00ff, 1048697, - 0x0101, 1048575, - 0x0103, 1048575, - 0x0105, 1048575, - 0x0107, 1048575, - 0x0109, 1048575, - 0x010b, 1048575, - 0x010d, 1048575, - 0x010f, 1048575, - 0x0111, 1048575, - 0x0113, 1048575, - 0x0115, 1048575, - 0x0117, 1048575, - 0x0119, 1048575, - 0x011b, 1048575, - 0x011d, 1048575, - 0x011f, 1048575, - 0x0121, 1048575, - 0x0123, 1048575, - 0x0125, 1048575, - 0x0127, 1048575, - 0x0129, 1048575, - 0x012b, 1048575, - 0x012d, 1048575, - 0x012f, 1048575, - 0x0131, 1048344, - 0x0133, 1048575, - 0x0135, 1048575, - 0x0137, 1048575, - 0x013a, 1048575, - 0x013c, 1048575, - 0x013e, 1048575, - 0x0140, 1048575, - 0x0142, 1048575, - 0x0144, 1048575, - 0x0146, 1048575, - 0x0148, 1048575, - 0x014b, 1048575, - 0x014d, 1048575, - 0x014f, 1048575, - 0x0151, 1048575, - 0x0153, 1048575, - 0x0155, 1048575, - 0x0157, 1048575, - 0x0159, 1048575, - 0x015b, 1048575, - 0x015d, 1048575, - 0x015f, 1048575, - 0x0161, 1048575, - 0x0163, 1048575, - 0x0165, 1048575, - 0x0167, 1048575, - 0x0169, 1048575, - 0x016b, 1048575, - 0x016d, 1048575, - 0x016f, 1048575, - 0x0171, 1048575, - 0x0173, 1048575, - 0x0175, 1048575, - 0x0177, 1048575, - 0x017a, 1048575, - 0x017c, 1048575, - 0x017e, 1048575, - 0x017f, 1048276, - 0x0180, 1048771, - 0x0183, 1048575, - 0x0185, 1048575, - 0x0188, 1048575, - 0x018c, 1048575, - 0x0192, 1048575, - 0x0195, 1048673, - 0x0199, 1048575, - 0x019a, 1048739, - 0x019e, 1048706, - 0x01a1, 1048575, - 0x01a3, 1048575, - 0x01a5, 1048575, - 0x01a8, 1048575, - 0x01ad, 1048575, - 0x01b0, 1048575, - 0x01b4, 1048575, - 0x01b6, 1048575, - 0x01b9, 1048575, - 0x01bd, 1048575, - 0x01bf, 1048632, - 0x01c4, 1048577, - 0x01c6, 1048575, - 0x01c7, 1048577, - 0x01c9, 1048575, - 0x01ca, 1048577, - 0x01cc, 1048575, - 0x01ce, 1048575, - 0x01d0, 1048575, - 0x01d2, 1048575, - 0x01d4, 1048575, - 0x01d6, 1048575, - 0x01d8, 1048575, - 0x01da, 1048575, - 0x01dc, 1048575, - 0x01dd, 1048497, - 0x01df, 1048575, - 0x01e1, 1048575, - 0x01e3, 1048575, - 0x01e5, 1048575, - 0x01e7, 1048575, - 0x01e9, 1048575, - 0x01eb, 1048575, - 0x01ed, 1048575, - 0x01ef, 1048575, - 0x01f1, 1048577, - 0x01f3, 1048575, - 0x01f5, 1048575, - 0x01f9, 1048575, - 0x01fb, 1048575, - 0x01fd, 1048575, - 0x01ff, 1048575, - 0x0201, 1048575, - 0x0203, 1048575, - 0x0205, 1048575, - 0x0207, 1048575, - 0x0209, 1048575, - 0x020b, 1048575, - 0x020d, 1048575, - 0x020f, 1048575, - 0x0211, 1048575, - 0x0213, 1048575, - 0x0215, 1048575, - 0x0217, 1048575, - 0x0219, 1048575, - 0x021b, 1048575, - 0x021d, 1048575, - 0x021f, 1048575, - 0x0223, 1048575, - 0x0225, 1048575, - 0x0227, 1048575, - 0x0229, 1048575, - 0x022b, 1048575, - 0x022d, 1048575, - 0x022f, 1048575, - 0x0231, 1048575, - 0x0233, 1048575, - 0x023c, 1048575, - 0x0242, 1048575, - 0x0247, 1048575, - 0x0249, 1048575, - 0x024b, 1048575, - 0x024d, 1048575, - 0x024f, 1048575, - 0x0250, 1059359, - 0x0251, 1059356, - 0x0252, 1059358, - 0x0253, 1048366, - 0x0254, 1048370, - 0x0259, 1048374, - 0x025b, 1048373, - 0x025c, 1090895, - 0x0260, 1048371, - 0x0261, 1090891, - 0x0263, 1048369, - 0x0265, 1090856, - 0x0266, 1090884, - 0x0268, 1048367, - 0x0269, 1048365, - 0x026b, 1059319, - 0x026c, 1090881, - 0x026f, 1048365, - 0x0271, 1059325, - 0x0272, 1048363, - 0x0275, 1048362, - 0x027d, 1059303, - 0x0280, 1048358, - 0x0283, 1048358, - 0x0287, 1090858, - 0x0288, 1048358, - 0x0289, 1048507, - 0x028c, 1048505, - 0x0292, 1048357, - 0x029e, 1090834, - 0x0345, 1048660, - 0x0371, 1048575, - 0x0373, 1048575, - 0x0377, 1048575, - 0x03ac, 1048538, - 0x03c2, 1048545, - 0x03cc, 1048512, - 0x03d0, 1048514, - 0x03d1, 1048519, - 0x03d5, 1048529, - 0x03d6, 1048522, - 0x03d7, 1048568, - 0x03d9, 1048575, - 0x03db, 1048575, - 0x03dd, 1048575, - 0x03df, 1048575, - 0x03e1, 1048575, - 0x03e3, 1048575, - 0x03e5, 1048575, - 0x03e7, 1048575, - 0x03e9, 1048575, - 0x03eb, 1048575, - 0x03ed, 1048575, - 0x03ef, 1048575, - 0x03f0, 1048490, - 0x03f1, 1048496, - 0x03f2, 1048583, - 0x03f3, 1048460, - 0x03f5, 1048480, - 0x03f8, 1048575, - 0x03fb, 1048575, - 0x0461, 1048575, - 0x0463, 1048575, - 0x0465, 1048575, - 0x0467, 1048575, - 0x0469, 1048575, - 0x046b, 1048575, - 0x046d, 1048575, - 0x046f, 1048575, - 0x0471, 1048575, - 0x0473, 1048575, - 0x0475, 1048575, - 0x0477, 1048575, - 0x0479, 1048575, - 0x047b, 1048575, - 0x047d, 1048575, - 0x047f, 1048575, - 0x0481, 1048575, - 0x048b, 1048575, - 0x048d, 1048575, - 0x048f, 1048575, - 0x0491, 1048575, - 0x0493, 1048575, - 0x0495, 1048575, - 0x0497, 1048575, - 0x0499, 1048575, - 0x049b, 1048575, - 0x049d, 1048575, - 0x049f, 1048575, - 0x04a1, 1048575, - 0x04a3, 1048575, - 0x04a5, 1048575, - 0x04a7, 1048575, - 0x04a9, 1048575, - 0x04ab, 1048575, - 0x04ad, 1048575, - 0x04af, 1048575, - 0x04b1, 1048575, - 0x04b3, 1048575, - 0x04b5, 1048575, - 0x04b7, 1048575, - 0x04b9, 1048575, - 0x04bb, 1048575, - 0x04bd, 1048575, - 0x04bf, 1048575, - 0x04c2, 1048575, - 0x04c4, 1048575, - 0x04c6, 1048575, - 0x04c8, 1048575, - 0x04ca, 1048575, - 0x04cc, 1048575, - 0x04ce, 1048575, - 0x04cf, 1048561, - 0x04d1, 1048575, - 0x04d3, 1048575, - 0x04d5, 1048575, - 0x04d7, 1048575, - 0x04d9, 1048575, - 0x04db, 1048575, - 0x04dd, 1048575, - 0x04df, 1048575, - 0x04e1, 1048575, - 0x04e3, 1048575, - 0x04e5, 1048575, - 0x04e7, 1048575, - 0x04e9, 1048575, - 0x04eb, 1048575, - 0x04ed, 1048575, - 0x04ef, 1048575, - 0x04f1, 1048575, - 0x04f3, 1048575, - 0x04f5, 1048575, - 0x04f7, 1048575, - 0x04f9, 1048575, - 0x04fb, 1048575, - 0x04fd, 1048575, - 0x04ff, 1048575, - 0x0501, 1048575, - 0x0503, 1048575, - 0x0505, 1048575, - 0x0507, 1048575, - 0x0509, 1048575, - 0x050b, 1048575, - 0x050d, 1048575, - 0x050f, 1048575, - 0x0511, 1048575, - 0x0513, 1048575, - 0x0515, 1048575, - 0x0517, 1048575, - 0x0519, 1048575, - 0x051b, 1048575, - 0x051d, 1048575, - 0x051f, 1048575, - 0x0521, 1048575, - 0x0523, 1048575, - 0x0525, 1048575, - 0x0527, 1048575, - 0x0529, 1048575, - 0x052b, 1048575, - 0x052d, 1048575, - 0x052f, 1048575, - 0x1d79, 1083908, - 0x1d7d, 1052390, - 0x1e01, 1048575, - 0x1e03, 1048575, - 0x1e05, 1048575, - 0x1e07, 1048575, - 0x1e09, 1048575, - 0x1e0b, 1048575, - 0x1e0d, 1048575, - 0x1e0f, 1048575, - 0x1e11, 1048575, - 0x1e13, 1048575, - 0x1e15, 1048575, - 0x1e17, 1048575, - 0x1e19, 1048575, - 0x1e1b, 1048575, - 0x1e1d, 1048575, - 0x1e1f, 1048575, - 0x1e21, 1048575, - 0x1e23, 1048575, - 0x1e25, 1048575, - 0x1e27, 1048575, - 0x1e29, 1048575, - 0x1e2b, 1048575, - 0x1e2d, 1048575, - 0x1e2f, 1048575, - 0x1e31, 1048575, - 0x1e33, 1048575, - 0x1e35, 1048575, - 0x1e37, 1048575, - 0x1e39, 1048575, - 0x1e3b, 1048575, - 0x1e3d, 1048575, - 0x1e3f, 1048575, - 0x1e41, 1048575, - 0x1e43, 1048575, - 0x1e45, 1048575, - 0x1e47, 1048575, - 0x1e49, 1048575, - 0x1e4b, 1048575, - 0x1e4d, 1048575, - 0x1e4f, 1048575, - 0x1e51, 1048575, - 0x1e53, 1048575, - 0x1e55, 1048575, - 0x1e57, 1048575, - 0x1e59, 1048575, - 0x1e5b, 1048575, - 0x1e5d, 1048575, - 0x1e5f, 1048575, - 0x1e61, 1048575, - 0x1e63, 1048575, - 0x1e65, 1048575, - 0x1e67, 1048575, - 0x1e69, 1048575, - 0x1e6b, 1048575, - 0x1e6d, 1048575, - 0x1e6f, 1048575, - 0x1e71, 1048575, - 0x1e73, 1048575, - 0x1e75, 1048575, - 0x1e77, 1048575, - 0x1e79, 1048575, - 0x1e7b, 1048575, - 0x1e7d, 1048575, - 0x1e7f, 1048575, - 0x1e81, 1048575, - 0x1e83, 1048575, - 0x1e85, 1048575, - 0x1e87, 1048575, - 0x1e89, 1048575, - 0x1e8b, 1048575, - 0x1e8d, 1048575, - 0x1e8f, 1048575, - 0x1e91, 1048575, - 0x1e93, 1048575, - 0x1e95, 1048575, - 0x1e9b, 1048517, - 0x1ea1, 1048575, - 0x1ea3, 1048575, - 0x1ea5, 1048575, - 0x1ea7, 1048575, - 0x1ea9, 1048575, - 0x1eab, 1048575, - 0x1ead, 1048575, - 0x1eaf, 1048575, - 0x1eb1, 1048575, - 0x1eb3, 1048575, - 0x1eb5, 1048575, - 0x1eb7, 1048575, - 0x1eb9, 1048575, - 0x1ebb, 1048575, - 0x1ebd, 1048575, - 0x1ebf, 1048575, - 0x1ec1, 1048575, - 0x1ec3, 1048575, - 0x1ec5, 1048575, - 0x1ec7, 1048575, - 0x1ec9, 1048575, - 0x1ecb, 1048575, - 0x1ecd, 1048575, - 0x1ecf, 1048575, - 0x1ed1, 1048575, - 0x1ed3, 1048575, - 0x1ed5, 1048575, - 0x1ed7, 1048575, - 0x1ed9, 1048575, - 0x1edb, 1048575, - 0x1edd, 1048575, - 0x1edf, 1048575, - 0x1ee1, 1048575, - 0x1ee3, 1048575, - 0x1ee5, 1048575, - 0x1ee7, 1048575, - 0x1ee9, 1048575, - 0x1eeb, 1048575, - 0x1eed, 1048575, - 0x1eef, 1048575, - 0x1ef1, 1048575, - 0x1ef3, 1048575, - 0x1ef5, 1048575, - 0x1ef7, 1048575, - 0x1ef9, 1048575, - 0x1efb, 1048575, - 0x1efd, 1048575, - 0x1eff, 1048575, - 0x1f51, 1048584, - 0x1f53, 1048584, - 0x1f55, 1048584, - 0x1f57, 1048584, - 0x1fb3, 1048585, - 0x1fbe, 1041371, - 0x1fc3, 1048585, - 0x1fe5, 1048583, - 0x1ff3, 1048585, - 0x214e, 1048548, - 0x2184, 1048575, - 0x2c61, 1048575, - 0x2c65, 1037781, - 0x2c66, 1037784, - 0x2c68, 1048575, - 0x2c6a, 1048575, - 0x2c6c, 1048575, - 0x2c73, 1048575, - 0x2c76, 1048575, - 0x2c81, 1048575, - 0x2c83, 1048575, - 0x2c85, 1048575, - 0x2c87, 1048575, - 0x2c89, 1048575, - 0x2c8b, 1048575, - 0x2c8d, 1048575, - 0x2c8f, 1048575, - 0x2c91, 1048575, - 0x2c93, 1048575, - 0x2c95, 1048575, - 0x2c97, 1048575, - 0x2c99, 1048575, - 0x2c9b, 1048575, - 0x2c9d, 1048575, - 0x2c9f, 1048575, - 0x2ca1, 1048575, - 0x2ca3, 1048575, - 0x2ca5, 1048575, - 0x2ca7, 1048575, - 0x2ca9, 1048575, - 0x2cab, 1048575, - 0x2cad, 1048575, - 0x2caf, 1048575, - 0x2cb1, 1048575, - 0x2cb3, 1048575, - 0x2cb5, 1048575, - 0x2cb7, 1048575, - 0x2cb9, 1048575, - 0x2cbb, 1048575, - 0x2cbd, 1048575, - 0x2cbf, 1048575, - 0x2cc1, 1048575, - 0x2cc3, 1048575, - 0x2cc5, 1048575, - 0x2cc7, 1048575, - 0x2cc9, 1048575, - 0x2ccb, 1048575, - 0x2ccd, 1048575, - 0x2ccf, 1048575, - 0x2cd1, 1048575, - 0x2cd3, 1048575, - 0x2cd5, 1048575, - 0x2cd7, 1048575, - 0x2cd9, 1048575, - 0x2cdb, 1048575, - 0x2cdd, 1048575, - 0x2cdf, 1048575, - 0x2ce1, 1048575, - 0x2ce3, 1048575, - 0x2cec, 1048575, - 0x2cee, 1048575, - 0x2cf3, 1048575, - 0x2d27, 1041312, - 0x2d2d, 1041312, - 0xa641, 1048575, - 0xa643, 1048575, - 0xa645, 1048575, - 0xa647, 1048575, - 0xa649, 1048575, - 0xa64b, 1048575, - 0xa64d, 1048575, - 0xa64f, 1048575, - 0xa651, 1048575, - 0xa653, 1048575, - 0xa655, 1048575, - 0xa657, 1048575, - 0xa659, 1048575, - 0xa65b, 1048575, - 0xa65d, 1048575, - 0xa65f, 1048575, - 0xa661, 1048575, - 0xa663, 1048575, - 0xa665, 1048575, - 0xa667, 1048575, - 0xa669, 1048575, - 0xa66b, 1048575, - 0xa66d, 1048575, - 0xa681, 1048575, - 0xa683, 1048575, - 0xa685, 1048575, - 0xa687, 1048575, - 0xa689, 1048575, - 0xa68b, 1048575, - 0xa68d, 1048575, - 0xa68f, 1048575, - 0xa691, 1048575, - 0xa693, 1048575, - 0xa695, 1048575, - 0xa697, 1048575, - 0xa699, 1048575, - 0xa69b, 1048575, - 0xa723, 1048575, - 0xa725, 1048575, - 0xa727, 1048575, - 0xa729, 1048575, - 0xa72b, 1048575, - 0xa72d, 1048575, - 0xa72f, 1048575, - 0xa733, 1048575, - 0xa735, 1048575, - 0xa737, 1048575, - 0xa739, 1048575, - 0xa73b, 1048575, - 0xa73d, 1048575, - 0xa73f, 1048575, - 0xa741, 1048575, - 0xa743, 1048575, - 0xa745, 1048575, - 0xa747, 1048575, - 0xa749, 1048575, - 0xa74b, 1048575, - 0xa74d, 1048575, - 0xa74f, 1048575, - 0xa751, 1048575, - 0xa753, 1048575, - 0xa755, 1048575, - 0xa757, 1048575, - 0xa759, 1048575, - 0xa75b, 1048575, - 0xa75d, 1048575, - 0xa75f, 1048575, - 0xa761, 1048575, - 0xa763, 1048575, - 0xa765, 1048575, - 0xa767, 1048575, - 0xa769, 1048575, - 0xa76b, 1048575, - 0xa76d, 1048575, - 0xa76f, 1048575, - 0xa77a, 1048575, - 0xa77c, 1048575, - 0xa77f, 1048575, - 0xa781, 1048575, - 0xa783, 1048575, - 0xa785, 1048575, - 0xa787, 1048575, - 0xa78c, 1048575, - 0xa791, 1048575, - 0xa793, 1048575, - 0xa797, 1048575, - 0xa799, 1048575, - 0xa79b, 1048575, - 0xa79d, 1048575, - 0xa79f, 1048575, - 0xa7a1, 1048575, - 0xa7a3, 1048575, - 0xa7a5, 1048575, - 0xa7a7, 1048575, - 0xa7a9, 1048575, -}; - -} // !namespace - -char32_t totitle(char32_t c) noexcept -{ - const char32_t* p; - - p = rbsearch(c, totitler, nelem (totitler) / 3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = rbsearch(c, totitles, nelem (totitles) / 2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -void encode(char32_t c, char res[5]) noexcept -{ - switch (nbytes_point(c)) { - case 1: - res[0] = static_cast<char>(c); - res[1] = '\0'; - break; - case 2: - res[0] = 0xC0 | ((c >> 6) & 0x1F); - res[1] = 0x80 | (c & 0x3F); - res[2] = '\0'; - break; - case 3: - res[0] = 0xE0 | ((c >> 12) & 0xF ); - res[1] = 0x80 | ((c >> 6) & 0x3F); - res[2] = 0x80 | (c & 0x3F); - res[3] = '\0'; - break; - case 4: - res[0] = 0xF0 | ((c >> 18) & 0x7 ); - res[1] = 0x80 | ((c >> 12) & 0x3F); - res[2] = 0x80 | ((c >> 6) & 0x3F); - res[3] = 0x80 | (c & 0x3F); - res[4] = '\0'; - break; - default: - break; - } -} - -void decode(char32_t& c, const char* res) noexcept -{ - c = 0; - - switch (nbytes_utf8(res[0])) { - case 1: - c = res[0]; - break; - case 2: - c = (res[0] & 0x1f) << 6; - c |= (res[1] & 0x3f); - break; - case 3: - c = (res[0] & 0x0f) << 12; - c |= (res[1] & 0x3f) << 6; - c |= (res[2] & 0x3f); - break; - case 4: - c = (res[0] & 0x07) << 16; - c |= (res[1] & 0x3f) << 12; - c |= (res[2] & 0x3f) << 6; - c |= (res[3] & 0x3f); - default: - break; - } -} - -int nbytes_utf8(char c) noexcept -{ - if (static_cast<unsigned char>(c) <= 127) - return 1; - if ((c & 0xE0) == 0xC0) - return 2; - if ((c & 0xF0) == 0xE0) - return 3; - if ((c & 0xF8) == 0xF0) - return 4; - - return -1; -} - -int nbytes_point(char32_t c) noexcept -{ - if (c <= 0x7F) - return 1; - if (c <= 0x7FF) - return 2; - if (c <= 0xFFFF) - return 3; - if (c <= 0x1FFFFF) - return 4; - - return -1; -} - -unsigned length(const std::string& str) -{ - unsigned total = 0; - - for_each(str, [&] (char32_t) { - ++ total; - }); - - return total; -} - -std::string to_utf8(const std::u32string& array) -{ - std::string res; - - for (size_t i = 0; i < array.size(); ++i) { - char tmp[5]; - int size = nbytes_point(array[i]); - - if (size < 0) - throw std::invalid_argument("invalid sequence"); - - encode(array[i], tmp); - res.insert(res.length(), tmp); - } - - return res; -} - -std::u32string to_utf32(const std::string& str) -{ - std::u32string res; - - for_each(str, [&] (char32_t code) { - res.push_back(code); - }); - - return res; -} - -} // !unicode - -} // !mlk
--- a/libcommon/malikania/unicode.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,273 +0,0 @@ -/* - * unicode.hpp -- UTF-8 to UTF-32 conversions and various operations - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef UNICODE_HPP -#define UNICODE_HPP - -/** - * \file unicode.hpp - * \brief UTF-8 to UTF-32 conversions - * \author David Demelier <markand@malikania.fr> - * \warning These files are auto-generated! - */ - -#include <stdexcept> -#include <string> - -namespace mlk { - -/** - * \brief Unicode namespace. - */ -namespace unicode { - -/** - * Encode the unicode code point into multibyte string. - * - * \param point the unicode code point - * \param res the output buffer - */ -void encode(char32_t point, char res[5]) noexcept; - -/** - * Decode the multibyte buffer into an unicode code point. - * - * \param c the code point destination - * \param res the multibyte string. - */ -void decode(char32_t& c, const char* res) noexcept; - -/** - * Get the number of bytes for the first multi byte character from a - * utf-8 string. - * - * This can be used to iterate a valid UTF-8 string to jump to the next - * real character. - * - * \param c the first multi byte character - * \return the number of bytes [1-4] or -1 if invalid - */ -int nbytes_utf8(char c) noexcept; - -/** - * Get the number of bytes for the unicode point. - * - * \param point the unicode point - * \return the number of bytes [1-4] or -1 if invalid - */ -int nbytes_point(char32_t point) noexcept; - -/** - * Get real number of character in a string. - * - * \param str the string - * \return the length - * \throw std::invalid_argument on invalid sequence - */ -unsigned length(const std::string& str); - -/** - * Iterate over all real characters in the UTF-8 string. - * - * The function must have the following signature: - * void f(char ch) - * - * \param str the UTF-8 string - * \param function the function callback - * \throw std::invalid_argument on invalid sequence - */ -template <typename Func> -void for_each(const std::string& str, Func function) -{ - for (size_t i = 0; i < str.size(); ) { - char32_t point = 0; - int size = nbytes_utf8(str[i]); - - if (size < 0) - throw std::invalid_argument("invalid sequence"); - - decode(point, str.data() + i); - function(point); - - i += size; - } -} - -/** - * Convert a UTF-32 string to UTF-8 string. - * - * \param array the UTF-32 string - * \return the UTF-8 string - * \throw std::invalid_argument on invalid sequence - */ -std::string to_utf8(const std::u32string& array); - -/** - * Convert a UTF-8 string to UTF-32 string. - * - * \param str the UTF-8 string - * \return the UTF-32 string - * \throw std::invalid_argument on invalid sequence - */ -std::u32string to_utf32(const std::string& str); - -/** - * Check if the unicode character is space. - * - * \param c the character - * \return true if space - */ -bool isspace(char32_t c) noexcept; - -/** - * Check if the unicode character is digit. - * - * \param c the character - * \return true if digit - */ -bool isdigit(char32_t c) noexcept; - -/** - * Check if the unicode character is alpha category. - * - * \param c the character - * \return true if alpha - */ -bool isalpha(char32_t c) noexcept; - -/** - * Check if the unicode character is upper case. - * - * \param c the character - * \return true if upper case - */ -bool isupper(char32_t c) noexcept; - -/** - * Check if the unicode character is lower case. - * - * \param c the character - * \return true if lower case - */ -bool islower(char32_t c) noexcept; - -/** - * Check if the unicode character is title case. - * - * \param c the character - * \return true if title case - */ -bool istitle(char32_t c) noexcept; - -/** - * Convert to upper case. - * - * \param c the character - * \return the upper case character - */ -char32_t toupper(char32_t c) noexcept; - -/** - * Convert to lower case. - * - * \param c the character - * \return the lower case character - */ -char32_t tolower(char32_t c) noexcept; - -/** - * Convert to title case. - * - * \param c the character - * \return the title case character - */ -char32_t totitle(char32_t c) noexcept; - -/** - * Convert the UTF-32 string to upper case. - * - * \param str the str - * \return the upper case string - */ -inline std::u32string toupper(std::u32string str) -{ - for (size_t i = 0; i < str.size(); ++i) - str[i] = toupper(str[i]); - - return str; -} - -/** - * Convert the UTF-8 string to upper case. - * - * \param str the str - * \return the upper case string - * \warning very slow at the moment - */ -inline std::string toupper(const std::string& str) -{ - std::string result; - char buffer[5]; - - for_each(str, [&] (char32_t code) { - encode(toupper(code), buffer); - result += buffer; - }); - - return result; -} - -/** - * Convert the UTF-32 string to lower case. - * - * \param str the str - * \return the lower case string - */ -inline std::u32string tolower(std::u32string str) -{ - for (size_t i = 0; i < str.size(); ++i) - str[i] = tolower(str[i]); - - return str; -} - -/** - * Convert the UTF-8 string to lower case. - * - * \param str the str - * \return the lower case string - * \warning very slow at the moment - */ -inline std::string tolower(const std::string& str) -{ - std::string result; - char buffer[5]; - - for_each(str, [&] (char32_t code) { - encode(tolower(code), buffer); - result += buffer; - }); - - return result; -} - -} // !unicode - -} // !mlk - -#endif // !UNICODE_HPP
--- a/libcommon/malikania/util.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,443 +0,0 @@ -/* - * util.cpp -- malikania utilities - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> -#include <climits> -#include <string> -#include <stdexcept> - -#if defined(__linux__) -# include <unistd.h> - -# include <cerrno> -# include <cstring> -# include <stdexcept> -#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) -# if defined(__NetBSD__) -# include <sys/param.h> -# else -# include <sys/types.h> -# endif - -# if defined(__OpenBSD__) -# include <unistd.h> -# endif - -# include <sys/sysctl.h> - -# include <array> -# include <cerrno> -# include <climits> -# include <cstddef> -# include <cstdlib> -# include <cstring> -# include <stdexcept> -#elif defined(__APPLE__) -# include <cerrno> -# include <cstring> -# include <libproc.h> -# include <unistd.h> -#elif defined(_WIN32) -# include <Windows.h> -#endif - -#include <boost/filesystem.hpp> - -#include "util.hpp" -#include "size.hpp" - -namespace { - -#if defined(__linux__) - -std::string executable_path() -{ - std::string result; - - result.resize(2048, '\0'); - - auto size = readlink("/proc/self/exe", &result[0], 2048); - - if (size < 0) { - throw std::runtime_error(std::strerror(errno)); - } - - result.resize(size, '\0'); - - return result; -} - -#elif defined(__FreeBSD__) || defined(__DragonFly__) - -std::string executable_path() -{ - std::array<int, 4> mib{ { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 } }; - std::string result; - std::size_t size = PATH_MAX + 1; - - result.resize(size, '\0'); - - if (sysctl(mib.data(), 4, &result[0], &size, nullptr, 0) < 0) { - throw std::runtime_error(std::strerror(errno)); - } - - result.resize(size, '\0'); - - return result; -} - -#elif defined(__APPLE__) - -std::string executable_path() -{ - std::string result; - std::size_t size = PROC_PIDPATHINFO_MAXSIZE; - - result.resize(size, '\0'); - - if ((size = proc_pidpath(getpid(), &result[0], size)) == 0) { - throw std::runtime_error(std::strerror(errno)); - } - - result.resize(size, '\0'); - - return result; -} - -#elif defined(_WIN32) - -std::string executable_path() -{ - std::string result; - std::size_t size = PATH_MAX; - - result.resize(size, '\0'); - - if (!(size = GetModuleFileNameA(nullptr, &result[0], size))) { - throw std::runtime_error("GetModuleFileName error"); - } - - result.resize(size, '\0'); - - return result; -} - -#elif defined(__NetBSD__) - -std::string executable_path() -{ - std::string result; - -#if defined(KERN_PROC_PATHNAME) - std::array<int, 4> mib{ CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME }; - std::size_t size = MAXPATHLEN; - - result.resize(size, '\0'); - - if (sysctl(mib.data(), 4, &result[0], &size, nullptr, 0) < 0) { - throw std::runtime_error(std::strerror(errno)); - } - - result.resize(size, '\0'); -#else - result.resize(2048, '\0'); - - auto size = readlink("/proc/curproc/exe", &result[0], 2048); - - if (size < 0) { - throw std::runtime_error(std::strerror(errno)); - } - - result.resize(size, '\0'); -#endif - - return result; -} - -#elif defined(__OpenBSD__) - -std::string executable_path() -{ - char **paths, *path; - std::string result; - std::size_t len; - std::array<int, 4> mib{ CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; - - if (sysctl(mib.data(), 4, nullptr, &len, nullptr, 0) == -1) { - throw std::runtime_error(std::strerror(errno)); - } - if ((paths = static_cast<char **>(malloc(len))) == nullptr) { - throw std::runtime_error(std::strerror(errno)); - } - - sysctl(mib.data(), 4, paths, &len, nullptr, 0); - - if ((path = static_cast<char *>(std::malloc(PATH_MAX + 1))) == nullptr) { - std::free(paths); - throw std::runtime_error(std::strerror(errno)); - } - - realpath(paths[0], path); - result = path; - - std::free(paths); - std::free(path); - - return result; -} - -#else - -std::string executable_path() -{ - // Not supported. - return ""; -} - -#endif - -} // !namespace - -namespace mlk { - -namespace util { - -std::vector<std::string> split(const std::string &list, const std::string &delimiters, int max) -{ - std::vector<std::string> result; - std::size_t next = -1, current; - int count = 1; - bool finished = false; - - if (list.empty()) { - return result; - } - - do { - std::string val; - - current = next + 1; - next = list.find_first_of(delimiters, current); - - // split max, get until the end - if (max >= 0 && count++ >= max) { - val = list.substr(current, std::string::npos); - finished = true; - } else { - val = list.substr(current, next - current); - finished = next == std::string::npos; - } - - result.push_back(val); - } while (!finished); - - return result; -} - -std::string basedir() noexcept -{ - std::string result = "./"; - - try { - boost::filesystem::path tmp = executable_path(); - - tmp = tmp.parent_path(); // remove executable name - tmp = tmp.parent_path(); // remove "bin" - result = tmp.string(); - } catch (...) { - // TODO: add log. - } - - return result; -} - -/* - * json utilities - * ------------------------------------------------------------------ - */ - -namespace json { - -/* - * XXX: until json get a non-throwing function to check if a pointer exists, - * use this to check for a value at the given pointer or throw a - * property_error. - */ -nlohmann::json require(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer, - const nlohmann::json::value_t expected) -{ - assert(object.is_object()); - - nlohmann::json value; - - try { - value = object.at(pointer); - } catch (...) { - throw property_error(object, pointer, nlohmann::json::value_t::null, expected); - } - - if (value.type() != expected) { - throw property_error(object, pointer, value.type(), expected); - } - - return value; -} - -nlohmann::json get(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer, - const nlohmann::json::value_t expected, - const nlohmann::json def) -{ - assert(object.is_object()); - - nlohmann::json value; - - try { - value = object.at(pointer); - } catch (...) { - } - - if (value.type() != expected) - value = def; - - return value; -} - -nlohmann::json require_array(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer) -{ - return require(object, pointer, nlohmann::json::value_t::array); -} - -bool require_bool(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer) -{ - return require(object, pointer, nlohmann::json::value_t::boolean); -} - -int require_int(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer) -{ - nlohmann::json v; - - try { - v = object.at(pointer); - - if (v.is_number_integer()) - return v.get<int>(); - else if (v.is_number_unsigned() && v.get<unsigned>() <= static_cast<unsigned>(INT_MAX)) - return static_cast<int>(v.get<unsigned>()); - } catch (...) { - } - - throw property_error(object, pointer, v.type(), nlohmann::json::value_t::number_integer); -} - -nlohmann::json require_object(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer) -{ - return require(object, pointer, nlohmann::json::value_t::object); -} - -std::string require_string(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer) -{ - return require(object, pointer, nlohmann::json::value_t::string); -} - -unsigned require_uint(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer) -{ - nlohmann::json v; - - try { - v = object.at(pointer); - - if (v.is_number_unsigned()) - return v.get<unsigned>(); - else if (v.is_number_integer() && v.get<int>() >= 0) - return static_cast<unsigned>(v.get<int>()); - } catch (...) { - } - - throw property_error(object, pointer, v.type(), nlohmann::json::value_t::number_unsigned); -} - -mlk::size require_size(const nlohmann::json& object, - const nlohmann::json::json_pointer& index) -{ - using pointer = nlohmann::json::json_pointer; - - return { - require_uint(object, pointer(index.to_string() + "/width")), - require_uint(object, pointer(index.to_string() + "/height")) - }; -} - -int get_int(const nlohmann::json &object, - const nlohmann::json::json_pointer &pointer, - int value) noexcept -{ - try { - auto v = object.at(pointer); - - if (v.is_number_integer()) - value = v.get<int>(); - else if (v.is_number_unsigned() && v.get<unsigned>() <= static_cast<unsigned>(INT_MAX)) - value = static_cast<int>(v.get<unsigned>()); - } catch (...) { - } - - return value; -} - -unsigned get_uint(const nlohmann::json &object, - const nlohmann::json::json_pointer& pointer, - unsigned value) noexcept -{ - try { - auto v = object.at(pointer); - - if (v.is_number_unsigned()) - value = v.get<unsigned>(); - else if (v.is_number_integer() && v.get<int>() >= 0) - value = static_cast<unsigned>(v.get<int>()); - } catch (...) { - } - - return value; -} - -mlk::size get_size(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer, - const mlk::size& def) noexcept -{ - using json_pointer = nlohmann::json::json_pointer; - - return { - get_uint(object, json_pointer(pointer.to_string() + "/width"), def.width), - get_uint(object, json_pointer(pointer.to_string() + "/height"), def.height) - }; -} - -} // !json - -} // !util - -} // !mlk
--- a/libcommon/malikania/util.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,331 +0,0 @@ -/* - * util.hpp -- malikania utilities - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_UTIL_HPP -#define MALIKANIA_UTIL_HPP - -/** - * \file util.hpp - * \brief Some utilities - */ - -#include <algorithm> -#include <exception> -#include <string> -#include <vector> - -#include "json.hpp" -#include "size.hpp" - -namespace mlk { - -/** - * \brief Utilities. - */ -namespace util { - -/** - * Split a line into a list of tokens. - * - * If max is less than 0, split as much as possible, otherwise split at most - * the number of specified tokens. - * - * \param line the line to split - * \param delim the list of delimiters allowed - * \param max the maximum number of tokens - * \return the list - */ -std::vector<std::string> split(const std::string& line, const std::string& delim, int max = -1); - -/** - * Get the base directory of the current executable. - * - * \return the base directory or empty if impossible to get - */ -std::string basedir() noexcept; - -/** - * Clamp the value between low and high. - * - * \param value the value - * \param low the minimum value - * \param high the maximum value - * \return the value between minimum and maximum - */ -template <typename T> -constexpr T clamp(T value, T low, T high) noexcept -{ - return (value < high) ? std::max(value, low) : std::min(value, high); -} - -/** - * \brief Utilities for networking. - */ -namespace net { - -/** - * Shortcut for util::split(line, " ", max); - * - * \param line the line - * \param max the maximum of tokens to split - * \return the list - */ -inline std::vector<std::string> split(const std::string& line, int max = -1) -{ - return util::split(line, " ", max); -} - -} // !net - -namespace json { - -/** - * \brief Indicates a property error in an object. - */ -class property_error : public std::exception { -private: - nlohmann::json m_object; - nlohmann::json::json_pointer m_pointer; - nlohmann::json::value_t m_type; - nlohmann::json::value_t m_expected; - std::string m_message; - -public: - /** - * Construct the property error. - * - * \param object the faulty object - * \param pointer the property path - * \param type the found type - * \param expected the expected type - */ - inline property_error(nlohmann::json object, - nlohmann::json::json_pointer pointer, - nlohmann::json::value_t type, - nlohmann::json::value_t expected) noexcept - : m_object(std::move(object)) - , m_pointer(std::move(pointer)) - , m_type(type) - , m_expected(expected) - { - m_message += "invalid '" + m_pointer.to_string() + "' property "; - m_message += "(" + nlohmann::json(expected).type_name(); - m_message += " expected, got "; - m_message += nlohmann::json(type).type_name() + ")"; - } - - /** - * Get the faulty object. - * - * return the object - */ - inline const nlohmann::json& object() const noexcept - { - return m_object; - } - - /** - * Get the pointer to the property. - * - * \return the pointer - */ - inline const nlohmann::json::json_pointer& pointer() const noexcept - { - return m_pointer; - } - - /** - * Get the actual type. - * - * \return the type - */ - inline nlohmann::json::value_t type() const noexcept - { - return m_type; - } - - /** - * Get the expected type. - * - * \return the type - */ - inline nlohmann::json::value_t expected() const noexcept - { - return m_expected; - } - - /** - * Get a human formatted message. - * - * \return the message - */ - const char* what() const noexcept - { - return m_message.c_str(); - } -}; - -/** - * Require a value at the given pointer, if the value does not match the - * expected type, an exception is thrown. - * - * If the property does not exists, a property_error with a null found type is - * thrown. - * - * \pre object.is_object() - * \param object the object - * \param pointer the pointer to the property - * \param expected the expected type - * \throw property_error on errors - */ -nlohmann::json require(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer, - const nlohmann::json::value_t expected); - -/** - * Require an array at the given pointer. - * - * \pre object.is_object() - * \param object the object - * \param pointer the pointer to the property - * \return the value - * \throw property_error on errors - */ -nlohmann::json require_array(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer); - -/** - * Require a boolean at the given pointer. - * - * \pre object.is_object() - * \param object the object - * \param pointer the pointer to the property - * \return the value - * \throw property_error on errors - */ -bool require_bool(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer); - -/** - * Require an integer at the given pointer. - * - * \pre object.is_object() - * \param object the object - * \param pointer the pointer to the property - * \return the value - * \throw property_error on errors - */ -int require_int(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer); - -/** - * Require an object at the given pointer. - * - * \pre object.is_object() - * \param object the object - * \param pointer the pointer to the property - * \return the value - * \throw property_error on errors - */ -nlohmann::json require_object(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer); - -/** - * Require a string at the given pointer. - * - * \pre object.is_object() - * \param object the object - * \param pointer the pointer to the property - * \return the value - * \throw property_error on errors - */ -std::string require_string(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer); - -/** - * Require an unsigned integer at the given pointer. - * - * \pre object.is_object() - * \param object the object - * \param pointer the pointer to the property - * \return the value - * \throw property_error on errors - */ -unsigned require_uint(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer); - -/** - * Require a size object at the given pointer. - * - * \pre object.is_object - * \param object the json object - * \param pointer the pointer to the property - * \return the value - * \throw property_error on errors - */ -mlk::size require_size(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer); - -/** - * Get an integer at the given pointer or default value if not present or - * invalid. - * - * \pre object.is_object - * \param object the json object - * \param pointer the pointer to the property - * \param def the default value - * \return an integer - */ -int get_int(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer, - int def = 0) noexcept; - -/** - * Get an unsigned integer at the given pointer or default value if not present - * or invalid. - * - * \pre object.is_object - * \param object the json object - * \param pointer the pointer to the property - * \param def the default value - * \return an integer - */ -unsigned get_uint(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer, - unsigned def = 0) noexcept; - -/** - * Get a size object at the given pointer or a default value. - * - * \pre object.is_object - * \param object the json object - * \param pointer the pointer to the property - * \param def the default value to return in case of error - * \return a size or a default value - */ -mlk::size get_size(const nlohmann::json& object, - const nlohmann::json::json_pointer& pointer, - const mlk::size& def = {}) noexcept; - -} // !json - -} // !util - -} // !mlk - -#endif // !MALIKANIA_UTIL_HPP
--- a/libdb/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -# -# CMakeLists.txt -- CMake build system for malikania -# -# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(libmlk-db) - -find_package(PostgreSQL REQUIRED) - -set( - HEADERS - ${libmlk-db_SOURCE_DIR}/malikania/db/account.hpp - ${libmlk-db_SOURCE_DIR}/malikania/db/character.hpp - ${libmlk-db_SOURCE_DIR}/malikania/db/database.hpp - ${libmlk-db_SOURCE_DIR}/malikania/db/model.hpp - ${libmlk-db_SOURCE_DIR}/malikania/db/spell.hpp -) - -set( - SOURCES - ${libmlk-db_SOURCE_DIR}/malikania/db/account.cpp - ${libmlk-db_SOURCE_DIR}/malikania/db/character.cpp - ${libmlk-db_SOURCE_DIR}/malikania/db/database.cpp - ${libmlk-db_SOURCE_DIR}/malikania/db/spell.cpp -) - -malikania_define_library( - TARGET libmlk-db - SOURCES ${HEADERS} ${SOURCES} - LIBRARIES - ${PostgreSQL_LIBRARIES} - PUBLIC_INCLUDES - ${Boost_INCLUDE_DIRS} - ${libmlk-db_SOURCE_DIR}/malikania - PRIVATE_INCLUDES - ${PostgreSQL_INCLUDE_DIRS} -)
--- a/libdb/malikania/db/account.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,242 +0,0 @@ -/* - * account.cpp -- database account object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include "account.hpp" - -namespace mlk::db { - -auto account::load(const result& res) -> account -{ - account a(PQgetvalue(res.get(), 0, 1), PQgetvalue(res.get(), 0, 2)); - - a.id_ = std::stoi(PQgetvalue(res.get(), 0, 0)); - a.firstname_ = PQgetvalue(res.get(), 0, 3); - a.lastname_ = PQgetvalue(res.get(), 0, 4); - a.email_ = PQgetvalue(res.get(), 0, 5); - a.characters_ = character::load(a); - - return a; -} - -void account::clear() -{ - id_ = 0U; -} - -account::account(std::string login, std::string password) noexcept - : login_(std::move(login)) - , password_(std::move(password)) -{ - assert(!login_.empty()); - assert(!password_.empty()); -} - -auto account::get_login() const noexcept -> const std::string& -{ - return login_; -} - -void account::set_password(std::string password) -{ - static const std::string sql( - "UPDATE account" - " SET password = $1" - " WHERE id = $2" - ); - - assert(!password.empty()); - - if (is_published() && password_ != password) - db::exec(sql, { password, id_ }); - - password_ = std::move(password); -} - -auto account::get_email() const noexcept -> const std::string& -{ - return email_; -} - -void account::set_email(std::string email) -{ - static const std::string sql( - "UPDATE account" - " SET email = $1" - " WHERE id = $2" - ); - - assert(!email.empty()); - - if (is_published() && email_ != email) - db::exec(sql, { email, id_ }); - - email_ = std::move(email); -} - -auto account::get_firstname() const noexcept -> const std::string& -{ - return firstname_; -} - -void account::set_firstname(std::string name) -{ - static const std::string sql( - "UPDATE account" - " SET firstname = $1" - " WHERE id = $2" - ); - - if (is_published() && firstname_ != name) - db::exec(sql, { name, id_ }); - - firstname_ = std::move(name); -} - -auto account::get_lastname() const noexcept -> const std::string& -{ - return lastname_; -} - -void account::set_lastname(std::string name) -{ - static const std::string sql( - "UPDATE account" - " SET lastname = $1" - " WHERE id = $2" - ); - - if (is_published() && lastname_ != name) - db::exec(sql, { name, id_ }); - - lastname_ = std::move(name); -} - -auto account::get_characters() const noexcept -> const std::vector<character>& -{ - return characters_; -} - -void account::add(character ch) -{ - assert(ch.is_draft()); - - characters_.reserve(characters_.size() + 1); - - if (is_published()) - ch.publish(*this); - - characters_.push_back(std::move(ch)); -} - -void account::remove(std::vector<character>::iterator it) -{ - // TODO: assert 'it' is in vector. - it->unpublish(); - characters_.erase(it); -} - -void account::publish() -{ - static const std::string sql( - "INSERT INTO account(" - " login," - " password," - " firstname," - " lastname," - " email" - ") " - "VALUES ($1, $2, $3, $4, $5) " - "RETURNING id" - ); - - assert(is_draft()); - - /* - * Recursively save the account, its characters and spells of those - * characters. - */ - transaction txn([this] { - clear(); - - for (auto& c : characters_) - c.clear(); - }); - - const auto r = select(sql, { login_, password_, firstname_, lastname_, email_ }); - - id_ = std::stoi(PQgetvalue(r.get(), 0, 0)); - - for (auto& c : characters_) - c.publish(*this); - - txn.commit(); - - assert(is_published()); -} - -void account::unpublish() -{ - static const std::string sql( - "DELETE" - " FROM account" - " WHERE id = $1" - ); - - assert(is_published()); - - id_ = 0; - - /* - * Recursively make all characters and their spells draft. - */ - for (auto& c : characters_) - c.clear(); - - assert(is_draft()); -} - -auto account::find_by_login(const std::string& login) -> std::optional<account> -{ - static const std::string sql( - "SELECT *" - " FROM account" - " WHERE login = $1" - ); - - const auto r = select(sql, { login }); - - if (PQntuples(r.get()) == 0) - return std::nullopt; - - return load(r); -} - -auto account::authenticate(const std::string& login, - const std::string& password) -> std::optional<account> -{ - auto ac = find_by_login(login); - - if (!ac || ac->password_ != password) - return std::nullopt; - - return ac; -} - -} // !mlk::db
--- a/libdb/malikania/db/account.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -/* - * account.hpp -- database account object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_DB_ACCOUNT_HPP -#define MALIKANIA_DB_ACCOUNT_HPP - -/** - * \file account.hpp - * \brief Database account object. - */ - -#include <optional> - -#include "character.hpp" -#include "database.hpp" -#include "model.hpp" - -namespace mlk::db { - -/** - * \brief Database account object. - */ -class account : public model { -private: - std::string login_; - std::string password_; - std::string email_; - std::string firstname_; - std::string lastname_; - std::vector<character> characters_; - - static auto load(const result&) -> account; - - void clear(); - -public: - /** - * Create a draft account. - * - * \pre !login.empty() - * \pre !password.empty() - * \param login the login name - * \param password the password - * \warning the password is saved as-is and **must** be hashed by the caller. - */ - account(std::string login, std::string password) noexcept; - - /** - * Get the account login. - * - * \return the login - */ - auto get_login() const noexcept -> const std::string&; - - /** - * Set the password. - * - * \pre !password.empty() - * \warning the password is saved as-is and **must** be hashed by the caller. - */ - void set_password(std::string password); - - /** - * Get the account email. - * - * \return the email - */ - auto get_email() const noexcept -> const std::string&; - - /** - * Set the account email. - * - * \pre !email.empty() - * \param email the new email - */ - void set_email(std::string email); - - /** - * Get the account first name. - * - * \return the name - */ - auto get_firstname() const noexcept -> const std::string&; - - /** - * Set the account firstname. - * - * \param name the new name - */ - void set_firstname(std::string name); - - /** - * Get the account last name. - * - * \return the name - */ - auto get_lastname() const noexcept -> const std::string&; - - /** - * Set the account last name. - * - * \param name the new name - */ - void set_lastname(std::string name); - - /** - * Get the caracter list. - * - * \return the associated characters. - */ - auto get_characters() const noexcept -> const std::vector<character>&; - - /** - * Add the character to the account. - * - * Account takes ownership of character. - * - * \pre ch.is_draft() - * \param ch the character - * \post ch.is_published() - */ - void add(character ch); - - /** - * Remove the character from the account. - * - * \pre it is in the the account character list - * \param ch the character - * \post ch == nullptr - */ - void remove(std::vector<character>::iterator it); - - /** - * Save the account, does nothing if is_published(). - * - * \throw std::exception on errors - * \post is_published() - */ - void publish(); - - /** - * Destroy the account. - * - * The account will contains no characters anymore. - * - * \throw std::exception on errors - * \post is_draft() - */ - void unpublish(); - - /** - * Find an account by login. - * - * \param login the login - * \return the account or none if not found - * \throw std::runtime_error on database errors - */ - static auto find_by_login(const std::string& login) -> std::optional<account>; - - /** - * Find and authenticate a user. - * - * \param login the login - * \param password the password - * \return the account or none if not found - * \throw std::runtime_error on database errors - */ - static auto authenticate(const std::string& login, - const std::string& password) -> std::optional<account>; -}; - -} // !mlk::db - -#endif // !MALIKANIA_DB_ACCOUNT_HPP
--- a/libdb/malikania/db/character.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,266 +0,0 @@ -/* - * character.cpp -- database character object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> -#include <numeric> - -#include "account.hpp" -#include "character.hpp" -#include "database.hpp" - -namespace mlk::db { - -auto character::load(const result& result, int row) -> character -{ - character ch(PQgetvalue(result.get(), row, 2), PQgetvalue(result.get(), row, 3)); - - ch.levels_[stat::hp] = std::stoi(PQgetvalue(result.get(), row, 4)); - ch.factors_[stat::hp] = std::stoi(PQgetvalue(result.get(), row, 5)); - ch.exp_[stat::hp] = std::stoi(PQgetvalue(result.get(), row, 6)); - - ch.levels_[stat::force] = std::stoi(PQgetvalue(result.get(), row, 7)); - ch.factors_[stat::force] = std::stoi(PQgetvalue(result.get(), row, 8)); - ch.exp_[stat::force] = std::stoi(PQgetvalue(result.get(), row, 9)); - - ch.levels_[stat::defense] = std::stoi(PQgetvalue(result.get(), row, 10)); - ch.factors_[stat::defense] = std::stoi(PQgetvalue(result.get(), row, 11)); - ch.exp_[stat::defense] = std::stoi(PQgetvalue(result.get(), row, 12)); - - ch.levels_[stat::agility] = std::stoi(PQgetvalue(result.get(), row, 13)); - ch.factors_[stat::agility] = std::stoi(PQgetvalue(result.get(), row, 14)); - ch.exp_[stat::agility] = std::stoi(PQgetvalue(result.get(), row, 15)); - - ch.levels_[stat::luck] = std::stoi(PQgetvalue(result.get(), row, 16)); - ch.factors_[stat::luck] = std::stoi(PQgetvalue(result.get(), row, 17)); - ch.exp_[stat::luck] = std::stoi(PQgetvalue(result.get(), row, 18)); - - ch.id_ = std::stoi(PQgetvalue(result.get(), row, 0)); - ch.spells_ = spell::load(ch); - - return ch; -} - -auto character::load(const account& parent) -> std::vector<character> -{ - static const std::string sql( - "SELECT *" - " FROM character" - " WHERE account_id = $1" - ); - - const auto r = select(sql, { parent.get_id() }); - - if (PQntuples(r.get()) == 0) - throw std::runtime_error("failed to load characters"); - - std::vector<character> characters; - - for (int i = 0; i < PQntuples(r.get()); ++i) - characters.push_back(load(r, i)); - - return characters; -} - -void character::clear() -{ - id_ = 0U; - - for (auto& s : spells_) - s.clear(); -} - -void character::publish(account& parent) -{ - static const std::string sql( - "INSERT INTO character (" - " account_id," - " nickname," - " type," - " hp_level," - " hp_factor," - " hp_exp," - " force_level," - " force_factor," - " force_exp," - " defense_level," - " defense_factor," - " defense_exp," - " agility_level," - " agility_factor," - " agility_exp," - " luck_level," - " luck_factor," - " luck_exp" - ") " - "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) " - "RETURNING id" - ); - - const auto r = select(sql, { - parent.get_id(), - nickname_, - type_, - levels_[stat::hp], - factors_[stat::hp], - exp_[stat::hp], - levels_[stat::force], - factors_[stat::force], - exp_[stat::force], - levels_[stat::defense], - factors_[stat::defense], - exp_[stat::defense], - levels_[stat::agility], - factors_[stat::agility], - exp_[stat::agility], - levels_[stat::luck], - factors_[stat::luck], - exp_[stat::luck] - }); - - if (PQntuples(r.get()) == 0) - throw std::runtime_error("failed to save character"); - - id_ = std::stoi(PQgetvalue(r.get(), 0, 0)); - - for (auto& s : spells_) - s.publish(*this); -} - -void character::unpublish() -{ - static const std::string sql( - "DELETE" - " FROM character" - " WHERE id = $1" - ); - - exec(sql, { id_ }); - clear(); -} - -character::character(std::string nickname, std::string type) noexcept - : nickname_(std::move(nickname)) - , type_(std::move(type)) -{ - assert(!nickname_.empty()); - assert(!type_.empty()); -} - -auto character::get_nickname() const noexcept -> const std::string& -{ - return nickname_; -} - -auto character::get_type() const noexcept -> const std::string& -{ - return type_; -} - -auto character::get_spells() const noexcept -> const std::vector<spell>& -{ - return spells_; -} - -auto character::get_levels() const noexcept -> const std::array<std::uint8_t, 5>& -{ - return levels_; -} - -void character::set_levels(std::array<std::uint8_t, 5> levels) -{ - static const std::string sql( - "UPDATE character" - " SET hp_level = $1" - " , force_level = $2" - " , defense_level = $3" - " , agility_level = $4" - " , luck_level = $5" - ); - - if (is_published()) - exec(sql, { id_, levels[0], levels[1], levels[2], levels[3], levels[4] }); - - levels_ = std::move(levels); -} - -auto character::get_factors() const noexcept -> const std::array<std::uint8_t, 5>& -{ - return factors_; -} - -void character::set_factors(std::array<std::uint8_t, 5> factors) -{ - static const std::string sql( - "UPDATE character" - " SET hp_factor = $1" - " , force_factor = $2" - " , defense_factor = $3" - " , agility_factor = $4" - " , luck_factor = $5" - ); - - assert(std::accumulate(factors.begin(), factors.end(), 0U) == 100U); - - if (is_published()) - exec(sql, { id_, factors[0], factors[1], factors[2], factors[3], factors[4] }); - - factors_ = std::move(factors); -} - -auto character::get_experience() const noexcept -> const std::array<std::uint32_t, 5>& -{ - return exp_; -} - -void character::set_experience(std::array<std::uint32_t, 5> experience) -{ - static const std::string sql( - "UPDATE character" - " SET hp_experience = $1" - " , force_experience = $2" - " , defense_experience = $3" - " , agility_experience = $4" - " , luck_experience = $5" - ); - - if (is_published()) - exec(sql, { id_, experience[0], experience[1], experience[2], experience[3], experience[4] }); - - exp_ = std::move(experience); -} - -void character::add(spell sp) -{ - assert(sp.is_draft()); - - spells_.reserve(spells_.size() + 1); - - if (is_published()) - sp.publish(*this); - - spells_.push_back(std::move(sp)); -} - -void character::remove(std::vector<spell>::iterator it) -{ - // TODO: assert 'it' is in vector. - it->unpublish(); - spells_.erase(it); -} - -} // !mlk::db
--- a/libdb/malikania/db/character.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +0,0 @@ -/* - * character.hpp -- database character object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_DB_CHARACTER_HPP -#define MALIKANIA_DB_CHARACTER_HPP - -/* - * \file character.hpp - * \brief Database character object. - */ - -#include <cstdint> -#include <array> -#include <vector> - -#include "database.hpp" -#include "model.hpp" -#include "spell.hpp" - -namespace mlk::db { - -class account; - -/* - * \brief Database character object. - */ -class character : public model { -public: - friend class account; - - /** - * \brief Stats index in arrays - * \see set_levels - * \see set_factors - * \see set_experience - */ - enum stat { - hp = 0, //!< hp index - force, //!< force index - defense, //!< defense index - agility, //!< agility index - luck //!< luck index - }; - -private: - std::string nickname_; - std::string type_; - std::vector<spell> spells_; - std::array<std::uint8_t, 5> levels_{1U, 1U, 1U, 1U, 1U}; - std::array<std::uint8_t, 5> factors_{20U, 20U, 20U, 20U, 20U}; - std::array<std::uint32_t, 5> exp_{0U, 0U, 0U, 0U, 0U}; - - static auto load(const result&, int) -> character; - static auto load(const account&) -> std::vector<character>; - - void clear(); - void publish(account&); - void unpublish(); - -public: - /** - * Construct a character, no database is modified yet. - * - * \pre !nickname.empty() - * \pre !type.empty() - * \param nickname the nickname - * \param type the type - */ - character(std::string nickname, std::string type) noexcept; - - /** - * Get the character nickname. - * - * \return the name - */ - auto get_nickname() const noexcept -> const std::string&; - - /** - * Get the character type name. - * - * \return the type name - */ - auto get_type() const noexcept -> const std::string&; - - /** - * Get the list of spells. - * - * \return the spells - */ - auto get_spells() const noexcept -> const std::vector<spell>&; - - /** - * Get the list of levels. - * - * \return the levels - */ - auto get_levels() const noexcept -> const std::array<std::uint8_t, 5>&; - - /** - * Set the new levels. - * - * \param levels the levels - */ - void set_levels(std::array<std::uint8_t, 5> levels); - - /** - * Get the list of factors. - * - * \return the factors - */ - auto get_factors() const noexcept -> const std::array<std::uint8_t, 5>&; - - /** - * Set progression factors. - * - * \pre factors sum must be 100 - * \param factors the factors - */ - void set_factors(std::array<std::uint8_t, 5> factors); - - /** - * Get the stats experience. - * - * \return the experience - */ - auto get_experience() const noexcept -> const std::array<std::uint32_t, 5>&; - - /** - * Set stats experience. - * - * \param experience the experience - */ - void set_experience(std::array<std::uint32_t, 5> experience); - - /** - * Add a spell. - * - * Character takes ownership of spell. - * - * \pre sp.is_draft() - * \param sp the spell (moved) - */ - void add(spell sp); - - /** - * Remove the spell from the character. - * - * \pre it must be valid - * \param it the spell iterator - */ - void remove(std::vector<spell>::iterator it); -}; - -} // !mlk::db - -#endif // !MALIKANIA_DB_CHARACTER_HPP
--- a/libdb/malikania/db/database.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -/* - * database.cpp -- connection to postgresql database - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> -#include <sstream> - -#include "database.hpp" - -namespace mlk::db { - -namespace { - -struct strify { - template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> - auto operator()(T i) const -> std::string - { - return std::to_string(i); - } - - auto operator()(bool v) const -> std::string - { - return v ? "t" : "f"; - } - - auto operator()(std::string s) const -> std::string - { - return s; - } -}; - -std::unique_ptr<PGconn, void (*)(PGconn*)> connection{nullptr, nullptr}; - -auto run(const std::string& sql, std::vector<arg> args = {}) -> result -{ - std::vector<const char*> list; - - /* - * PQexecParams requires an array of C strings, convert all arguments in the - * args vector to string and then keep the C string value into a temporary - * array. - */ - for (auto& arg : args) { - arg = std::visit(strify(), arg); - list.push_back(std::get<std::string>(arg).c_str()); - } - - return { - PQexecParams(connection.get(), sql.c_str(), list.size(), nullptr, - list.data(), nullptr, nullptr, 0 - ), - PQclear - }; -} - -} // !namespace - -void open(const std::string& host, - const std::string& port, - const std::string& user, - const std::string& database, - const std::string& password) -{ - assert(!connection); - - std::ostringstream oss; - - if (!host.empty()) - oss << "host=" << host << " "; - if (!port.empty()) - oss << "port=" << port << " "; - if (!user.empty()) - oss << "user=" << user << " "; - if (!database.empty()) - oss << "dbname=" << database << " "; - if (!password.empty()) - oss << "password=" << password; - - connection = { PQconnectdb(oss.str().c_str()), PQfinish }; - - if (PQstatus(connection.get()) != CONNECTION_OK) - throw std::runtime_error(PQerrorMessage(connection.get())); -} - -const std::string init_account( - "CREATE TABLE IF NOT EXISTS account(" - " id SERIAL," - " login TEXT NOT NULL," - " password TEXT NOT NULL," - " firstname TEXT," - " lastname TEXT," - " email TEXT," - " PRIMARY KEY(id)" - ")" -); - -const std::string init_character( - "CREATE TABLE IF NOT EXISTS character(" - " id SERIAL," - " account_id INTEGER NOT NULL," - " nickname TEXT NOT NULL," - " type TEXT NOT NULL," - " hp_level SMALLINT NOT NULL DEFAULT 1," - " hp_factor SMALLINT NOT NULL," - " hp_exp INT NOT NULL," - " force_level SMALLINT NOT NULL DEFAULT 1," - " force_factor SMALLINT NOT NULL," - " force_exp INT NOT NULL," - " defense_level SMALLINT NOT NULL DEFAULT 1," - " defense_factor SMALLINT NOT NULL," - " defense_exp INT NOT NULL," - " agility_level SMALLINT NOT NULL DEFAULT 1," - " agility_factor SMALLINT NOT NULL," - " agility_exp INT NOT NULL," - " luck_level SMALLINT NOT NULL DEFAULT 1," - " luck_factor SMALLINT NOT NULL," - " luck_exp INT NOT NULL," - " PRIMARY KEY(id)," - " FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE" - ")" -); - -const std::string init_spell( - "CREATE TABLE IF NOT EXISTS spell(" - " id SERIAL," - " character_id INTEGER NOT NULL," - " type TEXT NOT NULL," - " level SMALLINT NOT NULL," - " PRIMARY KEY(id)," - " FOREIGN KEY (character_id) REFERENCES character(id) ON DELETE CASCADE" - ")" -); - -void init() -{ - assert(connection); - - exec(init_account); - exec(init_character); - exec(init_spell); -} - -auto select(const std::string& sql, const std::vector<arg>& args) -> result -{ - assert(connection); - - auto result = run(sql, args); - - switch (PQresultStatus(result.get())) { - case PGRES_COMMAND_OK: - case PGRES_TUPLES_OK: - break; - default: - throw std::runtime_error(PQerrorMessage(connection.get())); - } - - return result; -} - -void exec(const std::string& sql, const std::vector<arg>& args) -{ - assert(connection); - - switch (const auto result = run(sql, args); PQresultStatus(result.get())) { - case PGRES_COMMAND_OK: - break; - default: - throw std::runtime_error(PQerrorMessage(connection.get())); - } -} - -transaction::transaction(rollback fn) - : rollback_(std::move(fn)) -{ - assert(rollback_); - - exec("BEGIN"); -} - -transaction::~transaction() -{ - if (!commit_) { - rollback_(); - exec("ROLLBACK"); - } -} - -void transaction::commit() -{ - if (!commit_) { - exec("COMMIT"); - commit_ = true; - } -} - -} // !db::mlk
--- a/libdb/malikania/db/database.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * database.hpp -- connection to postgresql database - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_DB_DATABASE_HPP -#define MALIKANIA_DB_DATABASE_HPP - -/** - * \file database.hpp - * \brief Abstract database interface. - */ - -#include <cstdint> -#include <functional> -#include <memory> -#include <stdexcept> -#include <string> -#include <variant> -#include <vector> - -#include <libpq-fe.h> - -namespace mlk::db { - -/** - * \brief Statement argument. - * - * When using prepared statement, you may pass any data you like using this - * variant. - */ -using arg = std::variant< - bool, - double, - std::int8_t, - std::uint8_t, - std::int16_t, - std::uint16_t, - std::int32_t, - std::uint32_t, - std::int64_t, - std::uint64_t, - std::string ->; - -/** - * \brief Convenient result type. - * - * This unique pointer holds the PostgreSQL result and free it automatically on - * out of scope. - */ -using result = std::unique_ptr<PGresult, void (*)(PGresult*)>; - -/** - * Open the connection to the database. - * - * All arguments are optional. - * - * \pre connection must be closed - * \param host the hostname - * \param port the port number - * \param user the user name - * \param database the database name - * \param password the user password - * \throw std::runtime_error on errors - */ -void open(const std::string& host, - const std::string& port, - const std::string& user, - const std::string& database, - const std::string& password); - -/** - * Unconditionally init the database. - * - * \throw std::runtime_error on errors - */ -void init(); - -/** - * Execute a SELECT statement. - * - * \param sql the SQL statement - * \param args the optional arguments to bind - * \return the result value - * \throw std::runtime_error on errors - */ -auto select(const std::string& sql, const std::vector<arg>& args = {}) -> result; - -/** - * Execute an UPDATE statement. - * - * \param sql the SQL statement - * \param args the optional arguments to bind - * \throw std::runtime_error on errors - */ -void exec(const std::string& sql, const std::vector<arg>& args = {}); - -class transaction { -public: - /** - * \brief Rollback function. - */ - using rollback = std::function<void ()>; - -private: - rollback rollback_; - bool commit_{false}; - -public: - /** - * Start a transaction. - * - * If there is already a transaction, the returned object is no-op. - * - * \param rollback the rollback function - * \return the transaction object - */ - transaction(rollback fn); - - /** - * Rollback the transaction if commit() has not been called. - */ - ~transaction(); - - /** - * Commit the transaction. - * - * Does nothing if already committed. - * - * \throw std::exception on errors - */ - void commit(); -}; - -} // !mlk::db - -#endif // !MALIKANIA_DB_DATABASE_HPP
--- a/libdb/malikania/db/model.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * model.hpp -- abstract database object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_DB_MODEL_HPP -#define MALIKANIA_DB_MODEL_HPP - -/** - * \file model.hpp - * \brief Abstract database object. - */ - -#include <cstdint> - -namespace mlk::db { - -/** - * \brief Abstract database object. - */ -class model { -public: - /** - * Id type. - */ - using id_type = std::uint64_t; - -private: - model(const model&) = delete; - model& operator=(const model&) = delete; - -protected: - /** - * Object id. - */ - id_type id_{0U}; - -public: - /** - * Default constructor. - */ - model() = default; - - /** - * Move constructor. - * - * \param other the original value (id resets to 0) - */ - inline model(model&& other) noexcept - : id_(other.id_) - { - other.id_ = 0U; - } - - /** - * Virtual destructor defaulted. - */ - virtual ~model() noexcept = default; - - /** - * Get the id. - * - * \return the id - */ - auto get_id() const noexcept -> id_type - { - return id_; - } - - /** - * Tells if the object is not persistent. - * - * \return true if object was never saved - */ - auto is_draft() const noexcept -> bool - { - return id_ == 0U; - } - - /** - * Tells if the object is present in database - * - * \return true if object is saved - */ - auto is_published() const noexcept -> bool - { - return id_ > 0U; - } - - /** - * Move operator. - * - * \param other the original value (id resets to 0) - * \return *this - */ - auto operator=(model&& other) noexcept -> model& - { - id_ = other.id_; - other.id_ = 0U; - - return *this; - } -}; - -} // !mlk::db - -#endif // !MALIKANIA_DB_MODEL_HPP
--- a/libdb/malikania/db/spell.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * spell.cpp -- database spell object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> - -#include "character.hpp" -#include "spell.hpp" - -namespace mlk::db { - -auto spell::load(const result& result, int row) -> spell -{ - spell s(PQgetvalue(result.get(), row, 2)); - - s.id_ = std::stoi(PQgetvalue(result.get(), row, 0)); - s.level_ = std::stoi(PQgetvalue(result.get(), row, 3)); - - return s; -} - -auto spell::load(const character& parent) -> std::vector<spell> -{ - static const std::string sql( - "SELECT *" - " FROM spell" - " WHERE id = $1" - ); - - const auto r = select(sql, { parent.get_id() }); - - if (PQntuples(r.get()) == 0) - throw std::runtime_error("failed to load spells"); - - std::vector<spell> spells; - - for (int i = 0; i < PQntuples(r.get()); ++i) - spells.push_back(load(r, i)); - - return spells; -} - -void spell::clear() -{ - id_ = 0U; -} - -void spell::unpublish() -{ - static const std::string sql( - "DELETE" - " FROM spell" - " WHERE id = $1" - ); - - exec(sql, { id_ }); - clear(); -} - -void spell::publish(character& parent) -{ - static const std::string sql( - "INSERT INTO spell(" - " character_id," - " type," - " level" - ") " - "VALUES ($1, $2, $3) " - "RETURNING id" - ); - - const auto r = select(sql, { parent.get_id(), type_, level_ }); - - if (PQntuples(r.get()) == 0) - throw std::runtime_error("failed to save spell"); - - id_ = std::stoi(PQgetvalue(r.get(), 0, 0)); -} - -spell::spell(std::string type) noexcept - : type_(std::move(type)) -{ - assert(!type_.empty()); -} - -auto spell::get_type() const noexcept -> const std::string& -{ - return type_; -} - -auto spell::get_level() const noexcept -> std::uint8_t -{ - return level_; -} - -void spell::set_level(std::uint8_t level) -{ - static const std::string sql( - "UPDATE spell" - " SET level = $1" - " WHERE id = $2" - ); - - if (is_published() && level_ != level) - db::exec(sql, { level_, id_ }); - - level_ = level; -} - -} // !mlk::db
--- a/libdb/malikania/db/spell.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * spell.hpp -- database spell object - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_DB_SPELL_HPP -#define MALIKANIA_DB_SPELL_HPP - -/** - * \file spell.hpp - * \brief Database spell object. - */ - -#include <cstdint> -#include <string> -#include <vector> - -#include "database.hpp" -#include "model.hpp" - -namespace mlk::db { - -class character; - -/** - * \brief Describe a spell. - */ -class spell : public model { -private: - friend class character; - - std::string type_; - std::uint8_t level_{1U}; - - static auto load(const result&, int) -> spell; - static auto load(const character&) -> std::vector<spell>; - - void clear(); - void unpublish(); - void publish(character&); - -public: - /** - * Constructor. - * - * \pre !type.empty() - * \param type the type name - */ - spell(std::string type) noexcept; - - /** - * Get the type. - * - * \return the type - */ - auto get_type() const noexcept -> const std::string&; - - /** - * Get the level. - * - * \return the level - */ - auto get_level() const noexcept -> std::uint8_t; - - /** - * Set the spell level. - * - * \param level the level - */ - void set_level(std::uint8_t level); -}; - -} // !mlk::db - -#endif // !MALIKANIA_DB_SPELL_HPP
--- a/libmlk-client-js-test/malikania/client/js/test/js_api_fixture.hpp Wed Oct 24 21:13:12 2018 +0200 +++ b/libmlk-client-js-test/malikania/client/js/test/js_api_fixture.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -26,7 +26,7 @@ #include <malikania/client/color.hpp> -#include <malikania/js_color.hpp> +#include <malikania/client/js/color_js_api.hpp> #include <malikania/js/test/js_api_fixture.hpp>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,52 @@ +# +# CMakeLists.txt -- CMake build system for malikania +# +# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +project(libmlk-client-js) + +set( + HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/animation_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/animator_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/color_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/font_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/image_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/loader_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/sprite_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/window_js_api.hpp +) + +set( + SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/animation_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/animator_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/color_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/font_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/image_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/loader_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/sprite_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/js/window_js_api.cpp +) + +malikania_define_library( + PROJECT libmlk-client-js + TARGET libmlk-client-js + SOURCES ${HEADERS} ${SOURCES} + LIBRARIES libmlk-client libmlk-common-js + PUBLIC_INCLUDES + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/animation_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,100 @@ +/* + * animation_js_api.cpp -- animation description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/client/animation.hpp> +#include <malikania/client/loader.hpp> + +#include "animation_js_api.hpp" +#include "loader_js_api.hpp" + +namespace mlk::client::js { + +namespace { + +const std::string_view signature("\xff""\xff""Malikania.Animation.self"); + +auto Animation_constructor(duk_context* ctx) -> duk_ret_t +{ + if (!duk_is_constructor_call(ctx)) + duk_error(ctx, DUK_ERR_ERROR, "animation must be new-constructed"); + + try { + auto anim = mlk::js::duk::require<client::loader>(ctx, 0).load_animation(mlk::js::duk::require<std::string_view>(ctx, 0)); + + duk_push_this(ctx); + duk_push_pointer(ctx, new animation(std::move(anim))); + duk_put_prop_string(ctx, -2, signature.data()); + duk_pop(ctx); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Animation_destructor(duk_context* ctx) -> duk_ret_t +{ + duk_get_prop_string(ctx, 0, signature.data()); + delete static_cast<animation*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, signature.data()); + + return 0; +} + +} // !namespace + +void load_animation_api(duk_context* ctx) +{ + assert(ctx); + + mlk::js::duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Animation_constructor, 1); + duk_push_object(ctx); + duk_push_c_function(ctx, Animation_destructor, 1); + duk_set_finalizer(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Animation"); + duk_pop(ctx); +} + +} // !mlk::client::js + +namespace mlk::js::duk { + +auto type_traits<mlk::client::animation>::require(duk_context* ctx, duk_idx_t index) -> mlk::client::animation& +{ + assert(ctx); + + duk::stack_guard sa(ctx); + + duk_get_prop_string(ctx, index, mlk::client::js::signature.data()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animation object"); + + return *static_cast<mlk::client::animation*>(ptr); +} + +} // !mlk::js::duk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/animation_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,64 @@ +/* + * animation_js_api.hpp -- animation description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_ANIMATION_HPP +#define MALIKANIA_CLIENT_JS_ANIMATION_HPP + +#include <malikania/js/duk.hpp> + +namespace mlk { + +namespace client { + +struct animation; + +namespace js { + +/** + * Load Malikania.Animation API into the context. + * + * \warning you need to put a mlk::client::loader before use + * \param ctx the context + */ +void load_animation_api(duk_context* ctx); + +} // !js + +} // !client + +} // !mlk + +namespace mlk::js::duk { + +template <> +struct type_traits<client::animation> { + /** + * Get an animation object at the given index or raise a Javascript + * error. + * + * \pre ctx != nullptr + * \param ctx the context + * \param index the value index + * \return the Animation object + */ + static auto require(duk_context* ctx, duk_idx_t index) -> client::animation&; +}; + +} // !mlk::js::duk + +#endif // !MALIKANIA_JS_ANIMATION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/animator_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,121 @@ +/* + * animator_js_api.cpp -- animation drawing object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> +#include <string> + +#include <malikania/client/animator.hpp> + +#include <malikania/js/point_js_api.hpp> + +#include "animation_js_api.hpp" +#include "animator_js_api.hpp" +#include "window_js_api.hpp" + +namespace mlk::client::js { + +namespace { + +const std::string_view signature("\xff""\xff""Malikania.Animator.self"); + +auto self(duk_context* ctx) -> animator& +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature.data()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animator object"); + + return *static_cast<client::animator*>(ptr); +} + +auto Animator_constructor(duk_context* ctx) -> duk_ret_t +{ + if (!duk_is_constructor_call(ctx)) + duk_error(ctx, DUK_ERR_ERROR, "Animator must be new-constructed"); + + duk_push_this(ctx); + duk_push_pointer(ctx, new animator(mlk::js::duk::require<animation>(ctx, 0))); + duk_put_prop_string(ctx, -2, signature.data()); + + // Be sure animation get not collected before. + duk_dup(ctx, 0); + duk_put_prop_string(ctx, -2, "\xff""\xff""animation"); + duk_pop(ctx); + + return 0; +} + +auto Animator_destructor(duk_context* ctx) -> duk_ret_t +{ + duk_get_prop_string(ctx, 0, signature.data()); + delete static_cast<animator*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, signature.data()); + + return 0; +} + +auto Animator_draw(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).draw(mlk::js::duk::require<window>(ctx, 0), mlk::js::duk::get<point>(ctx, 1)); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Animator_update(duk_context* ctx) -> duk_ret_t +{ + self(ctx).update(); + + return 0; +} + +const duk_function_list_entry methods[] = { + { "draw", Animator_draw, 2 }, + { "update", Animator_update, 0 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +void load_animator_api(duk_context* ctx) +{ + assert(ctx); + + mlk::js::duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Animator_constructor, 1); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_push_c_function(ctx, Animator_destructor, 1); + duk_set_finalizer(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Animator"); + duk_pop(ctx); +} + +} // !mlk::client::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/animator_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,35 @@ +/* + * animator_js_api.hpp -- animation drawing object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_ANIMATOR_HPP +#define MALIKANIA_CLIENT_JS_ANIMATOR_HPP + +#include <malikania/js/duk.hpp> + +namespace mlk::client::js { + +/** + * Load Malikania.ElapsedTimer API into the context. + * + * \param ctx the context + */ +void load_animator_api(duk_context* ctx); + +} // !mlk::client:;js + +#endif // !MALIKANIA_CLIENT_JS_ANIMATOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/color_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,193 @@ +/* + * color_js_api.cpp -- color description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/client/color.hpp> + +#include "color_js_api.hpp" + +namespace mlk::client::js { + +namespace { + +auto parse_string(duk_context* ctx, duk_idx_t index, bool required) -> color +{ + assert(duk_is_string(ctx, index)); + + color ret; + + try { + ret = color::from_name(duk_get_string(ctx, index)); + } catch (const std::exception &ex) { + if (required) + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return ret; +} + +auto parse_object(duk_context* ctx, duk_idx_t index, bool required) -> color +{ + assert(duk_is_object(ctx, index)); + + duk_get_prop_string(ctx, index, "red"); + const auto red = mlk::js::duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "green"); + const auto green = mlk::js::duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "blue"); + const auto blue = mlk::js::duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "alpha"); + auto alpha = mlk::js::duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + + if (required) { + if (!red) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'red' property"); + if (!green) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'green' property"); + if (!blue) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'blue' property"); + } + + if (!alpha) + alpha = 255; + + return { + static_cast<std::uint8_t>(*red), + static_cast<std::uint8_t>(*green), + static_cast<std::uint8_t>(*blue), + static_cast<std::uint8_t>(*alpha) + }; +} + +auto parse(duk_context* ctx, duk_idx_t index, bool required, color ret = {}) -> color +{ + switch (duk_get_type(ctx, index)) { + case DUK_TYPE_STRING: + ret = parse_string(ctx, index, required); + break; + case DUK_TYPE_OBJECT: + ret = parse_object(ctx, index, required); + break; + default: + if (required) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "Color (string, object) expected"); + + break; + } + + return ret; +} + +auto Color_constructor(duk_context* ctx) -> duk_ret_t +{ + color obj; + + /* + * The constructor allows an additional signature that takes 4 number + * arguments, otherwise use the literal parsing functions. + */ + if (duk_get_top(ctx) >= 3) { + // Alpha is optional. + obj.red = mlk::js::duk::require<unsigned>(ctx, 0); + obj.green = mlk::js::duk::require<unsigned>(ctx, 1); + obj.blue = mlk::js::duk::require<unsigned>(ctx, 2); + obj.alpha = duk_is_number(ctx, 3) ? mlk::js::duk::get<unsigned>(ctx, 3) : 255; + } else if (duk_get_top(ctx) == 1) + obj = mlk::js::duk::require<color>(ctx, 0); + + duk_ret_t ret; + + // Allow both constructor and non constructor calls. + if (duk_is_constructor_call(ctx)) { + duk_push_this(ctx); + mlk::js::duk::put(ctx, obj); + duk_pop(ctx); + ret = 0; + } else { + mlk::js::duk::push(ctx, obj); + ret = 1; + } + + return ret; +} + +} // !namespace + +void load_color_api(duk_context* ctx) +{ + mlk::js::duk::stack_guard sa(ctx, 0); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Color_constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Color"); + duk_pop(ctx); +} + +} // !mlk::client::js + +namespace mlk::js::duk { + +auto type_traits<mlk::client::color>::get(duk_context* ctx, duk_idx_t index) -> mlk::client::color +{ + return mlk::client::js::parse(ctx, index, false); +} + +auto type_traits<mlk::client::color>::require(duk_context* ctx, duk_idx_t index) -> mlk::client::color +{ + return mlk::client::js::parse(ctx, index, true); +} + +auto type_traits<mlk::client::color>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<mlk::client::color> +{ + try { + return mlk::client::js::parse(ctx, index, false); + } catch (...) { + return mlk::client::color(); + } +} + +void type_traits<mlk::client::color>::push(duk_context* ctx, const mlk::client::color& color) +{ + mlk::js::duk::stack_guard sa(ctx, 1); + + duk_push_object(ctx); + put(ctx, color); +} + +void type_traits<mlk::client::color>::put(duk_context* ctx, const mlk::client::color& color) +{ + assert(duk_is_object(ctx, -1)); + + mlk::js::duk::stack_guard sa(ctx, 0); + + mlk::js::duk::push<unsigned>(ctx, color.red); + duk_put_prop_string(ctx, -2, "red"); + mlk::js::duk::push<unsigned>(ctx, color.green); + duk_put_prop_string(ctx, -2, "green"); + mlk::js::duk::push<unsigned>(ctx, color.blue); + duk_put_prop_string(ctx, -2, "blue"); + mlk::js::duk::push<unsigned>(ctx, color.alpha); + duk_put_prop_string(ctx, -2, "alpha"); +} + +} // !mlk::js::duk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/color_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,116 @@ +/* + * color_js_api.hpp -- color description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_COLOR_HPP +#define MALIKANIA_CLIENT_JS_COLOR_HPP + +/** + * \file js_color.hpp + * \brief JavaScript binding for color. + * + * Colors can be created from plain JavaScript object. + * + * ```` + * { + * red: 0, + * green: 255, + * blue: 255, + * alpha: 255 + * } + * ```` + * + * It can also takes strings like "#rrggbbaa" and SVG names. + */ + +#include <malikania/js/duk.hpp> + +namespace mlk { + +namespace client { + +struct color; + +namespace js { + +/** + * Load Malikania.ElapsedTimer API into the context. + * + * \param ctx the context + */ +void load_color_api(duk_context* ctx); + +} // !js + +} // !client + +} // !mlk + +namespace mlk::js::duk { + +template <> +struct type_traits<mlk::client::color> { + /** + * Get a color. + * + * May return a default value or a color with adjusted components. + * + * \param ctx the context + * \param index the index + */ + static auto get(duk_context* ctx, duk_idx_t index) -> mlk::client::color; + + /** + * Require a color. + * + * If the color has any invalid component, raise a JavaScript error. + * + * \param ctx the context + * \param index the index + */ + static auto require(duk_context* ctx, duk_idx_t index) -> mlk::client::color; + + /** + * Like get, but return the default value only if the value at the given + * index is not an object or not a string, otherwise, adjust invalid values. + * + * \param ctx the context + * \param index the index + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<mlk::client::color>; + + /** + * Push the color as object. + * + * \param ctx the context + * \param color the color + */ + static void push(duk_context* ctx, const mlk::client::color& color); + + /** + * Put the color properties into the object at the top of the stack. + * + * \pre the top value must be an object + * \param ctx the context + * \param color the color + */ + static void put(duk_context* ctx, const mlk::client::color& color); +}; + +} // !mlk::js::duk + +#endif // !MALIKANIA_CLIENT_JS_COLOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/font_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,125 @@ +/* + * font_js_api.cpp -- font object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/size.hpp> + +#include <malikania/client/loader.hpp> +#include <malikania/client/font.hpp> + +#include <malikania/js/size_js_api.hpp> + +#include "font_js_api.hpp" +#include "loader_js_api.hpp" + +namespace mlk::client::js { + +namespace { + +const std::string signature("\xff""\xff""Malikania.Font.self"); + +auto self(duk_context* ctx) -> font& +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a font object"); + + return *static_cast<font*>(ptr); +} + +auto Font_constructor(duk_context* ctx) -> duk_ret_t +{ + mlk::js::duk::stack_guard sa(ctx); + + if (!duk_is_constructor_call(ctx)) + duk_error(ctx, DUK_ERR_ERROR, "font must be new-constructed"); + + try { + auto id = mlk::js::duk::require<std::string_view>(ctx, 0); + auto size = mlk::js::duk::require<unsigned>(ctx, 1); + + duk_push_this(ctx); + duk_push_pointer(ctx, new font(mlk::js::duk::require<loader>(ctx, 0).load_font(id, size))); + duk_put_prop_string(ctx, -2, signature.c_str()); + duk_pop(ctx); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Font_prototype_clip(duk_context* ctx) -> duk_ret_t +{ + try { + mlk::js::duk::push(ctx, self(ctx).clip(mlk::js::duk::require<std::string>(ctx, 0))); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 1; +} + +const duk_function_list_entry methods[] = { + { "clip", Font_prototype_clip, 1 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +void load_font_api(duk_context* ctx) +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Font_constructor, 2); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Font"); + duk_pop(ctx); +} + +} // !mlk::client::js + +namespace mlk::js::duk { + +auto type_traits<mlk::client::font>::require(duk_context* ctx, duk_idx_t index) -> mlk::client::font& +{ + assert(ctx); + + mlk::js::duk::stack_guard sa(ctx); + + duk_get_prop_string(ctx, index, mlk::client::js::signature.data()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Font object"); + + return *static_cast<mlk::client::font*>(ptr); +} + +} // !mlk::js::duk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/font_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,54 @@ +/* + * font_js_api.hpp -- font object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_FONT_HPP +#define MALIKANIA_CLIENT_JS_FONT_HPP + +#include <malikania/js/duk.hpp> + +namespace mlk { + +namespace client { + +class font; + +namespace js { + +/** + * Load Malikania.Font API into the context. + * + * \param ctx the context + */ +void load_font_api(duk_context* ctx); + +} // !js + +} // !client + +} // !mlk + +namespace mlk::js::duk { + +template <> +struct type_traits<mlk::client::font> { + static auto require(duk_context* ctx, duk_idx_t index) -> mlk::client::font&; +}; + +} // !mlk::js::duk + +#endif // !MALIKANIA_CLIENT_JS_FONT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/image_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,125 @@ +/* + * image_js_api.cpp -- image object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/client/image.hpp> +#include <malikania/client/loader.hpp> +#include <malikania/client/window.hpp> + +#include <malikania/js/point_js_api.hpp> +#include <malikania/js/rectangle_js_api.hpp> +#include <malikania/js/size_js_api.hpp> + +#include "image_js_api.hpp" +#include "loader_js_api.hpp" +#include "window_js_api.hpp" + +namespace mlk::client::js { + +namespace { + +const std::string_view signature("\xff""\xff""Malikania.Image.self"); + +auto self(duk_context* ctx) -> image& +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature.data()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Image object"); + + return *static_cast<image*>(ptr); +} + +auto Image_property_get_size(duk_context* ctx) -> duk_ret_t +{ + try { + mlk::js::duk::push(ctx, self(ctx).get_size()); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 1; +} + +auto Image_prototype_draw(duk_context* ctx) -> duk_ret_t +{ + try { + auto& image = self(ctx); + auto& win= mlk::js::duk::require<window>(ctx, 0); + + if (duk_get_top(ctx) == 2) + image.draw(win, mlk::js::duk::get<point>(ctx, 1)); + else if (duk_get_top(ctx) == 3) + image.draw(win, mlk::js::duk::get<rectangle>(ctx, 1), mlk::js::duk::get<rectangle>(ctx, 2)); + else + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid number of arguments: #%d", duk_get_top(ctx)); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Image_constructor(duk_context* ctx) -> duk_ret_t +{ + if (!duk_is_constructor_call(ctx)) + duk_error(ctx, DUK_ERR_ERROR, "Image must be new-constructed"); + + try { + duk_push_this(ctx); + duk_push_pointer(ctx, new image(mlk::js::duk::require<loader>(ctx, 0) + .load_image(mlk::js::duk::require<std::string_view>(ctx, 0)))); + duk_put_prop_string(ctx, -2, signature.data()); + duk_push_string(ctx, "size"); + duk_push_c_function(ctx, Image_property_get_size, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_pop(ctx); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +const duk_function_list_entry methods[] = { + { "draw", Image_prototype_draw, DUK_VARARGS }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +void load_image_api(duk_context* ctx) +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Image_constructor, 1); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Image"); + duk_pop(ctx); +} + +} // !mlk::client::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/image_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,35 @@ +/* + * image_js_api.hpp -- image object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_IMAGE_HPP +#define MALIKANIA_CLIENT_JS_IMAGE_HPP + +#include <malikania/js/duk.hpp> + +namespace mlk::client::js { + +/** + * Load Malikania.Image API into the context. + * + * \param ctx the context + */ +void load_image_api(duk_context* ctx); + +} // !mlk::client::js + +#endif // !MALIKANIA_CLIENT_JS_IMAGE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/loader_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,61 @@ +/* + * loader_js_api.cpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/client/loader.hpp> + +#include <malikania/js/loader_js_api.hpp> + +#include "loader_js_api.hpp" + +namespace mlk::js::duk { + +namespace { + +const std::string_view variable("\xff""\xff""Malikania.ClientLoader"); + +} // !namespace + +void type_traits<mlk::client::loader>::put(duk_context* ctx, mlk::client::loader& loader) +{ + assert(ctx); + + // Also store as parent. + type_traits<mlk::loader>::put(ctx, loader); + + duk::stack_guard sa(ctx); + + duk_push_pointer(ctx, &loader); + duk_put_global_string(ctx, variable.data()); +} + +auto type_traits<mlk::client::loader>::require(duk_context* ctx, duk_idx_t) -> mlk::client::loader& +{ + assert(ctx); + + duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, variable.data()); + auto ptr = static_cast<mlk::client::loader*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return *static_cast<mlk::client::loader*>(ptr); +} + +} // !mlk::js::duk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/loader_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,45 @@ +/* + * loader_js_api.hpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_LOADER_HPP +#define MALIKANIA_CLIENT_JS_LOADER_HPP + +#include <malikania/js/duk.hpp> + +namespace mlk { + +namespace client { + +class loader; + +} // !client + +} // !mlk + +namespace mlk::js::duk { + +template <> +struct type_traits<mlk::client::loader> { + static void put(duk_context* ctx, mlk::client::loader& loader); + + static auto require(duk_context* ctx, duk_idx_t) -> mlk::client::loader&; +}; + +} // !mlk::js::duk + +#endif // !MALIKANIA_CLIENT_JS_LOADER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/sprite_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,160 @@ +/* + * sprite_js_api.cpp -- sprite object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/client/loader.hpp> +#include <malikania/client/sprite.hpp> +#include <malikania/client/window.hpp> + +#include <malikania/js/point_js_api.hpp> +#include <malikania/js/size_js_api.hpp> + +#include "loader_js_api.hpp" +#include "sprite_js_api.hpp" +#include "window_js_api.hpp" + +namespace mlk::client::js { + +namespace { + +const std::string signature("\xff""\xff""Malikania.Sprite.self"); + +auto self(duk_context *ctx) -> sprite& +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Sprite object"); + + return *static_cast<sprite*>(ptr); +} + +auto Sprite_property_get_cell(duk_context* ctx) -> duk_ret_t +{ + return mlk::js::duk::push(ctx, self(ctx).get_cell()); +} + +auto Sprite_property_get_columns(duk_context* ctx) -> duk_ret_t +{ + return mlk::js::duk::push(ctx, self(ctx).get_columns()); +} + +auto Sprite_property_get_margins(duk_context* ctx) -> duk_ret_t +{ + return mlk::js::duk::push(ctx, self(ctx).get_margin()); +} + +auto Sprite_property_get_rows(duk_context* ctx) -> duk_ret_t +{ + return mlk::js::duk::push(ctx, self(ctx).get_rows()); +} + +auto Sprite_property_get_space(duk_context *ctx) -> duk_ret_t +{ + return mlk::js::duk::push(ctx, self(ctx).get_space()); +} + +auto Sprite_constructor(duk_context *ctx) -> duk_ret_t +{ + if (!duk_is_constructor_call(ctx)) + duk_error(ctx, DUK_ERR_ERROR, "Sprite must be new-constructed"); + + try { + auto sp = mlk::js::duk::require<loader>(ctx, 0).load_sprite(duk_require_string(ctx, 0)); + + duk_push_this(ctx); + duk_push_pointer(ctx, new sprite(std::move(sp))); + duk_put_prop_string(ctx, -2, signature.data()); + + // Cell. + duk_push_string(ctx, "cell"); + duk_push_c_function(ctx, Sprite_property_get_cell, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + + // Columns. + duk_push_string(ctx, "columns"); + duk_push_c_function(ctx, Sprite_property_get_columns, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + + // Margins. + duk_push_string(ctx, "margins"); + duk_push_c_function(ctx, Sprite_property_get_margins, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + + // Rows. + duk_push_string(ctx, "rows"); + duk_push_c_function(ctx, Sprite_property_get_rows, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + + // Space. + duk_push_string(ctx, "space"); + duk_push_c_function(ctx, Sprite_property_get_space, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + + duk_pop(ctx); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Sprite_prototype_draw(duk_context *ctx) -> duk_ret_t +{ + try { + auto& sprite = self(ctx); + auto& win = mlk::js::duk::require<window>(ctx, 0); + auto cell = mlk::js::duk::require<unsigned>(ctx, 1); + auto position = mlk::js::duk::require<point>(ctx, 2); + + if (cell >= sprite.get_total()) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "cell %d is out of range", cell); + + sprite.draw(win, cell, position); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +const duk_function_list_entry methods[] = { + { "draw", Sprite_prototype_draw, 3 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +void load_sprite_api(duk_context* ctx) +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Sprite_constructor, 1); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Sprite"); + duk_pop(ctx); +} + +} // !mlk::client::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/sprite_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,35 @@ +/* + * sprite_js_api.hpp -- sprite object (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_SPRITE_HPP +#define MALIKANIA_CLIENT_JS_SPRITE_HPP + +#include <malikania/js/duk.hpp> + +namespace mlk::client::js { + +/** + * Load Malikania.Sprite API into the context. + * + * \param ctx the context + */ +void load_sprite_api(duk_context* ctx); + +} // !mlk::client::js + +#endif // !MALIKANIA_CLIENT_JS_SPRITE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/window_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,232 @@ +/* + * window_js_api.cpp -- window management (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/line.hpp> +#include <malikania/rectangle.hpp> + +#include <malikania/client/color.hpp> +#include <malikania/client/window.hpp> + +#include <malikania/js/line_js_api.hpp> +#include <malikania/js/point_js_api.hpp> +#include <malikania/js/rectangle_js_api.hpp> + +#include "color_js_api.hpp" +#include "font_js_api.hpp" +#include "window_js_api.hpp" + +namespace mlk::client::js { + +namespace { + +const std::string_view signature("\xff""\xff""Malikania.Window.self"); +const std::string_view prototype("\xff""\xff""Malikania.Window.prototype"); + +auto self(duk_context* ctx) -> window& +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature.data()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Window object"); + + return *static_cast<window*>(ptr); +} + +auto Window_constructor(duk_context* ctx) -> duk_ret_t +{ + mlk::js::duk::stack_guard sa(ctx); + + if (!duk_is_constructor_call(ctx)) + duk_error(ctx, DUK_ERR_ERROR, "window must be new-constructed"); + + // TODO: add parameters. + try { + duk_push_this(ctx); + duk_push_pointer(ctx, new window); + duk_put_prop_string(ctx, -2, signature.data()); + duk_pop(ctx); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_clear(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).clear(); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_present(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).present(); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_drawingColor(duk_context* ctx) -> duk_ret_t +{ + try { + mlk::js::duk::push(ctx, self(ctx).get_drawing_color()); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 1; +} + +auto Window_prototype_drawLine(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).draw_line(mlk::js::duk::get<line>(ctx, 0)); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_drawPoint(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).draw_point(mlk::js::duk::get<point>(ctx, 0)); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_drawRectangle(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).draw_rectangle(mlk::js::duk::get<rectangle>(ctx, 0)); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_drawText(duk_context* ctx) -> duk_ret_t +{ + try { + auto& win = self(ctx); + auto text = mlk::js::duk::require<std::string>(ctx, 0); + auto& fnt = mlk::js::duk::require<font>(ctx, 1); + auto rect = mlk::js::duk::get<rectangle>(ctx, 2); + + if (!rect.is_null()) + win.draw_text(text, fnt, rect); + else + win.draw_text(text, fnt, point{rect.x, rect.y}); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_fillRectangle(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).fill_rectangle(mlk::js::duk::get<rectangle>(ctx, 0)); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +auto Window_prototype_setDrawingColor(duk_context* ctx) -> duk_ret_t +{ + try { + self(ctx).set_drawing_color(mlk::js::duk::get<color>(ctx, 0)); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +const duk_function_list_entry methods[] = { + { "clear", Window_prototype_clear, 0 }, + { "drawingColor", Window_prototype_drawingColor, 0 }, + { "drawLine", Window_prototype_drawLine, 1 }, + { "drawPoint", Window_prototype_drawPoint, 1 }, + { "drawRectangle", Window_prototype_drawRectangle, 1 }, + { "drawText", Window_prototype_drawText, 3 }, + { "fillRectangle", Window_prototype_fillRectangle, 1 }, + { "present", Window_prototype_present, 0 }, + { "setDrawingColor", Window_prototype_setDrawingColor, 1 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +void load_window_api(duk_context* ctx) +{ + mlk::js::duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Window_constructor, 0); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Window"); + duk_pop(ctx); +} + +} // !mlk::client::js + +namespace mlk::js::duk { + +auto type_traits<mlk::client::window>::require(duk_context* ctx, duk_idx_t index) -> mlk::client::window& +{ + assert(ctx); + + mlk::js::duk::stack_guard sa(ctx); + + duk_get_prop_string(ctx, index, mlk::client::js::signature.data()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Window object"); + + return *static_cast<mlk::client::window*>(ptr); +} + +} // !mlk::js::duk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client-js/malikania/client/js/window_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,54 @@ +/* + * window_js_api.hpp -- window management (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_JS_WINDOW_HPP +#define MALIKANIA_CLIENT_JS_WINDOW_HPP + +#include <malikania/js/duk.hpp> + +namespace mlk { + +namespace client { + +class window; + +namespace js { + +/** + * Load Malikania.Window API into the context. + * + * \param ctx the context + */ +void load_window_api(duk_context* ctx); + +} // !client + +} // !js + +} // !mlk + +namespace mlk::js::duk { + +template <> +struct type_traits<client::window> { + static auto require(duk_context* ctx, duk_idx_t index) -> client::window&; +}; + +} // !mlk::js::duk + +#endif // !MALIKANIA_CLIENT_JS_WINDOW_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,94 @@ +# +# CMakeLists.txt -- CMake build system for malikania +# +# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +project(libmlk-client) + +find_package(Boost REQUIRED COMPONENTS timer) + +set( + HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/animation.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/animator.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/button.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/client.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/color.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/connection.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/dispatcher.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/font.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/image.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/key.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/label.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/loader.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/mouse.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/sdl_util.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/sprite.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/state.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/state/lobby_state.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/state/login_state.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/state/map_state.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/theme.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/widget.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/window.hpp +) + +set( + SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/animator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/button.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/client.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/color.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/connection.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/font.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/image.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/label.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/sdl_util.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/sprite.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/state/lobby_state.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/state/login_state.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/state/map_state.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/theme.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/widget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client/window.cpp +) + +find_package(OpenSSL REQUIRED) +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) +find_package(SDL2_ttf REQUIRED) + +malikania_define_library( + PROJECT libmlk-client + TARGET libmlk-client + SOURCES ${HEADERS} ${SOURCES} + ASSETS ${libmlk-client_SOURCE_DIR}/assets/dejavu_sans.ttf + PUBLIC_INCLUDES + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + ${SDL2_INCLUDE_DIRS} + ${SDL2_IMAGE_INCLUDE_DIRS} + ${SDL2_TTF_INCLUDE_DIRS} + LIBRARIES + ${SDL2_LIBRARIES} + ${SDL2_IMAGE_LIBRARIES} + ${SDL2_TTF_LIBRARIES} + libmlk + Boost::boost + Boost::timer + OpenSSL::SSL + OpenSSL::Crypto +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/animation.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,64 @@ +/* + * animation.hpp -- animation description + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_ANIMATION_HPP +#define MALIKANIA_CLIENT_ANIMATION_HPP + +/** + * \file animation.hpp + * \brief Describe an animation. + */ + +#include <cstdint> +#include <vector> +#include <utility> + +#include "sprite.hpp" + +namespace mlk::client { + +/** + * \brief Animation description. + * + * An animation is composed of a sprite and a set of frames. For example, if + * your sprite has several images, you can select only the one you want by + * specifying the index in each frame. + * + * \see animator + */ +struct animation { + /** + * \brief Delay between each frames. + */ + struct frame { + std::uint64_t cell{0U}; //!< sprite cell index + std::uint64_t delay{50U}; //!< delay in milliseconds + }; + + /** + * \brief List of frames. + */ + using frame_list = std::vector<frame>; + + mlk::client::sprite sprite; //!< sprite used + mlk::client::animation::frame_list frames; //!< list of frames +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_ANIMATION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/animator.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,55 @@ +/* + * animator.cpp -- animation drawing object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include "animation.hpp" +#include "animator.hpp" + +namespace mlk::client { + +animator::animator(animation& animation) noexcept + : animation_(animation) + , current_(animation_.frames.begin()) +{ +} + +void animator::reset() noexcept +{ + timer_.start(); + current_ = animation_.frames.begin(); +} + +void animator::update() noexcept +{ + if (current_ == animation_.frames.end()) + return; + + if (timer_.elapsed().wall / 1000000LL >= static_cast<long long>(current_->delay)) { + current_ ++; + timer_.start(); + } +} + +void animator::draw(window& window, const point& point) +{ + if (current_ != animation_.frames.end()) + animation_.sprite.draw(window, current_->cell, point); +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/animator.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,85 @@ +/* + * animator.hpp -- animation drawing object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_ANIMATOR_HPP +#define MALIKANIA_CLIENT_ANIMATOR_HPP + +/** + * \file animator.hpp + * \brief Draw animations. + */ + +#include <boost/timer/timer.hpp> + +#include "animation.hpp" + +namespace mlk { + +struct point; + +namespace client { + +class window; + +/** + * \brief Object for drawing animations. + * + * The animator contains an animation and a state. + */ +class animator { +private: + boost::timer::cpu_timer timer_; + animation& animation_; + animation::frame_list::const_iterator current_; + +public: + /** + * Construct an animator. + * + * \pre animation must not be null + * \param animation the animation + */ + animator(animation& animation) noexcept; + + /** + * Reset the animator to the beginning. + */ + void reset() noexcept; + + /** + * Update the animator state. + * + * This function should be called in the main loop to update the cell + * to draw before calling draw(). + */ + void update() noexcept; + + /** + * Draw the animation. + * + * \param window the window + * \param position the position in the window + */ + void draw(window& window, const point& position); +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_ANIMATOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/button.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,54 @@ +/* + * button.cpp -- GUI button element + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "button.hpp" +#include "theme.hpp" +#include "window.hpp" + +namespace mlk::client { + +button::button(std::string text) + : text_(std::move(text)) +{ +} + +auto button::get_text() const noexcept -> const std::string& +{ + return text_; +} + +void button::set_text(std::string text) noexcept +{ + text_ = std::move(text); +} + +void button::handle_mouse_down(const mouse_click_event& ev) +{ + if (ev.button == mouse::left && on_press_) + on_press_(); + + // TODO: implement release. +} + +void button::draw(window& w, const size& size) +{ + (void)w; + (void)size; +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/button.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,88 @@ +/* + * button.hpp -- GUI button element + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_BUTTON_HPP +#define MALIKANIA_CLIENT_BUTTON_HPP + +/** + * \file button.hpp + * \brief GUI button element. + */ + +#include <functional> +#include <string> + +#include "widget.hpp" + +namespace mlk::client { + +/** + * \brief Basic button element. + */ +class button : public widget { +public: + using on_press_func = std::function<void ()>; + using on_release_func = std::function<void ()>; + +private: + on_press_func on_press_; + on_release_func on_released_; + + std::string text_; + +public: + /** + * Default constructor with optional text. + * + * \param text the text + */ + button(std::string text = ""); + + /** + * Get the button text. + * + * \return the text + */ + auto get_text() const noexcept -> const std::string&; + + /** + * Set the button text. + * + * \param text the text + */ + void set_text(std::string text) noexcept; + + /** + * \copydoc widget::handle_mouse_down + */ + void handle_mouse_down(const mouse_click_event& ev) override; + + /** + * Bring back other functions. + */ + using widget::draw; + + /** + * \copydoc widget::draw + */ + void draw(window& w, const size& size) override; +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_BUTTON_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/client.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,176 @@ +/* + * client.cpp -- main client game clas + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <iostream> +#include <thread> + +#include "client.hpp" +#include "connection.hpp" +#include "state.hpp" +#include "window.hpp" + +namespace mlk { + +namespace client { + +client::client(boost::asio::io_service& service, + mlk::client::connection& connection, + mlk::client::window& window) noexcept + : service_(service) + , connection_(connection) + , window_(window) +{ +} + +client::~client() noexcept = default; + +void client::recv() +{ + // Network thread space. + connection_.recv([this] (auto code, auto message) { + if (!code) + recv(); + + std::lock_guard<std::mutex> lock(nmutex_); + + nqueue_.push_back(std::bind(&client::handle_message, this, code, message)); + }); +} + +void client::connect(std::string host, std::uint16_t port) +{ + service_.post([this, host, port] () { + connection_.connect(host, port, [this] (auto code) { + // Start receiveing on success. + if (!code) + recv(); + + // Push the result to the main loop queue. + std::lock_guard<std::mutex> lock(nmutex_); + + nqueue_.push_back(std::bind(&client::handle_connect, this, code)); + }); + }); +} + +void client::send(nlohmann::json message) +{ + service_.post([this, message] () { + // TODO: error checking. + connection_.send(std::move(message), nullptr); + }); +} + +void client::set_state(std::unique_ptr<state> state) +{ + state_next_ = std::move(state); +} + +void client::handle_connect(const std::error_code& code) +{ + if (state_) + state_->handle_connect(code); +} + +void client::handle_message(const std::error_code& code, const nlohmann::json& msg) +{ + if (state_) + state_->handle_message(code, msg); +} + +void client::handle_key_down(const key_event& ev) +{ + if (state_) + state_->handle_key_down(ev); +} + +void client::handle_key_up(const key_event& ev) +{ + if (state_) + state_->handle_key_up(ev); +} + +void client::handle_mouse_down(const mouse_click_event& ev) +{ + if (state_) + state_->handle_mouse_down(ev); +} + +void client::handle_mouse_up(const mouse_click_event& ev) +{ + if (state_) + state_->handle_mouse_up(ev); +} + +void client::handle_mouse_wheel(const mouse_wheel_event& ev) +{ + if (state_) + state_->handle_mouse_wheel(ev); +} + +void client::handle_text(const text_event& ev) +{ + if (state_) + state_->handle_text(ev); +} + +void client::handle_quit() +{ + window_.close(); + service_.stop(); +} + +void client::run() +{ + std::thread t([this] () { + // TODO: change to an atomic member variable. + while (window_.is_open()) { + service_.reset(); + service_.run(); + } + }); + + while (window_.is_open()) { + // Network events. + { + std::lock_guard<std::mutex> lock(nmutex_); + + for (auto& ev : nqueue_) + ev(); + + nqueue_.clear(); + } + + // State and input events. + if (state_next_) + state_ = std::move(state_next_); + + window_.poll(*this); + + if (state_) { + state_->update(*this); + state_->draw(*this); + } + } + + t.join(); +} + +} // !client + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/client.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,180 @@ +/* + * client.hpp -- main client game clas + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_CLIENT_HPP +#define MALIKANIA_CLIENT_CLIENT_HPP + +/** + * \file client.hpp + * \brief Main client game class. + */ + +#include <functional> +#include <memory> +#include <mutex> +#include <vector> +#include <system_error> + +#include <boost/asio.hpp> + +#include <json.hpp> + +#include "dispatcher.hpp" + +namespace mlk { + +namespace client { + +class connection; +class state; +class window; + +/** + * \brief Main client game class + */ +class client : public dispatcher { +private: + boost::asio::io_service& service_; + + mlk::client::connection& connection_; + mlk::client::window& window_; + + std::unique_ptr<state> state_; + std::unique_ptr<state> state_next_; + std::mutex nmutex_; + std::vector<std::function<void ()>> nqueue_; + + void recv(); + +public: + /** + * Construct the client, no connection attempt will be made yet. + * + * \param service the I/O service + * \param connection the connection object + * \param window the window + */ + client(boost::asio::io_service& service, + mlk::client::connection& connection, + mlk::client::window& window) noexcept; + + /** + * Virtual destructor defaulted. + */ + virtual ~client() noexcept; + + /** + * Get the window. + * + * \return the window + */ + inline const mlk::client::window& window() const noexcept + { + return window_; + } + + /** + * Overloaded function. + * + * \return the window + */ + inline mlk::client::window& window() noexcept + { + return window_; + } + + /** + * Connect to the server. + * + * This is an alias of connection_.connect(*this, host, port); + * + * \param host the hostname + * \param port the port number + */ + void connect(std::string host, std::uint16_t port); + + /** + * Send a message. + * + * \param message the message + */ + void send(nlohmann::json message); + + /** + * Set the client state. + * + * \param state the state + */ + void set_state(std::unique_ptr<state>); + + /** + * Run the client until the game window is closed. + */ + void run(); + + /** + * \copydoc dispatcher::handle_connect + */ + void handle_connect(const std::error_code& code) override; + + /** + * \copydoc dispatcher::handle_message + */ + void handle_message(const std::error_code& code, const nlohmann::json& msg) override; + + /** + * \copydoc dispatcher::handle_key_down + */ + void handle_key_down(const key_event& ev) override; + + /** + * \copydoc dispatcher::handle_key_up + */ + void handle_key_up(const key_event& ev) override; + + /** + * \copydoc dispatcher::handle_mouse_down + */ + void handle_mouse_down(const mouse_click_event& ev) override; + + /** + * \copydoc dispatcher::handle_mouse_up + */ + void handle_mouse_up(const mouse_click_event& ev) override; + + /** + * \copydoc dispatcher::handle_mouse_wheel + */ + void handle_mouse_wheel(const mouse_wheel_event& ev) override; + + /** + * \copydoc dispatcher::handle_text + */ + void handle_text(const text_event& ev) override; + + /** + * \copydoc dispatcher::handle_quit + */ + void handle_quit() override; +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_CLIENT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/color.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,247 @@ +/* + * color.cpp -- color description + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cctype> +#include <locale> +#include <unordered_map> + +#include "color.hpp" + +namespace mlk::client { + +namespace { + +constexpr auto rgb(std::uint8_t r, std::uint8_t g, std::uint8_t b) noexcept -> unsigned +{ + return (0xff000000 | (r << 16) | (g << 8) | b); +} + +/* + * Convert hexadecimal value to the correct number. + */ +auto value(char digit) -> std::uint8_t +{ + if (std::isdigit(digit, {})) + return digit - '0'; + if ((digit = std::toupper(digit, {})) < 'A' || digit > 'F') + throw std::invalid_argument("invalid hexadecimal value: " + std::to_string(digit)); + + return digit - 55; +} + +auto value(char digit1, char digit2) -> std::uint8_t +{ + return ((value(digit1) << 4) & 0xf0) | value(digit2); +} + +const std::unordered_map<std::string_view, std::uint32_t> colors{ + { "aliceblue", rgb(240, 248, 255) }, + { "antiquewhite", rgb(250, 235, 215) }, + { "aqua", rgb( 0, 255, 255) }, + { "aquamarine", rgb(127, 255, 212) }, + { "azure", rgb(240, 255, 255) }, + { "beige", rgb(245, 245, 220) }, + { "bisque", rgb(255, 228, 196) }, + { "black", rgb( 0, 0, 0) }, + { "blanchedalmond", rgb(255, 235, 205) }, + { "blue", rgb( 0, 0, 255) }, + { "blueviolet", rgb(138, 43, 226) }, + { "brown", rgb(165, 42, 42) }, + { "burlywood", rgb(222, 184, 135) }, + { "cadetblue", rgb( 95, 158, 160) }, + { "chartreuse", rgb(127, 255, 0) }, + { "chocolate", rgb(210, 105, 30) }, + { "coral", rgb(255, 127, 80) }, + { "cornflowerblue", rgb(100, 149, 237) }, + { "cornsilk", rgb(255, 248, 220) }, + { "crimson", rgb(220, 20, 60) }, + { "cyan", rgb( 0, 255, 255) }, + { "darkblue", rgb( 0, 0, 139) }, + { "darkcyan", rgb( 0, 139, 139) }, + { "darkgoldenrod", rgb(184, 134, 11) }, + { "darkgray", rgb(169, 169, 169) }, + { "darkgreen", rgb( 0, 100, 0) }, + { "darkgrey", rgb(169, 169, 169) }, + { "darkkhaki", rgb(189, 183, 107) }, + { "darkmagenta", rgb(139, 0, 139) }, + { "darkolivegreen", rgb( 85, 107, 47) }, + { "darkorange", rgb(255, 140, 0) }, + { "darkorchid", rgb(153, 50, 204) }, + { "darkred", rgb(139, 0, 0) }, + { "darksalmon", rgb(233, 150, 122) }, + { "darkseagreen", rgb(143, 188, 143) }, + { "darkslateblue", rgb( 72, 61, 139) }, + { "darkslategray", rgb( 47, 79, 79) }, + { "darkslategrey", rgb( 47, 79, 79) }, + { "darkturquoise", rgb( 0, 206, 209) }, + { "darkviolet", rgb(148, 0, 211) }, + { "deeppink", rgb(255, 20, 147) }, + { "deepskyblue", rgb( 0, 191, 255) }, + { "dimgray", rgb(105, 105, 105) }, + { "dimgrey", rgb(105, 105, 105) }, + { "dodgerblue", rgb( 30, 144, 255) }, + { "firebrick", rgb(178, 34, 34) }, + { "floralwhite", rgb(255, 250, 240) }, + { "forestgreen", rgb( 34, 139, 34) }, + { "fuchsia", rgb(255, 0, 255) }, + { "gainsboro", rgb(220, 220, 220) }, + { "ghostwhite", rgb(248, 248, 255) }, + { "gold", rgb(255, 215, 0) }, + { "goldenrod", rgb(218, 165, 32) }, + { "gray", rgb(128, 128, 128) }, + { "green", rgb( 0, 128, 0) }, + { "greenyellow", rgb(173, 255, 47) }, + { "grey", rgb(128, 128, 128) }, + { "honeydew", rgb(240, 255, 240) }, + { "hotpink", rgb(255, 105, 180) }, + { "indianred", rgb(205, 92, 92) }, + { "indigo", rgb( 75, 0, 130) }, + { "ivory", rgb(255, 255, 240) }, + { "khaki", rgb(240, 230, 140) }, + { "lavender", rgb(230, 230, 250) }, + { "lavenderblush", rgb(255, 240, 245) }, + { "lawngreen", rgb(124, 252, 0) }, + { "lemonchiffon", rgb(255, 250, 205) }, + { "lightblue", rgb(173, 216, 230) }, + { "lightcoral", rgb(240, 128, 128) }, + { "lightcyan", rgb(224, 255, 255) }, + { "lightgoldenrodyellow", rgb(250, 250, 210) }, + { "lightgray", rgb(211, 211, 211) }, + { "lightgreen", rgb(144, 238, 144) }, + { "lightgrey", rgb(211, 211, 211) }, + { "lightpink", rgb(255, 182, 193) }, + { "lightsalmon", rgb(255, 160, 122) }, + { "lightseagreen", rgb( 32, 178, 170) }, + { "lightskyblue", rgb(135, 206, 250) }, + { "lightslategray", rgb(119, 136, 153) }, + { "lightslategrey", rgb(119, 136, 153) }, + { "lightsteelblue", rgb(176, 196, 222) }, + { "lightyellow", rgb(255, 255, 224) }, + { "lime", rgb( 0, 255, 0) }, + { "limegreen", rgb( 50, 205, 50) }, + { "linen", rgb(250, 240, 230) }, + { "magenta", rgb(255, 0, 255) }, + { "maroon", rgb(128, 0, 0) }, + { "mediumaquamarine", rgb(102, 205, 170) }, + { "mediumblue", rgb( 0, 0, 205) }, + { "mediumorchid", rgb(186, 85, 211) }, + { "mediumpurple", rgb(147, 112, 219) }, + { "mediumseagreen", rgb( 60, 179, 113) }, + { "mediumslateblue", rgb(123, 104, 238) }, + { "mediumspringgreen", rgb( 0, 250, 154) }, + { "mediumturquoise", rgb( 72, 209, 204) }, + { "mediumvioletred", rgb(199, 21, 133) }, + { "midnightblue", rgb( 25, 25, 112) }, + { "mintcream", rgb(245, 255, 250) }, + { "mistyrose", rgb(255, 228, 225) }, + { "moccasin", rgb(255, 228, 181) }, + { "navajowhite", rgb(255, 222, 173) }, + { "navy", rgb( 0, 0, 128) }, + { "oldlace", rgb(253, 245, 230) }, + { "olive", rgb(128, 128, 0) }, + { "olivedrab", rgb(107, 142, 35) }, + { "orange", rgb(255, 165, 0) }, + { "orangered", rgb(255, 69, 0) }, + { "orchid", rgb(218, 112, 214) }, + { "palegoldenrod", rgb(238, 232, 170) }, + { "palegreen", rgb(152, 251, 152) }, + { "paleturquoise", rgb(175, 238, 238) }, + { "palevioletred", rgb(219, 112, 147) }, + { "papayawhip", rgb(255, 239, 213) }, + { "peachpuff", rgb(255, 218, 185) }, + { "peru", rgb(205, 133, 63) }, + { "pink", rgb(255, 192, 203) }, + { "plum", rgb(221, 160, 221) }, + { "powderblue", rgb(176, 224, 230) }, + { "purple", rgb(128, 0, 128) }, + { "red", rgb(255, 0, 0) }, + { "rosybrown", rgb(188, 143, 143) }, + { "royalblue", rgb( 65, 105, 225) }, + { "saddlebrown", rgb(139, 69, 19) }, + { "salmon", rgb(250, 128, 114) }, + { "sandybrown", rgb(244, 164, 96) }, + { "seagreen", rgb( 46, 139, 87) }, + { "seashell", rgb(255, 245, 238) }, + { "sienna", rgb(160, 82, 45) }, + { "silver", rgb(192, 192, 192) }, + { "skyblue", rgb(135, 206, 235) }, + { "slateblue", rgb(106, 90, 205) }, + { "slategray", rgb(112, 128, 144) }, + { "slategrey", rgb(112, 128, 144) }, + { "snow", rgb(255, 250, 250) }, + { "springgreen", rgb( 0, 255, 127) }, + { "steelblue", rgb( 70, 130, 180) }, + { "tan", rgb(210, 180, 140) }, + { "teal", rgb( 0, 128, 128) }, + { "thistle", rgb(216, 191, 216) }, + { "tomato", rgb(255, 99, 71) }, + { "transparent", 0 }, + { "turquoise", rgb( 64, 224, 208) }, + { "violet", rgb(238, 130, 238) }, + { "wheat", rgb(245, 222, 179) }, + { "white", rgb(255, 255, 255) }, + { "whitesmoke", rgb(245, 245, 245) }, + { "yellow", rgb(255, 255, 0) }, + { "yellowgreen", rgb(154, 205, 50) } +}; + +} // !namespace + +auto color::from_hex(std::uint32_t hex) noexcept -> color +{ + return { + static_cast<std::uint8_t>((hex >> 16) & 0xff), + static_cast<std::uint8_t>((hex >> 8) & 0xff), + static_cast<std::uint8_t>((hex & 0xff)), + static_cast<std::uint8_t>((hex >> 24) & 0xff) + }; +} + +auto color::from_name(std::string_view name) -> color +{ + if (name.empty()) + return color(); + + color result; + + // Parse #rrggbb or #rgb. + if (name[0] == '#') { + if (name.length() == 7) { + result.red = value(name[1], name[2]); + result.green = value(name[3], name[4]); + result.blue = value(name[5], name[6]); + } else if (name.length() == 4) { + result.red = value(name[1], name[1]); + result.green = value(name[2], name[2]); + result.blue = value(name[3], name[3]); + } else + throw std::invalid_argument("invalid format"); + } else { + // Name lookup. + const auto it = colors.find(name); + + if (it == colors.end()) + throw std::invalid_argument("invalid color"); + + result = from_hex(it->second); + } + + return result; +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/color.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,61 @@ +/* + * color.hpp -- color description + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_COLOR_HPP +#define MALIKANIA_CLIENT_COLOR_HPP + +/** + * \file color.hpp + * \brief Colors. + */ + +#include <cstdint> +#include <string_view> + +namespace mlk::client { + +/** + * \brief color description + */ +struct color { + std::uint8_t red{0}; + std::uint8_t green{0}; + std::uint8_t blue{0}; + std::uint8_t alpha{255}; + + /** + * Constructor with an hexadecimal value. + * + * \param hex the color + */ + static auto from_hex(std::uint32_t hex) noexcept -> color; + + /** + * Construct a color from #rrggbb or name. + * + * See the SVG this [list](http://www.december.com/html/spec/colorsvg.html) for supported names. + * + * \param name the color name + * \throw std::invalid_argument if the color does not exist or is invalid + */ + static auto from_name(std::string_view name) -> color; +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_COLOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/connection.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,159 @@ +/* + * connection.hpp -- connection to server + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "connection.hpp" + +namespace mlk { + +namespace client { + +/* + * connection::connection + * ------------------------------------------------------------------ + */ +connection::connection(boost::asio::io_service& service) + : service_(service) + , context_(boost::asio::ssl::context::sslv23) + , resolver_(service_) +{ +} + +/* + * connection::handshake + * ------------------------------------------------------------------ + */ +void connection::handshake(connect_t handler) +{ + socket_->async_handshake(boost::asio::ssl::stream_base::client, std::move(handler)); +} + +/* + * connection::flush + * ------------------------------------------------------------------ + */ +void connection::flush() +{ + if (output_.empty()) + return; + + auto buffer = boost::asio::buffer(std::get<1>(output_[0])); + + boost::asio::async_write(*socket_, buffer, [this] (auto code, auto xfer) { + auto handler = std::get<2>(output_[0]); + + output_.pop_front(); + + if (handler) + handler(std::move(code), std::get<0>(output_[0])); + + // TODO: precise error code. + if (!code && xfer != 0) + flush(); + }); +} + +/* + * connection::connect + * ------------------------------------------------------------------ + */ +void connection::connect(const std::string& host, std::uint16_t port, connect_t handler) +{ + socket_ = std::make_unique<socket_t>(service_, context_); + + using tcp = boost::asio::ip::tcp; + + auto str = std::to_string(port); + + resolver_.async_resolve(tcp::resolver::query(host, str), [this, handler] (auto code, auto ep) { + if (code) + handler(std::move(code)); + else { + boost::asio::async_connect(socket_->lowest_layer(), ep, [this, handler] (auto code, auto) { + if (code) + handler(std::move(code)); + else + handshake(std::move(handler)); + }); + } + }); +} + +/* + * connection::send + * ------------------------------------------------------------------ + */ +void connection::send(nlohmann::json message, send_t handler) +{ + assert(socket_); + assert(message.is_object()); + + auto in_progress = !output_.empty(); + auto str = message.dump() + "\r\n\r\n"; + + output_.push_back(std::make_tuple(std::move(message), std::move(str), std::move(handler))); + + if (!in_progress) + flush(); +} + +/* + * connection::recv + * ------------------------------------------------------------------ + */ +void connection::recv(recv_t handler) +{ + assert(socket_); + +#if !defined(NDEBUG) + assert(!is_reading); + + is_reading = true; +#endif + + boost::asio::async_read_until(*socket_, input_, "\r\n\r\n", [this, handler] (auto code, auto xfer) { +#if !defined(NDEBUG) + is_reading = false; +#endif + if (code) + handler(std::move(code), nullptr); + else if (xfer == 0) + handler(make_error_code(boost::system::errc::network_down), nullptr); + else { + std::string command{ + boost::asio::buffers_begin(input_.data()), + boost::asio::buffers_begin(input_.data()) + xfer - /* \r\n\r\n */ 4 + }; + + input_.consume(xfer); + + nlohmann::json msg; + + try { + msg = nlohmann::json::parse(command); + } catch (const std::exception&) { + // TODO: add custom error code. + } + + handler(std::move(code), std::move(msg)); + } + }); +} + +} // !client + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/connection.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,123 @@ +/* + * connection.hpp -- connection to server + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_CONNECTION_HPP +#define MALIKANIA_CLIENT_CONNECTION_HPP + +/** + * \file connection.hpp + * \brief Connection to server. + */ + +#include <deque> +#include <functional> +#include <utility> + +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +#include <json.hpp> + +namespace mlk { + +namespace client { + +class client; + +/** + * \brief connection to server. + */ +class connection { +public: + /** + * Connection handler. + */ + using connect_t = std::function<void (boost::system::error_code)>; + + /** + * Receive handler. + */ + using recv_t = std::function<void (boost::system::error_code, nlohmann::json)>; + + /** + * Send handler. + */ + using send_t = std::function<void (boost::system::error_code, nlohmann::json)>; + +private: + /** + * Wrap an handler, the JSON message and its dump string. + */ + using output_item_t = std::tuple<nlohmann::json, std::string, send_t>; + + using socket_t = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>; + + boost::asio::io_service& service_; + boost::asio::ssl::context context_; + boost::asio::ip::tcp::resolver resolver_; + std::unique_ptr<socket_t> socket_; + boost::asio::streambuf input_; + std::deque<output_item_t> output_; + +#if !defined(NDEBUG) + bool is_reading{false}; +#endif + + void handshake(connect_t); + void flush(); + +public: + /** + * Create a connection object. + */ + connection(boost::asio::io_service& service); + + /** + * Connect to the given end point. + * + * \pre handler != nullptr + * \param host the hostname + * \param port the port number + * \param handler the handler + */ + virtual void connect(const std::string& host, std::uint16_t port, connect_t handler); + + /** + * Send the given message to the server. + * + * \pre message.is_object() + * \param message the message object + * \param handler the handler (may be null) + */ + virtual void send(nlohmann::json message, send_t handler); + + /** + * Request for a recv operation. + * + * \pre no reading operation must be pending + * \pre handler != nullptr + * \param handler the handler + */ + virtual void recv(recv_t handler); +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_CONNECTION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/dispatcher.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,183 @@ +/* + * dispatcher.hpp -- client event dispatcher + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_DISPATCHER_HPP +#define MALIKANIA_CLIENT_DISPATCHER_HPP + +/** + * \file dispatcher.hpp + * \brief Client event dispatcher. + */ + +#include <system_error> + +#include <json.hpp> + +#include <malikania/point.hpp> + +#include "mouse.hpp" +#include "key.hpp" + +namespace mlk::client { + +/** + * \brief Describe key event. + */ +struct key_event { + key keycode{key::unknown}; //!< layout-dependant key + key scancode{key::unknown}; //!< physical key + mod modifiers{mod::none}; //!< optional modifiers +}; + +/** + * \brief Describe mouse click event. + */ +struct mouse_click_event { + mouse button{mouse::none}; //!< which mouse button + point pos; //!< current mouse position +}; + +/** + * \brief Describe a mouse motion event. + */ +struct mouse_motion_event { + point pos; //!< current mouse position +}; + +/** + * \brief Describe mouse wheel (up/down) event. + */ +struct mouse_wheel_event { + point pos; //!< current mouse position +}; + +/** + * \brief Describe text edition event. + */ +struct text_event { + std::u32string text; //!< text added from this event +}; + +/** + * \brief Client event dispatcher. + */ +class dispatcher { +public: + /** + * Default constructor. + */ + dispatcher() noexcept = default; + + /** + * Virtual destructor defaulted. + */ + virtual ~dispatcher() noexcept = default; + + /** + * Connection event. + * + * \param code the result code + */ + virtual void handle_connect(const std::error_code& code) + { + (void)code; + } + + /** + * Message event. + * + * \param code the result code + * \param msg the network message + */ + virtual void handle_message(const std::error_code& code, const nlohmann::json& msg) + { + (void)code; + (void)msg; + } + + /** + * Key down event. + * + * \param ev the event + */ + virtual void handle_key_down(const key_event& ev) + { + (void)ev; + } + + /** + * Key released event. + * + * \param ev the event + */ + virtual void handle_key_up(const key_event& ev) + { + (void)ev; + } + + /** + * Mouse click event. + * + * \param ev the event + */ + virtual void handle_mouse_down(const mouse_click_event& ev) + { + (void)ev; + } + + /** + * Mouse click release event. + * + * \param ev the event + */ + virtual void handle_mouse_up(const mouse_click_event& ev) + { + (void)ev; + } + + /** + * Mouse wheel event. + * + * \param ev the event + */ + virtual void handle_mouse_wheel(const mouse_wheel_event& ev) + { + (void)ev; + } + + /** + * Text editing event. + * + * \param ev the event + */ + virtual void handle_text(const text_event& ev) + { + (void)ev; + } + + /** + * Quit request. + */ + virtual void handle_quit() + { + } +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_DISPATCHER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/font.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,72 @@ +/* + * font.cpp -- font object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/size.hpp> + +#include "font.hpp" +#include "sdl_util.hpp" + +namespace mlk::client { + +font::font(std::string data, std::size_t size) + : size_(size) +{ + assert(size > 0); + + auto rw = SDLx_RWFromBinary(std::move(data)); + + if (rw == nullptr) + throw std::runtime_error(SDL_GetError()); + + font_ = { TTF_OpenFontRW(rw, true, size), TTF_CloseFont }; + + if (font_ == nullptr) + throw std::runtime_error(TTF_GetError()); +} + +auto font::get_handle() const -> TTF_Font* +{ + return font_.get(); +} + +auto font::get_handle() -> TTF_Font* +{ + return font_.get(); +} + +auto font::get_size() const noexcept -> std::size_t +{ + return size_; +} + +auto font::clip(const std::string& text) const -> size +{ + int width, height; + + if (TTF_SizeUTF8(font_.get(), text.c_str(), &width, &height) != 0) + throw std::runtime_error(SDL_GetError()); + + return { + static_cast<unsigned>(width), + static_cast<unsigned>(height) + }; +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/font.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,91 @@ +/* + * font.hpp -- font object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_FONT_HPP +#define MALIKANIA_CLIENT_FONT_HPP + +/** + * \file font.hpp + * \brief fonts. + */ + +#include <memory> +#include <string> + +#include <SDL.h> +#include <SDL_ttf.h> + +namespace mlk { + +struct size; + +namespace client { + +/** + * \brief font object. + */ +class font { +private: + std::unique_ptr<TTF_Font, void (*)(TTF_Font*)> font_{nullptr, nullptr}; + std::size_t size_; + +public: + /** + * Construct a font from binary data. + * + * \pre size > 0 + * \param data the raw data + * \param size the size + */ + font(std::string data, std::size_t size); + + /** + * Get the underlying SDL TTF_Font. + * + * \return the font + */ + auto get_handle() const -> TTF_Font*; + + /** + * Overloaded function. + * + * \return the font + */ + auto get_handle() -> TTF_Font*; + + /** + * Get the font size. + * + * \return the font size + */ + auto get_size() const noexcept -> std::size_t; + + /** + * Get the clipping size required to draw the given text. + * + * \param text the text to clip + * \return the required size + */ + auto clip(const std::string& text) const -> size; +}; + +} // !client + +} // !mlk + +#endif // MALIKANIA_CLIENT_FONT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/image.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,112 @@ +/* + * image.cpp -- image object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <SDL_image.h> + +#include "image.hpp" +#include "sdl_util.hpp" +#include "window.hpp" + +namespace mlk::client { + +void image::create_texture(window& w) +{ + texture_ = { + SDL_CreateTextureFromSurface(w.get_renderer(), surface_.get()), + SDL_DestroyTexture + }; + + if (texture_ == nullptr) + throw std::runtime_error(SDL_GetError()); +} + +image::image(std::string data) +{ + auto rw = SDLx_RWFromBinary(std::move(data)); + + if (rw == nullptr) + throw std::runtime_error(SDL_GetError()); + + surface_ = { IMG_Load_RW(rw, true), SDL_FreeSurface }; + + if (!surface_) + throw std::runtime_error(SDL_GetError()); + + size_ = { + static_cast<unsigned>(surface_->w), + static_cast<unsigned>(surface_->h) + }; +} + +auto image::get_size() const noexcept -> const mlk::size& +{ + return size_; +} + +void image::draw(window& window, const point& point) +{ + /* + * Create texture at this step so the image constructor does not need the + * window. + */ + if (!texture_) + create_texture(window); + + SDL_Rect target; + + target.x = static_cast<int>(point.x); + target.y = static_cast<int>(point.y); + target.w = static_cast<int>(size_.width); + target.h = static_cast<int>(size_.height); + + if (SDL_RenderCopy(window.get_renderer(), texture_.get(), nullptr, &target) < 0) + throw std::runtime_error(SDL_GetError()); +} + +void image::draw(window& window, const rectangle& source, const rectangle& target) +{ + if (!texture_) + create_texture(window); + + SDL_Rect sr, st; + + sr.x = source.x; + sr.y = source.y; + sr.w = static_cast<int>(source.width); + sr.h = static_cast<int>(source.height); + + st.x = target.x; + st.y = target.y; + st.w = static_cast<int>(target.width); + st.h = static_cast<int>(target.height); + + // Readjust .w, .h if null. + if (source.is_null()) { + sr.w = static_cast<int>(size_.width); + sr.h = static_cast<int>(size_.height); + } + if (target.is_null()) { + st.w = static_cast<int>(size_.width); + st.h = static_cast<int>(size_.height); + } + + if (SDL_RenderCopy(window.get_renderer(), texture_.get(), &sr, &st) < 0) + throw std::runtime_error(SDL_GetError()); +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/image.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,88 @@ +/* + * image.hpp -- image object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_IMAGE_HPP +#define MALIKANIA_CLIENT_IMAGE_HPP + +/** + * \file image.hpp + * \brief Images. + */ + +#include <memory> +#include <string> + +#include <SDL.h> + +#include <malikania/point.hpp> +#include <malikania/rectangle.hpp> +#include <malikania/size.hpp> + +namespace mlk::client { + +class window; + +/** + * \brief Image object. + */ +class image { +private: + std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> surface_{nullptr, nullptr}; + std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)> texture_{nullptr, nullptr}; + + size size_; + + void create_texture(window& window); + +public: + /** + * Construct an image from the binary data. + * + * \param window the window + * \param data the data + */ + image(std::string data); + + /** + * Get the image size. + * + * \return the size + */ + auto get_size() const noexcept -> const mlk::size&; + + /** + * Draw the image to the window. + * + * \param window the window + * \param position the position + */ + void draw(window& window, const point& position = {0, 0}); + + /** + * Overloaded function. + * + * \param window the window + * \param source the source to clip + * \param target the target destination + */ + void draw(window& window, const rectangle& source, const rectangle& target); +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_IMAGE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/key.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,256 @@ +/* + * key.hpp -- key definitions + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_KEY_HPP +#define MALIKANIA_CLIENT_KEY_HPP + +namespace mlk::client { + +/** + * \brief Describe keyboard modifiers + * + * This enumeration is a satisfied the Bitmask concept. + */ +enum class mod { + none = 0, //!< no modifiers + left_control = (1 << 1), //!< left control + left_alt = (1 << 2), //!< left alt + left_shift = (1 << 3), //!< left shift + left_super = (1 << 4), //!< left logo + right_control = (1 << 5), //!< right control + right_alt = (1 << 6), //!< right alt + right_shift = (1 << 7), //!< right shift + right_super = (1 << 8), //!< right logo + num_lock = (1 << 9), //!< num lock is on + caps_lock = (1 << 10), //!< caps lock is on + + /** + * Left or right control. + */ + control = left_control | right_control, + + /** + * Left or right shift. + */ + shift = left_shift | right_shift, + + /** + * Left or right alt. + */ + alt = left_alt | right_alt, + + /** + * Left or right super. + */ + super = left_super | right_super +}; + +/** + * \cond ENUM_HIDDEN_SYMBOLS + */ + +inline auto operator^(mod v1, mod v2) noexcept -> mod +{ + return static_cast<mod>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2)); +} + +inline auto operator&(mod v1, mod v2) noexcept -> mod +{ + return static_cast<mod>(static_cast<unsigned>(v1)& static_cast<unsigned>(v2)); +} + +inline auto operator|(mod v1, mod v2) noexcept -> mod +{ + return static_cast<mod>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2)); +} + +inline auto operator~(mod v) noexcept -> mod +{ + return static_cast<mod>(~static_cast<unsigned>(v)); +} + +inline auto operator|=(mod& v1, mod v2) noexcept -> mod& +{ + v1 = static_cast<mod>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2)); + + return v1; +} + +inline auto operator&=(mod& v1, mod v2) noexcept -> mod& +{ + v1 = static_cast<mod>(static_cast<unsigned>(v1)& static_cast<unsigned>(v2)); + + return v1; +} + +inline auto operator^=(mod& v1, mod v2) noexcept -> mod& +{ + v1 = static_cast<mod>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2)); + + return v1; +} + +/** + * \endcond + */ + +/** + * \brief Key description. + */ +enum class key { + unknown, + a, + b, + c, + d, + e, + f, + g, + h, + i, + j, + k, + l, + m, + n, + o, + p, + q, + r, + s, + t, + u, + v, + w, + x, + y, + z, + exclaim, + double_quote, + percent, + dollar, + ampersand, + left_parenthese, + right_parenthese, + asterisk, + plus, + colon, + less, + greater, + question, + at, + caret, + underscore, + back_quote, + quote, + one, + two, + three, + four, + five, + six, + seven, + eight, + nine, + zero, + enter, + escape, + backspace, + tab, + space, + minus, + equals, + left_bracket, + right_bracket, + backslash, + hash, + semicolon, + apostrophe, + grave, + comma, + period, + slash, + caps_lock, + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, + f24, + print_screen, + scroll_lock, + pause, + insert, + home, + page_up, + page_down, + del, + end, + right, + left, + down, + up, + kp_divide, + kp_multiply, + kp_minus, + kp_plus, + kp_enter, + kp_one, + kp_two, + kp_three, + kp_four, + kp_five, + kp_six, + kp_seven, + kp_eight, + kp_nine, + kp_zero, + mute, + volume_up, + volume_down, + left_control, + left_alt, + left_shift, + left_super, + right_control, + right_alt, + right_shift, + right_super +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_KEY_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/label.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,49 @@ +/* + * label.cpp -- GUI label element + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/size.hpp> + +#include "label.hpp" +#include "theme.hpp" +#include "window.hpp" + +namespace mlk::client { + +label::label(std::string text) noexcept + : text_(std::move(text)) +{ +} + +auto label::get_text() const noexcept -> const std::string& +{ + return text_; +} + +void label::set_text(std::string text) noexcept +{ + text_ = std::move(text); +} + +void label::draw(window& w, const size& size) +{ + // TODO: implement. + (void)w; + (void)size; +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/label.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,70 @@ +/* + * label.hpp -- GUI label element + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_LABEL_HPP +#define MALIKANIA_CLIENT_LABEL_HPP + +/** + * \file label.hpp + * \brief GUI label element. + */ + +#include <string> + +#include "widget.hpp" + +namespace mlk::client { + +/** + * \brief Basic label for displaying test. + */ +class label : public widget { +private: + std::string text_; + +public: + /** + * Create a label with an optional text. + * + * \param text the text + */ + label(std::string text = "") noexcept; + + /** + * Get the text. + * + * \return the label text + */ + auto get_text() const noexcept -> const std::string&; + + /** + * Set the label text. + * + * \param text the text + */ + void set_text(std::string text) noexcept; + + /** + * \copydoc widget::draw + */ + void draw(window& w, const size& size) override; +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_LABEL_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/loader.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,108 @@ +/* + * client_resources_loader.cpp -- load shared resources files for the client + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <json.hpp> + +#include <malikania/locator.hpp> +#include <malikania/size.hpp> +#include <malikania/util.hpp> + +#include "animation.hpp" +#include "font.hpp" +#include "image.hpp" +#include "loader.hpp" +#include "sprite.hpp" + +using namespace nlohmann; + +namespace mlk::client { + +namespace { + +auto load_animation_frames(const json& value) +{ + animation::frame_list frames; + + for (const auto& v : value) { + if (!v.is_object()) + throw std::runtime_error("not a JSON object"); + + const auto cell = v.find("cell"); + const auto delay = v.find("delay"); + + if (cell == v.end() || !cell->is_number_unsigned()) + throw std::runtime_error("invalid cell"); + if (delay == v.end() || !delay->is_number_unsigned()) + throw std::runtime_error("invalid delay"); + + // TODO: range check. + frames.push_back({cell->get<unsigned>(), delay->get<unsigned>()}); + } + + return frames; +} + +} // !namespace + +loader::loader(locator& locator) noexcept + : mlk::loader(locator) +{ +} + +auto loader::load_font(std::string_view id, unsigned size) -> font +{ + return font(get_locator().read(id), size); +} + +auto loader::load_image(std::string_view id) -> image +{ + return image(get_locator().read(id)); +} + +auto loader::load_sprite(std::string_view id) -> sprite +{ + auto value = json::parse(get_locator().read(id)); + + if (!value.is_object()) + throw std::runtime_error(": not a JSON object"); + + return sprite( + load_image(util::json::require_string(value, "/image"_json_pointer)), + util::json::require_size(value, "/cell"_json_pointer), + util::json::get_size(value, "/margin"_json_pointer), + util::json::get_size(value, "/space"_json_pointer), + util::json::get_size(value, "/size"_json_pointer) + ); +} + +auto loader::load_animation(std::string_view id) -> animation +{ + const auto value = json::parse(get_locator().read(id)); + + if (!value.is_object()) + throw std::runtime_error("not a JSON object"); + + const auto s = load_sprite(util::json::require_string(value, "/sprite"_json_pointer)); + + return { + load_sprite(util::json::require_string(value, "/sprite"_json_pointer)), + load_animation_frames(util::json::require_array(value, "/frames"_json_pointer)) + }; +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/loader.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,99 @@ +/* + * client_resources_loader.hpp -- load shared resources files for the client + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_LOADER_HPP +#define MALIKANIA_CLIENT_LOADER_HPP + +/* + * \file loader.hpp + * \brief Load client assets. + */ + +#include <malikania/loader.hpp> + +#include <string> + +namespace mlk { + +struct size; + +namespace client { + +struct animation; + +class font; +class image; +class sprite; + +/** + * \brief Load client resources. + */ +class loader : public mlk::loader { +public: + /** + * Client resources loader constructor. + * + * The window is required because some of the resources require it. + * + * \param locator the resources locator + */ + loader(locator& locator) noexcept; + + /** + * Load a font. + * + * \param id the resource id + * \param size the desired size + * \return the font + * \throw std::runtime_error on errors + */ + virtual auto load_font(std::string_view id, unsigned size) -> font; + + /** + * Load an image. + * + * \param id the resource id + * \return the image + * \throw std::runtime_error on errors + */ + virtual auto load_image(std::string_view id) -> image; + + /** + * Load a sprite. + * + * \param id the resource id + * \return the sprite + * \throw std::runtime_error on errors + */ + virtual auto load_sprite(std::string_view id) -> sprite; + + /** + * Load an animation. + * + * \param id the resource id + * \return the animation + * \throw std::runtime_error on errors + */ + virtual auto load_animation(std::string_view id) -> animation; +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_LOADER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/mouse.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,41 @@ +/* + * mouse.hpp -- mouse definitions + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_MOUSE_HPP +#define MALIKANIA_CLIENT_MOUSE_HPP + +/** + * \file mouse.hpp + * \brief Mouse definitions. + */ + +namespace mlk::client { + +/** + * \brief Describe mouse button + */ +enum class mouse { + none, //!< no buttons are pressed + left, //!< left click is pressed + right, //!< right click is pressed + middle //!< middle click is pressed +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_MOUSE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/sdl_util.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,142 @@ +/* + * sdl_util.cpp -- common SDL2 related code + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <new> + +#include "sdl_util.hpp" + +namespace mlk::client { + +namespace { + +/* + * RWFromBinary implementation + * ------------------------------------------------------------------ + * + * A little bit inspired by official SDL_RWFromMem implementation, largely + * modified to match our conventions and the C++ code. + */ + +struct buffer { + std::string data; + std::uint64_t position; + std::uint64_t length; + + buffer(std::string input) noexcept + : data(std::move(input)) + , position(0ULL) + , length(data.length()) + { + } +}; + +auto size(SDL_RWops* ops) noexcept -> Sint64 +{ + return reinterpret_cast<buffer*>(ops->hidden.unknown.data1)->length; +} + +auto seek(SDL_RWops* ops, Sint64 offset, int whence) noexcept -> Sint64 +{ + auto data = reinterpret_cast<buffer*>(ops->hidden.unknown.data1); + auto position = data->position; + + switch (whence) { + case RW_SEEK_SET: + position = offset; + break; + case RW_SEEK_CUR: + position = data->position + offset; + break; + case RW_SEEK_END: + position = data->length + offset; + break; + default: + break; + } + + if (static_cast<std::uint64_t>(position) > data->length) + position = data->length; + + return (data->position = position); +} + +auto read(SDL_RWops* ops, void* dst, std::size_t size, std::size_t number) noexcept -> std::size_t +{ + auto data = reinterpret_cast<buffer*>(ops->hidden.unknown.data1); + auto total = number * size; + auto avail = data->length - data->position; + + if (number <= 0U || size <= 0U || ((total / number) != static_cast<std::size_t>(size))) + return 0; + if (total > avail) + total = avail; + + SDL_memcpy(dst, &data->data[data->position], total); + data->position += total; + + return total / size; +} + +auto write(SDL_RWops*, const void*, std::size_t, std::size_t) noexcept -> std::size_t +{ + SDL_SetError("write not supported"); + return -1; +} + +auto close(SDL_RWops* ops) noexcept -> int +{ + if (ops != nullptr) { + delete reinterpret_cast<buffer*>(ops->hidden.unknown.data1); + SDL_FreeRW(ops); + } + + return 0; +} + +} // !namespace + +auto SDLx_RWFromBinary(std::string data) noexcept -> SDL_RWops* +{ + SDL_RWops* ops = SDL_AllocRW(); + + if (ops == nullptr) + return nullptr; + + ops->hidden.unknown.data1 = new (std::nothrow) buffer(std::move(data)); + + if (ops->hidden.unknown.data1 == nullptr) { + SDL_SetError("%s", std::strerror(errno)); + SDL_FreeRW(ops); + + return nullptr; + } + + ops->type = SDL_RWOPS_UNKNOWN; + ops->seek = seek; + ops->size = size; + ops->read = read; + ops->write = write; + ops->close = close; + + return ops; +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/sdl_util.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,51 @@ +/* + * sdl_util.hpp -- common SDL2 related code + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SDL_UTIL_HPP +#define MALIKANIA_SDL_UTIL_HPP + +/** + * \file sdl_util.hpp + * \brief Utilities for SDL backend. + */ + +#include <SDL.h> + +#include <string> + +namespace mlk::client { + +/** + * Create a SDL_RWops that owns the binary data. + * + * This is a safe alternative to SDL_RWFromMem because it owns the memory + * pointed by data until it is closed. The data is moved so there are no copies. + * + * The stream has read-only support and can not write. + * + * Seeking past-the-end or past-the-begin readjust the position to the end or + * begin respectively. + * + * \param data the data + * \return the object or nullptr on errors + */ +auto SDLx_RWFromBinary(std::string data) noexcept -> SDL_RWops*; + +} // !mlk::client + +#endif // !MALIKANIA_SDL_UTIL_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/sprite.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,106 @@ +/* + * sprite.cpp -- image sprite + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include "sprite.hpp" + +namespace mlk::client { + +sprite::sprite(image image, + size cell, + size margin, + size space, + size dimension) noexcept + : image_(std::move(image)) + , cell_(std::move(cell)) + , margin_(std::move(margin)) + , space_(std::move(space)) + , size_(std::move(dimension)) +{ + assert(cell_.width > 0); + assert(cell_.height > 0); + + // If size is not specified, take from image. + if (size_.is_null()) + size_ = image_.get_size(); + + // Compute number of cells. + rows_ = (size_.height - (margin_.height * 2) + space_.height) / (cell_.height + space_.height); + columns_ = (size_.width - (margin_.width * 2) + space_.width) / (cell_.width + space_.width); +} + +auto sprite::get_image() const noexcept -> const image& +{ + return image_; +} + +auto sprite::get_image() noexcept -> image& +{ + return image_; +} + +auto sprite::get_cell() const noexcept -> const size& +{ + return cell_; +} + +auto sprite::get_margin() const noexcept -> const size& +{ + return margin_; +} + +auto sprite::get_space() const noexcept -> const size& +{ + return space_; +} + +auto sprite::get_rows() const noexcept -> unsigned +{ + return rows_; +} + +auto sprite::get_columns() const noexcept -> unsigned +{ + return columns_; +} + +auto sprite::get_total() const noexcept -> unsigned +{ + return columns_ * rows_; +} + +void sprite::draw(window& window, unsigned cell, const point& point) +{ + assert(cell < rows_ * columns_); + + // Compute index in the grid. + unsigned hindex = (cell % columns_); + unsigned vindex = (cell / columns_); + + // Compute the pixel boundaries. + int x = margin_.width + (hindex * space_.width) + (hindex * cell_.width); + int y = margin_.height + (vindex * space_.height) + (vindex * cell_.height); + + rectangle source{x, y, cell_.width, cell_.height}; + rectangle target{point.x, point.y, cell_.width, cell_.height}; + + image_.draw(window, source, target); +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/sprite.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,136 @@ +/* + * sprite.hpp -- image sprite + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_SPRITE_HPP +#define MALIKANIA_CLIENT_SPRITE_HPP + +/** + * \file sprite.hpp + * \brief Sprite description. + */ + +#include "image.hpp" + +namespace mlk { + +struct point; + +namespace client { + +/** + * \brief A Sprite is an image divided into cells. + */ +class sprite { +private: + image image_; + size cell_; + size margin_; + size space_; + size size_; + unsigned rows_; + unsigned columns_; + +public: + /** + * Construct a sprite. + * + * \pre cell must not have height or width null + * \param image the image to use + * \param cell size of cell in the image + * \param margin the optional space from borders + * \param space the optional space between cells + * \param dimension the sprite size (if 0, taken from the image) + */ + sprite(image image, + size cell, + size margin = { 0, 0 }, + size space = { 0, 0 }, + size dimension = { 0, 0 }) noexcept; + + /** + * Get the underlying image. + * + * \return the image + */ + auto get_image() const noexcept -> const image&; + + /** + * Overloaded function. + * + * \return the image + */ + auto get_image() noexcept -> image&; + + /** + * Get the cell size. + * + * \return the cell size + */ + auto get_cell() const noexcept -> const size&; + + /** + * Get the margin size. + * + * \return the margin size + */ + auto get_margin() const noexcept -> const size&; + + /** + * Get the space size. + * + * \return the space size + */ + auto get_space() const noexcept -> const size&; + + /** + * Get the number of rows in the grid. + * + * \return the number of rows + */ + auto get_rows() const noexcept -> unsigned; + + /** + * Get the number of columns in the grid. + * + * \return the number of columns + */ + auto get_columns() const noexcept -> unsigned; + + /** + * Get the max number of image in the sprite. + * + * \return the total + */ + auto get_total() const noexcept -> unsigned; + + /** + * Draw the sprite into the window at the specified position. + * + * \pre cell < rows() * columns() + * \param window the window + * \param cell the cell index + * \param position the position in the window + */ + void draw(window& window, unsigned cell, const point& position); +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_SPRITE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/state.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,71 @@ +/* + * state.hpp -- game client state + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_STATE_HPP +#define MALIKANIA_CLIENT_STATE_HPP + +/** + * \file state.hpp + * \brief Game client state. + */ + +#include "dispatcher.hpp" + +namespace mlk::client { + +class client; + +/** + * \brief Game client state. + */ +class state : public dispatcher { +public: + /** + * Default constructor. + */ + state() noexcept = default; + + /** + * Virtual destructor defaulted. + */ + virtual ~state() noexcept = default; + + /** + * Update the state. + * + * \param clt the client + */ + virtual void update(client& clt) + { + (void)clt; + } + + /** + * Draw the state. + * + * \param clt the client + */ + virtual void draw(client& clt) + { + (void)clt; + } +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_STATE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/state/lobby_state.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,76 @@ +/* + * lobby_state.cpp -- character management state + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/client/client.hpp> +#include <malikania/client/color.hpp> +#include <malikania/client/theme.hpp> +#include <malikania/client/window.hpp> + +#include "lobby_state.hpp" +#include "map_state.hpp" + +namespace mlk { + +namespace client { + +lobby_state::lobby_state(client& client) + : client_(client) + , names_{"erekin", "luna"} +{ +} + +void lobby_state::handle_key_down(const key_event& ev) +{ + if (ev.keycode == key::down) + index_ = index_ == names_.size() - 1 ? 0 : index_ + 1; + else if (ev.keycode == key::up) + index_ = index_ == 0 ? names_.size() - 1 : index_ - 1; + else + client_.set_state(std::make_unique<map_state>()); +} + +void lobby_state::update(client&) +{ +} + +void lobby_state::draw(client& clt) +{ + // TODO: lobby_window. + auto& win = clt.window(); + + win.set_drawing_color(color::from_hex(0xffffffff)); + win.clear(); + win.set_drawing_color(color::from_hex(0xff000000)); + win.draw_text("Select your player", theme::get_default().get_font(), {20, 10}); + + std::size_t i = 0U; + for (const auto& n : names_) { + int y = 30 + (10 * i); + + if (i++ == index_) + win.draw_text("»", theme::get_default().get_font(), {10, y}); + + win.draw_text(n, theme::get_default().get_font(), {20, y}); + } + + win.present(); +} + +} // !client + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/state/lobby_state.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,55 @@ +/* + * lobby_state.hpp -- character management state + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_LOBBY_STATE_HPP +#define MALIKANIA_CLIENT_LOBBY_STATE_HPP + +/** + * \file lobby_state.hpp + * \brief Character management state. + */ + +#include <string> +#include <vector> + +#include <malikania/client/state.hpp> + +namespace mlk::client { + +/** + * \brief Character management state. + */ +class lobby_state : public state { +private: + client& client_; + std::vector<std::string> names_; + std::size_t index_{0}; + +public: + lobby_state(client& client); + + void handle_key_down(const key_event& ev) override; + + void update(client&) override; + + void draw(client& clt) override; +}; + +} // !mlk::client + +#endif // !MALIKANIA_CLIENT_LOBBY_STATE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/state/login_state.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,133 @@ +/* + * login_state.cpp -- login state + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/unicode.hpp> + +#include <malikania/client/color.hpp> +#include <malikania/client/client.hpp> +#include <malikania/client/theme.hpp> +#include <malikania/client/window.hpp> + +#include "login_state.hpp" +#include "lobby_state.hpp" + +namespace mlk { + +namespace client { + +void login_state::do_connect() +{ + state_ = state_t::connecting; + status_ = "Connecting..."; + client_.connect("localhost", 3320); +} + +void login_state::do_auth() +{ + status_ = "Authenticating"; + state_ = state_t::authenticating; + client_.send({ + { "command", "auth" }, + { "login", unicode::to_utf8(login_) }, + { "password", unicode::to_utf8(password_) } + }); +} + +login_state::login_state(client& clt) + : client_(clt) +{ + client_.window().start_edit(); +} + +void login_state::handle_text(const text_event& ev) +{ + if (index_ == 0) + login_ += ev.text; + else + password_ += ev.text; +} + +void login_state::update(client&) +{ +} + +void login_state::handle_connect(const std::error_code& code) +{ + if (code) + status_ = code.message(); + else + do_auth(); +} + +void login_state::handle_message(const std::error_code& code, const nlohmann::json& msg) +{ + if (code) + status_ = code.message(); + else + status_ = msg["error"].get<std::string>(); +} + +void login_state::handle_key_down(const key_event& ev) +{ + switch (ev.keycode) { + case key::tab: + index_ ++; + + if (index_ == 2) + index_ = 0; + break; + case key::backspace: + if (index_ == 0) + login_.pop_back(); + else + password_.pop_back(); + break; + case key::enter: + if (index_ == 1 && state_ == state_t::disconnected) + do_connect(); + break; + default: + break; + } +} + +void login_state::draw(client& clt) +{ + auto& win = clt.window(); + const auto& font = theme::get_default().get_font(); + + win.set_drawing_color(color::from_hex(0xffffffff)); + win.clear(); + win.set_drawing_color(color::from_hex(0xff000000)); + win.draw_text("Please log in", font, {10, 10}); + win.draw_text("login: ", font, {10, 50}); + win.draw_text("password: ", font, {10, 70}); + + if (!login_.empty()) + win.draw_text(unicode::to_utf8(login_), font, {70, 50}); + if (!password_.empty()) + win.draw_text(std::string(password_.length(), '*'), font, {70, 70}); + if (!status_.empty()) + win.draw_text(status_, font, {70, 90}); + + win.present(); +} + +} // !client + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/state/login_state.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,69 @@ +/* + * login_state.cpp -- login state + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_LOGIN_STATE_HPP +#define MALIKANIA_CLIENT_LOGIN_STATE_HPP + +/** + * \file login_state.hpp + * \brief Login state. + */ + +#include <malikania/client/state.hpp> + +namespace mlk { + +namespace client { + +/** + * \brief Login state. + */ +class login_state : public state { +private: + enum class state_t { + disconnected, + connecting, + authenticating + }; + + client& client_; + state_t state_{state_t::disconnected}; + std::size_t index_{0}; + std::u32string login_; + std::u32string password_; + std::string status_; + + void do_connect(); + void do_auth(); + +public: + login_state(client& clt); + + void update(client&) override; + void draw(client& clt) override; + void handle_connect(const std::error_code& code) override; + void handle_message(const std::error_code& code, const nlohmann::json& msg) override; + void handle_key_down(const key_event& ev) override; + void handle_text(const text_event& ev) override; +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_LOGIN_STATE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/state/map_state.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,66 @@ +#include <malikania/point.hpp> +#include <malikania/rectangle.hpp> + +#include <malikania/client/client.hpp> +#include <malikania/client/color.hpp> +#include <malikania/client/theme.hpp> +#include <malikania/client/window.hpp> + +#include "map_state.hpp" + +namespace mlk { + +namespace client { + +void map_state::handle_key_down(const key_event& ev) +{ + if (ev.keycode == key::down) + delta_ = {delta_.x, 1}; + else if (ev.keycode == key::up) + delta_ = {delta_.x, -1}; + else if (ev.keycode == key::left) + delta_ = {-1, delta_.y}; + else if (ev.keycode == key::right) + delta_ = {1, delta_.y}; +} + +void map_state::handle_key_up(const key_event& ev) +{ + if (ev.keycode == key::down || ev.keycode == key::up) + delta_ = {delta_.x, 0}; + else if (ev.keycode == key::left || ev.keycode == key::right) + delta_ = {0, delta_.y}; +} + +void map_state::update(client&) +{ + position_ = { + position_.x + delta_.x, + position_.y + delta_.y + }; +} + +void map_state::draw(client& clt) +{ + auto& win = clt.window(); + + win.set_drawing_color(color::from_hex(0xffffffff)); + win.clear(); + win.set_drawing_color(color::from_hex(0xff000000)); + + // Draw a little square as user position. + win.fill_rectangle({ position_.x, position_.y, 10, 10 }); + + // Draw nickname on top of it. + auto clip = theme::get_default().get_font().clip("molko"); + + win.draw_text("molko", theme::get_default().get_font(), point{ + static_cast<int>(position_.x - (clip.width / 2)), + static_cast<int>(position_.y - clip.height - 10) + }); + win.present(); +} + +} // !client + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/state/map_state.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,54 @@ +/* + * map_state.hpp -- main game state + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_MAP_STATE_HPP +#define MALIKANIA_CLIENT_MAP_STATE_HPP + +/** + * \file map_state.hpp + * \brief Main game state. + */ + +#include <malikania/point.hpp> + +#include <malikania/client/state.hpp> + +namespace mlk { + +namespace client { + +/** + * \brief Main game state. + */ +class map_state : public state { +private: + point position_{320, 240}; + point delta_; + +public: + void update(client&) override; + void draw(client& clt) override; + void handle_key_down(const key_event& ev) override; + void handle_key_up(const key_event& ev) override; +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_MAP_STATE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/theme.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,106 @@ +/* + * theme.cpp -- theming support for gui elements + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/point.hpp> +#include <malikania/rectangle.hpp> + +#include "button.hpp" +#include "color.hpp" +#include "label.hpp" +#include "theme.hpp" +#include "window.hpp" + +namespace mlk::client { + +namespace { + +#include <dejavu_sans.hpp> + +} // !namespace + +std::unique_ptr<theme> theme::global; + +auto theme::get_default() noexcept -> theme& +{ + if (!global) + global = std::make_unique<theme>(); + + return *global; +} + +void theme::set_default(std::unique_ptr<theme> theme) noexcept +{ + global = std::move(theme); +} + +theme::theme() + : font_(std::string(dejavu_sans, sizeof (dejavu_sans)), 10) + , background_color_{228, 228, 228, 255} + , border_color_{102, 102, 102, 255} + , text_color_{50, 50, 50, 255} +{ +} + +auto theme::get_font() const noexcept -> const font& +{ + return font_; +} + +auto theme::get_font() noexcept -> font& +{ + return font_; +} + +auto theme::get_background_color() const noexcept -> const color& +{ + return background_color_; +} + +auto theme::get_border_color() const noexcept -> const color& +{ + return border_color_; +} + +auto theme::get_text_color() const noexcept -> const color& +{ + return text_color_; +} + +void theme::draw_button(window& w, const button& b, const rectangle& rect) +{ + // Border. + w.set_drawing_color(border_color_); + w.draw_rectangle({ rect.x, rect.y, rect.width, rect.height }); + + // Box content. + w.set_drawing_color(background_color_); + w.fill_rectangle({ rect.x + 2, rect.y + 2, rect.width - 2, rect.height - 2 }); + + // Text. + // TODO: alignment. + w.set_drawing_color(text_color_); + w.draw_text(b.get_text(), font_, point{rect.x + 5, rect.y + 5}); +} + +void theme::draw_label(window& w, const label& label, const rectangle& rect) +{ + w.set_drawing_color(text_color_); + w.draw_text(label.get_text(), font_, point{rect.x, rect.y}); +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/theme.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,128 @@ +/* + * theme.hpp -- theming support for gui elements + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_THEME_HPP +#define MALIKANIA_CLIENT_THEME_HPP + +/** + * \file theme.hpp + * \brief Theming support for gui elements. + */ + +#include <memory> + +#include <malikania/size.hpp> + +#include "color.hpp" +#include "font.hpp" + +namespace mlk { + +struct rectangle; + +namespace client { + +class button; +class label; +class window; + +/** + * \brief Reimplement this class to provide your own theme. + */ +class theme { +private: + static std::unique_ptr<theme> global; + + font font_; + color background_color_; + color border_color_; + color text_color_; + +public: + static auto get_default() noexcept -> theme&; + + static void set_default(std::unique_ptr<theme> theme) noexcept; + + /** + * Default constructor. + */ + theme(); + + /** + * Virtual destructor defaulted. + */ + virtual ~theme() noexcept = default; + + /** + * Get the font. + * + * \return the font + */ + virtual auto get_font() const noexcept -> const font&; + + /** + * Overloaded function. + * + * \return the font + */ + virtual auto get_font() noexcept -> font&; + + /** + * Get the background color for basic widgets. + * + * \return the color + */ + virtual auto get_background_color() const noexcept -> const color&; + + /** + * Get the border color for basic widgets. + * + * \return the color + */ + virtual auto get_border_color() const noexcept -> const color&; + + /** + * Get the text color for basic widgets. + * + * \return the color + */ + virtual auto get_text_color() const noexcept -> const color&; + + /** + * Draw a button. + * + * \param w the main window + * \param b the button + */ + virtual void draw_button(window& w, const button& b, const rectangle& rect); + + /** + * Draw a label. + * + * \param w the main window + * \param l the label + * \param rect the bounding rectangle. + */ + virtual void draw_label(window& w, const label& l, const rectangle& rect); +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_THEME_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/widget.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,54 @@ +/* + * widget.cpp -- basic abstract widget for GUI + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "theme.hpp" +#include "widget.hpp" + +namespace mlk::client { + +widget::widget() noexcept + : theme_(std::addressof(theme::get_default())) +{ +} + +auto widget::get_position() const noexcept -> const point& +{ + return position_; +} + +void widget::set_position(point position) noexcept +{ + position_ = std::move(position); +} + +auto widget::get_theme() const noexcept -> const theme& +{ + return *theme_; +} + +auto widget::get_theme() noexcept -> theme& +{ + return *theme_; +} + +void widget::set_theme(theme& theme) noexcept +{ + theme_ = std::addressof(theme); +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/widget.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,110 @@ +/* + * widget.hpp -- basic abstract widget for GUI + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_WIDGET_HPP +#define MALIKANIA_CLIENT_WIDGET_HPP + +/** + * \file widget.hpp + * \brief Basic abstract widget for GUI + */ + +#include <malikania/point.hpp> + +#include "dispatcher.hpp" + +namespace mlk { + +struct rectangle; +struct size; + +namespace client { + +class window; +class theme; + +/** + * \brief Abstract widget + */ +class widget : public dispatcher { +protected: + theme* theme_; //!< widget theme + point position_; //!< widget position + +public: + /** + * Constructor. + * + * Initialize the theme with the global one. + */ + widget() noexcept; + + /** + * Default destructor. + */ + virtual ~widget() noexcept = default; + + /** + * Get the widget position. + * + * \return the position + */ + auto get_position() const noexcept -> const point&; + + /** + * Set the widget position. + * + * \param position the new position + */ + void set_position(point position) noexcept; + + /** + * Get the theme. + * + * \return the theme + */ + auto get_theme() const noexcept -> const theme&; + + /** + * Overloaded function. + * + * \return the theme + */ + auto get_theme() noexcept -> theme&; + + /** + * Change the widget theme. + * + * \param theme the new theme + */ + void set_theme(theme& theme) noexcept; + + /** + * Draw the widget at the specified position. + * + * \param w the window + * \param size the maximum size allowed + */ + virtual void draw(window& w, const size& size) = 0; +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_WIDGET_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/window.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,588 @@ +/* + * window.cpp -- main window and basic drawing + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <iostream> +#include <stdexcept> + +#include <malikania/line.hpp> +#include <malikania/rectangle.hpp> +#include <malikania/unicode.hpp> + +#include "color.hpp" +#include "theme.hpp" +#include "widget.hpp" +#include "window.hpp" + +namespace mlk::client { + +namespace { + +/* + * conversion maps + * ------------------------------------------------------------------ + * + * There is a difference between scancode and key codes. The scancode is the + * key located on the keyboard which is always the same, the key code is the + * translated to the user layout. + * + * For example, on azerty, hitting the 'a' key makes a key code of 'a' but a + * scancode of 'q'. + * + * - scancodes_map : convert SDL scancode do key + * - keycodes_map : convert SDL key code to key + * - modifiers_map : convert masks + * - button_map : convert SDL mouse buttons + */ + +const std::unordered_map<SDL_Keycode, key> scancodes_map{ + { SDL_SCANCODE_A, key::a }, + { SDL_SCANCODE_B, key::b }, + { SDL_SCANCODE_C, key::c }, + { SDL_SCANCODE_D, key::d }, + { SDL_SCANCODE_E, key::e }, + { SDL_SCANCODE_F, key::f }, + { SDL_SCANCODE_G, key::g }, + { SDL_SCANCODE_H, key::h }, + { SDL_SCANCODE_I, key::i }, + { SDL_SCANCODE_J, key::j }, + { SDL_SCANCODE_K, key::k }, + { SDL_SCANCODE_L, key::l }, + { SDL_SCANCODE_M, key::m }, + { SDL_SCANCODE_N, key::n }, + { SDL_SCANCODE_O, key::o }, + { SDL_SCANCODE_P, key::p }, + { SDL_SCANCODE_Q, key::q }, + { SDL_SCANCODE_R, key::r }, + { SDL_SCANCODE_S, key::s }, + { SDL_SCANCODE_T, key::t }, + { SDL_SCANCODE_U, key::u }, + { SDL_SCANCODE_V, key::v }, + { SDL_SCANCODE_W, key::w }, + { SDL_SCANCODE_X, key::x }, + { SDL_SCANCODE_Y, key::y }, + { SDL_SCANCODE_Z, key::z }, + { SDL_SCANCODE_1, key::one }, + { SDL_SCANCODE_2, key::two }, + { SDL_SCANCODE_3, key::three }, + { SDL_SCANCODE_4, key::four }, + { SDL_SCANCODE_5, key::five }, + { SDL_SCANCODE_6, key::six }, + { SDL_SCANCODE_7, key::seven }, + { SDL_SCANCODE_8, key::eight }, + { SDL_SCANCODE_9, key::nine }, + { SDL_SCANCODE_0, key::zero }, + { SDL_SCANCODE_RETURN, key::enter }, + { SDL_SCANCODE_ESCAPE, key::escape }, + { SDL_SCANCODE_BACKSPACE, key::backspace }, + { SDL_SCANCODE_TAB, key::tab }, + { SDL_SCANCODE_SPACE, key::space }, + { SDL_SCANCODE_MINUS, key::minus }, + { SDL_SCANCODE_EQUALS, key::equals }, + { SDL_SCANCODE_LEFTBRACKET, key::left_bracket }, + { SDL_SCANCODE_RIGHTBRACKET, key::right_bracket }, + { SDL_SCANCODE_BACKSLASH, key::backslash }, + { SDL_SCANCODE_NONUSHASH, key::hash }, + { SDL_SCANCODE_SEMICOLON, key::semicolon }, + { SDL_SCANCODE_APOSTROPHE, key::apostrophe }, + { SDL_SCANCODE_GRAVE, key::grave }, + { SDL_SCANCODE_COMMA, key::comma }, + { SDL_SCANCODE_PERIOD, key::period }, + { SDL_SCANCODE_SLASH, key::slash }, + { SDL_SCANCODE_CAPSLOCK, key::caps_lock }, + { SDL_SCANCODE_F1, key::f1 }, + { SDL_SCANCODE_F2, key::f2 }, + { SDL_SCANCODE_F3, key::f3 }, + { SDL_SCANCODE_F4, key::f4 }, + { SDL_SCANCODE_F5, key::f5 }, + { SDL_SCANCODE_F6, key::f6 }, + { SDL_SCANCODE_F7, key::f7 }, + { SDL_SCANCODE_F8, key::f8 }, + { SDL_SCANCODE_F9, key::f9 }, + { SDL_SCANCODE_F10, key::f10 }, + { SDL_SCANCODE_F11, key::f11 }, + { SDL_SCANCODE_F12, key::f12 }, + { SDL_SCANCODE_F13, key::f13 }, + { SDL_SCANCODE_F14, key::f14 }, + { SDL_SCANCODE_F15, key::f15 }, + { SDL_SCANCODE_F16, key::f16 }, + { SDL_SCANCODE_F17, key::f17 }, + { SDL_SCANCODE_F18, key::f18 }, + { SDL_SCANCODE_F19, key::f19 }, + { SDL_SCANCODE_F20, key::f20 }, + { SDL_SCANCODE_F21, key::f21 }, + { SDL_SCANCODE_F22, key::f22 }, + { SDL_SCANCODE_F23, key::f23 }, + { SDL_SCANCODE_F24, key::f24 }, + { SDL_SCANCODE_PRINTSCREEN, key::print_screen }, + { SDL_SCANCODE_SCROLLLOCK, key::scroll_lock }, + { SDL_SCANCODE_PAUSE, key::pause }, + { SDL_SCANCODE_INSERT, key::insert }, + { SDL_SCANCODE_HOME, key::home }, + { SDL_SCANCODE_PAGEUP, key::page_up }, + { SDL_SCANCODE_PAGEDOWN, key::page_down }, + { SDL_SCANCODE_DELETE, key::del }, + { SDL_SCANCODE_END, key::end }, + { SDL_SCANCODE_RIGHT, key::right }, + { SDL_SCANCODE_LEFT, key::left }, + { SDL_SCANCODE_DOWN, key::down }, + { SDL_SCANCODE_UP, key::up }, + { SDL_SCANCODE_KP_DIVIDE, key::kp_divide }, + { SDL_SCANCODE_KP_MULTIPLY, key::kp_multiply }, + { SDL_SCANCODE_KP_MINUS, key::kp_minus }, + { SDL_SCANCODE_KP_PLUS, key::kp_plus }, + { SDL_SCANCODE_KP_ENTER, key::kp_enter }, + { SDL_SCANCODE_KP_1, key::kp_one }, + { SDL_SCANCODE_KP_2, key::kp_two }, + { SDL_SCANCODE_KP_3, key::kp_three }, + { SDL_SCANCODE_KP_4, key::kp_four }, + { SDL_SCANCODE_KP_5, key::kp_five }, + { SDL_SCANCODE_KP_6, key::kp_six }, + { SDL_SCANCODE_KP_7, key::kp_seven }, + { SDL_SCANCODE_KP_8, key::kp_eight }, + { SDL_SCANCODE_KP_9, key::kp_nine }, + { SDL_SCANCODE_KP_0, key::kp_zero }, + { SDL_SCANCODE_MUTE, key::mute }, + { SDL_SCANCODE_VOLUMEUP, key::volume_up }, + { SDL_SCANCODE_VOLUMEDOWN, key::volume_down }, + { SDL_SCANCODE_LCTRL, key::left_control }, + { SDL_SCANCODE_LALT, key::left_alt }, + { SDL_SCANCODE_LSHIFT, key::left_shift }, + { SDL_SCANCODE_LGUI, key::left_super }, + { SDL_SCANCODE_RCTRL, key::right_control }, + { SDL_SCANCODE_RALT, key::right_alt }, + { SDL_SCANCODE_RSHIFT, key::right_shift }, + { SDL_SCANCODE_RGUI, key::right_super } +}; + +const std::unordered_map<SDL_Keycode, key> keycodes_map{ + { SDLK_RETURN, key::enter }, + { SDLK_ESCAPE, key::escape }, + { SDLK_BACKSPACE, key::backspace }, + { SDLK_TAB, key::tab }, + { SDLK_SPACE, key::space }, + { SDLK_EXCLAIM, key::exclaim }, + { SDLK_QUOTEDBL, key::double_quote }, + { SDLK_HASH, key::hash }, + { SDLK_PERCENT, key::percent }, + { SDLK_DOLLAR, key::dollar }, + { SDLK_AMPERSAND, key::ampersand }, + { SDLK_QUOTE, key::quote }, + { SDLK_LEFTPAREN, key::left_parenthese }, + { SDLK_RIGHTPAREN, key::right_parenthese }, + { SDLK_ASTERISK, key::asterisk }, + { SDLK_PLUS, key::plus }, + { SDLK_COMMA, key::comma }, + { SDLK_MINUS, key::minus }, + { SDLK_PERIOD, key::period }, + { SDLK_SLASH, key::slash }, + { SDLK_0, key::zero }, + { SDLK_1, key::one }, + { SDLK_2, key::two }, + { SDLK_3, key::three }, + { SDLK_4, key::four }, + { SDLK_5, key::five }, + { SDLK_6, key::six }, + { SDLK_7, key::seven }, + { SDLK_8, key::eight }, + { SDLK_9, key::nine }, + { SDLK_COLON, key::colon }, + { SDLK_SEMICOLON, key::semicolon }, + { SDLK_LESS, key::less }, + { SDLK_EQUALS, key::equals }, + { SDLK_GREATER, key::greater }, + { SDLK_QUESTION, key::question }, + { SDLK_AT, key::at }, + { SDLK_LEFTBRACKET, key::left_bracket }, + { SDLK_BACKSLASH, key::backslash }, + { SDLK_RIGHTBRACKET, key::right_bracket }, + { SDLK_CARET, key::caret }, + { SDLK_UNDERSCORE, key::underscore }, + { SDLK_BACKQUOTE, key::back_quote }, + { SDLK_a, key::a }, + { SDLK_b, key::b }, + { SDLK_c, key::c }, + { SDLK_d, key::d }, + { SDLK_e, key::e }, + { SDLK_f, key::f }, + { SDLK_g, key::g }, + { SDLK_h, key::h }, + { SDLK_i, key::i }, + { SDLK_j, key::j }, + { SDLK_k, key::k }, + { SDLK_l, key::l }, + { SDLK_m, key::m }, + { SDLK_n, key::n }, + { SDLK_o, key::o }, + { SDLK_p, key::p }, + { SDLK_q, key::q }, + { SDLK_r, key::r }, + { SDLK_s, key::s }, + { SDLK_t, key::t }, + { SDLK_u, key::u }, + { SDLK_v, key::v }, + { SDLK_w, key::w }, + { SDLK_x, key::x }, + { SDLK_y, key::y }, + { SDLK_z, key::z }, + { SDLK_CAPSLOCK, key::caps_lock }, + { SDLK_F1, key::f1 }, + { SDLK_F2, key::f2 }, + { SDLK_F3, key::f3 }, + { SDLK_F4, key::f4 }, + { SDLK_F5, key::f5 }, + { SDLK_F6, key::f6 }, + { SDLK_F7, key::f7 }, + { SDLK_F8, key::f8 }, + { SDLK_F9, key::f9 }, + { SDLK_F10, key::f10 }, + { SDLK_F11, key::f11 }, + { SDLK_F12, key::f12 }, + { SDLK_F13, key::f13 }, + { SDLK_F14, key::f14 }, + { SDLK_F15, key::f15 }, + { SDLK_F16, key::f16 }, + { SDLK_F17, key::f17 }, + { SDLK_F18, key::f18 }, + { SDLK_F19, key::f19 }, + { SDLK_F20, key::f20 }, + { SDLK_F21, key::f21 }, + { SDLK_F22, key::f22 }, + { SDLK_F23, key::f23 }, + { SDLK_F24, key::f24 }, + { SDLK_PRINTSCREEN, key::print_screen }, + { SDLK_SCROLLLOCK, key::scroll_lock }, + { SDLK_PAUSE, key::pause }, + { SDLK_INSERT, key::insert }, + { SDLK_HOME, key::home }, + { SDLK_PAGEUP, key::page_up }, + { SDLK_PAGEDOWN, key::page_down }, + { SDLK_DELETE, key::del }, + { SDLK_END, key::end }, + { SDLK_RIGHT, key::right }, + { SDLK_LEFT, key::left }, + { SDLK_DOWN, key::down }, + { SDLK_UP, key::up }, + { SDLK_KP_DIVIDE, key::kp_divide }, + { SDLK_KP_MULTIPLY, key::kp_multiply }, + { SDLK_KP_MINUS, key::kp_minus }, + { SDLK_KP_PLUS, key::kp_plus }, + { SDLK_KP_ENTER, key::kp_enter }, + { SDLK_KP_1, key::kp_one }, + { SDLK_KP_2, key::kp_two }, + { SDLK_KP_3, key::kp_three }, + { SDLK_KP_4, key::kp_four }, + { SDLK_KP_5, key::kp_five }, + { SDLK_KP_6, key::kp_six }, + { SDLK_KP_7, key::kp_seven }, + { SDLK_KP_8, key::kp_eight }, + { SDLK_KP_9, key::kp_nine }, + { SDLK_KP_0, key::kp_zero }, + { SDLK_MUTE, key::mute }, + { SDLK_VOLUMEUP, key::volume_up }, + { SDLK_VOLUMEDOWN, key::volume_down }, + { SDLK_LCTRL, key::left_control }, + { SDLK_LALT, key::left_alt }, + { SDLK_LSHIFT, key::left_shift }, + { SDLK_LGUI, key::left_super }, + { SDLK_RCTRL, key::right_control }, + { SDLK_RALT, key::right_alt }, + { SDLK_RSHIFT, key::right_shift }, + { SDLK_RGUI, key::right_super } +}; + +const std::unordered_map<SDL_Keymod, mod> modifiers_map{ + { KMOD_LCTRL, mod::left_control }, + { KMOD_LALT, mod::left_alt }, + { KMOD_LSHIFT, mod::left_shift }, + { KMOD_LGUI, mod::left_super }, + { KMOD_RCTRL, mod::right_control }, + { KMOD_RALT, mod::right_alt }, + { KMOD_RSHIFT, mod::right_shift }, + { KMOD_RGUI, mod::right_super }, + { KMOD_NUM, mod::num_lock }, + { KMOD_CAPS, mod::caps_lock } +}; + +const std::unordered_map<Uint32, mouse> button_map{ + { SDL_BUTTON_LEFT, mouse::left }, + { SDL_BUTTON_RIGHT, mouse::right }, + { SDL_BUTTON_MIDDLE, mouse::middle } +}; + +} // !namespace + +void window::dispatch_key_event(dispatcher& dp, const SDL_Event& ev) const +{ + assert(ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP); + + // Key and scan code. + const auto kc = keycodes_map.find(ev.key.keysym.sym); + const auto sc = scancodes_map.find(ev.key.keysym.scancode); + + if (kc == keycodes_map.end() || sc == scancodes_map.end()) + return; + + key_event kev{kc->second, sc->second, mod::none}; + + // Modifier is a mask. + for (const auto& pair : modifiers_map) + if (ev.key.keysym.mod & pair.first) + kev.modifiers |= pair.second; + + if (ev.type == SDL_KEYDOWN) + dp.handle_key_down(kev); + else + dp.handle_key_up(kev); +} + +void window::dispatch_mouse_event(dispatcher& dp, const SDL_Event& ev) const +{ + assert(ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP); + + const auto which = button_map.find(ev.button.button); + + if (which == button_map.end()) + return; + + mouse_click_event mev{ + which->second, + point{ev.button.x, ev.button.y} + }; + + if (ev.type == SDL_MOUSEBUTTONDOWN) + dp.handle_mouse_down(mev); + else + dp.handle_mouse_up(mev); +} + +void window::dispatch_mouse_wheel_event(dispatcher& dp, const SDL_Event& ev) const +{ + assert(ev.type == SDL_MOUSEWHEEL); + + dp.handle_mouse_wheel({{ev.wheel.x, ev.wheel.y}}); +} + +void window::dispatch_text_event(dispatcher& dp, const SDL_Event& ev) const +{ + assert(ev.type == SDL_TEXTINPUT); + + dp.handle_text({unicode::to_utf32(ev.text.text)}); +} + + +void window::init() +{ + static bool is_initialized{false}; + + if (!is_initialized) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) + throw std::runtime_error(SDL_GetError()); + if (TTF_Init() < 0) + throw std::runtime_error(TTF_GetError()); + + is_initialized = true; + } +} + +window::window(unsigned width, unsigned height, const std::string& title) +{ + init(); + + window_ = { + SDL_CreateWindow( + title.c_str(), + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + width, height, + SDL_WINDOW_OPENGL + ), + SDL_DestroyWindow + }; + + if (window_ == nullptr) + throw std::runtime_error(SDL_GetError()); + + // Create renderer. + renderer_ = { + SDL_CreateRenderer(window_.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), + SDL_DestroyRenderer + }; + + if (renderer_ == nullptr) + throw std::runtime_error(SDL_GetError()); +} + +auto window::get_renderer() const noexcept -> const SDL_Renderer* +{ + assert(is_open_); + + return renderer_.get(); +} + +auto window::get_renderer() noexcept -> SDL_Renderer* +{ + assert(is_open_); + + return renderer_.get(); +} + +auto window::is_open() const noexcept -> bool +{ + return is_open_; +} + +void window::start_edit() +{ + if (!is_editing_) { + SDL_StartTextInput(); + is_editing_ = true; + } +} + +void window::stop_edit() +{ + if (is_editing_) { + SDL_StopTextInput(); + is_editing_ = false; + } +} + +void window::clear() +{ + SDL_RenderClear(renderer_.get()); +} + +void window::present() +{ + SDL_RenderPresent(renderer_.get()); +} + +void window::close() noexcept +{ + is_open_ = false; + renderer_ = nullptr; + window_ = nullptr; +} + +auto window::get_drawing_color() const -> color +{ + SDL_Color color; + + if (SDL_GetRenderDrawColor(renderer_.get(), &color.r, &color.g, &color.b, &color.a) < 0) + throw std::runtime_error(SDL_GetError()); + + return { color.r, color.g, color.b, color.a }; +} + +void window::set_drawing_color(const color& color) +{ + if (SDL_SetRenderDrawColor(renderer_.get(), color.red, color.green, color.blue, color.alpha) < 0) + throw std::runtime_error(SDL_GetError()); +} + +void window::draw_line(const line& line) +{ + if (SDL_RenderDrawLine(renderer_.get(), line.x1, line.y1, line.x2, line.y2) != 0) + throw std::runtime_error(SDL_GetError()); +} + +void window::draw_point(const point& point) +{ + if (SDL_RenderDrawPoint(renderer_.get(), point.x, point.y) != 0) + throw std::runtime_error(SDL_GetError()); +} + +void window::draw_rectangle(const rectangle& rectangle) +{ + SDL_Rect rect{ + rectangle.x, + rectangle.y, + static_cast<int>(rectangle.width), + static_cast<int>(rectangle.height) + }; + + if (SDL_RenderDrawRect(renderer_.get(), &rect) < 0) + throw std::runtime_error(SDL_GetError()); +} + +void window::fill_rectangle(const rectangle& rectangle) +{ + SDL_Rect rect{ + rectangle.x, + rectangle.y, + static_cast<int>(rectangle.width), + static_cast<int>(rectangle.height) + }; + + if (SDL_RenderFillRect(renderer_.get(), &rect) < 0) + throw std::runtime_error(SDL_GetError()); +} + +void window::draw_text(const std::string& text, const font& font, const rectangle& rectangle) +{ + SDL_Color color = { 0, 0, 0, 255 }; + SDL_Surface* message = TTF_RenderUTF8_Blended(font.get_handle(), text.c_str(), color); + SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer_.get(), message); + SDL_Rect rect = { rectangle.x, rectangle.y, (int)rectangle.width, (int)rectangle.height }; + SDL_RenderCopy(renderer_.get(), texture, nullptr, &rect); + SDL_FreeSurface(message); + SDL_DestroyTexture(texture); +} + +void window::draw_text(const std::string& text, const font& font, const point& point) +{ + SDL_Color color = { 0, 0, 0, 0 }; + SDL_GetRenderDrawColor(renderer_.get(), &color.r, &color.g, &color.b, &color.a); + SDL_Surface* message = TTF_RenderUTF8_Blended(font.get_handle(), text.c_str(), color); + SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer_.get(), message); + SDL_Rect rect = { point.x, point.y, message->w, message->h }; + SDL_RenderCopy(renderer_.get(), texture, nullptr, &rect); + SDL_FreeSurface(message); + SDL_DestroyTexture(texture); +} + +void window::poll(dispatcher& dp) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYUP: + case SDL_KEYDOWN: + dispatch_key_event(dp, event); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + dispatch_mouse_event(dp, event); + break; + case SDL_MOUSEWHEEL: + dispatch_mouse_wheel_event(dp, event); + break; + case SDL_TEXTINPUT: + dispatch_text_event(dp, event); + break; + case SDL_QUIT: + dp.handle_quit(); + break; + default: + break; + } + } +} + +} // !mlk::client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-client/malikania/client/window.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,212 @@ +/* + * window.hpp -- main window and basic drawing + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_WINDOW_HPP +#define MALIKANIA_CLIENT_WINDOW_HPP + +/** + * \file window.hpp + * \brief Window and drawing. + */ + +#include <memory> +#include <string> + +#include <SDL.h> + +#include "dispatcher.hpp" + +namespace mlk { + +struct line; +struct point; +struct rectangle; + +namespace client { + +struct color; + +class font; + +/** + * \brief Main window class and drawing. + */ +class window { +private: + std::unique_ptr<SDL_Window, void (*)(SDL_Window *)> window_{nullptr, nullptr}; + std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer *)> renderer_{nullptr, nullptr}; + + bool is_open_{true}; + bool is_editing_{false}; + + void dispatch_key_event(dispatcher&, const SDL_Event&) const; + void dispatch_mouse_event(dispatcher&, const SDL_Event&) const; + void dispatch_mouse_wheel_event(dispatcher&, const SDL_Event&) const; + void dispatch_text_event(dispatcher&, const SDL_Event&) const; + + void init(); + +public: + /** + * Create a window. + * + * \param width the initial width + * \param height the initial height + * \param title the optional title + * \throw std::runtime_error on errors + */ + window(unsigned width = 640, unsigned height = 480, const std::string& title = "Game"); + + /** + * Virtual destructor defaulted. + */ + virtual ~window() noexcept = default; + + /** + * Get the renderer. + * + * \pre is_open() + * \return the renderer + */ + auto get_renderer() const noexcept -> const SDL_Renderer*; + + /** + * Overloaded function. + * + * \pre is_open() + * \return the renderer + */ + auto get_renderer() noexcept -> SDL_Renderer*; + + /** + * Tells if the window is open. + * + * \return true if open + */ + auto is_open() const noexcept -> bool; + + /** + * Start editing input. + * + * \note may open a visual keyboard on some platforms + * \note can safely be called multiple times + */ + void start_edit(); + + /** + * Stop editing input. + * + * \note may close the visual keyboard on some platforms + * \note can safely be called multiple times + */ + void stop_edit(); + + /** + * Clear the window content with the current drawing color. + */ + void clear(); + + /** + * Render the content of the window to the screen. + */ + void present(); + + /** + * Close the window. + */ + void close() noexcept; + + /** + * Get the current drawing color. + * + * \return the color + */ + auto get_drawing_color() const -> color; + + /** + * Set the drawing color. + * + * \param color the color + */ + void set_drawing_color(const color& color); + + /** + * Draw a line. + * + * \param line the line + */ + void draw_line(const line& line); + + /** + * Draw a point. + * + * \param point the point + */ + void draw_point(const point& point); + + /** + * Draw a rectangle (only borders). + * + * \param rect the rectangle + * \see fillRectangle + */ + void draw_rectangle(const rectangle& rect); + + /** + * Fill the given rectangle with the current color. + * + * \param rect the rectangle + * \see drawRectangle + */ + void fill_rectangle(const rectangle& rect); + + /** + * Draw some text. + * + * This function may stretch the text texture. + * + * \param text the text (UTF-8) + * \param font the font + * \param rectangle the rectangle target + */ + void draw_text(const std::string& text, const font& font, const rectangle& rectangle); + + /** + * Overloaded function. + * + * Draw the text at the given position. + * + * \param text the text (UTF-8) + * \param font the font + * \param point the text position + */ + void draw_text(const std::string& text, const font& font, const point& point); + + /** + * Poll all pending events and call appropriate functions. + * + * \param dispatcher the event dispatcher + */ + void poll(dispatcher& dp); +}; + +} // !client + +} // !mlk + +#endif // !MALIKANIA_CLIENT_WINDOW_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,50 @@ +# +# CMakeLists.txt -- CMake build system for malikania +# +# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +project(libmlk-db) + +find_package(PostgreSQL REQUIRED) + +set( + HEADERS + ${libmlk-db_SOURCE_DIR}/malikania/db/account.hpp + ${libmlk-db_SOURCE_DIR}/malikania/db/character.hpp + ${libmlk-db_SOURCE_DIR}/malikania/db/database.hpp + ${libmlk-db_SOURCE_DIR}/malikania/db/model.hpp + ${libmlk-db_SOURCE_DIR}/malikania/db/spell.hpp +) + +set( + SOURCES + ${libmlk-db_SOURCE_DIR}/malikania/db/account.cpp + ${libmlk-db_SOURCE_DIR}/malikania/db/character.cpp + ${libmlk-db_SOURCE_DIR}/malikania/db/database.cpp + ${libmlk-db_SOURCE_DIR}/malikania/db/spell.cpp +) + +malikania_define_library( + TARGET libmlk-db + SOURCES ${HEADERS} ${SOURCES} + LIBRARIES + ${PostgreSQL_LIBRARIES} + PUBLIC_INCLUDES + ${Boost_INCLUDE_DIRS} + ${libmlk-db_SOURCE_DIR}/malikania + PRIVATE_INCLUDES + ${PostgreSQL_INCLUDE_DIRS} +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/account.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,242 @@ +/* + * account.cpp -- database account object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include "account.hpp" + +namespace mlk::db { + +auto account::load(const result& res) -> account +{ + account a(PQgetvalue(res.get(), 0, 1), PQgetvalue(res.get(), 0, 2)); + + a.id_ = std::stoi(PQgetvalue(res.get(), 0, 0)); + a.firstname_ = PQgetvalue(res.get(), 0, 3); + a.lastname_ = PQgetvalue(res.get(), 0, 4); + a.email_ = PQgetvalue(res.get(), 0, 5); + a.characters_ = character::load(a); + + return a; +} + +void account::clear() +{ + id_ = 0U; +} + +account::account(std::string login, std::string password) noexcept + : login_(std::move(login)) + , password_(std::move(password)) +{ + assert(!login_.empty()); + assert(!password_.empty()); +} + +auto account::get_login() const noexcept -> const std::string& +{ + return login_; +} + +void account::set_password(std::string password) +{ + static const std::string sql( + "UPDATE account" + " SET password = $1" + " WHERE id = $2" + ); + + assert(!password.empty()); + + if (is_published() && password_ != password) + db::exec(sql, { password, id_ }); + + password_ = std::move(password); +} + +auto account::get_email() const noexcept -> const std::string& +{ + return email_; +} + +void account::set_email(std::string email) +{ + static const std::string sql( + "UPDATE account" + " SET email = $1" + " WHERE id = $2" + ); + + assert(!email.empty()); + + if (is_published() && email_ != email) + db::exec(sql, { email, id_ }); + + email_ = std::move(email); +} + +auto account::get_firstname() const noexcept -> const std::string& +{ + return firstname_; +} + +void account::set_firstname(std::string name) +{ + static const std::string sql( + "UPDATE account" + " SET firstname = $1" + " WHERE id = $2" + ); + + if (is_published() && firstname_ != name) + db::exec(sql, { name, id_ }); + + firstname_ = std::move(name); +} + +auto account::get_lastname() const noexcept -> const std::string& +{ + return lastname_; +} + +void account::set_lastname(std::string name) +{ + static const std::string sql( + "UPDATE account" + " SET lastname = $1" + " WHERE id = $2" + ); + + if (is_published() && lastname_ != name) + db::exec(sql, { name, id_ }); + + lastname_ = std::move(name); +} + +auto account::get_characters() const noexcept -> const std::vector<character>& +{ + return characters_; +} + +void account::add(character ch) +{ + assert(ch.is_draft()); + + characters_.reserve(characters_.size() + 1); + + if (is_published()) + ch.publish(*this); + + characters_.push_back(std::move(ch)); +} + +void account::remove(std::vector<character>::iterator it) +{ + // TODO: assert 'it' is in vector. + it->unpublish(); + characters_.erase(it); +} + +void account::publish() +{ + static const std::string sql( + "INSERT INTO account(" + " login," + " password," + " firstname," + " lastname," + " email" + ") " + "VALUES ($1, $2, $3, $4, $5) " + "RETURNING id" + ); + + assert(is_draft()); + + /* + * Recursively save the account, its characters and spells of those + * characters. + */ + transaction txn([this] { + clear(); + + for (auto& c : characters_) + c.clear(); + }); + + const auto r = select(sql, { login_, password_, firstname_, lastname_, email_ }); + + id_ = std::stoi(PQgetvalue(r.get(), 0, 0)); + + for (auto& c : characters_) + c.publish(*this); + + txn.commit(); + + assert(is_published()); +} + +void account::unpublish() +{ + static const std::string sql( + "DELETE" + " FROM account" + " WHERE id = $1" + ); + + assert(is_published()); + + id_ = 0; + + /* + * Recursively make all characters and their spells draft. + */ + for (auto& c : characters_) + c.clear(); + + assert(is_draft()); +} + +auto account::find_by_login(const std::string& login) -> std::optional<account> +{ + static const std::string sql( + "SELECT *" + " FROM account" + " WHERE login = $1" + ); + + const auto r = select(sql, { login }); + + if (PQntuples(r.get()) == 0) + return std::nullopt; + + return load(r); +} + +auto account::authenticate(const std::string& login, + const std::string& password) -> std::optional<account> +{ + auto ac = find_by_login(login); + + if (!ac || ac->password_ != password) + return std::nullopt; + + return ac; +} + +} // !mlk::db
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/account.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,189 @@ +/* + * account.hpp -- database account object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_DB_ACCOUNT_HPP +#define MALIKANIA_DB_ACCOUNT_HPP + +/** + * \file account.hpp + * \brief Database account object. + */ + +#include <optional> + +#include "character.hpp" +#include "database.hpp" +#include "model.hpp" + +namespace mlk::db { + +/** + * \brief Database account object. + */ +class account : public model { +private: + std::string login_; + std::string password_; + std::string email_; + std::string firstname_; + std::string lastname_; + std::vector<character> characters_; + + static auto load(const result&) -> account; + + void clear(); + +public: + /** + * Create a draft account. + * + * \pre !login.empty() + * \pre !password.empty() + * \param login the login name + * \param password the password + * \warning the password is saved as-is and **must** be hashed by the caller. + */ + account(std::string login, std::string password) noexcept; + + /** + * Get the account login. + * + * \return the login + */ + auto get_login() const noexcept -> const std::string&; + + /** + * Set the password. + * + * \pre !password.empty() + * \warning the password is saved as-is and **must** be hashed by the caller. + */ + void set_password(std::string password); + + /** + * Get the account email. + * + * \return the email + */ + auto get_email() const noexcept -> const std::string&; + + /** + * Set the account email. + * + * \pre !email.empty() + * \param email the new email + */ + void set_email(std::string email); + + /** + * Get the account first name. + * + * \return the name + */ + auto get_firstname() const noexcept -> const std::string&; + + /** + * Set the account firstname. + * + * \param name the new name + */ + void set_firstname(std::string name); + + /** + * Get the account last name. + * + * \return the name + */ + auto get_lastname() const noexcept -> const std::string&; + + /** + * Set the account last name. + * + * \param name the new name + */ + void set_lastname(std::string name); + + /** + * Get the caracter list. + * + * \return the associated characters. + */ + auto get_characters() const noexcept -> const std::vector<character>&; + + /** + * Add the character to the account. + * + * Account takes ownership of character. + * + * \pre ch.is_draft() + * \param ch the character + * \post ch.is_published() + */ + void add(character ch); + + /** + * Remove the character from the account. + * + * \pre it is in the the account character list + * \param ch the character + * \post ch == nullptr + */ + void remove(std::vector<character>::iterator it); + + /** + * Save the account, does nothing if is_published(). + * + * \throw std::exception on errors + * \post is_published() + */ + void publish(); + + /** + * Destroy the account. + * + * The account will contains no characters anymore. + * + * \throw std::exception on errors + * \post is_draft() + */ + void unpublish(); + + /** + * Find an account by login. + * + * \param login the login + * \return the account or none if not found + * \throw std::runtime_error on database errors + */ + static auto find_by_login(const std::string& login) -> std::optional<account>; + + /** + * Find and authenticate a user. + * + * \param login the login + * \param password the password + * \return the account or none if not found + * \throw std::runtime_error on database errors + */ + static auto authenticate(const std::string& login, + const std::string& password) -> std::optional<account>; +}; + +} // !mlk::db + +#endif // !MALIKANIA_DB_ACCOUNT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/character.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,266 @@ +/* + * character.cpp -- database character object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> +#include <numeric> + +#include "account.hpp" +#include "character.hpp" +#include "database.hpp" + +namespace mlk::db { + +auto character::load(const result& result, int row) -> character +{ + character ch(PQgetvalue(result.get(), row, 2), PQgetvalue(result.get(), row, 3)); + + ch.levels_[stat::hp] = std::stoi(PQgetvalue(result.get(), row, 4)); + ch.factors_[stat::hp] = std::stoi(PQgetvalue(result.get(), row, 5)); + ch.exp_[stat::hp] = std::stoi(PQgetvalue(result.get(), row, 6)); + + ch.levels_[stat::force] = std::stoi(PQgetvalue(result.get(), row, 7)); + ch.factors_[stat::force] = std::stoi(PQgetvalue(result.get(), row, 8)); + ch.exp_[stat::force] = std::stoi(PQgetvalue(result.get(), row, 9)); + + ch.levels_[stat::defense] = std::stoi(PQgetvalue(result.get(), row, 10)); + ch.factors_[stat::defense] = std::stoi(PQgetvalue(result.get(), row, 11)); + ch.exp_[stat::defense] = std::stoi(PQgetvalue(result.get(), row, 12)); + + ch.levels_[stat::agility] = std::stoi(PQgetvalue(result.get(), row, 13)); + ch.factors_[stat::agility] = std::stoi(PQgetvalue(result.get(), row, 14)); + ch.exp_[stat::agility] = std::stoi(PQgetvalue(result.get(), row, 15)); + + ch.levels_[stat::luck] = std::stoi(PQgetvalue(result.get(), row, 16)); + ch.factors_[stat::luck] = std::stoi(PQgetvalue(result.get(), row, 17)); + ch.exp_[stat::luck] = std::stoi(PQgetvalue(result.get(), row, 18)); + + ch.id_ = std::stoi(PQgetvalue(result.get(), row, 0)); + ch.spells_ = spell::load(ch); + + return ch; +} + +auto character::load(const account& parent) -> std::vector<character> +{ + static const std::string sql( + "SELECT *" + " FROM character" + " WHERE account_id = $1" + ); + + const auto r = select(sql, { parent.get_id() }); + + if (PQntuples(r.get()) == 0) + throw std::runtime_error("failed to load characters"); + + std::vector<character> characters; + + for (int i = 0; i < PQntuples(r.get()); ++i) + characters.push_back(load(r, i)); + + return characters; +} + +void character::clear() +{ + id_ = 0U; + + for (auto& s : spells_) + s.clear(); +} + +void character::publish(account& parent) +{ + static const std::string sql( + "INSERT INTO character (" + " account_id," + " nickname," + " type," + " hp_level," + " hp_factor," + " hp_exp," + " force_level," + " force_factor," + " force_exp," + " defense_level," + " defense_factor," + " defense_exp," + " agility_level," + " agility_factor," + " agility_exp," + " luck_level," + " luck_factor," + " luck_exp" + ") " + "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) " + "RETURNING id" + ); + + const auto r = select(sql, { + parent.get_id(), + nickname_, + type_, + levels_[stat::hp], + factors_[stat::hp], + exp_[stat::hp], + levels_[stat::force], + factors_[stat::force], + exp_[stat::force], + levels_[stat::defense], + factors_[stat::defense], + exp_[stat::defense], + levels_[stat::agility], + factors_[stat::agility], + exp_[stat::agility], + levels_[stat::luck], + factors_[stat::luck], + exp_[stat::luck] + }); + + if (PQntuples(r.get()) == 0) + throw std::runtime_error("failed to save character"); + + id_ = std::stoi(PQgetvalue(r.get(), 0, 0)); + + for (auto& s : spells_) + s.publish(*this); +} + +void character::unpublish() +{ + static const std::string sql( + "DELETE" + " FROM character" + " WHERE id = $1" + ); + + exec(sql, { id_ }); + clear(); +} + +character::character(std::string nickname, std::string type) noexcept + : nickname_(std::move(nickname)) + , type_(std::move(type)) +{ + assert(!nickname_.empty()); + assert(!type_.empty()); +} + +auto character::get_nickname() const noexcept -> const std::string& +{ + return nickname_; +} + +auto character::get_type() const noexcept -> const std::string& +{ + return type_; +} + +auto character::get_spells() const noexcept -> const std::vector<spell>& +{ + return spells_; +} + +auto character::get_levels() const noexcept -> const std::array<std::uint8_t, 5>& +{ + return levels_; +} + +void character::set_levels(std::array<std::uint8_t, 5> levels) +{ + static const std::string sql( + "UPDATE character" + " SET hp_level = $1" + " , force_level = $2" + " , defense_level = $3" + " , agility_level = $4" + " , luck_level = $5" + ); + + if (is_published()) + exec(sql, { id_, levels[0], levels[1], levels[2], levels[3], levels[4] }); + + levels_ = std::move(levels); +} + +auto character::get_factors() const noexcept -> const std::array<std::uint8_t, 5>& +{ + return factors_; +} + +void character::set_factors(std::array<std::uint8_t, 5> factors) +{ + static const std::string sql( + "UPDATE character" + " SET hp_factor = $1" + " , force_factor = $2" + " , defense_factor = $3" + " , agility_factor = $4" + " , luck_factor = $5" + ); + + assert(std::accumulate(factors.begin(), factors.end(), 0U) == 100U); + + if (is_published()) + exec(sql, { id_, factors[0], factors[1], factors[2], factors[3], factors[4] }); + + factors_ = std::move(factors); +} + +auto character::get_experience() const noexcept -> const std::array<std::uint32_t, 5>& +{ + return exp_; +} + +void character::set_experience(std::array<std::uint32_t, 5> experience) +{ + static const std::string sql( + "UPDATE character" + " SET hp_experience = $1" + " , force_experience = $2" + " , defense_experience = $3" + " , agility_experience = $4" + " , luck_experience = $5" + ); + + if (is_published()) + exec(sql, { id_, experience[0], experience[1], experience[2], experience[3], experience[4] }); + + exp_ = std::move(experience); +} + +void character::add(spell sp) +{ + assert(sp.is_draft()); + + spells_.reserve(spells_.size() + 1); + + if (is_published()) + sp.publish(*this); + + spells_.push_back(std::move(sp)); +} + +void character::remove(std::vector<spell>::iterator it) +{ + // TODO: assert 'it' is in vector. + it->unpublish(); + spells_.erase(it); +} + +} // !mlk::db
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/character.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,171 @@ +/* + * character.hpp -- database character object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_DB_CHARACTER_HPP +#define MALIKANIA_DB_CHARACTER_HPP + +/* + * \file character.hpp + * \brief Database character object. + */ + +#include <cstdint> +#include <array> +#include <vector> + +#include "database.hpp" +#include "model.hpp" +#include "spell.hpp" + +namespace mlk::db { + +class account; + +/* + * \brief Database character object. + */ +class character : public model { +public: + friend class account; + + /** + * \brief Stats index in arrays + * \see set_levels + * \see set_factors + * \see set_experience + */ + enum stat { + hp = 0, //!< hp index + force, //!< force index + defense, //!< defense index + agility, //!< agility index + luck //!< luck index + }; + +private: + std::string nickname_; + std::string type_; + std::vector<spell> spells_; + std::array<std::uint8_t, 5> levels_{1U, 1U, 1U, 1U, 1U}; + std::array<std::uint8_t, 5> factors_{20U, 20U, 20U, 20U, 20U}; + std::array<std::uint32_t, 5> exp_{0U, 0U, 0U, 0U, 0U}; + + static auto load(const result&, int) -> character; + static auto load(const account&) -> std::vector<character>; + + void clear(); + void publish(account&); + void unpublish(); + +public: + /** + * Construct a character, no database is modified yet. + * + * \pre !nickname.empty() + * \pre !type.empty() + * \param nickname the nickname + * \param type the type + */ + character(std::string nickname, std::string type) noexcept; + + /** + * Get the character nickname. + * + * \return the name + */ + auto get_nickname() const noexcept -> const std::string&; + + /** + * Get the character type name. + * + * \return the type name + */ + auto get_type() const noexcept -> const std::string&; + + /** + * Get the list of spells. + * + * \return the spells + */ + auto get_spells() const noexcept -> const std::vector<spell>&; + + /** + * Get the list of levels. + * + * \return the levels + */ + auto get_levels() const noexcept -> const std::array<std::uint8_t, 5>&; + + /** + * Set the new levels. + * + * \param levels the levels + */ + void set_levels(std::array<std::uint8_t, 5> levels); + + /** + * Get the list of factors. + * + * \return the factors + */ + auto get_factors() const noexcept -> const std::array<std::uint8_t, 5>&; + + /** + * Set progression factors. + * + * \pre factors sum must be 100 + * \param factors the factors + */ + void set_factors(std::array<std::uint8_t, 5> factors); + + /** + * Get the stats experience. + * + * \return the experience + */ + auto get_experience() const noexcept -> const std::array<std::uint32_t, 5>&; + + /** + * Set stats experience. + * + * \param experience the experience + */ + void set_experience(std::array<std::uint32_t, 5> experience); + + /** + * Add a spell. + * + * Character takes ownership of spell. + * + * \pre sp.is_draft() + * \param sp the spell (moved) + */ + void add(spell sp); + + /** + * Remove the spell from the character. + * + * \pre it must be valid + * \param it the spell iterator + */ + void remove(std::vector<spell>::iterator it); +}; + +} // !mlk::db + +#endif // !MALIKANIA_DB_CHARACTER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/database.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,210 @@ +/* + * database.cpp -- connection to postgresql database + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> +#include <sstream> + +#include "database.hpp" + +namespace mlk::db { + +namespace { + +struct strify { + template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> + auto operator()(T i) const -> std::string + { + return std::to_string(i); + } + + auto operator()(bool v) const -> std::string + { + return v ? "t" : "f"; + } + + auto operator()(std::string s) const -> std::string + { + return s; + } +}; + +std::unique_ptr<PGconn, void (*)(PGconn*)> connection{nullptr, nullptr}; + +auto run(const std::string& sql, std::vector<arg> args = {}) -> result +{ + std::vector<const char*> list; + + /* + * PQexecParams requires an array of C strings, convert all arguments in the + * args vector to string and then keep the C string value into a temporary + * array. + */ + for (auto& arg : args) { + arg = std::visit(strify(), arg); + list.push_back(std::get<std::string>(arg).c_str()); + } + + return { + PQexecParams(connection.get(), sql.c_str(), list.size(), nullptr, + list.data(), nullptr, nullptr, 0 + ), + PQclear + }; +} + +} // !namespace + +void open(const std::string& host, + const std::string& port, + const std::string& user, + const std::string& database, + const std::string& password) +{ + assert(!connection); + + std::ostringstream oss; + + if (!host.empty()) + oss << "host=" << host << " "; + if (!port.empty()) + oss << "port=" << port << " "; + if (!user.empty()) + oss << "user=" << user << " "; + if (!database.empty()) + oss << "dbname=" << database << " "; + if (!password.empty()) + oss << "password=" << password; + + connection = { PQconnectdb(oss.str().c_str()), PQfinish }; + + if (PQstatus(connection.get()) != CONNECTION_OK) + throw std::runtime_error(PQerrorMessage(connection.get())); +} + +const std::string init_account( + "CREATE TABLE IF NOT EXISTS account(" + " id SERIAL," + " login TEXT NOT NULL," + " password TEXT NOT NULL," + " firstname TEXT," + " lastname TEXT," + " email TEXT," + " PRIMARY KEY(id)" + ")" +); + +const std::string init_character( + "CREATE TABLE IF NOT EXISTS character(" + " id SERIAL," + " account_id INTEGER NOT NULL," + " nickname TEXT NOT NULL," + " type TEXT NOT NULL," + " hp_level SMALLINT NOT NULL DEFAULT 1," + " hp_factor SMALLINT NOT NULL," + " hp_exp INT NOT NULL," + " force_level SMALLINT NOT NULL DEFAULT 1," + " force_factor SMALLINT NOT NULL," + " force_exp INT NOT NULL," + " defense_level SMALLINT NOT NULL DEFAULT 1," + " defense_factor SMALLINT NOT NULL," + " defense_exp INT NOT NULL," + " agility_level SMALLINT NOT NULL DEFAULT 1," + " agility_factor SMALLINT NOT NULL," + " agility_exp INT NOT NULL," + " luck_level SMALLINT NOT NULL DEFAULT 1," + " luck_factor SMALLINT NOT NULL," + " luck_exp INT NOT NULL," + " PRIMARY KEY(id)," + " FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE" + ")" +); + +const std::string init_spell( + "CREATE TABLE IF NOT EXISTS spell(" + " id SERIAL," + " character_id INTEGER NOT NULL," + " type TEXT NOT NULL," + " level SMALLINT NOT NULL," + " PRIMARY KEY(id)," + " FOREIGN KEY (character_id) REFERENCES character(id) ON DELETE CASCADE" + ")" +); + +void init() +{ + assert(connection); + + exec(init_account); + exec(init_character); + exec(init_spell); +} + +auto select(const std::string& sql, const std::vector<arg>& args) -> result +{ + assert(connection); + + auto result = run(sql, args); + + switch (PQresultStatus(result.get())) { + case PGRES_COMMAND_OK: + case PGRES_TUPLES_OK: + break; + default: + throw std::runtime_error(PQerrorMessage(connection.get())); + } + + return result; +} + +void exec(const std::string& sql, const std::vector<arg>& args) +{ + assert(connection); + + switch (const auto result = run(sql, args); PQresultStatus(result.get())) { + case PGRES_COMMAND_OK: + break; + default: + throw std::runtime_error(PQerrorMessage(connection.get())); + } +} + +transaction::transaction(rollback fn) + : rollback_(std::move(fn)) +{ + assert(rollback_); + + exec("BEGIN"); +} + +transaction::~transaction() +{ + if (!commit_) { + rollback_(); + exec("ROLLBACK"); + } +} + +void transaction::commit() +{ + if (!commit_) { + exec("COMMIT"); + commit_ = true; + } +} + +} // !db::mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/database.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,151 @@ +/* + * database.hpp -- connection to postgresql database + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_DB_DATABASE_HPP +#define MALIKANIA_DB_DATABASE_HPP + +/** + * \file database.hpp + * \brief Abstract database interface. + */ + +#include <cstdint> +#include <functional> +#include <memory> +#include <stdexcept> +#include <string> +#include <variant> +#include <vector> + +#include <libpq-fe.h> + +namespace mlk::db { + +/** + * \brief Statement argument. + * + * When using prepared statement, you may pass any data you like using this + * variant. + */ +using arg = std::variant< + bool, + double, + std::int8_t, + std::uint8_t, + std::int16_t, + std::uint16_t, + std::int32_t, + std::uint32_t, + std::int64_t, + std::uint64_t, + std::string +>; + +/** + * \brief Convenient result type. + * + * This unique pointer holds the PostgreSQL result and free it automatically on + * out of scope. + */ +using result = std::unique_ptr<PGresult, void (*)(PGresult*)>; + +/** + * Open the connection to the database. + * + * All arguments are optional. + * + * \pre connection must be closed + * \param host the hostname + * \param port the port number + * \param user the user name + * \param database the database name + * \param password the user password + * \throw std::runtime_error on errors + */ +void open(const std::string& host, + const std::string& port, + const std::string& user, + const std::string& database, + const std::string& password); + +/** + * Unconditionally init the database. + * + * \throw std::runtime_error on errors + */ +void init(); + +/** + * Execute a SELECT statement. + * + * \param sql the SQL statement + * \param args the optional arguments to bind + * \return the result value + * \throw std::runtime_error on errors + */ +auto select(const std::string& sql, const std::vector<arg>& args = {}) -> result; + +/** + * Execute an UPDATE statement. + * + * \param sql the SQL statement + * \param args the optional arguments to bind + * \throw std::runtime_error on errors + */ +void exec(const std::string& sql, const std::vector<arg>& args = {}); + +class transaction { +public: + /** + * \brief Rollback function. + */ + using rollback = std::function<void ()>; + +private: + rollback rollback_; + bool commit_{false}; + +public: + /** + * Start a transaction. + * + * If there is already a transaction, the returned object is no-op. + * + * \param rollback the rollback function + * \return the transaction object + */ + transaction(rollback fn); + + /** + * Rollback the transaction if commit() has not been called. + */ + ~transaction(); + + /** + * Commit the transaction. + * + * Does nothing if already committed. + * + * \throw std::exception on errors + */ + void commit(); +}; + +} // !mlk::db + +#endif // !MALIKANIA_DB_DATABASE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/model.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,120 @@ +/* + * model.hpp -- abstract database object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_DB_MODEL_HPP +#define MALIKANIA_DB_MODEL_HPP + +/** + * \file model.hpp + * \brief Abstract database object. + */ + +#include <cstdint> + +namespace mlk::db { + +/** + * \brief Abstract database object. + */ +class model { +public: + /** + * Id type. + */ + using id_type = std::uint64_t; + +private: + model(const model&) = delete; + model& operator=(const model&) = delete; + +protected: + /** + * Object id. + */ + id_type id_{0U}; + +public: + /** + * Default constructor. + */ + model() = default; + + /** + * Move constructor. + * + * \param other the original value (id resets to 0) + */ + inline model(model&& other) noexcept + : id_(other.id_) + { + other.id_ = 0U; + } + + /** + * Virtual destructor defaulted. + */ + virtual ~model() noexcept = default; + + /** + * Get the id. + * + * \return the id + */ + auto get_id() const noexcept -> id_type + { + return id_; + } + + /** + * Tells if the object is not persistent. + * + * \return true if object was never saved + */ + auto is_draft() const noexcept -> bool + { + return id_ == 0U; + } + + /** + * Tells if the object is present in database + * + * \return true if object is saved + */ + auto is_published() const noexcept -> bool + { + return id_ > 0U; + } + + /** + * Move operator. + * + * \param other the original value (id resets to 0) + * \return *this + */ + auto operator=(model&& other) noexcept -> model& + { + id_ = other.id_; + other.id_ = 0U; + + return *this; + } +}; + +} // !mlk::db + +#endif // !MALIKANIA_DB_MODEL_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/spell.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,124 @@ +/* + * spell.cpp -- database spell object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include "character.hpp" +#include "spell.hpp" + +namespace mlk::db { + +auto spell::load(const result& result, int row) -> spell +{ + spell s(PQgetvalue(result.get(), row, 2)); + + s.id_ = std::stoi(PQgetvalue(result.get(), row, 0)); + s.level_ = std::stoi(PQgetvalue(result.get(), row, 3)); + + return s; +} + +auto spell::load(const character& parent) -> std::vector<spell> +{ + static const std::string sql( + "SELECT *" + " FROM spell" + " WHERE id = $1" + ); + + const auto r = select(sql, { parent.get_id() }); + + if (PQntuples(r.get()) == 0) + throw std::runtime_error("failed to load spells"); + + std::vector<spell> spells; + + for (int i = 0; i < PQntuples(r.get()); ++i) + spells.push_back(load(r, i)); + + return spells; +} + +void spell::clear() +{ + id_ = 0U; +} + +void spell::unpublish() +{ + static const std::string sql( + "DELETE" + " FROM spell" + " WHERE id = $1" + ); + + exec(sql, { id_ }); + clear(); +} + +void spell::publish(character& parent) +{ + static const std::string sql( + "INSERT INTO spell(" + " character_id," + " type," + " level" + ") " + "VALUES ($1, $2, $3) " + "RETURNING id" + ); + + const auto r = select(sql, { parent.get_id(), type_, level_ }); + + if (PQntuples(r.get()) == 0) + throw std::runtime_error("failed to save spell"); + + id_ = std::stoi(PQgetvalue(r.get(), 0, 0)); +} + +spell::spell(std::string type) noexcept + : type_(std::move(type)) +{ + assert(!type_.empty()); +} + +auto spell::get_type() const noexcept -> const std::string& +{ + return type_; +} + +auto spell::get_level() const noexcept -> std::uint8_t +{ + return level_; +} + +void spell::set_level(std::uint8_t level) +{ + static const std::string sql( + "UPDATE spell" + " SET level = $1" + " WHERE id = $2" + ); + + if (is_published() && level_ != level) + db::exec(sql, { level_, id_ }); + + level_ = level; +} + +} // !mlk::db
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-db/malikania/db/spell.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,88 @@ +/* + * spell.hpp -- database spell object + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_DB_SPELL_HPP +#define MALIKANIA_DB_SPELL_HPP + +/** + * \file spell.hpp + * \brief Database spell object. + */ + +#include <cstdint> +#include <string> +#include <vector> + +#include "database.hpp" +#include "model.hpp" + +namespace mlk::db { + +class character; + +/** + * \brief Describe a spell. + */ +class spell : public model { +private: + friend class character; + + std::string type_; + std::uint8_t level_{1U}; + + static auto load(const result&, int) -> spell; + static auto load(const character&) -> std::vector<spell>; + + void clear(); + void unpublish(); + void publish(character&); + +public: + /** + * Constructor. + * + * \pre !type.empty() + * \param type the type name + */ + spell(std::string type) noexcept; + + /** + * Get the type. + * + * \return the type + */ + auto get_type() const noexcept -> const std::string&; + + /** + * Get the level. + * + * \return the level + */ + auto get_level() const noexcept -> std::uint8_t; + + /** + * Set the spell level. + * + * \param level the level + */ + void set_level(std::uint8_t level); +}; + +} // !mlk::db + +#endif // !MALIKANIA_DB_SPELL_HPP
--- a/libmlk-js-test/malikania/js/test/js_api_fixture.hpp Wed Oct 24 21:13:12 2018 +0200 +++ b/libmlk-js-test/malikania/js/test/js_api_fixture.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -30,13 +30,13 @@ #include <malikania/rectangle.hpp> #include <malikania/size.hpp> -#include <malikania/duk.hpp> -#include <malikania/js_elapsed_timer.hpp> -#include <malikania/js_line.hpp> -#include <malikania/js_point.hpp> -#include <malikania/js_rectangle.hpp> -#include <malikania/js_resources_loader.hpp> -#include <malikania/js_size.hpp> +#include <malikania/js/duk.hpp> +#include <malikania/js/elapsed_timer_js_api.hpp> +#include <malikania/js/line_js_api.hpp> +#include <malikania/js/point_js_api.hpp> +#include <malikania/js/rectangle_js_api.hpp> +#include <malikania/js/loader_js_api.hpp> +#include <malikania/js/size_js_api.hpp> namespace mlk::js::test {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,50 @@ +# +# CMakeLists.txt -- CMake build system for malikania +# +# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +project(libmlk-js) + +set( + HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/duk.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/elapsed_timer_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/line_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/loader_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/point_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/rectangle_js_api.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/size_js_api.hpp +) + +set( + SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/duk.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/elapsed_timer_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/line_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/loader_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/point_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/rectangle_js_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js/size_js_api.cpp +) + +malikania_define_library( + PROJECT libmlk-common-js + TARGET libmlk-common-js + SOURCES ${HEADERS} ${SOURCES} + PUBLIC_INCLUDES + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + LIBRARIES duktape json libmlk +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/duk.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,447 @@ +/* + * duk.cpp -- miscellaneous Duktape extras + * + * Copyright (c) 2017-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> +#include <cstdio> + +#include "duk.hpp" + +namespace mlk::js::duk { + +// {{{ stack_guard + +stack_guard::stack_guard(duk_context* ctx, unsigned expected) noexcept +#if !defined(NDEBUG) + : context_(ctx) + , expected_(expected) + , at_start_(duk_get_top(ctx)) +#endif +{ +#if defined(NDEBUG) + (void)ctx; + (void)expected; +#endif +} + +stack_guard::~stack_guard() noexcept +{ +#if !defined(NDEBUG) + auto result = duk_get_top(context_) - at_start_; + + if (result != static_cast<int>(expected_)) { + std::fprintf(stderr, "Corrupt stack detection in stack_guard:\n"); + std::fprintf(stderr, " Size at start: %d\n", at_start_); + std::fprintf(stderr, " Size at end: %d\n", duk_get_top(context_)); + std::fprintf(stderr, " Expected (user): %u\n", expected_); + std::fprintf(stderr, " Expected (adjusted): %u\n", expected_ + at_start_); + std::fprintf(stderr, " Difference count: %+d\n", result - expected_); + std::abort(); + } +#endif +} + +// }}} + +// {{{ context + +context::context() noexcept + : handle_(duk_create_heap_default(), duk_destroy_heap) +{ + duk_push_object(handle_.get()); + duk_put_global_string(handle_.get(), "Malikania"); +} + +context::operator duk_context*() noexcept +{ + return handle_.get(); +} + +context::operator duk_context*() const noexcept +{ + return handle_.get(); +} + +// }}} + +// {{{ stack_info + +stack_info::stack_info(std::string name, + std::string message, + std::string stack, + std::string file_name, + unsigned line_number) noexcept + : name_(std::move(name)) + , message_(std::move(message)) + , stack_(std::move(stack)) + , file_name_(std::move(file_name)) + , line_number_(line_number) +{ +} + +auto stack_info::get_name() const noexcept -> const std::string& +{ + return name_; +} + +auto stack_info::get_message() const noexcept -> const std::string& +{ + return message_; +} + +auto stack_info::get_stack() const noexcept -> const std::string& +{ + return stack_; +} + +auto stack_info::get_file_name() const noexcept -> const std::string& +{ + return file_name_; +} + +auto stack_info::get_line_number() const noexcept -> unsigned +{ + return line_number_; +} + +auto stack_info::what() const noexcept -> const char* +{ + return message_.c_str(); +} + +// }}} + +// {{{ error + +error::error(int type, std::string message) noexcept + : type_(type) + , message_(std::move(message)) +{ +} + +error::error(std::string message) noexcept + : message_(std::move(message)) +{ +} + +void error::create(duk_context* ctx) const +{ + duk_push_error_object(ctx, type_, "%s", message_.c_str()); +} + +// }}} + +// {{{ eval_error + +eval_error::eval_error(std::string message) noexcept + : error(DUK_ERR_EVAL_ERROR, std::move(message)) +{ +} + +// }}} + +// {{{ range_error + +range_error::range_error(std::string message) noexcept + : error(DUK_ERR_RANGE_ERROR, std::move(message)) +{ +} + +// }}} + +// {{{ reference_error + +reference_error::reference_error(std::string message) noexcept + : error(DUK_ERR_REFERENCE_ERROR, std::move(message)) +{ +} + +// }}} + +// {{{ syntax_error + +syntax_error::syntax_error(std::string message) noexcept + : error(DUK_ERR_SYNTAX_ERROR, std::move(message)) +{ +} + +// }}} + +// {{{ type_error + +type_error::type_error(std::string message) noexcept + : error(DUK_ERR_TYPE_ERROR, std::move(message)) +{ +} + +// }}} + +// {{{ uri_error + +uri_error::uri_error(std::string message) noexcept + : error(DUK_ERR_URI_ERROR, std::move(message)) +{ +} + +// }}} + +// {{{ get_stack + +auto get_stack(duk_context* ctx, int index, bool pop) -> stack_info +{ + index = duk_normalize_index(ctx, index); + + duk_get_prop_string(ctx, index, "name"); + auto name = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "message"); + auto message = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "fileName"); + auto file_name = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "lineNumber"); + auto line_number = duk_to_uint(ctx, -1); + duk_get_prop_string(ctx, index, "stack"); + auto stack = duk_to_string(ctx, -1); + duk_pop_n(ctx, 5); + + if (pop) + duk_remove(ctx, index); + + return { + std::move(name), + std::move(message), + std::move(stack), + std::move(file_name), + line_number + }; +} + +// }}} + +// {{{ type_traits<std::exception> + +void type_traits<std::exception>::raise(duk_context* ctx, const std::exception& ex) +{ + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); +} + +// }}} + +// {{{ type_traits<std::system_error> + +void type_traits<std::system_error>::raise(duk_context* ctx, const std::system_error& ex) +{ + duk_push_error_object(ctx, DUK_ERR_ERROR, ex.what()); + duk_push_int(ctx, ex.code().value()); + duk_put_prop_string(ctx, -2, "code"); + duk_push_string(ctx, ex.code().category().name()); + duk_put_prop_string(ctx, -2, "category"); + duk_throw(ctx); +} + +// }}} + +// {{{ type_traits<error> + +void type_traits<error>::raise(duk_context* ctx, const error& ex) +{ + ex.create(ctx); + duk_throw(ctx); +} + +// }}} + +// {{{ type_traits<bool> + +void type_traits<bool>::push(duk_context* ctx, bool value) +{ + duk_push_boolean(ctx, value); +} + +auto type_traits<bool>::get(duk_context* ctx, duk_idx_t index) -> bool +{ + return duk_get_boolean(ctx, index); +} + +auto type_traits<bool>::require(duk_context* ctx, duk_idx_t index) -> bool +{ + return duk_require_boolean(ctx, index); +} + +auto type_traits<bool>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<bool> +{ + return duk_is_boolean(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +// }}} + +// {{{ type_traits<duk_double_t> + +void type_traits<duk_double_t>::push(duk_context* ctx, duk_double_t value) +{ + duk_push_number(ctx, value); +} + +auto type_traits<duk_double_t>::get(duk_context* ctx, duk_idx_t index) -> duk_double_t +{ + return duk_get_number(ctx, index); +} + +auto type_traits<duk_double_t>::require(duk_context* ctx, duk_idx_t index) -> duk_double_t +{ + return duk_require_number(ctx, index); +} + +auto type_traits<duk_double_t>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_double_t> +{ + return duk_is_number(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +// }}} + +// {{{ type_traits<duk_int_t> + +void type_traits<duk_int_t>::push(duk_context* ctx, duk_int_t value) +{ + duk_push_int(ctx, value); +} + +auto type_traits<duk_int_t>::get(duk_context* ctx, duk_idx_t index) -> duk_int_t +{ + return duk_get_int(ctx, index); +} + +auto type_traits<duk_int_t>::require(duk_context* ctx, duk_idx_t index) -> duk_int_t +{ + return duk_require_int(ctx, index); +} + +auto type_traits<duk_int_t>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_int_t> +{ + return duk_is_number(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +// }}} + +// {{{ type_traits<duk_uint_t> + +void type_traits<duk_uint_t>::push(duk_context* ctx, duk_uint_t value) +{ + duk_push_uint(ctx, value); +} + +auto type_traits<duk_uint_t>::get(duk_context* ctx, duk_idx_t index) -> duk_uint_t +{ + return duk_get_uint(ctx, index); +} + +auto type_traits<duk_uint_t>::require(duk_context* ctx, duk_idx_t index) -> duk_uint_t +{ + return duk_require_uint(ctx, index); +} + +auto type_traits<duk_uint_t>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_uint_t> +{ + return duk_is_number(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +// }}} + +// {{{ type_traits<const char*> + +void type_traits<const char*>::push(duk_context* ctx, const char* value) +{ + duk_push_string(ctx, value); +} + +auto type_traits<const char*>::get(duk_context* ctx, duk_idx_t index) -> const char* +{ + return duk_get_string(ctx, index); +} + +auto type_traits<const char*>::require(duk_context* ctx, duk_idx_t index) -> const char* +{ + return duk_require_string(ctx, index); +} + +auto type_traits<const char*>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<const char*> +{ + return duk_is_string(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +// }}} + +// {{{ type_traits<std::string> + +void type_traits<std::string>::push(duk_context* ctx, const std::string& value) +{ + duk_push_lstring(ctx, value.data(), value.size()); +} + +auto type_traits<std::string>::get(duk_context* ctx, duk_idx_t index) -> std::string +{ + duk_size_t length; + const char* str = duk_get_lstring(ctx, index, &length); + + return { str, length }; +} + +auto type_traits<std::string>::require(duk_context* ctx, duk_idx_t index) -> std::string +{ + duk_size_t length; + const char* str = duk_require_lstring(ctx, index, &length); + + return { str, length }; +} + +auto type_traits<std::string>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string> +{ + return duk_is_string(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +// }}} + +// {{{ type_traits<std::string_view> + +void type_traits<std::string_view>::push(duk_context* ctx, std::string_view value) +{ + duk_push_lstring(ctx, value.data(), value.size()); +} + +auto type_traits<std::string_view>::get(duk_context* ctx, duk_idx_t index) -> std::string_view +{ + duk_size_t length; + const char* str = duk_get_lstring(ctx, index, &length); + + return { str, length }; +} + +auto type_traits<std::string_view>::require(duk_context* ctx, duk_idx_t index) -> std::string_view +{ + duk_size_t length; + const char* str = duk_require_lstring(ctx, index, &length); + + return { str, length }; +} + +auto type_traits<std::string_view>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string_view> +{ + return duk_is_string(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +// }}} + +} // !mlk::js::duk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/duk.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,988 @@ +/* + * duk.hpp -- miscellaneous Duktape extras + * + * Copyright (c) 2017-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JS_DUK_HPP +#define MALIKANIA_JS_DUK_HPP + +/** + * \file duk.hpp + * \brief Miscellaneous Duktape extras + * \author David Demelier <markand@malikania.fr> + * \version 0.2.0 + */ + +#include <exception> +#include <memory> +#include <optional> +#include <string> +#include <string_view> +#include <system_error> + +#include "duktape.h" + +/** + * \brief Miscellaneous Duktape extras. + */ +namespace mlk::js::duk { + +// {{{ stack_guard + +/** + * \brief Stack sanity checker. + * + * Instanciate this class where you need to manipulate the Duktape stack outside + * a Duktape/C function, its destructor will examinate if the stack size matches + * the user expected size. + * + * When compiled with NDEBUG, this class does nothing. + * + * To use it, just declare an lvalue at the beginning of your function. + */ +class stack_guard { +#if !defined(NDEBUG) +private: + duk_context* context_; + unsigned expected_; + int at_start_; +#endif + +public: + /** + * Create the stack checker. + * + * No-op if NDEBUG is set. + * + * \param ctx the context + * \param expected the size expected relative to the already existing values + */ + stack_guard(duk_context* ctx, unsigned expected = 0) noexcept; + + /** + * Verify the expected size. + * + * No-op if NDEBUG is set. + */ + ~stack_guard() noexcept; +}; + +// }}} + +// {{{ context + +/** + * \brief RAII based Duktape handler. + * + * This class is implicitly convertible to duk_context for convenience. + */ +class context { +private: + std::unique_ptr<duk_context, void (*)(duk_context*)> handle_; + + context(const context&) = delete; + void operator=(const context&) = delete; + +public: + /** + * Create default context. + */ + context() noexcept; + + /** + * Default move constructor. + */ + context(context&&) noexcept = default; + + /** + * Convert the context to the native Duktape/C type. + * + * \return the duk_context + */ + operator duk_context*() noexcept; + + /** + * Convert the context to the native Duktape/C type. + * + * \return the duk_context + */ + operator duk_context*() const noexcept; + + /** + * Default move assignment operator. + * + * \return this + */ + auto operator=(context&&) noexcept -> context& = default; +}; + +// }}} + +// {{{ stack_info + +/** + * \brief Error description. + * + * This class fills the fields got in an Error object. + */ +class stack_info : public std::exception { +private: + std::string name_; + std::string message_; + std::string stack_; + std::string file_name_; + unsigned line_number_; + +public: + /** + * Construct the stack information. + * + * \param name the exception name (e.g. ReferenceError) + * \param message the error message + * \param stack the stack trace + * \param file_name the optional filename + * \param line_number the optional line number + */ + stack_info(std::string name, + std::string message, + std::string stack, + std::string file_name, + unsigned line_number = 0) noexcept; + + /** + * Get the exception name. + * + * \return the exception name (e.g. ReferenceError) + */ + auto get_name() const noexcept -> const std::string&; + + /** + * Get the error message. + * + * \return the message + */ + auto get_message() const noexcept -> const std::string&; + + /** + * Get the stack trace. + * + * \return the stack + */ + auto get_stack() const noexcept -> const std::string&; + + /** + * Get the optional file name. + * + * \return the file name + */ + auto get_file_name() const noexcept -> const std::string&; + + /** + * Get the line number. + * + * \return the line number + */ + auto get_line_number() const noexcept -> unsigned; + + /** + * Get the error message. This effectively returns message field. + * + * \return the message + */ + auto what() const noexcept -> const char* override; +}; + +// }}} + +// {{{ type_traits + +/** + * \brief Operations on different types. + * + * This class provides some functions for the given type, depending on the + * nature of the function. + * + * For example, push will call type_traits<T>::push static function + * if the type_traits is implemented for that given T type. + * + * This helps passing/getting function between Javascript and C++ code. + * + * Example: + * + * ```cpp + * push(ctx, 123); // Uses type_traits<int> + * push(ctx, true); // Uses type_traits<bool> + * ``` + * + * This class is specialized for the following types: + * + * - `bool`, + * - `duk_int_t`, + * - `duk_uint_t`, + * - `duk_double_t`, + * - `const char*`, + * - `std::string`, + * - `std::string_view`. + * + * Regarding exceptions, this class is specialized for the following types: + * + * - error, + * - std::exception, + * - std::system_error. + * + * \see push + * \see get + * \see require + * \see raise + */ +template <typename T> +struct type_traits; + +// }}} + +// {{{ push + +/** + * Generic push function. + * + * This function calls type_traits<T>::push if specialized. + * + * \param ctx the Duktape context + * \param value the forwarded value + * \return 1 for convenience + */ +template <typename T> +auto push(duk_context* ctx, T&& value) -> int +{ + using Type = typename std::decay<T>::type; + + type_traits<Type>::push(ctx, std::forward<T>(value)); + + return 1; +} + +// }}} + +// {{{ put + +/** + * Generic put function. + * + * This function calls type_traits<T>::put if specialized. + * + * The purpose of this function is to inject the argument through the value at + * the top of the stack. + * + * \param ctx the Duktape context + * \param value the forwarded value + * \return 1 for convenience + */ +template <typename T> +auto put(duk_context* ctx, T&& value) -> int +{ + using Type = typename std::decay<T>::type; + + type_traits<Type>::put(ctx, std::forward<T>(value)); + + return 1; +} + +// }}} + +// {{{ get + +/** + * Generic get function. + * + * This functions calls type_traits<T>::get if specialized. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ +template <typename T> +auto get(duk_context* ctx, duk_idx_t index) -> decltype(auto) +{ + using Type = typename std::decay<T>::type; + + return type_traits<Type>::get(ctx, index); +} + +// }}} + +// {{{ optional + +/** + * Generic optional function. + * + * This functions calls type_traits<T>::optional if specialized. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ +template <typename T> +auto optional(duk_context* ctx, duk_idx_t index) -> decltype(auto) +{ + using Type = typename std::decay<T>::type; + + return type_traits<Type>::optional(ctx, index); +} + +// }}} + +// {{{ require + +/** + * Generic require function. + * + * This functions calls type_traits<T>::require if specialized. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ +template <typename T> +auto require(duk_context* ctx, duk_idx_t index) -> decltype(auto) +{ + using Type = typename std::decay<T>::type; + + return type_traits<Type>::require(ctx, index); +} + +// }}} + +// {{{ error + +/** + * \brief Base ECMAScript error class. + * \warning Override the function create for your own exceptions + */ +class error { +private: + int type_{DUK_ERR_ERROR}; + std::string message_; + +protected: + /** + * Constructor with a type of error specified, specially designed for + * derived errors. + * + * \param type of error (e.g. DUK_ERR_ERROR) + * \param message the message + */ + error(int type, std::string message) noexcept; + +public: + /** + * Constructor with a message. + * + * \param message the message + */ + error(std::string message) noexcept; + + /** + * Virtual destructor defaulted. + */ + ~error() = default; + + /** + * Create the exception on the stack. + * + * \note the default implementation search for the global variables + * \param ctx the context + */ + void create(duk_context* ctx) const; +}; + +// }}} + +// {{{ eval_error + +/** + * \brief Error in eval() function. + */ +class eval_error : public error { +public: + /** + * Construct an EvalError. + * + * \param message the message + */ + eval_error(std::string message) noexcept; +}; + +// }}} + +// {{{ range_error + +/** + * \brief Value is out of range. + */ +class range_error : public error { +public: + /** + * Construct an RangeError. + * + * \param message the message + */ + range_error(std::string message) noexcept; +}; + +// }}} + +// {{{ reference_error + +/** + * \brief Trying to use a variable that does not exist. + */ +class reference_error : public error { +public: + /** + * Construct an ReferenceError. + * + * \param message the message + */ + reference_error(std::string message) noexcept; +}; + +// }}} + +// {{{ syntax_error + +/** + * \brief Syntax error in the script. + */ +class syntax_error : public error { +public: + /** + * Construct an SyntaxError. + * + * \param message the message + */ + syntax_error(std::string message) noexcept; +}; + +// }}} + +// {{{ type_error + +/** + * \brief Invalid type given. + */ +class type_error : public error { +public: + /** + * Construct an TypeError. + * + * \param message the message + */ + type_error(std::string message) noexcept; +}; + +// }}} + +// {{{ uri_error + +/** + * \brief URI manipulation failure. + */ +class uri_error : public error { +public: + /** + * Construct an URIError. + * + * \param message the message + */ + uri_error(std::string message) noexcept; +}; + +// }}} + +// {{{ raise + +/** + * Create an exception into the stack and throws it. + * + * This function needs the following requirements in type_traits + * + * ```cpp + * static void raise(duk_context*, Error); + * ``` + * + * Error can be any kind of value, it is forwarded. + * + * \param ctx the Duktape context + * \param error the error object + */ +template <typename Error> +void raise(duk_context* ctx, Error&& error) +{ + using type = std::decay_t<Error>; + + type_traits<type>::raise(ctx, std::forward<Error>(error)); +} + +// }}} + +// {{{ get_stack + +/** + * Get the error object when a JavaScript error has been thrown (e.g. eval + * failure). + * + * \param ctx the context + * \param index the index + * \param pop if true, also remove the exception from the stack + * \return the information + */ +auto get_stack(duk_context* ctx, int index, bool pop = true) -> stack_info; + +// }}} + +// {{{ type_traits<std::exception> + +/** + * \brief Specialization for std::exception. + */ +template <> +struct type_traits<std::exception> { + /** + * Raise a Error object. + * + * \param ctx the Duktape context + * \param ex the exception + */ + static void raise(duk_context* ctx, const std::exception& ex); +}; + +// }}} + +// {{{ type_traits<std::system_error> + +/** + * \brief Specialization for std::system_error. + */ +template <> +struct type_traits<std::system_error> { + /** + * Raise a Error object. + * + * The error object has the following properties defined in it: + * + * - code: (int) error code, + * - category: (string) error category string. + * + * \param ctx the Duktape context + * \param ex the exception + */ + static void raise(duk_context* ctx, const std::system_error& ex); +}; + +// }}} + +// {{{ type_traits<error> + +/** + * \brief Specialization for error. + */ +template <> +struct type_traits<error> { + /** + * Raise a error. + * + * \param ctx the Duktape context + * \param ex the exception + */ + static void raise(duk_context* ctx, const error& ex); +}; + +// }}} + +// {{{ type_traits<bool> + +/** + * \brief Specialization for bool. + */ +template <> +struct type_traits<bool> { + /** + * Push a boolean. + * + * Uses duk_push_boolean + * + * \param ctx the Duktape context + * \param value the value + */ + static void push(duk_context* ctx, bool value); + + /** + * Get a boolean. + * + * Uses duk_get_boolean. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto get(duk_context* ctx, duk_idx_t index) -> bool; + + /** + * Require a boolean. + * + * Uses duk_require_boolean. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto require(duk_context* ctx, duk_idx_t index) -> bool; + + /** + * Get a boolean if convertible. + * + * Uses duk_get_boolean. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<bool>; +}; + +// }}} + +// {{{ type_traits<duk_double_t> + +/** + * \brief Specialization for duk_double_t. + */ +template <> +struct type_traits<duk_double_t> { + /** + * Push a double. + * + * Uses duk_push_number + * + * \param ctx the Duktape context + * \param value the value + */ + static void push(duk_context* ctx, duk_double_t value); + + /** + * Get a double. + * + * Uses duk_get_number. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto get(duk_context* ctx, duk_idx_t index) -> duk_double_t; + + /** + * Require a double. + * + * Uses duk_require_double. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto require(duk_context* ctx, duk_idx_t index) -> duk_double_t; + + /** + * Get a double if convertible + * + * Uses duk_get_number. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_double_t>; +}; + +// }}} + +// {{{ type_traits<duk_int_t> + +/** + * \brief Specialization for duk_int_t. + */ +template <> +struct type_traits<duk_int_t> { + /** + * Push an int. + * + * Uses duk_push_int + * + * \param ctx the Duktape context + * \param value the value + */ + static void push(duk_context* ctx, duk_int_t value); + + /** + * Get an int. + * + * Uses duk_get_int. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto get(duk_context* ctx, duk_idx_t index) -> duk_int_t; + + /** + * Require an int. + * + * Uses duk_require_int. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto require(duk_context* ctx, duk_idx_t index) -> duk_int_t; + + /** + * Get an int if convertible. + * + * Uses duk_get_int. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_int_t>; +}; + +// }}} + +// {{{ type_traits<duk_uint_t> + +/** + * \brief Specialization for duk_uint_t. + */ +template <> +struct type_traits<duk_uint_t> { + /** + * Push an unsigned int. + * + * Uses duk_push_uint + * + * \param ctx the Duktape context + * \param value the value + */ + static void push(duk_context* ctx, duk_uint_t value); + + /** + * Get an unsigned int. + * + * Uses duk_get_uint. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto get(duk_context* ctx, duk_idx_t index) -> duk_uint_t; + + /** + * Require an unsigned int. + * + * Uses duk_require_uint. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto require(duk_context* ctx, duk_idx_t index) -> duk_uint_t; + + /** + * Get an unsigned int if convertible. + * + * Uses duk_get_uint. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<duk_uint_t>; +}; + +// }}} + +// {{{ type_traits<const char*> + +/** + * \brief Specialization for C strings. + */ +template <> +struct type_traits<const char*> { + /** + * Push a C string. + * + * Uses duk_push_string + * + * \param ctx the Duktape context + * \param value the value + */ + static void push(duk_context* ctx, const char* value); + + /** + * Get a C string. + * + * Uses duk_get_string. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto get(duk_context* ctx, duk_idx_t index) -> const char*; + + /** + * Require a C string. + * + * Uses duk_require_string. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto require(duk_context* ctx, duk_idx_t index) -> const char*; + + /** + * Get a C string if convertible. + * + * Uses duk_get_string. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<const char*>; +}; + +// }}} + +// {{{ type_traits<std::string> + +/** + * \brief Specialization for C++ std::strings. + */ +template <> +struct type_traits<std::string> { + /** + * Push a C++ std::string. + * + * Uses duk_push_lstring + * + * \param ctx the Duktape context + * \param value the value + */ + static void push(duk_context* ctx, const std::string& value); + + /** + * Get a C++ std::string. + * + * Uses duk_get_lstring. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto get(duk_context* ctx, duk_idx_t index) -> std::string; + + /** + * Require a C++ std::string. + * + * Uses duk_require_lstring. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto require(duk_context* ctx, duk_idx_t index) -> std::string; + + /** + * Get a C++ std::string if convertible. + * + * Uses duk_get_lstring. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string>; +}; + +// }}} + +// {{{ type_traits<std::string_view> + +/** + * \brief Specialization for C++ std::string_views. + */ +template <> +struct type_traits<std::string_view> : public std::true_type { + /** + * Push a C++ std::string_view. + * + * Uses duk_push_lstring + * + * \param ctx the Duktape context + * \param value the value + */ + static void push(duk_context* ctx, std::string_view value); + + /** + * Get a C++ std::string_view. + * + * Uses duk_get_lstring. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto get(duk_context* ctx, duk_idx_t index) -> std::string_view; + + /** + * Require a C++ std::string_view. + * + * Uses duk_require_lstring. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto require(duk_context* ctx, duk_idx_t index) -> std::string_view; + + /** + * Get a C++ std::string_view if convertible. + * + * Uses duk_get_lstring. + * + * \param ctx the Duktape context + * \param index the value index + * \return the converted value + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<std::string_view>; +}; + +// }}} + +} // !mlk::js::duk + +#endif // !MALIKANIA_JS_DUK_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/elapsed_timer_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,170 @@ +/* + * elapsed_timer_js_api.cpp -- Malikania.ElapsedTimer API + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <boost/timer/timer.hpp> + +#include "elapsed_timer_js_api.hpp" + +namespace mlk::js { + +namespace { + +const std::string_view signature("\xff""\xff""Malikania.ElapsedTimer"); + +// {{{ self + +auto self(duk_context* ctx) -> boost::timer::cpu_timer* +{ + duk::stack_guard sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature.data()); + const auto ptr = static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1)); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object"); + + return ptr; +} + +// }}} + +// {{{ Irccd.ElapsedTimer.prototype.pause + +/* + * Method: ElapsedTimer.prototype.pause + * ------------------------------------------------------------------ + * + * Pause the timer, without resetting the current elapsed time stored. + */ +auto ElapsedTimer_prototype_pause(duk_context* ctx) -> duk_ret_t +{ + self(ctx)->stop(); + + return 0; +} + +// }}} + +// {{{ Irccd.ElapsedTimer.prototype.restart + +/* + * Method: Irccd.ElapsedTimer.prototype.restart + * ------------------------------------------------------------------ + * + * Restart the timer without resetting the current elapsed time. + */ +auto ElapsedTimer_prototype_restart(duk_context* ctx) -> duk_ret_t +{ + self(ctx)->resume(); + + return 0; +} + +// }}} + +// {{{ Irccd.ElapsedTimer.prototype.elapsed + +/* + * Method: ElapsedTimer.prototype.elapsed + * ------------------------------------------------------------------ + * + * Get the number of elapsed milliseconds. + * + * Returns: + * The time elapsed. + */ +auto ElapsedTimer_prototype_elapsed(duk_context* ctx) -> duk_ret_t +{ + duk_push_uint(ctx, self(ctx)->elapsed().wall / 1000000LL); + + return 1; +} + +// }}} + +// {{{ Irccd.ElapsedTimer [constructor] + +/* + * Function: Irccd.ElapsedTimer [constructor] + * ------------------------------------------------------------------ + * + * Construct a new ElapsedTimer object. + */ +auto ElapsedTimer_constructor(duk_context* ctx) -> duk_ret_t +{ + duk_push_this(ctx); + duk_push_pointer(ctx, new boost::timer::cpu_timer); + duk_put_prop_string(ctx, -2, signature.data()); + duk_pop(ctx); + + return 0; +} + +// }}} + +// {{{ Irccd.ElapsedTimer [destructor] + +/* + * Function: Irccd.ElapsedTimer [destructor] + * ------------------------------------------------------------------ + * + * Delete the property. + */ +auto ElapsedTimer_destructor(duk_context* ctx) -> duk_ret_t +{ + duk_get_prop_string(ctx, 0, signature.data()); + delete static_cast<boost::timer::cpu_timer*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, signature.data()); + + return 0; +} + +// }}} + +// {{{ definitions + +const duk_function_list_entry methods[] = { + { "elapsed", ElapsedTimer_prototype_elapsed, 0 }, + { "pause", ElapsedTimer_prototype_pause, 0 }, + { "restart", ElapsedTimer_prototype_restart, 0 }, + { nullptr, nullptr, 0 } +}; + +// }}} + +} // !namespace + +void load_elapsed_timer_api(duk_context* ctx) +{ + duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, ElapsedTimer_constructor, 0); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_push_c_function(ctx, ElapsedTimer_destructor, 1); + duk_set_finalizer(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "ElapsedTimer"); + duk_pop(ctx); +} + +} // !mlk::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/elapsed_timer_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,40 @@ +/* + * elapsed_timer_js_api.hpp -- Malikania.ElapsedTimer API + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JS_ELAPSED_TIMER_HPP +#define MALIKANIA_JS_ELAPSED_TIMER_HPP + +/** + * \file js_elapsed_timer.hpp + * \brief Malikania.ElapsedTimer Javascript API. + */ + +#include "duk.hpp" + +namespace mlk::js { + +/** + * Load Malikania.ElapsedTimer API into the context. + * + * \param ctx the context + */ +void load_elapsed_timer_api(duk_context* ctx); + +} // !mlk::js + +#endif // !MALIKANIA_JS_ELAPSED_TIMER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/line_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,155 @@ +/* + * line_js_api.cpp -- line description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/line.hpp> + +#include "line_js_api.hpp" + +namespace mlk::js { + +namespace { + +auto Line_constructor(duk_context* ctx) -> duk_ret_t +{ + line obj; + + if (duk_get_top(ctx) == 4) + obj = line{ + duk::require<int>(ctx, 0), + duk::require<int>(ctx, 1), + duk::require<int>(ctx, 2), + duk::require<int>(ctx, 3) + }; + else if (duk_get_top(ctx) == 1) + obj = duk::require<line>(ctx, 0); + + duk_ret_t ret; + + // Allow both constructor and non constructor calls. + if (duk_is_constructor_call(ctx)) { + duk_push_this(ctx); + duk::put(ctx, obj); + duk_pop(ctx); + ret = 0; + } else { + duk::push(ctx, obj); + ret = 1; + } + + return ret; +} + +} // !namespace + +namespace duk { + +auto type_traits<line>::get(duk_context* ctx, duk_idx_t index) -> line +{ + duk::stack_guard sa(ctx); + + line ret; + + duk_get_prop_string(ctx, index, "x1"); + ret.x1 = duk::get<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y1"); + ret.y1 = duk::get<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "x2"); + ret.x2 = duk::get<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y2"); + ret.y2 = duk::get<int>(ctx, -1); + duk_pop(ctx); + + return ret; +} + +auto type_traits<line>::require(duk_context* ctx, duk_idx_t index) -> line +{ + duk::stack_guard sa(ctx); + + duk_get_prop_string(ctx, index, "x1"); + const auto x1 = duk::optional<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y1"); + const auto y1 = duk::optional<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "x2"); + const auto x2 = duk::optional<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y2"); + const auto y2 = duk::optional<int>(ctx, -1); + duk_pop(ctx); + + if (!x1) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x1' property"); + if (!y1) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y1' property"); + if (!x2) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x2' property"); + if (!y2) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y2' property"); + + return { *x1, *y1, *x2, *y2 }; +} + +auto type_traits<line>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<line> +{ + return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +void type_traits<line>::push(duk_context* ctx, const line& line) +{ + duk::stack_guard sa(ctx, 1); + + duk_push_object(ctx); + put(ctx, line); +} + +void type_traits<line>::put(duk_context* ctx, const line& line) +{ + assert(duk_is_object(ctx, -1)); + + duk::stack_guard sa(ctx); + + duk::push(ctx, line.x1); + duk_put_prop_string(ctx, -2, "x1"); + duk::push(ctx, line.y1); + duk_put_prop_string(ctx, -2, "y1"); + duk::push(ctx, line.x2); + duk_put_prop_string(ctx, -2, "x2"); + duk::push(ctx, line.y2); + duk_put_prop_string(ctx, -2, "y2"); +} + +} // !duk + +void load_line_api(duk_context* ctx) +{ + duk::stack_guard sa(ctx, 0); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Line_constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Line"); + duk_pop(ctx); +} + +} // !mlk::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/line_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,110 @@ +/* + * line_js_api.hpp -- line description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JS_LINE_HPP +#define MALIKANIA_JS_LINE_HPP + +/** + * \file js_line.hpp + * \brief JavaScript binding for line. + * + * Lines are plain objects. + * + * ```` + * { + * x1: 10, + * y1: 10, + * x2: 50, + * y2: 50 + * } + * ```` + */ + +#include "duk.hpp" + +namespace mlk { + +struct line; + +namespace js { + +namespace duk { + +template <> +struct type_traits<line> { + /** + * Get a line. + * + * \param ctx the context + * \param index the index + * \return the line + */ + static auto get(duk_context* ctx, duk_idx_t index) -> line; + + /** + * Require a line. + * + * If value is not an object or any property is invalid, raise a + * JavaScript error. + * + * \param ctx the context + * \param index the index + * \return the line + */ + static auto require(duk_context* ctx, duk_idx_t index) -> line; + + /** + * Like get but return def if the value at the given index is not an object. + * + * \param ctx the context + * \param index the index + * \return the line + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<line>; + + /** + * Push the line as object. + * + * \param ctx the context + * \param line the line + */ + static void push(duk_context* ctx, const line& line); + + /** + * Put the line properties into the object at the top of the stack. + * + * \param ctx the context + * \param line the line + */ + static void put(duk_context* ctx, const line& line); +}; + +} // !duk + +/** + * Load Malikania.Line API into the context. + * + * \param ctx the context + */ +void load_line_api(duk_context* ctx); + +} // !js + +} // !mlk + +#endif // !MALIKANIA_JS_LINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/loader_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,56 @@ +/* + * loader_js_api.cpp -- resources loader (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/loader.hpp> + +#include "loader_js_api.hpp" + +namespace mlk::js::duk { + +namespace { + +const std::string_view variable("\xff""\xff""Malikania.Loader"); + +} // !namespace + +void type_traits<loader>::put(duk_context *ctx, loader& loader) +{ + assert(ctx); + + duk::stack_guard sa(ctx); + + duk_push_pointer(ctx, &loader); + duk_put_global_string(ctx, variable.data()); +} + +auto type_traits<loader>::require(duk_context* ctx, duk_idx_t) -> loader& +{ + assert(ctx); + + duk::stack_guard sa(ctx); + + duk_get_global_string(ctx, variable.data()); + auto ptr = static_cast<loader*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return *static_cast<loader*>(ptr); +} + +} // !mlk::js::duk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/loader_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,45 @@ +/* + * loader_js_api.hpp -- resources loader (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JS_LOADER_HPP +#define MALIKANIA_JS_LOADER_HPP + +#include "duk.hpp" + +namespace mlk { + +class loader; + +namespace js { + +namespace duk { + +template <> +struct type_traits<loader> { + static void put(duk_context* ctx, loader& loader); + + static auto require(duk_context* ctx, duk_idx_t index) -> loader&; +}; + +} // !duk + +} // !js + +} // !mlk + +#endif // !MALIKANIA_JS_LOADER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/point_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,133 @@ +/* + * point_js_api.cpp -- point description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/point.hpp> + +#include "point_js_api.hpp" + +namespace mlk::js { + +namespace { + +auto Point_constructor(duk_context* ctx) -> duk_ret_t +{ + point obj; + + if (duk_get_top(ctx) == 2) + obj = point{ + duk::require<int>(ctx, 0), + duk::require<int>(ctx, 1) + }; + else if (duk_get_top(ctx) == 1) + obj = duk::require<point>(ctx, 0); + + duk_ret_t ret; + + // Allow both constructor and non constructor calls. + if (duk_is_constructor_call(ctx)) { + duk_push_this(ctx); + duk::put(ctx, obj); + duk_pop(ctx); + ret = 0; + } else { + duk::push(ctx, obj); + ret = 1; + } + + return ret; +} + +} // !namespace + +namespace duk { + +auto type_traits<point>::get(duk_context* ctx, duk_idx_t index) -> point +{ + duk::stack_guard sa(ctx); + + point ret; + + duk_get_prop_string(ctx, index, "x"); + ret.x = duk::get<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y"); + ret.y = duk::get<int>(ctx, -1); + duk_pop(ctx); + + return ret; +} + +auto type_traits<point>::require(duk_context* ctx, duk_idx_t index) -> point +{ + duk::stack_guard sa(ctx); + + duk_get_prop_string(ctx, index, "x"); + const auto x = duk::optional<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y"); + const auto y = duk::optional<int>(ctx, -1); + duk_pop(ctx); + + if (!x) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x' property"); + if (!y) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y' property"); + + return { *x, *y }; +} + +auto type_traits<point>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<point> +{ + return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +void type_traits<point>::push(duk_context* ctx, const point &point) +{ + duk::stack_guard sa(ctx, 1); + + duk_push_object(ctx); + put(ctx, point); +} + +void type_traits<point>::put(duk_context* ctx, const point& point) +{ + assert(duk_is_object(ctx, -1)); + + duk::stack_guard sa(ctx); + + duk::push(ctx, point.x); + duk_put_prop_string(ctx, -2, "x"); + duk::push(ctx, point.y); + duk_put_prop_string(ctx, -2, "y"); +} + +} // !duk + +void load_point_api(duk_context* ctx) +{ + duk::stack_guard sa(ctx, 0); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Point_constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Point"); + duk_pop(ctx); +} + +} // !mlk::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/point_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,72 @@ +/* + * point_js_api.hpp -- point description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JS_POINT_HPP +#define MALIKANIA_JS_POINT_HPP + +/** + * \file js_point.hpp + * \brief JavaScript binding for line. + * + * Points are plain objects. + * + * ```` + * { + * x: 10, + * y: 10, + * } + * ```` + */ + +#include "duk.hpp" + +namespace mlk { + +struct point; + +namespace js { + +namespace duk { + +template <> +struct type_traits<point> { + static auto require(duk_context* ctx, duk_idx_t index) -> point; + + static auto get(duk_context* ctx, duk_idx_t index) -> point; + + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<point>; + + static void push(duk_context* ctx, const point& point); + + static void put(duk_context* ctx, const point& point); +}; + +} // !duk + +/** + * Load Malikania.Point API into the context. + * + * \param ctx the context + */ +void load_point_api(duk_context* ctx); + +} // !js + +} // !mlk + +#endif // !MALIKANIA_JS_POINT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/rectangle_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,158 @@ +/* + * rectangle_js_api.cpp -- rectangle description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/rectangle.hpp> + +#include "rectangle_js_api.hpp" + +namespace mlk::js { + +namespace { + +auto Rectangle_constructor(duk_context* ctx) -> duk_ret_t +{ + rectangle rect; + + if (duk_get_top(ctx) == 4) { + rect = rectangle{ + duk::require<int>(ctx, 0), + duk::require<int>(ctx, 1), + duk::require<unsigned>(ctx, 2), + duk::require<unsigned>(ctx, 3) + }; + } else if (duk_get_top(ctx) == 1) + rect = duk::require<rectangle>(ctx, 0); + + duk_ret_t ret; + + // Allow both constructor and non constructor calls. + if (duk_is_constructor_call(ctx)) { + duk_push_this(ctx); + duk::put(ctx, rect); + duk_pop(ctx); + ret = 0; + } else { + duk::push(ctx, rect); + ret = 1; + } + + return ret; +} + +} // !namespace + +namespace duk { + +auto type_traits<rectangle>::get(duk_context* ctx, duk_idx_t index) -> rectangle +{ + duk::stack_guard sa(ctx); + + rectangle ret; + + if (!duk_is_object(ctx, index)) + return ret; + + duk_get_prop_string(ctx, index, "x"); + ret.x = duk::get<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y"); + ret.y = duk::get<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "width"); + ret.width = duk::get<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "height"); + ret.height = duk::get<int>(ctx, -1); + duk_pop(ctx); + + return ret; +} + +auto type_traits<rectangle>::require(duk_context* ctx, duk_idx_t index) -> rectangle +{ + duk::stack_guard sa(ctx); + + duk_get_prop_string(ctx, index, "x"); + const auto x = duk::optional<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y"); + const auto y = duk::optional<int>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "width"); + const auto width = duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "height"); + const auto height = duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + + if (!x) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'x' property"); + if (!y) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'y' property"); + if (!width) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'width' property"); + if (!height) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'height' property"); + + return { *x, *y, *width, *height }; +} + +auto type_traits<rectangle>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<rectangle> +{ + return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt;; +} + +void type_traits<rectangle>::push(duk_context* ctx, const rectangle& rect) +{ + duk::stack_guard sa(ctx, 1); + + duk_push_object(ctx); + put(ctx, rect); +} + +void type_traits<rectangle>::put(duk_context* ctx, const rectangle& rect) +{ + assert(duk_is_object(ctx, -1)); + + duk::stack_guard sa(ctx); + + duk::push(ctx, rect.x); + duk_put_prop_string(ctx, -2, "x"); + duk::push(ctx, rect.y); + duk_put_prop_string(ctx, -2, "y"); + duk::push(ctx, rect.width); + duk_put_prop_string(ctx, -2, "width"); + duk::push(ctx, rect.height); + duk_put_prop_string(ctx, -2, "height"); +} + +} // !duk + +void load_rectangle_api(duk_context* ctx) +{ + duk::stack_guard sa(ctx, 0); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Rectangle_constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Rectangle"); + duk_pop(ctx); +} + +} // !mlk::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/rectangle_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,111 @@ +/* + * rectangle_js_api.hpp -- rectangle description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JS_RECTANGLE_HPP +#define MALIKANIA_JS_RECTANGLE_HPP + +/** + * \file js_rectangle.hpp + * \brief JavaScript binding for rectangle. + * + * Rectangles are plain objects. + * + * ```` + * { + * x: 10, + * y: 20, + * width: 100, + * height: 200 + * } + * ```` + */ + +#include "duk.hpp" + +namespace mlk { + +struct rectangle; + +namespace js { + +namespace duk { + +template <> +struct type_traits<rectangle> { + /** + * Get a rectangle. + * + * The rectangle may be adjusted if any values are incorrect. + * + * \param ctx the context + * \param index the value index + * \return the rectangle + */ + static auto get(duk_context* ctx, duk_idx_t index) -> rectangle; + + /** + * Require a rectangle. + * + * If the object is not a rectangle or if width, height are invalid, raise a JavaScript error. + * + * \param ctx the context + * \param index the index + * \return the rectangle + */ + static auto require(duk_context* ctx, duk_idx_t index) -> rectangle; + + /** + * Like get but return the default value if the value at the given index is not an object or invalid + * + * \param ctx the context + * \param index the idnex + * \return the rectangle + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<rectangle>; + + /** + * Push the rectangle as object. + * + * \param ctx the context + * \param rect the rectangle + */ + static void push(duk_context* ctx, const rectangle &rect); + + /** + * Put the rectangle properties into the object at the top of the stack. + * + * \param ctx the context + * \param rect the rectangle + */ + static void put(duk_context* ctx, const rectangle& rect); +}; + +} // !duk + +/** + * Load Malikania.Rectangle API into the context. + * + * \param ctx the context + */ +void load_rectangle_api(duk_context* ctx); + +} // !js + +} // !mlk + +#endif // !MALIKANIA_JS_RECTANGLE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/size_js_api.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,133 @@ +/* + * size_js_api.cpp -- size description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include <malikania/size.hpp> + +#include "size_js_api.hpp" + +namespace mlk::js { + +namespace { + +auto Size_constructor(duk_context* ctx) -> duk_ret_t +{ + size obj; + + if (duk_get_top(ctx) == 2) { + obj = size{ + duk::require<unsigned>(ctx, 0), + duk::require<unsigned>(ctx, 1) + }; + } else if (duk_get_top(ctx) == 1) + obj = duk::require<size>(ctx, 0); + + duk_ret_t ret; + + // Allow both constructor and non constructor calls. + if (duk_is_constructor_call(ctx)) { + duk_push_this(ctx); + duk::put(ctx, obj); + duk_pop(ctx); + ret = 0; + } else { + duk::push(ctx, obj); + ret = 1; + } + + return ret; +} + +} // !namespace + +namespace duk { + +auto type_traits<size>::get(duk_context* ctx, duk_idx_t index) -> size +{ + duk::stack_guard sa(ctx); + + size ret; + + duk_get_prop_string(ctx, index, "width"); + ret.width = duk::get<unsigned>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "height"); + ret.height = duk::get<unsigned>(ctx, -1); + duk_pop(ctx); + + return ret; +} + +auto type_traits<size>::require(duk_context* ctx, duk_idx_t index) -> size +{ + duk::stack_guard sa(ctx); + + duk_get_prop_string(ctx, index, "width"); + const auto width = duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "height"); + const auto height = duk::optional<unsigned>(ctx, -1); + duk_pop(ctx); + + if (!width) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'width' property"); + if (!height) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid 'height' property"); + + return { *width, *height }; +} + +auto type_traits<size>::optional(duk_context* ctx, duk_idx_t index) -> std::optional<size> +{ + return duk_is_object(ctx, index) ? std::make_optional(get(ctx, index)) : std::nullopt; +} + +void type_traits<size>::push(duk_context* ctx, const size& size) +{ + duk::stack_guard sa(ctx, 1); + + duk_push_object(ctx); + put(ctx, size); +} + +void type_traits<size>::put(duk_context* ctx, const size& size) +{ + assert(duk_is_object(ctx, -1)); + + duk::stack_guard sa(ctx, 0); + + duk::push(ctx, size.width); + duk_put_prop_string(ctx, -2, "width"); + duk::push(ctx, size.height); + duk_put_prop_string(ctx, -2, "height"); +} + +} // !duk + +void load_size_api(duk_context* ctx) +{ + duk::stack_guard sa(ctx, 0); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, Size_constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Size"); + duk_pop(ctx); +} + +} // !mlk::js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-js/malikania/js/size_js_api.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,108 @@ +/* + * size_js_api.hpp -- size description (JavaScript binding) + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JS_SIZE_HPP +#define MALIKANIA_JS_SIZE_HPP + +/** + * \file js_size.hpp + * \brief JavaScript binding for size. + * + * Sizes are plain objects. + * + * ```` + * { + * width: 1000, + * height: 2000 + * } + * ```` + */ + +#include "duk.hpp" + +namespace mlk { + +struct size; + +namespace js { + +namespace duk { + +template <> +struct type_traits<size> { + /** + * Get a size. + * + * The size may be adjusted if any values are incorrect. + * + * \param ctx the context + * \param index the value index + * \return the size + */ + static auto get(duk_context* ctx, duk_idx_t index) -> size; + + /** + * Require a size + * + * If the object is not a size, raise a JavaScript error. + * + * \param ctx the context + * \param index the index + * \return the size + */ + static auto require(duk_context* ctx, duk_idx_t index) -> size; + + /** + * \param ctx the context + * \param index the idnex + * \param def the default value + * \return the size + */ + static auto optional(duk_context* ctx, duk_idx_t index) -> std::optional<size>; + + /** + * Push the size as object. + * + * \param ctx the context + * \param size the size + */ + static void push(duk_context* ctx, const size& size); + + /** + * Put the size properties into the object at the top of the stack. + * + * \param ctx the context + * \param size the size + */ + static void put(duk_context* ctx, const size& size); +}; + +} // !duk + +/** + * Load Malikania.Size API into the context. + * + * \param ctx the context + */ +void load_size_api(duk_context* ctx); + +} // !js + +} // !mlk + +#endif // !MALIKANIA_JS_SIZE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,59 @@ +# +# CMakeLists.txt -- CMake build system for malikania +# +# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +project(libmlk-server) + +find_package(Threads REQUIRED) + +set( + HEADERS + ${libmlk-server_SOURCE_DIR}/malikania/server/client.hpp + ${libmlk-server_SOURCE_DIR}/malikania/server/net/auth_handler.hpp + ${libmlk-server_SOURCE_DIR}/malikania/server/server.hpp +) + +set( + SOURCES + ${libmlk-server_SOURCE_DIR}/malikania/server/client.cpp + ${libmlk-server_SOURCE_DIR}/malikania/server/net/auth_handler.cpp + ${libmlk-server_SOURCE_DIR}/malikania/server/server.cpp +) + +set( + LIBRARIES + OpenSSL::Crypto + OpenSSL::SSL + Threads::Threads + json + libmlk + libmlk-db +) + +if (CMAKE_SYSTEM_NAME MATCHES Windows) + list(APPEND LIBRARIES mswsock) +endif () + +malikania_define_library( + TARGET libmlk-server + SOURCES ${HEADERS} ${SOURCES} + LIBRARIES ${LIBRARIES} + PUBLIC_INCLUDES + ${libmlk-server_SOURCE_DIR} + PRIVATE_INCLUDES + ${libmlk-server_SOURCE_DIR}/malikania/server +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/client.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,185 @@ +/* + * client.cpp -- client connected to the server + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> +#include <iostream> + +#include "client.hpp" +#include "server.hpp" + +namespace mlk::server { + +void client::handle_read(std::error_code code, std::size_t xfer) +{ + // TODO: use fixed size stream + verify exceed. + if (code) + server_.handle_disconnect(shared_from_this()); + else { + std::string message( + boost::asio::buffers_begin(input_.data()), + boost::asio::buffers_begin(input_.data()) + xfer - 4 + ); + + // Remove early in case of errors. + input_.consume(xfer); + + try { + server_.handle_read(shared_from_this(), nlohmann::json::parse(message)); + } catch (const std::exception& ex) { + std::cerr << ex.what() << std::endl; + } + + do_read(); + } +} + +void client::handle_write(std::error_code code, std::size_t) +{ + if (code) { + server_.handle_disconnect(shared_from_this()); + } else { + output_.pop_front(); + + if (!output_.empty()) { + do_write(); + } else if (state_ == state::closing) { + server_.handle_disconnect(shared_from_this()); + } + } +} + +void client::do_read() +{ + const auto self = shared_from_this(); + + boost::asio::async_read_until(socket_, input_, "\r\n\r\n", [self] (auto code, auto xfer) { + self->handle_read(code, xfer); + }); +} + +void client::do_write() +{ + assert(!output_.empty()); + + const auto self = shared_from_this(); + + boost::asio::async_write(socket_, boost::asio::buffer(output_[0]), [self] (auto code, auto xfer) { + self->handle_write(code, xfer); + }); +} + +void client::handshake() +{ + const auto self = shared_from_this(); + + socket_.async_handshake(boost::asio::ssl::stream_base::server, [self] (auto code) { + if (code) { + std::cerr << "handshake failure: " << code << std::endl; + } else { + self->read(); + } + }); +} + +void client::read() +{ + do_read(); +} + +client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context) + : server_(server) + , socket_(service, context) +{ +} + +auto client::get_state() const noexcept -> state +{ + return state_; +} + +void client::set_state(state state) noexcept +{ + state_ = state; +} + +auto client::get_account() const noexcept -> const db::account& +{ + assert(state_ == state::ready); + + return *account_; +} + +auto client::get_account() noexcept -> db::account& +{ + assert(state_ == state::ready); + + return *account_; +} + +void client::set_account(db::account account) noexcept +{ + account_ = std::move(account); +} + +void client::send(nlohmann::json message) +{ + assert(message.is_object()); + + if (state_ == state::closing) { + return; + } + + const auto in_progress = !output_.empty(); + + output_.push_back(message.dump() + "\r\n\r\n"); + + if (!in_progress) { + do_write(); + } +} + +void client::ok(std::string cmd, nlohmann::json message) +{ + assert(message.is_null() || message.is_object()); + + if (!message.is_object()) { + message = nlohmann::json::object(); + } + + message["command"] = std::move(cmd); + message["status"] = true; + + send(std::move(message)); +} + +void client::error(std::string cmd, std::error_code code) +{ + send({ + { "command", std::move(cmd) }, + { "status", code.value() }, + { "error", code.message() } + }); +} + +void client::fatal(std::string cmd, std::error_code code) +{ + error(std::move(cmd), std::move(code)); + state_ = state::closing; +} + +} // !mlk::server
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/client.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,184 @@ +/* + * client.hpp -- client connected to the server + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SERVER_CLIENT_HPP +#define MALIKANIA_SERVER_CLIENT_HPP + +/** + * \file client.hpp + * \brief Client connected to the server. + */ + +#include <cstdint> +#include <deque> +#include <memory> +#include <optional> +#include <sstream> +#include <string> +#include <system_error> + +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +#include <json.hpp> + +#include "db/account.hpp" + +namespace mlk::server { + +class server; + +/** + * \brief Client connected to the server. + */ +class client : public std::enable_shared_from_this<client> { +public: + friend class server; + + /** + * \brief Describe client current state + */ + enum class state : std::uint8_t { + /** + * The client is authenticating. + */ + authenticating, + + /** + * The client is ready for I/O + */ + ready, + + /** + * The client is closing. + * + * No more messages are accepted for output, the pending queue is sent + * to the client and then disconnected. + */ + closing + }; + +private: + server& server_; + state state_{state::authenticating}; + + boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; + boost::asio::streambuf input_; + std::deque<std::string> output_; + std::optional<db::account> account_; + + void handle_read(std::error_code, std::size_t); + void handle_write(std::error_code, std::size_t); + + void do_read(); + void do_write(); + + void handshake(); + void read(); + +public: + /** + * Create the client in the associated server. + * + * \param server the server object + * \param service the main loop service + * \param context the ssl context + */ + client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context); + + /** + * Get the client state. + * + * \return the state + */ + auto get_state() const noexcept -> state; + + /** + * Set the client state. + * + * \param new_state the state + */ + void set_state(state state) noexcept; + + /** + * Get the underlying account database object. + * + * \pre get_state() == ready + * \return the account + */ + auto get_account() const noexcept -> const db::account&; + + /** + * Overloaded function. + * + * \pre get_state() == ready + * \return the account + */ + auto get_account() noexcept -> db::account&; + + /** + * Set the client account. + * + * \param account the account + */ + void set_account(db::account account) noexcept; + + /** + * Send a command and its arguments. + * + * \pre !cmd.empty() + * \param message the message to send + */ + void send(nlohmann::json message); + + /** + * Send successful command result. + * + * \pre !cmd.empty() + * \pre args.is_object() || args.is_object() + * \param cmd the command name + * \param args the extra data + */ + void ok(std::string cmd, nlohmann::json args = nullptr); + + /** + * Send a error command result. + * + * \pre !cmd.empty() + * \pre code + * \param cmd the command name + * \param code the error code + */ + void error(std::string cmd, std::error_code code); + + /** + * Send a fatal error result. + * + * The client state is changed to closing. + * + * \pre !cmd.empty() + * \pre code + * \param cmd the command name + * \param code the error code + */ + void fatal(std::string cmd, std::error_code code); +}; + +} // !mlk::server + +#endif // !MALIKANIA_SERVER_CLIENT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/hash.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,262 @@ +/* + * hash.hpp -- hash functions + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_SERVER_HASH_HPP +#define MLK_SERVER_HASH_HPP + +/** + * \file hash.hpp + * \brief Hash functions. + * \author David Demelier <markand@malikania.fr> + * \version 2.0.0-dev + */ + +/** + * \brief Define buffer size. + */ +#if !defined(HASH_BUFFER_SIZE) +# define HASH_BUFFER_SIZE 2048 +#endif + +#include <cassert> +#include <istream> +#include <iterator> +#include <sstream> +#include <string> +#include <string_view> + +#include <openssl/sha.h> +#include <openssl/md5.h> + +/** + * \brief Hash namespace. + */ +namespace mlk::server::hash { + +/** + * \cond HASH_HIDDEN_SYMBOLS + */ + +namespace detail { + +template <typename Context> +using init_func = int (*)(Context*); + +template <typename Context> +using update_func = int (*)(Context*, const void*, size_t); + +template <typename Context> +using final_func = int (*)(unsigned char*, Context*); + +template <typename Context, size_t Length, typename InputIt> +inline auto convert(InputIt it, + InputIt end, + init_func<Context> init, + update_func<Context> update, + final_func<Context> finalize) -> std::string +{ + unsigned char digest[Length] = { 0 }; + char hash[Length * 2 + 1]; + char buf[HASH_BUFFER_SIZE]; + + Context ctx; + init(&ctx); + + while (it != end) { + unsigned i; + + for (i = 0; it != end && i < HASH_BUFFER_SIZE; ++i) + buf[i] = *it++; + + update(&ctx, buf, i); + } + + finalize(digest, &ctx); + + for (unsigned long i = 0; i < Length; i++) + std::snprintf(&hash[i * 2], 2 + 1, "%02x", static_cast<unsigned>(digest[i])); + + return std::string(hash); +} + +} // !namespace + +/** + * \endcond + */ + +/** + * \brief The scheme to use. + */ +enum class scheme { + md5, //!< MD5 + sha1, //!< SHA-1 + sha256, //!< SHA-256 + sha512 //!< SHA-512 +}; + +/** + * Generic function. + * + * \param scheme the scheme to use + * \param it the first character + * \param end the last character + * \return the string + */ +template <typename InputIt> +inline auto to_string(scheme scheme, InputIt it, InputIt end) -> std::string +{ + assert(scheme >= scheme::md5 && scheme <= scheme::sha512); + + std::string result; + + switch (scheme) { + case scheme::md5: + result = detail::convert<MD5_CTX, MD5_DIGEST_LENGTH>(it, end, MD5_Init, MD5_Update, MD5_Final); + break; + case scheme::sha1: + result = detail::convert<SHA_CTX, SHA_DIGEST_LENGTH>(it, end, SHA1_Init, SHA1_Update, SHA1_Final);; + break; + case scheme::sha256: + result = detail::convert<SHA256_CTX, SHA256_DIGEST_LENGTH>(it, end, SHA256_Init, SHA256_Update, SHA256_Final); + break; + case scheme::sha512: + result = detail::convert<SHA512_CTX, SHA512_DIGEST_LENGTH>(it, end, SHA512_Init, SHA512_Update, SHA512_Final); + break; + default: + break; + } + + return result; +} + +/** + * Overload for std::istream. + * + * \param scheme the scheme to use + * \param input the input stream + * \return the string + */ +inline auto to_string(scheme scheme, std::istream& input) -> std::string +{ + return to_string(scheme, std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>()); +} + +/** + * Overload for std::string_view. + * + * \param scheme the scheme to use + * \param input the input string + * \return the string + */ +inline auto to_string(scheme scheme, std::string_view input) -> std::string +{ + return to_string(scheme, input.begin(), input.end()); +} + +/** + * Hash using MD5. + * + * \param input the input string + * \return the hashed string + */ +inline auto md5(std::string_view input) -> std::string +{ + return to_string(scheme::md5, input); +} + +/** + * Hash using MD5. + * + * \param input the input stream + * \return the hashed string + */ +inline auto md5(std::istream& input) -> std::string +{ + return to_string(scheme::md5, input); +} + +/** + * Hash using SHA1. + * + * \param input the input string + * \return the hashed string + */ +inline auto sha1(std::string_view input) -> std::string +{ + return to_string(scheme::sha1, input); +} + +/** + * Hash using SHA1. + * + * \param input the input stream + * \return the hashed string + */ +inline auto sha1(std::istream& input) -> std::string +{ + return to_string(scheme::sha1, input); +} + +/** + * Hash using SHA256. + * + * \param input the input string + * \return the hashed string + */ +inline auto sha256(std::string_view input) -> std::string +{ + return to_string(scheme::sha256, input); +} + +/** + * Hash using SHA256. + * + * \param input the input stream + * \return the hashed string + */ +inline auto sha256(std::istream& input) -> std::string +{ + return to_string(scheme::sha256, input); +} + +/** + * Hash using SHA512. + * + * \param input the input string + * \return the hashed string + */ +inline auto sha512(std::string_view input) -> std::string +{ + return to_string(scheme::sha512, input); +} + +/** + * Hash using SHA512. + * + * \param input the input stream + * \return the hashed string + */ +inline auto sha512(std::istream& input) -> std::string +{ + return to_string(scheme::sha512, input); +} + +} // !mlk::hash + +#endif // !MLK_SERVER_HASH_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/net/auth_handler.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,66 @@ +/* + * auth_handler.cpp -- handle "auth" network command + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/util.hpp> + +#include <malikania/error/auth_error.hpp> + +#include "db/account.hpp" + +#include "auth_handler.hpp" +#include "client.hpp" +#include "server.hpp" + +namespace mlk::server { + +namespace { + +auto is_connected(const server& server, const db::account& account) noexcept -> bool +{ + const auto& clients = server.get_clients(); + const auto it = std::find_if(clients.begin(), clients.end(), [&] (const auto& c) { + if (c->get_state() != client::state::ready) + return false; + + return c->get_account().get_login() == account.get_login(); + }); + + return it != clients.end(); +} + +} // !namespace + +void auth_handler::exec(server& server, client& clt, nlohmann::json object) noexcept +{ + auto ac = db::account::authenticate( + util::json::require_string(object, "/login"_json_pointer), + util::json::require_string(object, "/password"_json_pointer) + ); + + if (!ac) + clt.fatal("auth", auth_error::invalid_credentials); + else if (is_connected(server, *ac)) + clt.fatal("auth", auth_error::already_connected); + else { + clt.set_account(std::move(*ac)); + clt.set_state(client::state::ready); + clt.ok("auth"); + } +} + +} // !mlk::server
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/net/auth_handler.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,44 @@ +/* + * auth_handler.hpp -- handle "auth" network command + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SERVER_AUTH_HANDLER_HPP +#define MALIKANIA_SERVER_AUTH_HANDLER_HPP + +/** + * \file auth_handler.hpp + * \brief Handle "auth" network command. + */ + +#include "handler.hpp" + +namespace mlk::server { + +/** + * \brief Handle "auth" network command. + */ +class auth_handler : public handler { +public: + /** + * \copydoc handler::exec + */ + void exec(server& server, client& clt, nlohmann::json object) noexcept override; +}; + +} // !mlk::server + +#endif // !MALIKANIA_SERVER_AUTH_HANDLER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/net/handler.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,63 @@ +/* + * handler.hpp -- server side remote command + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SERVER_HANDLER_HPP +#define MALIKANIA_SERVER_HANDLER_HPP + +/** + * \file handler.hpp + * \brief Server side remote command. + */ + +#include <memory> + +#include <json.hpp> + +namespace mlk::server { + +class server; +class client; + +/** + * \brief Server side remote command. + */ +class handler { +public: + /** + * Default constructor. + */ + handler() noexcept = default; + + /** + * Virtual destructor defaulted. + */ + virtual ~handler() noexcept = default; + + /** + * Execute the function from the given client. + * + * \param server the global object server + * \param client the client + * \param message the network message + */ + virtual void exec(server& server, client& client, nlohmann::json message) noexcept = 0; +}; + +} // !mlk::server + +#endif // !MALIKANIA_SERVER_HANDLER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/server.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,124 @@ +/* + * server.cpp -- malikania basic server + * + * Copyright (c) 2016-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/util.hpp> + +#include "client.hpp" +#include "server.hpp" + +#include "net/auth_handler.hpp" + +namespace mlk::server { + +namespace { + +auto endpoint(const settings& params) -> boost::asio::ip::tcp::endpoint +{ + // TODO: add more settings there. + return boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), params.port); +} + +} // !namespace + +void server::load() +{ + handle("auth", std::make_unique<auth_handler>()); +} + +void server::start() +{ + auto clt = std::make_shared<client>(*this, service_, context_); + + acceptor_.async_accept(clt->socket_.lowest_layer(), [this, clt] (auto code) { + handle_accept(std::move(clt), code); + }); +} + +server::server(boost::asio::io_service& service, const settings& settings) + : service_(service) + , acceptor_(service, endpoint(settings)) + , context_(boost::asio::ssl::context::sslv23) +{ + context_.use_certificate_chain_file(settings.certificate); + context_.use_private_key_file(settings.key, boost::asio::ssl::context::pem); + + load(); + start(); +} + +auto server::get_clients() const noexcept -> const clients& +{ + return clients_; +} + +auto server::get_clients() noexcept -> clients& +{ + return clients_; +} + +void server::handle(std::string name, std::unique_ptr<handler> handler) +{ + assert(!name.empty()); + assert(handler); + + commands_.emplace(std::move(name), std::move(handler)); +} + +void server::handle_disconnect(std::shared_ptr<client> clt) +{ + clients_.erase(std::move(clt)); +} + +void server::handle_read(std::shared_ptr<client> clt, nlohmann::json message) +{ + assert(message.is_object()); + + const auto cmd = message.find("command"); + + if (cmd == message.end() || !cmd->is_string()) { + // TODO: log error. + return; + } + + const auto it = commands_.find(*cmd); + + if (it == commands_.end()) { + // TODO: log error. + return; + } + + try { + it->second->exec(*this, *clt, std::move(message)); + } catch (const std::exception&) { + // TODO: log error. + } +} + +void server::handle_accept(std::shared_ptr<client> clt, std::error_code code) +{ + if (code) { + // TODO: log error. + } else { + clt->handshake(); + clients_.insert(std::move(clt)); + } + + start(); +} + +} // !mlk::server
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-server/malikania/server/server.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,139 @@ +/* + * server.hpp -- malikania basic server + * + * Copyright (c) 2016-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SERVER_SERVER_HPP +#define MALIKANIA_SERVER_SERVER_HPP + +/** + * \file server.hpp + * \brief Malikania basic server. + */ + +#include <cstdint> +#include <memory> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <system_error> + +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +#include <json.hpp> + +#include "net/handler.hpp" + +namespace mlk::server { + +class client; +class database; + +/** + * \brief Server parameters + */ +struct settings { + std::uint16_t port{3320}; + std::string certificate; + std::string key; +}; + +/** + * \file server.hpp + * \brief Malikania basic server. + */ +class server { +public: + using clients = std::unordered_set<std::shared_ptr<client>>; + using commands = std::unordered_map<std::string, std::unique_ptr<handler>>; + +private: + boost::asio::io_service& service_; + boost::asio::ip::tcp::acceptor acceptor_; + boost::asio::ssl::context context_; + + clients clients_; + commands commands_; + + void load(); + void start(); + +public: + /** + * Construct a server object. + * + * \param ctx the IO context + * \param settings the settings + */ + server(boost::asio::io_service& service, const settings& settings); + + /** + * Get the set of connected clients. + * + * \return the clients + */ + auto get_clients() const noexcept -> const clients&; + + /** + * Overloaded function. + * + * \return the clients + */ + auto get_clients() noexcept -> clients&; + + /** + * Add network handler. + * + * If a handler is already present, it will be replaced with the new one. + * + * \pre handler != nullptr + * \pre !name.empty() + * \param handler the handler + */ + void handle(std::string name, std::unique_ptr<handler> handler); + + /** + * Handle client disconnection. + * + * \param client the client + */ + virtual void handle_disconnect(std::shared_ptr<client> client); + + /** + * Asynchronous function called once a message has been completely and + * successfully received from the client. + * + * The default implementation searches for a handler defined for this + * message. + * + * \param client the client + * \param message the message received + */ + virtual void handle_read(std::shared_ptr<client>, nlohmann::json message); + + /** + * Handle accept of a new client. + * + * \param client the newly received client + * \param code the error code if any + */ + virtual void handle_accept(std::shared_ptr<client> client, std::error_code code); +}; + +} // !mlk + +#endif // !MALIKANIA_SERVER_SERVER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,64 @@ +# +# CMakeLists.txt -- CMake build system for malikania +# +# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +project(libmlk) + +find_package(Boost REQUIRED filesystem system) +find_package(OpenSSL REQUIRED) + +set( + HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/error/auth_error.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/error/error.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/game.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/line.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/loader.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/locator.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/point.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/rectangle.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/size.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/socket.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/tileset.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/unicode.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/util.hpp +) + +set( + SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/error/auth_error.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/locator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/socket.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/unicode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/util.cpp +) + +malikania_define_library( + PROJECT libmlk + TARGET libmlk + SOURCES ${HEADERS} ${SOURCES} + PUBLIC_INCLUDES + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + LIBRARIES + Boost::boost + Boost::filesystem + Boost::system + OpenSSL::Crypto + OpenSSL::SSL + json +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/error/auth_error.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,40 @@ +/* + * auth_error.hpp -- auth command error + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "auth_error.hpp" + +namespace mlk { + +auto auth_error::error_category() -> std::string +{ + return "auth"; +} + +auto auth_error::error_message(error code) -> std::string +{ + switch (code) { + case invalid_credentials: + return "invalid credentials"; + case already_connected: + return "already connected"; + default: + return "no error"; + } +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/error/auth_error.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,73 @@ +/* + * auth_error.hpp -- auth command error + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_AUTH_ERROR_HPP +#define MALIKANIA_AUTH_ERROR_HPP + +/** + * \file auth_error.hpp + * \brief Auth command error. + */ + +#include "error.hpp" + +namespace mlk { + +/** + * \brief Auth command error. + */ +struct auth_error { + /** + * \brief Error description + */ + enum error { + /** + * \brief No error. + */ + no_error = 0, + + /** + * \brief Invalid password or login. + */ + invalid_credentials, + + /** + * \brief User is already connected. + */ + already_connected + }; + + static auto error_category() -> std::string; + + /** + * Convert the code to a human message. + * + * \param code the code + */ + static auto error_message(error code) -> std::string; +}; + +} // !mlk + +MALIKANIA_ERROR_CODE( + mlk::auth_error::error, + mlk::auth_error::error_category, + mlk::auth_error::error_message +) + +#endif // !MALIKANIA_AUTH_ERROR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/error/error.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,99 @@ +/* + * error.hpp -- error code creation + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_ERROR_HPP +#define MALIKANIA_ERROR_HPP + +/** + * \file error.hpp + * \brief Error code creation. + */ + +#include <string> +#include <system_error> +#include <type_traits> + +/** + * Generate a custom std::error_code with the given type. The macro must be + * called outside mlk namespace. + * + * See the following example. + * + * ```cpp + * namespace mlk { + * + * class foo { + * public: + * enum class error { + * no_error = 0, + * error_kind_foo, + * error_kind_bar + * }; + * + * static auto error_category() -> std::string + * { + * return "sometext"; + * } + * + * static auto error_message(error code) -> std::string + * { + * // convert code to a string. + * } + * }; + * + * } // !mlk + * + * MALIKANIA_ERROR_CODE( + * my_error::error, + * my_error::error_category, + * my_error::error_message + * ) + * ``` + */ +#define MALIKANIA_ERROR_CODE(Enum, Category, Message) \ +namespace std { \ + \ +template <> \ +struct is_error_code_enum<Enum> : public std::true_type { \ +}; \ + \ +} \ + \ +namespace mlk { \ + \ +inline auto make_error_code(Enum code) noexcept -> std::error_code \ +{ \ + static const class : public std::error_category { \ + public: \ + auto name() const noexcept -> const char* override \ + { \ + return Category().c_str(); \ + } \ + \ + auto message(int e) const -> std::string override \ + { \ + return Message(static_cast<Enum>(e)); \ + } \ + } category; \ + \ + return { static_cast<int>(code), category }; \ +} \ + \ +} + +#endif // !MALIKANIA_ERROR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/game.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,44 @@ +/* + * game.hpp -- basic game class + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_GAME_HPP +#define MALIKANIA_GAME_HPP + +/** + * \file game.hpp + * \brief Game description. + */ + +#include <string> + +namespace mlk { + +/** + * \brief Basic game description. + */ +struct game { + std::string name; + std::string version; + std::string requires; + std::string license; + std::string author; +}; + +} // !mlk + +#endif // !MALIKANIA_GAME_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/line.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,68 @@ +/* + * line.hpp -- line description + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_LINE_HPP +#define MALIKANIA_LINE_HPP + +/** + * \file line.hpp + * \brief line description. + */ + +namespace mlk { + +/** + * \brief line description. + * + * A line has an origin (x, y) and a destination (x, y). + */ +struct line { + int x1{0}; + int y1{0}; + int x2{0}; + int y2{0}; +}; + +/** + * Compare equality. + * + * \param l1 the first line + * \param l2 the second line + * \return true if they equal + */ +inline auto operator==(const line& l1, const line& l2) noexcept -> bool +{ + return l1.x1 == l2.x1 && l1.x2 == l2.x2 && + l1.y1 == l2.y1 && l1.y2 == l2.y2; +} + +/** + * Compare equality. + * + * \param l1 the first line + * \param l2 the second line + * \return false if they equal + */ +inline auto operator!=(const line& l1, const line& l2) noexcept -> bool +{ + return !(l1 == l2); +} + +} // !mlk + +#endif // !MALIKANIA_LINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/loader.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,108 @@ +/* + * loader.cpp -- load shared resources files + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "game.hpp" +#include "loader.hpp" +#include "locator.hpp" +#include "tileset.hpp" +#include "util.hpp" + +namespace mlk { + +namespace { + +auto load_tileset_tile_properties(const nlohmann::json& json) -> tileset::properties_map +{ + auto it = json.find("properties"); + + if (it == json.end()) + return {}; + + tileset::properties_map props; + + for (auto pair = it->begin(); pair != it->end(); ++pair) { + // TODO: maxi convert + if (!pair->is_string()) + continue; + + props.emplace(pair.key(), pair->get<std::string>()); + } + + return props; +} + +auto load_tileset_tiles_properties(const nlohmann::json& json) -> tileset::tile_properties_map +{ + auto tiles = json.find("tiles"); + + if (tiles == json.end()) + return {}; + + tileset::tile_properties_map props; + + for (auto it = tiles->begin(); it != tiles->end(); ++it) + props.emplace(std::stoi(it.key()), load_tileset_tile_properties(*it)); + + return props; +} + +} // !namespace + +loader::loader(mlk::locator& locator) + : locator_(locator) +{ +} + +auto loader::get_locator() noexcept -> locator& +{ + return locator_; +} + +auto loader::load_game() const -> game +{ + auto value = nlohmann::json::parse(locator_.read("game.json")); + + if (!value.is_object()) + throw std::runtime_error("game.json: not a JSON object"); + + return game{ + util::json::require_string(value, "/name"_json_pointer), + util::json::require_string(value, "/version"_json_pointer), + util::json::require_string(value, "/requires"_json_pointer), + value.count("license") > 0 ? value["license"] : "", + value.count("author") > 0 ? value["author"] : "" + }; +} + +auto loader::load_tileset(std::string_view id) const -> tileset +{ + auto value = nlohmann::json::parse(locator_.read(id)); + + if (!value.is_object()) + throw std::runtime_error("not a valid tileset"); + + tileset tileset; + + tileset.image = util::json::require_string(value, "/image"_json_pointer); + tileset.cell = util::json::require_size(value, "/cell"_json_pointer); + tileset.tile_properties = load_tileset_tiles_properties(value); + + return tileset; +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/loader.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,83 @@ +/* + * loader.hpp -- load shared resources files + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_LOADER_HPP +#define MALIKANIA_LOADER_HPP + +#include <string> + +namespace mlk { + +struct game; +struct tileset; + +class locator; + +/** + * \brief Open resources files using a locator. + * + * This class is used to load resources files that are common to the server and + * the client. + * + * \see client_loader + */ +class loader { +private: + locator& locator_; + +public: + /** + * Construct the resources loader. + * + * \param locator the locator + */ + loader(locator& locator); + + /** + * Virtual destructor defaulted. + */ + virtual ~loader() noexcept = default; + + /** + * Get the underlying locator. + * + * \return the locator + */ + auto get_locator() noexcept -> locator&; + + /** + * Load a game. + * + * \return the game + * \throw std::runtime_error on errors + */ + virtual auto load_game() const -> game; + + /** + * Load a tileset. + * + * \param id the tileset id + * \return a tileset ready to use + * \throw std::runtime_error on errors + */ + virtual auto load_tileset(std::string_view id) const -> tileset; +}; + +} // !mlk + +#endif // !MALIKANIA_LOADER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/locator.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,69 @@ +/* + * locator.cpp -- file and stream loader + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cerrno> +#include <cstring> +#include <fstream> +#include <iterator> +#include <sstream> +#include <stdexcept> + +#include "locator.hpp" + +namespace mlk { + +auto directory_locator::make_path(std::string_view id) -> std::string +{ + std::ostringstream oss; + + oss << path_; + oss << "/"; + oss << id; + + return oss.str(); +} + +directory_locator::directory_locator(std::string path) noexcept + : path_(std::move(path)) +{ +} + +auto directory_locator::read(std::string_view id) -> std::string +{ + std::ifstream in(make_path(id), std::ifstream::in | std::ifstream::binary); + + if (!in) + throw std::runtime_error(std::strerror(errno)); + + return std::string( + std::istreambuf_iterator<char>(in.rdbuf()), + std::istreambuf_iterator<char>() + ); +} + +auto directory_locator::open(std::string_view id) -> std::unique_ptr<std::istream> +{ + auto ptr = std::make_unique<std::ifstream>(make_path(id)); + + if (!(*ptr)) + throw std::runtime_error(std::strerror(errno)); + + return std::move(ptr); +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/locator.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,88 @@ +/* + * locator.hpp -- file and stream loader + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_LOCATOR_HPP +#define MALIKANIA_LOCATOR_HPP + +#include <istream> +#include <memory> +#include <string> +#include <string_view> + +namespace mlk { + +/** + * \brief Abstract assets locator. + */ +class locator { +public: + /** + * Default destructor. + */ + virtual ~locator() = default; + + /** + * Read a whole resource as a string. + * + * \param id the resource id + * \return the string + * \throw std::runtime_error on any errors + */ + virtual auto read(std::string_view id) -> std::string = 0; + + /** + * Open a resource as a stream. + * + * \param id the resource id + * \return the stream + * \throw std::runtime_error on any errors + */ + virtual auto open(std::string_view id) -> std::unique_ptr<std::istream> = 0; +}; + +/** + * \brief Load a game from a directory. + */ +class directory_locator : public locator { +private: + std::string path_; + + auto make_path(std::string_view) -> std::string; + +public: + /** + * Load the game from the directory. + * + * \param path the base directory + */ + directory_locator(std::string path) noexcept; + + /** + * \copydoc locator::read + */ + auto read(std::string_view id) -> std::string override; + + /** + * \copydoc locator::open + */ + auto open(std::string_view id) -> std::unique_ptr<std::istream> override; +}; + +} // !mlk + +#endif // !MALIKANIA_LOCATOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/point.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,63 @@ +/* + * point.hpp -- point description + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_POINT_HPP +#define MALIKANIA_POINT_HPP + +/** + * \file point.hpp + * \brief point description. + */ + +namespace mlk { + +/** + * \brief point coordinate. + */ +struct point { + int x{0}; + int y{0}; +}; + +/** + * Compare equality. + * + * \param p1 the first point + * \param p2 the second point + * \return true if they equal + */ +inline auto operator==(const point& p1, const point& p2) noexcept -> bool +{ + return p1.x == p2.x && p1.y == p2.y; +} + +/** + * Compare equality. + * + * \param p1 the first point + * \param p2 the second point + * \return false if they equal + */ +inline auto operator!=(const point& p1, const point& p2) noexcept -> bool +{ + return !(p1 == p2); +} + +} // !mlk + +#endif // !MALIKANIA_POINT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/rectangle.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,79 @@ +/* + * rectangle.hpp -- rectangle description + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_RECTANGLE_HPP +#define MALIKANIA_RECTANGLE_HPP + +/** + * \file rectangle.hpp + * \brief rectangle description. + */ + +namespace mlk { + +/** + * \brief rectangle description. + * + * A rectangle has coordinates (x, y) and dimensions (width, height). + * + * They are commonly used for clipping images into the window. + */ +struct rectangle { + int x{0}; //!< x coordinate + int y{0}; //!< y coordinate + unsigned width{0}; //!< width + unsigned height{0}; //!< height + + /** + * Check if the rectangle has null dimensions. + * + * \return true if weight and height are 0 + */ + inline auto is_null() const noexcept -> bool + { + return width == 0 && height == 0; + } +}; + +/** + * Compare equality. + * + * \param r1 the first rectangle + * \param r2 the second rectangle + * \return true if they equal + */ +inline auto operator==(const rectangle& r1, const rectangle& r2) noexcept -> bool +{ + return r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height == r2.height; +} + +/** + * Compare equality. + * + * \param r1 the first rectangle + * \param r2 the second rectangle + * \return false if they equal + */ +inline auto operator!=(const rectangle& r1, const rectangle& r2) noexcept -> bool +{ + return !(r1 == r2); +} + +} // !mlk + +#endif // !MALIKANIA_RECTANGLE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/size.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,91 @@ +/* + * size.hpp -- size description + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SIZE_HPP +#define MALIKANIA_SIZE_HPP + +#include <ostream> + +namespace mlk { + +/** + * \brief size description. + */ +struct size { + /** + * \brief Width. + */ + unsigned width{0}; + + /** + * \brief Height. + */ + unsigned height{0}; + + /** + * Check if the size is 0, 0. + * + * \return true if height and width are 0 + */ + inline auto is_null() const noexcept -> bool + { + return height == 0 && width == 0; + } +}; + +/** + * Compare equality. + * + * \param s1 the first size + * \param s2 the second size + * \return true if they equal + */ +inline auto operator==(const size& s1, const size& s2) noexcept -> bool +{ + return s1.width == s2.width && s1.height == s2.height; +} + +/** + * Compare equality. + * + * \param s1 the first size + * \param s2 the second size + * \return false if they equal + */ +inline auto operator!=(const size& s1, const size& s2) noexcept -> bool +{ + return !(s1 == s2); +} + +/** + * Prints the size object. + * + * \param out the output + * \param size the size object + * \return out + */ +inline auto operator<<(std::ostream& out, const size& size) -> std::ostream& +{ + out << "{" << size.width << ", " << size.height << "}"; + + return out; +} + +} // !mlk + +#endif // !MALIKANIA_SIZE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/socket.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,154 @@ +/* + * socket.cpp -- SSL socket using JSON messages + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include "socket.hpp" + +namespace mlk { + +void socket::do_recv(recv_handler handler) +{ + boost::asio::async_read_until(socket_, rbuffer_, "\r\n\r\n", [this, handler] (auto code, auto xfer) { + if (code) + handler(std::move(code), nullptr); + else if (xfer == 0U) + handler(make_error_code(boost::system::errc::network_down), nullptr); + else { + std::string str( + boost::asio::buffers_begin(rbuffer_.data()), + boost::asio::buffers_begin(rbuffer_.data()) + xfer - 4 + ); + + // Remove early in case of errors. + rbuffer_.consume(xfer); + + // TODO: catch nlohmann::json::parse_error when 3.0.0 is released. + nlohmann::json message; + + try { + message = nlohmann::json::parse(str); + } catch (...) {} + + if (!message.is_object()) + handler(make_error_code(boost::system::errc::invalid_argument), nullptr); + else + handler(code, std::move(message)); + } + }); +} + +void socket::do_send(const std::string& str, send_handler handler) +{ + boost::asio::async_write(socket_, boost::asio::buffer(str), [handler] (auto code, auto xfer) { + if (xfer == 0U) + handler(make_error_code(boost::system::errc::network_down)); + else + handler(code); + }); +} + +socket::socket(boost::asio::io_service& service, + boost::asio::ssl::context& ctx) + : socket_(service, ctx) +{ +} + +auto socket::get_socket() const noexcept -> const socket_t& +{ + return socket_; +} + +auto socket::get_socket() noexcept -> socket_t& +{ + return socket_; +} + +auto socket::is_receiving() const noexcept -> bool +{ + return !rqueue_.empty(); +} + +auto socket::is_sending() const noexcept -> bool +{ + return !squeue_.empty(); +} + +auto socket::is_active() const noexcept -> bool +{ + return is_receiving() || is_sending(); +} + +void socket::rflush() +{ + if (rqueue_.empty()) + return; + + do_recv([this] (auto code, auto json) { + auto handler = rqueue_.front(); + + rqueue_.pop_front(); + handler(code, std::move(json)); + + if (!code) + rflush(); + }); +} + +void socket::sflush() +{ + if (squeue_.empty()) + return; + + do_send(squeue_.front().first, [this] (auto code) { + auto handler = squeue_.front().second; + + squeue_.pop_front(); + + if (handler) + handler(code); + if (!code) + sflush(); + }); +} + +void socket::recv(recv_handler handler) +{ + assert(handler); + + auto in_progress = !rqueue_.empty(); + + rqueue_.push_back(std::move(handler)); + + if (!in_progress) + rflush(); +} + +void socket::send(nlohmann::json json, send_handler handler) +{ + assert(json.is_object()); + + auto in_progress = !squeue_.empty(); + + squeue_.emplace_back(json.dump(0) + "\r\n\r\n", std::move(handler)); + + if (!in_progress) + sflush(); +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/socket.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,148 @@ +/* + * socket.hpp -- SSL socket using JSON messages + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_COMMON_SOCKET_HPP +#define MALIKANIA_COMMON_SOCKET_HPP + +/** + * \file socket.hpp + * \brief SSL socket using JSON messages + */ + +#include "sysconfig.hpp" + +#include <deque> +#include <functional> +#include <string> +#include <system_error> +#include <utility> + +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +#include <json.hpp> + +namespace mlk { + +/** + * \brief SSL socket using JSON messages + * + * This class can be used to perform I/O over a networking socket, it is + * implemented as asynchronous operations over Boost.Asio. + * + * All recv/send operations are placed in a queue and performed when possible. + */ +class socket { +public: + /** + * Read handler. + * + * Call this function when a receive operation has finished on success or + * failure. + */ + using recv_handler = std::function<void (std::error_code, nlohmann::json)>; + + /** + * Send handler. + * + * Call this function when a send operation has finished on success or failure. + */ + using send_handler = std::function<void (std::error_code)>; + +private: + using socket_t = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>; + using rbuffer_t = boost::asio::streambuf; + using rqueue_t = std::deque<recv_handler>; + using squeue_t = std::deque<std::pair<std::string, send_handler>>; + + socket_t socket_; + rbuffer_t rbuffer_; + rqueue_t rqueue_; + squeue_t squeue_; + + void rflush(); + void sflush(); + void do_recv(recv_handler); + void do_send(const std::string&, send_handler); + +public: + /** + * Construct the socket. + * + * \param service the IO service + * \param ctx the SSL context + */ + socket(boost::asio::io_service& service, + boost::asio::ssl::context& ctx); + + /** + * Get the underlying socket. + * + * \return the socket + */ + auto get_socket() const noexcept -> const socket_t&; + + /** + * Overloaded function. + * + * \return the socket + */ + auto get_socket() noexcept -> socket_t&; + + /** + * Tells if receive operations are pending. + * + * \return true if receiving is in progress + */ + auto is_receiving() const noexcept -> bool; + + /** + * Tells if send operations are pending. + * + * \return true if sending is in progress + */ + auto is_sending() const noexcept -> bool; + + /** + * Tells if there are any I/O pending. + * + * \return true if sending is in progress + */ + auto is_active() const noexcept -> bool; + + /** + * Request a receive operation. + * + * \pre handler != nullptr + * \param handler the handler + */ + void recv(recv_handler); + + /** + * Request a send operation. + * + * \pre json.is_object() + * \param json the json message + * \param handler the optional handler + */ + void send(nlohmann::json json, send_handler = nullptr); +}; + +} // !mlk + +#endif // MALIKANIA_COMMON_SOCKET_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/tileset.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,58 @@ +/* + * tileset.hpp -- map tileset definition + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_COMMON_TILESET_HPP +#define MALIKANIA_COMMON_TILESET_HPP + +/** + * \file tileset.hpp + * \brief Map tileset definition. + */ + +#include <boost/variant.hpp> + +#include <string> +#include <unordered_map> + +#include "size.hpp" + +namespace mlk { + +/** + * \brief Map tileset definition. + */ +struct tileset { + /** + * Map of general properties. + */ + using properties_map = std::unordered_map<std::string, std::string>; + + /** + * Per tile properties. + */ + using tile_properties_map = std::unordered_map<int, properties_map>; + + std::string image; + size cell; + properties_map properties; + tile_properties_map tile_properties; +}; + +} // !mlk + +#endif // !MALIKANIA_COMMON_TILESET_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/unicode.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,4838 @@ +/* + * unicode.cpp -- UTF-8 to UTF-32 conversions and various operations + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "unicode.hpp" + +/* + * The following code has been generated from Go mkrunetype adapted to our + * needs. + */ + +namespace mlk::unicode { + +#define nelem(x) (sizeof (x) / sizeof ((x)[0])) + +namespace { + +auto search(char32_t c, const char32_t* t, int n, int ne) noexcept -> const char32_t* +{ + const char32_t* p; + int m; + + while (n > 1) { + m = n >> 1; + p = t + m * ne; + + if (c >= p[0]) { + t = p; + n = n - m; + } else + n = m; + } + + if (n && c >= t[0]) + return t; + + return nullptr; +} + +} // !namespace + +namespace { + +const char32_t isspacer[] = { + 0x0009, 0x000d, + 0x0020, 0x0020, + 0x0085, 0x0085, + 0x00a0, 0x00a0, + 0x1680, 0x1680, + 0x2000, 0x200a, + 0x2028, 0x2029, + 0x202f, 0x202f, + 0x205f, 0x205f, + 0x3000, 0x3000, + 0xfeff, 0xfeff, +}; + +} // !namespace + +auto isspace(char32_t c) noexcept -> bool +{ + const char32_t* p; + + p = search(c, isspacer, nelem (isspacer) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + return false; +} + +namespace { + +const char32_t isdigitr[] = { + 0x0030, 0x0039, + 0x0660, 0x0669, + 0x06f0, 0x06f9, + 0x07c0, 0x07c9, + 0x0966, 0x096f, + 0x09e6, 0x09ef, + 0x0a66, 0x0a6f, + 0x0ae6, 0x0aef, + 0x0b66, 0x0b6f, + 0x0be6, 0x0bef, + 0x0c66, 0x0c6f, + 0x0ce6, 0x0cef, + 0x0d66, 0x0d6f, + 0x0de6, 0x0def, + 0x0e50, 0x0e59, + 0x0ed0, 0x0ed9, + 0x0f20, 0x0f29, + 0x1040, 0x1049, + 0x1090, 0x1099, + 0x17e0, 0x17e9, + 0x1810, 0x1819, + 0x1946, 0x194f, + 0x19d0, 0x19d9, + 0x1a80, 0x1a89, + 0x1a90, 0x1a99, + 0x1b50, 0x1b59, + 0x1bb0, 0x1bb9, + 0x1c40, 0x1c49, + 0x1c50, 0x1c59, + 0xa620, 0xa629, + 0xa8d0, 0xa8d9, + 0xa900, 0xa909, + 0xa9d0, 0xa9d9, + 0xa9f0, 0xa9f9, + 0xaa50, 0xaa59, + 0xabf0, 0xabf9, + 0xff10, 0xff19, + 0x104a0, 0x104a9, + 0x11066, 0x1106f, + 0x110f0, 0x110f9, + 0x11136, 0x1113f, + 0x111d0, 0x111d9, + 0x112f0, 0x112f9, + 0x114d0, 0x114d9, + 0x11650, 0x11659, + 0x116c0, 0x116c9, + 0x118e0, 0x118e9, + 0x16a60, 0x16a69, + 0x16b50, 0x16b59, + 0x1d7ce, 0x1d7ff, +}; + +} // !namespace + +auto isdigit(char32_t c) noexcept -> bool +{ + const char32_t* p; + + p = search(c, isdigitr, nelem (isdigitr) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + return false; +} + +namespace { + +const char32_t isalphar[] = { + 0x0041, 0x005a, + 0x0061, 0x007a, + 0x00c0, 0x00d6, + 0x00d8, 0x00f6, + 0x00f8, 0x02c1, + 0x02c6, 0x02d1, + 0x02e0, 0x02e4, + 0x0370, 0x0374, + 0x0376, 0x0377, + 0x037a, 0x037d, + 0x0388, 0x038a, + 0x038e, 0x03a1, + 0x03a3, 0x03f5, + 0x03f7, 0x0481, + 0x048a, 0x052f, + 0x0531, 0x0556, + 0x0561, 0x0587, + 0x05d0, 0x05ea, + 0x05f0, 0x05f2, + 0x0620, 0x064a, + 0x066e, 0x066f, + 0x0671, 0x06d3, + 0x06e5, 0x06e6, + 0x06ee, 0x06ef, + 0x06fa, 0x06fc, + 0x0712, 0x072f, + 0x074d, 0x07a5, + 0x07ca, 0x07ea, + 0x07f4, 0x07f5, + 0x0800, 0x0815, + 0x0840, 0x0858, + 0x08a0, 0x08b2, + 0x0904, 0x0939, + 0x0958, 0x0961, + 0x0971, 0x0980, + 0x0985, 0x098c, + 0x098f, 0x0990, + 0x0993, 0x09a8, + 0x09aa, 0x09b0, + 0x09b6, 0x09b9, + 0x09dc, 0x09dd, + 0x09df, 0x09e1, + 0x09f0, 0x09f1, + 0x0a05, 0x0a0a, + 0x0a0f, 0x0a10, + 0x0a13, 0x0a28, + 0x0a2a, 0x0a30, + 0x0a32, 0x0a33, + 0x0a35, 0x0a36, + 0x0a38, 0x0a39, + 0x0a59, 0x0a5c, + 0x0a72, 0x0a74, + 0x0a85, 0x0a8d, + 0x0a8f, 0x0a91, + 0x0a93, 0x0aa8, + 0x0aaa, 0x0ab0, + 0x0ab2, 0x0ab3, + 0x0ab5, 0x0ab9, + 0x0ae0, 0x0ae1, + 0x0b05, 0x0b0c, + 0x0b0f, 0x0b10, + 0x0b13, 0x0b28, + 0x0b2a, 0x0b30, + 0x0b32, 0x0b33, + 0x0b35, 0x0b39, + 0x0b5c, 0x0b5d, + 0x0b5f, 0x0b61, + 0x0b85, 0x0b8a, + 0x0b8e, 0x0b90, + 0x0b92, 0x0b95, + 0x0b99, 0x0b9a, + 0x0b9e, 0x0b9f, + 0x0ba3, 0x0ba4, + 0x0ba8, 0x0baa, + 0x0bae, 0x0bb9, + 0x0c05, 0x0c0c, + 0x0c0e, 0x0c10, + 0x0c12, 0x0c28, + 0x0c2a, 0x0c39, + 0x0c58, 0x0c59, + 0x0c60, 0x0c61, + 0x0c85, 0x0c8c, + 0x0c8e, 0x0c90, + 0x0c92, 0x0ca8, + 0x0caa, 0x0cb3, + 0x0cb5, 0x0cb9, + 0x0ce0, 0x0ce1, + 0x0cf1, 0x0cf2, + 0x0d05, 0x0d0c, + 0x0d0e, 0x0d10, + 0x0d12, 0x0d3a, + 0x0d60, 0x0d61, + 0x0d7a, 0x0d7f, + 0x0d85, 0x0d96, + 0x0d9a, 0x0db1, + 0x0db3, 0x0dbb, + 0x0dc0, 0x0dc6, + 0x0e01, 0x0e30, + 0x0e32, 0x0e33, + 0x0e40, 0x0e46, + 0x0e81, 0x0e82, + 0x0e87, 0x0e88, + 0x0e94, 0x0e97, + 0x0e99, 0x0e9f, + 0x0ea1, 0x0ea3, + 0x0eaa, 0x0eab, + 0x0ead, 0x0eb0, + 0x0eb2, 0x0eb3, + 0x0ec0, 0x0ec4, + 0x0edc, 0x0edf, + 0x0f40, 0x0f47, + 0x0f49, 0x0f6c, + 0x0f88, 0x0f8c, + 0x1000, 0x102a, + 0x1050, 0x1055, + 0x105a, 0x105d, + 0x1065, 0x1066, + 0x106e, 0x1070, + 0x1075, 0x1081, + 0x10a0, 0x10c5, + 0x10d0, 0x10fa, + 0x10fc, 0x1248, + 0x124a, 0x124d, + 0x1250, 0x1256, + 0x125a, 0x125d, + 0x1260, 0x1288, + 0x128a, 0x128d, + 0x1290, 0x12b0, + 0x12b2, 0x12b5, + 0x12b8, 0x12be, + 0x12c2, 0x12c5, + 0x12c8, 0x12d6, + 0x12d8, 0x1310, + 0x1312, 0x1315, + 0x1318, 0x135a, + 0x1380, 0x138f, + 0x13a0, 0x13f4, + 0x1401, 0x166c, + 0x166f, 0x167f, + 0x1681, 0x169a, + 0x16a0, 0x16ea, + 0x16f1, 0x16f8, + 0x1700, 0x170c, + 0x170e, 0x1711, + 0x1720, 0x1731, + 0x1740, 0x1751, + 0x1760, 0x176c, + 0x176e, 0x1770, + 0x1780, 0x17b3, + 0x1820, 0x1877, + 0x1880, 0x18a8, + 0x18b0, 0x18f5, + 0x1900, 0x191e, + 0x1950, 0x196d, + 0x1970, 0x1974, + 0x1980, 0x19ab, + 0x19c1, 0x19c7, + 0x1a00, 0x1a16, + 0x1a20, 0x1a54, + 0x1b05, 0x1b33, + 0x1b45, 0x1b4b, + 0x1b83, 0x1ba0, + 0x1bae, 0x1baf, + 0x1bba, 0x1be5, + 0x1c00, 0x1c23, + 0x1c4d, 0x1c4f, + 0x1c5a, 0x1c7d, + 0x1ce9, 0x1cec, + 0x1cee, 0x1cf1, + 0x1cf5, 0x1cf6, + 0x1d00, 0x1dbf, + 0x1e00, 0x1f15, + 0x1f18, 0x1f1d, + 0x1f20, 0x1f45, + 0x1f48, 0x1f4d, + 0x1f50, 0x1f57, + 0x1f5f, 0x1f7d, + 0x1f80, 0x1fb4, + 0x1fb6, 0x1fbc, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fcc, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fdb, + 0x1fe0, 0x1fec, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ffc, + 0x2090, 0x209c, + 0x210a, 0x2113, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x212f, 0x2139, + 0x213c, 0x213f, + 0x2145, 0x2149, + 0x2183, 0x2184, + 0x2c00, 0x2c2e, + 0x2c30, 0x2c5e, + 0x2c60, 0x2ce4, + 0x2ceb, 0x2cee, + 0x2cf2, 0x2cf3, + 0x2d00, 0x2d25, + 0x2d30, 0x2d67, + 0x2d80, 0x2d96, + 0x2da0, 0x2da6, + 0x2da8, 0x2dae, + 0x2db0, 0x2db6, + 0x2db8, 0x2dbe, + 0x2dc0, 0x2dc6, + 0x2dc8, 0x2dce, + 0x2dd0, 0x2dd6, + 0x2dd8, 0x2dde, + 0x3005, 0x3006, + 0x3031, 0x3035, + 0x303b, 0x303c, + 0x3041, 0x3096, + 0x309d, 0x309f, + 0x30a1, 0x30fa, + 0x30fc, 0x30ff, + 0x3105, 0x312d, + 0x3131, 0x318e, + 0x31a0, 0x31ba, + 0x31f0, 0x31ff, + 0x3400, 0x4db5, + 0x4e00, 0x9fcc, + 0xa000, 0xa48c, + 0xa4d0, 0xa4fd, + 0xa500, 0xa60c, + 0xa610, 0xa61f, + 0xa62a, 0xa62b, + 0xa640, 0xa66e, + 0xa67f, 0xa69d, + 0xa6a0, 0xa6e5, + 0xa717, 0xa71f, + 0xa722, 0xa788, + 0xa78b, 0xa78e, + 0xa790, 0xa7ad, + 0xa7b0, 0xa7b1, + 0xa7f7, 0xa801, + 0xa803, 0xa805, + 0xa807, 0xa80a, + 0xa80c, 0xa822, + 0xa840, 0xa873, + 0xa882, 0xa8b3, + 0xa8f2, 0xa8f7, + 0xa90a, 0xa925, + 0xa930, 0xa946, + 0xa960, 0xa97c, + 0xa984, 0xa9b2, + 0xa9e0, 0xa9e4, + 0xa9e6, 0xa9ef, + 0xa9fa, 0xa9fe, + 0xaa00, 0xaa28, + 0xaa40, 0xaa42, + 0xaa44, 0xaa4b, + 0xaa60, 0xaa76, + 0xaa7e, 0xaaaf, + 0xaab5, 0xaab6, + 0xaab9, 0xaabd, + 0xaadb, 0xaadd, + 0xaae0, 0xaaea, + 0xaaf2, 0xaaf4, + 0xab01, 0xab06, + 0xab09, 0xab0e, + 0xab11, 0xab16, + 0xab20, 0xab26, + 0xab28, 0xab2e, + 0xab30, 0xab5a, + 0xab5c, 0xab5f, + 0xab64, 0xab65, + 0xabc0, 0xabe2, + 0xac00, 0xd7a3, + 0xd7b0, 0xd7c6, + 0xd7cb, 0xd7fb, + 0xf900, 0xfa6d, + 0xfa70, 0xfad9, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xfb1f, 0xfb28, + 0xfb2a, 0xfb36, + 0xfb38, 0xfb3c, + 0xfb40, 0xfb41, + 0xfb43, 0xfb44, + 0xfb46, 0xfbb1, + 0xfbd3, 0xfd3d, + 0xfd50, 0xfd8f, + 0xfd92, 0xfdc7, + 0xfdf0, 0xfdfb, + 0xfe70, 0xfe74, + 0xfe76, 0xfefc, + 0xff21, 0xff3a, + 0xff41, 0xff5a, + 0xff66, 0xffbe, + 0xffc2, 0xffc7, + 0xffca, 0xffcf, + 0xffd2, 0xffd7, + 0xffda, 0xffdc, + 0x10000, 0x1000b, + 0x1000d, 0x10026, + 0x10028, 0x1003a, + 0x1003c, 0x1003d, + 0x1003f, 0x1004d, + 0x10050, 0x1005d, + 0x10080, 0x100fa, + 0x10280, 0x1029c, + 0x102a0, 0x102d0, + 0x10300, 0x1031f, + 0x10330, 0x10340, + 0x10342, 0x10349, + 0x10350, 0x10375, + 0x10380, 0x1039d, + 0x103a0, 0x103c3, + 0x103c8, 0x103cf, + 0x10400, 0x1049d, + 0x10500, 0x10527, + 0x10530, 0x10563, + 0x10600, 0x10736, + 0x10740, 0x10755, + 0x10760, 0x10767, + 0x10800, 0x10805, + 0x1080a, 0x10835, + 0x10837, 0x10838, + 0x1083f, 0x10855, + 0x10860, 0x10876, + 0x10880, 0x1089e, + 0x10900, 0x10915, + 0x10920, 0x10939, + 0x10980, 0x109b7, + 0x109be, 0x109bf, + 0x10a10, 0x10a13, + 0x10a15, 0x10a17, + 0x10a19, 0x10a33, + 0x10a60, 0x10a7c, + 0x10a80, 0x10a9c, + 0x10ac0, 0x10ac7, + 0x10ac9, 0x10ae4, + 0x10b00, 0x10b35, + 0x10b40, 0x10b55, + 0x10b60, 0x10b72, + 0x10b80, 0x10b91, + 0x10c00, 0x10c48, + 0x11003, 0x11037, + 0x11083, 0x110af, + 0x110d0, 0x110e8, + 0x11103, 0x11126, + 0x11150, 0x11172, + 0x11183, 0x111b2, + 0x111c1, 0x111c4, + 0x11200, 0x11211, + 0x11213, 0x1122b, + 0x112b0, 0x112de, + 0x11305, 0x1130c, + 0x1130f, 0x11310, + 0x11313, 0x11328, + 0x1132a, 0x11330, + 0x11332, 0x11333, + 0x11335, 0x11339, + 0x1135d, 0x11361, + 0x11480, 0x114af, + 0x114c4, 0x114c5, + 0x11580, 0x115ae, + 0x11600, 0x1162f, + 0x11680, 0x116aa, + 0x118a0, 0x118df, + 0x11ac0, 0x11af8, + 0x12000, 0x12398, + 0x13000, 0x1342e, + 0x16800, 0x16a38, + 0x16a40, 0x16a5e, + 0x16ad0, 0x16aed, + 0x16b00, 0x16b2f, + 0x16b40, 0x16b43, + 0x16b63, 0x16b77, + 0x16b7d, 0x16b8f, + 0x16f00, 0x16f44, + 0x16f93, 0x16f9f, + 0x1b000, 0x1b001, + 0x1bc00, 0x1bc6a, + 0x1bc70, 0x1bc7c, + 0x1bc80, 0x1bc88, + 0x1bc90, 0x1bc99, + 0x1d400, 0x1d454, + 0x1d456, 0x1d49c, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d51e, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d552, 0x1d6a5, + 0x1d6a8, 0x1d6c0, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6fa, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d734, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d76e, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d7a8, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7cb, + 0x1e800, 0x1e8c4, + 0x1ee00, 0x1ee03, + 0x1ee05, 0x1ee1f, + 0x1ee21, 0x1ee22, + 0x1ee29, 0x1ee32, + 0x1ee34, 0x1ee37, + 0x1ee4d, 0x1ee4f, + 0x1ee51, 0x1ee52, + 0x1ee61, 0x1ee62, + 0x1ee67, 0x1ee6a, + 0x1ee6c, 0x1ee72, + 0x1ee74, 0x1ee77, + 0x1ee79, 0x1ee7c, + 0x1ee80, 0x1ee89, + 0x1ee8b, 0x1ee9b, + 0x1eea1, 0x1eea3, + 0x1eea5, 0x1eea9, + 0x1eeab, 0x1eebb, + 0x20000, 0x2a6d6, + 0x2a700, 0x2b734, + 0x2b740, 0x2b81d, + 0x2f800, 0x2fa1d, +}; + +} // !namespace + +namespace { + +const char32_t isalphas[] = { + 0x00aa, + 0x00b5, + 0x00ba, + 0x02ec, + 0x02ee, + 0x037f, + 0x0386, + 0x038c, + 0x0559, + 0x06d5, + 0x06ff, + 0x0710, + 0x07b1, + 0x07fa, + 0x081a, + 0x0824, + 0x0828, + 0x093d, + 0x0950, + 0x09b2, + 0x09bd, + 0x09ce, + 0x0a5e, + 0x0abd, + 0x0ad0, + 0x0b3d, + 0x0b71, + 0x0b83, + 0x0b9c, + 0x0bd0, + 0x0c3d, + 0x0cbd, + 0x0cde, + 0x0d3d, + 0x0d4e, + 0x0dbd, + 0x0e84, + 0x0e8a, + 0x0e8d, + 0x0ea5, + 0x0ea7, + 0x0ebd, + 0x0ec6, + 0x0f00, + 0x103f, + 0x1061, + 0x108e, + 0x10c7, + 0x10cd, + 0x1258, + 0x12c0, + 0x17d7, + 0x17dc, + 0x18aa, + 0x1aa7, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1fbe, + 0x2071, + 0x207f, + 0x2102, + 0x2107, + 0x2115, + 0x2124, + 0x2126, + 0x2128, + 0x214e, + 0x2d27, + 0x2d2d, + 0x2d6f, + 0x2e2f, + 0xa8fb, + 0xa9cf, + 0xaa7a, + 0xaab1, + 0xaac0, + 0xaac2, + 0xfb1d, + 0xfb3e, + 0x10808, + 0x1083c, + 0x10a00, + 0x11176, + 0x111da, + 0x1133d, + 0x114c7, + 0x11644, + 0x118ff, + 0x16f50, + 0x1d4a2, + 0x1d4bb, + 0x1d546, + 0x1ee24, + 0x1ee27, + 0x1ee39, + 0x1ee3b, + 0x1ee42, + 0x1ee47, + 0x1ee49, + 0x1ee4b, + 0x1ee54, + 0x1ee57, + 0x1ee59, + 0x1ee5b, + 0x1ee5d, + 0x1ee5f, + 0x1ee64, + 0x1ee7e, +}; + +} // !namespace + +auto isalpha(char32_t c) noexcept -> bool +{ + const char32_t* p; + + p = search(c, isalphar, nelem (isalphar) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, isalphas, nelem (isalphas), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t isupperr[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03d2, 0x03d4, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x210b, 0x210d, + 0x2110, 0x2112, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x2130, 0x2133, + 0x213e, 0x213f, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xa7aa, 0xa7ad, + 0xa7b0, 0xa7b1, + 0xff21, 0xff3a, + 0x10400, 0x10427, + 0x118a0, 0x118bf, + 0x1d400, 0x1d419, + 0x1d434, 0x1d44d, + 0x1d468, 0x1d481, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b5, + 0x1d4d0, 0x1d4e9, + 0x1d504, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d538, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d56c, 0x1d585, + 0x1d5a0, 0x1d5b9, + 0x1d5d4, 0x1d5ed, + 0x1d608, 0x1d621, + 0x1d63c, 0x1d655, + 0x1d670, 0x1d689, + 0x1d6a8, 0x1d6c0, + 0x1d6e2, 0x1d6fa, + 0x1d71c, 0x1d734, + 0x1d756, 0x1d76e, + 0x1d790, 0x1d7a8, +}; + +} // !namespace + +namespace { + +const char32_t isuppers[] = { + 0x0100, + 0x0102, + 0x0104, + 0x0106, + 0x0108, + 0x010a, + 0x010c, + 0x010e, + 0x0110, + 0x0112, + 0x0114, + 0x0116, + 0x0118, + 0x011a, + 0x011c, + 0x011e, + 0x0120, + 0x0122, + 0x0124, + 0x0126, + 0x0128, + 0x012a, + 0x012c, + 0x012e, + 0x0130, + 0x0132, + 0x0134, + 0x0136, + 0x0139, + 0x013b, + 0x013d, + 0x013f, + 0x0141, + 0x0143, + 0x0145, + 0x0147, + 0x014a, + 0x014c, + 0x014e, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x015a, + 0x015c, + 0x015e, + 0x0160, + 0x0162, + 0x0164, + 0x0166, + 0x0168, + 0x016a, + 0x016c, + 0x016e, + 0x0170, + 0x0172, + 0x0174, + 0x0176, + 0x017b, + 0x017d, + 0x0184, + 0x01a2, + 0x01a4, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c4, + 0x01c7, + 0x01ca, + 0x01cd, + 0x01cf, + 0x01d1, + 0x01d3, + 0x01d5, + 0x01d7, + 0x01d9, + 0x01db, + 0x01de, + 0x01e0, + 0x01e2, + 0x01e4, + 0x01e6, + 0x01e8, + 0x01ea, + 0x01ec, + 0x01ee, + 0x01f1, + 0x01f4, + 0x01fa, + 0x01fc, + 0x01fe, + 0x0200, + 0x0202, + 0x0204, + 0x0206, + 0x0208, + 0x020a, + 0x020c, + 0x020e, + 0x0210, + 0x0212, + 0x0214, + 0x0216, + 0x0218, + 0x021a, + 0x021c, + 0x021e, + 0x0220, + 0x0222, + 0x0224, + 0x0226, + 0x0228, + 0x022a, + 0x022c, + 0x022e, + 0x0230, + 0x0232, + 0x0241, + 0x0248, + 0x024a, + 0x024c, + 0x024e, + 0x0370, + 0x0372, + 0x0376, + 0x037f, + 0x0386, + 0x038c, + 0x03cf, + 0x03d8, + 0x03da, + 0x03dc, + 0x03de, + 0x03e0, + 0x03e2, + 0x03e4, + 0x03e6, + 0x03e8, + 0x03ea, + 0x03ec, + 0x03ee, + 0x03f4, + 0x03f7, + 0x0460, + 0x0462, + 0x0464, + 0x0466, + 0x0468, + 0x046a, + 0x046c, + 0x046e, + 0x0470, + 0x0472, + 0x0474, + 0x0476, + 0x0478, + 0x047a, + 0x047c, + 0x047e, + 0x0480, + 0x048a, + 0x048c, + 0x048e, + 0x0490, + 0x0492, + 0x0494, + 0x0496, + 0x0498, + 0x049a, + 0x049c, + 0x049e, + 0x04a0, + 0x04a2, + 0x04a4, + 0x04a6, + 0x04a8, + 0x04aa, + 0x04ac, + 0x04ae, + 0x04b0, + 0x04b2, + 0x04b4, + 0x04b6, + 0x04b8, + 0x04ba, + 0x04bc, + 0x04be, + 0x04c3, + 0x04c5, + 0x04c7, + 0x04c9, + 0x04cb, + 0x04cd, + 0x04d0, + 0x04d2, + 0x04d4, + 0x04d6, + 0x04d8, + 0x04da, + 0x04dc, + 0x04de, + 0x04e0, + 0x04e2, + 0x04e4, + 0x04e6, + 0x04e8, + 0x04ea, + 0x04ec, + 0x04ee, + 0x04f0, + 0x04f2, + 0x04f4, + 0x04f6, + 0x04f8, + 0x04fa, + 0x04fc, + 0x04fe, + 0x0500, + 0x0502, + 0x0504, + 0x0506, + 0x0508, + 0x050a, + 0x050c, + 0x050e, + 0x0510, + 0x0512, + 0x0514, + 0x0516, + 0x0518, + 0x051a, + 0x051c, + 0x051e, + 0x0520, + 0x0522, + 0x0524, + 0x0526, + 0x0528, + 0x052a, + 0x052c, + 0x052e, + 0x10c7, + 0x10cd, + 0x1e00, + 0x1e02, + 0x1e04, + 0x1e06, + 0x1e08, + 0x1e0a, + 0x1e0c, + 0x1e0e, + 0x1e10, + 0x1e12, + 0x1e14, + 0x1e16, + 0x1e18, + 0x1e1a, + 0x1e1c, + 0x1e1e, + 0x1e20, + 0x1e22, + 0x1e24, + 0x1e26, + 0x1e28, + 0x1e2a, + 0x1e2c, + 0x1e2e, + 0x1e30, + 0x1e32, + 0x1e34, + 0x1e36, + 0x1e38, + 0x1e3a, + 0x1e3c, + 0x1e3e, + 0x1e40, + 0x1e42, + 0x1e44, + 0x1e46, + 0x1e48, + 0x1e4a, + 0x1e4c, + 0x1e4e, + 0x1e50, + 0x1e52, + 0x1e54, + 0x1e56, + 0x1e58, + 0x1e5a, + 0x1e5c, + 0x1e5e, + 0x1e60, + 0x1e62, + 0x1e64, + 0x1e66, + 0x1e68, + 0x1e6a, + 0x1e6c, + 0x1e6e, + 0x1e70, + 0x1e72, + 0x1e74, + 0x1e76, + 0x1e78, + 0x1e7a, + 0x1e7c, + 0x1e7e, + 0x1e80, + 0x1e82, + 0x1e84, + 0x1e86, + 0x1e88, + 0x1e8a, + 0x1e8c, + 0x1e8e, + 0x1e90, + 0x1e92, + 0x1e94, + 0x1e9e, + 0x1ea0, + 0x1ea2, + 0x1ea4, + 0x1ea6, + 0x1ea8, + 0x1eaa, + 0x1eac, + 0x1eae, + 0x1eb0, + 0x1eb2, + 0x1eb4, + 0x1eb6, + 0x1eb8, + 0x1eba, + 0x1ebc, + 0x1ebe, + 0x1ec0, + 0x1ec2, + 0x1ec4, + 0x1ec6, + 0x1ec8, + 0x1eca, + 0x1ecc, + 0x1ece, + 0x1ed0, + 0x1ed2, + 0x1ed4, + 0x1ed6, + 0x1ed8, + 0x1eda, + 0x1edc, + 0x1ede, + 0x1ee0, + 0x1ee2, + 0x1ee4, + 0x1ee6, + 0x1ee8, + 0x1eea, + 0x1eec, + 0x1eee, + 0x1ef0, + 0x1ef2, + 0x1ef4, + 0x1ef6, + 0x1ef8, + 0x1efa, + 0x1efc, + 0x1efe, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1f5f, + 0x2102, + 0x2107, + 0x2115, + 0x2124, + 0x2126, + 0x2128, + 0x2145, + 0x2183, + 0x2c60, + 0x2c67, + 0x2c69, + 0x2c6b, + 0x2c72, + 0x2c75, + 0x2c82, + 0x2c84, + 0x2c86, + 0x2c88, + 0x2c8a, + 0x2c8c, + 0x2c8e, + 0x2c90, + 0x2c92, + 0x2c94, + 0x2c96, + 0x2c98, + 0x2c9a, + 0x2c9c, + 0x2c9e, + 0x2ca0, + 0x2ca2, + 0x2ca4, + 0x2ca6, + 0x2ca8, + 0x2caa, + 0x2cac, + 0x2cae, + 0x2cb0, + 0x2cb2, + 0x2cb4, + 0x2cb6, + 0x2cb8, + 0x2cba, + 0x2cbc, + 0x2cbe, + 0x2cc0, + 0x2cc2, + 0x2cc4, + 0x2cc6, + 0x2cc8, + 0x2cca, + 0x2ccc, + 0x2cce, + 0x2cd0, + 0x2cd2, + 0x2cd4, + 0x2cd6, + 0x2cd8, + 0x2cda, + 0x2cdc, + 0x2cde, + 0x2ce0, + 0x2ce2, + 0x2ceb, + 0x2ced, + 0x2cf2, + 0xa640, + 0xa642, + 0xa644, + 0xa646, + 0xa648, + 0xa64a, + 0xa64c, + 0xa64e, + 0xa650, + 0xa652, + 0xa654, + 0xa656, + 0xa658, + 0xa65a, + 0xa65c, + 0xa65e, + 0xa660, + 0xa662, + 0xa664, + 0xa666, + 0xa668, + 0xa66a, + 0xa66c, + 0xa680, + 0xa682, + 0xa684, + 0xa686, + 0xa688, + 0xa68a, + 0xa68c, + 0xa68e, + 0xa690, + 0xa692, + 0xa694, + 0xa696, + 0xa698, + 0xa69a, + 0xa722, + 0xa724, + 0xa726, + 0xa728, + 0xa72a, + 0xa72c, + 0xa72e, + 0xa732, + 0xa734, + 0xa736, + 0xa738, + 0xa73a, + 0xa73c, + 0xa73e, + 0xa740, + 0xa742, + 0xa744, + 0xa746, + 0xa748, + 0xa74a, + 0xa74c, + 0xa74e, + 0xa750, + 0xa752, + 0xa754, + 0xa756, + 0xa758, + 0xa75a, + 0xa75c, + 0xa75e, + 0xa760, + 0xa762, + 0xa764, + 0xa766, + 0xa768, + 0xa76a, + 0xa76c, + 0xa76e, + 0xa779, + 0xa77b, + 0xa780, + 0xa782, + 0xa784, + 0xa786, + 0xa78b, + 0xa78d, + 0xa790, + 0xa792, + 0xa796, + 0xa798, + 0xa79a, + 0xa79c, + 0xa79e, + 0xa7a0, + 0xa7a2, + 0xa7a4, + 0xa7a6, + 0xa7a8, + 0x1d49c, + 0x1d4a2, + 0x1d546, + 0x1d7ca, +}; + +} // !namespace + +auto isupper(char32_t c) noexcept -> bool +{ + const char32_t* p; + + p = search(c, isupperr, nelem (isupperr) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, isuppers, nelem (isuppers), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t islowerr[] = { + 0x0061, 0x007a, + 0x00df, 0x00f6, + 0x00f8, 0x00ff, + 0x0137, 0x0138, + 0x0148, 0x0149, + 0x017e, 0x0180, + 0x018c, 0x018d, + 0x0199, 0x019b, + 0x01aa, 0x01ab, + 0x01b9, 0x01ba, + 0x01bd, 0x01bf, + 0x01dc, 0x01dd, + 0x01ef, 0x01f0, + 0x0233, 0x0239, + 0x023f, 0x0240, + 0x024f, 0x0293, + 0x0295, 0x02af, + 0x037b, 0x037d, + 0x03ac, 0x03ce, + 0x03d0, 0x03d1, + 0x03d5, 0x03d7, + 0x03ef, 0x03f3, + 0x03fb, 0x03fc, + 0x0430, 0x045f, + 0x04ce, 0x04cf, + 0x0561, 0x0587, + 0x1d00, 0x1d2b, + 0x1d6b, 0x1d77, + 0x1d79, 0x1d9a, + 0x1e95, 0x1e9d, + 0x1eff, 0x1f07, + 0x1f10, 0x1f15, + 0x1f20, 0x1f27, + 0x1f30, 0x1f37, + 0x1f40, 0x1f45, + 0x1f50, 0x1f57, + 0x1f60, 0x1f67, + 0x1f70, 0x1f7d, + 0x1f80, 0x1f87, + 0x1f90, 0x1f97, + 0x1fa0, 0x1fa7, + 0x1fb0, 0x1fb4, + 0x1fb6, 0x1fb7, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fc7, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fd7, + 0x1fe0, 0x1fe7, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ff7, + 0x210e, 0x210f, + 0x213c, 0x213d, + 0x2146, 0x2149, + 0x2170, 0x217f, + 0x24d0, 0x24e9, + 0x2c30, 0x2c5e, + 0x2c65, 0x2c66, + 0x2c73, 0x2c74, + 0x2c76, 0x2c7b, + 0x2ce3, 0x2ce4, + 0x2d00, 0x2d25, + 0xa72f, 0xa731, + 0xa771, 0xa778, + 0xa793, 0xa795, + 0xab30, 0xab5a, + 0xab64, 0xab65, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xff41, 0xff5a, + 0x10428, 0x1044f, + 0x118c0, 0x118df, + 0x1d41a, 0x1d433, + 0x1d44e, 0x1d454, + 0x1d456, 0x1d467, + 0x1d482, 0x1d49b, + 0x1d4b6, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d4cf, + 0x1d4ea, 0x1d503, + 0x1d51e, 0x1d537, + 0x1d552, 0x1d56b, + 0x1d586, 0x1d59f, + 0x1d5ba, 0x1d5d3, + 0x1d5ee, 0x1d607, + 0x1d622, 0x1d63b, + 0x1d656, 0x1d66f, + 0x1d68a, 0x1d6a5, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6e1, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d71b, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d755, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d78f, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7c9, +}; + +} // !namespace + +namespace { + +const char32_t islowers[] = { + 0x00b5, + 0x0101, + 0x0103, + 0x0105, + 0x0107, + 0x0109, + 0x010b, + 0x010d, + 0x010f, + 0x0111, + 0x0113, + 0x0115, + 0x0117, + 0x0119, + 0x011b, + 0x011d, + 0x011f, + 0x0121, + 0x0123, + 0x0125, + 0x0127, + 0x0129, + 0x012b, + 0x012d, + 0x012f, + 0x0131, + 0x0133, + 0x0135, + 0x013a, + 0x013c, + 0x013e, + 0x0140, + 0x0142, + 0x0144, + 0x0146, + 0x014b, + 0x014d, + 0x014f, + 0x0151, + 0x0153, + 0x0155, + 0x0157, + 0x0159, + 0x015b, + 0x015d, + 0x015f, + 0x0161, + 0x0163, + 0x0165, + 0x0167, + 0x0169, + 0x016b, + 0x016d, + 0x016f, + 0x0171, + 0x0173, + 0x0175, + 0x0177, + 0x017a, + 0x017c, + 0x0183, + 0x0185, + 0x0188, + 0x0192, + 0x0195, + 0x019e, + 0x01a1, + 0x01a3, + 0x01a5, + 0x01a8, + 0x01ad, + 0x01b0, + 0x01b4, + 0x01b6, + 0x01c6, + 0x01c9, + 0x01cc, + 0x01ce, + 0x01d0, + 0x01d2, + 0x01d4, + 0x01d6, + 0x01d8, + 0x01da, + 0x01df, + 0x01e1, + 0x01e3, + 0x01e5, + 0x01e7, + 0x01e9, + 0x01eb, + 0x01ed, + 0x01f3, + 0x01f5, + 0x01f9, + 0x01fb, + 0x01fd, + 0x01ff, + 0x0201, + 0x0203, + 0x0205, + 0x0207, + 0x0209, + 0x020b, + 0x020d, + 0x020f, + 0x0211, + 0x0213, + 0x0215, + 0x0217, + 0x0219, + 0x021b, + 0x021d, + 0x021f, + 0x0221, + 0x0223, + 0x0225, + 0x0227, + 0x0229, + 0x022b, + 0x022d, + 0x022f, + 0x0231, + 0x023c, + 0x0242, + 0x0247, + 0x0249, + 0x024b, + 0x024d, + 0x0371, + 0x0373, + 0x0377, + 0x0390, + 0x03d9, + 0x03db, + 0x03dd, + 0x03df, + 0x03e1, + 0x03e3, + 0x03e5, + 0x03e7, + 0x03e9, + 0x03eb, + 0x03ed, + 0x03f5, + 0x03f8, + 0x0461, + 0x0463, + 0x0465, + 0x0467, + 0x0469, + 0x046b, + 0x046d, + 0x046f, + 0x0471, + 0x0473, + 0x0475, + 0x0477, + 0x0479, + 0x047b, + 0x047d, + 0x047f, + 0x0481, + 0x048b, + 0x048d, + 0x048f, + 0x0491, + 0x0493, + 0x0495, + 0x0497, + 0x0499, + 0x049b, + 0x049d, + 0x049f, + 0x04a1, + 0x04a3, + 0x04a5, + 0x04a7, + 0x04a9, + 0x04ab, + 0x04ad, + 0x04af, + 0x04b1, + 0x04b3, + 0x04b5, + 0x04b7, + 0x04b9, + 0x04bb, + 0x04bd, + 0x04bf, + 0x04c2, + 0x04c4, + 0x04c6, + 0x04c8, + 0x04ca, + 0x04cc, + 0x04d1, + 0x04d3, + 0x04d5, + 0x04d7, + 0x04d9, + 0x04db, + 0x04dd, + 0x04df, + 0x04e1, + 0x04e3, + 0x04e5, + 0x04e7, + 0x04e9, + 0x04eb, + 0x04ed, + 0x04ef, + 0x04f1, + 0x04f3, + 0x04f5, + 0x04f7, + 0x04f9, + 0x04fb, + 0x04fd, + 0x04ff, + 0x0501, + 0x0503, + 0x0505, + 0x0507, + 0x0509, + 0x050b, + 0x050d, + 0x050f, + 0x0511, + 0x0513, + 0x0515, + 0x0517, + 0x0519, + 0x051b, + 0x051d, + 0x051f, + 0x0521, + 0x0523, + 0x0525, + 0x0527, + 0x0529, + 0x052b, + 0x052d, + 0x052f, + 0x1e01, + 0x1e03, + 0x1e05, + 0x1e07, + 0x1e09, + 0x1e0b, + 0x1e0d, + 0x1e0f, + 0x1e11, + 0x1e13, + 0x1e15, + 0x1e17, + 0x1e19, + 0x1e1b, + 0x1e1d, + 0x1e1f, + 0x1e21, + 0x1e23, + 0x1e25, + 0x1e27, + 0x1e29, + 0x1e2b, + 0x1e2d, + 0x1e2f, + 0x1e31, + 0x1e33, + 0x1e35, + 0x1e37, + 0x1e39, + 0x1e3b, + 0x1e3d, + 0x1e3f, + 0x1e41, + 0x1e43, + 0x1e45, + 0x1e47, + 0x1e49, + 0x1e4b, + 0x1e4d, + 0x1e4f, + 0x1e51, + 0x1e53, + 0x1e55, + 0x1e57, + 0x1e59, + 0x1e5b, + 0x1e5d, + 0x1e5f, + 0x1e61, + 0x1e63, + 0x1e65, + 0x1e67, + 0x1e69, + 0x1e6b, + 0x1e6d, + 0x1e6f, + 0x1e71, + 0x1e73, + 0x1e75, + 0x1e77, + 0x1e79, + 0x1e7b, + 0x1e7d, + 0x1e7f, + 0x1e81, + 0x1e83, + 0x1e85, + 0x1e87, + 0x1e89, + 0x1e8b, + 0x1e8d, + 0x1e8f, + 0x1e91, + 0x1e93, + 0x1e9f, + 0x1ea1, + 0x1ea3, + 0x1ea5, + 0x1ea7, + 0x1ea9, + 0x1eab, + 0x1ead, + 0x1eaf, + 0x1eb1, + 0x1eb3, + 0x1eb5, + 0x1eb7, + 0x1eb9, + 0x1ebb, + 0x1ebd, + 0x1ebf, + 0x1ec1, + 0x1ec3, + 0x1ec5, + 0x1ec7, + 0x1ec9, + 0x1ecb, + 0x1ecd, + 0x1ecf, + 0x1ed1, + 0x1ed3, + 0x1ed5, + 0x1ed7, + 0x1ed9, + 0x1edb, + 0x1edd, + 0x1edf, + 0x1ee1, + 0x1ee3, + 0x1ee5, + 0x1ee7, + 0x1ee9, + 0x1eeb, + 0x1eed, + 0x1eef, + 0x1ef1, + 0x1ef3, + 0x1ef5, + 0x1ef7, + 0x1ef9, + 0x1efb, + 0x1efd, + 0x1fbe, + 0x210a, + 0x2113, + 0x212f, + 0x2134, + 0x2139, + 0x214e, + 0x2184, + 0x2c61, + 0x2c68, + 0x2c6a, + 0x2c6c, + 0x2c71, + 0x2c81, + 0x2c83, + 0x2c85, + 0x2c87, + 0x2c89, + 0x2c8b, + 0x2c8d, + 0x2c8f, + 0x2c91, + 0x2c93, + 0x2c95, + 0x2c97, + 0x2c99, + 0x2c9b, + 0x2c9d, + 0x2c9f, + 0x2ca1, + 0x2ca3, + 0x2ca5, + 0x2ca7, + 0x2ca9, + 0x2cab, + 0x2cad, + 0x2caf, + 0x2cb1, + 0x2cb3, + 0x2cb5, + 0x2cb7, + 0x2cb9, + 0x2cbb, + 0x2cbd, + 0x2cbf, + 0x2cc1, + 0x2cc3, + 0x2cc5, + 0x2cc7, + 0x2cc9, + 0x2ccb, + 0x2ccd, + 0x2ccf, + 0x2cd1, + 0x2cd3, + 0x2cd5, + 0x2cd7, + 0x2cd9, + 0x2cdb, + 0x2cdd, + 0x2cdf, + 0x2ce1, + 0x2cec, + 0x2cee, + 0x2cf3, + 0x2d27, + 0x2d2d, + 0xa641, + 0xa643, + 0xa645, + 0xa647, + 0xa649, + 0xa64b, + 0xa64d, + 0xa64f, + 0xa651, + 0xa653, + 0xa655, + 0xa657, + 0xa659, + 0xa65b, + 0xa65d, + 0xa65f, + 0xa661, + 0xa663, + 0xa665, + 0xa667, + 0xa669, + 0xa66b, + 0xa66d, + 0xa681, + 0xa683, + 0xa685, + 0xa687, + 0xa689, + 0xa68b, + 0xa68d, + 0xa68f, + 0xa691, + 0xa693, + 0xa695, + 0xa697, + 0xa699, + 0xa69b, + 0xa723, + 0xa725, + 0xa727, + 0xa729, + 0xa72b, + 0xa72d, + 0xa733, + 0xa735, + 0xa737, + 0xa739, + 0xa73b, + 0xa73d, + 0xa73f, + 0xa741, + 0xa743, + 0xa745, + 0xa747, + 0xa749, + 0xa74b, + 0xa74d, + 0xa74f, + 0xa751, + 0xa753, + 0xa755, + 0xa757, + 0xa759, + 0xa75b, + 0xa75d, + 0xa75f, + 0xa761, + 0xa763, + 0xa765, + 0xa767, + 0xa769, + 0xa76b, + 0xa76d, + 0xa76f, + 0xa77a, + 0xa77c, + 0xa77f, + 0xa781, + 0xa783, + 0xa785, + 0xa787, + 0xa78c, + 0xa78e, + 0xa791, + 0xa797, + 0xa799, + 0xa79b, + 0xa79d, + 0xa79f, + 0xa7a1, + 0xa7a3, + 0xa7a5, + 0xa7a7, + 0xa7a9, + 0xa7fa, + 0x1d4bb, + 0x1d7cb, +}; + +} // !namespace + +auto islower(char32_t c) noexcept -> bool +{ + const char32_t* p; + + p = search(c, islowerr, nelem (islowerr) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, islowers, nelem (islowers), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t istitler[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xa7aa, 0xa7ad, + 0xa7b0, 0xa7b1, + 0xff21, 0xff3a, + 0x10400, 0x10427, + 0x118a0, 0x118bf, +}; + +} // !namespace + +namespace { + +const char32_t istitles[] = { + 0x0100, + 0x0102, + 0x0104, + 0x0106, + 0x0108, + 0x010a, + 0x010c, + 0x010e, + 0x0110, + 0x0112, + 0x0114, + 0x0116, + 0x0118, + 0x011a, + 0x011c, + 0x011e, + 0x0120, + 0x0122, + 0x0124, + 0x0126, + 0x0128, + 0x012a, + 0x012c, + 0x012e, + 0x0132, + 0x0134, + 0x0136, + 0x0139, + 0x013b, + 0x013d, + 0x013f, + 0x0141, + 0x0143, + 0x0145, + 0x0147, + 0x014a, + 0x014c, + 0x014e, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x015a, + 0x015c, + 0x015e, + 0x0160, + 0x0162, + 0x0164, + 0x0166, + 0x0168, + 0x016a, + 0x016c, + 0x016e, + 0x0170, + 0x0172, + 0x0174, + 0x0176, + 0x017b, + 0x017d, + 0x0184, + 0x01a2, + 0x01a4, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c5, + 0x01c8, + 0x01cb, + 0x01cd, + 0x01cf, + 0x01d1, + 0x01d3, + 0x01d5, + 0x01d7, + 0x01d9, + 0x01db, + 0x01de, + 0x01e0, + 0x01e2, + 0x01e4, + 0x01e6, + 0x01e8, + 0x01ea, + 0x01ec, + 0x01ee, + 0x01f2, + 0x01f4, + 0x01fa, + 0x01fc, + 0x01fe, + 0x0200, + 0x0202, + 0x0204, + 0x0206, + 0x0208, + 0x020a, + 0x020c, + 0x020e, + 0x0210, + 0x0212, + 0x0214, + 0x0216, + 0x0218, + 0x021a, + 0x021c, + 0x021e, + 0x0220, + 0x0222, + 0x0224, + 0x0226, + 0x0228, + 0x022a, + 0x022c, + 0x022e, + 0x0230, + 0x0232, + 0x0241, + 0x0248, + 0x024a, + 0x024c, + 0x024e, + 0x0370, + 0x0372, + 0x0376, + 0x037f, + 0x0386, + 0x038c, + 0x03cf, + 0x03d8, + 0x03da, + 0x03dc, + 0x03de, + 0x03e0, + 0x03e2, + 0x03e4, + 0x03e6, + 0x03e8, + 0x03ea, + 0x03ec, + 0x03ee, + 0x03f7, + 0x0460, + 0x0462, + 0x0464, + 0x0466, + 0x0468, + 0x046a, + 0x046c, + 0x046e, + 0x0470, + 0x0472, + 0x0474, + 0x0476, + 0x0478, + 0x047a, + 0x047c, + 0x047e, + 0x0480, + 0x048a, + 0x048c, + 0x048e, + 0x0490, + 0x0492, + 0x0494, + 0x0496, + 0x0498, + 0x049a, + 0x049c, + 0x049e, + 0x04a0, + 0x04a2, + 0x04a4, + 0x04a6, + 0x04a8, + 0x04aa, + 0x04ac, + 0x04ae, + 0x04b0, + 0x04b2, + 0x04b4, + 0x04b6, + 0x04b8, + 0x04ba, + 0x04bc, + 0x04be, + 0x04c3, + 0x04c5, + 0x04c7, + 0x04c9, + 0x04cb, + 0x04cd, + 0x04d0, + 0x04d2, + 0x04d4, + 0x04d6, + 0x04d8, + 0x04da, + 0x04dc, + 0x04de, + 0x04e0, + 0x04e2, + 0x04e4, + 0x04e6, + 0x04e8, + 0x04ea, + 0x04ec, + 0x04ee, + 0x04f0, + 0x04f2, + 0x04f4, + 0x04f6, + 0x04f8, + 0x04fa, + 0x04fc, + 0x04fe, + 0x0500, + 0x0502, + 0x0504, + 0x0506, + 0x0508, + 0x050a, + 0x050c, + 0x050e, + 0x0510, + 0x0512, + 0x0514, + 0x0516, + 0x0518, + 0x051a, + 0x051c, + 0x051e, + 0x0520, + 0x0522, + 0x0524, + 0x0526, + 0x0528, + 0x052a, + 0x052c, + 0x052e, + 0x10c7, + 0x10cd, + 0x1e00, + 0x1e02, + 0x1e04, + 0x1e06, + 0x1e08, + 0x1e0a, + 0x1e0c, + 0x1e0e, + 0x1e10, + 0x1e12, + 0x1e14, + 0x1e16, + 0x1e18, + 0x1e1a, + 0x1e1c, + 0x1e1e, + 0x1e20, + 0x1e22, + 0x1e24, + 0x1e26, + 0x1e28, + 0x1e2a, + 0x1e2c, + 0x1e2e, + 0x1e30, + 0x1e32, + 0x1e34, + 0x1e36, + 0x1e38, + 0x1e3a, + 0x1e3c, + 0x1e3e, + 0x1e40, + 0x1e42, + 0x1e44, + 0x1e46, + 0x1e48, + 0x1e4a, + 0x1e4c, + 0x1e4e, + 0x1e50, + 0x1e52, + 0x1e54, + 0x1e56, + 0x1e58, + 0x1e5a, + 0x1e5c, + 0x1e5e, + 0x1e60, + 0x1e62, + 0x1e64, + 0x1e66, + 0x1e68, + 0x1e6a, + 0x1e6c, + 0x1e6e, + 0x1e70, + 0x1e72, + 0x1e74, + 0x1e76, + 0x1e78, + 0x1e7a, + 0x1e7c, + 0x1e7e, + 0x1e80, + 0x1e82, + 0x1e84, + 0x1e86, + 0x1e88, + 0x1e8a, + 0x1e8c, + 0x1e8e, + 0x1e90, + 0x1e92, + 0x1e94, + 0x1ea0, + 0x1ea2, + 0x1ea4, + 0x1ea6, + 0x1ea8, + 0x1eaa, + 0x1eac, + 0x1eae, + 0x1eb0, + 0x1eb2, + 0x1eb4, + 0x1eb6, + 0x1eb8, + 0x1eba, + 0x1ebc, + 0x1ebe, + 0x1ec0, + 0x1ec2, + 0x1ec4, + 0x1ec6, + 0x1ec8, + 0x1eca, + 0x1ecc, + 0x1ece, + 0x1ed0, + 0x1ed2, + 0x1ed4, + 0x1ed6, + 0x1ed8, + 0x1eda, + 0x1edc, + 0x1ede, + 0x1ee0, + 0x1ee2, + 0x1ee4, + 0x1ee6, + 0x1ee8, + 0x1eea, + 0x1eec, + 0x1eee, + 0x1ef0, + 0x1ef2, + 0x1ef4, + 0x1ef6, + 0x1ef8, + 0x1efa, + 0x1efc, + 0x1efe, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1f5f, + 0x2132, + 0x2183, + 0x2c60, + 0x2c67, + 0x2c69, + 0x2c6b, + 0x2c72, + 0x2c75, + 0x2c82, + 0x2c84, + 0x2c86, + 0x2c88, + 0x2c8a, + 0x2c8c, + 0x2c8e, + 0x2c90, + 0x2c92, + 0x2c94, + 0x2c96, + 0x2c98, + 0x2c9a, + 0x2c9c, + 0x2c9e, + 0x2ca0, + 0x2ca2, + 0x2ca4, + 0x2ca6, + 0x2ca8, + 0x2caa, + 0x2cac, + 0x2cae, + 0x2cb0, + 0x2cb2, + 0x2cb4, + 0x2cb6, + 0x2cb8, + 0x2cba, + 0x2cbc, + 0x2cbe, + 0x2cc0, + 0x2cc2, + 0x2cc4, + 0x2cc6, + 0x2cc8, + 0x2cca, + 0x2ccc, + 0x2cce, + 0x2cd0, + 0x2cd2, + 0x2cd4, + 0x2cd6, + 0x2cd8, + 0x2cda, + 0x2cdc, + 0x2cde, + 0x2ce0, + 0x2ce2, + 0x2ceb, + 0x2ced, + 0x2cf2, + 0xa640, + 0xa642, + 0xa644, + 0xa646, + 0xa648, + 0xa64a, + 0xa64c, + 0xa64e, + 0xa650, + 0xa652, + 0xa654, + 0xa656, + 0xa658, + 0xa65a, + 0xa65c, + 0xa65e, + 0xa660, + 0xa662, + 0xa664, + 0xa666, + 0xa668, + 0xa66a, + 0xa66c, + 0xa680, + 0xa682, + 0xa684, + 0xa686, + 0xa688, + 0xa68a, + 0xa68c, + 0xa68e, + 0xa690, + 0xa692, + 0xa694, + 0xa696, + 0xa698, + 0xa69a, + 0xa722, + 0xa724, + 0xa726, + 0xa728, + 0xa72a, + 0xa72c, + 0xa72e, + 0xa732, + 0xa734, + 0xa736, + 0xa738, + 0xa73a, + 0xa73c, + 0xa73e, + 0xa740, + 0xa742, + 0xa744, + 0xa746, + 0xa748, + 0xa74a, + 0xa74c, + 0xa74e, + 0xa750, + 0xa752, + 0xa754, + 0xa756, + 0xa758, + 0xa75a, + 0xa75c, + 0xa75e, + 0xa760, + 0xa762, + 0xa764, + 0xa766, + 0xa768, + 0xa76a, + 0xa76c, + 0xa76e, + 0xa779, + 0xa77b, + 0xa780, + 0xa782, + 0xa784, + 0xa786, + 0xa78b, + 0xa78d, + 0xa790, + 0xa792, + 0xa796, + 0xa798, + 0xa79a, + 0xa79c, + 0xa79e, + 0xa7a0, + 0xa7a2, + 0xa7a4, + 0xa7a6, + 0xa7a8, +}; + +} // !namespace + +auto istitle(char32_t c) noexcept -> bool +{ + const char32_t* p; + + p = search(c, istitler, nelem (istitler) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, istitles, nelem (istitles), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t toupperr[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, + 0x118c0, 0x118df, 1048544, +}; + +} // !namespace + +namespace { + +const char32_t touppers[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0101, 1048575, + 0x0103, 1048575, + 0x0105, 1048575, + 0x0107, 1048575, + 0x0109, 1048575, + 0x010b, 1048575, + 0x010d, 1048575, + 0x010f, 1048575, + 0x0111, 1048575, + 0x0113, 1048575, + 0x0115, 1048575, + 0x0117, 1048575, + 0x0119, 1048575, + 0x011b, 1048575, + 0x011d, 1048575, + 0x011f, 1048575, + 0x0121, 1048575, + 0x0123, 1048575, + 0x0125, 1048575, + 0x0127, 1048575, + 0x0129, 1048575, + 0x012b, 1048575, + 0x012d, 1048575, + 0x012f, 1048575, + 0x0131, 1048344, + 0x0133, 1048575, + 0x0135, 1048575, + 0x0137, 1048575, + 0x013a, 1048575, + 0x013c, 1048575, + 0x013e, 1048575, + 0x0140, 1048575, + 0x0142, 1048575, + 0x0144, 1048575, + 0x0146, 1048575, + 0x0148, 1048575, + 0x014b, 1048575, + 0x014d, 1048575, + 0x014f, 1048575, + 0x0151, 1048575, + 0x0153, 1048575, + 0x0155, 1048575, + 0x0157, 1048575, + 0x0159, 1048575, + 0x015b, 1048575, + 0x015d, 1048575, + 0x015f, 1048575, + 0x0161, 1048575, + 0x0163, 1048575, + 0x0165, 1048575, + 0x0167, 1048575, + 0x0169, 1048575, + 0x016b, 1048575, + 0x016d, 1048575, + 0x016f, 1048575, + 0x0171, 1048575, + 0x0173, 1048575, + 0x0175, 1048575, + 0x0177, 1048575, + 0x017a, 1048575, + 0x017c, 1048575, + 0x017e, 1048575, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0183, 1048575, + 0x0185, 1048575, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a1, 1048575, + 0x01a3, 1048575, + 0x01a5, 1048575, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b4, 1048575, + 0x01b6, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c5, 1048575, + 0x01c6, 1048574, + 0x01c8, 1048575, + 0x01c9, 1048574, + 0x01cb, 1048575, + 0x01cc, 1048574, + 0x01ce, 1048575, + 0x01d0, 1048575, + 0x01d2, 1048575, + 0x01d4, 1048575, + 0x01d6, 1048575, + 0x01d8, 1048575, + 0x01da, 1048575, + 0x01dc, 1048575, + 0x01dd, 1048497, + 0x01df, 1048575, + 0x01e1, 1048575, + 0x01e3, 1048575, + 0x01e5, 1048575, + 0x01e7, 1048575, + 0x01e9, 1048575, + 0x01eb, 1048575, + 0x01ed, 1048575, + 0x01ef, 1048575, + 0x01f2, 1048575, + 0x01f3, 1048574, + 0x01f5, 1048575, + 0x01f9, 1048575, + 0x01fb, 1048575, + 0x01fd, 1048575, + 0x01ff, 1048575, + 0x0201, 1048575, + 0x0203, 1048575, + 0x0205, 1048575, + 0x0207, 1048575, + 0x0209, 1048575, + 0x020b, 1048575, + 0x020d, 1048575, + 0x020f, 1048575, + 0x0211, 1048575, + 0x0213, 1048575, + 0x0215, 1048575, + 0x0217, 1048575, + 0x0219, 1048575, + 0x021b, 1048575, + 0x021d, 1048575, + 0x021f, 1048575, + 0x0223, 1048575, + 0x0225, 1048575, + 0x0227, 1048575, + 0x0229, 1048575, + 0x022b, 1048575, + 0x022d, 1048575, + 0x022f, 1048575, + 0x0231, 1048575, + 0x0233, 1048575, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0247, 1048575, + 0x0249, 1048575, + 0x024b, 1048575, + 0x024d, 1048575, + 0x024f, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x025c, 1090895, + 0x0260, 1048371, + 0x0261, 1090891, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0266, 1090884, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026c, 1090881, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0287, 1090858, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x029e, 1090834, + 0x0345, 1048660, + 0x0371, 1048575, + 0x0373, 1048575, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03d9, 1048575, + 0x03db, 1048575, + 0x03dd, 1048575, + 0x03df, 1048575, + 0x03e1, 1048575, + 0x03e3, 1048575, + 0x03e5, 1048575, + 0x03e7, 1048575, + 0x03e9, 1048575, + 0x03eb, 1048575, + 0x03ed, 1048575, + 0x03ef, 1048575, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f3, 1048460, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x0461, 1048575, + 0x0463, 1048575, + 0x0465, 1048575, + 0x0467, 1048575, + 0x0469, 1048575, + 0x046b, 1048575, + 0x046d, 1048575, + 0x046f, 1048575, + 0x0471, 1048575, + 0x0473, 1048575, + 0x0475, 1048575, + 0x0477, 1048575, + 0x0479, 1048575, + 0x047b, 1048575, + 0x047d, 1048575, + 0x047f, 1048575, + 0x0481, 1048575, + 0x048b, 1048575, + 0x048d, 1048575, + 0x048f, 1048575, + 0x0491, 1048575, + 0x0493, 1048575, + 0x0495, 1048575, + 0x0497, 1048575, + 0x0499, 1048575, + 0x049b, 1048575, + 0x049d, 1048575, + 0x049f, 1048575, + 0x04a1, 1048575, + 0x04a3, 1048575, + 0x04a5, 1048575, + 0x04a7, 1048575, + 0x04a9, 1048575, + 0x04ab, 1048575, + 0x04ad, 1048575, + 0x04af, 1048575, + 0x04b1, 1048575, + 0x04b3, 1048575, + 0x04b5, 1048575, + 0x04b7, 1048575, + 0x04b9, 1048575, + 0x04bb, 1048575, + 0x04bd, 1048575, + 0x04bf, 1048575, + 0x04c2, 1048575, + 0x04c4, 1048575, + 0x04c6, 1048575, + 0x04c8, 1048575, + 0x04ca, 1048575, + 0x04cc, 1048575, + 0x04ce, 1048575, + 0x04cf, 1048561, + 0x04d1, 1048575, + 0x04d3, 1048575, + 0x04d5, 1048575, + 0x04d7, 1048575, + 0x04d9, 1048575, + 0x04db, 1048575, + 0x04dd, 1048575, + 0x04df, 1048575, + 0x04e1, 1048575, + 0x04e3, 1048575, + 0x04e5, 1048575, + 0x04e7, 1048575, + 0x04e9, 1048575, + 0x04eb, 1048575, + 0x04ed, 1048575, + 0x04ef, 1048575, + 0x04f1, 1048575, + 0x04f3, 1048575, + 0x04f5, 1048575, + 0x04f7, 1048575, + 0x04f9, 1048575, + 0x04fb, 1048575, + 0x04fd, 1048575, + 0x04ff, 1048575, + 0x0501, 1048575, + 0x0503, 1048575, + 0x0505, 1048575, + 0x0507, 1048575, + 0x0509, 1048575, + 0x050b, 1048575, + 0x050d, 1048575, + 0x050f, 1048575, + 0x0511, 1048575, + 0x0513, 1048575, + 0x0515, 1048575, + 0x0517, 1048575, + 0x0519, 1048575, + 0x051b, 1048575, + 0x051d, 1048575, + 0x051f, 1048575, + 0x0521, 1048575, + 0x0523, 1048575, + 0x0525, 1048575, + 0x0527, 1048575, + 0x0529, 1048575, + 0x052b, 1048575, + 0x052d, 1048575, + 0x052f, 1048575, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e01, 1048575, + 0x1e03, 1048575, + 0x1e05, 1048575, + 0x1e07, 1048575, + 0x1e09, 1048575, + 0x1e0b, 1048575, + 0x1e0d, 1048575, + 0x1e0f, 1048575, + 0x1e11, 1048575, + 0x1e13, 1048575, + 0x1e15, 1048575, + 0x1e17, 1048575, + 0x1e19, 1048575, + 0x1e1b, 1048575, + 0x1e1d, 1048575, + 0x1e1f, 1048575, + 0x1e21, 1048575, + 0x1e23, 1048575, + 0x1e25, 1048575, + 0x1e27, 1048575, + 0x1e29, 1048575, + 0x1e2b, 1048575, + 0x1e2d, 1048575, + 0x1e2f, 1048575, + 0x1e31, 1048575, + 0x1e33, 1048575, + 0x1e35, 1048575, + 0x1e37, 1048575, + 0x1e39, 1048575, + 0x1e3b, 1048575, + 0x1e3d, 1048575, + 0x1e3f, 1048575, + 0x1e41, 1048575, + 0x1e43, 1048575, + 0x1e45, 1048575, + 0x1e47, 1048575, + 0x1e49, 1048575, + 0x1e4b, 1048575, + 0x1e4d, 1048575, + 0x1e4f, 1048575, + 0x1e51, 1048575, + 0x1e53, 1048575, + 0x1e55, 1048575, + 0x1e57, 1048575, + 0x1e59, 1048575, + 0x1e5b, 1048575, + 0x1e5d, 1048575, + 0x1e5f, 1048575, + 0x1e61, 1048575, + 0x1e63, 1048575, + 0x1e65, 1048575, + 0x1e67, 1048575, + 0x1e69, 1048575, + 0x1e6b, 1048575, + 0x1e6d, 1048575, + 0x1e6f, 1048575, + 0x1e71, 1048575, + 0x1e73, 1048575, + 0x1e75, 1048575, + 0x1e77, 1048575, + 0x1e79, 1048575, + 0x1e7b, 1048575, + 0x1e7d, 1048575, + 0x1e7f, 1048575, + 0x1e81, 1048575, + 0x1e83, 1048575, + 0x1e85, 1048575, + 0x1e87, 1048575, + 0x1e89, 1048575, + 0x1e8b, 1048575, + 0x1e8d, 1048575, + 0x1e8f, 1048575, + 0x1e91, 1048575, + 0x1e93, 1048575, + 0x1e95, 1048575, + 0x1e9b, 1048517, + 0x1ea1, 1048575, + 0x1ea3, 1048575, + 0x1ea5, 1048575, + 0x1ea7, 1048575, + 0x1ea9, 1048575, + 0x1eab, 1048575, + 0x1ead, 1048575, + 0x1eaf, 1048575, + 0x1eb1, 1048575, + 0x1eb3, 1048575, + 0x1eb5, 1048575, + 0x1eb7, 1048575, + 0x1eb9, 1048575, + 0x1ebb, 1048575, + 0x1ebd, 1048575, + 0x1ebf, 1048575, + 0x1ec1, 1048575, + 0x1ec3, 1048575, + 0x1ec5, 1048575, + 0x1ec7, 1048575, + 0x1ec9, 1048575, + 0x1ecb, 1048575, + 0x1ecd, 1048575, + 0x1ecf, 1048575, + 0x1ed1, 1048575, + 0x1ed3, 1048575, + 0x1ed5, 1048575, + 0x1ed7, 1048575, + 0x1ed9, 1048575, + 0x1edb, 1048575, + 0x1edd, 1048575, + 0x1edf, 1048575, + 0x1ee1, 1048575, + 0x1ee3, 1048575, + 0x1ee5, 1048575, + 0x1ee7, 1048575, + 0x1ee9, 1048575, + 0x1eeb, 1048575, + 0x1eed, 1048575, + 0x1eef, 1048575, + 0x1ef1, 1048575, + 0x1ef3, 1048575, + 0x1ef5, 1048575, + 0x1ef7, 1048575, + 0x1ef9, 1048575, + 0x1efb, 1048575, + 0x1efd, 1048575, + 0x1eff, 1048575, + 0x1f51, 1048584, + 0x1f53, 1048584, + 0x1f55, 1048584, + 0x1f57, 1048584, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c68, 1048575, + 0x2c6a, 1048575, + 0x2c6c, 1048575, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0x2c81, 1048575, + 0x2c83, 1048575, + 0x2c85, 1048575, + 0x2c87, 1048575, + 0x2c89, 1048575, + 0x2c8b, 1048575, + 0x2c8d, 1048575, + 0x2c8f, 1048575, + 0x2c91, 1048575, + 0x2c93, 1048575, + 0x2c95, 1048575, + 0x2c97, 1048575, + 0x2c99, 1048575, + 0x2c9b, 1048575, + 0x2c9d, 1048575, + 0x2c9f, 1048575, + 0x2ca1, 1048575, + 0x2ca3, 1048575, + 0x2ca5, 1048575, + 0x2ca7, 1048575, + 0x2ca9, 1048575, + 0x2cab, 1048575, + 0x2cad, 1048575, + 0x2caf, 1048575, + 0x2cb1, 1048575, + 0x2cb3, 1048575, + 0x2cb5, 1048575, + 0x2cb7, 1048575, + 0x2cb9, 1048575, + 0x2cbb, 1048575, + 0x2cbd, 1048575, + 0x2cbf, 1048575, + 0x2cc1, 1048575, + 0x2cc3, 1048575, + 0x2cc5, 1048575, + 0x2cc7, 1048575, + 0x2cc9, 1048575, + 0x2ccb, 1048575, + 0x2ccd, 1048575, + 0x2ccf, 1048575, + 0x2cd1, 1048575, + 0x2cd3, 1048575, + 0x2cd5, 1048575, + 0x2cd7, 1048575, + 0x2cd9, 1048575, + 0x2cdb, 1048575, + 0x2cdd, 1048575, + 0x2cdf, 1048575, + 0x2ce1, 1048575, + 0x2ce3, 1048575, + 0x2cec, 1048575, + 0x2cee, 1048575, + 0x2cf3, 1048575, + 0x2d27, 1041312, + 0x2d2d, 1041312, + 0xa641, 1048575, + 0xa643, 1048575, + 0xa645, 1048575, + 0xa647, 1048575, + 0xa649, 1048575, + 0xa64b, 1048575, + 0xa64d, 1048575, + 0xa64f, 1048575, + 0xa651, 1048575, + 0xa653, 1048575, + 0xa655, 1048575, + 0xa657, 1048575, + 0xa659, 1048575, + 0xa65b, 1048575, + 0xa65d, 1048575, + 0xa65f, 1048575, + 0xa661, 1048575, + 0xa663, 1048575, + 0xa665, 1048575, + 0xa667, 1048575, + 0xa669, 1048575, + 0xa66b, 1048575, + 0xa66d, 1048575, + 0xa681, 1048575, + 0xa683, 1048575, + 0xa685, 1048575, + 0xa687, 1048575, + 0xa689, 1048575, + 0xa68b, 1048575, + 0xa68d, 1048575, + 0xa68f, 1048575, + 0xa691, 1048575, + 0xa693, 1048575, + 0xa695, 1048575, + 0xa697, 1048575, + 0xa699, 1048575, + 0xa69b, 1048575, + 0xa723, 1048575, + 0xa725, 1048575, + 0xa727, 1048575, + 0xa729, 1048575, + 0xa72b, 1048575, + 0xa72d, 1048575, + 0xa72f, 1048575, + 0xa733, 1048575, + 0xa735, 1048575, + 0xa737, 1048575, + 0xa739, 1048575, + 0xa73b, 1048575, + 0xa73d, 1048575, + 0xa73f, 1048575, + 0xa741, 1048575, + 0xa743, 1048575, + 0xa745, 1048575, + 0xa747, 1048575, + 0xa749, 1048575, + 0xa74b, 1048575, + 0xa74d, 1048575, + 0xa74f, 1048575, + 0xa751, 1048575, + 0xa753, 1048575, + 0xa755, 1048575, + 0xa757, 1048575, + 0xa759, 1048575, + 0xa75b, 1048575, + 0xa75d, 1048575, + 0xa75f, 1048575, + 0xa761, 1048575, + 0xa763, 1048575, + 0xa765, 1048575, + 0xa767, 1048575, + 0xa769, 1048575, + 0xa76b, 1048575, + 0xa76d, 1048575, + 0xa76f, 1048575, + 0xa77a, 1048575, + 0xa77c, 1048575, + 0xa77f, 1048575, + 0xa781, 1048575, + 0xa783, 1048575, + 0xa785, 1048575, + 0xa787, 1048575, + 0xa78c, 1048575, + 0xa791, 1048575, + 0xa793, 1048575, + 0xa797, 1048575, + 0xa799, 1048575, + 0xa79b, 1048575, + 0xa79d, 1048575, + 0xa79f, 1048575, + 0xa7a1, 1048575, + 0xa7a3, 1048575, + 0xa7a5, 1048575, + 0xa7a7, 1048575, + 0xa7a9, 1048575, +}; + +} // !namespace + +auto toupper(char32_t c) noexcept -> char32_t +{ + const char32_t* p; + + p = search(c, toupperr, nelem (toupperr) / 3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = search(c, touppers, nelem (touppers) / 2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +namespace { + +const char32_t tolowerr[] = { + 0x0041, 0x005a, 1048608, + 0x00c0, 0x00d6, 1048608, + 0x00d8, 0x00de, 1048608, + 0x0189, 0x018a, 1048781, + 0x01b1, 0x01b2, 1048793, + 0x0388, 0x038a, 1048613, + 0x038e, 0x038f, 1048639, + 0x0391, 0x03a1, 1048608, + 0x03a3, 0x03ab, 1048608, + 0x03fd, 0x03ff, 1048446, + 0x0400, 0x040f, 1048656, + 0x0410, 0x042f, 1048608, + 0x0531, 0x0556, 1048624, + 0x10a0, 0x10c5, 1055840, + 0x1f08, 0x1f0f, 1048568, + 0x1f18, 0x1f1d, 1048568, + 0x1f28, 0x1f2f, 1048568, + 0x1f38, 0x1f3f, 1048568, + 0x1f48, 0x1f4d, 1048568, + 0x1f68, 0x1f6f, 1048568, + 0x1f88, 0x1f8f, 1048568, + 0x1f98, 0x1f9f, 1048568, + 0x1fa8, 0x1faf, 1048568, + 0x1fb8, 0x1fb9, 1048568, + 0x1fba, 0x1fbb, 1048502, + 0x1fc8, 0x1fcb, 1048490, + 0x1fd8, 0x1fd9, 1048568, + 0x1fda, 0x1fdb, 1048476, + 0x1fe8, 0x1fe9, 1048568, + 0x1fea, 0x1feb, 1048464, + 0x1ff8, 0x1ff9, 1048448, + 0x1ffa, 0x1ffb, 1048450, + 0x2160, 0x216f, 1048592, + 0x24b6, 0x24cf, 1048602, + 0x2c00, 0x2c2e, 1048624, + 0x2c7e, 0x2c7f, 1037761, + 0xff21, 0xff3a, 1048608, + 0x10400, 0x10427, 1048616, + 0x118a0, 0x118bf, 1048608, +}; + +} // !namespace + +namespace { + +const char32_t tolowers[] = { + 0x0100, 1048577, + 0x0102, 1048577, + 0x0104, 1048577, + 0x0106, 1048577, + 0x0108, 1048577, + 0x010a, 1048577, + 0x010c, 1048577, + 0x010e, 1048577, + 0x0110, 1048577, + 0x0112, 1048577, + 0x0114, 1048577, + 0x0116, 1048577, + 0x0118, 1048577, + 0x011a, 1048577, + 0x011c, 1048577, + 0x011e, 1048577, + 0x0120, 1048577, + 0x0122, 1048577, + 0x0124, 1048577, + 0x0126, 1048577, + 0x0128, 1048577, + 0x012a, 1048577, + 0x012c, 1048577, + 0x012e, 1048577, + 0x0130, 1048377, + 0x0132, 1048577, + 0x0134, 1048577, + 0x0136, 1048577, + 0x0139, 1048577, + 0x013b, 1048577, + 0x013d, 1048577, + 0x013f, 1048577, + 0x0141, 1048577, + 0x0143, 1048577, + 0x0145, 1048577, + 0x0147, 1048577, + 0x014a, 1048577, + 0x014c, 1048577, + 0x014e, 1048577, + 0x0150, 1048577, + 0x0152, 1048577, + 0x0154, 1048577, + 0x0156, 1048577, + 0x0158, 1048577, + 0x015a, 1048577, + 0x015c, 1048577, + 0x015e, 1048577, + 0x0160, 1048577, + 0x0162, 1048577, + 0x0164, 1048577, + 0x0166, 1048577, + 0x0168, 1048577, + 0x016a, 1048577, + 0x016c, 1048577, + 0x016e, 1048577, + 0x0170, 1048577, + 0x0172, 1048577, + 0x0174, 1048577, + 0x0176, 1048577, + 0x0178, 1048455, + 0x0179, 1048577, + 0x017b, 1048577, + 0x017d, 1048577, + 0x0181, 1048786, + 0x0182, 1048577, + 0x0184, 1048577, + 0x0186, 1048782, + 0x0187, 1048577, + 0x018b, 1048577, + 0x018e, 1048655, + 0x018f, 1048778, + 0x0190, 1048779, + 0x0191, 1048577, + 0x0193, 1048781, + 0x0194, 1048783, + 0x0196, 1048787, + 0x0197, 1048785, + 0x0198, 1048577, + 0x019c, 1048787, + 0x019d, 1048789, + 0x019f, 1048790, + 0x01a0, 1048577, + 0x01a2, 1048577, + 0x01a4, 1048577, + 0x01a6, 1048794, + 0x01a7, 1048577, + 0x01a9, 1048794, + 0x01ac, 1048577, + 0x01ae, 1048794, + 0x01af, 1048577, + 0x01b3, 1048577, + 0x01b5, 1048577, + 0x01b7, 1048795, + 0x01b8, 1048577, + 0x01bc, 1048577, + 0x01c4, 1048578, + 0x01c5, 1048577, + 0x01c7, 1048578, + 0x01c8, 1048577, + 0x01ca, 1048578, + 0x01cb, 1048577, + 0x01cd, 1048577, + 0x01cf, 1048577, + 0x01d1, 1048577, + 0x01d3, 1048577, + 0x01d5, 1048577, + 0x01d7, 1048577, + 0x01d9, 1048577, + 0x01db, 1048577, + 0x01de, 1048577, + 0x01e0, 1048577, + 0x01e2, 1048577, + 0x01e4, 1048577, + 0x01e6, 1048577, + 0x01e8, 1048577, + 0x01ea, 1048577, + 0x01ec, 1048577, + 0x01ee, 1048577, + 0x01f1, 1048578, + 0x01f2, 1048577, + 0x01f4, 1048577, + 0x01f6, 1048479, + 0x01f7, 1048520, + 0x01f8, 1048577, + 0x01fa, 1048577, + 0x01fc, 1048577, + 0x01fe, 1048577, + 0x0200, 1048577, + 0x0202, 1048577, + 0x0204, 1048577, + 0x0206, 1048577, + 0x0208, 1048577, + 0x020a, 1048577, + 0x020c, 1048577, + 0x020e, 1048577, + 0x0210, 1048577, + 0x0212, 1048577, + 0x0214, 1048577, + 0x0216, 1048577, + 0x0218, 1048577, + 0x021a, 1048577, + 0x021c, 1048577, + 0x021e, 1048577, + 0x0220, 1048446, + 0x0222, 1048577, + 0x0224, 1048577, + 0x0226, 1048577, + 0x0228, 1048577, + 0x022a, 1048577, + 0x022c, 1048577, + 0x022e, 1048577, + 0x0230, 1048577, + 0x0232, 1048577, + 0x023a, 1059371, + 0x023b, 1048577, + 0x023d, 1048413, + 0x023e, 1059368, + 0x0241, 1048577, + 0x0243, 1048381, + 0x0244, 1048645, + 0x0245, 1048647, + 0x0246, 1048577, + 0x0248, 1048577, + 0x024a, 1048577, + 0x024c, 1048577, + 0x024e, 1048577, + 0x0370, 1048577, + 0x0372, 1048577, + 0x0376, 1048577, + 0x037f, 1048692, + 0x0386, 1048614, + 0x038c, 1048640, + 0x03cf, 1048584, + 0x03d8, 1048577, + 0x03da, 1048577, + 0x03dc, 1048577, + 0x03de, 1048577, + 0x03e0, 1048577, + 0x03e2, 1048577, + 0x03e4, 1048577, + 0x03e6, 1048577, + 0x03e8, 1048577, + 0x03ea, 1048577, + 0x03ec, 1048577, + 0x03ee, 1048577, + 0x03f4, 1048516, + 0x03f7, 1048577, + 0x03f9, 1048569, + 0x03fa, 1048577, + 0x0460, 1048577, + 0x0462, 1048577, + 0x0464, 1048577, + 0x0466, 1048577, + 0x0468, 1048577, + 0x046a, 1048577, + 0x046c, 1048577, + 0x046e, 1048577, + 0x0470, 1048577, + 0x0472, 1048577, + 0x0474, 1048577, + 0x0476, 1048577, + 0x0478, 1048577, + 0x047a, 1048577, + 0x047c, 1048577, + 0x047e, 1048577, + 0x0480, 1048577, + 0x048a, 1048577, + 0x048c, 1048577, + 0x048e, 1048577, + 0x0490, 1048577, + 0x0492, 1048577, + 0x0494, 1048577, + 0x0496, 1048577, + 0x0498, 1048577, + 0x049a, 1048577, + 0x049c, 1048577, + 0x049e, 1048577, + 0x04a0, 1048577, + 0x04a2, 1048577, + 0x04a4, 1048577, + 0x04a6, 1048577, + 0x04a8, 1048577, + 0x04aa, 1048577, + 0x04ac, 1048577, + 0x04ae, 1048577, + 0x04b0, 1048577, + 0x04b2, 1048577, + 0x04b4, 1048577, + 0x04b6, 1048577, + 0x04b8, 1048577, + 0x04ba, 1048577, + 0x04bc, 1048577, + 0x04be, 1048577, + 0x04c0, 1048591, + 0x04c1, 1048577, + 0x04c3, 1048577, + 0x04c5, 1048577, + 0x04c7, 1048577, + 0x04c9, 1048577, + 0x04cb, 1048577, + 0x04cd, 1048577, + 0x04d0, 1048577, + 0x04d2, 1048577, + 0x04d4, 1048577, + 0x04d6, 1048577, + 0x04d8, 1048577, + 0x04da, 1048577, + 0x04dc, 1048577, + 0x04de, 1048577, + 0x04e0, 1048577, + 0x04e2, 1048577, + 0x04e4, 1048577, + 0x04e6, 1048577, + 0x04e8, 1048577, + 0x04ea, 1048577, + 0x04ec, 1048577, + 0x04ee, 1048577, + 0x04f0, 1048577, + 0x04f2, 1048577, + 0x04f4, 1048577, + 0x04f6, 1048577, + 0x04f8, 1048577, + 0x04fa, 1048577, + 0x04fc, 1048577, + 0x04fe, 1048577, + 0x0500, 1048577, + 0x0502, 1048577, + 0x0504, 1048577, + 0x0506, 1048577, + 0x0508, 1048577, + 0x050a, 1048577, + 0x050c, 1048577, + 0x050e, 1048577, + 0x0510, 1048577, + 0x0512, 1048577, + 0x0514, 1048577, + 0x0516, 1048577, + 0x0518, 1048577, + 0x051a, 1048577, + 0x051c, 1048577, + 0x051e, 1048577, + 0x0520, 1048577, + 0x0522, 1048577, + 0x0524, 1048577, + 0x0526, 1048577, + 0x0528, 1048577, + 0x052a, 1048577, + 0x052c, 1048577, + 0x052e, 1048577, + 0x10c7, 1055840, + 0x10cd, 1055840, + 0x1e00, 1048577, + 0x1e02, 1048577, + 0x1e04, 1048577, + 0x1e06, 1048577, + 0x1e08, 1048577, + 0x1e0a, 1048577, + 0x1e0c, 1048577, + 0x1e0e, 1048577, + 0x1e10, 1048577, + 0x1e12, 1048577, + 0x1e14, 1048577, + 0x1e16, 1048577, + 0x1e18, 1048577, + 0x1e1a, 1048577, + 0x1e1c, 1048577, + 0x1e1e, 1048577, + 0x1e20, 1048577, + 0x1e22, 1048577, + 0x1e24, 1048577, + 0x1e26, 1048577, + 0x1e28, 1048577, + 0x1e2a, 1048577, + 0x1e2c, 1048577, + 0x1e2e, 1048577, + 0x1e30, 1048577, + 0x1e32, 1048577, + 0x1e34, 1048577, + 0x1e36, 1048577, + 0x1e38, 1048577, + 0x1e3a, 1048577, + 0x1e3c, 1048577, + 0x1e3e, 1048577, + 0x1e40, 1048577, + 0x1e42, 1048577, + 0x1e44, 1048577, + 0x1e46, 1048577, + 0x1e48, 1048577, + 0x1e4a, 1048577, + 0x1e4c, 1048577, + 0x1e4e, 1048577, + 0x1e50, 1048577, + 0x1e52, 1048577, + 0x1e54, 1048577, + 0x1e56, 1048577, + 0x1e58, 1048577, + 0x1e5a, 1048577, + 0x1e5c, 1048577, + 0x1e5e, 1048577, + 0x1e60, 1048577, + 0x1e62, 1048577, + 0x1e64, 1048577, + 0x1e66, 1048577, + 0x1e68, 1048577, + 0x1e6a, 1048577, + 0x1e6c, 1048577, + 0x1e6e, 1048577, + 0x1e70, 1048577, + 0x1e72, 1048577, + 0x1e74, 1048577, + 0x1e76, 1048577, + 0x1e78, 1048577, + 0x1e7a, 1048577, + 0x1e7c, 1048577, + 0x1e7e, 1048577, + 0x1e80, 1048577, + 0x1e82, 1048577, + 0x1e84, 1048577, + 0x1e86, 1048577, + 0x1e88, 1048577, + 0x1e8a, 1048577, + 0x1e8c, 1048577, + 0x1e8e, 1048577, + 0x1e90, 1048577, + 0x1e92, 1048577, + 0x1e94, 1048577, + 0x1e9e, 1040961, + 0x1ea0, 1048577, + 0x1ea2, 1048577, + 0x1ea4, 1048577, + 0x1ea6, 1048577, + 0x1ea8, 1048577, + 0x1eaa, 1048577, + 0x1eac, 1048577, + 0x1eae, 1048577, + 0x1eb0, 1048577, + 0x1eb2, 1048577, + 0x1eb4, 1048577, + 0x1eb6, 1048577, + 0x1eb8, 1048577, + 0x1eba, 1048577, + 0x1ebc, 1048577, + 0x1ebe, 1048577, + 0x1ec0, 1048577, + 0x1ec2, 1048577, + 0x1ec4, 1048577, + 0x1ec6, 1048577, + 0x1ec8, 1048577, + 0x1eca, 1048577, + 0x1ecc, 1048577, + 0x1ece, 1048577, + 0x1ed0, 1048577, + 0x1ed2, 1048577, + 0x1ed4, 1048577, + 0x1ed6, 1048577, + 0x1ed8, 1048577, + 0x1eda, 1048577, + 0x1edc, 1048577, + 0x1ede, 1048577, + 0x1ee0, 1048577, + 0x1ee2, 1048577, + 0x1ee4, 1048577, + 0x1ee6, 1048577, + 0x1ee8, 1048577, + 0x1eea, 1048577, + 0x1eec, 1048577, + 0x1eee, 1048577, + 0x1ef0, 1048577, + 0x1ef2, 1048577, + 0x1ef4, 1048577, + 0x1ef6, 1048577, + 0x1ef8, 1048577, + 0x1efa, 1048577, + 0x1efc, 1048577, + 0x1efe, 1048577, + 0x1f59, 1048568, + 0x1f5b, 1048568, + 0x1f5d, 1048568, + 0x1f5f, 1048568, + 0x1fbc, 1048567, + 0x1fcc, 1048567, + 0x1fec, 1048569, + 0x1ffc, 1048567, + 0x2126, 1041059, + 0x212a, 1040193, + 0x212b, 1040314, + 0x2132, 1048604, + 0x2183, 1048577, + 0x2c60, 1048577, + 0x2c62, 1037833, + 0x2c63, 1044762, + 0x2c64, 1037849, + 0x2c67, 1048577, + 0x2c69, 1048577, + 0x2c6b, 1048577, + 0x2c6d, 1037796, + 0x2c6e, 1037827, + 0x2c6f, 1037793, + 0x2c70, 1037794, + 0x2c72, 1048577, + 0x2c75, 1048577, + 0x2c80, 1048577, + 0x2c82, 1048577, + 0x2c84, 1048577, + 0x2c86, 1048577, + 0x2c88, 1048577, + 0x2c8a, 1048577, + 0x2c8c, 1048577, + 0x2c8e, 1048577, + 0x2c90, 1048577, + 0x2c92, 1048577, + 0x2c94, 1048577, + 0x2c96, 1048577, + 0x2c98, 1048577, + 0x2c9a, 1048577, + 0x2c9c, 1048577, + 0x2c9e, 1048577, + 0x2ca0, 1048577, + 0x2ca2, 1048577, + 0x2ca4, 1048577, + 0x2ca6, 1048577, + 0x2ca8, 1048577, + 0x2caa, 1048577, + 0x2cac, 1048577, + 0x2cae, 1048577, + 0x2cb0, 1048577, + 0x2cb2, 1048577, + 0x2cb4, 1048577, + 0x2cb6, 1048577, + 0x2cb8, 1048577, + 0x2cba, 1048577, + 0x2cbc, 1048577, + 0x2cbe, 1048577, + 0x2cc0, 1048577, + 0x2cc2, 1048577, + 0x2cc4, 1048577, + 0x2cc6, 1048577, + 0x2cc8, 1048577, + 0x2cca, 1048577, + 0x2ccc, 1048577, + 0x2cce, 1048577, + 0x2cd0, 1048577, + 0x2cd2, 1048577, + 0x2cd4, 1048577, + 0x2cd6, 1048577, + 0x2cd8, 1048577, + 0x2cda, 1048577, + 0x2cdc, 1048577, + 0x2cde, 1048577, + 0x2ce0, 1048577, + 0x2ce2, 1048577, + 0x2ceb, 1048577, + 0x2ced, 1048577, + 0x2cf2, 1048577, + 0xa640, 1048577, + 0xa642, 1048577, + 0xa644, 1048577, + 0xa646, 1048577, + 0xa648, 1048577, + 0xa64a, 1048577, + 0xa64c, 1048577, + 0xa64e, 1048577, + 0xa650, 1048577, + 0xa652, 1048577, + 0xa654, 1048577, + 0xa656, 1048577, + 0xa658, 1048577, + 0xa65a, 1048577, + 0xa65c, 1048577, + 0xa65e, 1048577, + 0xa660, 1048577, + 0xa662, 1048577, + 0xa664, 1048577, + 0xa666, 1048577, + 0xa668, 1048577, + 0xa66a, 1048577, + 0xa66c, 1048577, + 0xa680, 1048577, + 0xa682, 1048577, + 0xa684, 1048577, + 0xa686, 1048577, + 0xa688, 1048577, + 0xa68a, 1048577, + 0xa68c, 1048577, + 0xa68e, 1048577, + 0xa690, 1048577, + 0xa692, 1048577, + 0xa694, 1048577, + 0xa696, 1048577, + 0xa698, 1048577, + 0xa69a, 1048577, + 0xa722, 1048577, + 0xa724, 1048577, + 0xa726, 1048577, + 0xa728, 1048577, + 0xa72a, 1048577, + 0xa72c, 1048577, + 0xa72e, 1048577, + 0xa732, 1048577, + 0xa734, 1048577, + 0xa736, 1048577, + 0xa738, 1048577, + 0xa73a, 1048577, + 0xa73c, 1048577, + 0xa73e, 1048577, + 0xa740, 1048577, + 0xa742, 1048577, + 0xa744, 1048577, + 0xa746, 1048577, + 0xa748, 1048577, + 0xa74a, 1048577, + 0xa74c, 1048577, + 0xa74e, 1048577, + 0xa750, 1048577, + 0xa752, 1048577, + 0xa754, 1048577, + 0xa756, 1048577, + 0xa758, 1048577, + 0xa75a, 1048577, + 0xa75c, 1048577, + 0xa75e, 1048577, + 0xa760, 1048577, + 0xa762, 1048577, + 0xa764, 1048577, + 0xa766, 1048577, + 0xa768, 1048577, + 0xa76a, 1048577, + 0xa76c, 1048577, + 0xa76e, 1048577, + 0xa779, 1048577, + 0xa77b, 1048577, + 0xa77d, 1013244, + 0xa77e, 1048577, + 0xa780, 1048577, + 0xa782, 1048577, + 0xa784, 1048577, + 0xa786, 1048577, + 0xa78b, 1048577, + 0xa78d, 1006296, + 0xa790, 1048577, + 0xa792, 1048577, + 0xa796, 1048577, + 0xa798, 1048577, + 0xa79a, 1048577, + 0xa79c, 1048577, + 0xa79e, 1048577, + 0xa7a0, 1048577, + 0xa7a2, 1048577, + 0xa7a4, 1048577, + 0xa7a6, 1048577, + 0xa7a8, 1048577, + 0xa7aa, 1006268, + 0xa7ab, 1006257, + 0xa7ac, 1006261, + 0xa7ad, 1006271, + 0xa7b0, 1006318, + 0xa7b1, 1006294, +}; + +} // !namespace + +auto tolower(char32_t c) noexcept -> char32_t +{ + const char32_t* p; + + p = search(c, tolowerr, nelem (tolowerr) / 3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = search(c, tolowers, nelem (tolowers) / 2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +namespace { + +const char32_t totitler[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, + 0x118c0, 0x118df, 1048544, +}; + +} // !namespace + +namespace { + +const char32_t totitles[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0101, 1048575, + 0x0103, 1048575, + 0x0105, 1048575, + 0x0107, 1048575, + 0x0109, 1048575, + 0x010b, 1048575, + 0x010d, 1048575, + 0x010f, 1048575, + 0x0111, 1048575, + 0x0113, 1048575, + 0x0115, 1048575, + 0x0117, 1048575, + 0x0119, 1048575, + 0x011b, 1048575, + 0x011d, 1048575, + 0x011f, 1048575, + 0x0121, 1048575, + 0x0123, 1048575, + 0x0125, 1048575, + 0x0127, 1048575, + 0x0129, 1048575, + 0x012b, 1048575, + 0x012d, 1048575, + 0x012f, 1048575, + 0x0131, 1048344, + 0x0133, 1048575, + 0x0135, 1048575, + 0x0137, 1048575, + 0x013a, 1048575, + 0x013c, 1048575, + 0x013e, 1048575, + 0x0140, 1048575, + 0x0142, 1048575, + 0x0144, 1048575, + 0x0146, 1048575, + 0x0148, 1048575, + 0x014b, 1048575, + 0x014d, 1048575, + 0x014f, 1048575, + 0x0151, 1048575, + 0x0153, 1048575, + 0x0155, 1048575, + 0x0157, 1048575, + 0x0159, 1048575, + 0x015b, 1048575, + 0x015d, 1048575, + 0x015f, 1048575, + 0x0161, 1048575, + 0x0163, 1048575, + 0x0165, 1048575, + 0x0167, 1048575, + 0x0169, 1048575, + 0x016b, 1048575, + 0x016d, 1048575, + 0x016f, 1048575, + 0x0171, 1048575, + 0x0173, 1048575, + 0x0175, 1048575, + 0x0177, 1048575, + 0x017a, 1048575, + 0x017c, 1048575, + 0x017e, 1048575, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0183, 1048575, + 0x0185, 1048575, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a1, 1048575, + 0x01a3, 1048575, + 0x01a5, 1048575, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b4, 1048575, + 0x01b6, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c4, 1048577, + 0x01c6, 1048575, + 0x01c7, 1048577, + 0x01c9, 1048575, + 0x01ca, 1048577, + 0x01cc, 1048575, + 0x01ce, 1048575, + 0x01d0, 1048575, + 0x01d2, 1048575, + 0x01d4, 1048575, + 0x01d6, 1048575, + 0x01d8, 1048575, + 0x01da, 1048575, + 0x01dc, 1048575, + 0x01dd, 1048497, + 0x01df, 1048575, + 0x01e1, 1048575, + 0x01e3, 1048575, + 0x01e5, 1048575, + 0x01e7, 1048575, + 0x01e9, 1048575, + 0x01eb, 1048575, + 0x01ed, 1048575, + 0x01ef, 1048575, + 0x01f1, 1048577, + 0x01f3, 1048575, + 0x01f5, 1048575, + 0x01f9, 1048575, + 0x01fb, 1048575, + 0x01fd, 1048575, + 0x01ff, 1048575, + 0x0201, 1048575, + 0x0203, 1048575, + 0x0205, 1048575, + 0x0207, 1048575, + 0x0209, 1048575, + 0x020b, 1048575, + 0x020d, 1048575, + 0x020f, 1048575, + 0x0211, 1048575, + 0x0213, 1048575, + 0x0215, 1048575, + 0x0217, 1048575, + 0x0219, 1048575, + 0x021b, 1048575, + 0x021d, 1048575, + 0x021f, 1048575, + 0x0223, 1048575, + 0x0225, 1048575, + 0x0227, 1048575, + 0x0229, 1048575, + 0x022b, 1048575, + 0x022d, 1048575, + 0x022f, 1048575, + 0x0231, 1048575, + 0x0233, 1048575, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0247, 1048575, + 0x0249, 1048575, + 0x024b, 1048575, + 0x024d, 1048575, + 0x024f, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x025c, 1090895, + 0x0260, 1048371, + 0x0261, 1090891, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0266, 1090884, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026c, 1090881, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0287, 1090858, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x029e, 1090834, + 0x0345, 1048660, + 0x0371, 1048575, + 0x0373, 1048575, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03d9, 1048575, + 0x03db, 1048575, + 0x03dd, 1048575, + 0x03df, 1048575, + 0x03e1, 1048575, + 0x03e3, 1048575, + 0x03e5, 1048575, + 0x03e7, 1048575, + 0x03e9, 1048575, + 0x03eb, 1048575, + 0x03ed, 1048575, + 0x03ef, 1048575, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f3, 1048460, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x0461, 1048575, + 0x0463, 1048575, + 0x0465, 1048575, + 0x0467, 1048575, + 0x0469, 1048575, + 0x046b, 1048575, + 0x046d, 1048575, + 0x046f, 1048575, + 0x0471, 1048575, + 0x0473, 1048575, + 0x0475, 1048575, + 0x0477, 1048575, + 0x0479, 1048575, + 0x047b, 1048575, + 0x047d, 1048575, + 0x047f, 1048575, + 0x0481, 1048575, + 0x048b, 1048575, + 0x048d, 1048575, + 0x048f, 1048575, + 0x0491, 1048575, + 0x0493, 1048575, + 0x0495, 1048575, + 0x0497, 1048575, + 0x0499, 1048575, + 0x049b, 1048575, + 0x049d, 1048575, + 0x049f, 1048575, + 0x04a1, 1048575, + 0x04a3, 1048575, + 0x04a5, 1048575, + 0x04a7, 1048575, + 0x04a9, 1048575, + 0x04ab, 1048575, + 0x04ad, 1048575, + 0x04af, 1048575, + 0x04b1, 1048575, + 0x04b3, 1048575, + 0x04b5, 1048575, + 0x04b7, 1048575, + 0x04b9, 1048575, + 0x04bb, 1048575, + 0x04bd, 1048575, + 0x04bf, 1048575, + 0x04c2, 1048575, + 0x04c4, 1048575, + 0x04c6, 1048575, + 0x04c8, 1048575, + 0x04ca, 1048575, + 0x04cc, 1048575, + 0x04ce, 1048575, + 0x04cf, 1048561, + 0x04d1, 1048575, + 0x04d3, 1048575, + 0x04d5, 1048575, + 0x04d7, 1048575, + 0x04d9, 1048575, + 0x04db, 1048575, + 0x04dd, 1048575, + 0x04df, 1048575, + 0x04e1, 1048575, + 0x04e3, 1048575, + 0x04e5, 1048575, + 0x04e7, 1048575, + 0x04e9, 1048575, + 0x04eb, 1048575, + 0x04ed, 1048575, + 0x04ef, 1048575, + 0x04f1, 1048575, + 0x04f3, 1048575, + 0x04f5, 1048575, + 0x04f7, 1048575, + 0x04f9, 1048575, + 0x04fb, 1048575, + 0x04fd, 1048575, + 0x04ff, 1048575, + 0x0501, 1048575, + 0x0503, 1048575, + 0x0505, 1048575, + 0x0507, 1048575, + 0x0509, 1048575, + 0x050b, 1048575, + 0x050d, 1048575, + 0x050f, 1048575, + 0x0511, 1048575, + 0x0513, 1048575, + 0x0515, 1048575, + 0x0517, 1048575, + 0x0519, 1048575, + 0x051b, 1048575, + 0x051d, 1048575, + 0x051f, 1048575, + 0x0521, 1048575, + 0x0523, 1048575, + 0x0525, 1048575, + 0x0527, 1048575, + 0x0529, 1048575, + 0x052b, 1048575, + 0x052d, 1048575, + 0x052f, 1048575, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e01, 1048575, + 0x1e03, 1048575, + 0x1e05, 1048575, + 0x1e07, 1048575, + 0x1e09, 1048575, + 0x1e0b, 1048575, + 0x1e0d, 1048575, + 0x1e0f, 1048575, + 0x1e11, 1048575, + 0x1e13, 1048575, + 0x1e15, 1048575, + 0x1e17, 1048575, + 0x1e19, 1048575, + 0x1e1b, 1048575, + 0x1e1d, 1048575, + 0x1e1f, 1048575, + 0x1e21, 1048575, + 0x1e23, 1048575, + 0x1e25, 1048575, + 0x1e27, 1048575, + 0x1e29, 1048575, + 0x1e2b, 1048575, + 0x1e2d, 1048575, + 0x1e2f, 1048575, + 0x1e31, 1048575, + 0x1e33, 1048575, + 0x1e35, 1048575, + 0x1e37, 1048575, + 0x1e39, 1048575, + 0x1e3b, 1048575, + 0x1e3d, 1048575, + 0x1e3f, 1048575, + 0x1e41, 1048575, + 0x1e43, 1048575, + 0x1e45, 1048575, + 0x1e47, 1048575, + 0x1e49, 1048575, + 0x1e4b, 1048575, + 0x1e4d, 1048575, + 0x1e4f, 1048575, + 0x1e51, 1048575, + 0x1e53, 1048575, + 0x1e55, 1048575, + 0x1e57, 1048575, + 0x1e59, 1048575, + 0x1e5b, 1048575, + 0x1e5d, 1048575, + 0x1e5f, 1048575, + 0x1e61, 1048575, + 0x1e63, 1048575, + 0x1e65, 1048575, + 0x1e67, 1048575, + 0x1e69, 1048575, + 0x1e6b, 1048575, + 0x1e6d, 1048575, + 0x1e6f, 1048575, + 0x1e71, 1048575, + 0x1e73, 1048575, + 0x1e75, 1048575, + 0x1e77, 1048575, + 0x1e79, 1048575, + 0x1e7b, 1048575, + 0x1e7d, 1048575, + 0x1e7f, 1048575, + 0x1e81, 1048575, + 0x1e83, 1048575, + 0x1e85, 1048575, + 0x1e87, 1048575, + 0x1e89, 1048575, + 0x1e8b, 1048575, + 0x1e8d, 1048575, + 0x1e8f, 1048575, + 0x1e91, 1048575, + 0x1e93, 1048575, + 0x1e95, 1048575, + 0x1e9b, 1048517, + 0x1ea1, 1048575, + 0x1ea3, 1048575, + 0x1ea5, 1048575, + 0x1ea7, 1048575, + 0x1ea9, 1048575, + 0x1eab, 1048575, + 0x1ead, 1048575, + 0x1eaf, 1048575, + 0x1eb1, 1048575, + 0x1eb3, 1048575, + 0x1eb5, 1048575, + 0x1eb7, 1048575, + 0x1eb9, 1048575, + 0x1ebb, 1048575, + 0x1ebd, 1048575, + 0x1ebf, 1048575, + 0x1ec1, 1048575, + 0x1ec3, 1048575, + 0x1ec5, 1048575, + 0x1ec7, 1048575, + 0x1ec9, 1048575, + 0x1ecb, 1048575, + 0x1ecd, 1048575, + 0x1ecf, 1048575, + 0x1ed1, 1048575, + 0x1ed3, 1048575, + 0x1ed5, 1048575, + 0x1ed7, 1048575, + 0x1ed9, 1048575, + 0x1edb, 1048575, + 0x1edd, 1048575, + 0x1edf, 1048575, + 0x1ee1, 1048575, + 0x1ee3, 1048575, + 0x1ee5, 1048575, + 0x1ee7, 1048575, + 0x1ee9, 1048575, + 0x1eeb, 1048575, + 0x1eed, 1048575, + 0x1eef, 1048575, + 0x1ef1, 1048575, + 0x1ef3, 1048575, + 0x1ef5, 1048575, + 0x1ef7, 1048575, + 0x1ef9, 1048575, + 0x1efb, 1048575, + 0x1efd, 1048575, + 0x1eff, 1048575, + 0x1f51, 1048584, + 0x1f53, 1048584, + 0x1f55, 1048584, + 0x1f57, 1048584, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c68, 1048575, + 0x2c6a, 1048575, + 0x2c6c, 1048575, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0x2c81, 1048575, + 0x2c83, 1048575, + 0x2c85, 1048575, + 0x2c87, 1048575, + 0x2c89, 1048575, + 0x2c8b, 1048575, + 0x2c8d, 1048575, + 0x2c8f, 1048575, + 0x2c91, 1048575, + 0x2c93, 1048575, + 0x2c95, 1048575, + 0x2c97, 1048575, + 0x2c99, 1048575, + 0x2c9b, 1048575, + 0x2c9d, 1048575, + 0x2c9f, 1048575, + 0x2ca1, 1048575, + 0x2ca3, 1048575, + 0x2ca5, 1048575, + 0x2ca7, 1048575, + 0x2ca9, 1048575, + 0x2cab, 1048575, + 0x2cad, 1048575, + 0x2caf, 1048575, + 0x2cb1, 1048575, + 0x2cb3, 1048575, + 0x2cb5, 1048575, + 0x2cb7, 1048575, + 0x2cb9, 1048575, + 0x2cbb, 1048575, + 0x2cbd, 1048575, + 0x2cbf, 1048575, + 0x2cc1, 1048575, + 0x2cc3, 1048575, + 0x2cc5, 1048575, + 0x2cc7, 1048575, + 0x2cc9, 1048575, + 0x2ccb, 1048575, + 0x2ccd, 1048575, + 0x2ccf, 1048575, + 0x2cd1, 1048575, + 0x2cd3, 1048575, + 0x2cd5, 1048575, + 0x2cd7, 1048575, + 0x2cd9, 1048575, + 0x2cdb, 1048575, + 0x2cdd, 1048575, + 0x2cdf, 1048575, + 0x2ce1, 1048575, + 0x2ce3, 1048575, + 0x2cec, 1048575, + 0x2cee, 1048575, + 0x2cf3, 1048575, + 0x2d27, 1041312, + 0x2d2d, 1041312, + 0xa641, 1048575, + 0xa643, 1048575, + 0xa645, 1048575, + 0xa647, 1048575, + 0xa649, 1048575, + 0xa64b, 1048575, + 0xa64d, 1048575, + 0xa64f, 1048575, + 0xa651, 1048575, + 0xa653, 1048575, + 0xa655, 1048575, + 0xa657, 1048575, + 0xa659, 1048575, + 0xa65b, 1048575, + 0xa65d, 1048575, + 0xa65f, 1048575, + 0xa661, 1048575, + 0xa663, 1048575, + 0xa665, 1048575, + 0xa667, 1048575, + 0xa669, 1048575, + 0xa66b, 1048575, + 0xa66d, 1048575, + 0xa681, 1048575, + 0xa683, 1048575, + 0xa685, 1048575, + 0xa687, 1048575, + 0xa689, 1048575, + 0xa68b, 1048575, + 0xa68d, 1048575, + 0xa68f, 1048575, + 0xa691, 1048575, + 0xa693, 1048575, + 0xa695, 1048575, + 0xa697, 1048575, + 0xa699, 1048575, + 0xa69b, 1048575, + 0xa723, 1048575, + 0xa725, 1048575, + 0xa727, 1048575, + 0xa729, 1048575, + 0xa72b, 1048575, + 0xa72d, 1048575, + 0xa72f, 1048575, + 0xa733, 1048575, + 0xa735, 1048575, + 0xa737, 1048575, + 0xa739, 1048575, + 0xa73b, 1048575, + 0xa73d, 1048575, + 0xa73f, 1048575, + 0xa741, 1048575, + 0xa743, 1048575, + 0xa745, 1048575, + 0xa747, 1048575, + 0xa749, 1048575, + 0xa74b, 1048575, + 0xa74d, 1048575, + 0xa74f, 1048575, + 0xa751, 1048575, + 0xa753, 1048575, + 0xa755, 1048575, + 0xa757, 1048575, + 0xa759, 1048575, + 0xa75b, 1048575, + 0xa75d, 1048575, + 0xa75f, 1048575, + 0xa761, 1048575, + 0xa763, 1048575, + 0xa765, 1048575, + 0xa767, 1048575, + 0xa769, 1048575, + 0xa76b, 1048575, + 0xa76d, 1048575, + 0xa76f, 1048575, + 0xa77a, 1048575, + 0xa77c, 1048575, + 0xa77f, 1048575, + 0xa781, 1048575, + 0xa783, 1048575, + 0xa785, 1048575, + 0xa787, 1048575, + 0xa78c, 1048575, + 0xa791, 1048575, + 0xa793, 1048575, + 0xa797, 1048575, + 0xa799, 1048575, + 0xa79b, 1048575, + 0xa79d, 1048575, + 0xa79f, 1048575, + 0xa7a1, 1048575, + 0xa7a3, 1048575, + 0xa7a5, 1048575, + 0xa7a7, 1048575, + 0xa7a9, 1048575, +}; + +} // !namespace + +auto totitle(char32_t c) noexcept -> char32_t +{ + const char32_t* p; + + p = search(c, totitler, nelem (totitler) / 3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = search(c, totitles, nelem (totitles) / 2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +void encode(char32_t c, char res[5]) noexcept +{ + switch (nbytes_point(c)) { + case 1: + res[0] = static_cast<char>(c); + res[1] = '\0'; + break; + case 2: + res[0] = 0xC0 | ((c >> 6) & 0x1F); + res[1] = 0x80 | (c & 0x3F); + res[2] = '\0'; + break; + case 3: + res[0] = 0xE0 | ((c >> 12) & 0xF ); + res[1] = 0x80 | ((c >> 6) & 0x3F); + res[2] = 0x80 | (c & 0x3F); + res[3] = '\0'; + break; + case 4: + res[0] = 0xF0 | ((c >> 18) & 0x7 ); + res[1] = 0x80 | ((c >> 12) & 0x3F); + res[2] = 0x80 | ((c >> 6) & 0x3F); + res[3] = 0x80 | (c & 0x3F); + res[4] = '\0'; + break; + default: + break; + } +} + +void decode(char32_t& c, const char* res) noexcept +{ + c = 0; + + switch (nbytes_utf8(res[0])) { + case 1: + c = res[0]; + break; + case 2: + c = (res[0] & 0x1f) << 6; + c |= (res[1] & 0x3f); + break; + case 3: + c = (res[0] & 0x0f) << 12; + c |= (res[1] & 0x3f) << 6; + c |= (res[2] & 0x3f); + break; + case 4: + c = (res[0] & 0x07) << 16; + c |= (res[1] & 0x3f) << 12; + c |= (res[2] & 0x3f) << 6; + c |= (res[3] & 0x3f); + default: + break; + } +} + +auto nbytes_utf8(char c) noexcept -> int +{ + if (static_cast<unsigned char>(c) <= 127) + return 1; + if ((c & 0xE0) == 0xC0) + return 2; + if ((c & 0xF0) == 0xE0) + return 3; + if ((c & 0xF8) == 0xF0) + return 4; + + return -1; +} + +auto nbytes_point(char32_t c) noexcept -> int +{ + if (c <= 0x7F) + return 1; + if (c <= 0x7FF) + return 2; + if (c <= 0xFFFF) + return 3; + if (c <= 0x1FFFFF) + return 4; + + return -1; +} + +auto length(std::string_view str) -> unsigned +{ + unsigned total = 0; + + for_each(str, [&] (auto) { + ++ total; + }); + + return total; +} + +auto to_utf8(std::u32string_view array) -> std::string +{ + std::string res; + + for (size_t i = 0; i < array.size(); ++i) { + char tmp[5]; + int size = nbytes_point(array[i]); + + if (size < 0) + throw std::invalid_argument("invalid sequence"); + + encode(array[i], tmp); + res.insert(res.length(), tmp); + } + + return res; +} + +auto to_utf32(std::string_view str) -> std::u32string +{ + std::u32string res; + + for_each(str, [&] (char32_t code) { + res.push_back(code); + }); + + return res; +} + +auto toupper(std::u32string_view str) -> std::u32string +{ + std::u32string res(str); + + for (size_t i = 0; i < str.size(); ++i) + res[i] = toupper(str[i]); + + return res; +} + +auto toupper(std::string_view str) -> std::string +{ + std::string res; + char buffer[5]; + + for_each(str, [&] (auto code) { + encode(toupper(code), buffer); + res += buffer; + }); + + return res; +} + +auto tolower(std::u32string_view str) -> std::u32string +{ + std::u32string ret(str); + + for (size_t i = 0; i < str.size(); ++i) + ret[i] = tolower(str[i]); + + return ret; +} + +auto tolower(std::string_view str) -> std::string +{ + std::string res; + char buffer[5]; + + for_each(str, [&] (auto code) { + encode(tolower(code), buffer); + res += buffer; + }); + + return res; +} + +} // !mlk::unicode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/unicode.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,236 @@ +/* + * unicode.hpp -- UTF-8 to UTF-32 conversions and various operations + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_CORE_UNICODE_HPP +#define MLK_CORE_UNICODE_HPP + +/** + * \file unicode.hpp + * \brief UTF-8 to UTF-32 conversions + * \author David Demelier <markand@malikania.fr> + * \warning These files are auto-generated! + */ + +#include <stdexcept> +#include <string> +#include <string_view> + +/** + * \brief Unicode namespace. + */ +namespace mlk::unicode { + +/** + * Encode the unicode code point into multibyte string. + * + * \param point the unicode code point + * \param res the output buffer + */ +void encode(char32_t point, char res[5]) noexcept; + +/** + * Decode the multibyte buffer into an unicode code point. + * + * \param c the code point destination + * \param res the multibyte string. + */ +void decode(char32_t& c, const char* res) noexcept; + +/** + * Get the number of bytes for the first multi byte character from a + * utf-8 string. + * + * This can be used to iterate a valid UTF-8 string to jump to the next + * real character. + * + * \param c the first multi byte character + * \return the number of bytes [1-4] or -1 if invalid + */ +auto nbytes_utf8(char c) noexcept -> int; + +/** + * Get the number of bytes for the unicode point. + * + * \param point the unicode point + * \return the number of bytes [1-4] or -1 if invalid + */ +auto nbytes_point(char32_t point) noexcept -> int; + +/** + * Get real number of character in a string. + * + * \param str the string + * \return the length + * \throw std::invalid_argument on invalid sequence + */ +auto length(std::string_view str) -> unsigned; + +/** + * Iterate over all real characters in the UTF-8 string. + * + * The function must have the following signature: + * void f(char ch) + * + * \param str the UTF-8 string + * \param function the function callback + * \throw std::invalid_argument on invalid sequence + */ +template <typename Func> +void for_each(std::string_view str, Func function) +{ + for (size_t i = 0; i < str.size(); ) { + char32_t point = 0; + int size = nbytes_utf8(str[i]); + + if (size < 0) + throw std::invalid_argument("invalid sequence"); + + decode(point, str.data() + i); + function(point); + + i += size; + } +} + +/** + * Convert a UTF-32 string to UTF-8 string. + * + * \param array the UTF-32 string + * \return the UTF-8 string + * \throw std::invalid_argument on invalid sequence + */ +auto to_utf8(std::u32string_view array) -> std::string; + +/** + * Convert a UTF-8 string to UTF-32 string. + * + * \param str the UTF-8 string + * \return the UTF-32 string + * \throw std::invalid_argument on invalid sequence + */ +auto to_utf32(std::string_view str) -> std::u32string; + +/** + * Check if the unicode character is space. + * + * \param c the character + * \return true if space + */ +auto isspace(char32_t c) noexcept -> bool; + +/** + * Check if the unicode character is digit. + * + * \param c the character + * \return true if digit + */ +auto isdigit(char32_t c) noexcept -> bool; + +/** + * Check if the unicode character is alpha category. + * + * \param c the character + * \return true if alpha + */ +auto isalpha(char32_t c) noexcept -> bool; + +/** + * Check if the unicode character is upper case. + * + * \param c the character + * \return true if upper case + */ +auto isupper(char32_t c) noexcept -> bool; + +/** + * Check if the unicode character is lower case. + * + * \param c the character + * \return true if lower case + */ +auto islower(char32_t c) noexcept -> bool; + +/** + * Check if the unicode character is title case. + * + * \param c the character + * \return true if title case + */ +auto istitle(char32_t c) noexcept -> bool; + +/** + * Convert to upper case. + * + * \param c the character + * \return the upper case character + */ +auto toupper(char32_t c) noexcept -> char32_t; + +/** + * Convert to lower case. + * + * \param c the character + * \return the lower case character + */ +auto tolower(char32_t c) noexcept -> char32_t; + +/** + * Convert to title case. + * + * \param c the character + * \return the title case character + */ +auto totitle(char32_t c) noexcept -> char32_t; + +/** + * Convert the UTF-32 string to upper case. + * + * \param str the string + * \return the upper case string + */ +auto toupper(std::u32string_view str) -> std::u32string; + +/** + * Convert the UTF-8 string to upper case. + * + * \param str the string + * \return the upper case string + * \warning very slow at the moment + */ +auto toupper(std::string_view str) -> std::string; + +/** + * Convert the UTF-32 string to lower case. + * + * \param str the string + * \return the lower case string + */ +auto tolower(std::u32string_view str) -> std::u32string; + +/** + * Convert the UTF-8 string to lower case. + * + * \param str the string + * \return the lower case string + * \warning very slow at the moment + */ +auto tolower(std::string_view str) -> std::string; + +} // !mlk::unicode + +#endif // !MLK_CORE_UNICODE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/util.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,443 @@ +/* + * util.cpp -- malikania utilities + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> +#include <climits> +#include <string> +#include <stdexcept> + +#if defined(__linux__) +# include <unistd.h> + +# include <cerrno> +# include <cstring> +# include <stdexcept> +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) +# if defined(__NetBSD__) +# include <sys/param.h> +# else +# include <sys/types.h> +# endif + +# if defined(__OpenBSD__) +# include <unistd.h> +# endif + +# include <sys/sysctl.h> + +# include <array> +# include <cerrno> +# include <climits> +# include <cstddef> +# include <cstdlib> +# include <cstring> +# include <stdexcept> +#elif defined(__APPLE__) +# include <cerrno> +# include <cstring> +# include <libproc.h> +# include <unistd.h> +#elif defined(_WIN32) +# include <Windows.h> +#endif + +#include <boost/filesystem.hpp> + +#include "util.hpp" +#include "size.hpp" + +namespace { + +#if defined(__linux__) + +std::string executable_path() +{ + std::string result; + + result.resize(2048, '\0'); + + auto size = readlink("/proc/self/exe", &result[0], 2048); + + if (size < 0) { + throw std::runtime_error(std::strerror(errno)); + } + + result.resize(size, '\0'); + + return result; +} + +#elif defined(__FreeBSD__) || defined(__DragonFly__) + +std::string executable_path() +{ + std::array<int, 4> mib{ { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 } }; + std::string result; + std::size_t size = PATH_MAX + 1; + + result.resize(size, '\0'); + + if (sysctl(mib.data(), 4, &result[0], &size, nullptr, 0) < 0) { + throw std::runtime_error(std::strerror(errno)); + } + + result.resize(size, '\0'); + + return result; +} + +#elif defined(__APPLE__) + +std::string executable_path() +{ + std::string result; + std::size_t size = PROC_PIDPATHINFO_MAXSIZE; + + result.resize(size, '\0'); + + if ((size = proc_pidpath(getpid(), &result[0], size)) == 0) { + throw std::runtime_error(std::strerror(errno)); + } + + result.resize(size, '\0'); + + return result; +} + +#elif defined(_WIN32) + +std::string executable_path() +{ + std::string result; + std::size_t size = PATH_MAX; + + result.resize(size, '\0'); + + if (!(size = GetModuleFileNameA(nullptr, &result[0], size))) { + throw std::runtime_error("GetModuleFileName error"); + } + + result.resize(size, '\0'); + + return result; +} + +#elif defined(__NetBSD__) + +std::string executable_path() +{ + std::string result; + +#if defined(KERN_PROC_PATHNAME) + std::array<int, 4> mib{ CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME }; + std::size_t size = MAXPATHLEN; + + result.resize(size, '\0'); + + if (sysctl(mib.data(), 4, &result[0], &size, nullptr, 0) < 0) { + throw std::runtime_error(std::strerror(errno)); + } + + result.resize(size, '\0'); +#else + result.resize(2048, '\0'); + + auto size = readlink("/proc/curproc/exe", &result[0], 2048); + + if (size < 0) { + throw std::runtime_error(std::strerror(errno)); + } + + result.resize(size, '\0'); +#endif + + return result; +} + +#elif defined(__OpenBSD__) + +std::string executable_path() +{ + char **paths, *path; + std::string result; + std::size_t len; + std::array<int, 4> mib{ CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; + + if (sysctl(mib.data(), 4, nullptr, &len, nullptr, 0) == -1) { + throw std::runtime_error(std::strerror(errno)); + } + if ((paths = static_cast<char **>(malloc(len))) == nullptr) { + throw std::runtime_error(std::strerror(errno)); + } + + sysctl(mib.data(), 4, paths, &len, nullptr, 0); + + if ((path = static_cast<char *>(std::malloc(PATH_MAX + 1))) == nullptr) { + std::free(paths); + throw std::runtime_error(std::strerror(errno)); + } + + realpath(paths[0], path); + result = path; + + std::free(paths); + std::free(path); + + return result; +} + +#else + +std::string executable_path() +{ + // Not supported. + return ""; +} + +#endif + +} // !namespace + +namespace mlk { + +namespace util { + +std::vector<std::string> split(const std::string &list, const std::string &delimiters, int max) +{ + std::vector<std::string> result; + std::size_t next = -1, current; + int count = 1; + bool finished = false; + + if (list.empty()) { + return result; + } + + do { + std::string val; + + current = next + 1; + next = list.find_first_of(delimiters, current); + + // split max, get until the end + if (max >= 0 && count++ >= max) { + val = list.substr(current, std::string::npos); + finished = true; + } else { + val = list.substr(current, next - current); + finished = next == std::string::npos; + } + + result.push_back(val); + } while (!finished); + + return result; +} + +std::string basedir() noexcept +{ + std::string result = "./"; + + try { + boost::filesystem::path tmp = executable_path(); + + tmp = tmp.parent_path(); // remove executable name + tmp = tmp.parent_path(); // remove "bin" + result = tmp.string(); + } catch (...) { + // TODO: add log. + } + + return result; +} + +/* + * json utilities + * ------------------------------------------------------------------ + */ + +namespace json { + +/* + * XXX: until json get a non-throwing function to check if a pointer exists, + * use this to check for a value at the given pointer or throw a + * property_error. + */ +nlohmann::json require(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer, + const nlohmann::json::value_t expected) +{ + assert(object.is_object()); + + nlohmann::json value; + + try { + value = object.at(pointer); + } catch (...) { + throw property_error(object, pointer, nlohmann::json::value_t::null, expected); + } + + if (value.type() != expected) { + throw property_error(object, pointer, value.type(), expected); + } + + return value; +} + +nlohmann::json get(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer, + const nlohmann::json::value_t expected, + const nlohmann::json def) +{ + assert(object.is_object()); + + nlohmann::json value; + + try { + value = object.at(pointer); + } catch (...) { + } + + if (value.type() != expected) + value = def; + + return value; +} + +nlohmann::json require_array(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer) +{ + return require(object, pointer, nlohmann::json::value_t::array); +} + +bool require_bool(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer) +{ + return require(object, pointer, nlohmann::json::value_t::boolean); +} + +int require_int(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer) +{ + nlohmann::json v; + + try { + v = object.at(pointer); + + if (v.is_number_integer()) + return v.get<int>(); + else if (v.is_number_unsigned() && v.get<unsigned>() <= static_cast<unsigned>(INT_MAX)) + return static_cast<int>(v.get<unsigned>()); + } catch (...) { + } + + throw property_error(object, pointer, v.type(), nlohmann::json::value_t::number_integer); +} + +nlohmann::json require_object(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer) +{ + return require(object, pointer, nlohmann::json::value_t::object); +} + +std::string require_string(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer) +{ + return require(object, pointer, nlohmann::json::value_t::string); +} + +unsigned require_uint(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer) +{ + nlohmann::json v; + + try { + v = object.at(pointer); + + if (v.is_number_unsigned()) + return v.get<unsigned>(); + else if (v.is_number_integer() && v.get<int>() >= 0) + return static_cast<unsigned>(v.get<int>()); + } catch (...) { + } + + throw property_error(object, pointer, v.type(), nlohmann::json::value_t::number_unsigned); +} + +mlk::size require_size(const nlohmann::json& object, + const nlohmann::json::json_pointer& index) +{ + using pointer = nlohmann::json::json_pointer; + + return { + require_uint(object, pointer(index.to_string() + "/width")), + require_uint(object, pointer(index.to_string() + "/height")) + }; +} + +int get_int(const nlohmann::json &object, + const nlohmann::json::json_pointer &pointer, + int value) noexcept +{ + try { + auto v = object.at(pointer); + + if (v.is_number_integer()) + value = v.get<int>(); + else if (v.is_number_unsigned() && v.get<unsigned>() <= static_cast<unsigned>(INT_MAX)) + value = static_cast<int>(v.get<unsigned>()); + } catch (...) { + } + + return value; +} + +unsigned get_uint(const nlohmann::json &object, + const nlohmann::json::json_pointer& pointer, + unsigned value) noexcept +{ + try { + auto v = object.at(pointer); + + if (v.is_number_unsigned()) + value = v.get<unsigned>(); + else if (v.is_number_integer() && v.get<int>() >= 0) + value = static_cast<unsigned>(v.get<int>()); + } catch (...) { + } + + return value; +} + +mlk::size get_size(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer, + const mlk::size& def) noexcept +{ + using json_pointer = nlohmann::json::json_pointer; + + return { + get_uint(object, json_pointer(pointer.to_string() + "/width"), def.width), + get_uint(object, json_pointer(pointer.to_string() + "/height"), def.height) + }; +} + +} // !json + +} // !util + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk/malikania/util.hpp Thu Oct 25 21:36:14 2018 +0200 @@ -0,0 +1,331 @@ +/* + * util.hpp -- malikania utilities + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_UTIL_HPP +#define MALIKANIA_UTIL_HPP + +/** + * \file util.hpp + * \brief Some utilities + */ + +#include <algorithm> +#include <exception> +#include <string> +#include <vector> + +#include "json.hpp" +#include "size.hpp" + +namespace mlk { + +/** + * \brief Utilities. + */ +namespace util { + +/** + * Split a line into a list of tokens. + * + * If max is less than 0, split as much as possible, otherwise split at most + * the number of specified tokens. + * + * \param line the line to split + * \param delim the list of delimiters allowed + * \param max the maximum number of tokens + * \return the list + */ +std::vector<std::string> split(const std::string& line, const std::string& delim, int max = -1); + +/** + * Get the base directory of the current executable. + * + * \return the base directory or empty if impossible to get + */ +std::string basedir() noexcept; + +/** + * Clamp the value between low and high. + * + * \param value the value + * \param low the minimum value + * \param high the maximum value + * \return the value between minimum and maximum + */ +template <typename T> +constexpr T clamp(T value, T low, T high) noexcept +{ + return (value < high) ? std::max(value, low) : std::min(value, high); +} + +/** + * \brief Utilities for networking. + */ +namespace net { + +/** + * Shortcut for util::split(line, " ", max); + * + * \param line the line + * \param max the maximum of tokens to split + * \return the list + */ +inline std::vector<std::string> split(const std::string& line, int max = -1) +{ + return util::split(line, " ", max); +} + +} // !net + +namespace json { + +/** + * \brief Indicates a property error in an object. + */ +class property_error : public std::exception { +private: + nlohmann::json m_object; + nlohmann::json::json_pointer m_pointer; + nlohmann::json::value_t m_type; + nlohmann::json::value_t m_expected; + std::string m_message; + +public: + /** + * Construct the property error. + * + * \param object the faulty object + * \param pointer the property path + * \param type the found type + * \param expected the expected type + */ + inline property_error(nlohmann::json object, + nlohmann::json::json_pointer pointer, + nlohmann::json::value_t type, + nlohmann::json::value_t expected) noexcept + : m_object(std::move(object)) + , m_pointer(std::move(pointer)) + , m_type(type) + , m_expected(expected) + { + m_message += "invalid '" + m_pointer.to_string() + "' property "; + m_message += "(" + nlohmann::json(expected).type_name(); + m_message += " expected, got "; + m_message += nlohmann::json(type).type_name() + ")"; + } + + /** + * Get the faulty object. + * + * return the object + */ + inline const nlohmann::json& object() const noexcept + { + return m_object; + } + + /** + * Get the pointer to the property. + * + * \return the pointer + */ + inline const nlohmann::json::json_pointer& pointer() const noexcept + { + return m_pointer; + } + + /** + * Get the actual type. + * + * \return the type + */ + inline nlohmann::json::value_t type() const noexcept + { + return m_type; + } + + /** + * Get the expected type. + * + * \return the type + */ + inline nlohmann::json::value_t expected() const noexcept + { + return m_expected; + } + + /** + * Get a human formatted message. + * + * \return the message + */ + const char* what() const noexcept + { + return m_message.c_str(); + } +}; + +/** + * Require a value at the given pointer, if the value does not match the + * expected type, an exception is thrown. + * + * If the property does not exists, a property_error with a null found type is + * thrown. + * + * \pre object.is_object() + * \param object the object + * \param pointer the pointer to the property + * \param expected the expected type + * \throw property_error on errors + */ +nlohmann::json require(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer, + const nlohmann::json::value_t expected); + +/** + * Require an array at the given pointer. + * + * \pre object.is_object() + * \param object the object + * \param pointer the pointer to the property + * \return the value + * \throw property_error on errors + */ +nlohmann::json require_array(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer); + +/** + * Require a boolean at the given pointer. + * + * \pre object.is_object() + * \param object the object + * \param pointer the pointer to the property + * \return the value + * \throw property_error on errors + */ +bool require_bool(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer); + +/** + * Require an integer at the given pointer. + * + * \pre object.is_object() + * \param object the object + * \param pointer the pointer to the property + * \return the value + * \throw property_error on errors + */ +int require_int(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer); + +/** + * Require an object at the given pointer. + * + * \pre object.is_object() + * \param object the object + * \param pointer the pointer to the property + * \return the value + * \throw property_error on errors + */ +nlohmann::json require_object(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer); + +/** + * Require a string at the given pointer. + * + * \pre object.is_object() + * \param object the object + * \param pointer the pointer to the property + * \return the value + * \throw property_error on errors + */ +std::string require_string(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer); + +/** + * Require an unsigned integer at the given pointer. + * + * \pre object.is_object() + * \param object the object + * \param pointer the pointer to the property + * \return the value + * \throw property_error on errors + */ +unsigned require_uint(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer); + +/** + * Require a size object at the given pointer. + * + * \pre object.is_object + * \param object the json object + * \param pointer the pointer to the property + * \return the value + * \throw property_error on errors + */ +mlk::size require_size(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer); + +/** + * Get an integer at the given pointer or default value if not present or + * invalid. + * + * \pre object.is_object + * \param object the json object + * \param pointer the pointer to the property + * \param def the default value + * \return an integer + */ +int get_int(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer, + int def = 0) noexcept; + +/** + * Get an unsigned integer at the given pointer or default value if not present + * or invalid. + * + * \pre object.is_object + * \param object the json object + * \param pointer the pointer to the property + * \param def the default value + * \return an integer + */ +unsigned get_uint(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer, + unsigned def = 0) noexcept; + +/** + * Get a size object at the given pointer or a default value. + * + * \pre object.is_object + * \param object the json object + * \param pointer the pointer to the property + * \param def the default value to return in case of error + * \return a size or a default value + */ +mlk::size get_size(const nlohmann::json& object, + const nlohmann::json::json_pointer& pointer, + const mlk::size& def = {}) noexcept; + +} // !json + +} // !util + +} // !mlk + +#endif // !MALIKANIA_UTIL_HPP
--- a/libserver/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -# -# CMakeLists.txt -- CMake build system for malikania -# -# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(libmlk-server) - -find_package(Threads REQUIRED) - -set( - HEADERS - ${libmlk-server_SOURCE_DIR}/malikania/server/client.hpp - ${libmlk-server_SOURCE_DIR}/malikania/server/net/auth_handler.hpp - ${libmlk-server_SOURCE_DIR}/malikania/server/server.hpp -) - -set( - SOURCES - ${libmlk-server_SOURCE_DIR}/malikania/server/client.cpp - ${libmlk-server_SOURCE_DIR}/malikania/server/net/auth_handler.cpp - ${libmlk-server_SOURCE_DIR}/malikania/server/server.cpp -) - -set( - LIBRARIES - OpenSSL::Crypto - OpenSSL::SSL - Threads::Threads - libmlk-common - libmlk-db -) - -if (CMAKE_SYSTEM_NAME MATCHES Windows) - list(APPEND LIBRARIES mswsock) -endif () - -malikania_define_library( - TARGET libmlk-server - SOURCES ${HEADERS} ${SOURCES} - LIBRARIES ${LIBRARIES} - PUBLIC_INCLUDES - ${libmlk-server_SOURCE_DIR} - PRIVATE_INCLUDES - ${libmlk-server_SOURCE_DIR}/malikania/server -)
--- a/libserver/malikania/server/client.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* - * client.cpp -- client connected to the server - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cassert> -#include <iostream> - -#include "client.hpp" -#include "server.hpp" - -namespace mlk::server { - -void client::handle_read(std::error_code code, std::size_t xfer) -{ - // TODO: use fixed size stream + verify exceed. - if (code) - server_.handle_disconnect(shared_from_this()); - else { - std::string message( - boost::asio::buffers_begin(input_.data()), - boost::asio::buffers_begin(input_.data()) + xfer - 4 - ); - - // Remove early in case of errors. - input_.consume(xfer); - - try { - server_.handle_read(shared_from_this(), nlohmann::json::parse(message)); - } catch (const std::exception& ex) { - std::cerr << ex.what() << std::endl; - } - - do_read(); - } -} - -void client::handle_write(std::error_code code, std::size_t) -{ - if (code) { - server_.handle_disconnect(shared_from_this()); - } else { - output_.pop_front(); - - if (!output_.empty()) { - do_write(); - } else if (state_ == state::closing) { - server_.handle_disconnect(shared_from_this()); - } - } -} - -void client::do_read() -{ - const auto self = shared_from_this(); - - boost::asio::async_read_until(socket_, input_, "\r\n\r\n", [self] (auto code, auto xfer) { - self->handle_read(code, xfer); - }); -} - -void client::do_write() -{ - assert(!output_.empty()); - - const auto self = shared_from_this(); - - boost::asio::async_write(socket_, boost::asio::buffer(output_[0]), [self] (auto code, auto xfer) { - self->handle_write(code, xfer); - }); -} - -void client::handshake() -{ - const auto self = shared_from_this(); - - socket_.async_handshake(boost::asio::ssl::stream_base::server, [self] (auto code) { - if (code) { - std::cerr << "handshake failure: " << code << std::endl; - } else { - self->read(); - } - }); -} - -void client::read() -{ - do_read(); -} - -client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context) - : server_(server) - , socket_(service, context) -{ -} - -auto client::get_state() const noexcept -> state -{ - return state_; -} - -void client::set_state(state state) noexcept -{ - state_ = state; -} - -auto client::get_account() const noexcept -> const db::account& -{ - assert(state_ == state::ready); - - return *account_; -} - -auto client::get_account() noexcept -> db::account& -{ - assert(state_ == state::ready); - - return *account_; -} - -void client::set_account(db::account account) noexcept -{ - account_ = std::move(account); -} - -void client::send(nlohmann::json message) -{ - assert(message.is_object()); - - if (state_ == state::closing) { - return; - } - - const auto in_progress = !output_.empty(); - - output_.push_back(message.dump() + "\r\n\r\n"); - - if (!in_progress) { - do_write(); - } -} - -void client::ok(std::string cmd, nlohmann::json message) -{ - assert(message.is_null() || message.is_object()); - - if (!message.is_object()) { - message = nlohmann::json::object(); - } - - message["command"] = std::move(cmd); - message["status"] = true; - - send(std::move(message)); -} - -void client::error(std::string cmd, std::error_code code) -{ - send({ - { "command", std::move(cmd) }, - { "status", code.value() }, - { "error", code.message() } - }); -} - -void client::fatal(std::string cmd, std::error_code code) -{ - error(std::move(cmd), std::move(code)); - state_ = state::closing; -} - -} // !mlk::server
--- a/libserver/malikania/server/client.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ -/* - * client.hpp -- client connected to the server - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_SERVER_CLIENT_HPP -#define MALIKANIA_SERVER_CLIENT_HPP - -/** - * \file client.hpp - * \brief Client connected to the server. - */ - -#include <cstdint> -#include <deque> -#include <memory> -#include <optional> -#include <sstream> -#include <string> -#include <system_error> - -#include <boost/asio.hpp> -#include <boost/asio/ssl.hpp> - -#include <json.hpp> - -#include "db/account.hpp" - -namespace mlk::server { - -class server; - -/** - * \brief Client connected to the server. - */ -class client : public std::enable_shared_from_this<client> { -public: - friend class server; - - /** - * \brief Describe client current state - */ - enum class state : std::uint8_t { - /** - * The client is authenticating. - */ - authenticating, - - /** - * The client is ready for I/O - */ - ready, - - /** - * The client is closing. - * - * No more messages are accepted for output, the pending queue is sent - * to the client and then disconnected. - */ - closing - }; - -private: - server& server_; - state state_{state::authenticating}; - - boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; - boost::asio::streambuf input_; - std::deque<std::string> output_; - std::optional<db::account> account_; - - void handle_read(std::error_code, std::size_t); - void handle_write(std::error_code, std::size_t); - - void do_read(); - void do_write(); - - void handshake(); - void read(); - -public: - /** - * Create the client in the associated server. - * - * \param server the server object - * \param service the main loop service - * \param context the ssl context - */ - client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context); - - /** - * Get the client state. - * - * \return the state - */ - auto get_state() const noexcept -> state; - - /** - * Set the client state. - * - * \param new_state the state - */ - void set_state(state state) noexcept; - - /** - * Get the underlying account database object. - * - * \pre get_state() == ready - * \return the account - */ - auto get_account() const noexcept -> const db::account&; - - /** - * Overloaded function. - * - * \pre get_state() == ready - * \return the account - */ - auto get_account() noexcept -> db::account&; - - /** - * Set the client account. - * - * \param account the account - */ - void set_account(db::account account) noexcept; - - /** - * Send a command and its arguments. - * - * \pre !cmd.empty() - * \param message the message to send - */ - void send(nlohmann::json message); - - /** - * Send successful command result. - * - * \pre !cmd.empty() - * \pre args.is_object() || args.is_object() - * \param cmd the command name - * \param args the extra data - */ - void ok(std::string cmd, nlohmann::json args = nullptr); - - /** - * Send a error command result. - * - * \pre !cmd.empty() - * \pre code - * \param cmd the command name - * \param code the error code - */ - void error(std::string cmd, std::error_code code); - - /** - * Send a fatal error result. - * - * The client state is changed to closing. - * - * \pre !cmd.empty() - * \pre code - * \param cmd the command name - * \param code the error code - */ - void fatal(std::string cmd, std::error_code code); -}; - -} // !mlk::server - -#endif // !MALIKANIA_SERVER_CLIENT_HPP
--- a/libserver/malikania/server/hash.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,262 +0,0 @@ -/* - * hash.hpp -- hash functions - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_SERVER_HASH_HPP -#define MALIKANIA_SERVER_HASH_HPP - -/** - * \file hash.hpp - * \brief Hash functions. - * \author David Demelier <markand@malikania.fr> - */ - -/** - * \brief Define buffer size. - */ -#if !defined(HASH_BUFFER_SIZE) -# define HASH_BUFFER_SIZE 2048 -#endif - -#include <cassert> -#include <istream> -#include <iterator> -#include <sstream> -#include <string> - -#include <openssl/sha.h> -#include <openssl/md5.h> - -/** - * \brief Hash namespace. - */ -namespace hash { - -/** - * \cond HASH_HIDDEN_SYMBOLS - */ - -namespace detail { - -template <typename Context> -using init_func = int (*)(Context *); - -template <typename Context> -using update_func = int (*)(Context *, const void *, size_t); - -template <typename Context> -using final_func = int (*)(unsigned char *, Context *); - -template <typename Context, size_t Length, typename InputIt> -inline std::string convert(InputIt it, - InputIt end, - init_func<Context> init, - update_func<Context> update, - final_func<Context> finalize) -{ - unsigned char digest[Length] = { 0 }; - char hash[Length * 2 + 1]; - char buf[HASH_BUFFER_SIZE]; - - Context ctx; - init(&ctx); - - while (it != end) { - unsigned i; - - for (i = 0; it != end && i < HASH_BUFFER_SIZE; ++i) { - buf[i] = *it++; - } - - update(&ctx, buf, i); - } - - finalize(digest, &ctx); - - for (unsigned long i = 0; i < Length; i++) { - std::snprintf(&hash[i * 2], 2 + 1, "%02x", static_cast<unsigned>(digest[i])); - } - - return std::string(hash); -} - -} // !namespace - -/** - * \endcond - */ - -/** - * \brief The scheme to use. - */ -enum class scheme { - md5, //!< MD5 - sha1, //!< SHA-1 - sha256, //!< SHA-256 - sha512 //!< SHA-512 -}; - -/** - * Generic function. - * - * \param scheme the scheme to use - * \param it the first character - * \param end the last character - * \return the string - */ -template <typename InputIt> -inline std::string to_string(scheme scheme, InputIt it, InputIt end) -{ - assert(scheme >= scheme::md5 && scheme <= scheme::sha512); - - std::string result; - - switch (scheme) { - case scheme::md5: - result = detail::convert<MD5_CTX, MD5_DIGEST_LENGTH>(it, end, MD5_Init, MD5_Update, MD5_Final); - break; - case scheme::sha1: - result = detail::convert<SHA_CTX, SHA_DIGEST_LENGTH>(it, end, SHA1_Init, SHA1_Update, SHA1_Final);; - break; - case scheme::sha256: - result = detail::convert<SHA256_CTX, SHA256_DIGEST_LENGTH>(it, end, SHA256_Init, SHA256_Update, SHA256_Final); - break; - case scheme::sha512: - result = detail::convert<SHA512_CTX, SHA512_DIGEST_LENGTH>(it, end, SHA512_Init, SHA512_Update, SHA512_Final); - break; - default: - break; - } - - return result; -} - -/** - * Overload for std::istream. - * - * \param scheme the scheme to use - * \param input the input stream - * \return the string - */ -inline std::string to_string(scheme scheme, std::istream &input) -{ - return to_string(scheme, std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>()); -} - -/** - * Overload for std::string. - * - * \param scheme the scheme to use - * \param input the input stream - * \return the string - */ -inline std::string to_string(scheme scheme, const std::string &input) -{ - return to_string(scheme, input.begin(), input.end()); -} - -/** - * Hash using MD5. - * - * \param input the input string - * \return the hashed string - */ -inline std::string md5(const std::string &input) -{ - return to_string(scheme::md5, input); -} - -/** - * Hash using MD5. - * - * \param input the input stream - * \return the hashed string - */ -inline std::string md5(std::istream &input) -{ - return to_string(scheme::md5, input); -} - -/** - * Hash using SHA1. - * - * \param input the input string - * \return the hashed string - */ -inline std::string sha1(const std::string &input) -{ - return to_string(scheme::sha1, input); -} - -/** - * Hash using SHA1. - * - * \param input the input stream - * \return the hashed string - */ -inline std::string sha1(std::istream &input) -{ - return to_string(scheme::sha1, input); -} - -/** - * Hash using SHA256. - * - * \param input the input string - * \return the hashed string - */ -inline std::string sha256(const std::string &input) -{ - return to_string(scheme::sha256, input); -} - -/** - * Hash using SHA256. - * - * \param input the input stream - * \return the hashed string - */ -inline std::string sha256(std::istream &input) -{ - return to_string(scheme::sha256, input); -} - -/** - * Hash using SHA512. - * - * \param input the input string - * \return the hashed string - */ -inline std::string sha512(const std::string &input) -{ - return to_string(scheme::sha512, input); -} - -/** - * Hash using SHA512. - * - * \param input the input stream - * \return the hashed string - */ -inline std::string sha512(std::istream &input) -{ - return to_string(scheme::sha512, input); -} - -} // !hash - -#endif // !MALIKANIA_SERVER_HASH_HPP
--- a/libserver/malikania/server/net/auth_handler.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * auth_handler.cpp -- handle "auth" network command - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <util.hpp> - -#include <malikania/error/auth_error.hpp> - -#include "db/account.hpp" - -#include "auth_handler.hpp" -#include "client.hpp" -#include "server.hpp" - -namespace mlk::server { - -namespace { - -auto is_connected(const server& server, const db::account& account) noexcept -> bool -{ - const auto& clients = server.get_clients(); - const auto it = std::find_if(clients.begin(), clients.end(), [&] (const auto& c) { - if (c->get_state() != client::state::ready) - return false; - - return c->get_account().get_login() == account.get_login(); - }); - - return it != clients.end(); -} - -} // !namespace - -void auth_handler::exec(server& server, client& clt, nlohmann::json object) noexcept -{ - auto ac = db::account::authenticate( - util::json::require_string(object, "/login"_json_pointer), - util::json::require_string(object, "/password"_json_pointer) - ); - - if (!ac) - clt.fatal("auth", auth_error::invalid_credentials); - else if (is_connected(server, *ac)) - clt.fatal("auth", auth_error::already_connected); - else { - clt.set_account(std::move(*ac)); - clt.set_state(client::state::ready); - clt.ok("auth"); - } -} - -} // !mlk::server
--- a/libserver/malikania/server/net/auth_handler.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * auth_handler.hpp -- handle "auth" network command - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_SERVER_AUTH_HANDLER_HPP -#define MALIKANIA_SERVER_AUTH_HANDLER_HPP - -/** - * \file auth_handler.hpp - * \brief Handle "auth" network command. - */ - -#include "handler.hpp" - -namespace mlk::server { - -/** - * \brief Handle "auth" network command. - */ -class auth_handler : public handler { -public: - /** - * \copydoc handler::exec - */ - void exec(server& server, client& clt, nlohmann::json object) noexcept override; -}; - -} // !mlk::server - -#endif // !MALIKANIA_SERVER_AUTH_HANDLER_HPP
--- a/libserver/malikania/server/net/handler.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * handler.hpp -- server side remote command - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_SERVER_HANDLER_HPP -#define MALIKANIA_SERVER_HANDLER_HPP - -/** - * \file handler.hpp - * \brief Server side remote command. - */ - -#include <memory> - -#include <json.hpp> - -namespace mlk::server { - -class server; -class client; - -/** - * \brief Server side remote command. - */ -class handler { -public: - /** - * Default constructor. - */ - handler() noexcept = default; - - /** - * Virtual destructor defaulted. - */ - virtual ~handler() noexcept = default; - - /** - * Execute the function from the given client. - * - * \param server the global object server - * \param client the client - * \param message the network message - */ - virtual void exec(server& server, client& client, nlohmann::json message) noexcept = 0; -}; - -} // !mlk::server - -#endif // !MALIKANIA_SERVER_HANDLER_HPP
--- a/libserver/malikania/server/server.cpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * server.cpp -- malikania basic server - * - * Copyright (c) 2016-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "client.hpp" -#include "server.hpp" -#include "util.hpp" - -#include "net/auth_handler.hpp" - -namespace mlk::server { - -namespace { - -auto endpoint(const settings& params) -> boost::asio::ip::tcp::endpoint -{ - // TODO: add more settings there. - return boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), params.port); -} - -} // !namespace - -void server::load() -{ - handle("auth", std::make_unique<auth_handler>()); -} - -void server::start() -{ - auto clt = std::make_shared<client>(*this, service_, context_); - - acceptor_.async_accept(clt->socket_.lowest_layer(), [this, clt] (auto code) { - handle_accept(std::move(clt), code); - }); -} - -server::server(boost::asio::io_service& service, const settings& settings) - : service_(service) - , acceptor_(service, endpoint(settings)) - , context_(boost::asio::ssl::context::sslv23) -{ - context_.use_certificate_chain_file(settings.certificate); - context_.use_private_key_file(settings.key, boost::asio::ssl::context::pem); - - load(); - start(); -} - -auto server::get_clients() const noexcept -> const clients& -{ - return clients_; -} - -auto server::get_clients() noexcept -> clients& -{ - return clients_; -} - -void server::handle(std::string name, std::unique_ptr<handler> handler) -{ - assert(!name.empty()); - assert(handler); - - commands_.emplace(std::move(name), std::move(handler)); -} - -void server::handle_disconnect(std::shared_ptr<client> clt) -{ - clients_.erase(std::move(clt)); -} - -void server::handle_read(std::shared_ptr<client> clt, nlohmann::json message) -{ - assert(message.is_object()); - - const auto cmd = message.find("command"); - - if (cmd == message.end() || !cmd->is_string()) { - // TODO: log error. - return; - } - - const auto it = commands_.find(*cmd); - - if (it == commands_.end()) { - // TODO: log error. - return; - } - - try { - it->second->exec(*this, *clt, std::move(message)); - } catch (const std::exception&) { - // TODO: log error. - } -} - -void server::handle_accept(std::shared_ptr<client> clt, std::error_code code) -{ - if (code) { - // TODO: log error. - } else { - clt->handshake(); - clients_.insert(std::move(clt)); - } - - start(); -} - -} // !mlk::server
--- a/libserver/malikania/server/server.hpp Wed Oct 24 21:13:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* - * server.hpp -- malikania basic server - * - * Copyright (c) 2016-2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MALIKANIA_SERVER_SERVER_HPP -#define MALIKANIA_SERVER_SERVER_HPP - -/** - * \file server.hpp - * \brief Malikania basic server. - */ - -#include <cstdint> -#include <memory> -#include <string> -#include <unordered_map> -#include <unordered_set> -#include <system_error> - -#include <boost/asio.hpp> -#include <boost/asio/ssl.hpp> - -#include <json.hpp> - -#include "net/handler.hpp" - -namespace mlk::server { - -class client; -class database; - -/** - * \brief Server parameters - */ -struct settings { - std::uint16_t port{3320}; - std::string certificate; - std::string key; -}; - -/** - * \file server.hpp - * \brief Malikania basic server. - */ -class server { -public: - using clients = std::unordered_set<std::shared_ptr<client>>; - using commands = std::unordered_map<std::string, std::unique_ptr<handler>>; - -private: - boost::asio::io_service& service_; - boost::asio::ip::tcp::acceptor acceptor_; - boost::asio::ssl::context context_; - - clients clients_; - commands commands_; - - void load(); - void start(); - -public: - /** - * Construct a server object. - * - * \param ctx the IO context - * \param settings the settings - */ - server(boost::asio::io_service& service, const settings& settings); - - /** - * Get the set of connected clients. - * - * \return the clients - */ - auto get_clients() const noexcept -> const clients&; - - /** - * Overloaded function. - * - * \return the clients - */ - auto get_clients() noexcept -> clients&; - - /** - * Add network handler. - * - * If a handler is already present, it will be replaced with the new one. - * - * \pre handler != nullptr - * \pre !name.empty() - * \param handler the handler - */ - void handle(std::string name, std::unique_ptr<handler> handler); - - /** - * Handle client disconnection. - * - * \param client the client - */ - virtual void handle_disconnect(std::shared_ptr<client> client); - - /** - * Asynchronous function called once a message has been completely and - * successfully received from the client. - * - * The default implementation searches for a handler defined for this - * message. - * - * \param client the client - * \param message the message received - */ - virtual void handle_read(std::shared_ptr<client>, nlohmann::json message); - - /** - * Handle accept of a new client. - * - * \param client the newly received client - * \param code the error code if any - */ - virtual void handle_accept(std::shared_ptr<client> client, std::error_code code); -}; - -} // !mlk - -#endif // !MALIKANIA_SERVER_SERVER_HPP
--- a/tests/libclient/js-color/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libclient/js-color/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -54,7 +54,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 0); BOOST_TEST(component(ctx_, "g") == 0); @@ -73,7 +73,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 255); BOOST_TEST(component(ctx_, "g") == 255); @@ -92,7 +92,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 0); BOOST_TEST(component(ctx_, "g") == 0); @@ -111,7 +111,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 10); BOOST_TEST(component(ctx_, "g") == 20); @@ -130,7 +130,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 10); BOOST_TEST(component(ctx_, "g") == 20); @@ -149,7 +149,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 10); BOOST_TEST(component(ctx_, "g") == 20); @@ -168,7 +168,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 10); BOOST_TEST(component(ctx_, "g") == 20); @@ -191,7 +191,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); BOOST_TEST(component(ctx_, "r") == 10); BOOST_TEST(component(ctx_, "g") == 20); @@ -220,7 +220,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -242,7 +242,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -268,7 +268,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -290,7 +290,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -312,7 +312,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -334,7 +334,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -356,7 +356,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -380,7 +380,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "Error"); @@ -402,7 +402,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "Error"); @@ -428,7 +428,7 @@ BOOST_AUTO_TEST_CASE(success) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto color = duk::require<mlk::client::color>(ctx, 0); + const auto color = mlk::js::duk::require<mlk::client::color>(ctx, 0); duk_push_uint(ctx, color.red); duk_put_global_string(ctx, "r"); @@ -446,7 +446,7 @@ const auto ret = duk_peval_string(ctx_, "draw('#ff0000');"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "r"); BOOST_TEST(duk_to_uint(ctx_, -1) == 255U); @@ -465,7 +465,7 @@ BOOST_AUTO_TEST_CASE(fail) { duk_push_c_function(ctx_, [] (auto ctx) { - duk::require<mlk::client::color>(ctx, 0); + mlk::js::duk::require<mlk::client::color>(ctx, 0); return 0; }, 1); @@ -481,7 +481,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "Error"); @@ -498,7 +498,7 @@ BOOST_AUTO_TEST_CASE(fail_alpha) { duk_push_c_function(ctx_, [] (auto ctx) { - duk::require<mlk::client::color>(ctx, 0); + mlk::js::duk::require<mlk::client::color>(ctx, 0); return 0; }, 1); @@ -514,7 +514,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -540,7 +540,7 @@ BOOST_AUTO_TEST_CASE(normal) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto color = duk::get<mlk::client::color>(ctx, 0); + const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0); duk_push_uint(ctx, color.red); duk_put_global_string(ctx, "r"); @@ -558,7 +558,7 @@ const auto ret = duk_peval_string(ctx_, "draw('#ff0000');"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "r"); BOOST_TEST(duk_to_uint(ctx_, -1) == 255U); @@ -577,7 +577,7 @@ BOOST_AUTO_TEST_CASE(adjust_rgb) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto color = duk::get<mlk::client::color>(ctx, 0); + const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0); duk_push_uint(ctx, color.red); duk_put_global_string(ctx, "r"); @@ -595,7 +595,7 @@ const auto ret = duk_peval_string(ctx_, "draw('#ghijkl');"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "r"); BOOST_TEST(duk_to_uint(ctx_, -1) == 0U); @@ -616,7 +616,7 @@ BOOST_AUTO_TEST_CASE(adjust_all) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto color = duk::get<mlk::client::color>(ctx, 0); + const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0); duk_push_uint(ctx, color.red); duk_put_global_string(ctx, "r"); @@ -634,7 +634,7 @@ const auto ret = duk_peval_string(ctx_, "draw({ red: -1, green: 256, blue: 100, alpha: 800 });"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "r"); BOOST_TEST(duk_to_uint(ctx_, -1) == 0U); @@ -655,7 +655,7 @@ BOOST_AUTO_TEST_CASE(something_else) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto color = duk::get<mlk::client::color>(ctx, 0); + const auto color = mlk::js::duk::get<mlk::client::color>(ctx, 0); duk_push_uint(ctx, color.red); duk_put_global_string(ctx, "r"); @@ -673,7 +673,7 @@ const auto ret = duk_peval_string(ctx_, "draw(null);"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "r"); BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
--- a/tests/libcommon/js-elapsed-timer/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libcommon/js-elapsed-timer/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -50,12 +50,12 @@ BOOST_AUTO_TEST_CASE(standard) { if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); std::this_thread::sleep_for(300ms); if (duk_peval_string(ctx_, "result = timer.elapsed();") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "result"); assert_range(duk_to_int(ctx_, -1), 300); @@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE(pause) { if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); /* * Simulate a pause in the game like this: @@ -78,17 +78,17 @@ std::this_thread::sleep_for(10ms); if (duk_peval_string(ctx_, "timer.pause();") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); std::this_thread::sleep_for(5ms); if (duk_peval_string(ctx_, "timer.restart();") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); std::this_thread::sleep_for(6ms); if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "result"); assert_range(duk_to_int(ctx_, -1), 16); @@ -98,17 +98,17 @@ BOOST_AUTO_TEST_CASE(doublecheck) { if (duk_peval_string(ctx_, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); std::this_thread::sleep_for(50ms); if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); std::this_thread::sleep_for(50ms); if (duk_peval_string(ctx_, "result = timer.elapsed()") != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "result"); assert_range(duk_to_int(ctx_, -1), 100);
--- a/tests/libcommon/js-line/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libcommon/js-line/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -21,8 +21,6 @@ #include <malikania/line.hpp> -#include <malikania/js_line.hpp> - #include <malikania/js/test/js_api_fixture.hpp> namespace mlk { @@ -49,7 +47,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x1"); BOOST_TEST(duk_to_int(ctx_, -1) == 0); @@ -76,7 +74,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x1"); BOOST_TEST(duk_to_int(ctx_, -1) == 10); @@ -103,7 +101,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x1"); BOOST_TEST(duk_to_int(ctx_, -1) == 10); @@ -130,7 +128,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x1"); BOOST_TEST(duk_to_int(ctx_, -1) == 10); @@ -167,7 +165,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -189,7 +187,7 @@ BOOST_AUTO_TEST_CASE(success) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto line = duk::require<mlk::line>(ctx, 0); + const auto line = mlk::js::duk::require<mlk::line>(ctx, 0); duk_push_int(ctx, line.x1); duk_put_global_string(ctx, "x1"); @@ -207,7 +205,7 @@ const auto ret = duk_peval_string(ctx_, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x1"); BOOST_TEST(duk_to_int(ctx_, -1) == 50); @@ -226,7 +224,7 @@ BOOST_AUTO_TEST_CASE(fail) { duk_push_c_function(ctx_, [] (auto ctx) { - duk::require<mlk::line>(ctx, 0); + mlk::js::duk::require<mlk::line>(ctx, 0); return 0; }, 1); @@ -242,7 +240,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -264,7 +262,7 @@ BOOST_AUTO_TEST_CASE(adjust_all) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto line = duk::get<mlk::line>(ctx, 0); + const auto line = mlk::js::duk::get<mlk::line>(ctx, 0); duk_push_int(ctx, line.x1); duk_put_global_string(ctx, "x1"); @@ -282,7 +280,7 @@ const auto ret = duk_peval_string(ctx_, "build({});"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x1"); BOOST_TEST(duk_to_int(ctx_, -1) == 0);
--- a/tests/libcommon/js-point/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libcommon/js-point/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -21,8 +21,6 @@ #include <malikania/point.hpp> -#include <malikania/js_point.hpp> - #include <malikania/js/test/js_api_fixture.hpp> namespace mlk { @@ -47,7 +45,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 0); @@ -66,7 +64,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == -10); @@ -85,7 +83,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 100); @@ -104,7 +102,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 100); @@ -135,7 +133,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -157,7 +155,7 @@ BOOST_AUTO_TEST_CASE(success) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto point = duk::require<mlk::point>(ctx, 0); + const auto point = mlk::js::duk::require<mlk::point>(ctx, 0); duk_push_int(ctx, point.x); duk_put_global_string(ctx, "x"); @@ -171,7 +169,7 @@ const auto ret = duk_peval_string(ctx_, "build({ x: 100, y: 200 });"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 100); @@ -184,7 +182,7 @@ BOOST_AUTO_TEST_CASE(fail) { duk_push_c_function(ctx_, [] (auto ctx) { - duk::require<mlk::point>(ctx, 0); + mlk::js::duk::require<mlk::point>(ctx, 0); return 0; }, 1); @@ -200,7 +198,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -222,7 +220,7 @@ BOOST_AUTO_TEST_CASE(adjust_all) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto point = duk::get<mlk::point>(ctx, 0); + const auto point = mlk::js::duk::get<mlk::point>(ctx, 0); duk_push_int(ctx, point.x); duk_put_global_string(ctx, "x"); @@ -236,7 +234,7 @@ const auto ret = duk_peval_string(ctx_, "build({});"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 0);
--- a/tests/libcommon/js-rectangle/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libcommon/js-rectangle/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -47,7 +47,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 0); @@ -74,7 +74,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 10); @@ -101,7 +101,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 10); @@ -128,7 +128,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 10); @@ -165,7 +165,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -191,7 +191,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(success) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto rect = duk::require<mlk::rectangle>(ctx, 0); + const auto rect = mlk::js::duk::require<mlk::rectangle>(ctx, 0); duk_push_int(ctx, rect.x); duk_put_global_string(ctx, "x"); @@ -233,7 +233,7 @@ const auto ret = duk_peval_string(ctx_, "build({ x: 50, y: 80, width: 100, height: 200 });"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 50); @@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(fail) { duk_push_c_function(ctx_, [] (auto ctx) { - duk::require<mlk::rectangle>(ctx, 0); + mlk::js::duk::require<mlk::rectangle>(ctx, 0); return 0; }, 1); @@ -268,7 +268,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(adjust_all) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto rect = duk::get<mlk::rectangle>(ctx, 0); + const auto rect = mlk::js::duk::get<mlk::rectangle>(ctx, 0); duk_push_int(ctx, rect.x); duk_put_global_string(ctx, "x"); @@ -307,7 +307,7 @@ const auto ret = duk_peval_string(ctx_, "build({});"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "x"); BOOST_TEST(duk_to_int(ctx_, -1) == 0);
--- a/tests/libcommon/js-size/main.cpp Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libcommon/js-size/main.cpp Thu Oct 25 21:36:14 2018 +0200 @@ -43,7 +43,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "w"); BOOST_TEST(duk_to_uint(ctx_, -1) == 0U); @@ -62,7 +62,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "w"); BOOST_TEST(duk_to_uint(ctx_, -1) == 100U); @@ -81,7 +81,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "w"); BOOST_TEST(duk_to_uint(ctx_, -1) == 100U); @@ -100,7 +100,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "w"); BOOST_TEST(duk_to_uint(ctx_, -1) == 100U); @@ -131,7 +131,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -157,7 +157,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -179,7 +179,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -201,7 +201,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -223,7 +223,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "RangeError"); @@ -247,7 +247,7 @@ BOOST_AUTO_TEST_CASE(success) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto size = duk::require<mlk::size>(ctx, 0); + const auto size = mlk::js::duk::require<mlk::size>(ctx, 0); duk_push_uint(ctx, size.width); duk_put_global_string(ctx, "w"); @@ -261,7 +261,7 @@ const auto ret = duk_peval_string(ctx_, "build({ width: 100, height: 200 });"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "w"); BOOST_TEST(duk_to_uint(ctx_, -1) == 100U); @@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE(fail) { duk_push_c_function(ctx_, [] (auto ctx) { - duk::require<mlk::size>(ctx, 0); + mlk::js::duk::require<mlk::size>(ctx, 0); return 0; }, 1); @@ -290,7 +290,7 @@ ); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "name"); BOOST_TEST(duk_to_string(ctx_, -1) == "TypeError"); @@ -312,7 +312,7 @@ BOOST_AUTO_TEST_CASE(adjust_all) { duk_push_c_function(ctx_, [] (auto ctx) { - const auto size = duk::get<mlk::size>(ctx, 0); + const auto size = mlk::js::duk::get<mlk::size>(ctx, 0); duk_push_uint(ctx, size.width); duk_put_global_string(ctx, "w"); @@ -326,7 +326,7 @@ const auto ret = duk_peval_string(ctx_, "build({});"); if (ret != 0) - throw duk::get_stack(ctx_, -1); + throw mlk::js::duk::get_stack(ctx_, -1); duk_get_global_string(ctx_, "w"); BOOST_TEST(duk_to_uint(ctx_, -1) == 0U);
--- a/tests/libcommon/size/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libcommon/size/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -18,6 +18,6 @@ malikania_create_test( NAME size - LIBRARIES libmlk-common + LIBRARIES libmlk SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp )
--- a/tests/libcommon/util/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/libcommon/util/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -18,6 +18,6 @@ malikania_create_test( NAME util - LIBRARIES libmlk-common + LIBRARIES libmlk SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp )
--- a/tests/tools/tileset/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ b/tests/tools/tileset/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -51,7 +51,7 @@ malikania_create_test( NAME mlk-tileset - LIBRARIES libmlk-common + LIBRARIES libmlk SOURCES ${TILESET_SOURCES} ${TILESET_OUTPUTS}
--- a/tools/tileset/CMakeLists.txt Wed Oct 24 21:13:12 2018 +0200 +++ b/tools/tileset/CMakeLists.txt Thu Oct 25 21:36:14 2018 +0200 @@ -23,6 +23,6 @@ malikania_define_executable( TARGET mlk-tileset INCLUDES ${Boost_INCLUDE_DIRS} - LIBRARIES ${Boost_LIBRARIES} json libmlk-common + LIBRARIES ${Boost_LIBRARIES} json libmlk SOURCES ${mlk-tileset_SOURCE_DIR}/main.cpp )