1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +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
json/JsonBonus.h
json/JsonFormatException.h
json/JsonNode.h
json/JsonParser.h
json/JsonRandom.h

View File

@ -14,6 +14,11 @@
VCMI_LIB_NAMESPACE_BEGIN
struct Bonus;
class ILimiter;
class CSelector;
class CAddInfo;
namespace JsonUtils
{
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(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>");
}
@ -88,7 +92,7 @@ JsonNode::JsonNode(const JsonPath & fileURI)
{
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());
}
@ -96,7 +100,7 @@ JsonNode::JsonNode(const JsonPath & fileURI, const std::string & idx)
{
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());
}
@ -104,7 +108,7 @@ JsonNode::JsonNode(const JsonPath & fileURI, bool &isValidSyntax)
{
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());
isValidSyntax = parser.isValid();
}

View File

@ -17,10 +17,23 @@ class JsonNode;
using JsonMap = std::map<std::string, JsonNode>;
using JsonVector = std::vector<JsonNode>;
struct Bonus;
class CSelector;
class CAddInfo;
class ILimiter;
struct JsonParsingSettings
{
enum class JsonFormatMode
{
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
{
@ -58,6 +71,7 @@ public:
/// Create tree from Json-formatted input
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
explicit JsonNode(const JsonPath & fileURI);

View File

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

View File

@ -16,6 +16,8 @@ VCMI_LIB_NAMESPACE_BEGIN
//Internal class for string -> JsonNode conversion
class JsonParser
{
const JsonParsingSettings settings;
std::string errors; // Contains description of all encountered errors
std::string_view input; // Input data
ui32 lineCount; // Currently parsed line, starting from 1
@ -44,7 +46,7 @@ class JsonParser
bool error(const std::string &message, bool warning=false);
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
JsonNode parse(const std::string & fileName);

View File

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