1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Implemented 'strict' json support

This commit is contained in:
Ivan Savenko
2024-02-13 18:08:35 +02:00
parent d1c274f93f
commit 41493d6f67
8 changed files with 69 additions and 13 deletions

View File

@ -405,6 +405,7 @@ set(lib_HEADERS
filesystem/ResourcePath.h filesystem/ResourcePath.h
json/JsonBonus.h json/JsonBonus.h
json/JsonFormatException.h
json/JsonNode.h json/JsonNode.h
json/JsonParser.h json/JsonParser.h
json/JsonRandom.h json/JsonRandom.h

View File

@ -14,6 +14,11 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
struct Bonus;
class ILimiter;
class CSelector;
class CAddInfo;
namespace JsonUtils namespace JsonUtils
{ {
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec); DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);

View File

@ -0,0 +1,20 @@
/*
* JsonFormatException.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
VCMI_LIB_NAMESPACE_BEGIN
class JsonFormatException : public std::runtime_error
{
public:
using runtime_error::runtime_error;
};
VCMI_LIB_NAMESPACE_END

View File

@ -79,8 +79,12 @@ JsonNode::JsonNode(const std::string & string)
{} {}
JsonNode::JsonNode(const std::byte *data, size_t datasize) JsonNode::JsonNode(const std::byte *data, size_t datasize)
:JsonNode(data, datasize, JsonParsingSettings())
{}
JsonNode::JsonNode(const std::byte *data, size_t datasize, const JsonParsingSettings & parserSettings)
{ {
JsonParser parser(reinterpret_cast<const char*>(data), datasize); JsonParser parser(reinterpret_cast<const char*>(data), datasize, parserSettings);
*this = parser.parse("<unknown>"); *this = parser.parse("<unknown>");
} }
@ -88,7 +92,7 @@ JsonNode::JsonNode(const JsonPath & fileURI)
{ {
auto file = CResourceHandler::get()->load(fileURI)->readAll(); auto file = CResourceHandler::get()->load(fileURI)->readAll();
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second); JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second, JsonParsingSettings());
*this = parser.parse(fileURI.getName()); *this = parser.parse(fileURI.getName());
} }
@ -96,7 +100,7 @@ JsonNode::JsonNode(const JsonPath & fileURI, const std::string & idx)
{ {
auto file = CResourceHandler::get(idx)->load(fileURI)->readAll(); auto file = CResourceHandler::get(idx)->load(fileURI)->readAll();
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second); JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second, JsonParsingSettings());
*this = parser.parse(fileURI.getName()); *this = parser.parse(fileURI.getName());
} }
@ -104,7 +108,7 @@ JsonNode::JsonNode(const JsonPath & fileURI, bool &isValidSyntax)
{ {
auto file = CResourceHandler::get()->load(fileURI)->readAll(); auto file = CResourceHandler::get()->load(fileURI)->readAll();
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second); JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second, JsonParsingSettings());
*this = parser.parse(fileURI.getName()); *this = parser.parse(fileURI.getName());
isValidSyntax = parser.isValid(); isValidSyntax = parser.isValid();
} }

View File

@ -17,10 +17,23 @@ class JsonNode;
using JsonMap = std::map<std::string, JsonNode>; using JsonMap = std::map<std::string, JsonNode>;
using JsonVector = std::vector<JsonNode>; using JsonVector = std::vector<JsonNode>;
struct Bonus; struct JsonParsingSettings
class CSelector; {
class CAddInfo; enum class JsonFormatMode
class ILimiter; {
JSON, // strict implementation of json format
JSONC, // json format that also allows comments that start from '//'
//JSON5 // TODO?
};
JsonFormatMode mode = JsonFormatMode::JSONC;
/// Maximum depth of elements
uint32_t maxDepth = 30;
/// If set to true, parser will throw on any encountered error
bool strict = false;
};
class DLL_LINKAGE JsonNode class DLL_LINKAGE JsonNode
{ {
@ -58,6 +71,7 @@ public:
/// Create tree from Json-formatted input /// Create tree from Json-formatted input
explicit JsonNode(const std::byte * data, size_t datasize); explicit JsonNode(const std::byte * data, size_t datasize);
explicit JsonNode(const std::byte * data, size_t datasize, const JsonParsingSettings & parserSettings);
/// Create tree from JSON file /// Create tree from JSON file
explicit JsonNode(const JsonPath & fileURI); explicit JsonNode(const JsonPath & fileURI);

View File

@ -11,12 +11,14 @@
#include "StdInc.h" #include "StdInc.h"
#include "JsonParser.h" #include "JsonParser.h"
#include "JsonFormatException.h"
#include "../TextOperations.h" #include "../TextOperations.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
JsonParser::JsonParser(const char * inputString, size_t stringSize): JsonParser::JsonParser(const char * inputString, size_t stringSize, const JsonParsingSettings & settings):
input(inputString, stringSize), input(inputString, stringSize),
settings(settings),
lineCount(1), lineCount(1),
lineStart(0), lineStart(0),
pos(0) pos(0)
@ -105,9 +107,13 @@ bool JsonParser::extractWhitespace(bool verbose)
} }
pos++; pos++;
} }
if (pos >= input.size() || input[pos] != '/') if (pos >= input.size() || input[pos] != '/')
break; break;
if (settings.mode == JsonParsingSettings::JsonFormatMode::JSON)
error("Comments are not permitted in json!", true);
pos++; pos++;
if (pos == input.size()) if (pos == input.size())
break; break;
@ -346,9 +352,8 @@ bool JsonParser::extractElement(JsonNode &node, char terminator)
if (input[pos] == terminator) if (input[pos] == terminator)
{ {
//FIXME: MOD COMPATIBILITY: Too many of these right now, re-enable later if (comma)
//if (comma) error("Extra comma found!", true);
//error("Extra comma found!", true);
return true; return true;
} }
@ -456,6 +461,9 @@ bool JsonParser::extractFloat(JsonNode &node)
bool JsonParser::error(const std::string &message, bool warning) bool JsonParser::error(const std::string &message, bool warning)
{ {
if (settings.strict)
throw JsonFormatException(message);
std::ostringstream stream; std::ostringstream stream;
std::string type(warning?" warning: ":" error: "); std::string type(warning?" warning: ":" error: ");

View File

@ -16,6 +16,8 @@ VCMI_LIB_NAMESPACE_BEGIN
//Internal class for string -> JsonNode conversion //Internal class for string -> JsonNode conversion
class JsonParser class JsonParser
{ {
const JsonParsingSettings settings;
std::string errors; // Contains description of all encountered errors std::string errors; // Contains description of all encountered errors
std::string_view input; // Input data std::string_view input; // Input data
ui32 lineCount; // Currently parsed line, starting from 1 ui32 lineCount; // Currently parsed line, starting from 1
@ -44,7 +46,7 @@ class JsonParser
bool error(const std::string &message, bool warning=false); bool error(const std::string &message, bool warning=false);
public: public:
JsonParser(const char * inputString, size_t stringSize); JsonParser(const char * inputString, size_t stringSize, const JsonParsingSettings & settings);
/// do actual parsing. filename is name of file that will printed to console if any errors were found /// do actual parsing. filename is name of file that will printed to console if any errors were found
JsonNode parse(const std::string & fileName); JsonNode parse(const std::string & fileName);

View File

@ -14,6 +14,8 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
struct Bonus;
namespace spells namespace spells
{ {
namespace effects namespace effects