From c3957c2c2a69bbf71c3fb76bede17a180d3396cc Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sun, 11 Feb 2024 23:09:01 +0200 Subject: [PATCH] Moved json files to new directory, split on per-class basis --- client/CMusicHandler.cpp | 1 - client/CPlayerInterface.cpp | 1 - client/gui/InterfaceObjectConfigurable.cpp | 3 +- client/gui/InterfaceObjectConfigurable.h | 2 +- client/mainmenu/CMainMenu.cpp | 1 - client/mainmenu/CMainMenu.h | 2 +- client/render/CAnimation.cpp | 2 +- client/render/ColorFilter.cpp | 2 +- client/render/Colors.cpp | 5 +- client/render/Graphics.cpp | 2 +- client/renderSDL/CBitmapHanFont.cpp | 2 +- client/renderSDL/CTrueTypeFont.cpp | 2 +- client/renderSDL/SDLImage.cpp | 2 +- client/renderSDL/ScreenHandler.cpp | 1 + launcher/jsonutils.cpp | 2 + launcher/jsonutils.h | 3 +- launcher/modManager/cmodlist.cpp | 1 - lib/BasicTypes.cpp | 1 - lib/BattleFieldHandler.cpp | 2 +- lib/CArtHandler.cpp | 2 +- lib/CBonusTypeHandler.cpp | 2 +- lib/CConfigHandler.cpp | 7 +- lib/CConfigHandler.h | 2 +- lib/CCreatureHandler.cpp | 1 + lib/CCreatureHandler.h | 1 - lib/CHeroHandler.cpp | 2 +- lib/CMakeLists.txt | 22 +- lib/CSkillHandler.cpp | 4 +- lib/CStack.h | 1 - lib/CTownHandler.cpp | 2 +- lib/GameSettings.cpp | 2 +- lib/LogicalExpression.h | 3 +- lib/ObstacleHandler.cpp | 2 +- lib/ResourceSet.cpp | 1 - lib/RiverHandler.cpp | 2 +- lib/RoadHandler.cpp | 2 +- lib/ScriptHandler.h | 2 +- lib/TerrainHandler.cpp | 2 +- lib/bonuses/Bonus.cpp | 1 + lib/bonuses/BonusEnum.cpp | 7 +- lib/bonuses/BonusList.cpp | 3 +- lib/bonuses/BonusParams.h | 2 +- lib/bonuses/Limiters.cpp | 1 + lib/bonuses/Updaters.cpp | 3 +- lib/campaign/CampaignState.cpp | 1 - lib/filesystem/AdapterLoaders.cpp | 2 +- lib/filesystem/Filesystem.cpp | 2 +- lib/filesystem/ResourcePath.cpp | 1 - lib/gameState/CGameState.cpp | 1 + lib/json/JsonNode.cpp | 430 +++++++++++ lib/{ => json}/JsonNode.h | 95 +-- lib/json/JsonParser.cpp | 465 ++++++++++++ lib/json/JsonParser.h | 82 +++ lib/{ => json}/JsonRandom.cpp | 31 +- lib/{ => json}/JsonRandom.h | 0 lib/{JsonNode.cpp => json/JsonUtils.cpp} | 452 +----------- lib/json/JsonUtils.h | 104 +++ lib/json/JsonValidator.cpp | 687 ++++++++++++++++++ lib/json/JsonValidator.h | 49 ++ lib/json/JsonWriter.cpp | 144 ++++ lib/json/JsonWriter.h | 35 + .../AObjectTypeHandler.cpp | 3 +- .../AObjectTypeHandler.h | 2 +- .../CBankInstanceConstructor.cpp | 2 +- .../CBankInstanceConstructor.h | 1 + .../CObjectClassesHandler.cpp | 2 +- .../CObjectClassesHandler.h | 3 +- .../CommonConstructors.cpp | 2 +- .../DwellingInstanceConstructor.cpp | 2 +- .../DwellingInstanceConstructor.h | 2 + .../HillFortInstanceConstructor.h | 1 + .../ShipyardInstanceConstructor.h | 1 + lib/mapObjects/CGHeroInstance.cpp | 1 + lib/mapObjects/CObjectHandler.cpp | 2 +- lib/mapObjects/ObjectTemplate.cpp | 1 - lib/mapping/CMapHeader.cpp | 1 + lib/mapping/CMapHeader.h | 2 + lib/mapping/CMapService.cpp | 1 + lib/mapping/MapEditUtils.cpp | 1 - lib/mapping/MapFormatJson.cpp | 4 +- lib/mapping/MapFormatJson.h | 1 - lib/mapping/MapIdentifiersH3M.cpp | 1 - lib/modding/CModHandler.cpp | 1 + lib/modding/CModInfo.h | 2 +- lib/modding/ContentTypeHandler.cpp | 1 + lib/modding/ContentTypeHandler.h | 2 +- lib/modding/IdentifierStorage.cpp | 1 - lib/networkPacks/BattleChanges.h | 2 +- lib/networkPacks/EntityChanges.h | 4 +- lib/rewardable/Info.cpp | 2 +- lib/rewardable/Info.h | 2 +- lib/serializer/JsonDeserializer.cpp | 2 - lib/serializer/JsonSerializeFormat.cpp | 2 - lib/serializer/JsonSerializeFormat.h | 3 +- lib/serializer/JsonSerializer.cpp | 2 - lib/serializer/JsonUpdater.cpp | 3 +- lib/spells/CSpellHandler.cpp | 2 +- lib/spells/CSpellHandler.h | 2 +- lib/spells/TargetCondition.cpp | 2 +- lib/spells/effects/Moat.cpp | 1 + lib/spells/effects/Timed.cpp | 1 + mapeditor/Animation.cpp | 2 +- mapeditor/Animation.h | 5 +- mapeditor/graphics.cpp | 1 - mapeditor/jsonutils.cpp | 2 + mapeditor/jsonutils.h | 3 +- mapeditor/maphandler.cpp | 1 - .../resourceExtractor/ResourceConverter.cpp | 1 - scripting/lua/LuaScriptingContext.cpp | 2 +- scripting/lua/LuaSpellEffect.cpp | 1 + scripting/lua/LuaStack.cpp | 2 +- scripting/lua/api/BonusSystem.cpp | 2 +- test/JsonComparer.h | 2 +- test/entity/CCreatureTest.cpp | 1 + test/game/CGameStateTest.cpp | 1 + test/map/CMapEditManagerTest.cpp | 1 - test/map/CMapFormatTest.cpp | 2 - test/mock/BattleFake.h | 1 - test/mock/mock_scripting_Context.h | 2 +- test/scripting/LuaSpellEffectAPITest.cpp | 1 + test/scripting/LuaSpellEffectTest.cpp | 1 + test/scripting/ScriptFixture.h | 2 +- test/spells/effects/CloneTest.cpp | 1 + test/spells/effects/DamageTest.cpp | 1 + test/spells/effects/DispelTest.cpp | 1 + test/spells/effects/EffectFixture.h | 1 - test/spells/effects/HealTest.cpp | 1 + test/spells/effects/SacrificeTest.cpp | 1 + test/spells/effects/SummonTest.cpp | 1 + test/spells/effects/TeleportTest.cpp | 1 + test/spells/effects/TimedTest.cpp | 3 +- 131 files changed, 2164 insertions(+), 653 deletions(-) create mode 100644 lib/json/JsonNode.cpp rename lib/{ => json}/JsonNode.h (56%) create mode 100644 lib/json/JsonParser.cpp create mode 100644 lib/json/JsonParser.h rename lib/{ => json}/JsonRandom.cpp (97%) rename lib/{ => json}/JsonRandom.h (100%) rename lib/{JsonNode.cpp => json/JsonUtils.cpp} (77%) create mode 100644 lib/json/JsonUtils.h create mode 100644 lib/json/JsonValidator.cpp create mode 100644 lib/json/JsonValidator.h create mode 100644 lib/json/JsonWriter.cpp create mode 100644 lib/json/JsonWriter.h diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index 1339a4de9..bb8cf46ee 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -17,7 +17,6 @@ #include "eventsSDL/InputHandler.h" #include "gui/CGuiHandler.h" -#include "../lib/JsonNode.h" #include "../lib/GameConstants.h" #include "../lib/filesystem/Filesystem.h" #include "../lib/constants/StringConstants.h" diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 3d08ad7d9..0a5a548d1 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -75,7 +75,6 @@ #include "../lib/CTownHandler.h" #include "../lib/CondSh.h" #include "../lib/GameConstants.h" -#include "../lib/JsonNode.h" #include "../lib/RoadHandler.h" #include "../lib/StartInfo.h" #include "../lib/TerrainHandler.h" diff --git a/client/gui/InterfaceObjectConfigurable.cpp b/client/gui/InterfaceObjectConfigurable.cpp index b12bb75b1..38ad05cad 100644 --- a/client/gui/InterfaceObjectConfigurable.cpp +++ b/client/gui/InterfaceObjectConfigurable.cpp @@ -29,7 +29,8 @@ #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" -#include "../../lib//constants/StringConstants.h" +#include "../../lib/constants/StringConstants.h" +#include "../../lib/json/JsonUtils.h" #include "../../lib/CGeneralTextHandler.h" #include "../../lib/filesystem/ResourcePath.h" diff --git a/client/gui/InterfaceObjectConfigurable.h b/client/gui/InterfaceObjectConfigurable.h index cc812299e..b1ce32b67 100644 --- a/client/gui/InterfaceObjectConfigurable.h +++ b/client/gui/InterfaceObjectConfigurable.h @@ -14,7 +14,7 @@ #include "TextAlignment.h" #include "../render/EFont.h" -#include "../../lib/JsonNode.h" +#include "../../lib/json/JsonNode.h" class CPicture; class CLabel; diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index 613812f1a..f36e0718e 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/client/mainmenu/CMainMenu.cpp @@ -45,7 +45,6 @@ #include "../../CCallback.h" #include "../../lib/CGeneralTextHandler.h" -#include "../../lib/JsonNode.h" #include "../../lib/campaign/CampaignHandler.h" #include "../../lib/serializer/CTypeList.h" #include "../../lib/filesystem/Filesystem.h" diff --git a/client/mainmenu/CMainMenu.h b/client/mainmenu/CMainMenu.h index 32576d85b..e4d62aef1 100644 --- a/client/mainmenu/CMainMenu.h +++ b/client/mainmenu/CMainMenu.h @@ -10,7 +10,7 @@ #pragma once #include "../windows/CWindowObject.h" -#include "../../lib/JsonNode.h" +#include "../../lib/json/JsonNode.h" #include "../../lib/LoadProgress.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/client/render/CAnimation.cpp b/client/render/CAnimation.cpp index 662f41ccc..91ca64c0f 100644 --- a/client/render/CAnimation.cpp +++ b/client/render/CAnimation.cpp @@ -14,7 +14,7 @@ #include "Graphics.h" #include "../../lib/filesystem/Filesystem.h" -#include "../../lib/JsonNode.h" +#include "../../lib/json/JsonUtils.h" #include "../renderSDL/SDLImage.h" std::shared_ptr CAnimation::getFromExtraDef(std::string filename) diff --git a/client/render/ColorFilter.cpp b/client/render/ColorFilter.cpp index d6234116f..793c1b647 100644 --- a/client/render/ColorFilter.cpp +++ b/client/render/ColorFilter.cpp @@ -10,8 +10,8 @@ #include "StdInc.h" #include "ColorFilter.h" -#include "../../lib/JsonNode.h" #include "../../lib/Color.h" +#include "../../lib/json/JsonNode.h" ColorRGBA ColorFilter::shiftColor(const ColorRGBA & in) const { diff --git a/client/render/Colors.cpp b/client/render/Colors.cpp index e53f55543..d0bd8e23f 100644 --- a/client/render/Colors.cpp +++ b/client/render/Colors.cpp @@ -10,7 +10,8 @@ #include "StdInc.h" #include "Colors.h" -#include "../../lib/JsonNode.h" + +#include "../../lib/json/JsonNode.h" const ColorRGBA Colors::YELLOW = { 229, 215, 123, ColorRGBA::ALPHA_OPAQUE }; const ColorRGBA Colors::WHITE = { 255, 243, 222, ColorRGBA::ALPHA_OPAQUE }; @@ -48,4 +49,4 @@ std::optional Colors::parseColor(std::string text) } return std::nullopt; -} \ No newline at end of file +} diff --git a/client/render/Graphics.cpp b/client/render/Graphics.cpp index 603972feb..023a6ce55 100644 --- a/client/render/Graphics.cpp +++ b/client/render/Graphics.cpp @@ -29,13 +29,13 @@ #include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/CBinaryReader.h" +#include "../../lib/json/JsonNode.h" #include "../lib/modding/CModHandler.h" #include "../lib/modding/ModScope.h" #include "CGameInfo.h" #include "../lib/VCMI_Lib.h" #include "../CCallback.h" #include "../lib/CGeneralTextHandler.h" -#include "../lib/JsonNode.h" #include "../lib/vcmi_endian.h" #include "../lib/CStopWatch.h" #include "../lib/CHeroHandler.h" diff --git a/client/renderSDL/CBitmapHanFont.cpp b/client/renderSDL/CBitmapHanFont.cpp index cb527d054..ac1684185 100644 --- a/client/renderSDL/CBitmapHanFont.cpp +++ b/client/renderSDL/CBitmapHanFont.cpp @@ -13,8 +13,8 @@ #include "CBitmapFont.h" #include "SDL_Extensions.h" -#include "../../lib/JsonNode.h" #include "../../lib/filesystem/Filesystem.h" +#include "../../lib/json/JsonNode.h" #include "../../lib/TextOperations.h" #include "../../lib/Rect.h" diff --git a/client/renderSDL/CTrueTypeFont.cpp b/client/renderSDL/CTrueTypeFont.cpp index b9d19aa12..e977a6c4c 100644 --- a/client/renderSDL/CTrueTypeFont.cpp +++ b/client/renderSDL/CTrueTypeFont.cpp @@ -15,8 +15,8 @@ #include "../render/Colors.h" #include "../renderSDL/SDL_Extensions.h" -#include "../../lib/JsonNode.h" #include "../../lib/TextOperations.h" +#include "../../lib/json/JsonNode.h" #include "../../lib/filesystem/Filesystem.h" #include diff --git a/client/renderSDL/SDLImage.cpp b/client/renderSDL/SDLImage.cpp index 84373ad46..465597b63 100644 --- a/client/renderSDL/SDLImage.cpp +++ b/client/renderSDL/SDLImage.cpp @@ -18,7 +18,7 @@ #include "../render/CDefFile.h" #include "../render/Graphics.h" -#include "../../lib/JsonNode.h" +#include "../../lib/json/JsonNode.h" #include diff --git a/client/renderSDL/ScreenHandler.cpp b/client/renderSDL/ScreenHandler.cpp index 265c3b021..f8ceb26f1 100644 --- a/client/renderSDL/ScreenHandler.cpp +++ b/client/renderSDL/ScreenHandler.cpp @@ -12,6 +12,7 @@ #include "ScreenHandler.h" #include "../../lib/CConfigHandler.h" +#include "../../lib/constants/StringConstants.h" #include "../gui/CGuiHandler.h" #include "../eventsSDL/NotificationHandler.h" #include "../gui/WindowHandler.h" diff --git a/launcher/jsonutils.cpp b/launcher/jsonutils.cpp index 895eee540..0f472f096 100644 --- a/launcher/jsonutils.cpp +++ b/launcher/jsonutils.cpp @@ -10,6 +10,8 @@ #include "StdInc.h" #include "jsonutils.h" +#include "../lib/json/JsonNode.h" + static QVariantMap JsonToMap(const JsonMap & json) { QVariantMap map; diff --git a/launcher/jsonutils.h b/launcher/jsonutils.h index 6dd7e7bbf..791711eb0 100644 --- a/launcher/jsonutils.h +++ b/launcher/jsonutils.h @@ -10,10 +10,11 @@ #pragma once #include -#include "../lib/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN +class JsonNode; + namespace JsonUtils { QVariant toVariant(const JsonNode & node); diff --git a/launcher/modManager/cmodlist.cpp b/launcher/modManager/cmodlist.cpp index 6facca796..e1a516e27 100644 --- a/launcher/modManager/cmodlist.cpp +++ b/launcher/modManager/cmodlist.cpp @@ -11,7 +11,6 @@ #include "cmodlist.h" #include "../lib/CConfigHandler.h" -#include "../../lib/JsonNode.h" #include "../../lib/filesystem/CFileInputStream.h" #include "../../lib/GameConstants.h" #include "../../lib/modding/CModVersion.h" diff --git a/lib/BasicTypes.cpp b/lib/BasicTypes.cpp index 5ff9a1fe0..b366bda55 100644 --- a/lib/BasicTypes.cpp +++ b/lib/BasicTypes.cpp @@ -13,7 +13,6 @@ #include "VCMI_Lib.h" #include "GameConstants.h" #include "GameSettings.h" -#include "JsonNode.h" #include "bonuses/BonusList.h" #include "bonuses/Bonus.h" #include "bonuses/IBonusBearer.h" diff --git a/lib/BattleFieldHandler.cpp b/lib/BattleFieldHandler.cpp index c0791c568..672e7cf12 100644 --- a/lib/BattleFieldHandler.cpp +++ b/lib/BattleFieldHandler.cpp @@ -11,7 +11,7 @@ #include #include "BattleFieldHandler.h" -#include "JsonNode.h" +#include "json/JsonUtils.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index b932542fc..bbe046d43 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -15,7 +15,7 @@ #include "GameSettings.h" #include "mapObjects/MapObjects.h" #include "constants/StringConstants.h" - +#include "json/JsonUtils.h" #include "mapObjectConstructors/AObjectTypeHandler.h" #include "mapObjectConstructors/CObjectClassesHandler.h" #include "serializer/JsonSerializeFormat.h" diff --git a/lib/CBonusTypeHandler.cpp b/lib/CBonusTypeHandler.cpp index ba86a2d8e..c77a66c3b 100644 --- a/lib/CBonusTypeHandler.cpp +++ b/lib/CBonusTypeHandler.cpp @@ -13,12 +13,12 @@ #include "CBonusTypeHandler.h" -#include "JsonNode.h" #include "filesystem/Filesystem.h" #include "GameConstants.h" #include "CCreatureHandler.h" #include "CGeneralTextHandler.h" +#include "json/JsonUtils.h" #include "spells/CSpellHandler.h" template class std::vector; diff --git a/lib/CConfigHandler.cpp b/lib/CConfigHandler.cpp index 5df984740..5b7924edc 100644 --- a/lib/CConfigHandler.cpp +++ b/lib/CConfigHandler.cpp @@ -10,9 +10,10 @@ #include "StdInc.h" #include "CConfigHandler.h" -#include "../lib/filesystem/Filesystem.h" -#include "../lib/GameConstants.h" -#include "../lib/VCMIDirs.h" +#include "filesystem/Filesystem.h" +#include "GameConstants.h" +#include "VCMIDirs.h" +#include "json/JsonUtils.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/CConfigHandler.h b/lib/CConfigHandler.h index a446d8e5c..915863a52 100644 --- a/lib/CConfigHandler.h +++ b/lib/CConfigHandler.h @@ -9,7 +9,7 @@ */ #pragma once -#include "../lib/JsonNode.h" +#include "json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 87889fe1d..8fe85a7a1 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -20,6 +20,7 @@ #include "constants/StringConstants.h" #include "bonuses/Limiters.h" #include "bonuses/Updaters.h" +#include "json/JsonUtils.h" #include "serializer/JsonDeserializer.h" #include "serializer/JsonUpdater.h" #include "mapObjectConstructors/AObjectTypeHandler.h" diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 4bfada15d..b38652ba4 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -14,7 +14,6 @@ #include "ConstTransitivePtr.h" #include "ResourceSet.h" #include "GameConstants.h" -#include "JsonNode.h" #include "IHandlerBase.h" #include "Color.h" #include "filesystem/ResourcePath.h" diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index b8ba71690..413d10fe6 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -13,7 +13,6 @@ #include "CGeneralTextHandler.h" #include "filesystem/Filesystem.h" #include "VCMI_Lib.h" -#include "JsonNode.h" #include "constants/StringConstants.h" #include "battle/BattleHex.h" #include "CCreatureHandler.h" @@ -24,6 +23,7 @@ #include "BattleFieldHandler.h" #include "bonuses/Limiters.h" #include "bonuses/Updaters.h" +#include "json/JsonUtils.h" #include "mapObjectConstructors/AObjectTypeHandler.h" #include "mapObjectConstructors/CObjectClassesHandler.h" #include "modding/IdentifierStorage.h" diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7cfd624a6..a74e3d195 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -61,6 +61,13 @@ set(lib_SRCS filesystem/MinizipExtensions.cpp filesystem/ResourcePath.cpp + json/JsonNode.cpp + json/JsonParser.cpp + json/JsonRandom.cpp + json/JsonUtils.cpp + json/JsonValidator.cpp + json/JsonWriter.cpp + gameState/CGameState.cpp gameState/CGameStateCampaign.cpp gameState/InfoAboutArmy.cpp @@ -245,9 +252,6 @@ set(lib_SRCS GameSettings.cpp IGameCallback.cpp IHandlerBase.cpp - JsonDetail.cpp - JsonNode.cpp - JsonRandom.cpp LoadProgress.cpp LogicalExpression.cpp MetaString.cpp @@ -399,6 +403,13 @@ set(lib_HEADERS filesystem/MinizipExtensions.h filesystem/ResourcePath.h + json/JsonNode.h + json/JsonParser.h + json/JsonRandom.h + json/JsonUtils.h + json/JsonValidator.h + json/JsonWriter.h + gameState/CGameState.h gameState/CGameStateCampaign.h gameState/EVictoryLossCheckResult.h @@ -636,9 +647,6 @@ set(lib_HEADERS IGameEventsReceiver.h IHandlerBase.h int3.h - JsonDetail.h - JsonNode.h - JsonRandom.h Languages.h LoadProgress.h LogicalExpression.h @@ -772,4 +780,4 @@ if(APPLE_IOS AND NOT USING_CONAN) endif() install(${INSTALL_TYPE} ${LINKED_LIB_REAL} LIBRARY DESTINATION ${LIB_DIR}) endforeach() -endif() \ No newline at end of file +endif() diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 1c186e009..f6fa25fe9 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -16,12 +16,10 @@ #include "CGeneralTextHandler.h" #include "filesystem/Filesystem.h" +#include "json/JsonUtils.h" #include "modding/IdentifierStorage.h" #include "modding/ModUtility.h" #include "modding/ModScope.h" - -#include "JsonNode.h" - #include "constants/StringConstants.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/CStack.h b/lib/CStack.h index 915f8de5a..3252a722a 100644 --- a/lib/CStack.h +++ b/lib/CStack.h @@ -9,7 +9,6 @@ */ #pragma once -#include "JsonNode.h" #include "bonuses/Bonus.h" #include "bonuses/CBonusSystemNode.h" #include "CCreatureHandler.h" //todo: remove diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index cac5982bc..a540a7c71 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -12,7 +12,6 @@ #include "VCMI_Lib.h" #include "CGeneralTextHandler.h" -#include "JsonNode.h" #include "constants/StringConstants.h" #include "CCreatureHandler.h" #include "CHeroHandler.h" @@ -23,6 +22,7 @@ #include "filesystem/Filesystem.h" #include "bonuses/Bonus.h" #include "bonuses/Propagators.h" +#include "json/JsonUtils.h" #include "ResourceSet.h" #include "mapObjectConstructors/AObjectTypeHandler.h" #include "mapObjectConstructors/CObjectClassesHandler.h" diff --git a/lib/GameSettings.cpp b/lib/GameSettings.cpp index 3bfa34b2b..6f59f69bc 100644 --- a/lib/GameSettings.cpp +++ b/lib/GameSettings.cpp @@ -9,7 +9,7 @@ */ #include "StdInc.h" #include "GameSettings.h" -#include "JsonNode.h" +#include "json/JsonUtils.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/LogicalExpression.h b/lib/LogicalExpression.h index 10cf000cb..673662cef 100644 --- a/lib/LogicalExpression.h +++ b/lib/LogicalExpression.h @@ -9,8 +9,7 @@ */ #pragma once -//FIXME: move some of code into .cpp to avoid this include? -#include "JsonNode.h" +#include "json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/ObstacleHandler.cpp b/lib/ObstacleHandler.cpp index f85eae74c..d7b613959 100644 --- a/lib/ObstacleHandler.cpp +++ b/lib/ObstacleHandler.cpp @@ -10,8 +10,8 @@ #include "StdInc.h" #include "ObstacleHandler.h" #include "BattleFieldHandler.h" +#include "json/JsonNode.h" #include "modding/IdentifierStorage.h" -#include "JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/ResourceSet.cpp b/lib/ResourceSet.cpp index be8986312..71db0db46 100644 --- a/lib/ResourceSet.cpp +++ b/lib/ResourceSet.cpp @@ -12,7 +12,6 @@ #include "GameConstants.h" #include "ResourceSet.h" #include "constants/StringConstants.h" -#include "JsonNode.h" #include "serializer/JsonSerializeFormat.h" #include "mapObjects/CObjectHandler.h" #include "VCMI_Lib.h" diff --git a/lib/RiverHandler.cpp b/lib/RiverHandler.cpp index ca0a28756..7ed62a7a5 100644 --- a/lib/RiverHandler.cpp +++ b/lib/RiverHandler.cpp @@ -12,7 +12,7 @@ #include "RiverHandler.h" #include "CGeneralTextHandler.h" #include "GameSettings.h" -#include "JsonNode.h" +#include "json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/RoadHandler.cpp b/lib/RoadHandler.cpp index 0ae298dfb..5ebbe54f1 100644 --- a/lib/RoadHandler.cpp +++ b/lib/RoadHandler.cpp @@ -12,7 +12,7 @@ #include "RoadHandler.h" #include "CGeneralTextHandler.h" #include "GameSettings.h" -#include "JsonNode.h" +#include "json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/ScriptHandler.h b/lib/ScriptHandler.h index a29688ada..57f84b0f8 100644 --- a/lib/ScriptHandler.h +++ b/lib/ScriptHandler.h @@ -13,7 +13,7 @@ #if SCRIPTING_ENABLED #include #include "IHandlerBase.h" -#include "JsonNode.h" +#include "json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/TerrainHandler.cpp b/lib/TerrainHandler.cpp index 805f41362..6980d98b8 100644 --- a/lib/TerrainHandler.cpp +++ b/lib/TerrainHandler.cpp @@ -12,7 +12,7 @@ #include "TerrainHandler.h" #include "CGeneralTextHandler.h" #include "GameSettings.h" -#include "JsonNode.h" +#include "json/JsonNode.h" #include "modding/IdentifierStorage.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/bonuses/Bonus.cpp b/lib/bonuses/Bonus.cpp index c0324824c..6f7a04d3e 100644 --- a/lib/bonuses/Bonus.cpp +++ b/lib/bonuses/Bonus.cpp @@ -26,6 +26,7 @@ #include "../TerrainHandler.h" #include "../constants/StringConstants.h" #include "../battle/BattleInfo.h" +#include "../json/JsonUtils.h" #include "../modding/ModUtility.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/bonuses/BonusEnum.cpp b/lib/bonuses/BonusEnum.cpp index 903e3a32f..ed5fe7c59 100644 --- a/lib/bonuses/BonusEnum.cpp +++ b/lib/bonuses/BonusEnum.cpp @@ -7,13 +7,10 @@ * Full text of license available in license.txt file, in main folder * */ - - #include "StdInc.h" #include "BonusEnum.h" - -#include "../JsonNode.h" +#include "../json/JsonUtils.h" VCMI_LIB_NAMESPACE_BEGIN @@ -82,4 +79,4 @@ namespace BonusDuration } } -VCMI_LIB_NAMESPACE_END \ No newline at end of file +VCMI_LIB_NAMESPACE_END diff --git a/lib/bonuses/BonusList.cpp b/lib/bonuses/BonusList.cpp index 4920881b3..3fbabefe3 100644 --- a/lib/bonuses/BonusList.cpp +++ b/lib/bonuses/BonusList.cpp @@ -10,8 +10,7 @@ #include "StdInc.h" #include "CBonusSystemNode.h" - -#include "../JsonNode.h" +#include "../json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/bonuses/BonusParams.h b/lib/bonuses/BonusParams.h index b0b2d3ef2..57e79c43a 100644 --- a/lib/bonuses/BonusParams.h +++ b/lib/bonuses/BonusParams.h @@ -12,7 +12,7 @@ #include "Bonus.h" #include "../GameConstants.h" -#include "../JsonNode.h" +#include "../json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/bonuses/Limiters.cpp b/lib/bonuses/Limiters.cpp index b0e031368..2e952a56f 100644 --- a/lib/bonuses/Limiters.cpp +++ b/lib/bonuses/Limiters.cpp @@ -24,6 +24,7 @@ #include "../TerrainHandler.h" #include "../constants/StringConstants.h" #include "../battle/BattleInfo.h" +#include "../json/JsonUtils.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/bonuses/Updaters.cpp b/lib/bonuses/Updaters.cpp index 0debdaabc..5729574c0 100644 --- a/lib/bonuses/Updaters.cpp +++ b/lib/bonuses/Updaters.cpp @@ -13,6 +13,7 @@ #include "Updaters.h" #include "Limiters.h" +#include "../json/JsonUtils.h" #include "../mapObjects/CGHeroInstance.h" #include "../CStack.h" @@ -208,4 +209,4 @@ std::shared_ptr OwnerUpdater::createUpdatedBonus(const std::shared_ptr +Node & resolvePointer(Node & in, const std::string & pointer) +{ + if(pointer.empty()) + return in; + assert(pointer[0] == '/'); + + size_t splitPos = pointer.find('/', 1); + + std::string entry = pointer.substr(1, splitPos - 1); + std::string remainer = splitPos == std::string::npos ? "" : pointer.substr(splitPos); + + if(in.getType() == VCMI_LIB_WRAP_NAMESPACE(JsonNode)::JsonType::DATA_VECTOR) + { + if(entry.find_first_not_of("0123456789") != std::string::npos) // non-numbers in string + throw std::runtime_error("Invalid Json pointer"); + + if(entry.size() > 1 && entry[0] == '0') // leading zeros are not allowed + throw std::runtime_error("Invalid Json pointer"); + + auto index = boost::lexical_cast(entry); + + if (in.Vector().size() > index) + return in.Vector()[index].resolvePointer(remainer); + } + return in[entry].resolvePointer(remainer); +} +} + +VCMI_LIB_NAMESPACE_BEGIN + +using namespace JsonDetail; + +class LibClasses; +class CModHandler; + +static const JsonNode nullNode; + +JsonNode::JsonNode(JsonType Type) +{ + setType(Type); +} + +JsonNode::JsonNode(const std::byte *data, size_t datasize) + :JsonNode(reinterpret_cast(data), datasize) +{} + +JsonNode::JsonNode(const char *data, size_t datasize) +{ + JsonParser parser(data, datasize); + *this = parser.parse(""); +} + +JsonNode::JsonNode(const JsonPath & fileURI) +{ + auto file = CResourceHandler::get()->load(fileURI)->readAll(); + + JsonParser parser(reinterpret_cast(file.first.get()), file.second); + *this = parser.parse(fileURI.getName()); +} + +JsonNode::JsonNode(const std::string & idx, const JsonPath & fileURI) +{ + auto file = CResourceHandler::get(idx)->load(fileURI)->readAll(); + + JsonParser parser(reinterpret_cast(file.first.get()), file.second); + *this = parser.parse(fileURI.getName()); +} + +JsonNode::JsonNode(const JsonPath & fileURI, bool &isValidSyntax) +{ + auto file = CResourceHandler::get()->load(fileURI)->readAll(); + + JsonParser parser(reinterpret_cast(file.first.get()), file.second); + *this = parser.parse(fileURI.getName()); + isValidSyntax = parser.isValid(); +} + +bool JsonNode::operator == (const JsonNode &other) const +{ + return data == other.data; +} + +bool JsonNode::operator != (const JsonNode &other) const +{ + return !(*this == other); +} + +JsonNode::JsonType JsonNode::getType() const +{ + return static_cast(data.index()); +} + +void JsonNode::setMeta(const std::string & metadata, bool recursive) +{ + meta = metadata; + if (recursive) + { + switch (getType()) + { + break; case JsonType::DATA_VECTOR: + { + for(auto & node : Vector()) + { + node.setMeta(metadata); + } + } + break; case JsonType::DATA_STRUCT: + { + for(auto & node : Struct()) + { + node.second.setMeta(metadata); + } + } + } + } +} + +void JsonNode::setType(JsonType Type) +{ + if (getType() == Type) + return; + + //float<->int conversion + if(getType() == JsonType::DATA_FLOAT && Type == JsonType::DATA_INTEGER) + { + si64 converted = static_cast(std::get(data)); + data = JsonData(converted); + return; + } + else if(getType() == JsonType::DATA_INTEGER && Type == JsonType::DATA_FLOAT) + { + double converted = static_cast(std::get(data)); + data = JsonData(converted); + return; + } + + //Set new node type + switch(Type) + { + break; case JsonType::DATA_NULL: data = JsonData(); + break; case JsonType::DATA_BOOL: data = JsonData(false); + break; case JsonType::DATA_FLOAT: data = JsonData(static_cast(0.0)); + break; case JsonType::DATA_STRING: data = JsonData(std::string()); + break; case JsonType::DATA_VECTOR: data = JsonData(JsonVector()); + break; case JsonType::DATA_STRUCT: data = JsonData(JsonMap()); + break; case JsonType::DATA_INTEGER: data = JsonData(static_cast(0)); + } +} + +bool JsonNode::isNull() const +{ + return getType() == JsonType::DATA_NULL; +} + +bool JsonNode::isNumber() const +{ + return getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT; +} + +bool JsonNode::isString() const +{ + return getType() == JsonType::DATA_STRING; +} + +bool JsonNode::isVector() const +{ + return getType() == JsonType::DATA_VECTOR; +} + +bool JsonNode::isStruct() const +{ + return getType() == JsonType::DATA_STRUCT; +} + +bool JsonNode::containsBaseData() const +{ + switch(getType()) + { + case JsonType::DATA_NULL: + return false; + case JsonType::DATA_STRUCT: + for(const auto & elem : Struct()) + { + if(elem.second.containsBaseData()) + return true; + } + return false; + default: + //other types (including vector) cannot be extended via merge + return true; + } +} + +bool JsonNode::isCompact() const +{ + switch(getType()) + { + case JsonType::DATA_VECTOR: + for(const JsonNode & elem : Vector()) + { + if(!elem.isCompact()) + return false; + } + return true; + case JsonType::DATA_STRUCT: + { + auto propertyCount = Struct().size(); + if(propertyCount == 0) + return true; + else if(propertyCount == 1) + return Struct().begin()->second.isCompact(); + } + return false; + default: + return true; + } +} + +bool JsonNode::TryBoolFromString(bool & success) const +{ + success = true; + if(getType() == JsonNode::JsonType::DATA_BOOL) + return Bool(); + + success = getType() == JsonNode::JsonType::DATA_STRING; + if(success) + { + auto boolParamStr = String(); + boost::algorithm::trim(boolParamStr); + boost::algorithm::to_lower(boolParamStr); + success = boolParamStr == "true"; + + if(success) + return true; + + success = boolParamStr == "false"; + } + return false; +} + +void JsonNode::clear() +{ + setType(JsonType::DATA_NULL); +} + +bool & JsonNode::Bool() +{ + setType(JsonType::DATA_BOOL); + return std::get(data); +} + +double & JsonNode::Float() +{ + setType(JsonType::DATA_FLOAT); + return std::get(data); +} + +si64 & JsonNode::Integer() +{ + setType(JsonType::DATA_INTEGER); + return std::get(data); +} + +std::string & JsonNode::String() +{ + setType(JsonType::DATA_STRING); + return std::get(data); +} + +JsonVector & JsonNode::Vector() +{ + setType(JsonType::DATA_VECTOR); + return std::get(data); +} + +JsonMap & JsonNode::Struct() +{ + setType(JsonType::DATA_STRUCT); + return std::get(data); +} + +const bool boolDefault = false; +bool JsonNode::Bool() const +{ + assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_BOOL); + + if (getType() == JsonType::DATA_BOOL) + return std::get(data); + + return boolDefault; +} + +const double floatDefault = 0; +double JsonNode::Float() const +{ + assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT); + + if(getType() == JsonType::DATA_FLOAT) + return std::get(data); + + if(getType() == JsonType::DATA_INTEGER) + return static_cast(std::get(data)); + + return floatDefault; +} + +const si64 integerDefault = 0; +si64 JsonNode::Integer() const +{ + assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT); + + if(getType() == JsonType::DATA_INTEGER) + return std::get(data); + + if(getType() == JsonType::DATA_FLOAT) + return static_cast(std::get(data)); + + return integerDefault; +} + +const std::string stringDefault = std::string(); +const std::string & JsonNode::String() const +{ + assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRING); + + if (getType() == JsonType::DATA_STRING) + return std::get(data); + + return stringDefault; +} + +const JsonVector vectorDefault = JsonVector(); +const JsonVector & JsonNode::Vector() const +{ + assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_VECTOR); + + if (getType() == JsonType::DATA_VECTOR) + return std::get(data); + + return vectorDefault; +} + +const JsonMap mapDefault = JsonMap(); +const JsonMap & JsonNode::Struct() const +{ + assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRUCT); + + if (getType() == JsonType::DATA_STRUCT) + return std::get(data); + + return mapDefault; +} + +JsonNode & JsonNode::operator[](const std::string & child) +{ + return Struct()[child]; +} + +const JsonNode & JsonNode::operator[](const std::string & child) const +{ + auto it = Struct().find(child); + if (it != Struct().end()) + return it->second; + return nullNode; +} + +JsonNode & JsonNode::operator[](size_t child) +{ + if (child >= Vector().size() ) + Vector().resize(child + 1); + return Vector()[child]; +} + +const JsonNode & JsonNode::operator[](size_t child) const +{ + if (child < Vector().size() ) + return Vector()[child]; + + return nullNode; +} + +const JsonNode & JsonNode::resolvePointer(const std::string &jsonPointer) const +{ + return ::resolvePointer(*this, jsonPointer); +} + +JsonNode & JsonNode::resolvePointer(const std::string &jsonPointer) +{ + return ::resolvePointer(*this, jsonPointer); +} + +std::vector JsonNode::toBytes(bool compact) const +{ + std::string jsonString = toJson(compact); + auto dataBegin = reinterpret_cast(jsonString.data()); + auto dataEnd = dataBegin + jsonString.size(); + std::vector result(dataBegin, dataEnd); + return result; +} + +std::string JsonNode::toJson(bool compact) const +{ + std::ostringstream out; + JsonWriter writer(out, compact); + writer.writeNode(*this); + return out.str(); +} + +VCMI_LIB_NAMESPACE_END diff --git a/lib/JsonNode.h b/lib/json/JsonNode.h similarity index 56% rename from lib/JsonNode.h rename to lib/json/JsonNode.h index 75f9128b2..ab4fc37f5 100644 --- a/lib/JsonNode.h +++ b/lib/json/JsonNode.h @@ -8,8 +8,8 @@ * */ #pragma once -#include "GameConstants.h" -#include "filesystem/ResourcePath.h" + +#include "../filesystem/ResourcePath.h" VCMI_LIB_NAMESPACE_BEGIN @@ -127,97 +127,6 @@ public: } }; -namespace JsonUtils -{ - DLL_LINKAGE std::shared_ptr parseBonus(const JsonVector & ability_vec); - DLL_LINKAGE std::shared_ptr parseBonus(const JsonNode & ability); - DLL_LINKAGE std::shared_ptr parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description); - DLL_LINKAGE bool parseBonus(const JsonNode & ability, Bonus * placement); - DLL_LINKAGE std::shared_ptr parseLimiter(const JsonNode & limiter); - DLL_LINKAGE CSelector parseSelector(const JsonNode &ability); - DLL_LINKAGE void resolveAddInfo(CAddInfo & var, const JsonNode & node); - - /** - * @brief recursively merges source into dest, replacing identical fields - * struct : recursively calls this function - * arrays : each entry will be merged recursively - * values : value in source will replace value in dest - * null : if value in source is present but set to null it will delete entry in dest - * @note this function will destroy data in source - */ - DLL_LINKAGE void merge(JsonNode & dest, JsonNode & source, bool ignoreOverride = false, bool copyMeta = false); - - /** - * @brief recursively merges source into dest, replacing identical fields - * struct : recursively calls this function - * arrays : each entry will be merged recursively - * values : value in source will replace value in dest - * null : if value in source is present but set to null it will delete entry in dest - * @note this function will preserve data stored in source by creating copy - */ - DLL_LINKAGE void mergeCopy(JsonNode & dest, JsonNode source, bool ignoreOverride = false, bool copyMeta = false); - - /** @brief recursively merges descendant into copy of base node - * Result emulates inheritance semantic - */ - DLL_LINKAGE void inherit(JsonNode & descendant, const JsonNode & base); - - /** - * @brief construct node representing the common structure of input nodes - * @param pruneEmpty - omit common properties whose intersection is empty - * different types: null - * struct: recursive intersect on common properties - * other: input if equal, null otherwise - */ - DLL_LINKAGE JsonNode intersect(const JsonNode & a, const JsonNode & b, bool pruneEmpty = true); - DLL_LINKAGE JsonNode intersect(const std::vector & nodes, bool pruneEmpty = true); - - /** - * @brief construct node representing the difference "node - base" - * merging difference with base gives node - */ - DLL_LINKAGE JsonNode difference(const JsonNode & node, const JsonNode & base); - - /** - * @brief generate one Json structure from multiple files - * @param files - list of filenames with parts of json structure - */ - DLL_LINKAGE JsonNode assembleFromFiles(const std::vector & files); - DLL_LINKAGE JsonNode assembleFromFiles(const std::vector & files, bool & isValid); - - /// This version loads all files with same name (overridden by mods) - DLL_LINKAGE JsonNode assembleFromFiles(const std::string & filename); - - /** - * @brief removes all nodes that are identical to default entry in schema - * @param node - JsonNode to minimize - * @param schemaName - name of schema to use - * @note for minimizing data must be valid against given schema - */ - DLL_LINKAGE void minimize(JsonNode & node, const std::string & schemaName); - /// opposed to minimize, adds all missing, required entries that have default value - DLL_LINKAGE void maximize(JsonNode & node, const std::string & schemaName); - - /** - * @brief validate node against specified schema - * @param node - JsonNode to check - * @param schemaName - name of schema to use - * @param dataName - some way to identify data (printed in console in case of errors) - * @returns true if data in node fully compilant with schema - */ - DLL_LINKAGE bool validate(const JsonNode & node, const std::string & schemaName, const std::string & dataName); - - /// get schema by json URI: vcmi:# - /// example: schema "vcmi:settings" is used to check user settings - DLL_LINKAGE const JsonNode & getSchema(const std::string & URI); - - /// for easy construction of JsonNodes; helps with inserting primitives into vector node - DLL_LINKAGE JsonNode boolNode(bool value); - DLL_LINKAGE JsonNode floatNode(double value); - DLL_LINKAGE JsonNode stringNode(const std::string & value); - DLL_LINKAGE JsonNode intNode(si64 value); -} - namespace JsonDetail { // conversion helpers for JsonNode::convertTo (partial template function instantiation is illegal in c++) diff --git a/lib/json/JsonParser.cpp b/lib/json/JsonParser.cpp new file mode 100644 index 000000000..0d122d53f --- /dev/null +++ b/lib/json/JsonParser.cpp @@ -0,0 +1,465 @@ +/* + * JsonParser.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "JsonParser.h" + +#include "../TextOperations.h" + +VCMI_LIB_NAMESPACE_BEGIN + +JsonParser::JsonParser(const char * inputString, size_t stringSize): + input(inputString, stringSize), + lineCount(1), + lineStart(0), + pos(0) +{ +} + +JsonNode JsonParser::parse(const std::string & fileName) +{ + JsonNode root; + + if (input.size() == 0) + { + error("File is empty", false); + } + else + { + if (!TextOperations::isValidUnicodeString(&input[0], input.size())) + error("Not a valid UTF-8 file", false); + + extractValue(root); + extractWhitespace(false); + + //Warn if there are any non-whitespace symbols left + if (pos < input.size()) + error("Not all file was parsed!", true); + } + + if (!errors.empty()) + { + logMod->warn("File %s is not a valid JSON file!", fileName); + logMod->warn(errors); + } + return root; +} + +bool JsonParser::isValid() +{ + return errors.empty(); +} + +bool JsonParser::extractSeparator() +{ + if (!extractWhitespace()) + return false; + + if ( input[pos] !=':') + return error("Separator expected"); + + pos++; + return true; +} + +bool JsonParser::extractValue(JsonNode &node) +{ + if (!extractWhitespace()) + return false; + + switch (input[pos]) + { + case '\"': return extractString(node); + case 'n' : return extractNull(node); + case 't' : return extractTrue(node); + case 'f' : return extractFalse(node); + case '{' : return extractStruct(node); + case '[' : return extractArray(node); + case '-' : return extractFloat(node); + default: + { + if (input[pos] >= '0' && input[pos] <= '9') + return extractFloat(node); + return error("Value expected!"); + } + } +} + +bool JsonParser::extractWhitespace(bool verbose) +{ + while (true) + { + while(pos < input.size() && static_cast(input[pos]) <= ' ') + { + if (input[pos] == '\n') + { + lineCount++; + lineStart = pos+1; + } + pos++; + } + if (pos >= input.size() || input[pos] != '/') + break; + + pos++; + if (pos == input.size()) + break; + if (input[pos] == '/') + pos++; + else + error("Comments must consist of two slashes!", true); + + while (pos < input.size() && input[pos] != '\n') + pos++; + } + + if (pos >= input.size() && verbose) + return error("Unexpected end of file!"); + return true; +} + +bool JsonParser::extractEscaping(std::string &str) +{ + switch(input[pos]) + { + break; case '\"': str += '\"'; + break; case '\\': str += '\\'; + break; case 'b': str += '\b'; + break; case 'f': str += '\f'; + break; case 'n': str += '\n'; + break; case 'r': str += '\r'; + break; case 't': str += '\t'; + break; case '/': str += '/'; + break; default: return error("Unknown escape sequence!", true); + } + return true; +} + +bool JsonParser::extractString(std::string &str) +{ + if (input[pos] != '\"') + return error("String expected!"); + pos++; + + size_t first = pos; + + while (pos != input.size()) + { + if (input[pos] == '\"') // Correct end of string + { + str.append( &input[first], pos-first); + pos++; + return true; + } + if (input[pos] == '\\') // Escaping + { + str.append( &input[first], pos-first); + pos++; + if (pos == input.size()) + break; + extractEscaping(str); + first = pos + 1; + } + if (input[pos] == '\n') // end-of-line + { + str.append( &input[first], pos-first); + return error("Closing quote not found!", true); + } + if(static_cast(input[pos]) < ' ') // control character + { + str.append( &input[first], pos-first); + first = pos+1; + error("Illegal character in the string!", true); + } + pos++; + } + return error("Unterminated string!"); +} + +bool JsonParser::extractString(JsonNode &node) +{ + std::string str; + if (!extractString(str)) + return false; + + node.setType(JsonNode::JsonType::DATA_STRING); + node.String() = str; + return true; +} + +bool JsonParser::extractLiteral(const std::string &literal) +{ + if (literal.compare(0, literal.size(), &input[pos], literal.size()) != 0) + { + while (pos < input.size() && ((input[pos]>'a' && input[pos]<'z') + || (input[pos]>'A' && input[pos]<'Z'))) + pos++; + return error("Unknown literal found", true); + } + + pos += literal.size(); + return true; +} + +bool JsonParser::extractNull(JsonNode &node) +{ + if (!extractLiteral("null")) + return false; + + node.clear(); + return true; +} + +bool JsonParser::extractTrue(JsonNode &node) +{ + if (!extractLiteral("true")) + return false; + + node.Bool() = true; + return true; +} + +bool JsonParser::extractFalse(JsonNode &node) +{ + if (!extractLiteral("false")) + return false; + + node.Bool() = false; + return true; +} + +bool JsonParser::extractStruct(JsonNode &node) +{ + node.setType(JsonNode::JsonType::DATA_STRUCT); + pos++; + + if (!extractWhitespace()) + return false; + + //Empty struct found + if (input[pos] == '}') + { + pos++; + return true; + } + + while (true) + { + if (!extractWhitespace()) + return false; + + std::string key; + if (!extractString(key)) + return false; + + // split key string into actual key and meta-flags + std::vector keyAndFlags; + boost::split(keyAndFlags, key, boost::is_any_of("#")); + key = keyAndFlags[0]; + // check for unknown flags - helps with debugging + std::vector knownFlags = { "override" }; + for(int i = 1; i < keyAndFlags.size(); i++) + { + if(!vstd::contains(knownFlags, keyAndFlags[i])) + error("Encountered unknown flag #" + keyAndFlags[i], true); + } + + if (node.Struct().find(key) != node.Struct().end()) + error("Duplicate element encountered!", true); + + if (!extractSeparator()) + return false; + + if (!extractElement(node.Struct()[key], '}')) + return false; + + // flags from key string belong to referenced element + for(int i = 1; i < keyAndFlags.size(); i++) + node.Struct()[key].flags.push_back(keyAndFlags[i]); + + if (input[pos] == '}') + { + pos++; + return true; + } + } +} + +bool JsonParser::extractArray(JsonNode &node) +{ + pos++; + node.setType(JsonNode::JsonType::DATA_VECTOR); + + if (!extractWhitespace()) + return false; + + //Empty array found + if (input[pos] == ']') + { + pos++; + return true; + } + + while (true) + { + //NOTE: currently 50% of time is this vector resizing. + //May be useful to use list during parsing and then swap() all items to vector + node.Vector().resize(node.Vector().size()+1); + + if (!extractElement(node.Vector().back(), ']')) + return false; + + if (input[pos] == ']') + { + pos++; + return true; + } + } +} + +bool JsonParser::extractElement(JsonNode &node, char terminator) +{ + if (!extractValue(node)) + return false; + + if (!extractWhitespace()) + return false; + + bool comma = (input[pos] == ','); + if (comma ) + { + pos++; + if (!extractWhitespace()) + return false; + } + + if (input[pos] == terminator) + { + //FIXME: MOD COMPATIBILITY: Too many of these right now, re-enable later + //if (comma) + //error("Extra comma found!", true); + return true; + } + + if (!comma) + error("Comma expected!", true); + + return true; +} + +bool JsonParser::extractFloat(JsonNode &node) +{ + assert(input[pos] == '-' || (input[pos] >= '0' && input[pos] <= '9')); + bool negative=false; + double result=0; + si64 integerPart = 0; + bool isFloat = false; + + if (input[pos] == '-') + { + pos++; + negative = true; + } + + if (input[pos] < '0' || input[pos] > '9') + return error("Number expected!"); + + //Extract integer part + while (input[pos] >= '0' && input[pos] <= '9') + { + integerPart = integerPart*10+(input[pos]-'0'); + pos++; + } + + result = static_cast(integerPart); + + if (input[pos] == '.') + { + //extract fractional part + isFloat = true; + pos++; + double fractMult = 0.1; + if (input[pos] < '0' || input[pos] > '9') + return error("Decimal part expected!"); + + while (input[pos] >= '0' && input[pos] <= '9') + { + result = result + fractMult*(input[pos]-'0'); + fractMult /= 10; + pos++; + } + } + + if(input[pos] == 'e') + { + //extract exponential part + pos++; + isFloat = true; + bool powerNegative = false; + double power = 0; + + if(input[pos] == '-') + { + pos++; + powerNegative = true; + } + else if(input[pos] == '+') + { + pos++; + } + + if (input[pos] < '0' || input[pos] > '9') + return error("Exponential part expected!"); + + while (input[pos] >= '0' && input[pos] <= '9') + { + power = power*10 + (input[pos]-'0'); + pos++; + } + + if(powerNegative) + power = -power; + + result *= std::pow(10, power); + } + + if(isFloat) + { + if(negative) + result = -result; + + node.setType(JsonNode::JsonType::DATA_FLOAT); + node.Float() = result; + } + else + { + if(negative) + integerPart = -integerPart; + + node.setType(JsonNode::JsonType::DATA_INTEGER); + node.Integer() = integerPart; + } + + return true; +} + +bool JsonParser::error(const std::string &message, bool warning) +{ + std::ostringstream stream; + std::string type(warning?" warning: ":" error: "); + + stream << "At line " << lineCount << ", position "< JsonNode conversion +class JsonParser +{ + std::string errors; // Contains description of all encountered errors + constString input; // Input data + ui32 lineCount; // Currently parsed line, starting from 1 + size_t lineStart; // Position of current line start + size_t pos; // Current position of parser + + //Helpers + bool extractEscaping(std::string &str); + bool extractLiteral(const std::string &literal); + bool extractString(std::string &string); + bool extractWhitespace(bool verbose = true); + bool extractSeparator(); + bool extractElement(JsonNode &node, char terminator); + + //Methods for extracting JSON data + bool extractArray(JsonNode &node); + bool extractFalse(JsonNode &node); + bool extractFloat(JsonNode &node); + bool extractNull(JsonNode &node); + bool extractString(JsonNode &node); + bool extractStruct(JsonNode &node); + bool extractTrue(JsonNode &node); + bool extractValue(JsonNode &node); + + //Add error\warning message to list + bool error(const std::string &message, bool warning=false); + +public: + JsonParser(const char * inputString, size_t stringSize); + + /// do actual parsing. filename is name of file that will printed to console if any errors were found + JsonNode parse(const std::string & fileName); + + /// returns true if parsing was successful + bool isValid(); +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/JsonRandom.cpp b/lib/json/JsonRandom.cpp similarity index 97% rename from lib/JsonRandom.cpp rename to lib/json/JsonRandom.cpp index 9809a7f00..e9527f4a2 100644 --- a/lib/JsonRandom.cpp +++ b/lib/json/JsonRandom.cpp @@ -13,21 +13,22 @@ #include -#include "JsonNode.h" -#include "CRandomGenerator.h" -#include "constants/StringConstants.h" -#include "VCMI_Lib.h" -#include "CArtHandler.h" -#include "CCreatureHandler.h" -#include "CCreatureSet.h" -#include "spells/CSpellHandler.h" -#include "CSkillHandler.h" -#include "CHeroHandler.h" -#include "IGameCallback.h" -#include "gameState/CGameState.h" -#include "mapObjects/IObjectInterface.h" -#include "modding/IdentifierStorage.h" -#include "modding/ModScope.h" +#include "JsonUtils.h" + +#include "../CRandomGenerator.h" +#include "../constants/StringConstants.h" +#include "../VCMI_Lib.h" +#include "../CArtHandler.h" +#include "../CCreatureHandler.h" +#include "../CCreatureSet.h" +#include "../spells/CSpellHandler.h" +#include "../CSkillHandler.h" +#include "../CHeroHandler.h" +#include "../IGameCallback.h" +#include "../gameState/CGameState.h" +#include "../mapObjects/IObjectInterface.h" +#include "../modding/IdentifierStorage.h" +#include "../modding/ModScope.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/JsonRandom.h b/lib/json/JsonRandom.h similarity index 100% rename from lib/JsonRandom.h rename to lib/json/JsonRandom.h diff --git a/lib/JsonNode.cpp b/lib/json/JsonUtils.cpp similarity index 77% rename from lib/JsonNode.cpp rename to lib/json/JsonUtils.cpp index f0a6334f8..51f8c9900 100644 --- a/lib/JsonNode.cpp +++ b/lib/json/JsonUtils.cpp @@ -1,5 +1,5 @@ /* - * JsonNode.cpp, part of VCMI engine + * JsonUtils.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * @@ -9,437 +9,25 @@ */ #include "StdInc.h" -#include "JsonNode.h" +#include "JsonUtils.h" -#include "ScopeGuard.h" +#include "JsonValidator.h" -#include "bonuses/BonusParams.h" -#include "bonuses/Bonus.h" -#include "bonuses/Limiters.h" -#include "bonuses/Propagators.h" -#include "bonuses/Updaters.h" -#include "filesystem/Filesystem.h" -#include "modding/IdentifierStorage.h" -#include "VCMI_Lib.h" //for identifier resolution -#include "CGeneralTextHandler.h" -#include "JsonDetail.h" -#include "constants/StringConstants.h" -#include "battle/BattleHex.h" - -namespace -{ -// to avoid duplicating const and non-const code -template -Node & resolvePointer(Node & in, const std::string & pointer) -{ - if(pointer.empty()) - return in; - assert(pointer[0] == '/'); - - size_t splitPos = pointer.find('/', 1); - - std::string entry = pointer.substr(1, splitPos - 1); - std::string remainer = splitPos == std::string::npos ? "" : pointer.substr(splitPos); - - if(in.getType() == VCMI_LIB_WRAP_NAMESPACE(JsonNode)::JsonType::DATA_VECTOR) - { - if(entry.find_first_not_of("0123456789") != std::string::npos) // non-numbers in string - throw std::runtime_error("Invalid Json pointer"); - - if(entry.size() > 1 && entry[0] == '0') // leading zeros are not allowed - throw std::runtime_error("Invalid Json pointer"); - - auto index = boost::lexical_cast(entry); - - if (in.Vector().size() > index) - return in.Vector()[index].resolvePointer(remainer); - } - return in[entry].resolvePointer(remainer); -} -} - -VCMI_LIB_NAMESPACE_BEGIN - -using namespace JsonDetail; - -class LibClasses; -class CModHandler; +#include "../ScopeGuard.h" +#include "../bonuses/BonusParams.h" +#include "../bonuses/Bonus.h" +#include "../bonuses/Limiters.h" +#include "../bonuses/Propagators.h" +#include "../bonuses/Updaters.h" +#include "../filesystem/Filesystem.h" +#include "../modding/IdentifierStorage.h" +#include "../VCMI_Lib.h" //for identifier resolution +#include "../CGeneralTextHandler.h" +#include "../constants/StringConstants.h" +#include "../battle/BattleHex.h" static const JsonNode nullNode; -JsonNode::JsonNode(JsonType Type) -{ - setType(Type); -} - -JsonNode::JsonNode(const std::byte *data, size_t datasize) - :JsonNode(reinterpret_cast(data), datasize) -{} - -JsonNode::JsonNode(const char *data, size_t datasize) -{ - JsonParser parser(data, datasize); - *this = parser.parse(""); -} - -JsonNode::JsonNode(const JsonPath & fileURI) -{ - auto file = CResourceHandler::get()->load(fileURI)->readAll(); - - JsonParser parser(reinterpret_cast(file.first.get()), file.second); - *this = parser.parse(fileURI.getName()); -} - -JsonNode::JsonNode(const std::string & idx, const JsonPath & fileURI) -{ - auto file = CResourceHandler::get(idx)->load(fileURI)->readAll(); - - JsonParser parser(reinterpret_cast(file.first.get()), file.second); - *this = parser.parse(fileURI.getName()); -} - -JsonNode::JsonNode(const JsonPath & fileURI, bool &isValidSyntax) -{ - auto file = CResourceHandler::get()->load(fileURI)->readAll(); - - JsonParser parser(reinterpret_cast(file.first.get()), file.second); - *this = parser.parse(fileURI.getName()); - isValidSyntax = parser.isValid(); -} - -bool JsonNode::operator == (const JsonNode &other) const -{ - return data == other.data; -} - -bool JsonNode::operator != (const JsonNode &other) const -{ - return !(*this == other); -} - -JsonNode::JsonType JsonNode::getType() const -{ - return static_cast(data.index()); -} - -void JsonNode::setMeta(const std::string & metadata, bool recursive) -{ - meta = metadata; - if (recursive) - { - switch (getType()) - { - break; case JsonType::DATA_VECTOR: - { - for(auto & node : Vector()) - { - node.setMeta(metadata); - } - } - break; case JsonType::DATA_STRUCT: - { - for(auto & node : Struct()) - { - node.second.setMeta(metadata); - } - } - } - } -} - -void JsonNode::setType(JsonType Type) -{ - if (getType() == Type) - return; - - //float<->int conversion - if(getType() == JsonType::DATA_FLOAT && Type == JsonType::DATA_INTEGER) - { - si64 converted = static_cast(std::get(data)); - data = JsonData(converted); - return; - } - else if(getType() == JsonType::DATA_INTEGER && Type == JsonType::DATA_FLOAT) - { - double converted = static_cast(std::get(data)); - data = JsonData(converted); - return; - } - - //Set new node type - switch(Type) - { - break; case JsonType::DATA_NULL: data = JsonData(); - break; case JsonType::DATA_BOOL: data = JsonData(false); - break; case JsonType::DATA_FLOAT: data = JsonData(static_cast(0.0)); - break; case JsonType::DATA_STRING: data = JsonData(std::string()); - break; case JsonType::DATA_VECTOR: data = JsonData(JsonVector()); - break; case JsonType::DATA_STRUCT: data = JsonData(JsonMap()); - break; case JsonType::DATA_INTEGER: data = JsonData(static_cast(0)); - } -} - -bool JsonNode::isNull() const -{ - return getType() == JsonType::DATA_NULL; -} - -bool JsonNode::isNumber() const -{ - return getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT; -} - -bool JsonNode::isString() const -{ - return getType() == JsonType::DATA_STRING; -} - -bool JsonNode::isVector() const -{ - return getType() == JsonType::DATA_VECTOR; -} - -bool JsonNode::isStruct() const -{ - return getType() == JsonType::DATA_STRUCT; -} - -bool JsonNode::containsBaseData() const -{ - switch(getType()) - { - case JsonType::DATA_NULL: - return false; - case JsonType::DATA_STRUCT: - for(const auto & elem : Struct()) - { - if(elem.second.containsBaseData()) - return true; - } - return false; - default: - //other types (including vector) cannot be extended via merge - return true; - } -} - -bool JsonNode::isCompact() const -{ - switch(getType()) - { - case JsonType::DATA_VECTOR: - for(const JsonNode & elem : Vector()) - { - if(!elem.isCompact()) - return false; - } - return true; - case JsonType::DATA_STRUCT: - { - auto propertyCount = Struct().size(); - if(propertyCount == 0) - return true; - else if(propertyCount == 1) - return Struct().begin()->second.isCompact(); - } - return false; - default: - return true; - } -} - -bool JsonNode::TryBoolFromString(bool & success) const -{ - success = true; - if(getType() == JsonNode::JsonType::DATA_BOOL) - return Bool(); - - success = getType() == JsonNode::JsonType::DATA_STRING; - if(success) - { - auto boolParamStr = String(); - boost::algorithm::trim(boolParamStr); - boost::algorithm::to_lower(boolParamStr); - success = boolParamStr == "true"; - - if(success) - return true; - - success = boolParamStr == "false"; - } - return false; -} - -void JsonNode::clear() -{ - setType(JsonType::DATA_NULL); -} - -bool & JsonNode::Bool() -{ - setType(JsonType::DATA_BOOL); - return std::get(data); -} - -double & JsonNode::Float() -{ - setType(JsonType::DATA_FLOAT); - return std::get(data); -} - -si64 & JsonNode::Integer() -{ - setType(JsonType::DATA_INTEGER); - return std::get(data); -} - -std::string & JsonNode::String() -{ - setType(JsonType::DATA_STRING); - return std::get(data); -} - -JsonVector & JsonNode::Vector() -{ - setType(JsonType::DATA_VECTOR); - return std::get(data); -} - -JsonMap & JsonNode::Struct() -{ - setType(JsonType::DATA_STRUCT); - return std::get(data); -} - -const bool boolDefault = false; -bool JsonNode::Bool() const -{ - assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_BOOL); - - if (getType() == JsonType::DATA_BOOL) - return std::get(data); - - return boolDefault; -} - -const double floatDefault = 0; -double JsonNode::Float() const -{ - assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT); - - if(getType() == JsonType::DATA_FLOAT) - return std::get(data); - - if(getType() == JsonType::DATA_INTEGER) - return static_cast(std::get(data)); - - return floatDefault; -} - -const si64 integerDefault = 0; -si64 JsonNode::Integer() const -{ - assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT); - - if(getType() == JsonType::DATA_INTEGER) - return std::get(data); - - if(getType() == JsonType::DATA_FLOAT) - return static_cast(std::get(data)); - - return integerDefault; -} - -const std::string stringDefault = std::string(); -const std::string & JsonNode::String() const -{ - assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRING); - - if (getType() == JsonType::DATA_STRING) - return std::get(data); - - return stringDefault; -} - -const JsonVector vectorDefault = JsonVector(); -const JsonVector & JsonNode::Vector() const -{ - assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_VECTOR); - - if (getType() == JsonType::DATA_VECTOR) - return std::get(data); - - return vectorDefault; -} - -const JsonMap mapDefault = JsonMap(); -const JsonMap & JsonNode::Struct() const -{ - assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRUCT); - - if (getType() == JsonType::DATA_STRUCT) - return std::get(data); - - return mapDefault; -} - -JsonNode & JsonNode::operator[](const std::string & child) -{ - return Struct()[child]; -} - -const JsonNode & JsonNode::operator[](const std::string & child) const -{ - auto it = Struct().find(child); - if (it != Struct().end()) - return it->second; - return nullNode; -} - -JsonNode & JsonNode::operator[](size_t child) -{ - if (child >= Vector().size() ) - Vector().resize(child + 1); - return Vector()[child]; -} - -const JsonNode & JsonNode::operator[](size_t child) const -{ - if (child < Vector().size() ) - return Vector()[child]; - - return nullNode; -} - -const JsonNode & JsonNode::resolvePointer(const std::string &jsonPointer) const -{ - return ::resolvePointer(*this, jsonPointer); -} - -JsonNode & JsonNode::resolvePointer(const std::string &jsonPointer) -{ - return ::resolvePointer(*this, jsonPointer); -} - -std::vector JsonNode::toBytes(bool compact) const -{ - std::string jsonString = toJson(compact); - auto dataBegin = reinterpret_cast(jsonString.data()); - auto dataEnd = dataBegin + jsonString.size(); - std::vector result(dataBegin, dataEnd); - return result; -} - -std::string JsonNode::toJson(bool compact) const -{ - std::ostringstream out; - JsonWriter writer(out, compact); - writer.writeNode(*this); - return out.str(); -} - -///JsonUtils - static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const JsonNode & node) { if (node.isNull()) @@ -1145,7 +733,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) if (!value->isNull()) { //ALL_CREATURES old propagator compatibility - if(value->String() == "ALL_CREATURES") + if(value->String() == "ALL_CREATURES") { logMod->warn("ALL_CREATURES propagator is deprecated. Use GLOBAL_EFFECT propagator with CREATURES_ONLY limiter"); b->addLimiter(std::make_shared()); @@ -1182,7 +770,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability) CSelector base = Selector::none; for(const auto & andN : value->Vector()) base = base.Or(parseSelector(andN)); - + ret = ret.And(base); } @@ -1192,7 +780,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability) CSelector base = Selector::none; for(const auto & andN : value->Vector()) base = base.Or(parseSelector(andN)); - + ret = ret.And(base.Not()); } @@ -1237,7 +825,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability) else if(src) ret = ret.And(Selector::sourceTypeSel(*src)); - + value = &ability["targetSourceType"]; if(value->isString()) { @@ -1649,5 +1237,3 @@ DLL_LINKAGE JsonNode JsonUtils::intNode(si64 value) node.Integer() = value; return node; } - -VCMI_LIB_NAMESPACE_END diff --git a/lib/json/JsonUtils.h b/lib/json/JsonUtils.h new file mode 100644 index 000000000..2a733655e --- /dev/null +++ b/lib/json/JsonUtils.h @@ -0,0 +1,104 @@ +/* + * JsonUtils.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "JsonNode.h" +#include "../GameConstants.h" + +namespace JsonUtils +{ + DLL_LINKAGE std::shared_ptr parseBonus(const JsonVector & ability_vec); + DLL_LINKAGE std::shared_ptr parseBonus(const JsonNode & ability); + DLL_LINKAGE std::shared_ptr parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description); + DLL_LINKAGE bool parseBonus(const JsonNode & ability, Bonus * placement); + DLL_LINKAGE std::shared_ptr parseLimiter(const JsonNode & limiter); + DLL_LINKAGE CSelector parseSelector(const JsonNode &ability); + DLL_LINKAGE void resolveAddInfo(CAddInfo & var, const JsonNode & node); + + /** + * @brief recursively merges source into dest, replacing identical fields + * struct : recursively calls this function + * arrays : each entry will be merged recursively + * values : value in source will replace value in dest + * null : if value in source is present but set to null it will delete entry in dest + * @note this function will destroy data in source + */ + DLL_LINKAGE void merge(JsonNode & dest, JsonNode & source, bool ignoreOverride = false, bool copyMeta = false); + + /** + * @brief recursively merges source into dest, replacing identical fields + * struct : recursively calls this function + * arrays : each entry will be merged recursively + * values : value in source will replace value in dest + * null : if value in source is present but set to null it will delete entry in dest + * @note this function will preserve data stored in source by creating copy + */ + DLL_LINKAGE void mergeCopy(JsonNode & dest, JsonNode source, bool ignoreOverride = false, bool copyMeta = false); + + /** @brief recursively merges descendant into copy of base node + * Result emulates inheritance semantic + */ + DLL_LINKAGE void inherit(JsonNode & descendant, const JsonNode & base); + + /** + * @brief construct node representing the common structure of input nodes + * @param pruneEmpty - omit common properties whose intersection is empty + * different types: null + * struct: recursive intersect on common properties + * other: input if equal, null otherwise + */ + DLL_LINKAGE JsonNode intersect(const JsonNode & a, const JsonNode & b, bool pruneEmpty = true); + DLL_LINKAGE JsonNode intersect(const std::vector & nodes, bool pruneEmpty = true); + + /** + * @brief construct node representing the difference "node - base" + * merging difference with base gives node + */ + DLL_LINKAGE JsonNode difference(const JsonNode & node, const JsonNode & base); + + /** + * @brief generate one Json structure from multiple files + * @param files - list of filenames with parts of json structure + */ + DLL_LINKAGE JsonNode assembleFromFiles(const std::vector & files); + DLL_LINKAGE JsonNode assembleFromFiles(const std::vector & files, bool & isValid); + + /// This version loads all files with same name (overridden by mods) + DLL_LINKAGE JsonNode assembleFromFiles(const std::string & filename); + + /** + * @brief removes all nodes that are identical to default entry in schema + * @param node - JsonNode to minimize + * @param schemaName - name of schema to use + * @note for minimizing data must be valid against given schema + */ + DLL_LINKAGE void minimize(JsonNode & node, const std::string & schemaName); + /// opposed to minimize, adds all missing, required entries that have default value + DLL_LINKAGE void maximize(JsonNode & node, const std::string & schemaName); + + /** + * @brief validate node against specified schema + * @param node - JsonNode to check + * @param schemaName - name of schema to use + * @param dataName - some way to identify data (printed in console in case of errors) + * @returns true if data in node fully compilant with schema + */ + DLL_LINKAGE bool validate(const JsonNode & node, const std::string & schemaName, const std::string & dataName); + + /// get schema by json URI: vcmi:# + /// example: schema "vcmi:settings" is used to check user settings + DLL_LINKAGE const JsonNode & getSchema(const std::string & URI); + + /// for easy construction of JsonNodes; helps with inserting primitives into vector node + DLL_LINKAGE JsonNode boolNode(bool value); + DLL_LINKAGE JsonNode floatNode(double value); + DLL_LINKAGE JsonNode stringNode(const std::string & value); + DLL_LINKAGE JsonNode intNode(si64 value); +} diff --git a/lib/json/JsonValidator.cpp b/lib/json/JsonValidator.cpp new file mode 100644 index 000000000..c2941081c --- /dev/null +++ b/lib/json/JsonValidator.cpp @@ -0,0 +1,687 @@ +/* + * JsonValidator.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "JsonValidator.h" + +#include "JsonUtils.h" + +#include "../VCMI_Lib.h" +#include "../filesystem/Filesystem.h" +#include "../modding/ModScope.h" +#include "../modding/CModHandler.h" +#include "../ScopeGuard.h" + +VCMI_LIB_NAMESPACE_BEGIN + +//TODO: integer support + +static const std::unordered_map stringToType = +{ + {"null", JsonNode::JsonType::DATA_NULL}, + {"boolean", JsonNode::JsonType::DATA_BOOL}, + {"number", JsonNode::JsonType::DATA_FLOAT}, + {"string", JsonNode::JsonType::DATA_STRING}, + {"array", JsonNode::JsonType::DATA_VECTOR}, + {"object", JsonNode::JsonType::DATA_STRUCT} +}; + +namespace +{ + namespace Common + { + std::string emptyCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + // check is not needed - e.g. incorporated into another check + return ""; + } + + std::string notImplementedCheck(Validation::ValidationData & validator, + const JsonNode & baseSchema, + const JsonNode & schema, + const JsonNode & data) + { + return "Not implemented entry in schema"; + } + + std::string schemaListCheck(Validation::ValidationData & validator, + const JsonNode & baseSchema, + const JsonNode & schema, + const JsonNode & data, + const std::string & errorMsg, + const std::function & isValid) + { + std::string errors = "\n"; + size_t result = 0; + + for(const auto & schemaEntry : schema.Vector()) + { + std::string error = check(schemaEntry, data, validator); + if (error.empty()) + { + result++; + } + else + { + errors += error; + errors += "\n"; + } + } + if (isValid(result)) + return ""; + else + return validator.makeErrorMessage(errorMsg) + errors; + } + + std::string allOfCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + return schemaListCheck(validator, baseSchema, schema, data, "Failed to pass all schemas", [&](size_t count) + { + return count == schema.Vector().size(); + }); + } + + std::string anyOfCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + return schemaListCheck(validator, baseSchema, schema, data, "Failed to pass any schema", [&](size_t count) + { + return count > 0; + }); + } + + std::string oneOfCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + return schemaListCheck(validator, baseSchema, schema, data, "Failed to pass exactly one schema", [&](size_t count) + { + return count == 1; + }); + } + + std::string notCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (check(schema, data, validator).empty()) + return validator.makeErrorMessage("Successful validation against negative check"); + return ""; + } + + std::string enumCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + for(const auto & enumEntry : schema.Vector()) + { + if (data == enumEntry) + return ""; + } + return validator.makeErrorMessage("Key must have one of predefined values"); + } + + std::string typeCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + const auto & typeName = schema.String(); + auto it = stringToType.find(typeName); + if(it == stringToType.end()) + { + return validator.makeErrorMessage("Unknown type in schema:" + typeName); + } + + JsonNode::JsonType type = it->second; + + //FIXME: hack for integer values + if(data.isNumber() && type == JsonNode::JsonType::DATA_FLOAT) + return ""; + + if(type != data.getType() && data.getType() != JsonNode::JsonType::DATA_NULL) + return validator.makeErrorMessage("Type mismatch! Expected " + schema.String()); + return ""; + } + + std::string refCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + std::string URI = schema.String(); + //node must be validated using schema pointed by this reference and not by data here + //Local reference. Turn it into more easy to handle remote ref + if (boost::algorithm::starts_with(URI, "#")) + { + const std::string name = validator.usedSchemas.back(); + const std::string nameClean = name.substr(0, name.find('#')); + URI = nameClean + URI; + } + return check(URI, data, validator); + } + + std::string formatCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + auto formats = Validation::getKnownFormats(); + std::string errors; + auto checker = formats.find(schema.String()); + if (checker != formats.end()) + { + if (data.isString()) + { + std::string result = checker->second(data); + if (!result.empty()) + errors += validator.makeErrorMessage(result); + } + else + { + errors += validator.makeErrorMessage("Format value must be string: " + schema.String()); + } + } + else + errors += validator.makeErrorMessage("Unsupported format type: " + schema.String()); + return errors; + } + } + + namespace String + { + std::string maxLengthCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (data.String().size() > schema.Float()) + return validator.makeErrorMessage((boost::format("String is longer than %d symbols") % schema.Float()).str()); + return ""; + } + + std::string minLengthCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (data.String().size() < schema.Float()) + return validator.makeErrorMessage((boost::format("String is shorter than %d symbols") % schema.Float()).str()); + return ""; + } + } + + namespace Number + { + + std::string maximumCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (baseSchema["exclusiveMaximum"].Bool()) + { + if (data.Float() >= schema.Float()) + return validator.makeErrorMessage((boost::format("Value is bigger than %d") % schema.Float()).str()); + } + else + { + if (data.Float() > schema.Float()) + return validator.makeErrorMessage((boost::format("Value is bigger than %d") % schema.Float()).str()); + } + return ""; + } + + std::string minimumCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (baseSchema["exclusiveMinimum"].Bool()) + { + if (data.Float() <= schema.Float()) + return validator.makeErrorMessage((boost::format("Value is smaller than %d") % schema.Float()).str()); + } + else + { + if (data.Float() < schema.Float()) + return validator.makeErrorMessage((boost::format("Value is smaller than %d") % schema.Float()).str()); + } + return ""; + } + + std::string multipleOfCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + double result = data.Float() / schema.Float(); + if (floor(result) != result) + return validator.makeErrorMessage((boost::format("Value is not divisible by %d") % schema.Float()).str()); + return ""; + } + } + + namespace Vector + { + std::string itemEntryCheck(Validation::ValidationData & validator, const JsonVector & items, const JsonNode & schema, size_t index) + { + validator.currentPath.emplace_back(); + validator.currentPath.back().Float() = static_cast(index); + auto onExit = vstd::makeScopeGuard([&]() + { + validator.currentPath.pop_back(); + }); + + if (!schema.isNull()) + return check(schema, items[index], validator); + return ""; + } + + std::string itemsCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + std::string errors; + for (size_t i=0; i i) + errors += itemEntryCheck(validator, data.Vector(), schema.Vector()[i], i); + } + else + { + errors += itemEntryCheck(validator, data.Vector(), schema, i); + } + } + return errors; + } + + std::string additionalItemsCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + std::string errors; + // "items" is struct or empty (defaults to empty struct) - validation always successful + const JsonNode & items = baseSchema["items"]; + if (items.getType() != JsonNode::JsonType::DATA_VECTOR) + return ""; + + for (size_t i=items.Vector().size(); i schema.Float()) + return validator.makeErrorMessage((boost::format("Length is bigger than %d") % schema.Float()).str()); + return ""; + } + + std::string uniqueItemsCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (schema.Bool()) + { + for (auto itA = schema.Vector().begin(); itA != schema.Vector().end(); itA++) + { + auto itB = itA; + while (++itB != schema.Vector().end()) + { + if (*itA == *itB) + return validator.makeErrorMessage("List must consist from unique items"); + } + } + } + return ""; + } + } + + namespace Struct + { + std::string maxPropertiesCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (data.Struct().size() > schema.Float()) + return validator.makeErrorMessage((boost::format("Number of entries is bigger than %d") % schema.Float()).str()); + return ""; + } + + std::string minPropertiesCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + if (data.Struct().size() < schema.Float()) + return validator.makeErrorMessage((boost::format("Number of entries is less than %d") % schema.Float()).str()); + return ""; + } + + std::string uniquePropertiesCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + for (auto itA = data.Struct().begin(); itA != data.Struct().end(); itA++) + { + auto itB = itA; + while (++itB != data.Struct().end()) + { + if (itA->second == itB->second) + return validator.makeErrorMessage("List must consist from unique items"); + } + } + return ""; + } + + std::string requiredCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + std::string errors; + for(const auto & required : schema.Vector()) + { + if (data[required.String()].isNull()) + errors += validator.makeErrorMessage("Required entry " + required.String() + " is missing"); + } + return errors; + } + + std::string dependenciesCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + std::string errors; + for(const auto & deps : schema.Struct()) + { + if (!data[deps.first].isNull()) + { + if (deps.second.getType() == JsonNode::JsonType::DATA_VECTOR) + { + JsonVector depList = deps.second.Vector(); + for(auto & depEntry : depList) + { + if (data[depEntry.String()].isNull()) + errors += validator.makeErrorMessage("Property " + depEntry.String() + " required for " + deps.first + " is missing"); + } + } + else + { + if (!check(deps.second, data, validator).empty()) + errors += validator.makeErrorMessage("Requirements for " + deps.first + " are not fulfilled"); + } + } + } + return errors; + } + + std::string propertyEntryCheck(Validation::ValidationData & validator, const JsonNode &node, const JsonNode & schema, const std::string & nodeName) + { + validator.currentPath.emplace_back(); + validator.currentPath.back().String() = nodeName; + auto onExit = vstd::makeScopeGuard([&]() + { + validator.currentPath.pop_back(); + }); + + // there is schema specifically for this item + if (!schema.isNull()) + return check(schema, node, validator); + return ""; + } + + std::string propertiesCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + std::string errors; + + for(const auto & entry : data.Struct()) + errors += propertyEntryCheck(validator, entry.second, schema[entry.first], entry.first); + return errors; + } + + std::string additionalPropertiesCheck(Validation::ValidationData & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data) + { + std::string errors; + for(const auto & entry : data.Struct()) + { + if (baseSchema["properties"].Struct().count(entry.first) == 0) + { + // try generic additionalItems schema + if (schema.getType() == JsonNode::JsonType::DATA_STRUCT) + errors += propertyEntryCheck(validator, entry.second, schema, entry.first); + + // or, additionalItems field can be bool which indicates if such items are allowed + else if(!schema.isNull() && !schema.Bool()) // present and set to false - error + errors += validator.makeErrorMessage("Unknown entry found: " + entry.first); + } + } + return errors; + } + } + + namespace Formats + { + bool testFilePresence(const std::string & scope, const ResourcePath & resource) + { + std::set allowedScopes; + if(scope != ModScope::scopeBuiltin() && !scope.empty()) // all real mods may have dependencies + { + //NOTE: recursive dependencies are not allowed at the moment - update code if this changes + bool found = true; + allowedScopes = VLC->modh->getModDependencies(scope, found); + + if(!found) + return false; + + allowedScopes.insert(ModScope::scopeBuiltin()); // all mods can use H3 files + } + allowedScopes.insert(scope); // mods can use their own files + + for(const auto & entry : allowedScopes) + { + if (CResourceHandler::get(entry)->existsResource(resource)) + return true; + } + return false; + } + + #define TEST_FILE(scope, prefix, file, type) \ + if (testFilePresence(scope, ResourcePath(prefix + file, type))) \ + return "" + + std::string testAnimation(const std::string & path, const std::string & scope) + { + TEST_FILE(scope, "Sprites/", path, EResType::ANIMATION); + TEST_FILE(scope, "Sprites/", path, EResType::JSON); + return "Animation file \"" + path + "\" was not found"; + } + + std::string textFile(const JsonNode & node) + { + TEST_FILE(node.meta, "", node.String(), EResType::JSON); + return "Text file \"" + node.String() + "\" was not found"; + } + + std::string musicFile(const JsonNode & node) + { + TEST_FILE(node.meta, "Music/", node.String(), EResType::SOUND); + TEST_FILE(node.meta, "", node.String(), EResType::SOUND); + return "Music file \"" + node.String() + "\" was not found"; + } + + std::string soundFile(const JsonNode & node) + { + TEST_FILE(node.meta, "Sounds/", node.String(), EResType::SOUND); + return "Sound file \"" + node.String() + "\" was not found"; + } + + std::string defFile(const JsonNode & node) + { + return testAnimation(node.String(), node.meta); + } + + std::string animationFile(const JsonNode & node) + { + return testAnimation(node.String(), node.meta); + } + + std::string imageFile(const JsonNode & node) + { + TEST_FILE(node.meta, "Data/", node.String(), EResType::IMAGE); + TEST_FILE(node.meta, "Sprites/", node.String(), EResType::IMAGE); + if (node.String().find(':') != std::string::npos) + return testAnimation(node.String().substr(0, node.String().find(':')), node.meta); + return "Image file \"" + node.String() + "\" was not found"; + } + + std::string videoFile(const JsonNode & node) + { + TEST_FILE(node.meta, "Video/", node.String(), EResType::VIDEO); + return "Video file \"" + node.String() + "\" was not found"; + } + + #undef TEST_FILE + } + + Validation::TValidatorMap createCommonFields() + { + Validation::TValidatorMap ret; + + ret["format"] = Common::formatCheck; + ret["allOf"] = Common::allOfCheck; + ret["anyOf"] = Common::anyOfCheck; + ret["oneOf"] = Common::oneOfCheck; + ret["enum"] = Common::enumCheck; + ret["type"] = Common::typeCheck; + ret["not"] = Common::notCheck; + ret["$ref"] = Common::refCheck; + + // fields that don't need implementation + ret["title"] = Common::emptyCheck; + ret["$schema"] = Common::emptyCheck; + ret["default"] = Common::emptyCheck; + ret["description"] = Common::emptyCheck; + ret["definitions"] = Common::emptyCheck; + return ret; + } + + Validation::TValidatorMap createStringFields() + { + Validation::TValidatorMap ret = createCommonFields(); + ret["maxLength"] = String::maxLengthCheck; + ret["minLength"] = String::minLengthCheck; + + ret["pattern"] = Common::notImplementedCheck; + return ret; + } + + Validation::TValidatorMap createNumberFields() + { + Validation::TValidatorMap ret = createCommonFields(); + ret["maximum"] = Number::maximumCheck; + ret["minimum"] = Number::minimumCheck; + ret["multipleOf"] = Number::multipleOfCheck; + + ret["exclusiveMaximum"] = Common::emptyCheck; + ret["exclusiveMinimum"] = Common::emptyCheck; + return ret; + } + + Validation::TValidatorMap createVectorFields() + { + Validation::TValidatorMap ret = createCommonFields(); + ret["items"] = Vector::itemsCheck; + ret["minItems"] = Vector::minItemsCheck; + ret["maxItems"] = Vector::maxItemsCheck; + ret["uniqueItems"] = Vector::uniqueItemsCheck; + ret["additionalItems"] = Vector::additionalItemsCheck; + return ret; + } + + Validation::TValidatorMap createStructFields() + { + Validation::TValidatorMap ret = createCommonFields(); + ret["additionalProperties"] = Struct::additionalPropertiesCheck; + ret["uniqueProperties"] = Struct::uniquePropertiesCheck; + ret["maxProperties"] = Struct::maxPropertiesCheck; + ret["minProperties"] = Struct::minPropertiesCheck; + ret["dependencies"] = Struct::dependenciesCheck; + ret["properties"] = Struct::propertiesCheck; + ret["required"] = Struct::requiredCheck; + + ret["patternProperties"] = Common::notImplementedCheck; + return ret; + } + + Validation::TFormatMap createFormatMap() + { + Validation::TFormatMap ret; + ret["textFile"] = Formats::textFile; + ret["musicFile"] = Formats::musicFile; + ret["soundFile"] = Formats::soundFile; + ret["defFile"] = Formats::defFile; + ret["animationFile"] = Formats::animationFile; + ret["imageFile"] = Formats::imageFile; + ret["videoFile"] = Formats::videoFile; + + return ret; + } +} + +namespace Validation +{ + std::string ValidationData::makeErrorMessage(const std::string &message) + { + std::string errors; + errors += "At "; + if (!currentPath.empty()) + { + for(const JsonNode &path : currentPath) + { + errors += "/"; + if (path.getType() == JsonNode::JsonType::DATA_STRING) + errors += path.String(); + else + errors += std::to_string(static_cast(path.Float())); + } + } + else + errors += ""; + errors += "\n\t Error: " + message + "\n"; + return errors; + } + + std::string check(const std::string & schemaName, const JsonNode & data) + { + ValidationData validator; + return check(schemaName, data, validator); + } + + std::string check(const std::string & schemaName, const JsonNode & data, ValidationData & validator) + { + validator.usedSchemas.push_back(schemaName); + auto onscopeExit = vstd::makeScopeGuard([&]() + { + validator.usedSchemas.pop_back(); + }); + return check(JsonUtils::getSchema(schemaName), data, validator); + } + + std::string check(const JsonNode & schema, const JsonNode & data, ValidationData & validator) + { + const TValidatorMap & knownFields = getKnownFieldsFor(data.getType()); + std::string errors; + for(const auto & entry : schema.Struct()) + { + auto checker = knownFields.find(entry.first); + if (checker != knownFields.end()) + errors += checker->second(validator, schema, entry.second, data); + //else + // errors += validator.makeErrorMessage("Unknown entry in schema " + entry.first); + } + return errors; + } + + const TValidatorMap & getKnownFieldsFor(JsonNode::JsonType type) + { + static const TValidatorMap commonFields = createCommonFields(); + static const TValidatorMap numberFields = createNumberFields(); + static const TValidatorMap stringFields = createStringFields(); + static const TValidatorMap vectorFields = createVectorFields(); + static const TValidatorMap structFields = createStructFields(); + + switch (type) + { + case JsonNode::JsonType::DATA_FLOAT: + case JsonNode::JsonType::DATA_INTEGER: + return numberFields; + case JsonNode::JsonType::DATA_STRING: return stringFields; + case JsonNode::JsonType::DATA_VECTOR: return vectorFields; + case JsonNode::JsonType::DATA_STRUCT: return structFields; + default: return commonFields; + } + } + + const TFormatMap & getKnownFormats() + { + static TFormatMap knownFormats = createFormatMap(); + return knownFormats; + } + +} // Validation namespace + +VCMI_LIB_NAMESPACE_END diff --git a/lib/json/JsonValidator.h b/lib/json/JsonValidator.h new file mode 100644 index 000000000..35cc23797 --- /dev/null +++ b/lib/json/JsonValidator.h @@ -0,0 +1,49 @@ +/* + * JsonValidator.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "JsonNode.h" + +VCMI_LIB_NAMESPACE_BEGIN + + +//Internal class for Json validation. Mostly compilant with json-schema v4 draft +namespace Validation +{ + /// struct used to pass data around during validation + struct ValidationData + { + /// path from root node to current one. + /// JsonNode is used as variant - either string (name of node) or as float (index in list) + std::vector currentPath; + + /// Stack of used schemas. Last schema is the one used currently. + /// May contain multiple items in case if remote references were found + std::vector usedSchemas; + + /// generates error message + std::string makeErrorMessage(const std::string &message); + }; + + using TFormatValidator = std::function; + using TFormatMap = std::unordered_map; + using TFieldValidator = std::function; + using TValidatorMap = std::unordered_map; + + /// map of known fields in schema + const TValidatorMap & getKnownFieldsFor(JsonNode::JsonType type); + const TFormatMap & getKnownFormats(); + + std::string check(const std::string & schemaName, const JsonNode & data); + std::string check(const std::string & schemaName, const JsonNode & data, ValidationData & validator); + std::string check(const JsonNode & schema, const JsonNode & data, ValidationData & validator); +} + +VCMI_LIB_NAMESPACE_END diff --git a/lib/json/JsonWriter.cpp b/lib/json/JsonWriter.cpp new file mode 100644 index 000000000..205343d79 --- /dev/null +++ b/lib/json/JsonWriter.cpp @@ -0,0 +1,144 @@ +/* + * JsonWriter.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "JsonWriter.h" + +VCMI_LIB_NAMESPACE_BEGIN + +template +void JsonWriter::writeContainer(Iterator begin, Iterator end) +{ + if (begin == end) + return; + + prefix += '\t'; + + writeEntry(begin++); + + while (begin != end) + { + out << (compactMode ? ", " : ",\n"); + writeEntry(begin++); + } + + out << (compactMode ? "" : "\n"); + prefix.resize(prefix.size()-1); +} + +void JsonWriter::writeEntry(JsonMap::const_iterator entry) +{ + if(!compactMode) + { + if (!entry->second.meta.empty()) + out << prefix << " // " << entry->second.meta << "\n"; + if(!entry->second.flags.empty()) + out << prefix << " // flags: " << boost::algorithm::join(entry->second.flags, ", ") << "\n"; + out << prefix; + } + writeString(entry->first); + out << " : "; + writeNode(entry->second); +} + +void JsonWriter::writeEntry(JsonVector::const_iterator entry) +{ + if(!compactMode) + { + if (!entry->meta.empty()) + out << prefix << " // " << entry->meta << "\n"; + if(!entry->flags.empty()) + out << prefix << " // flags: " << boost::algorithm::join(entry->flags, ", ") << "\n"; + out << prefix; + } + writeNode(*entry); +} + +void JsonWriter::writeString(const std::string &string) +{ + static const std::string escaped = "\"\\\b\f\n\r\t/"; + + static const std::array escaped_code = {'\"', '\\', 'b', 'f', 'n', 'r', 't', '/'}; + + out <<'\"'; + size_t pos = 0; + size_t start = 0; + for (; pos + void writeContainer(Iterator begin, Iterator end); + void writeEntry(JsonMap::const_iterator entry); + void writeEntry(JsonVector::const_iterator entry); + void writeString(const std::string & string); + void writeNode(const JsonNode & node); + JsonWriter(std::ostream & output, bool compact); +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjectConstructors/AObjectTypeHandler.cpp b/lib/mapObjectConstructors/AObjectTypeHandler.cpp index a3ed75ef4..c3573b761 100644 --- a/lib/mapObjectConstructors/AObjectTypeHandler.cpp +++ b/lib/mapObjectConstructors/AObjectTypeHandler.cpp @@ -13,8 +13,9 @@ #include "IObjectInfo.h" #include "../CGeneralTextHandler.h" -#include "../modding/IdentifierStorage.h" #include "../VCMI_Lib.h" +#include "../json/JsonUtils.h" +#include "../modding/IdentifierStorage.h" #include "../mapObjects/CGObjectInstance.h" #include "../mapObjects/ObjectTemplate.h" diff --git a/lib/mapObjectConstructors/AObjectTypeHandler.h b/lib/mapObjectConstructors/AObjectTypeHandler.h index 4222ff29d..ba298d13f 100644 --- a/lib/mapObjectConstructors/AObjectTypeHandler.h +++ b/lib/mapObjectConstructors/AObjectTypeHandler.h @@ -9,9 +9,9 @@ */ #pragma once +#include "../constants/EntityIdentifiers.h" #include "RandomMapInfo.h" #include "SObjectSounds.h" -#include "../JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapObjectConstructors/CBankInstanceConstructor.cpp b/lib/mapObjectConstructors/CBankInstanceConstructor.cpp index 5b7bf8b9a..170aa1239 100644 --- a/lib/mapObjectConstructors/CBankInstanceConstructor.cpp +++ b/lib/mapObjectConstructors/CBankInstanceConstructor.cpp @@ -10,7 +10,7 @@ #include "StdInc.h" #include "CBankInstanceConstructor.h" -#include "../JsonRandom.h" +#include "../json/JsonRandom.h" #include "../CGeneralTextHandler.h" #include "../IGameCallback.h" #include "../CRandomGenerator.h" diff --git a/lib/mapObjectConstructors/CBankInstanceConstructor.h b/lib/mapObjectConstructors/CBankInstanceConstructor.h index 2bf2251ed..5a609f5d2 100644 --- a/lib/mapObjectConstructors/CBankInstanceConstructor.h +++ b/lib/mapObjectConstructors/CBankInstanceConstructor.h @@ -14,6 +14,7 @@ #include "../CCreatureSet.h" #include "../ResourceSet.h" +#include "../json/JsonNode.h" #include "../mapObjects/CBank.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapObjectConstructors/CObjectClassesHandler.cpp b/lib/mapObjectConstructors/CObjectClassesHandler.cpp index b626e7fab..e6ee4f2dd 100644 --- a/lib/mapObjectConstructors/CObjectClassesHandler.cpp +++ b/lib/mapObjectConstructors/CObjectClassesHandler.cpp @@ -12,12 +12,12 @@ #include "../filesystem/Filesystem.h" #include "../filesystem/CBinaryReader.h" +#include "../json/JsonUtils.h" #include "../VCMI_Lib.h" #include "../GameConstants.h" #include "../constants/StringConstants.h" #include "../CGeneralTextHandler.h" #include "../GameSettings.h" -#include "../JsonNode.h" #include "../CSoundBase.h" #include "../mapObjectConstructors/CBankInstanceConstructor.h" diff --git a/lib/mapObjectConstructors/CObjectClassesHandler.h b/lib/mapObjectConstructors/CObjectClassesHandler.h index cb65b23eb..b1cb1ca64 100644 --- a/lib/mapObjectConstructors/CObjectClassesHandler.h +++ b/lib/mapObjectConstructors/CObjectClassesHandler.h @@ -9,8 +9,9 @@ */ #pragma once +#include "../constants/EntityIdentifiers.h" #include "../IHandlerBase.h" -#include "../JsonNode.h" +#include "../json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapObjectConstructors/CommonConstructors.cpp b/lib/mapObjectConstructors/CommonConstructors.cpp index 9864bd5bf..41ea8f9fc 100644 --- a/lib/mapObjectConstructors/CommonConstructors.cpp +++ b/lib/mapObjectConstructors/CommonConstructors.cpp @@ -14,7 +14,7 @@ #include "../CHeroHandler.h" #include "../CTownHandler.h" #include "../IGameCallback.h" -#include "../JsonRandom.h" +#include "../json/JsonRandom.h" #include "../constants/StringConstants.h" #include "../TerrainHandler.h" #include "../VCMI_Lib.h" diff --git a/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp b/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp index ee3d584f5..c52281505 100644 --- a/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp +++ b/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp @@ -12,7 +12,7 @@ #include "../CCreatureHandler.h" #include "../CGeneralTextHandler.h" -#include "../JsonRandom.h" +#include "../json/JsonRandom.h" #include "../VCMI_Lib.h" #include "../mapObjects/CGDwelling.h" #include "../modding/IdentifierStorage.h" diff --git a/lib/mapObjectConstructors/DwellingInstanceConstructor.h b/lib/mapObjectConstructors/DwellingInstanceConstructor.h index 78d32f60a..bf68fdb26 100644 --- a/lib/mapObjectConstructors/DwellingInstanceConstructor.h +++ b/lib/mapObjectConstructors/DwellingInstanceConstructor.h @@ -10,6 +10,8 @@ #pragma once #include "CDefaultObjectTypeHandler.h" + +#include "../json/JsonNode.h" #include "../mapObjects/CGDwelling.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapObjectConstructors/HillFortInstanceConstructor.h b/lib/mapObjectConstructors/HillFortInstanceConstructor.h index e43ab93c5..645270f17 100644 --- a/lib/mapObjectConstructors/HillFortInstanceConstructor.h +++ b/lib/mapObjectConstructors/HillFortInstanceConstructor.h @@ -10,6 +10,7 @@ #pragma once #include "CDefaultObjectTypeHandler.h" +#include "../json/JsonNode.h" #include "../mapObjects/MiscObjects.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapObjectConstructors/ShipyardInstanceConstructor.h b/lib/mapObjectConstructors/ShipyardInstanceConstructor.h index 334031cd1..8d33b7a76 100644 --- a/lib/mapObjectConstructors/ShipyardInstanceConstructor.h +++ b/lib/mapObjectConstructors/ShipyardInstanceConstructor.h @@ -10,6 +10,7 @@ #pragma once #include "CDefaultObjectTypeHandler.h" +#include "../json/JsonNode.h" #include "../mapObjects/MiscObjects.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index d9ad418a7..0b4dca5b6 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -32,6 +32,7 @@ #include "../StartInfo.h" #include "CGTownInstance.h" #include "../campaign/CampaignState.h" +#include "../json/JsonUtils.h" #include "../pathfinder/TurnInfo.h" #include "../serializer/JsonSerializeFormat.h" #include "../mapObjectConstructors/AObjectTypeHandler.h" diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp index bf9c2158d..8226d01ef 100644 --- a/lib/mapObjects/CObjectHandler.cpp +++ b/lib/mapObjects/CObjectHandler.cpp @@ -13,7 +13,7 @@ #include "CGObjectInstance.h" #include "../filesystem/ResourcePath.h" -#include "../JsonNode.h" +#include "../json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapObjects/ObjectTemplate.cpp b/lib/mapObjects/ObjectTemplate.cpp index 817ca57c7..6fced7254 100644 --- a/lib/mapObjects/ObjectTemplate.cpp +++ b/lib/mapObjects/ObjectTemplate.cpp @@ -16,7 +16,6 @@ #include "../GameConstants.h" #include "../constants/StringConstants.h" #include "../CGeneralTextHandler.h" -#include "../JsonNode.h" #include "../TerrainHandler.h" #include "../mapObjectConstructors/CRewardableConstructor.h" diff --git a/lib/mapping/CMapHeader.cpp b/lib/mapping/CMapHeader.cpp index c67940ac5..74ec81358 100644 --- a/lib/mapping/CMapHeader.cpp +++ b/lib/mapping/CMapHeader.cpp @@ -15,6 +15,7 @@ #include "../VCMI_Lib.h" #include "../CTownHandler.h" #include "../CGeneralTextHandler.h" +#include "../json/JsonUtils.h" #include "../modding/CModHandler.h" #include "../CHeroHandler.h" #include "../Languages.h" diff --git a/lib/mapping/CMapHeader.h b/lib/mapping/CMapHeader.h index 4f72ec311..deaf52e98 100644 --- a/lib/mapping/CMapHeader.h +++ b/lib/mapping/CMapHeader.h @@ -10,6 +10,8 @@ #pragma once +#include "../constants/EntityIdentifiers.h" +#include "../constants/Enumerations.h" #include "../constants/VariantIdentifier.h" #include "../modding/CModInfo.h" #include "../LogicalExpression.h" diff --git a/lib/mapping/CMapService.cpp b/lib/mapping/CMapService.cpp index 7a7ecbcb3..f78a67ee5 100644 --- a/lib/mapping/CMapService.cpp +++ b/lib/mapping/CMapService.cpp @@ -10,6 +10,7 @@ #include "StdInc.h" #include "CMapService.h" +#include "../json/JsonUtils.h" #include "../filesystem/Filesystem.h" #include "../filesystem/CBinaryReader.h" #include "../filesystem/CCompressedStream.h" diff --git a/lib/mapping/MapEditUtils.cpp b/lib/mapping/MapEditUtils.cpp index 8d9e6a2d7..d0691e082 100644 --- a/lib/mapping/MapEditUtils.cpp +++ b/lib/mapping/MapEditUtils.cpp @@ -12,7 +12,6 @@ #include "MapEditUtils.h" #include "../filesystem/Filesystem.h" -#include "../JsonNode.h" #include "../TerrainHandler.h" #include "CMap.h" #include "CMapOperation.h" diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 90ad01008..9fa0a48dd 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -13,7 +13,7 @@ #include "../filesystem/CInputStream.h" #include "../filesystem/COutputStream.h" -#include "../JsonDetail.h" +#include "../json/JsonWriter.h" #include "CMap.h" #include "MapFormat.h" #include "../ArtifactUtils.h" @@ -1201,7 +1201,7 @@ CMapSaverJson::~CMapSaverJson() = default; void CMapSaverJson::addToArchive(const JsonNode & data, const std::string & filename) { std::ostringstream out; - JsonWriter writer(out); + JsonWriter writer(out, false); writer.writeNode(data); out.flush(); diff --git a/lib/mapping/MapFormatJson.h b/lib/mapping/MapFormatJson.h index fb8a78e2f..117e9f2bb 100644 --- a/lib/mapping/MapFormatJson.h +++ b/lib/mapping/MapFormatJson.h @@ -11,7 +11,6 @@ #pragma once #include "CMapService.h" -#include "../JsonNode.h" #include "../filesystem/CZipSaver.h" #include "../filesystem/CZipLoader.h" diff --git a/lib/mapping/MapIdentifiersH3M.cpp b/lib/mapping/MapIdentifiersH3M.cpp index 0f7207e0c..15a7602ce 100644 --- a/lib/mapping/MapIdentifiersH3M.cpp +++ b/lib/mapping/MapIdentifiersH3M.cpp @@ -11,7 +11,6 @@ #include "StdInc.h" #include "MapIdentifiersH3M.h" -#include "../JsonNode.h" #include "../VCMI_Lib.h" #include "../CTownHandler.h" #include "../CHeroHandler.h" diff --git a/lib/modding/CModHandler.cpp b/lib/modding/CModHandler.cpp index 1fe9d4b17..ef08b5009 100644 --- a/lib/modding/CModHandler.cpp +++ b/lib/modding/CModHandler.cpp @@ -25,6 +25,7 @@ #include "../ScriptHandler.h" #include "../constants/StringConstants.h" #include "../filesystem/Filesystem.h" +#include "../json/JsonUtils.h" #include "../spells/CSpellHandler.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/modding/CModInfo.h b/lib/modding/CModInfo.h index b89fdae02..3d6b40320 100644 --- a/lib/modding/CModInfo.h +++ b/lib/modding/CModInfo.h @@ -9,7 +9,7 @@ */ #pragma once -#include "../JsonNode.h" +#include "../json/JsonNode.h" #include "ModVerificationInfo.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/modding/ContentTypeHandler.cpp b/lib/modding/ContentTypeHandler.cpp index c255ebc07..0c2abf99a 100644 --- a/lib/modding/ContentTypeHandler.cpp +++ b/lib/modding/ContentTypeHandler.cpp @@ -31,6 +31,7 @@ #include "../ScriptHandler.h" #include "../constants/StringConstants.h" #include "../TerrainHandler.h" +#include "../json/JsonUtils.h" #include "../mapObjectConstructors/CObjectClassesHandler.h" #include "../rmg/CRmgTemplateStorage.h" #include "../spells/CSpellHandler.h" diff --git a/lib/modding/ContentTypeHandler.h b/lib/modding/ContentTypeHandler.h index e1224013e..7093c12d5 100644 --- a/lib/modding/ContentTypeHandler.h +++ b/lib/modding/ContentTypeHandler.h @@ -9,7 +9,7 @@ */ #pragma once -#include "../JsonNode.h" +#include "../json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/modding/IdentifierStorage.cpp b/lib/modding/IdentifierStorage.cpp index d8b16d7d0..dd17b15ae 100644 --- a/lib/modding/IdentifierStorage.cpp +++ b/lib/modding/IdentifierStorage.cpp @@ -13,7 +13,6 @@ #include "CModHandler.h" #include "ModScope.h" -#include "../JsonNode.h" #include "../VCMI_Lib.h" #include "../constants/StringConstants.h" #include "../spells/CSpellHandler.h" diff --git a/lib/networkPacks/BattleChanges.h b/lib/networkPacks/BattleChanges.h index 92dca1d47..1a06195bb 100644 --- a/lib/networkPacks/BattleChanges.h +++ b/lib/networkPacks/BattleChanges.h @@ -9,7 +9,7 @@ */ #pragma once -#include "JsonNode.h" +#include "../json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/networkPacks/EntityChanges.h b/lib/networkPacks/EntityChanges.h index 7d5aacf87..f502c309d 100644 --- a/lib/networkPacks/EntityChanges.h +++ b/lib/networkPacks/EntityChanges.h @@ -9,9 +9,9 @@ */ #pragma once -#include +#include "../json/JsonNode.h" -#include "../JsonNode.h" +#include VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp index 334c6a701..8a6fa89cc 100644 --- a/lib/rewardable/Info.cpp +++ b/lib/rewardable/Info.cpp @@ -17,7 +17,7 @@ #include "../CGeneralTextHandler.h" #include "../IGameCallback.h" -#include "../JsonRandom.h" +#include "../json/JsonRandom.h" #include "../mapObjects/IObjectInterface.h" #include "../modding/IdentifierStorage.h" #include "../CRandomGenerator.h" diff --git a/lib/rewardable/Info.h b/lib/rewardable/Info.h index 3216d5f68..e2bb4322f 100644 --- a/lib/rewardable/Info.h +++ b/lib/rewardable/Info.h @@ -10,7 +10,7 @@ #pragma once -#include "../JsonNode.h" +#include "../json/JsonNode.h" #include "../mapObjectConstructors/IObjectInfo.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/serializer/JsonDeserializer.cpp b/lib/serializer/JsonDeserializer.cpp index a2b840777..15d20e989 100644 --- a/lib/serializer/JsonDeserializer.cpp +++ b/lib/serializer/JsonDeserializer.cpp @@ -10,8 +10,6 @@ #include "StdInc.h" #include "JsonDeserializer.h" -#include "../JsonNode.h" - #include VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/serializer/JsonSerializeFormat.cpp b/lib/serializer/JsonSerializeFormat.cpp index bbf576a96..e258d5b83 100644 --- a/lib/serializer/JsonSerializeFormat.cpp +++ b/lib/serializer/JsonSerializeFormat.cpp @@ -10,8 +10,6 @@ #include "StdInc.h" #include "JsonSerializeFormat.h" -#include "../JsonNode.h" - VCMI_LIB_NAMESPACE_BEGIN //JsonSerializeHelper diff --git a/lib/serializer/JsonSerializeFormat.h b/lib/serializer/JsonSerializeFormat.h index b86dbcad4..e5d16021d 100644 --- a/lib/serializer/JsonSerializeFormat.h +++ b/lib/serializer/JsonSerializeFormat.h @@ -9,7 +9,8 @@ */ #pragma once -#include "../JsonNode.h" +#include "../constants/IdentifierBase.h" +#include "../json/JsonNode.h" #include "../modding/IdentifierStorage.h" #include "../modding/ModScope.h" #include "../VCMI_Lib.h" diff --git a/lib/serializer/JsonSerializer.cpp b/lib/serializer/JsonSerializer.cpp index 430a6809a..32575e2e0 100644 --- a/lib/serializer/JsonSerializer.cpp +++ b/lib/serializer/JsonSerializer.cpp @@ -10,8 +10,6 @@ #include "StdInc.h" #include "JsonSerializer.h" -#include "../JsonNode.h" - VCMI_LIB_NAMESPACE_BEGIN JsonSerializer::JsonSerializer(const IInstanceResolver * instanceResolver_, JsonNode & root_): diff --git a/lib/serializer/JsonUpdater.cpp b/lib/serializer/JsonUpdater.cpp index 6a29bc910..d1719a029 100644 --- a/lib/serializer/JsonUpdater.cpp +++ b/lib/serializer/JsonUpdater.cpp @@ -10,10 +10,9 @@ #include "StdInc.h" #include "JsonUpdater.h" -#include "../JsonNode.h" - #include "../bonuses/CBonusSystemNode.h" #include "../bonuses/Bonus.h" +#include "../json/JsonUtils.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index b5751ee53..e5908340a 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -25,7 +25,7 @@ #include "../battle/BattleInfo.h" #include "../battle/CBattleInfoCallback.h" #include "../battle/Unit.h" - +#include "../json/JsonUtils.h" #include "../mapObjects/CGHeroInstance.h" //todo: remove #include "../serializer/CSerializer.h" #include "../modding/IdentifierStorage.h" diff --git a/lib/spells/CSpellHandler.h b/lib/spells/CSpellHandler.h index 522e30d83..b4f079c90 100644 --- a/lib/spells/CSpellHandler.h +++ b/lib/spells/CSpellHandler.h @@ -13,7 +13,6 @@ #include #include #include -#include "../JsonNode.h" #include "../IHandlerBase.h" #include "../ConstTransitivePtr.h" #include "../int3.h" @@ -21,6 +20,7 @@ #include "../battle/BattleHex.h" #include "../bonuses/Bonus.h" #include "../filesystem/ResourcePath.h" +#include "../json/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/spells/TargetCondition.cpp b/lib/spells/TargetCondition.cpp index a3dfeb3de..cabe2aa87 100644 --- a/lib/spells/TargetCondition.cpp +++ b/lib/spells/TargetCondition.cpp @@ -17,7 +17,7 @@ #include "../battle/Unit.h" #include "../bonuses/BonusParams.h" #include "../bonuses/BonusList.h" - +#include "../json/JsonUtils.h" #include "../modding/IdentifierStorage.h" #include "../modding/ModUtility.h" #include "../serializer/JsonSerializeFormat.h" diff --git a/lib/spells/effects/Moat.cpp b/lib/spells/effects/Moat.cpp index 359f2460b..b51e91b1b 100644 --- a/lib/spells/effects/Moat.cpp +++ b/lib/spells/effects/Moat.cpp @@ -18,6 +18,7 @@ #include "../../bonuses/Limiters.h" #include "../../battle/IBattleState.h" #include "../../battle/CBattleInfoCallback.h" +#include "../../json/JsonUtils.h" #include "../../serializer/JsonSerializeFormat.h" #include "../../networkPacks/PacksForClient.h" #include "../../networkPacks/PacksForClientBattle.h" diff --git a/lib/spells/effects/Timed.cpp b/lib/spells/effects/Timed.cpp index 956fcf884..2fa25d090 100644 --- a/lib/spells/effects/Timed.cpp +++ b/lib/spells/effects/Timed.cpp @@ -17,6 +17,7 @@ #include "../../battle/IBattleState.h" #include "../../battle/CBattleInfoCallback.h" #include "../../battle/Unit.h" +#include "../../json/JsonUtils.h" #include "../../mapObjects/CGHeroInstance.h" #include "../../networkPacks/PacksForClientBattle.h" #include "../../networkPacks/SetStackEffect.h" diff --git a/mapeditor/Animation.cpp b/mapeditor/Animation.cpp index 4c12a220c..5aff952da 100644 --- a/mapeditor/Animation.cpp +++ b/mapeditor/Animation.cpp @@ -19,7 +19,7 @@ #include "../lib/vcmi_endian.h" #include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/ISimpleResourceLoader.h" -#include "../lib/JsonNode.h" +#include "../lib/json/JsonUtils.h" #include "../lib/CRandomGenerator.h" #include "../lib/VCMIDirs.h" diff --git a/mapeditor/Animation.h b/mapeditor/Animation.h index eb5342f0d..2e4556413 100644 --- a/mapeditor/Animation.h +++ b/mapeditor/Animation.h @@ -10,11 +10,14 @@ #pragma once //code is copied from vcmiclient/CAnimation.h with minimal changes -#include "../lib/JsonNode.h" #include "../lib/GameConstants.h" #include #include +VCMI_LIB_NAMESPACE_BEGIN +class JsonNode; +VCMI_LIB_NAMESPACE_END + /* * Base class for images, can be used for non-animation pictures as well */ diff --git a/mapeditor/graphics.cpp b/mapeditor/graphics.cpp index d80dd6121..73e80b2b3 100644 --- a/mapeditor/graphics.cpp +++ b/mapeditor/graphics.cpp @@ -28,7 +28,6 @@ #include "../CCallback.h" #include "../lib/CGeneralTextHandler.h" #include "BitmapHandler.h" -#include "../lib/JsonNode.h" #include "../lib/CStopWatch.h" #include "../lib/mapObjectConstructors/AObjectTypeHandler.h" #include "../lib/mapObjectConstructors/CObjectClassesHandler.h" diff --git a/mapeditor/jsonutils.cpp b/mapeditor/jsonutils.cpp index a10129c14..15649d97f 100644 --- a/mapeditor/jsonutils.cpp +++ b/mapeditor/jsonutils.cpp @@ -10,6 +10,8 @@ #include "StdInc.h" #include "jsonutils.h" +#include "../lib/json/JsonNode.h" + static QVariantMap JsonToMap(const JsonMap & json) { QVariantMap map; diff --git a/mapeditor/jsonutils.h b/mapeditor/jsonutils.h index 6dd7e7bbf..791711eb0 100644 --- a/mapeditor/jsonutils.h +++ b/mapeditor/jsonutils.h @@ -10,10 +10,11 @@ #pragma once #include -#include "../lib/JsonNode.h" VCMI_LIB_NAMESPACE_BEGIN +class JsonNode; + namespace JsonUtils { QVariant toVariant(const JsonNode & node); diff --git a/mapeditor/maphandler.cpp b/mapeditor/maphandler.cpp index 3c11ed278..f5db55ba0 100644 --- a/mapeditor/maphandler.cpp +++ b/mapeditor/maphandler.cpp @@ -22,7 +22,6 @@ #include "../lib/CHeroHandler.h" #include "../lib/CTownHandler.h" #include "../lib/GameConstants.h" -#include "../lib/JsonDetail.h" const int tileSize = 32; diff --git a/mapeditor/resourceExtractor/ResourceConverter.cpp b/mapeditor/resourceExtractor/ResourceConverter.cpp index ed21d3320..54dc3bc22 100644 --- a/mapeditor/resourceExtractor/ResourceConverter.cpp +++ b/mapeditor/resourceExtractor/ResourceConverter.cpp @@ -12,7 +12,6 @@ #include "ResourceConverter.h" -#include "../lib/JsonNode.h" #include "../lib/VCMIDirs.h" #include "../lib/filesystem/Filesystem.h" diff --git a/scripting/lua/LuaScriptingContext.cpp b/scripting/lua/LuaScriptingContext.cpp index 2eda9ac47..d92e43735 100644 --- a/scripting/lua/LuaScriptingContext.cpp +++ b/scripting/lua/LuaScriptingContext.cpp @@ -19,7 +19,7 @@ #include "api/Registry.h" -#include "../../lib/JsonNode.h" +#include "../../lib/json/JsonNode.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/battle/IBattleInfoCallback.h" #include "../../lib/CGameInfoCallback.h" diff --git a/scripting/lua/LuaSpellEffect.cpp b/scripting/lua/LuaSpellEffect.cpp index c039567f3..2d51dd281 100644 --- a/scripting/lua/LuaSpellEffect.cpp +++ b/scripting/lua/LuaSpellEffect.cpp @@ -18,6 +18,7 @@ #include "../../lib/battle/Unit.h" #include "../../lib/battle/CBattleInfoCallback.h" +#include "../../lib/json/JsonUtils.h" #include "../../lib/serializer/JsonSerializeFormat.h" static const std::string APPLICABLE_GENERAL = "applicable"; diff --git a/scripting/lua/LuaStack.cpp b/scripting/lua/LuaStack.cpp index 18dc12803..b406a278d 100644 --- a/scripting/lua/LuaStack.cpp +++ b/scripting/lua/LuaStack.cpp @@ -11,7 +11,7 @@ #include "LuaStack.h" -#include "../../lib/JsonNode.h" +#include "../../lib/json/JsonNode.h" #include "../../lib/int3.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/scripting/lua/api/BonusSystem.cpp b/scripting/lua/api/BonusSystem.cpp index 2ce613ab0..f15acebec 100644 --- a/scripting/lua/api/BonusSystem.cpp +++ b/scripting/lua/api/BonusSystem.cpp @@ -11,7 +11,7 @@ #include "BonusSystem.h" -#include "../../../lib/JsonNode.h" +#include "../../../lib/json/JsonNode.h" #include "../../../lib/bonuses/BonusList.h" #include "../../../lib/bonuses/Bonus.h" diff --git a/test/JsonComparer.h b/test/JsonComparer.h index dd10b6950..e98ed039c 100644 --- a/test/JsonComparer.h +++ b/test/JsonComparer.h @@ -10,7 +10,7 @@ #pragma once -#include "../lib/JsonNode.h" +#include "../lib/json/JsonNode.h" namespace vstd { diff --git a/test/entity/CCreatureTest.cpp b/test/entity/CCreatureTest.cpp index a70d3f9c1..3ffdd4d7d 100644 --- a/test/entity/CCreatureTest.cpp +++ b/test/entity/CCreatureTest.cpp @@ -10,6 +10,7 @@ #include "StdInc.h" #include "../../lib/CCreatureHandler.h" +#include "../../lib/json/JsonNode.h" namespace test { diff --git a/test/game/CGameStateTest.cpp b/test/game/CGameStateTest.cpp index 1f2aa6053..29a6a43d5 100644 --- a/test/game/CGameStateTest.cpp +++ b/test/game/CGameStateTest.cpp @@ -15,6 +15,7 @@ #include "mock/mock_spells_Problem.h" #include "../../lib/VCMIDirs.h" +#include "../../lib/json/JsonUtils.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/networkPacks/PacksForClient.h" #include "../../lib/networkPacks/PacksForClientBattle.h" diff --git a/test/map/CMapEditManagerTest.cpp b/test/map/CMapEditManagerTest.cpp index f25a0434b..0020a6e93 100644 --- a/test/map/CMapEditManagerTest.cpp +++ b/test/map/CMapEditManagerTest.cpp @@ -14,7 +14,6 @@ #include "../lib/mapping/CMapService.h" #include "../lib/mapping/CMap.h" #include "../lib/TerrainHandler.h" -#include "../lib/JsonNode.h" #include "../lib/mapping/CMapEditManager.h" #include "../lib/int3.h" #include "../lib/CRandomGenerator.h" diff --git a/test/map/CMapFormatTest.cpp b/test/map/CMapFormatTest.cpp index cf20dfed1..afd72b8c3 100644 --- a/test/map/CMapFormatTest.cpp +++ b/test/map/CMapFormatTest.cpp @@ -9,8 +9,6 @@ */ #include "StdInc.h" -#include "../../lib/JsonDetail.h" - #include "../../lib/filesystem/CMemoryBuffer.h" #include "../../lib/filesystem/Filesystem.h" diff --git a/test/mock/BattleFake.h b/test/mock/BattleFake.h index 8ce30c38f..4a8d04b4d 100644 --- a/test/mock/BattleFake.h +++ b/test/mock/BattleFake.h @@ -19,7 +19,6 @@ #include "mock_scripting_Pool.h" #endif -#include "../../lib/JsonNode.h" #include "../../lib/battle/CBattleInfoCallback.h" namespace test diff --git a/test/mock/mock_scripting_Context.h b/test/mock/mock_scripting_Context.h index a78cceaa2..365458f57 100644 --- a/test/mock/mock_scripting_Context.h +++ b/test/mock/mock_scripting_Context.h @@ -12,7 +12,7 @@ #include -#include "../../../lib/JsonNode.h" +#include "../../../lib/json/JsonNode.h" namespace scripting { diff --git a/test/scripting/LuaSpellEffectAPITest.cpp b/test/scripting/LuaSpellEffectAPITest.cpp index 759aef93e..78958dfa7 100644 --- a/test/scripting/LuaSpellEffectAPITest.cpp +++ b/test/scripting/LuaSpellEffectAPITest.cpp @@ -12,6 +12,7 @@ #include "ScriptFixture.h" #include "../../lib/networkPacks/PacksForClientBattle.h" +#include "../../lib/json/JsonUtils.h" #include "../mock/mock_ServerCallback.h" diff --git a/test/scripting/LuaSpellEffectTest.cpp b/test/scripting/LuaSpellEffectTest.cpp index bb22c142d..b917c9746 100644 --- a/test/scripting/LuaSpellEffectTest.cpp +++ b/test/scripting/LuaSpellEffectTest.cpp @@ -19,6 +19,7 @@ #include "../mock/mock_ServerCallback.h" #include "../../../lib/VCMI_Lib.h" +#include "../../lib/json/JsonUtils.h" #include "../../../lib/ScriptHandler.h" #include "../../../lib/CScriptingModule.h" diff --git a/test/scripting/ScriptFixture.h b/test/scripting/ScriptFixture.h index ea9f0cbe3..97edbe1fe 100644 --- a/test/scripting/ScriptFixture.h +++ b/test/scripting/ScriptFixture.h @@ -14,7 +14,7 @@ #include -#include "../../lib/JsonNode.h" +#include "../../../lib/json/JsonNode.h" #include "../../lib/ScriptHandler.h" #include "../../lib/battle/CBattleInfoCallback.h" #include "../../lib/bonuses/Bonus.h" diff --git a/test/spells/effects/CloneTest.cpp b/test/spells/effects/CloneTest.cpp index e4523a0d9..810824b6b 100644 --- a/test/spells/effects/CloneTest.cpp +++ b/test/spells/effects/CloneTest.cpp @@ -14,6 +14,7 @@ #include #include "../../../lib/battle/CUnitState.h" +#include "../../../lib/json/JsonNode.h" namespace test { diff --git a/test/spells/effects/DamageTest.cpp b/test/spells/effects/DamageTest.cpp index 05614ade1..a8bae9734 100644 --- a/test/spells/effects/DamageTest.cpp +++ b/test/spells/effects/DamageTest.cpp @@ -14,6 +14,7 @@ #include #include "../../../lib/battle/CUnitState.h" +#include "../../../lib/json/JsonNode.h" #include "mock/mock_UnitEnvironment.h" diff --git a/test/spells/effects/DispelTest.cpp b/test/spells/effects/DispelTest.cpp index 5d6f1db39..5d05ea81a 100644 --- a/test/spells/effects/DispelTest.cpp +++ b/test/spells/effects/DispelTest.cpp @@ -10,6 +10,7 @@ #include "StdInc.h" #include "EffectFixture.h" +#include "../../../lib/json/JsonNode.h" namespace test { diff --git a/test/spells/effects/EffectFixture.h b/test/spells/effects/EffectFixture.h index dde8e9a2d..4a2d38034 100644 --- a/test/spells/effects/EffectFixture.h +++ b/test/spells/effects/EffectFixture.h @@ -33,7 +33,6 @@ #include "../../mock/mock_ServerCallback.h" -#include "../../../lib/JsonNode.h" #include "../../../lib/battle/CBattleInfoCallback.h" namespace battle diff --git a/test/spells/effects/HealTest.cpp b/test/spells/effects/HealTest.cpp index af24fb1b7..d2479951c 100644 --- a/test/spells/effects/HealTest.cpp +++ b/test/spells/effects/HealTest.cpp @@ -14,6 +14,7 @@ #include #include "../../../lib/battle/CUnitState.h" +#include "../../../lib/json/JsonNode.h" #include "mock/mock_UnitEnvironment.h" diff --git a/test/spells/effects/SacrificeTest.cpp b/test/spells/effects/SacrificeTest.cpp index a8a4ebf62..2bde689ef 100644 --- a/test/spells/effects/SacrificeTest.cpp +++ b/test/spells/effects/SacrificeTest.cpp @@ -14,6 +14,7 @@ #include #include "../../../lib/battle/CUnitState.h" +#include "../../../lib/json/JsonNode.h" #include "mock/mock_UnitEnvironment.h" diff --git a/test/spells/effects/SummonTest.cpp b/test/spells/effects/SummonTest.cpp index cdd20af1c..2dfbfc659 100644 --- a/test/spells/effects/SummonTest.cpp +++ b/test/spells/effects/SummonTest.cpp @@ -14,6 +14,7 @@ #include #include "../../../lib/CCreatureHandler.h" +#include "../../../lib/json/JsonNode.h" namespace test { diff --git a/test/spells/effects/TeleportTest.cpp b/test/spells/effects/TeleportTest.cpp index e8b597689..00f46bfd1 100644 --- a/test/spells/effects/TeleportTest.cpp +++ b/test/spells/effects/TeleportTest.cpp @@ -11,6 +11,7 @@ #include "EffectFixture.h" +#include "../../../lib/json/JsonNode.h" #include namespace test diff --git a/test/spells/effects/TimedTest.cpp b/test/spells/effects/TimedTest.cpp index 01d9a2d10..e96f3d476 100644 --- a/test/spells/effects/TimedTest.cpp +++ b/test/spells/effects/TimedTest.cpp @@ -12,7 +12,8 @@ #include "EffectFixture.h" #include -#include "lib/modding/ModScope.h" +#include "../../../lib/modding/ModScope.h" +#include "../../../lib/json/JsonNode.h" namespace test {