2012-12-19 17:54:10 +03:00
/*
* JsonNode . 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
*
*/
2012-07-16 19:18:02 +03:00
# pragma once
2021-01-14 00:02:13 +02:00
# include "GameConstants.h"
2012-07-16 19:18:02 +03:00
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2012-07-16 19:18:02 +03:00
class JsonNode ;
2023-04-17 23:11:16 +02:00
using JsonMap = std : : map < std : : string , JsonNode > ;
using JsonVector = std : : vector < JsonNode > ;
2012-07-16 19:18:02 +03:00
2012-07-19 21:52:44 +03:00
struct Bonus ;
2023-03-09 01:18:30 +02:00
class CSelector ;
2012-08-02 14:03:26 +03:00
class ResourceID ;
2018-03-12 07:20:18 +02:00
class CAddInfo ;
2018-04-01 13:17:34 +02:00
class ILimiter ;
2012-07-16 19:18:02 +03:00
class DLL_LINKAGE JsonNode
{
public :
2017-11-26 23:18:18 +02:00
enum class JsonType
2012-07-16 19:18:02 +03:00
{
DATA_NULL ,
DATA_BOOL ,
DATA_FLOAT ,
DATA_STRING ,
DATA_VECTOR ,
2016-11-13 12:38:42 +02:00
DATA_STRUCT ,
DATA_INTEGER
2012-07-16 19:18:02 +03:00
} ;
private :
union JsonData
{
bool Bool ;
double Float ;
std : : string * String ;
JsonVector * Vector ;
JsonMap * Struct ;
2016-11-13 12:38:42 +02:00
si64 Integer ;
2012-07-16 19:18:02 +03:00
} ;
JsonType type ;
JsonData data ;
public :
2018-03-05 05:30:10 +02:00
/// free to use metadata fields
2013-04-25 17:03:35 +03:00
std : : string meta ;
2018-03-05 05:30:10 +02:00
// meta-flags like override
std : : vector < std : : string > flags ;
2013-04-25 17:03:35 +03:00
2012-07-16 19:18:02 +03:00
//Create empty node
2017-11-26 23:18:18 +02:00
JsonNode ( JsonType Type = JsonType : : DATA_NULL ) ;
2012-07-16 19:18:02 +03:00
//Create tree from Json-formatted input
explicit JsonNode ( const char * data , size_t datasize ) ;
//Create tree from JSON file
2012-08-02 14:03:26 +03:00
explicit JsonNode ( ResourceID & & fileURI ) ;
2016-01-27 10:38:35 +02:00
explicit JsonNode ( const ResourceID & fileURI ) ;
2022-06-20 16:39:50 +02:00
explicit JsonNode ( const std : : string & idx , const ResourceID & fileURI ) ;
2013-11-08 23:36:26 +03:00
explicit JsonNode ( ResourceID & & fileURI , bool & isValidSyntax ) ;
2012-07-16 19:18:02 +03:00
//Copy c-tor
JsonNode ( const JsonNode & copy ) ;
~ JsonNode ( ) ;
void swap ( JsonNode & b ) ;
JsonNode & operator = ( JsonNode node ) ;
bool operator = = ( const JsonNode & other ) const ;
bool operator ! = ( const JsonNode & other ) const ;
2023-03-13 23:26:44 +02:00
void setMeta ( const std : : string & metadata , bool recursive = true ) ;
2013-04-25 17:03:35 +03:00
2013-06-26 14:18:27 +03:00
/// Convert node to another type. Converting to nullptr will clear all data
2012-07-16 19:18:02 +03:00
void setType ( JsonType Type ) ;
JsonType getType ( ) const ;
bool isNull ( ) const ;
2016-11-13 12:38:42 +02:00
bool isNumber ( ) const ;
2023-01-22 18:17:26 +02:00
bool isString ( ) const ;
bool isVector ( ) const ;
bool isStruct ( ) const ;
2017-09-16 00:23:31 +02:00
/// true if node contains not-null data that cannot be extended via merging
/// used for generating common base node from multiple nodes (e.g. bonuses)
bool containsBaseData ( ) const ;
2017-09-14 03:03:44 +02:00
bool isCompact ( ) const ;
2013-04-02 20:06:43 +03:00
/// removes all data from node and sets type to null
void clear ( ) ;
2012-07-16 19:18:02 +03:00
2021-04-25 14:07:06 +02:00
/// returns bool or bool equivalent of string value if 'success' is true, or false otherwise
bool TryBoolFromString ( bool & success ) const ;
2013-04-02 20:06:43 +03:00
/// non-const accessors, node will change type on type mismatch
2012-07-16 19:18:02 +03:00
bool & Bool ( ) ;
double & Float ( ) ;
2016-11-13 12:38:42 +02:00
si64 & Integer ( ) ;
2012-07-16 19:18:02 +03:00
std : : string & String ( ) ;
JsonVector & Vector ( ) ;
JsonMap & Struct ( ) ;
2013-04-02 20:06:43 +03:00
/// const accessors, will cause assertion failure on type mismatch
2016-11-13 12:38:42 +02:00
bool Bool ( ) const ;
///float and integer allowed
double Float ( ) const ;
///only integer allowed
si64 Integer ( ) const ;
2012-07-16 19:18:02 +03:00
const std : : string & String ( ) const ;
const JsonVector & Vector ( ) const ;
const JsonMap & Struct ( ) const ;
2013-04-02 20:06:43 +03:00
/// returns resolved "json pointer" (string in format "/path/to/node")
const JsonNode & resolvePointer ( const std : : string & jsonPointer ) const ;
JsonNode & resolvePointer ( const std : : string & jsonPointer ) ;
2012-12-02 15:21:44 +03:00
/// convert json tree into specified type. Json tree must have same type as Type
/// Valid types: bool, string, any numeric, map and vector
/// example: convertTo< std::map< std::vector<int> > >();
template < typename Type >
Type convertTo ( ) const ;
2012-07-16 19:18:02 +03:00
//operator [], for structs only - get child node by name
2023-03-13 23:26:44 +02:00
JsonNode & operator [ ] ( const std : : string & child ) ;
const JsonNode & operator [ ] ( const std : : string & child ) const ;
2012-07-16 19:18:02 +03:00
2017-09-14 03:03:44 +02:00
std : : string toJson ( bool compact = false ) const ;
2017-08-11 15:27:42 +02:00
2012-11-13 14:52:23 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2013-04-25 17:03:35 +03:00
h & meta ;
2022-06-20 16:39:50 +02:00
h & flags ;
2014-06-05 23:51:24 +03:00
h & type ;
2017-10-29 17:23:30 +02:00
switch ( type )
2016-11-13 12:38:42 +02:00
{
2017-10-29 17:23:30 +02:00
case JsonType : : DATA_NULL :
break ;
case JsonType : : DATA_BOOL :
h & data . Bool ;
break ;
case JsonType : : DATA_FLOAT :
h & data . Float ;
break ;
case JsonType : : DATA_STRING :
h & data . String ;
break ;
case JsonType : : DATA_VECTOR :
h & data . Vector ;
break ;
case JsonType : : DATA_STRUCT :
h & data . Struct ;
break ;
case JsonType : : DATA_INTEGER :
2022-06-20 16:39:50 +02:00
h & data . Integer ;
2017-10-29 17:23:30 +02:00
break ;
2016-11-13 12:38:42 +02:00
}
2012-11-13 14:52:23 +03:00
}
2012-07-16 19:18:02 +03:00
} ;
2012-12-02 15:21:44 +03:00
namespace JsonUtils
2012-10-05 16:11:26 +03:00
{
2013-02-25 15:18:45 +03:00
/**
* @ brief parse short bonus format , excluding type
* @ note sets duration to Permament
2016-01-27 10:38:35 +02:00
*/
2023-03-13 23:26:44 +02:00
DLL_LINKAGE void parseTypedBonusShort ( const JsonVector & source , const std : : shared_ptr < Bonus > & dest ) ;
2016-01-27 10:38:35 +02:00
2013-02-25 15:18:45 +03:00
///
2023-03-13 23:26:44 +02:00
DLL_LINKAGE std : : shared_ptr < Bonus > parseBonus ( const JsonVector & ability_vec ) ;
DLL_LINKAGE std : : shared_ptr < Bonus > parseBonus ( const JsonNode & ability ) ;
DLL_LINKAGE std : : shared_ptr < Bonus > parseBuildingBonus ( const JsonNode & ability , const BuildingID & building , const std : : string & description ) ;
DLL_LINKAGE bool parseBonus ( const JsonNode & ability , Bonus * placement ) ;
2018-04-01 13:17:34 +02:00
DLL_LINKAGE std : : shared_ptr < ILimiter > parseLimiter ( const JsonNode & limiter ) ;
2023-03-09 01:18:30 +02:00
DLL_LINKAGE CSelector parseSelector ( const JsonNode & ability ) ;
2023-03-13 23:26:44 +02:00
DLL_LINKAGE void resolveIdentifier ( si32 & var , const JsonNode & node , const std : : string & name ) ;
DLL_LINKAGE void resolveIdentifier ( const JsonNode & node , si32 & var ) ;
2018-03-12 07:20:18 +02:00
DLL_LINKAGE void resolveAddInfo ( CAddInfo & var , const JsonNode & node ) ;
2012-12-02 15:21:44 +03:00
2013-02-25 15:18:45 +03:00
/**
2014-05-19 01:28:44 +03:00
* @ brief recursively merges source into dest , replacing identical fields
2013-02-25 15:18:45 +03:00
* 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
*/
2022-11-30 17:38:53 +02:00
DLL_LINKAGE void merge ( JsonNode & dest , JsonNode & source , bool ignoreOverride = false , bool copyMeta = false ) ;
2016-01-27 10:38:35 +02:00
2013-02-25 15:18:45 +03:00
/**
2014-05-19 01:28:44 +03:00
* @ brief recursively merges source into dest , replacing identical fields
2013-02-25 15:18:45 +03:00
* 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
2016-01-27 10:38:35 +02:00
*/
2022-11-30 17:38:53 +02:00
DLL_LINKAGE void mergeCopy ( JsonNode & dest , JsonNode source , bool ignoreOverride = false , bool copyMeta = false ) ;
2016-01-27 10:38:35 +02:00
2023-03-13 23:26:44 +02:00
/** @brief recursively merges descendant into copy of base node
* Result emulates inheritance semantic
*/
2014-05-19 01:28:44 +03:00
DLL_LINKAGE void inherit ( JsonNode & descendant , const JsonNode & base ) ;
2012-12-02 15:21:44 +03:00
2017-09-13 08:58:14 +02:00
/**
* @ 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 < JsonNode > & nodes , bool pruneEmpty = true ) ;
2017-09-13 10:27:01 +02:00
/**
* @ brief construct node representing the difference " node - base "
* merging difference with base gives node
*/
DLL_LINKAGE JsonNode difference ( const JsonNode & node , const JsonNode & base ) ;
2012-12-12 14:13:57 +03:00
/**
* @ brief generate one Json structure from multiple files
* @ param files - list of filenames with parts of json structure
*/
2023-03-13 23:26:44 +02:00
DLL_LINKAGE JsonNode assembleFromFiles ( const std : : vector < std : : string > & files ) ;
DLL_LINKAGE JsonNode assembleFromFiles ( const std : : vector < std : : string > & files , bool & isValid ) ;
2012-12-12 14:13:57 +03:00
2014-05-19 01:28:44 +03:00
/// This version loads all files with same name (overridden by mods)
2023-03-13 23:26:44 +02:00
DLL_LINKAGE JsonNode assembleFromFiles ( const std : : string & filename ) ;
2013-04-26 00:50:55 +03:00
2013-04-02 20:06:43 +03:00
/**
* @ 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
*/
2023-03-13 23:26:44 +02:00
DLL_LINKAGE void minimize ( JsonNode & node , const std : : string & schemaName ) ;
2013-04-02 20:06:43 +03:00
/// opposed to minimize, adds all missing, required entries that have default value
2023-03-13 23:26:44 +02:00
DLL_LINKAGE void maximize ( JsonNode & node , const std : : string & schemaName ) ;
2012-12-02 15:21:44 +03:00
2013-04-02 20:06:43 +03:00
/**
* @ 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
*/
2023-03-13 23:26:44 +02:00
DLL_LINKAGE bool validate ( const JsonNode & node , const std : : string & schemaName , const std : : string & dataName ) ;
2013-04-02 20:06:43 +03:00
/// get schema by json URI: vcmi:<name of file in schemas directory>#<entry in file, optional>
/// example: schema "vcmi:settings" is used to check user settings
2023-03-13 23:26:44 +02:00
DLL_LINKAGE const JsonNode & getSchema ( const std : : string & URI ) ;
2017-09-12 01:56:38 +02:00
/// for easy construction of JsonNodes; helps with inserting primitives into vector node
DLL_LINKAGE JsonNode boolNode ( bool value ) ;
DLL_LINKAGE JsonNode floatNode ( double value ) ;
2023-03-13 23:26:44 +02:00
DLL_LINKAGE JsonNode stringNode ( const std : : string & value ) ;
2017-09-12 01:56:38 +02:00
DLL_LINKAGE JsonNode intNode ( si64 value ) ;
2012-10-05 16:11:26 +03:00
}
2012-12-02 15:21:44 +03:00
namespace JsonDetail
2012-10-05 16:11:26 +03:00
{
2014-03-23 15:59:03 +03:00
// conversion helpers for JsonNode::convertTo (partial template function instantiation is illegal in c++)
2013-02-04 00:05:44 +03:00
2016-01-27 10:38:35 +02:00
template < typename T , int arithm >
2013-02-04 00:05:44 +03:00
struct JsonConvImpl ;
template < typename T >
2013-02-11 02:24:57 +03:00
struct JsonConvImpl < T , 1 >
2013-02-04 00:05:44 +03:00
{
static T convertImpl ( const JsonNode & node )
{
2013-02-11 02:24:57 +03:00
return T ( ( int ) node . Float ( ) ) ;
2013-02-04 00:05:44 +03:00
}
} ;
template < typename T >
2013-02-11 02:24:57 +03:00
struct JsonConvImpl < T , 0 >
2013-02-04 00:05:44 +03:00
{
static T convertImpl ( const JsonNode & node )
{
2020-10-01 10:38:06 +02:00
return T ( node . Float ( ) ) ;
2013-02-04 00:05:44 +03:00
}
} ;
2012-12-02 15:21:44 +03:00
template < typename Type >
struct JsonConverter
2012-10-05 16:11:26 +03:00
{
2012-12-02 15:21:44 +03:00
static Type convert ( const JsonNode & node )
{
2013-02-04 00:05:44 +03:00
///this should be triggered only for numeric types and enums
2013-02-11 02:24:57 +03:00
static_assert ( boost : : mpl : : or_ < std : : is_arithmetic < Type > , std : : is_enum < Type > , boost : : is_class < Type > > : : value , " Unsupported type for JsonNode::convertTo()! " ) ;
return JsonConvImpl < Type , boost : : mpl : : or_ < std : : is_enum < Type > , boost : : is_class < Type > > : : value > : : convertImpl ( node ) ;
2016-01-27 10:38:35 +02:00
2012-12-02 15:21:44 +03:00
}
} ;
2012-10-05 16:11:26 +03:00
2012-12-02 15:21:44 +03:00
template < typename Type >
struct JsonConverter < std : : map < std : : string , Type > >
{
static std : : map < std : : string , Type > convert ( const JsonNode & node )
{
std : : map < std : : string , Type > ret ;
2013-06-29 16:05:48 +03:00
for ( const JsonMap : : value_type & entry : node . Struct ( ) )
2012-12-02 15:21:44 +03:00
{
ret . insert ( entry . first , entry . second . convertTo < Type > ( ) ) ;
}
return ret ;
}
} ;
2012-07-16 19:18:02 +03:00
2013-01-10 21:53:49 +03:00
template < typename Type >
struct JsonConverter < std : : set < Type > >
{
static std : : set < Type > convert ( const JsonNode & node )
{
std : : set < Type > ret ;
2013-06-29 16:05:48 +03:00
for ( const JsonVector : : value_type & entry : node . Vector ( ) )
2013-01-10 21:53:49 +03:00
{
ret . insert ( entry . convertTo < Type > ( ) ) ;
}
return ret ;
}
} ;
2012-12-02 15:21:44 +03:00
template < typename Type >
struct JsonConverter < std : : vector < Type > >
2012-07-16 19:18:02 +03:00
{
2012-12-02 15:21:44 +03:00
static std : : vector < Type > convert ( const JsonNode & node )
{
std : : vector < Type > ret ;
2013-06-29 16:05:48 +03:00
for ( const JsonVector : : value_type & entry : node . Vector ( ) )
2012-12-02 15:21:44 +03:00
{
ret . push_back ( entry . convertTo < Type > ( ) ) ;
}
return ret ;
}
} ;
2012-07-16 19:18:02 +03:00
2012-12-02 15:21:44 +03:00
template < >
struct JsonConverter < std : : string >
2012-07-16 19:18:02 +03:00
{
2012-12-02 15:21:44 +03:00
static std : : string convert ( const JsonNode & node )
{
return node . String ( ) ;
}
2012-07-16 19:18:02 +03:00
} ;
2012-12-02 15:21:44 +03:00
template < >
struct JsonConverter < bool >
2012-07-16 19:18:02 +03:00
{
2012-12-02 15:21:44 +03:00
static bool convert ( const JsonNode & node )
{
return node . Bool ( ) ;
}
} ;
2017-07-20 06:08:49 +02:00
}
2012-12-02 15:21:44 +03:00
template < typename Type >
Type JsonNode : : convertTo ( ) const
{
return JsonDetail : : JsonConverter < Type > : : convert ( * this ) ;
2013-03-02 19:55:51 +03:00
}
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_END