diff --git a/CMakeLists.txt b/CMakeLists.txt index cffcc39a..1e142a4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,17 +47,23 @@ ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug") SET(SOURCES # game sources src/main.cpp - src/allocator.cpp # game net src/protocollogin.cpp # framework core + src/framework/core/global.cpp src/framework/core/dispatcher.cpp src/framework/core/configs.cpp src/framework/core/resources.cpp src/framework/core/engine.cpp src/framework/core/modules.cpp + src/framework/core/allocator.cpp + +# framework otml + src/framework/otml/otmlemitter.cpp + src/framework/otml/otmlparser.cpp + src/framework/otml/otmlnode.cpp # framework script src/framework/script/scriptable.cpp @@ -66,11 +72,10 @@ SET(SOURCES # framework utilities src/framework/util/color.cpp - src/framework/util/util.cpp + src/framework/util/translator.cpp + src/framework/util/convert.cpp src/framework/util/logger.cpp - src/framework/util/rsa.cpp src/framework/util/apngloader.cpp - src/framework/util/fml.cpp # framework graphics src/framework/graphics/image.cpp @@ -108,6 +113,7 @@ SET(SOURCES src/framework/net/protocol.cpp src/framework/net/inputmessage.cpp src/framework/net/outputmessage.cpp + src/framework/net/rsa.cpp ) IF(WIN32) diff --git a/data/modules/mainmenu/entergamewindow.yml b/data/modules/mainmenu/entergamewindow.yml index 5a20fcd8..857275a4 100644 --- a/data/modules/mainmenu/entergamewindow.yml +++ b/data/modules/mainmenu/entergamewindow.yml @@ -1,25 +1,25 @@ -window#enterGameWindow +%window#enterGameWindow title: Enter Game size: [236, 178] anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter onLoad: self.locked = true - label#accountNameLabel + %label#accountNameLabel text: Account name anchors.left: parent.left anchors.top: parent.top margin.left: 18 margin.top: 33 - label#passwordLabel + %label#passwordLabel text: "Password:" anchors.left: parent.left anchors.top: parent.top margin.left: 18 margin.top: 62 - label#createAccountLabel + %label#createAccountLabel text: | If you don't have an account yet @@ -28,7 +28,7 @@ window#enterGameWindow margin.left: 18 margin.top: 87 - button#createAccountButton + %button#createAccountButton text: Create Account anchors.left: parent.left anchors.top: parent.top @@ -36,7 +36,7 @@ window#enterGameWindow margin.left: 132 onClick: messageBox("Error", "Not implemented yet") - button#okButton + %button#okButton text: Ok size: [43, 20] anchors.right: parent.right @@ -45,7 +45,7 @@ window#enterGameWindow margin.right: 66 onClick: enterGame_onOkClicked() - button#cancelButton + %button#cancelButton text: Cancel size: [43, 20] anchors.right: parent.right @@ -54,13 +54,13 @@ window#enterGameWindow margin.right: 13 onClick: self.parent:destroy() - textEdit#accountNameTextEdit + %textEdit#accountNameTextEdit anchors.right: parent.right anchors.top: parent.top margin.top: 32 margin.right: 18 - textEdit#passwordTextEdit + %textEdit#passwordTextEdit anchors.right: parent.right anchors.top: parent.top margin.top: 61 diff --git a/data/modules/mainmenu/infowindow.yml b/data/modules/mainmenu/infowindow.yml index ec6a90b9..f401536e 100644 --- a/data/modules/mainmenu/infowindow.yml +++ b/data/modules/mainmenu/infowindow.yml @@ -1,11 +1,11 @@ -window#infoWindow +%window#infoWindow title: Info size: [244, 221] anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter onLoad: self.locked = true - panel#infoPanel + %panel#infoPanel skin: flatPanel size: [208, 129] anchors.left: parent.left @@ -13,7 +13,7 @@ window#infoWindow margin.top: 32 margin.left: 18 - label#infoLabel + %label#infoLabel align: center text: |- OTClient @@ -23,21 +23,21 @@ window#infoWindow anchors.top: parent.top margin.top: 20 - lineDecoration#bottomSeparator + %lineDecoration#bottomSeparator size: [190, 2] anchors.left: parent.left anchors.top: parent.top margin.top: 83 margin.left: 9 - label#websiteLabel + %label#websiteLabel text: Official Website anchors.left: parent.left anchors.bottom: parent.bottom margin.bottom: 14 margin.left: 9 - button#websiteButton + %button#websiteButton text: Github Page size: [80,22] anchors.right: parent.right @@ -45,7 +45,7 @@ window#infoWindow margin.bottom: 9 margin.right: 9 - lineDecoration#bottomSeparator + %lineDecoration#bottomSeparator anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -53,7 +53,7 @@ window#infoWindow margin.left: 13 margin.right: 13 - button#okButton + %button#okButton text: Ok size: [43, 20] anchors.left: parent.left diff --git a/data/modules/mainmenu/mainmenu.yml b/data/modules/mainmenu/mainmenu.yml index 5815741a..e5dc3f6a 100644 --- a/data/modules/mainmenu/mainmenu.yml +++ b/data/modules/mainmenu/mainmenu.yml @@ -1,11 +1,11 @@ -panel#background +%panel#background skin: mainMenuBackground anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom - panel#icos4d + %panel#icos4d skin: image: /skins/lightness/mouse.png anchors.left: parent.left @@ -13,7 +13,7 @@ panel#background margin.left: -2 margin.top: 70 - panel#mouse + %panel#mouse skin: image: /skins/lightness/icos4d.png anchors.right: parent.right @@ -21,7 +21,7 @@ panel#background margin.left: 60 margin.top: 70 - panel#mainMenu + %panel#mainMenu skin: roundedGridPanel size: [117, 171] anchors.left: parent.left @@ -29,35 +29,35 @@ panel#background margin.left: 60 margin.bottom: 70 - button#enterGameButton + %button#enterGameButton text: Enter Game anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter margin.top: 16 onClick: UI.load("entergamewindow.yml") - button#accessAccountButton + %button#accessAccountButton text: Access Account anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter margin.top: 46 onClick: messageBox("Error", "Not implemented yet") - button#optionsButton + %button#optionsButton text: Options anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter margin.top: 76 onClick: UI.load("optionswindow.yml") - button#infoButton + %button#infoButton text: Info anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter margin.top: 106 onClick: UI.load("infowindow.yml") - button#exitGameButton + %button#exitGameButton text: Exit anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter diff --git a/data/modules/mainmenu/optionswindow.yml b/data/modules/mainmenu/optionswindow.yml index 45a7da56..4d05e453 100644 --- a/data/modules/mainmenu/optionswindow.yml +++ b/data/modules/mainmenu/optionswindow.yml @@ -1,4 +1,4 @@ -window#optionsWindow +%window#optionsWindow title: Options size: [286, 262] anchors.horizontalCenter: parent.horizontalCenter @@ -6,14 +6,14 @@ window#optionsWindow onLoad: self.locked = true # general - button#generalButton + %button#generalButton text: General anchors.left: parent.left anchors.top: parent.top margin.left: 18 margin.top: 32 - label#generalLabel + %label#generalLabel text: |- Change general game options @@ -23,14 +23,14 @@ window#optionsWindow margin.top: 29 # graphics - button#graphicsButton + %button#graphicsButton text: Graphics anchors.left: parent.left anchors.top: parent.top margin.left: 18 margin.top: 65 - label#graphicsLabel + %label#graphicsLabel text: |- Change graphics and performance settings @@ -40,14 +40,14 @@ window#optionsWindow margin.top: 62 # console - button#consoleButton + %button#consoleButton text: Console anchors.left: parent.left anchors.top: parent.top margin.left: 18 margin.top: 98 - label#consoleLabel + %label#consoleLabel text: Customise the console anchors.left: parent.left anchors.top: parent.top @@ -55,21 +55,21 @@ window#optionsWindow margin.top: 95 # hotkeys - button#hotkeysButton + %button#hotkeysButton text: Hotkeys anchors.left: parent.left anchors.top: parent.top margin.left: 18 margin.top: 131 - label#hotkeysLabel + %label#hotkeysLabel text: Edit your hotkey texts anchors.left: parent.left anchors.top: parent.top margin.left: 117 margin.top: 128 - lineDecoration#middleSeparator + %lineDecoration#middleSeparator anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -78,14 +78,14 @@ window#optionsWindow margin.right: 18 # motd - button#motdButton + %button#motdButton text: Motd anchors.left: parent.left anchors.bottom: parent.bottom margin.left: 18 margin.bottom: 60 - label#motdLabel + %label#motdLabel text: | Show the most recent Message of the Day @@ -94,7 +94,7 @@ window#optionsWindow margin.left: 117 margin.bottom: 56 - lineDecoration#bottomSeparator + %lineDecoration#bottomSeparator anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -103,7 +103,7 @@ window#optionsWindow margin.right: 13 # ok button - button#okButton + %button#okButton text: Ok size: [43, 20] anchors.right: parent.right diff --git a/data/modules/messagebox/messagebox.yml b/data/modules/messagebox/messagebox.yml index 5cf4b510..778f04d5 100644 --- a/data/modules/messagebox/messagebox.yml +++ b/data/modules/messagebox/messagebox.yml @@ -1,15 +1,15 @@ -window#messageBoxWindow +%window#messageBoxWindow size: [192, 78] anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter - label#textLabel + %label#textLabel anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top margin.top: 27 - button#okButton + %button#okButton text: Ok size: [43, 20] anchors.right: parent.right diff --git a/src/framework/const.h b/src/framework/const.h new file mode 100644 index 00000000..b5b21713 --- /dev/null +++ b/src/framework/const.h @@ -0,0 +1,22 @@ +#ifndef CONST_H +#define CONST_H + +enum AlignmentFlag { + AlignLeft = 1, + AlignRight = 2, + AlignTop = 4, + AlignBottom = 8, + AlignHorizontalCenter = 16, + AlignVerticalCenter = 32, + AlignTopLeft = AlignTop | AlignLeft, + AlignTopRight = AlignTop | AlignRight, + AlignBottomLeft = AlignBottom | AlignLeft, + AlignBottomRight = AlignBottom | AlignRight, + AlignLeftCenter = AlignLeft | AlignVerticalCenter, + AlignRightCenter = AlignRight | AlignVerticalCenter, + AlignTopCenter = AlignTop | AlignHorizontalCenter, + AlignBottomCenter = AlignBottom | AlignHorizontalCenter, + AlignCenter = AlignVerticalCenter | AlignHorizontalCenter +}; + +#endif // CONST_H diff --git a/src/allocator.cpp b/src/framework/core/allocator.cpp similarity index 87% rename from src/allocator.cpp rename to src/framework/core/allocator.cpp index d25dc055..19ec87f1 100644 --- a/src/allocator.cpp +++ b/src/framework/core/allocator.cpp @@ -1,3 +1,27 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + #ifdef _DEBUG_MEMORY #include "allocator.h" @@ -101,6 +125,13 @@ static void addr2line(void *address, const char* name, bool viewSource = false) } } } + } else { + pos = (char*)strrchr(name, '/'); + if(!pos) + pos = (char*) name; + else + pos++; + printf("%p (%s)", address, pos); } printf("\n"); diff --git a/src/allocator.h b/src/framework/core/allocator.h similarity index 63% rename from src/allocator.h rename to src/framework/core/allocator.h index 45174f45..cae40f74 100644 --- a/src/allocator.h +++ b/src/framework/core/allocator.h @@ -1,3 +1,27 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + #ifndef __ALLOCATOR_H__ #define __ALLOCATOR_H__ @@ -31,7 +55,7 @@ struct block_hash : std::unary_function { std::size_t seed = 0; boost::hash_combine(seed, block->bytes); - for(int i=0;i<3;++i) { + for(int i=0;i<4;++i) { if(i < block->backtraceSize) boost::hash_combine(seed, block->backtraceBuffer[i]); else diff --git a/src/framework/core/configs.cpp b/src/framework/core/configs.cpp index 77ffb6c5..591388cf 100644 --- a/src/framework/core/configs.cpp +++ b/src/framework/core/configs.cpp @@ -22,9 +22,10 @@ */ -#include +#include #include #include +#include Configs g_configs; @@ -32,18 +33,18 @@ bool Configs::load(const std::string& fileName) { m_fileName = fileName; + if(!g_resources.fileExists(fileName)) + return false; + std::stringstream fin; if(!g_resources.loadFile(fileName, fin)) return false; try { - FML::Parser parser(fin, fileName); - FML::Node* doc = parser.getDocument(); - - foreach(FML::Node* node, *doc) - m_confsMap[node->tag()] = node->value(); - } catch(FML::Exception e) { - flogError("ERROR: Malformed config file: %s", e.what()); + OTMLParser parser(fin, fileName); + parser.getDocument()->read(&m_confsMap); + } catch(OTMLException e) { + error("ERROR: Malformed config file: ", e.what()); return false; } @@ -53,9 +54,8 @@ bool Configs::load(const std::string& fileName) void Configs::save() { if(!m_fileName.empty()) { - FML::Emitter emitter; - FML::Node *doc = emitter.createDocument(); - doc->write(m_confsMap); + OTMLEmitter emitter; + emitter.createDocument()->write(m_confsMap); g_resources.saveFile(m_fileName, emitter.emitDocument()); } } diff --git a/src/framework/core/configs.h b/src/framework/core/configs.h index 8e677a7f..048b0629 100644 --- a/src/framework/core/configs.h +++ b/src/framework/core/configs.h @@ -25,13 +25,13 @@ #ifndef CONFIGS_H #define CONFIGS_H -#include +#include struct ConfigValueProxy { - operator std::string() const { return convert_cast(value); } - operator float() const { return convert_cast(value); } - operator int() const { return convert_cast(value); } - operator bool() const { return convert_cast(value); } + operator std::string() const { return convert(value); } + operator float() const { return convert(value); } + operator int() const { return convert(value); } + operator bool() const { return convert(value); } std::string value; }; @@ -41,7 +41,9 @@ public: bool load(const std::string& fileName); void save(); - template void set(const std::string& key, const T& value) { m_confsMap[key] = convert_cast(value); } + template + void set(const std::string& key, const T& value) { m_confsMap[key] = convert(value); } + ConfigValueProxy get(const std::string& key) { return ConfigValueProxy{m_confsMap[key]}; } private: diff --git a/src/framework/core/dispatcher.cpp b/src/framework/core/dispatcher.cpp index ef279a63..02b09c08 100644 --- a/src/framework/core/dispatcher.cpp +++ b/src/framework/core/dispatcher.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include @@ -54,12 +54,12 @@ void Dispatcher::poll() } } -void Dispatcher::scheduleTask(const SimpleCallback& callback, int delay) +void Dispatcher::scheduleTask(const boost::function& callback, int delay) { m_scheduledTaskList.push(new ScheduledTask(g_engine.getCurrentFrameTicks() + delay, callback)); } -void Dispatcher::addTask(const SimpleCallback& callback, bool pushFront) +void Dispatcher::addTask(const boost::function& callback, bool pushFront) { if(pushFront) m_taskList.push_front(callback); diff --git a/src/framework/core/dispatcher.h b/src/framework/core/dispatcher.h index e84101f3..92c45953 100644 --- a/src/framework/core/dispatcher.h +++ b/src/framework/core/dispatcher.h @@ -25,15 +25,19 @@ #ifndef DISPATCHER_H #define DISPATCHER_H -#include +#include +#include + +#include +#include class ScheduledTask { public: - inline ScheduledTask(const SimpleCallback& _callback) : ticks(0), callback(_callback) { } - inline ScheduledTask(int _ticks, const SimpleCallback& _callback) : ticks(_ticks), callback(_callback) { } + inline ScheduledTask(const boost::function& _callback) : ticks(0), callback(_callback) { } + inline ScheduledTask(int _ticks, const boost::function& _callback) : ticks(_ticks), callback(_callback) { } inline bool operator<(const ScheduledTask& other) const { return ticks > other.ticks; } int ticks; - SimpleCallback callback; + boost::function callback; }; class lessScheduledTask : public std::binary_function { @@ -53,13 +57,13 @@ public: void poll(); /// Add an event - void addTask(const SimpleCallback& callback, bool pushFront = false); + void addTask(const boost::function& callback, bool pushFront = false); /// Schedula an event - void scheduleTask(const SimpleCallback& callback, int delay); + void scheduleTask(const boost::function& callback, int delay); private: - std::list m_taskList; + std::list> m_taskList; std::priority_queue, lessScheduledTask> m_scheduledTaskList; }; diff --git a/src/framework/core/engine.cpp b/src/framework/core/engine.cpp index 0d3bd70e..508b31c4 100644 --- a/src/framework/core/engine.cpp +++ b/src/framework/core/engine.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include #include @@ -78,7 +78,7 @@ void Engine::run() // check if root container has elements const UIContainerPtr& rootContainer = UIContainer::getRoot(); if(rootContainer->getChildCount() == 0) - logFatal("FATAL ERROR: no ui loaded at all, no reason to continue running"); + fatal("FATAL ERROR: no ui loaded at all, no reason to continue running"); std::string fpsText; Size fpsTextSize; @@ -106,7 +106,7 @@ void Engine::run() frameCount = 0; // update fps text - fpsText = fmt("FPS: %d", fps); + fpsText = make_string("FPS: ", fps); fpsTextSize = defaultFont->calculateTextRectSize(fpsText); } } diff --git a/src/framework/core/engine.h b/src/framework/core/engine.h index 6f964e43..4083778d 100644 --- a/src/framework/core/engine.h +++ b/src/framework/core/engine.h @@ -25,7 +25,7 @@ #ifndef ENGINE_H #define ENGINE_H -#include +#include #include class Engine diff --git a/src/framework/util/util.cpp b/src/framework/core/global.cpp similarity index 61% rename from src/framework/util/util.cpp rename to src/framework/core/global.cpp index 4b610740..05e83870 100644 --- a/src/framework/util/util.cpp +++ b/src/framework/core/global.cpp @@ -21,29 +21,5 @@ * THE SOFTWARE. */ -#include -#include -AlignmentFlag parseAlignment(std::string aligment) -{ - boost::to_lower(aligment); - boost::erase_all(aligment, " "); - if(aligment == "topleft") - return AlignTopLeft; - else if(aligment == "topright") - return AlignTopRight; - else if(aligment == "bottomleft") - return AlignBottomLeft; - else if(aligment == "bottomright") - return AlignBottomRight; - else if(aligment == "left") - return AlignLeftCenter; - else if(aligment == "right") - return AlignRightCenter; - else if(aligment == "top") - return AlignTopCenter; - else if(aligment == "bottom") - return AlignBottomCenter; - else - return AlignCenter; -} \ No newline at end of file +#include "global.h" diff --git a/src/framework/core/input.h b/src/framework/core/input.h index 1fdc348c..e0d40172 100644 --- a/src/framework/core/input.h +++ b/src/framework/core/input.h @@ -25,7 +25,7 @@ #ifndef INPUT_H #define INPUT_H -#include +#include enum EKeyCode { KC_UNKNOWN = 0x00, diff --git a/src/framework/core/platform.h b/src/framework/core/platform.h index ba2f3dd7..cff71d6d 100644 --- a/src/framework/core/platform.h +++ b/src/framework/core/platform.h @@ -25,7 +25,7 @@ #ifndef PLATFORM_H #define PLATFORM_H -#include +#include class Platform { diff --git a/src/framework/core/resources.cpp b/src/framework/core/resources.cpp index 9962f180..5bb41ed8 100644 --- a/src/framework/core/resources.cpp +++ b/src/framework/core/resources.cpp @@ -22,10 +22,11 @@ */ -#include +#include #include #include +#include #include Resources g_resources; @@ -35,34 +36,32 @@ void Resources::init(const char *argv0) PHYSFS_init(argv0); // try to find data directory - std::list searchPaths; std::string dir; std::string baseDir = PHYSFS_getBaseDir(); - std::list possibleDirs; - possibleDirs.push_back("data"); - possibleDirs.push_back(baseDir + "data"); - possibleDirs.push_back(baseDir + "../data"); - possibleDirs.push_back(baseDir + "../share/otclient/data"); - possibleDirs.push_back(""); + std::string possibleDirs[] = { "data", + baseDir + "data", + baseDir + "../data", + baseDir + "../share/otclient/data", + "" }; bool found = false; foreach(dir, possibleDirs) { if(g_resources.addToSearchPath(dir)) { - flogInfo("Using data directory: %s", dir.c_str()); + info("Using data directory: ", dir.c_str()); found = true; break; } } if(!found) - logFatal("ERROR: could not find data directory"); + fatal("ERROR: could not find data directory"); // setup write directory dir = Platform::getAppUserDir(); if(g_resources.setWriteDir(dir)) g_resources.addToSearchPath(dir); else - logError("ERROR: could not setup write directory"); + error("ERROR: could not setup write directory"); } void Resources::terminate() @@ -109,7 +108,7 @@ bool Resources::loadFile(const std::string& fileName, std::iostream& out) out.clear(std::ios::goodbit); PHYSFS_file *file = PHYSFS_openRead(fullPath.c_str()); if(!file) { - flogError("ERROR: Failed to load file \"%s\": %s", fullPath.c_str() % PHYSFS_getLastError()); + error("ERROR: Failed to load file '", fullPath.c_str(), "': ", PHYSFS_getLastError()); out.clear(std::ios::failbit); return false; } else { @@ -131,7 +130,7 @@ bool Resources::saveFile(const std::string &fileName, const uchar *data, uint si { PHYSFS_file *file = PHYSFS_openWrite(resolvePath(fileName).c_str()); if(!file) { - flogError("ERROR: Failed to save file \"%s\": %s", fileName.c_str() % PHYSFS_getLastError()); + error("ERROR: Failed to save file '",fileName,"': ",PHYSFS_getLastError()); return false; } diff --git a/src/framework/core/resources.h b/src/framework/core/resources.h index 3a9904c3..c6449ae2 100644 --- a/src/framework/core/resources.h +++ b/src/framework/core/resources.h @@ -25,7 +25,8 @@ #ifndef RESOURCES_H #define RESOURCES_H -#include +#include +#include class Resources { diff --git a/src/framework/global.h b/src/framework/global.h new file mode 100644 index 00000000..2404d2aa --- /dev/null +++ b/src/framework/global.h @@ -0,0 +1,45 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +// common C headers +#include +#include +#include +#include +#include +#include + +// common STL headers +#include +#include +#include +#include +#include +#include +#include +#include + +// smart pointers +#include +#include +#include + +// constants +#include "const.h" + +// easy types +#include + +// custom types +#include +#include +#include +#include + +// additional utilities +#include +#include +#include +#include + +#endif // GLOBAL_H diff --git a/src/framework/graphics/animatedtexture.h b/src/framework/graphics/animatedtexture.h index b85bd876..d93631cb 100644 --- a/src/framework/graphics/animatedtexture.h +++ b/src/framework/graphics/animatedtexture.h @@ -25,8 +25,8 @@ #ifndef ANIMATEDTEXTURE_H #define ANIMATEDTEXTURE_H -#include -#include +#include +#include class AnimatedTexture : public Texture { diff --git a/src/framework/graphics/borderedimage.cpp b/src/framework/graphics/borderedimage.cpp index 83d92036..f2e91b8b 100644 --- a/src/framework/graphics/borderedimage.cpp +++ b/src/framework/graphics/borderedimage.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include #include diff --git a/src/framework/graphics/borderedimage.h b/src/framework/graphics/borderedimage.h index ed637759..917a3a56 100644 --- a/src/framework/graphics/borderedimage.h +++ b/src/framework/graphics/borderedimage.h @@ -25,7 +25,7 @@ #ifndef BORDEREDIMAGE_H #define BORDEREDIMAGE_H -#include +#include #include #include diff --git a/src/framework/graphics/font.cpp b/src/framework/graphics/font.cpp index 49e03444..799aac4c 100644 --- a/src/framework/graphics/font.cpp +++ b/src/framework/graphics/font.cpp @@ -22,11 +22,12 @@ */ -#include +#include #include #include #include #include +#include void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize) { @@ -70,7 +71,7 @@ bool Font::load(const std::string& file) { std::stringstream fin; if(!g_resources.loadFile(file, fin)) { - flogError("ERROR: Coult not load font file \"%s", file.c_str()); + error("ERROR: Coult not load font file '",file,"'"); return false; } @@ -78,8 +79,8 @@ bool Font::load(const std::string& file) Size glyphSize; try { - FML::Parser parser(fin, file); - FML::Node* doc = parser.getDocument(); + OTMLParser parser(fin, file); + OTMLNode* doc = parser.getDocument(); // required values textureName = doc->valueAt("image"); @@ -92,7 +93,7 @@ bool Font::load(const std::string& file) // load texture m_texture = g_textures.get(textureName); if(!m_texture) { - flogError("ERROR: Failed to load image for font file \"%s\"", file.c_str()); + error("ERROR: Failed to load image for font file '",file,"'"); return false; } @@ -115,8 +116,8 @@ bool Font::load(const std::string& file) m_glyphsSize[glyph].width(), m_glyphHeight); } - } catch(FML::Exception e) { - flogError("ERROR: Malformed font file \"%s\":\n %s", file.c_str() % e.what()); + } catch(OTMLException e) { + error("ERROR: Malformed font file \"", file.c_str(), "\":\n ", e.what()); return false; } diff --git a/src/framework/graphics/font.h b/src/framework/graphics/font.h index e6809583..d2f55d6c 100644 --- a/src/framework/graphics/font.h +++ b/src/framework/graphics/font.h @@ -25,8 +25,8 @@ #ifndef FONT_H #define FONT_H -#include -#include +#include +#include class Font { diff --git a/src/framework/graphics/fonts.cpp b/src/framework/graphics/fonts.cpp index a8a26439..70b4fde6 100644 --- a/src/framework/graphics/fonts.cpp +++ b/src/framework/graphics/fonts.cpp @@ -22,10 +22,12 @@ */ -#include +#include #include #include +#include + Fonts g_fonts; void Fonts::init() @@ -55,7 +57,7 @@ FontPtr Fonts::get(const std::string& fontName) return font; } - flogFatal("ERROR: Font \"%s\" not found", fontName.c_str()); + fatal("ERROR: Font '",fontName,"' not found"); return FontPtr(); } diff --git a/src/framework/graphics/fonts.h b/src/framework/graphics/fonts.h index 65f887b2..7fa638cb 100644 --- a/src/framework/graphics/fonts.h +++ b/src/framework/graphics/fonts.h @@ -25,7 +25,7 @@ #ifndef FONTS_H #define FONTS_H -#include +#include #include class Fonts diff --git a/src/framework/graphics/framebuffer.cpp b/src/framework/graphics/framebuffer.cpp index f80c63a6..cd0e6ffc 100644 --- a/src/framework/graphics/framebuffer.cpp +++ b/src/framework/graphics/framebuffer.cpp @@ -21,7 +21,7 @@ * THE SOFTWARE. */ -#include +#include #include #include #include diff --git a/src/framework/graphics/framebuffer.h b/src/framework/graphics/framebuffer.h index 8907d96f..3386885d 100644 --- a/src/framework/graphics/framebuffer.h +++ b/src/framework/graphics/framebuffer.h @@ -25,7 +25,7 @@ #ifndef FRAMEBUFFER_H #define FRAMEBUFFER_H -#include +#include class FrameBuffer { diff --git a/src/framework/graphics/graphics.cpp b/src/framework/graphics/graphics.cpp index 42fee22c..3780bbfd 100644 --- a/src/framework/graphics/graphics.cpp +++ b/src/framework/graphics/graphics.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include Graphics g_graphics; @@ -40,8 +40,8 @@ void Graphics::init() glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - flogInfo("GPU %s", (const char*)glGetString(GL_RENDERER)); - flogInfo("OpenGL %s", (const char*)glGetString(GL_VERSION)); + info("GPU ", glGetString(GL_RENDERER)); + info("OpenGL ", glGetString(GL_VERSION)); } void Graphics::terminate() diff --git a/src/framework/graphics/graphics.h b/src/framework/graphics/graphics.h index 2064de3c..abac278a 100644 --- a/src/framework/graphics/graphics.h +++ b/src/framework/graphics/graphics.h @@ -25,8 +25,12 @@ #ifndef GRAPHICS_H #define GRAPHICS_H -#include -#include +#include +#include + +#include +#include +#include class Graphics { diff --git a/src/framework/graphics/image.cpp b/src/framework/graphics/image.cpp index 0e377b2d..eb571aba 100644 --- a/src/framework/graphics/image.cpp +++ b/src/framework/graphics/image.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include #include diff --git a/src/framework/graphics/image.h b/src/framework/graphics/image.h index 482263f9..e4b412b7 100644 --- a/src/framework/graphics/image.h +++ b/src/framework/graphics/image.h @@ -25,7 +25,7 @@ #ifndef IMAGE_H #define IMAGE_H -#include +#include #include class Image diff --git a/src/framework/graphics/textarea.cpp b/src/framework/graphics/textarea.cpp index 54ed42e4..b4204d4c 100644 --- a/src/framework/graphics/textarea.cpp +++ b/src/framework/graphics/textarea.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include #include diff --git a/src/framework/graphics/textarea.h b/src/framework/graphics/textarea.h index 1d6c3d14..67549afd 100644 --- a/src/framework/graphics/textarea.h +++ b/src/framework/graphics/textarea.h @@ -25,7 +25,7 @@ #ifndef TEXTAREA_H #define TEXTAREA_H -#include +#include #include "font.h" class TextArea diff --git a/src/framework/graphics/texture.cpp b/src/framework/graphics/texture.cpp index d5ddff70..666d85f5 100644 --- a/src/framework/graphics/texture.cpp +++ b/src/framework/graphics/texture.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include "graphics.h" @@ -37,7 +37,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int GLint texSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize); if(width > texSize || height > texSize) { - flogError("loading texture with size %dx%d failed, the maximum size is %dx%d", width % height % texSize % texSize); + error("loading texture with size ",width,"x",height," failed, the maximum size is ",texSize,"x",texSize); return 0; } diff --git a/src/framework/graphics/texture.h b/src/framework/graphics/texture.h index f79459bf..175e5e66 100644 --- a/src/framework/graphics/texture.h +++ b/src/framework/graphics/texture.h @@ -25,7 +25,7 @@ #ifndef TEXTURE_H #define TEXTURE_H -#include +#include class Texture : public boost::enable_shared_from_this { diff --git a/src/framework/graphics/textureloader.cpp b/src/framework/graphics/textureloader.cpp index 14597cfe..5b585014 100644 --- a/src/framework/graphics/textureloader.cpp +++ b/src/framework/graphics/textureloader.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include #include diff --git a/src/framework/graphics/textureloader.h b/src/framework/graphics/textureloader.h index 1a3158cf..36629d08 100644 --- a/src/framework/graphics/textureloader.h +++ b/src/framework/graphics/textureloader.h @@ -25,7 +25,7 @@ #ifndef TEXTURELOADER_H #define TEXTURELOADER_H -#include +#include #include class TextureLoader diff --git a/src/framework/graphics/textures.cpp b/src/framework/graphics/textures.cpp index 602df1c5..370c76fc 100644 --- a/src/framework/graphics/textures.cpp +++ b/src/framework/graphics/textures.cpp @@ -22,12 +22,14 @@ */ -#include +#include #include #include #include #include +#include + Textures g_textures; TexturePtr Textures::get(const std::string& textureFile) @@ -47,14 +49,14 @@ TexturePtr Textures::get(const std::string& textureFile) if(!texture) { // currently only png textures are supported if(!boost::ends_with(textureFile, ".png")) { - flogError("ERROR: Unable to load texture %s, file format no supported.", textureFile.c_str()); + error("ERROR: Unable to load texture '",textureFile,"', file format no supported."); return texture; } // load texture file data std::stringstream fin; if(!g_resources.loadFile(textureFile, fin)) { - flogError("ERROR: Unable to load texture %s, file could not be read.", textureFile.c_str()); + error("ERROR: Unable to load texture '",textureFile,"', file could not be read."); return texture; } @@ -62,7 +64,7 @@ TexturePtr Textures::get(const std::string& textureFile) // load the texture texture = TexturePtr(TextureLoader::loadPNG(fin)); if(!texture) - flogError("ERROR: Unable to load texture %s", textureFile.c_str()); + error("ERROR: Unable to load texture '",textureFile,"'"); } return texture; } diff --git a/src/framework/graphics/textures.h b/src/framework/graphics/textures.h index f41f3bdc..fd8314ee 100644 --- a/src/framework/graphics/textures.h +++ b/src/framework/graphics/textures.h @@ -25,9 +25,8 @@ #ifndef TEXTURES_H #define TEXTURES_H -#include +#include #include -#include class Textures { diff --git a/src/framework/net/connection.cpp b/src/framework/net/connection.cpp index 6f1f38ed..a03bcadd 100644 --- a/src/framework/net/connection.cpp +++ b/src/framework/net/connection.cpp @@ -40,12 +40,12 @@ void Connection::poll() ioService.reset(); } -void Connection::connect(const std::string& host, uint16 port, const SimpleCallback& connectCallback) +void Connection::connect(const std::string& host, uint16 port, const boost::function& connectCallback) { m_connectCallback = connectCallback; m_connectionState = CONNECTION_STATE_RESOLVING; - boost::asio::ip::tcp::resolver::query query(host, convert_cast(port)); + boost::asio::ip::tcp::resolver::query query(host, convert(port)); m_resolver.async_resolve(query, boost::bind(&Connection::onResolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); m_timer.expires_from_now(boost::posix_time::seconds(2)); @@ -70,7 +70,7 @@ void Connection::onTimeout(const boost::system::error_code& error) void Connection::onResolve(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator endpointIterator) { - logTrace(); + trace(); m_timer.cancel(); @@ -88,7 +88,7 @@ void Connection::onResolve(const boost::system::error_code& error, boost::asio:: void Connection::onConnect(const boost::system::error_code& error) { - logTrace(); + trace(); m_timer.cancel(); @@ -108,7 +108,7 @@ void Connection::onConnect(const boost::system::error_code& error) void Connection::onSend(const boost::system::error_code& error, size_t) { - logTrace(); + trace(); m_timer.cancel(); @@ -121,7 +121,7 @@ void Connection::onSend(const boost::system::error_code& error, size_t) void Connection::onRecvHeader(const boost::system::error_code& error) { - logTrace(); + trace(); if(error) { if(m_errorCallback) @@ -139,7 +139,7 @@ void Connection::onRecvHeader(const boost::system::error_code& error) void Connection::onRecvData(const boost::system::error_code& error) { - logTrace(); + trace(); if(error) { if(m_errorCallback) diff --git a/src/framework/net/connection.h b/src/framework/net/connection.h index e925e870..22140d27 100644 --- a/src/framework/net/connection.h +++ b/src/framework/net/connection.h @@ -25,10 +25,13 @@ #ifndef CONNECTION_H #define CONNECTION_H +#include + #include #include -#include + #include +#include typedef boost::function ErrorCallback; typedef boost::function RecvCallback; @@ -40,7 +43,7 @@ public: static void poll(); - void connect(const std::string& host, uint16 port, const SimpleCallback& connectCallback); + void connect(const std::string& host, uint16 port, const boost::function& connectCallback); void send(OutputMessage *outputMessage); void setErrorCallback(const ErrorCallback& errorCallback) { m_errorCallback = errorCallback; } @@ -63,7 +66,7 @@ public: private: ErrorCallback m_errorCallback; RecvCallback m_recvCallback; - SimpleCallback m_connectCallback; + boost::function m_connectCallback; ConnectionState_t m_connectionState; boost::asio::deadline_timer m_timer; diff --git a/src/framework/net/inputmessage.cpp b/src/framework/net/inputmessage.cpp index c2da5b5d..28311fbb 100644 --- a/src/framework/net/inputmessage.cpp +++ b/src/framework/net/inputmessage.cpp @@ -87,6 +87,6 @@ std::string InputMessage::getString() bool InputMessage::canRead(int bytes) { if((m_readPos + bytes > m_messageSize) || (m_readPos + bytes > BUFFER_MAXSIZE)) - logFatal("[InputMessage::canRead()]: Cant read. Message is finished or read position has reached buffer's maximum size."); + fatal("[InputMessage::canRead()]: Cant read. Message is finished or read position has reached buffer's maximum size."); return true; } diff --git a/src/framework/net/inputmessage.h b/src/framework/net/inputmessage.h index 34e2e896..a762b638 100644 --- a/src/framework/net/inputmessage.h +++ b/src/framework/net/inputmessage.h @@ -25,7 +25,7 @@ #ifndef INPUTMESSAGE_H #define INPUTMESSAGE_H -#include +#include class InputMessage { diff --git a/src/framework/net/outputmessage.cpp b/src/framework/net/outputmessage.cpp index 8ab995b7..63dbd503 100644 --- a/src/framework/net/outputmessage.cpp +++ b/src/framework/net/outputmessage.cpp @@ -105,6 +105,6 @@ void OutputMessage::addPaddingBytes(int bytes, uint8 byte) bool OutputMessage::canWrite(int bytes) { if(m_writePos + bytes > BUFFER_MAXSIZE) - logFatal("[OutputMessage::canWrite()]: Can't write. Write position has reached buffer's maxium size."); + fatal("[OutputMessage::canWrite()]: Can't write. Write position has reached buffer's maxium size."); return true; } diff --git a/src/framework/net/outputmessage.h b/src/framework/net/outputmessage.h index 5721d4fa..36ac8399 100644 --- a/src/framework/net/outputmessage.h +++ b/src/framework/net/outputmessage.h @@ -25,7 +25,7 @@ #ifndef OUTPUTMESSAGE_H #define OUTPUTMESSAGE_H -#include +#include class OutputMessage { diff --git a/src/framework/net/protocol.cpp b/src/framework/net/protocol.cpp index d0adde0d..3267f813 100644 --- a/src/framework/net/protocol.cpp +++ b/src/framework/net/protocol.cpp @@ -24,6 +24,8 @@ #include +#include + Protocol::Protocol() : m_connection(new Connection) { @@ -32,7 +34,7 @@ Protocol::Protocol() : m_xteaEncryptionEnabled = false; } -void Protocol::connect(const std::string& host, uint16 port, const SimpleCallback& callback) +void Protocol::connect(const std::string& host, uint16 port, const boost::function& callback) { m_connection->connect(host, port, callback); } @@ -62,7 +64,7 @@ void Protocol::onRecv(InputMessage *inputMessage) uint32 checksum = getAdlerChecksum(inputMessage->getBuffer() + InputMessage::DATA_POS, inputMessage->getMessageSize() - InputMessage::CHECKSUM_LENGTH); if(inputMessage->getU32() != checksum) { // error - logError("Checksum is invalid."); + error("Checksum is invalid."); return; } @@ -70,9 +72,9 @@ void Protocol::onRecv(InputMessage *inputMessage) xteaDecrypt(inputMessage); } -void Protocol::onError(const boost::system::error_code& error) +void Protocol::onError(const boost::system::error_code& err) { - flogError("PROTOCOL ERROR: %s", error.message()); + error("PROTOCOL ERROR: ", err.message()); // invalid hostname // connection timeouted diff --git a/src/framework/net/protocol.h b/src/framework/net/protocol.h index 46155a70..0241cf52 100644 --- a/src/framework/net/protocol.h +++ b/src/framework/net/protocol.h @@ -43,11 +43,11 @@ class Protocol : public Scriptable public: Protocol(); - void connect(const std::string& host, uint16 port, const SimpleCallback& callback); + void connect(const std::string& host, uint16 port, const boost::function& callback); void send(OutputMessage *outputMessage); virtual void onRecv(InputMessage *inputMessage); - virtual void onError(const boost::system::error_code& error); + virtual void onError(const boost::system::error_code& err); virtual const char *getScriptableName() const { return "Protocol"; } diff --git a/src/framework/util/rsa.cpp b/src/framework/net/rsa.cpp similarity index 98% rename from src/framework/util/rsa.cpp rename to src/framework/net/rsa.cpp index 61351d13..730408db 100644 --- a/src/framework/util/rsa.cpp +++ b/src/framework/net/rsa.cpp @@ -21,8 +21,8 @@ * THE SOFTWARE. */ -#include -#include +#include +#include "rsa.h" Rsa::Rsa() { diff --git a/src/framework/util/rsa.h b/src/framework/net/rsa.h similarity index 96% rename from src/framework/util/rsa.h rename to src/framework/net/rsa.h index 6cd37ccb..89cc8cfb 100644 --- a/src/framework/util/rsa.h +++ b/src/framework/net/rsa.h @@ -24,11 +24,12 @@ #ifndef RSA_H #define RSA_H -#include +#include #include -class Rsa{ +class Rsa +{ public: Rsa(); ~Rsa(); diff --git a/src/framework/otml/otml.h b/src/framework/otml/otml.h new file mode 100644 index 00000000..d7a767ec --- /dev/null +++ b/src/framework/otml/otml.h @@ -0,0 +1,9 @@ +#ifndef OTML_H +#define OTML_H + +#include "otmlnode.h" +#include "otmlemitter.h" +#include "otmlparser.h" + +#endif // OTML_H + diff --git a/src/framework/otml/otmlemitter.cpp b/src/framework/otml/otmlemitter.cpp new file mode 100644 index 00000000..0850b94b --- /dev/null +++ b/src/framework/otml/otmlemitter.cpp @@ -0,0 +1,63 @@ +#include "otmlemitter.h" +#include "otmlnode.h" + +#include + +OTMLEmitter::OTMLEmitter() : + m_rootNode(0) +{ +} + +OTMLEmitter::~OTMLEmitter() +{ + if(m_rootNode) + delete m_rootNode; +} + +OTMLNode* OTMLEmitter::createDocument() +{ + m_rootNode = new OTMLNode; + return m_rootNode; +} + +std::string OTMLEmitter::emitDocument() +{ + if(m_rootNode) + return emitNode(m_rootNode, 0); + return std::string(); +} + +std::string OTMLEmitter::emitNodeValue(OTMLNode* node) +{ + std::string value = node->value(); + if(!value.empty() && (value[0] == '"' || *value.rbegin() == '"'|| + value[0] == ' ' || *value.rbegin() == ' '|| + value[0] == '-' || value[0] == '{' || value[0] == '[' || value[0] == '|' || + value.find("\n") != std::string::npos)) { + boost::replace_all(value, "\\", "\\\\"); + boost::replace_all(value, "\"", "\\\""); + boost::replace_all(value, "\n", "\\n"); + value.append("\""); + value.insert(0, "\""); + } + return value; +} + +std::string OTMLEmitter::emitNode(OTMLNode* node, int currentDepth) +{ + std::stringstream ss; + for(int i=1;i 0) { + if(node->hasTag()) + ss << node->tag(); + if(node->hasValue()) + ss << (node->hasTag() ? ": " : "- ") << emitNodeValue(node); + if(!node->hasTag() && !node->hasValue()) + ss << "-"; + ss << std::endl; + } + for(int i=0;isize();++i) + ss << emitNode(node->at(i), currentDepth+1); + return ss.str(); +} diff --git a/src/framework/otml/otmlemitter.h b/src/framework/otml/otmlemitter.h new file mode 100644 index 00000000..7d057e7c --- /dev/null +++ b/src/framework/otml/otmlemitter.h @@ -0,0 +1,24 @@ +#ifndef OTMLEMITTER_H +#define OTMLEMITTER_H + +#include + +class OTMLNode; + +class OTMLEmitter +{ +public: + OTMLEmitter(); + ~OTMLEmitter(); + + OTMLNode* createDocument(); + std::string emitDocument(); + + static std::string emitNodeValue(OTMLNode* node); + static std::string emitNode(OTMLNode* node, int currentDepth = 0); + +private: + OTMLNode* m_rootNode; +}; + +#endif // OTMLEMITTER_H diff --git a/src/framework/otml/otmlnode.cpp b/src/framework/otml/otmlnode.cpp new file mode 100644 index 00000000..3bba8b74 --- /dev/null +++ b/src/framework/otml/otmlnode.cpp @@ -0,0 +1,93 @@ +#include "otmlnode.h" + +#include + +OTMLNode::OTMLNode(std::string what) : + m_parent(0), m_line(0), m_what(what) +{ +} + +OTMLNode::~OTMLNode() +{ + for(int i=0;itag()!=childTag) + ++i; + return at(i); +} + +OTMLNode* OTMLNode::at(int pos) const +{ + if(pos < (int)m_children.size() && pos >= 0) + return m_children[pos]; + return 0; +} + +OTMLNode* OTMLNode::atPath(const std::string& path) const +{ + std::vector nodeTags; + OTMLNode* node = const_cast(this); + std::string shortcutKey; + + boost::split(nodeTags, path, boost::is_any_of(std::string("/"))); + foreach(std::string& stag, nodeTags) { + if(!shortcutKey.empty()) + shortcutKey += '.'; + shortcutKey += stag; + if(node) + node = node->at(stag); + } + + if(node) + return node; + else + return at(shortcutKey); +} + +OTMLNode* OTMLNode::createNode(std::string tag) +{ + OTMLNode* node = new OTMLNode; + node->setTag(tag); + addNode(node); + return node; +} + +void OTMLNode::addNode(OTMLNode* node) { + if(node->hasTag() && node->hasValue()) + if(OTMLNode* other = at(node->tag())) + removeNode(other); + m_children.push_back(node); + node->setParent(this); +} + +bool OTMLNode::removeNode(OTMLNode* node) { + for(NodeList::iterator it = m_children.begin(); it != m_children.end(); ++it) { + if((*it) == node) { + m_children.erase(it); + return true; + } + } + return false; +} + +std::string OTMLNode::generateErrorMessage(const std::string& message) const { + std::stringstream ss; + ss << "OTML error"; + if(!what().empty()) + ss << " in '" << what() << "'"; + if(m_line > 0) + ss << " at line " << m_line; + if(m_line > 0 && hasTag()) + ss << ", in node '" << tag() << "'"; + ss << ": " << message; + return ss.str(); +} + +void OTMLNode::throwError(const std::string& message) const +{ + throw OTMLException(generateErrorMessage(message)); +} diff --git a/src/framework/otml/otmlnode.h b/src/framework/otml/otmlnode.h new file mode 100644 index 00000000..0469aee6 --- /dev/null +++ b/src/framework/otml/otmlnode.h @@ -0,0 +1,260 @@ +#ifndef OTMLNODE_H +#define OTMLNODE_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class OTMLException : public std::runtime_error { +public: + OTMLException(const std::string& what) : std::runtime_error(what) {} +}; + +class OTMLNode +{ +public: + typedef std::vector NodeList; + typedef NodeList::iterator iterator; + typedef NodeList::const_iterator const_iterator; + + OTMLNode(std::string what = ""); + ~OTMLNode(); + + bool hasTag() const { return !m_tag.empty(); } + bool hasChildren() const { return size() > 0; } + bool hasValue() const { return !m_value.empty(); } + bool hasNode(const std::string ctag) const { return at(ctag) != 0; } + + void setTag(std::string tag) { m_tag = tag; } + void setLine(int line) { m_line = line; } + void setValue(const std::string& value) { m_value = value; } + void setParent(OTMLNode* parent) { m_parent = parent; } + + std::string tag() const { return m_tag; } + int line() const { return m_line; } + int size() const { return m_children.size(); } + OTMLNode* parent() { return m_parent; } + std::string what() const { return (m_parent ? m_parent->what() : m_what); } + + iterator begin() { return m_children.begin(); } + iterator end() { return m_children.end(); } + const_iterator begin() const { return m_children.begin(); } + const_iterator end() const { return m_children.end(); } + + OTMLNode* front() const { return at(0); } + OTMLNode* back() const { return at(size()-1); } + + OTMLNode* at(const std::string& ctag) const; + OTMLNode* at(int pos) const; + OTMLNode *atPath(const std::string& path) const; + + OTMLNode* createNode(std::string tag = ""); + void addNode(OTMLNode* node); + bool removeNode(OTMLNode* node); + + std::string generateErrorMessage(const std::string& message) const; + void throwError(const std::string& message) const; + + std::string value(const std::string& def = "") const { return (m_value.empty() ? def : m_value); } + std::string valueAt(const std::string ctag, const std::string& def = "") const { + OTMLNode* c = at(ctag); + return (c ? c->value() : def); + } + std::string valueAt(int pos, const std::string& def = "") const { + OTMLNode* n = at(pos); + return (n ? n->value() : def); + } + std::string valueAtPath(const std::string path, const std::string& def = "") const { + OTMLNode* c = atPath(path); + return (c ? c->value() : def); + } + + // read into memory + template + void read(T* v) const { + if(!(*this >> *v)) + throwError(make_string("failed to cast node value to type ", std::string(typeid(T).name()))); + } + + template + bool readAt(const std::string& ctag, T* v) const { + if(OTMLNode* node = at(ctag)) { + node->read(v); + return true; + } + return false; + } + + template + bool readAt(int pos, T* v) const { + if(OTMLNode* node = at(pos)) { + node->read(v); + return true; + } + return false; + } + + template + bool readAtPath(const std::string& ctag, T* v) const { + if(OTMLNode* node = atPath(ctag)) { + node->read(v); + return true; + } + return false; + } + + // read returning the result + template + T read() const { T v; read(&v); return v;} + + template + T readAt(const std::string& ctag) const { + T v; + if(!readAt(ctag, &v)) + throwError(make_string("child node \'", ctag, "\' not found")); + return v; + } + + template + T readAt(int pos) const { + T v; + if(!readAt(pos, &v)) + throwError(make_string("child node at pos ", pos, " not found")); + return v; + } + + template + T readAtPath(const std::string& ctag) const { + T v; + if(!readAtPath(ctag, &v)) + throwError(make_string("child node in path \'", ctag, "\' not found")); + return v; + } + + // read with default supplied + template + T readAt(const std::string& ctag, const T& def) const { + OTMLNode* c = at(ctag); + return (c ? c->read() : def); + } + + template + T readAt(int pos, const T& def) const { + OTMLNode* c = at(pos); + return (c ? c->read() : def); + } + + template + T readAtPath(const std::string& path, const T& def) const { + OTMLNode* c = atPath(path); + return (c ? c->read() : def); + } + + // writing + template + void write(T v) { + if(!(*this << v)) + throwError(make_string("failed to cast to string node value of type ", typeid(T).name())); + } + + template + void writeIn(int pos, T v) { + OTMLNode* c; + while(!at(pos)) + c = createNode(); + c->write(v); + } + + template + void writeIn(const std::string& ctag, T v) { + OTMLNode* c = at(ctag); + if(!c) + c = createNode(ctag); + c->write(v); + } + +private: + OTMLNode* m_parent; + int m_line; + std::string m_what; + NodeList m_children; + std::string m_tag; + std::string m_value; +}; + +// read operators +template +bool operator >> (const OTMLNode& node, T& v) { return safe_convert(node.value(), v); } + +template +bool operator >> (const OTMLNode& node, std::vector& v) { + v.resize(node.size()); + for(unsigned i=0;i(i); + return true; +} + +template +bool operator >> (const OTMLNode& node, std::list& v) { + for(unsigned i=0;i(i)); + return true; +} + +template +bool operator >> (const OTMLNode& node, std::map& m) { + for(int i=0;itag(), k)) + return false; + m[k] = node.at(i)->read(); + } + return true; +} + +// write operators +template +bool operator << (OTMLNode& node, const T& v) { + std::string out; + if(!safe_convert(v, out)) + return false; + node.setValue(out); + return true; +} + +template +bool operator << (OTMLNode& node, const std::vector& v) { + for(unsigned i=0;iwrite(v[i]); + return true; +} + +template +bool operator << (OTMLNode& node, const std::list& v) { + for(unsigned i=0;iwrite(v[i]); + return true; +} + +template +bool operator << (OTMLNode& node, const std::map& m) { + typename std::map::const_iterator it; + for(it = m.begin(); it != m.end(); ++it) { + std::string k; + if(!safe_convert(it->first, k)) + return false; + node.createNode(k)->write(it->second); + } + return true; +} + +#include "otmlnodeext.h" + +#endif // OTMLNODE_H diff --git a/src/framework/otml/otmlnodeext.h b/src/framework/otml/otmlnodeext.h new file mode 100644 index 00000000..27566bab --- /dev/null +++ b/src/framework/otml/otmlnodeext.h @@ -0,0 +1,84 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef OTMLNODEEXT_H +#define OTMLNODEEXT_H + +#include +#include +#include +#include + +inline bool operator>>(const OTMLNode& node, Color& color) +{ + int r, g, b, a; + if(node.readAt(0, &r) && + node.readAt(1, &g) && + node.readAt(2, &b)) { + a = 255; + node.readAt(3, &a); + color.setRGBA(r,g,b,a); + return true; + } + return false; +} + +template +inline bool operator>>(const OTMLNode& node, TPoint& point) +{ + T x, y; + if(node.readAt(0, &x) && node.readAt(1, &y)) { + point.x = x; + point.y = y; + return true; + } + return false; +} + +template +inline bool operator>>(const OTMLNode& node, TSize& size) +{ + T w, h; + if(node.readAt(0, &w) && node.readAt(1, &h)) { + size.setSize(w, h); + return true; + } + return false; +} + +template +inline bool operator>>(const OTMLNode& node, TRect& rect) +{ + T x, y, width, height; + if(node.readAt(0, &x) && + node.readAt(1, &y) && + node.readAt(2, &width) && + node.readAt(3, &height)) { + rect.setRect(x, y, width, height); + return true; + } + return false; +} + +#endif // OTMLNODEEXT_H diff --git a/src/framework/otml/otmlparser.cpp b/src/framework/otml/otmlparser.cpp new file mode 100644 index 00000000..9dcf9641 --- /dev/null +++ b/src/framework/otml/otmlparser.cpp @@ -0,0 +1,259 @@ +#include "otmlparser.h" +#include "otmlnode.h" + +#include + +OTMLParser::OTMLParser(std::istream& in, std::string what) : + m_currentDepth(0), m_currentLine(0), + m_rootNode(new OTMLNode), m_currentParent(m_rootNode), m_previousNode(0), + m_what(what), m_in(in) +{ + parse(); +} + +OTMLParser::~OTMLParser() +{ + delete m_rootNode; +} + +void OTMLParser::throwError(const std::string& message, int line) +{ + std::stringstream ss; + ss << "OTML syntax error"; + if(!m_what.empty()) + ss << " in '" << m_what << "'"; + if(line > 0) + ss << " at line " << line; + ss << ": " << message; + throw OTMLException(ss.str()); +} + +void OTMLParser::parse() +{ + m_rootNode->setTag("document"); + + while(m_in.good() && !m_in.eof()) { + m_currentLine++; + std::string line; + std::getline(m_in, line); + parseLine(line); + } +} + +void OTMLParser::parseLine(std::string line) +{ + // calculate depth + std::size_t numSpaces = line.find_first_not_of(' '); + + // trim left whitespaces + boost::trim_left(line); + + // skip comment or empty lines + if(line[0] == '#' || line.empty()) + return; + + // calculate depth + int depth = 0; + if(numSpaces != std::string::npos) + depth = numSpaces / 2; + + // check for syntax error + if(numSpaces != std::string::npos && numSpaces % 2 != 0) + throwError("file must be idented every 2 whitespaces", m_currentLine); + + // a depth above, change current parent to the previous added node + if(depth == m_currentDepth+1) { + m_currentParent = m_previousNode; + // a depth below, change parent to previus parent + } else if(depth < m_currentDepth) { + for(int i=0;iparent(); + // else if it isn't the current depth it's a syntax error + } else if(depth != m_currentDepth) { + throwError("invalid indentation level", m_currentLine); + } + + // update current depth + m_currentDepth = depth; + + // add node + OTMLNode* node = m_currentParent->createNode(); + m_previousNode = node; + parseNode(node, line); +} + +void OTMLParser::parseNode(OTMLNode* node, std::string data) +{ + std::string tag; + std::string value; + std::size_t dotsPos = data.find_first_of(':'); + + // its a node that has a value but no tag + if(!data.empty() && data[0] == '-') { + value = data.substr(1); + boost::trim(value); + + // check if it's value is shortcut for adding a child node + if(dotsPos != std::string::npos && !value.empty() && value[0] != '"') { + OTMLNode* child = node->createNode(); + parseNode(child, value); + value.clear(); + } + } + // its a node that has tag and possible a value + else if(dotsPos != std::string::npos) { + tag = data.substr(0, dotsPos); + value = data.substr(dotsPos+1); + } + // its a node that has only a tag + else { + tag = data; + } + + // set node tag + boost::trim(tag); + node->setTag(tag); + + // set node line + node->setLine(m_currentLine); + + // process node value + parseNodeValue(node, value); +} + +void OTMLParser::parseNodeValue(OTMLNode* node, std::string value) +{ + boost::trim(value); + if(value.empty()) + return; + + // multiline text scalar + if(value[0] == '|') { + std::string multiLineData; + do { + std::string line; + size_t lastPos = m_in.tellg(); + std::getline(m_in, line); + + // calculate numspaces + std::size_t numSpaces = line.find_first_not_of(' '); + + // depth above current depth, add the text to the multiline + if(numSpaces != std::string::npos && (int)numSpaces >= (m_currentDepth+1)*2) { + boost::trim(line); + parseTextValue(line); + multiLineData += line + "\n"; + } + // if has contents below the current depth, its a node + else if(numSpaces != std::string::npos) { + m_in.seekg(lastPos, std::ios::beg); + break; + } + // else its just a new line + else { + multiLineData += "\n"; + } + } while(!m_in.eof()); + + // determine how to treat last new lines + if(value.length() == 1 || (value.length() == 2 && value[1] == '-')) { + // remove all new lines at the end + while(*multiLineData.rbegin() == '\n') + multiLineData.erase(multiLineData.length()-1, 1); + // keep just one extra line + if(value[0] == '-') + multiLineData.append("\n"); + } else if(value.length() > 2 || value[1] != '+') + throwError("invalid multiline identifier", m_currentLine); + + node->setValue(multiLineData); + } + // sequence + else if(value[0] == '[') { + std::vector tokens; + parseTokens(value.substr(1), tokens); + foreach(std::string& token, tokens) { + OTMLNode* child = node->createNode(); + child->setLine(m_currentLine); + parseNodeValue(child, token); + } + } + // inline map + else if(value[0] == '{') { + std::vector tokens; + parseTokens(value.substr(1), tokens); + foreach(std::string& token, tokens) { + OTMLNode* child = node->createNode(); + parseNode(child, token); + } + } + // text scalar + else { + parseTextValue(value); + node->setValue(value); + } +} + +void OTMLParser::parseTextValue(std::string& value) +{ + if(value[0] == '"' && value[value.length()-1] == '"') { + value = value.substr(1, value.length()-2); + // escape characters + boost::replace_all(value, "\\\\", "\\"); + boost::replace_all(value, "\\\"", "\""); + boost::replace_all(value, "\\n", "\n"); + } +} + +void OTMLParser::parseTokens(std::string data, std::vector& out) +{ + bool inQuote = false; + int brackets = 1; + + std::string tmp; + uint i = 0; + do { + if(i= data.length() && !m_in.eof()) { + std::string line; + std::getline(m_in, line); + boost::trim(line); + data += " "; + data += line; + } + ++i; + } while(i + +class OTMLNode; + +class OTMLParser +{ +public: + OTMLParser(std::istream& in, std::string what = ""); + ~OTMLParser(); + + OTMLNode* getDocument() const { return m_rootNode; } + std::string what() { return m_what; } + + void throwError(const std::string& message, int line); + +protected: + void parse(); + void parseLine(std::string line); + void parseNode(OTMLNode* node, std::string data); + void parseNodeValue(OTMLNode* node, std::string value); + void parseTextValue(std::string& value); + + void parseTokens(std::string data, std::vector& out); + +private: + int m_currentDepth; + int m_currentLine; + OTMLNode* m_rootNode; + OTMLNode* m_currentParent; + OTMLNode* m_previousNode; + std::string m_what; + std::istream& m_in; +}; + +#endif // OTMLPARSER_H diff --git a/src/framework/platform/win32platform.cpp b/src/framework/platform/win32platform.cpp index 751d0cf5..7686b852 100644 --- a/src/framework/platform/win32platform.cpp +++ b/src/framework/platform/win32platform.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include @@ -211,7 +211,7 @@ void Platform::init(const char *appName) wc.lpszClassName = win32.appName.c_str(); // Set The Class Name if(!RegisterClassA(&wc)) - logFatal("FATAL ERROR: Failed to register the window class."); + fatal("FATAL ERROR: Failed to register the window class."); // force first tick Platform::getTicks(); @@ -226,7 +226,7 @@ void Platform::terminate() if(win32.instance) { if(!UnregisterClassA(win32.appName.c_str(), win32.instance)) - logError("ERROR: Unregister class failed."); + error("ERROR: Unregister class failed."); win32.instance = NULL; } @@ -286,7 +286,7 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i if(!win32.window) { terminate(); - logFatal("FATAL ERROR: Window creation error."); + fatal("FATAL ERROR: Window creation error."); return false; } @@ -315,31 +315,31 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i if(!(win32.hdc = GetDC(win32.window))) { terminate(); - logFatal("FATAL ERROR: Can't Create A GL Device Context."); + fatal("FATAL ERROR: Can't Create A GL Device Context."); return false; } if(!(pixelFormat = ChoosePixelFormat(win32.hdc, &pfd))) { terminate(); - logFatal("FATAL ERROR: Can't Find A Suitable PixelFormat."); + fatal("FATAL ERROR: Can't Find A Suitable PixelFormat."); return false; } if(!SetPixelFormat(win32.hdc, pixelFormat, &pfd)) { terminate(); - logFatal("FATAL ERROR: Can't Set The PixelFormat."); + fatal("FATAL ERROR: Can't Set The PixelFormat."); return false; } if(!(win32.hrc = wglCreateContext(win32.hdc))) { terminate(); - logFatal("FATAL ERROR: Can't Create A GL Rendering Context."); + fatal("FATAL ERROR: Can't Create A GL Rendering Context."); return false; } if(!wglMakeCurrent(win32.hdc, win32.hrc)) { terminate(); - logFatal("FATAL ERROR: Can't Activate The GL Rendering Context."); + fatal("FATAL ERROR: Can't Activate The GL Rendering Context."); return false; } @@ -350,24 +350,24 @@ void Platform::destroyWindow() { if(win32.hrc) { if(!wglMakeCurrent(NULL, NULL)) - logError("ERROR: Release Of DC And RC Failed."); + error("ERROR: Release Of DC And RC Failed."); if(!wglDeleteContext(win32.hrc)) - logError("ERROR: Release Rendering Context Failed."); + error("ERROR: Release Rendering Context Failed."); win32.hrc = NULL; } if(win32.hdc) { if(!ReleaseDC(win32.window, win32.hdc)) - logError("ERROR: Release Device Context Failed."); + error("ERROR: Release Device Context Failed."); win32.hdc = NULL; } if(win32.window) { if(!DestroyWindow(win32.window)) - logError("ERROR: Destroy window failed."); + error("ERROR: Destroy window failed."); win32.window = NULL; } @@ -502,7 +502,7 @@ std::string Platform::getAppUserDir() std::stringstream sdir; sdir << PHYSFS_getUserDir() << "/." << win32.appName << "/"; if((mkdir(sdir.str().c_str()) != 0) && (errno != EEXIST)) - flogError("ERROR: Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str()); + ferror("ERROR: Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str()); return sdir.str(); } diff --git a/src/framework/platform/x11platform.cpp b/src/framework/platform/x11platform.cpp index 50a7dfba..118e3a3e 100644 --- a/src/framework/platform/x11platform.cpp +++ b/src/framework/platform/x11platform.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include #include @@ -237,18 +237,18 @@ void Platform::init(const char *appName) // open display x11.display = XOpenDisplay(0); if(!x11.display) - logFatal("FATAL ERROR: Failed to open X display"); + fatal("FATAL ERROR: Failed to open X display"); // check if GLX is supported on this display if(!glXQueryExtension(x11.display, 0, 0)) - logFatal("FATAL ERROR: GLX not supported"); + fatal("FATAL ERROR: GLX not supported"); // retrieve GLX version int glxMajor; int glxMinor; if(!glXQueryVersion(x11.display, &glxMajor, &glxMinor)) - logFatal("FATAL ERROR: Unable to query GLX version"); - flogInfo("GLX version %d.%d", glxMajor % glxMinor); + fatal("FATAL ERROR: Unable to query GLX version"); + info("GLX version ",glxMajor,".",glxMinor); // clipboard related atoms x11.atomClipboard = XInternAtom(x11.display, "CLIPBOARD", False); @@ -352,7 +352,7 @@ void Platform::poll() keysym != XK_Escape && (uchar)(buf[0]) >= 32 ) { - //logDebug("char: %c code: %d", buf[0], (uchar)buf[0]); + //debug("char: ", buf[0], " code: ", (uint)buf[0]); inputEvent.type = EV_TEXT_ENTER; inputEvent.keychar = buf[0]; inputEvent.keycode = KC_UNKNOWN; @@ -500,12 +500,12 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i // choose OpenGL, RGBA, double buffered, visual x11.visual = glXChooseVisual(x11.display, DefaultScreen(x11.display), attrList); if(!x11.visual) - logFatal("FATAL ERROR: RGBA/Double buffered visual not supported"); + fatal("FATAL ERROR: RGBA/Double buffered visual not supported"); // create GLX context x11.glxContext = glXCreateContext(x11.display, x11.visual, 0, GL_TRUE); if(!x11.glxContext) - logFatal("FATAL ERROR: Unable to create GLX context"); + fatal("FATAL ERROR: Unable to create GLX context"); // color map x11.colormap = XCreateColormap(x11.display, @@ -538,7 +538,7 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i &wa); if(!x11.window) - logFatal("FATAL ERROR: Unable to create X window"); + fatal("FATAL ERROR: Unable to create X window"); // create input context (to have better key input handling) if(XSupportsLocale()) { @@ -550,14 +550,14 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i XIMPreeditNothing | XIMStatusNothing, XNClientWindow, x11.window, NULL); if(!x11.xic) - logError("ERROR: Unable to create the input context"); + error("ERROR: Unable to create the input context"); } else - logError("ERROR: Failed to open an input method"); + error("ERROR: Failed to open an input method"); } else - logError("ERROR: X11 does not support the current locale"); + error("ERROR: X11 does not support the current locale"); if(!x11.xic) - logWarning("Input of special keys maybe messed up because we couldn't create an input context"); + warning("Input of special keys maybe messed up because we couldn't create an input context"); // set window minimum size @@ -839,6 +839,6 @@ std::string Platform::getAppUserDir() std::stringstream sdir; sdir << PHYSFS_getUserDir() << "." << x11.appName; if((mkdir(sdir.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST)) - flogError("ERROR: Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str()); + error("ERROR: Couldn't create directory for saving configuration file. (",sdir.str(),")"); return sdir.str(); } diff --git a/src/framework/script/luafunctions.cpp b/src/framework/script/luafunctions.cpp index 672de75a..f78b7b63 100644 --- a/src/framework/script/luafunctions.cpp +++ b/src/framework/script/luafunctions.cpp @@ -22,7 +22,7 @@ */ -#include +#include #include