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
class JsonNode ;
typedef std : : map < std : : string , JsonNode > JsonMap ;
typedef std : : vector < JsonNode > JsonVector ;
2012-07-19 21:52:44 +03:00
struct Bonus ;
2012-08-02 14:03:26 +03:00
class ResourceID ;
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 ) ;
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 ;
2013-04-25 17:03:35 +03:00
void setMeta ( std : : string metadata , bool recursive = true ) ;
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 ;
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
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
JsonNode & operator [ ] ( std : : string child ) ;
const JsonNode & operator [ ] ( std : : string child ) const ;
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 ;
2018-03-05 05:30:10 +02:00
if ( version > = 782 )
{
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 :
if ( version > = 770 )
{
2016-11-13 12:38:42 +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
*/
2016-09-19 23:36:35 +02:00
DLL_LINKAGE void parseTypedBonusShort ( const JsonVector & source , std : : shared_ptr < Bonus > dest ) ;
2016-01-27 10:38:35 +02:00
2013-02-25 15:18:45 +03:00
///
2016-10-22 10:00:55 +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 bool parseBonus ( const JsonNode & ability , Bonus * placement ) ;
2016-09-19 23:36:35 +02:00
DLL_LINKAGE void unparseBonus ( JsonNode & node , const std : : shared_ptr < Bonus > & bonus ) ;
2016-10-22 10:00:55 +02:00
DLL_LINKAGE void resolveIdentifier ( si32 & var , const JsonNode & node , std : : string name ) ;
DLL_LINKAGE void resolveIdentifier ( const JsonNode & node , si32 & var ) ;
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
*/
2018-03-05 05:30:10 +02:00
DLL_LINKAGE void merge ( JsonNode & dest , JsonNode & source , bool noOverride = 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
*/
2018-03-05 05:30:10 +02:00
DLL_LINKAGE void mergeCopy ( JsonNode & dest , JsonNode source , bool noOverride = false ) ;
2016-01-27 10:38:35 +02:00
2014-05-19 01:28:44 +03:00
/** @brief recursively merges descendant into copy of base node
* Result emulates inheritance semantic
2016-01-27 10:38:35 +02:00
*
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
*/
DLL_LINKAGE JsonNode assembleFromFiles ( std : : vector < std : : string > files ) ;
2013-11-08 23:36:26 +03:00
DLL_LINKAGE JsonNode assembleFromFiles ( 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)
2013-04-26 00:50:55 +03:00
DLL_LINKAGE JsonNode assembleFromFiles ( std : : string filename ) ;
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
*/
DLL_LINKAGE void minimize ( JsonNode & node , std : : string schemaName ) ;
/// opposed to minimize, adds all missing, required entries that have default value
DLL_LINKAGE void maximize ( JsonNode & node , 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
*/
DLL_LINKAGE bool validate ( const JsonNode & node , std : : string schemaName , std : : string dataName ) ;
/// 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
DLL_LINKAGE const JsonNode & getSchema ( 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 ) ;
DLL_LINKAGE JsonNode stringNode ( std : : string value ) ;
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 )
{
return node . Float ( ) ;
}
} ;
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
}