diff options
author | davilla <davilla@svn> | 2010-02-13 17:53:47 +0000 |
---|---|---|
committer | davilla <davilla@svn> | 2010-02-13 17:53:47 +0000 |
commit | 9ac3aa97a6d139116f0c2ec2d2ae12e35a64d611 (patch) | |
tree | c3e6db1c2d126335adefe560fd15740b7ab78031 | |
parent | 216555f7400cbd9190799b750a512707782d637a (diff) |
commit jsoncpp-r91 into trunk
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@27729 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
165 files changed, 10391 insertions, 0 deletions
diff --git a/lib/jsoncpp/jsoncpp/AUTHORS b/lib/jsoncpp/jsoncpp/AUTHORS new file mode 100644 index 0000000000..c0fbbeec11 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/AUTHORS @@ -0,0 +1 @@ +Baptiste Lepilleur <blep@users.sourceforge.net> diff --git a/lib/jsoncpp/jsoncpp/README.txt b/lib/jsoncpp/jsoncpp/README.txt new file mode 100644 index 0000000000..c1b2c73383 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/README.txt @@ -0,0 +1,53 @@ +* Introduction: + +JSON (JavaScript Object Notation) is a lightweight data-interchange format. +It can represent integer, real number, string, an ordered sequence of +value, and a collection of name/value pairs. + +JsonCpp is a simple API to manipulate JSON value, and handle serialization +and unserialization to string. + +It can also preserve existing comment in unserialization/serialization steps, +making it a convenient format to store user input files. + +Unserialization parsing is user friendly and provides precise error reports. + +* Building/Testing: + +JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires +python to be installed (http://www.python.org). + +You download scons-local distribution from the following url: +http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375 + +Unzip it in the directory where you found this README file. scons.py Should be +at the same level as README. + +python scons.py platform=PLTFRM [TARGET] +where PLTFRM may be one of: + suncc Sun C++ (Solaris) + vacpp Visual Age C++ (AIX) + mingw + msvc6 Microsoft Visual Studio 6 service pack 5-6 + msvc70 Microsoft Visual Studio 2002 + msvc71 Microsoft Visual Studio 2003 + msvc80 Microsoft Visual Studio 2005 + linux-gcc Gnu C++ (linux, also reported to work for Mac OS X) + +adding platform is fairly simple. You need to change the Sconstruct file +to do so. + +and TARGET may be: + check: build library and run unit tests. + doc: build documentation + doc-dist: build documentation tarball + +To run the test manually: +cd test +# This will run the Reader/Writer tests +python runjsontests.py "path to jsontest.exe" +# This will run the unit tests (mostly Value) +python rununittests.py "path to test_lib_json.exe" + +You can run the tests using valgrind using: +python rununittests.py --valgrind "path to test_lib_json.exe" diff --git a/lib/jsoncpp/jsoncpp/SConstruct b/lib/jsoncpp/jsoncpp/SConstruct new file mode 100644 index 0000000000..00d37411bd --- /dev/null +++ b/lib/jsoncpp/jsoncpp/SConstruct @@ -0,0 +1,300 @@ +""" +Build system can be clean-up by sticking to a few core production factory, with automatic dependencies resolution. +4 basic project productions: +- library +- binary +- documentation +- tests + +* Library: + Input: + - dependencies (other libraries) + - headers: include path & files + - sources + - generated sources + - resources + - generated resources + Production: + - Static library + - Dynamic library + - Naming rule + Life-cycle: + - Library compilation + - Compilation as a dependencies + - Run-time + - Packaging + Identity: + - Name + - Version +* Binary: + Input: + - dependencies (other libraries) + - headers: include path & files (usually empty) + - sources + - generated sources + - resources + - generated resources + - supported variant (optimized/debug, dll/static...) + Production: + - Binary executable + - Manifest [on some platforms] + - Debug symbol [on some platforms] + Life-cycle: + - Compilation + - Run-time + - Packaging + Identity: + - Name + - Version +* Documentation: + Input: + - dependencies (libraries, binaries) + - additional sources + - generated sources + - resources + - generated resources + - supported variant (public/internal) + Production: + - HTML documentation + - PDF documentation + - CHM documentation + Life-cycle: + - Documentation + - Packaging + - Test + Identity: + - Name + - Version +""" + + + +import os +import os.path +import sys + +JSONCPP_VERSION = '0.2' +DIST_DIR = '#dist' + +options = Variables() +options.Add( EnumVariable('platform', + 'Platform (compiler/stl) used to build the project', + 'msvc71', + allowed_values='suncc vacpp mingw msvc6 msvc7 msvc71 msvc80 linux-gcc'.split(), + ignorecase=2) ) + +try: + platform = ARGUMENTS['platform'] + if platform == 'linux-gcc': + CXX = 'g++' # not quite right, but env is not yet available. + import commands + version = commands.getoutput('%s -dumpversion' %CXX) + platform = 'linux-gcc-%s' %version + print "Using platform '%s'" %platform + LD_LIBRARY_PATH = os.environ.get('LD_LIBRARY_PATH', '') + LD_LIBRARY_PATH = "%s:libs/%s" %(LD_LIBRARY_PATH, platform) + os.environ['LD_LIBRARY_PATH'] = LD_LIBRARY_PATH + print "LD_LIBRARY_PATH =", LD_LIBRARY_PATH +except KeyError: + print 'You must specify a "platform"' + sys.exit(2) + +print "Building using PLATFORM =", platform + +rootbuild_dir = Dir('#buildscons') +build_dir = os.path.join( '#buildscons', platform ) +bin_dir = os.path.join( '#bin', platform ) +lib_dir = os.path.join( '#libs', platform ) +sconsign_dir_path = Dir(build_dir).abspath +sconsign_path = os.path.join( sconsign_dir_path, '.sconsign.dbm' ) + +# Ensure build directory exist (SConsignFile fail otherwise!) +if not os.path.exists( sconsign_dir_path ): + os.makedirs( sconsign_dir_path ) + +# Store all dependencies signature in a database +SConsignFile( sconsign_path ) + +def make_environ_vars(): + """Returns a dictionnary with environment variable to use when compiling.""" + # PATH is required to find the compiler + # TEMP is required for at least mingw + vars = {} + for name in ('PATH', 'TEMP', 'TMP'): + if name in os.environ: + vars[name] = os.environ[name] + return vars + + +env = Environment( ENV = make_environ_vars(), + toolpath = ['scons-tools'], + tools=[] ) #, tools=['default'] ) + +if platform == 'suncc': + env.Tool( 'sunc++' ) + env.Tool( 'sunlink' ) + env.Tool( 'sunar' ) + env.Append( CCFLAGS = ['-mt'] ) +elif platform == 'vacpp': + env.Tool( 'default' ) + env.Tool( 'aixcc' ) + env['CXX'] = 'xlC_r' #scons does not pick-up the correct one ! + # using xlC_r ensure multi-threading is enabled: + # http://publib.boulder.ibm.com/infocenter/pseries/index.jsp?topic=/com.ibm.vacpp7a.doc/compiler/ref/cuselect.htm + env.Append( CCFLAGS = '-qrtti=all', + LINKFLAGS='-bh:5' ) # -bh:5 remove duplicate symbol warning +elif platform == 'msvc6': + env['MSVS_VERSION']='6.0' + for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: + env.Tool( tool ) + env['CXXFLAGS']='-GR -GX /nologo /MT' +elif platform == 'msvc70': + env['MSVS_VERSION']='7.0' + for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: + env.Tool( tool ) + env['CXXFLAGS']='-GR -GX /nologo /MT' +elif platform == 'msvc71': + env['MSVS_VERSION']='7.1' + for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: + env.Tool( tool ) + env['CXXFLAGS']='-GR -GX /nologo /MT' +elif platform == 'msvc80': + env['MSVS_VERSION']='8.0' + for tool in ['msvc', 'msvs', 'mslink', 'masm', 'mslib']: + env.Tool( tool ) + env['CXXFLAGS']='-GR -EHsc /nologo /MT' +elif platform == 'mingw': + env.Tool( 'mingw' ) + env.Append( CPPDEFINES=[ "WIN32", "NDEBUG", "_MT" ] ) +elif platform.startswith('linux-gcc'): + env.Tool( 'default' ) + env.Append( LIBS = ['pthread'], CCFLAGS = "-Wall" ) + env['SHARED_LIB_ENABLED'] = True +else: + print "UNSUPPORTED PLATFORM." + env.Exit(1) + +env.Tool('doxygen') +env.Tool('substinfile') +env.Tool('targz') +env.Tool('srcdist') +env.Tool('globtool') + +env.Append( CPPPATH = ['#include'], + LIBPATH = lib_dir ) +short_platform = platform +if short_platform.startswith('msvc'): + short_platform = short_platform[2:] +# Notes: on Windows you need to rebuild the source for each variant +# Build script does not support that yet so we only build static libraries. +# This also fails on AIX because both dynamic and static library ends with +# extension .a. +env['SHARED_LIB_ENABLED'] = env.get('SHARED_LIB_ENABLED', False) +env['LIB_PLATFORM'] = short_platform +env['LIB_LINK_TYPE'] = 'lib' # static +env['LIB_CRUNTIME'] = 'mt' +env['LIB_NAME_SUFFIX'] = '${LIB_PLATFORM}_${LIB_LINK_TYPE}${LIB_CRUNTIME}' # must match autolink naming convention +env['JSONCPP_VERSION'] = JSONCPP_VERSION +env['BUILD_DIR'] = env.Dir(build_dir) +env['ROOTBUILD_DIR'] = env.Dir(rootbuild_dir) +env['DIST_DIR'] = DIST_DIR +if 'TarGz' in env['BUILDERS']: + class SrcDistAdder: + def __init__( self, env ): + self.env = env + def __call__( self, *args, **kw ): + apply( self.env.SrcDist, (self.env['SRCDIST_TARGET'],) + args, kw ) + env['SRCDIST_BUILDER'] = env.TarGz +else: # If tarfile module is missing + class SrcDistAdder: + def __init__( self, env ): + pass + def __call__( self, *args, **kw ): + pass +env['SRCDIST_ADD'] = SrcDistAdder( env ) +env['SRCDIST_TARGET'] = os.path.join( DIST_DIR, 'jsoncpp-src-%s.tar.gz' % env['JSONCPP_VERSION'] ) + +env_testing = env.Clone( ) +env_testing.Append( LIBS = ['json_${LIB_NAME_SUFFIX}'] ) + +def buildJSONExample( env, target_sources, target_name ): + env = env.Clone() + env.Append( CPPPATH = ['#'] ) + exe = env.Program( target=target_name, + source=target_sources ) + env['SRCDIST_ADD']( source=[target_sources] ) + global bin_dir + return env.Install( bin_dir, exe ) + +def buildJSONTests( env, target_sources, target_name ): + jsontests_node = buildJSONExample( env, target_sources, target_name ) + check_alias_target = env.Alias( 'check', jsontests_node, RunJSONTests( jsontests_node, jsontests_node ) ) + env.AlwaysBuild( check_alias_target ) + +def buildUnitTests( env, target_sources, target_name ): + jsontests_node = buildJSONExample( env, target_sources, target_name ) + check_alias_target = env.Alias( 'check', jsontests_node, + RunUnitTests( jsontests_node, jsontests_node ) ) + env.AlwaysBuild( check_alias_target ) + +def buildLibrary( env, target_sources, target_name ): + static_lib = env.StaticLibrary( target=target_name + '_${LIB_NAME_SUFFIX}', + source=target_sources ) + global lib_dir + env.Install( lib_dir, static_lib ) + if env['SHARED_LIB_ENABLED']: + shared_lib = env.SharedLibrary( target=target_name + '_${LIB_NAME_SUFFIX}', + source=target_sources ) + env.Install( lib_dir, shared_lib ) + env['SRCDIST_ADD']( source=[target_sources] ) + +Export( 'env env_testing buildJSONExample buildLibrary buildJSONTests buildUnitTests' ) + +def buildProjectInDirectory( target_directory ): + global build_dir + target_build_dir = os.path.join( build_dir, target_directory ) + target = os.path.join( target_directory, 'sconscript' ) + SConscript( target, build_dir=target_build_dir, duplicate=0 ) + env['SRCDIST_ADD']( source=[target] ) + + +def runJSONTests_action( target, source = None, env = None ): + # Add test scripts to python path + jsontest_path = Dir( '#test' ).abspath + sys.path.insert( 0, jsontest_path ) + data_path = os.path.join( jsontest_path, 'data' ) + import runjsontests + return runjsontests.runAllTests( os.path.abspath(source[0].path), data_path ) + +def runJSONTests_string( target, source = None, env = None ): + return 'RunJSONTests("%s")' % source[0] + +import SCons.Action +ActionFactory = SCons.Action.ActionFactory +RunJSONTests = ActionFactory(runJSONTests_action, runJSONTests_string ) + +def runUnitTests_action( target, source = None, env = None ): + # Add test scripts to python path + jsontest_path = Dir( '#test' ).abspath + sys.path.insert( 0, jsontest_path ) + import rununittests + return rununittests.runAllTests( os.path.abspath(source[0].path) ) + +def runUnitTests_string( target, source = None, env = None ): + return 'RunUnitTests("%s")' % source[0] + +RunUnitTests = ActionFactory(runUnitTests_action, runUnitTests_string ) + +env.Alias( 'check' ) + +srcdist_cmd = env['SRCDIST_ADD']( source = """ + AUTHORS README.txt SConstruct + """.split() ) +env.Alias( 'src-dist', srcdist_cmd ) + +buildProjectInDirectory( 'src/jsontestrunner' ) +buildProjectInDirectory( 'src/lib_json' ) +buildProjectInDirectory( 'src/test_lib_json' ) +buildProjectInDirectory( 'doc' ) +#print env.Dump() + diff --git a/lib/jsoncpp/jsoncpp/doc/doxyfile.in b/lib/jsoncpp/jsoncpp/doc/doxyfile.in new file mode 100644 index 0000000000..f19f037705 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/doc/doxyfile.in @@ -0,0 +1,232 @@ +# Doxyfile 1.4.3 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "JsonCpp" +PROJECT_NUMBER = %JSONCPP_VERSION% +OUTPUT_DIRECTORY = %DOC_TOPDIR% +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = %TOPDIR% +STRIP_FROM_INC_PATH = %TOPDIR%/include +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 3 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = jsoncpp-doxygen-warning.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../include ../src/lib_json . +FILE_PATTERNS = *.h *.cpp *.dox +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = json-html-doc-%JSONCPP_VERSION% +HTML_FILE_EXTENSION = .html +HTML_HEADER = header.html +HTML_FOOTER = footer.html +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = jsoncpp.chm +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = ../include +INCLUDE_FILE_PATTERNS = *.h +PREDEFINED = JSONCPP_DOC_EXCLUDE_IMPLEMENTATION JSON_VALUE_USE_INTERNAL_MAP +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/lib/jsoncpp/jsoncpp/doc/footer.html b/lib/jsoncpp/jsoncpp/doc/footer.html new file mode 100644 index 0000000000..a61d9528a1 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/doc/footer.html @@ -0,0 +1,23 @@ +<hr> +<table width="100%"> + <tr> + <td width="10%" align="left" valign="center"> + <a href="http://sourceforge.net"> + <img + src="http://sourceforge.net/sflogo.php?group_id=144446" + width="88" height="31" border="0" alt="SourceForge Logo"></a> + </td> + <td width="20%" align="left" valign="center"> + hosts this site. + </td> + <td> + </td> + <td align="right" valign="center"> + Send comments to:<br> + <a href="mailto:jsoncpp-devel@lists.sourceforge.net">Json-cpp Developers</a> + </td> + </tr> +</table> + +</body> +</html> diff --git a/lib/jsoncpp/jsoncpp/doc/header.html b/lib/jsoncpp/jsoncpp/doc/header.html new file mode 100644 index 0000000000..d56ea59c69 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/doc/header.html @@ -0,0 +1,24 @@ +<html> +<head> +<title> +JsonCpp - JSON data format manipulation library +</title> +<link href="doxygen.css" rel="stylesheet" type="text/css"> +<link href="tabs.css" rel="stylesheet" type="text/css"> +</head> + +<body bgcolor="#ffffff"> +<table width="100%"> + <tr> + <td width="40%" align="left" valign="center"> + <a href="http://sourceforge.net/projects/jsoncpp"> + JsonCpp project page + </a> + </td> + <td width="40%" align="right" valign="center"> + <a href="http://jsoncpp.sourceforge.net">JsonCpp home page</a> + </td> + </tr> +</table> + +<hr> diff --git a/lib/jsoncpp/jsoncpp/doc/jsoncpp.dox b/lib/jsoncpp/jsoncpp/doc/jsoncpp.dox new file mode 100644 index 0000000000..fc7b530eba --- /dev/null +++ b/lib/jsoncpp/jsoncpp/doc/jsoncpp.dox @@ -0,0 +1,97 @@ +/** +\mainpage +\section _intro Introduction + +<a HREF="http://www.json.org/">JSON (JavaScript Object Notation)</a> + is a lightweight data-interchange format. +It can represents integer, real number, string, an ordered sequence of value, and +a collection of name/value pairs. + +Here is an example of JSON data: +\verbatim +// Configuration options +{ + // Default encoding for text + "encoding" : "UTF-8", + + // Plug-ins loaded at start-up + "plug-ins" : [ + "python", + "c++", + "ruby" + ], + + // Tab indent size + "indent" : { "length" : 3, "use_space" = true } +} +\endverbatim + +\section _features Features +- read and write JSON document +- rewrite JSON document preserving original comments + +\code +Json::Value root; // will contains the root value after parsing. +Json::Reader reader; +bool parsingSuccessful = reader.parse( config_doc, root ); +if ( !parsingSuccessful ) +{ + // report to the user the failure and their locations in the document. + std::cout << "Failed to parse configuration\n" + << reader.getFormatedErrorMessages(); + return; +} + +// Get the value of the member of root named 'encoding', return 'UTF-8' if there is no +// such member. +std::string encoding = root.get("encoding", "UTF-8" ).asString(); +// Get the value of the member of root named 'encoding', return a 'null' value if +// there is no such member. +const Json::Value plugins = root["plug-ins"]; +for ( int index = 0; index < plugins.size(); ++index ) // Iterates over the sequence elements. + loadPlugIn( plugins[index].asString() ); + +setIndentLength( root["indent"].get("length", 3).asInt() ); +setIndentUseSpace( root["indent"].get("use_space", true).asBool() ); + +// ... +// At application shutdown to make the new configuration document: +// Since Json::Value has implicit constructor for all value types, it is not +// necessary to explicitely construct the Json::Value object: +root["encoding"] = getCurrentEncoding(); +root["indent"]["length"] = getCurrentIndentLength(); +root["indent"]["use_space"] = getCurrentIndentUseSpace(); + +Json::StyledWriter writer; +// Make a new JSON document for the configuration. Preserve original comments. +std::string outputConfig = writer.write( root ); + +// You can also use streams. This will put the contents of any JSON +// stream at a particular sub-value, if you'd like. +std::cin >> root["subtree"]; + +// And you can write to a stream, using the StyledWriter automatically. +std::cout << root; +\endcode + +\section _plinks Build instructions +The build instruction are located in the file +<a HREF="README.txt">README.txt</a> in the top-directory of the project. + +Permanent link to the lastest revision of the file in subversion: +<a HREF="http://svn.sourceforge.net/viewcvs.cgi/jsoncpp/README.txt?view=markup">lastest README.txt</a> + +\section _plinks Project links +- <a HREF="http://jsoncpp.sourceforge.net">json-cpp home</a> +- <a HREF="http://www.sourceforge.net/projects/jsoncpp">json-cpp sourceforge project</a> + +\section _rlinks Related links +- <a HREF="http://www.json.org/">JSON</a> Specification and alternate language implementations. +- <a HREF="http://www.yaml.org/">YAML</a> A data format designed for human readability. +- <a HREF="http://www.cl.cam.ac.uk/~mgk25/unicode.html">UTF-8 and Unicode FAQ</a>. + +\section _license License +The json-cpp library and this documentation are in Public Domain. + +\author Baptiste Lepilleur <blep@users.sourceforge.net> +*/ diff --git a/lib/jsoncpp/jsoncpp/doc/readme.txt b/lib/jsoncpp/jsoncpp/doc/readme.txt new file mode 100644 index 0000000000..0e42cdfb4c --- /dev/null +++ b/lib/jsoncpp/jsoncpp/doc/readme.txt @@ -0,0 +1 @@ +The documentation is generated using doxygen (http://www.doxygen.org). diff --git a/lib/jsoncpp/jsoncpp/doc/roadmap.dox b/lib/jsoncpp/jsoncpp/doc/roadmap.dox new file mode 100644 index 0000000000..84648b9eed --- /dev/null +++ b/lib/jsoncpp/jsoncpp/doc/roadmap.dox @@ -0,0 +1,35 @@ +/*! \page roadmap JsonCpp roadmap + \section ms_release Makes JsonCpp ready for release + - Build system clean-up: + - Fix build on Windows (shared-library build is broken) + - Fix doxygen build issue (discard doxygen dependency check, always rebuild) + - Add enable/disable flag for static and shared library build + - Enhance help + - Test with recent Scons checkpoint + - Platform portability check: + - linux/gcc, + - solaris/cc, + - windows/msvc678, + - aix/vacpp + - Add JsonCpp version to header as numeric for use in preprocessor test + - Remove buggy experimental hash stuff + - Release on sourceforge download + \section ms_unicode Clean-up unicode handling + - Ensure reader properly convert \u and \U unicode sequence to UTF8 + - Ensure writer emit only UTF8 string. + - Provides hook to convert string to/from utf8/other encoding. + - look into iconv, icu and windows API + \section ms_strict Adds a strict mode to reader/parser + Strict JSON support as specific in RFC 4627 (http://www.ietf.org/rfc/rfc4627.txt?number=4627). + - Enforce only object or array as root element + - Disable comment support + \section ms_separation Expose json reader/writer API that do not impose using Json::Value. + Some typical use-case involve an application specific structure to/from a JSON document. + - Performance oriented parser/writer: + - Provides an event based parser. Should allow pulling & skipping events for ease of use. + - Provides a JSON document builder: fast only. + \section ms_perfo Performance tuning + - Provides support for static property name definition avoiding allocation + - Static property dictionnary can be provided to JSON reader + - Performance scenario & benchmarking +*/ diff --git a/lib/jsoncpp/jsoncpp/doc/sconscript b/lib/jsoncpp/jsoncpp/doc/sconscript new file mode 100644 index 0000000000..7b78a21d80 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/doc/sconscript @@ -0,0 +1,61 @@ +Import( 'env' ) +import os.path + +if 'doxygen' in env['TOOLS']: + doc_topdir = str(env['ROOTBUILD_DIR']) + html_dir = 'jsoncpp-api-doc' + + doxygen_inputs = env.Glob( includes = '*.dox', dir = '#doc' ) \ + + env.Glob( includes = '*.h', dir = '#include/json/' ) \ + + env.Glob( includes = ('*.dox','*.h','*.inl','*.cpp'), + dir = '#src/lib_json' ) +## for p in doxygen_inputs: +## print p.abspath + + top_dir = env.Dir('#').abspath + include_top_dir = env.Dir('#include').abspath + env['DOXYFILE_DICT'] = { 'PROJECT_NAME': 'JsonCpp', + 'PROJECT_NUMBER': env['JSONCPP_VERSION'], + 'STRIP_FROM_PATH': top_dir, + 'STRIP_FROM_INC_PATH': include_top_dir, + 'HTML_OUTPUT': html_dir, + 'HTML_HEADER': env.File('#doc/header.html').abspath, + 'HTML_FOOTER': env.File('#doc/footer.html').abspath, + 'INCLUDE_PATH': include_top_dir, + 'PREDEFINED': 'JSONCPP_DOC_EXCLUDE_IMPLEMENTATION JSON_VALUE_USE_INTERNAL_MAP' + } + env['DOXYFILE_FILE'] = 'doxyfile.in' + doxfile_nodes = env.Doxyfile( os.path.join( doc_topdir, 'doxyfile' ), doxygen_inputs ) + html_doc_path = os.path.join( doc_topdir, html_dir ) + doc_nodes = env.Doxygen( source = doxfile_nodes, + target = os.path.join( html_doc_path, 'index.html' ) ) + alias_doc_cmd = env.Alias('doc', doc_nodes ) + env.Alias('doc', env.Install( html_doc_path, '#README.txt' ) ) + if 'TarGz' in env['BUILDERS']: + targz_path = os.path.join( env['DIST_DIR'], '%s.tar.gz' % html_dir ) + zip_doc_cmd = env.TarGz( targz_path, [env.Dir(html_doc_path)], + TARGZ_BASEDIR = env['ROOTBUILD_DIR'] ) + env.Depends( zip_doc_cmd, alias_doc_cmd ) + env.Alias( 'doc-dist', zip_doc_cmd ) +## +## doxyfile = env.SubstInFile( '#doc/doxyfile', 'doxyfile.in', +## SUBST_DICT = { +## '%JSONCPP_VERSION%' : env['JSONCPP_VERSION'], +## '%TOPDIR%' : env.Dir('#').abspath, +## '%DOC_TOPDIR%' : str(doc_topdir) } ) +## doc_cmd = env.Doxygen( doxyfile ) +## alias_doc_cmd = env.Alias('doc', doc_cmd ) +## env.AlwaysBuild(alias_doc_cmd) +## +## for dir in doc_cmd: +## env.Alias('doc', env.Install( '#' + dir.path, '#README.txt' ) ) +## filename = os.path.split(dir.path)[1] +## targz_path = os.path.join( env['DIST_DIR'], '%s.tar.gz' % filename ) +## zip_doc_cmd = env.TarGz( targz_path, [env.Dir(dir)], +## TARGZ_BASEDIR = doc_topdir ) +## env.Depends( zip_doc_cmd, alias_doc_cmd ) +## env.Alias( 'doc-dist', zip_doc_cmd ) +## +## # When doxyfile gets updated, I get errors on the first pass. +## # I have to run scons twice. Something is wrong with the dependencies +## # here, but I avoid it by running "scons doc/doxyfile" first. diff --git a/lib/jsoncpp/jsoncpp/include/json/autolink.h b/lib/jsoncpp/jsoncpp/include/json/autolink.h new file mode 100644 index 0000000000..37c9258ed5 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/autolink.h @@ -0,0 +1,19 @@ +#ifndef JSON_AUTOLINK_H_INCLUDED +# define JSON_AUTOLINK_H_INCLUDED + +# include "config.h" + +# ifdef JSON_IN_CPPTL +# include <cpptl/cpptl_autolink.h> +# endif + +# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) +# define CPPTL_AUTOLINK_NAME "json" +# undef CPPTL_AUTOLINK_DLL +# ifdef JSON_DLL +# define CPPTL_AUTOLINK_DLL +# endif +# include "autolink.h" +# endif + +#endif // JSON_AUTOLINK_H_INCLUDED diff --git a/lib/jsoncpp/jsoncpp/include/json/config.h b/lib/jsoncpp/jsoncpp/include/json/config.h new file mode 100644 index 0000000000..5d334cbc5e --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/config.h @@ -0,0 +1,43 @@ +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +# ifdef JSON_IN_CPPTL +# include <cpptl/config.h> +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/lib/jsoncpp/jsoncpp/include/json/features.h b/lib/jsoncpp/jsoncpp/include/json/features.h new file mode 100644 index 0000000000..f1404f6204 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/features.h @@ -0,0 +1,42 @@ +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+# define CPPTL_JSON_FEATURES_H_INCLUDED
+
+# include "forwards.h"
+
+namespace Json {
+
+ /** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+ class JSON_API Features
+ {
+ public:
+ /** \brief A configuration that allows all features and assumes all strings are UTF-8.
+ * - C & C++ comments are allowed
+ * - Root object can be any JSON value
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features all();
+
+ /** \brief A configuration that is strictly compatible with the JSON specification.
+ * - Comments are forbidden.
+ * - Root object must be either an array or an object value.
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features strictMode();
+
+ /** \brief Initialize the configuration like JsonConfig::allFeatures;
+ */
+ Features();
+
+ /// \c true if comments are allowed. Default: \c true.
+ bool allowComments_;
+
+ /// \c true if root must be either an array or an object value. Default: \c false.
+ bool strictRoot_;
+ };
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
diff --git a/lib/jsoncpp/jsoncpp/include/json/forwards.h b/lib/jsoncpp/jsoncpp/include/json/forwards.h new file mode 100644 index 0000000000..ee76071c12 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/forwards.h @@ -0,0 +1,34 @@ +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +# include "config.h" + +namespace Json { + + class FastWriter; + class Reader; + class StyledWriter; + + // features.h + class Features; + + // value.h + class StaticString; + class Path; + class PathArgument; + class Value; + class ValueIteratorBase; + class ValueIterator; + class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + class ValueAllocator; + class ValueMapAllocator; + class ValueInternalLink; + class ValueInternalArray; + class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/lib/jsoncpp/jsoncpp/include/json/json.h b/lib/jsoncpp/jsoncpp/include/json/json.h new file mode 100644 index 0000000000..c71ed65abf --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/json.h @@ -0,0 +1,10 @@ +#ifndef JSON_JSON_H_INCLUDED +# define JSON_JSON_H_INCLUDED + +# include "autolink.h" +# include "value.h" +# include "reader.h" +# include "writer.h" +# include "features.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/lib/jsoncpp/jsoncpp/include/json/reader.h b/lib/jsoncpp/jsoncpp/include/json/reader.h new file mode 100644 index 0000000000..ee1d6a2444 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/reader.h @@ -0,0 +1,196 @@ +#ifndef CPPTL_JSON_READER_H_INCLUDED +# define CPPTL_JSON_READER_H_INCLUDED + +# include "features.h" +# include "value.h" +# include <deque> +# include <stack> +# include <string> +# include <iostream> + +namespace Json { + + /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value. + * + */ + class JSON_API Reader + { + public: + typedef char Char; + typedef const Char *Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader( const Features &features ); + + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const std::string &document, + Value &root, + bool collectComments = true ); + + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments = true ); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse( std::istream &is, + Value &root, + bool collectComments = true ); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormatedErrorMessages() const; + + private: + enum TokenType + { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque<ErrorInfo> Errors; + + bool expectToken( TokenType type, Token &token, const char *message ); + bool readToken( Token &token ); + void skipSpaces(); + bool match( Location pattern, + int patternLength ); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject( Token &token ); + bool readArray( Token &token ); + bool decodeNumber( Token &token ); + bool decodeString( Token &token ); + bool decodeString( Token &token, std::string &decoded ); + bool decodeDouble( Token &token ); + bool decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool addError( const std::string &message, + Token &token, + Location extra = 0 ); + bool recoverFromError( TokenType skipUntilToken ); + bool addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ); + void skipUntilSpace(); + Value ¤tValue(); + Char getNextChar(); + void getLocationLineAndColumn( Location location, + int &line, + int &column ) const; + std::string getLocationLineAndColumn( Location location ) const; + void addComment( Location begin, + Location end, + CommentPlacement placement ); + void skipCommentTokens( Token &token ); + + typedef std::stack<Value *> Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value *lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; + }; + + /** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() + */ + std::istream& operator>>( std::istream&, Value& ); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/lib/jsoncpp/jsoncpp/include/json/value.h b/lib/jsoncpp/jsoncpp/include/json/value.h new file mode 100644 index 0000000000..ce3d3cd0e9 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/value.h @@ -0,0 +1,1068 @@ +#ifndef CPPTL_JSON_H_INCLUDED +# define CPPTL_JSON_H_INCLUDED + +# include "forwards.h" +# include <string> +# include <vector> + +# ifndef JSON_USE_CPPTL_SMALLMAP +# include <map> +# else +# include <cpptl/smallmap.h> +# endif +# ifdef JSON_USE_CPPTL +# include <cpptl/forwards.h> +# endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + + /** \brief Type of the value held by a Value object. + */ + enum ValueType + { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). + }; + + enum CommentPlacement + { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement + }; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames; +// typedef CppTL::AnyEnumerator<const Value &> EnumValues; +//# endif + + /** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + class JSON_API StaticString + { + public: + explicit StaticString( const char *czstring ) + : str_( czstring ) + { + } + + operator const char *() const + { + return str_; + } + + const char *c_str() const + { + return str_; + } + + private: + const char *str_; + }; + + /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ + class JSON_API Value + { + friend class ValueIteratorBase; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +# endif + public: + typedef std::vector<std::string> Members; + typedef int Int; + typedef unsigned int UInt; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef UInt ArrayIndex; + + static const Value null; + static const Int minInt; + static const Int maxInt; + static const UInt maxUInt; + + private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +# ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy + { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString( int index ); + CZString( const char *cstr, DuplicationPolicy allocate ); + CZString( const CZString &other ); + ~CZString(); + CZString &operator =( const CZString &other ); + bool operator<( const CZString &other ) const; + bool operator==( const CZString &other ) const; + int index() const; + const char *c_str() const; + bool isStaticString() const; + private: + void swap( CZString &other ); + const char *cstr_; + int index_; + }; + + public: +# ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map<CZString, Value> ObjectValues; +# else + typedef CppTL::SmallMap<CZString, Value> ObjectValues; +# endif // ifndef JSON_USE_CPPTL_SMALLMAP +# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value( ValueType type = nullValue ); + Value( Int value ); + Value( UInt value ); + Value( double value ); + Value( const char *value ); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value( const StaticString &value ); + Value( const std::string &value ); +# ifdef JSON_USE_CPPTL + Value( const CppTL::ConstString &value ); +# endif + Value( bool value ); + Value( const Value &other ); + ~Value(); + + Value &operator=( const Value &other ); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap( Value &other ); + + ValueType type() const; + + bool operator <( const Value &other ) const; + bool operator <=( const Value &other ) const; + bool operator >=( const Value &other ) const; + bool operator >( const Value &other ) const; + + bool operator ==( const Value &other ) const; + bool operator !=( const Value &other ) const; + + int compare( const Value &other ); + + const char *asCString() const; + std::string asString() const; +# ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +# endif + Int asInt() const; + UInt asUInt() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isUInt() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo( ValueType other ) const; + + /// Number of values in array or object + UInt size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize( UInt size ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( UInt index ); + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( UInt index ) const; + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get( UInt index, + const Value &defaultValue ) const; + /// Return true if index < size(). + bool isValidIndex( UInt index ) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value &append( const Value &value ); + + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const char *key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const char *key ) const; + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const std::string &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const std::string &key ) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value &operator[]( const StaticString &key ); +# ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const CppTL::ConstString &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const CppTL::ConstString &key ) const; +# endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const char *key, + const Value &defaultValue ) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const std::string &key, + const Value &defaultValue ) const; +# ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const CppTL::ConstString &key, + const Value &defaultValue ) const; +# endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember( const char* key ); + /// Same as removeMember(const char*) + Value removeMember( const std::string &key ); + + /// Return true if the object has a member named key. + bool isMember( const char *key ) const; + /// Return true if the object has a member named key. + bool isMember( const std::string &key ) const; +# ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember( const CppTL::ConstString &key ) const; +# endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + +//# ifdef JSON_USE_CPPTL +// EnumMemberNames enumMemberNames() const; +// EnumValues enumValues() const; +//# endif + + /// Comments must be //... or /* ... */ + void setComment( const char *comment, + CommentPlacement placement ); + /// Comments must be //... or /* ... */ + void setComment( const std::string &comment, + CommentPlacement placement ); + bool hasComment( CommentPlacement placement ) const; + /// Include delimiters and embedded newlines. + std::string getComment( CommentPlacement placement ) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + private: + Value &resolveReference( const char *key, + bool isStatic ); + +# ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const + { + return itemIsUsed_ == 0; + } + + inline void setItemUsed( bool isUsed = true ) + { + itemIsUsed_ = isUsed ? 1 : 0; + } + + inline bool isMemberNameStatic() const + { + return memberNameIsStatic_ == 0; + } + + inline void setMemberNameIsStatic( bool isStatic ) + { + memberNameIsStatic_ = isStatic ? 1 : 0; + } +# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + + private: + struct CommentInfo + { + CommentInfo(); + ~CommentInfo(); + + void setComment( const char *text ); + + char *comment_; + }; + + //struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder + { + Int int_; + UInt uint_; + double real_; + bool bool_; + char *string_; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray *array_; + ValueInternalMap *map_; +#else + ObjectValues *map_; +# endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +# ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +# endif + CommentInfo *comments_; + }; + + + /** \brief Experimental and untested: represents an element of the "path" to access a node. + */ + class PathArgument + { + public: + friend class Path; + + PathArgument(); + PathArgument( Value::UInt index ); + PathArgument( const char *key ); + PathArgument( const std::string &key ); + + private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + Value::UInt index_; + Kind kind_; + }; + + /** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ + class Path + { + public: + Path( const std::string &path, + const PathArgument &a1 = PathArgument(), + const PathArgument &a2 = PathArgument(), + const PathArgument &a3 = PathArgument(), + const PathArgument &a4 = PathArgument(), + const PathArgument &a5 = PathArgument() ); + + const Value &resolve( const Value &root ) const; + Value resolve( const Value &root, + const Value &defaultValue ) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value &make( Value &root ) const; + + private: + typedef std::vector<const PathArgument *> InArgs; + typedef std::vector<PathArgument> Args; + + void makePath( const std::string &path, + const InArgs &in ); + void addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ); + void invalidPath( const std::string &path, + int location ); + + Args args_; + }; + + /** \brief Allocator to customize member name and string value memory management done by Value. + * + * - makeMemberName() and releaseMemberName() are called to respectively duplicate and + * free an Json::objectValue member name. + * - duplicateStringValue() and releaseStringValue() are called similarly to + * duplicate and free a Json::stringValue value. + */ + class ValueAllocator + { + public: + enum { unknown = (unsigned)-1 }; + + virtual ~ValueAllocator(); + + virtual char *makeMemberName( const char *memberName ) = 0; + virtual void releaseMemberName( char *memberName ) = 0; + virtual char *duplicateStringValue( const char *value, + unsigned int length = unknown ) = 0; + virtual void releaseStringValue( char *value ) = 0; + }; + +#ifdef JSON_VALUE_USE_INTERNAL_MAP + /** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } + }; + * \endcode + */ + class JSON_API ValueMapAllocator + { + public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap *newMap() = 0; + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; + virtual void destructMap( ValueInternalMap *map ) = 0; + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; + virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; + virtual ValueInternalLink *allocateMapLink() = 0; + virtual void releaseMapLink( ValueInternalLink *link ) = 0; + }; + + /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ + class JSON_API ValueInternalLink + { + public: + enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char *keys_[itemPerLink]; + ValueInternalLink *previous_; + ValueInternalLink *next_; + }; + + + /** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ + class JSON_API ValueInternalMap + { + friend class ValueIteratorBase; + friend class Value; + public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState + { + IteratorState() + : map_(0) + , link_(0) + , itemIndex_(0) + , bucketIndex_(0) + { + } + ValueInternalMap *map_; + ValueInternalLink *link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalMap(); + ValueInternalMap( const ValueInternalMap &other ); + ValueInternalMap &operator =( const ValueInternalMap &other ); + ~ValueInternalMap(); + + void swap( ValueInternalMap &other ); + + BucketIndex size() const; + + void clear(); + + bool reserveDelta( BucketIndex growth ); + + bool reserve( BucketIndex newItemCount ); + + const Value *find( const char *key ) const; + + Value *find( const char *key ); + + Value &resolveReference( const char *key, + bool isStatic ); + + void remove( const char *key ); + + void doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ); + + ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + + Value &setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ); + + Value &unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ); + + HashKey hash( const char *key ) const; + + int compare( const ValueInternalMap &other ) const; + + private: + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void incrementBucket( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static const char *key( const IteratorState &iterator ); + static const char *key( const IteratorState &iterator, bool &isStatic ); + static Value &value( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + + private: + ValueInternalLink *buckets_; + ValueInternalLink *tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; + }; + + /** \brief A simplified deque implementation used internally by Value. + * \internal + * It is based on a list of fixed "page", each page contains a fixed number of items. + * Instead of using a linked-list, a array of pointer is used for fast item look-up. + * Look-up for an element is as follow: + * - compute page index: pageIndex = itemIndex / itemsPerPage + * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] + * + * Insertion is amortized constant time (only the array containing the index of pointers + * need to be reallocated when items are appended). + */ + class JSON_API ValueInternalArray + { + friend class Value; + friend class ValueIteratorBase; + public: + enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState // Must be a POD + { + IteratorState() + : array_(0) + , currentPageIndex_(0) + , currentItemIndex_(0) + { + } + ValueInternalArray *array_; + Value **currentPageIndex_; + unsigned int currentItemIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalArray(); + ValueInternalArray( const ValueInternalArray &other ); + ValueInternalArray &operator =( const ValueInternalArray &other ); + ~ValueInternalArray(); + void swap( ValueInternalArray &other ); + + void clear(); + void resize( ArrayIndex newSize ); + + Value &resolveReference( ArrayIndex index ); + + Value *find( ArrayIndex index ) const; + + ArrayIndex size() const; + + int compare( const ValueInternalArray &other ) const; + + private: + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static Value &dereference( const IteratorState &iterator ); + static Value &unsafeDereference( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + static ArrayIndex indexOf( const IteratorState &iterator ); + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + void makeIterator( IteratorState &it, ArrayIndex index ) const; + + void makeIndexValid( ArrayIndex index ); + + Value **pages_; + ArrayIndex size_; + PageIndex pageCount_; + }; + + /** \brief Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destruct( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast<Value **>( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + \endcode + */ + class JSON_API ValueArrayAllocator + { + public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray *newArray() = 0; + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; + virtual void destructArray( ValueInternalArray *array ) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) = 0; + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) = 0; + virtual Value *allocateArrayPage() = 0; + virtual void releaseArrayPage( Value *value ) = 0; + }; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + + + /** \brief Experimental and untested: base class for Value iterators. + * + */ + class ValueIteratorBase + { + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + ValueIteratorBase(); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); +#else + ValueIteratorBase( const ValueInternalArray::IteratorState &state ); + ValueIteratorBase( const ValueInternalMap::IteratorState &state ); +#endif + + bool operator ==( const SelfType &other ) const + { + return isEqual( other ); + } + + bool operator !=( const SelfType &other ) const + { + return !isEqual( other ); + } + + difference_type operator -( const SelfType &other ) const + { + return computeDistance( other ); + } + + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + Value::UInt index() const; + + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char *memberName() const; + + protected: + Value &deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance( const SelfType &other ) const; + + bool isEqual( const SelfType &other ) const; + + void copy( const SelfType &other ); + + private: +#ifndef JSON_VALUE_USE_INTERNAL_MAP + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +#else + union + { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; +#endif + }; + + /** \brief Experimental and untested: const iterator for object and array value. + * + */ + class ValueConstIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value &reference; + typedef const Value *pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueConstIterator( const ValueInternalArray::IteratorState &state ); + ValueConstIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + SelfType &operator =( const ValueIteratorBase &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + + /** \brief Experimental and untested: iterator for object and array value. + */ + class ValueIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value &reference; + typedef Value *pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator( const ValueConstIterator &other ); + ValueIterator( const ValueIterator &other ); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueIterator( const ValueInternalArray::IteratorState &state ); + ValueIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + + SelfType &operator =( const SelfType &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + +} // namespace Json + + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/lib/jsoncpp/jsoncpp/include/json/writer.h b/lib/jsoncpp/jsoncpp/include/json/writer.h new file mode 100644 index 0000000000..cfa92c6ae4 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/include/json/writer.h @@ -0,0 +1,174 @@ +#ifndef JSON_WRITER_H_INCLUDED +# define JSON_WRITER_H_INCLUDED + +# include "value.h" +# include <vector> +# include <string> +# include <iostream> + +namespace Json { + + class Value; + + /** \brief Abstract class for writers. + */ + class JSON_API Writer + { + public: + virtual ~Writer(); + + virtual std::string write( const Value &root ) = 0; + }; + + /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ + class JSON_API FastWriter : public Writer + { + public: + FastWriter(); + virtual ~FastWriter(){} + + void enableYAMLCompatibility(); + + public: // overridden from Writer + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + + std::string document_; + bool yamlCompatiblityEnabled_; + }; + + /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledWriter: public Writer + { + public: + StyledWriter(); + virtual ~StyledWriter(){} + + public: // overridden from Writer + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector<std::string> ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; + }; + + /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledStreamWriter + { + public: + StyledStreamWriter( std::string indentation="\t" ); + ~StyledStreamWriter(){} + + public: + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write( std::ostream &out, const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector<std::string> ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; + }; + + std::string JSON_API valueToString( Value::Int value ); + std::string JSON_API valueToString( Value::UInt value ); + std::string JSON_API valueToString( double value ); + std::string JSON_API valueToString( bool value ); + std::string JSON_API valueToQuotedString( const char *value ); + + /// \brief Output using the StyledStreamWriter. + /// \see Json::operator>>() + std::ostream& operator<<( std::ostream&, const Value &root ); + +} // namespace Json + + + +#endif // JSON_WRITER_H_INCLUDED diff --git a/lib/jsoncpp/jsoncpp/makefiles/vs71/jsoncpp.sln b/lib/jsoncpp/jsoncpp/makefiles/vs71/jsoncpp.sln new file mode 100644 index 0000000000..5bfa366547 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/makefiles/vs71/jsoncpp.sln @@ -0,0 +1,46 @@ +Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_json", "lib_json.vcproj", "{B84F7231-16CE-41D8-8C08-7B523FF4225B}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsontest", "jsontest.vcproj", "{25AF2DD2-D396-4668-B188-488C33B8E620}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B} = {B84F7231-16CE-41D8-8C08-7B523FF4225B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_lib_json", "test_lib_json.vcproj", "{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B} = {B84F7231-16CE-41D8-8C08-7B523FF4225B}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ dummy = dummy
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Debug.ActiveCfg = Debug|Win32
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Debug.Build.0 = Debug|Win32
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B}.dummy.ActiveCfg = dummy|Win32
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B}.dummy.Build.0 = dummy|Win32
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Release.ActiveCfg = Release|Win32
+ {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Release.Build.0 = Release|Win32
+ {25AF2DD2-D396-4668-B188-488C33B8E620}.Debug.ActiveCfg = Debug|Win32
+ {25AF2DD2-D396-4668-B188-488C33B8E620}.Debug.Build.0 = Debug|Win32
+ {25AF2DD2-D396-4668-B188-488C33B8E620}.dummy.ActiveCfg = Debug|Win32
+ {25AF2DD2-D396-4668-B188-488C33B8E620}.dummy.Build.0 = Debug|Win32
+ {25AF2DD2-D396-4668-B188-488C33B8E620}.Release.ActiveCfg = Release|Win32
+ {25AF2DD2-D396-4668-B188-488C33B8E620}.Release.Build.0 = Release|Win32
+ {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug.ActiveCfg = Debug|Win32
+ {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug.Build.0 = Debug|Win32
+ {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.dummy.ActiveCfg = Debug|Win32
+ {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.dummy.Build.0 = Debug|Win32
+ {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release.ActiveCfg = Release|Win32
+ {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/lib/jsoncpp/jsoncpp/makefiles/vs71/jsontest.vcproj b/lib/jsoncpp/jsoncpp/makefiles/vs71/jsontest.vcproj new file mode 100644 index 0000000000..99a4dd6971 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/makefiles/vs71/jsontest.vcproj @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="jsontest"
+ ProjectGUID="{25AF2DD2-D396-4668-B188-488C33B8E620}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../build/vs71/debug/jsontest"
+ IntermediateDirectory="../../build/vs71/debug/jsontest"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/jsontest.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/jsontest.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../build/vs71/release/jsontest"
+ IntermediateDirectory="../../build/vs71/release/jsontest"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/jsontest.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\src\jsontestrunner\main.cpp">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/lib/jsoncpp/jsoncpp/makefiles/vs71/lib_json.vcproj b/lib/jsoncpp/jsoncpp/makefiles/vs71/lib_json.vcproj new file mode 100644 index 0000000000..1aa5978a1f --- /dev/null +++ b/lib/jsoncpp/jsoncpp/makefiles/vs71/lib_json.vcproj @@ -0,0 +1,214 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="lib_json" + ProjectGUID="{B84F7231-16CE-41D8-8C08-7B523FF4225B}" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="../../build/vs71/debug/lib_json" + IntermediateDirectory="../../build/vs71/debug/lib_json" + ConfigurationType="4" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="../../include" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB" + StringPooling="TRUE" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + EnableFunctionLevelLinking="TRUE" + DisableLanguageExtensions="TRUE" + ForceConformanceInForLoopScope="FALSE" + RuntimeTypeInfo="TRUE" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile="$(OutDir)/json_vc71_libmtd.lib"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="../../build/vs71/release/lib_json" + IntermediateDirectory="../../build/vs71/release/lib_json" + ConfigurationType="4" + CharacterSet="2" + WholeProgramOptimization="TRUE"> + <Tool + Name="VCCLCompilerTool" + GlobalOptimizations="TRUE" + EnableIntrinsicFunctions="TRUE" + AdditionalIncludeDirectories="../../include" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="TRUE" + RuntimeLibrary="0" + EnableFunctionLevelLinking="TRUE" + DisableLanguageExtensions="TRUE" + ForceConformanceInForLoopScope="FALSE" + RuntimeTypeInfo="TRUE" + UsePrecompiledHeader="0" + AssemblerOutput="4" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile="$(OutDir)/json_vc71_libmt.lib"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="dummy|Win32" + OutputDirectory="$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="2" + WholeProgramOptimization="TRUE"> + <Tool + Name="VCCLCompilerTool" + GlobalOptimizations="TRUE" + EnableIntrinsicFunctions="TRUE" + AdditionalIncludeDirectories="../../include" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="TRUE" + RuntimeLibrary="4" + EnableFunctionLevelLinking="TRUE" + DisableLanguageExtensions="TRUE" + ForceConformanceInForLoopScope="FALSE" + RuntimeTypeInfo="TRUE" + UsePrecompiledHeader="0" + AssemblerOutput="4" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + GenerateDebugInformation="TRUE" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath="..\..\include\json\autolink.h"> + </File> + <File + RelativePath="..\..\include\json\config.h"> + </File> + <File + RelativePath="..\..\include\json\features.h"> + </File> + <File + RelativePath="..\..\include\json\forwards.h"> + </File> + <File + RelativePath="..\..\include\json\json.h"> + </File> + <File + RelativePath="..\..\src\lib_json\json_batchallocator.h"> + </File> + <File + RelativePath="..\..\src\lib_json\json_internalarray.inl"> + </File> + <File + RelativePath="..\..\src\lib_json\json_internalmap.inl"> + </File> + <File + RelativePath="..\..\src\lib_json\json_reader.cpp"> + </File> + <File + RelativePath="..\..\src\lib_json\json_value.cpp"> + </File> + <File + RelativePath="..\..\src\lib_json\json_valueiterator.inl"> + </File> + <File + RelativePath="..\..\src\lib_json\json_writer.cpp"> + </File> + <File + RelativePath="..\..\include\json\reader.h"> + </File> + <File + RelativePath="..\..\include\json\value.h"> + </File> + <File + RelativePath="..\..\include\json\writer.h"> + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/lib/jsoncpp/jsoncpp/makefiles/vs71/test_lib_json.vcproj b/lib/jsoncpp/jsoncpp/makefiles/vs71/test_lib_json.vcproj new file mode 100644 index 0000000000..df36700bdc --- /dev/null +++ b/lib/jsoncpp/jsoncpp/makefiles/vs71/test_lib_json.vcproj @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test_lib_json"
+ ProjectGUID="{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}"
+ RootNamespace="test_lib_json"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../build/vs71/debug/test_lib_json"
+ IntermediateDirectory="../../build/vs71/debug/test_lib_json"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/test_lib_json.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/test_lib_json.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Running all unit tests"
+ CommandLine="$(TargetPath)"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../build/vs71/release/test_lib_json"
+ IntermediateDirectory="../../build/vs71/release/test_lib_json"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/test_lib_json.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Running all unit tests"
+ CommandLine="$(TargetPath)"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\src\test_lib_json\jsontest.cpp">
+ </File>
+ <File
+ RelativePath="..\..\src\test_lib_json\jsontest.h">
+ </File>
+ <File
+ RelativePath="..\..\src\test_lib_json\main.cpp">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/lib/jsoncpp/jsoncpp/scons-tools/doxygen.py b/lib/jsoncpp/jsoncpp/scons-tools/doxygen.py new file mode 100644 index 0000000000..5ace420a4c --- /dev/null +++ b/lib/jsoncpp/jsoncpp/scons-tools/doxygen.py @@ -0,0 +1,116 @@ +# Big issue: +# emitter depends on doxyfile which is generated from doxyfile.in. +# build fails after cleaning and relaunching the build. + +# Todo: +# Add helper function to environment like for glob +# Easier passage of header/footer +# Automatic deduction of index.html path based on custom parameters passed to doxyfile + +import os +import os.path +from fnmatch import fnmatch +import SCons + +def Doxyfile_emitter(target, source, env): + """ + Modify the target and source lists to use the defaults if nothing + else has been specified. + + Dependencies on external HTML documentation references are also + appended to the source list. + """ + doxyfile_template = env.File(env['DOXYFILE_FILE']) + source.insert(0, doxyfile_template) + + return target, source + +def Doxyfile_Builder(target, source, env): + """Input: + DOXYFILE_FILE + Path of the template file for the output doxyfile + + DOXYFILE_DICT + A dictionnary of parameter to append to the generated doxyfile + """ + subdir = os.path.split(source[0].abspath)[0] + doc_top_dir = os.path.split(target[0].abspath)[0] + doxyfile_path = source[0].abspath + doxy_file = file( target[0].abspath, 'wt' ) + try: + # First, output the template file + try: + f = file(doxyfile_path, 'rt') + doxy_file.write( f.read() ) + f.close() + doxy_file.write( '\n' ) + doxy_file.write( '# Generated content:\n' ) + except: + raise SCons.Errors.UserError, "Can't read doxygen template file '%s'" % doxyfile_path + # Then, the input files + doxy_file.write( 'INPUT = \\\n' ) + for source in source: + if source.abspath != doxyfile_path: # skip doxyfile path, which is the first source + doxy_file.write( '"%s" \\\n' % source.abspath ) + doxy_file.write( '\n' ) + # Dot... + values_dict = { 'HAVE_DOT': env.get('DOT') and 'YES' or 'NO', + 'DOT_PATH': env.get('DOT') and os.path.split(env['DOT'])[0] or '', + 'OUTPUT_DIRECTORY': doc_top_dir, + 'WARN_LOGFILE': target[0].abspath + '-warning.log'} + values_dict.update( env['DOXYFILE_DICT'] ) + # Finally, output user dictionary values which override any of the previously set parameters. + for key, value in values_dict.iteritems(): + doxy_file.write ('%s = "%s"\n' % (key, str(value))) + finally: + doxy_file.close() + +def generate(env): + """ + Add builders and construction variables for the + Doxygen tool. + """ + ## Doxyfile builder + def doxyfile_message (target, source, env): + return "creating Doxygen config file '%s'" % target[0] + + doxyfile_variables = [ + 'DOXYFILE_DICT', + 'DOXYFILE_FILE' + ] + + #doxyfile_action = SCons.Action.Action( Doxyfile_Builder, doxyfile_message, + # doxyfile_variables ) + doxyfile_action = SCons.Action.Action( Doxyfile_Builder, doxyfile_message) + + doxyfile_builder = SCons.Builder.Builder( action = doxyfile_action, + emitter = Doxyfile_emitter ) + + env['BUILDERS']['Doxyfile'] = doxyfile_builder + env['DOXYFILE_DICT'] = {} + env['DOXYFILE_FILE'] = 'doxyfile.in' + + ## Doxygen builder + def Doxygen_emitter(target, source, env): + output_dir = str( source[0].dir ) + if str(target[0]) == str(source[0]): + target = env.File( os.path.join( output_dir, 'html', 'index.html' ) ) + return target, source + + doxygen_action = SCons.Action.Action( [ '$DOXYGEN_COM'] ) + doxygen_builder = SCons.Builder.Builder( action = doxygen_action, + emitter = Doxygen_emitter ) + env['BUILDERS']['Doxygen'] = doxygen_builder + env['DOXYGEN_COM'] = '$DOXYGEN $DOXYGEN_FLAGS $SOURCE' + env['DOXYGEN_FLAGS'] = '' + env['DOXYGEN'] = 'doxygen' + + dot_path = env.WhereIs("dot") + if dot_path: + env['DOT'] = dot_path + +def exists(env): + """ + Make sure doxygen exists. + """ + return env.Detect("doxygen") diff --git a/lib/jsoncpp/jsoncpp/scons-tools/globtool.py b/lib/jsoncpp/jsoncpp/scons-tools/globtool.py new file mode 100644 index 0000000000..8ee3cbb0b6 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/scons-tools/globtool.py @@ -0,0 +1,53 @@ +import fnmatch
+import os
+
+def generate( env ):
+ def Glob( env, includes = None, excludes = None, dir = '.' ):
+ """Adds Glob( includes = Split( '*' ), excludes = None, dir = '.')
+ helper function to environment.
+
+ Glob both the file-system files.
+
+ includes: list of file name pattern included in the return list when matched.
+ excludes: list of file name pattern exluced from the return list.
+
+ Example:
+ sources = env.Glob( ("*.cpp", '*.h'), "~*.cpp", "#src" )
+ """
+ def filterFilename(path):
+ abs_path = os.path.join( dir, path )
+ if not os.path.isfile(abs_path):
+ return 0
+ fn = os.path.basename(path)
+ match = 0
+ for include in includes:
+ if fnmatch.fnmatchcase( fn, include ):
+ match = 1
+ break
+ if match == 1 and not excludes is None:
+ for exclude in excludes:
+ if fnmatch.fnmatchcase( fn, exclude ):
+ match = 0
+ break
+ return match
+ if includes is None:
+ includes = ('*',)
+ elif type(includes) in ( type(''), type(u'') ):
+ includes = (includes,)
+ if type(excludes) in ( type(''), type(u'') ):
+ excludes = (excludes,)
+ dir = env.Dir(dir).abspath
+ paths = os.listdir( dir )
+ def makeAbsFileNode( path ):
+ return env.File( os.path.join( dir, path ) )
+ nodes = filter( filterFilename, paths )
+ return map( makeAbsFileNode, nodes )
+
+ from SCons.Script import Environment
+ Environment.Glob = Glob +
+def exists(env):
+ """
+ Tool always exists.
+ """
+ return True
diff --git a/lib/jsoncpp/jsoncpp/scons-tools/srcdist.py b/lib/jsoncpp/jsoncpp/scons-tools/srcdist.py new file mode 100644 index 0000000000..864ff40815 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/scons-tools/srcdist.py @@ -0,0 +1,179 @@ +import os +import os.path +from fnmatch import fnmatch +import targz + +##def DoxyfileParse(file_contents): +## """ +## Parse a Doxygen source file and return a dictionary of all the values. +## Values will be strings and lists of strings. +## """ +## data = {} +## +## import shlex +## lex = shlex.shlex(instream = file_contents, posix = True) +## lex.wordchars += "*+./-:" +## lex.whitespace = lex.whitespace.replace("\n", "") +## lex.escape = "" +## +## lineno = lex.lineno +## last_backslash_lineno = lineno +## token = lex.get_token() +## key = token # the first token should be a key +## last_token = "" +## key_token = False +## next_key = False +## new_data = True +## +## def append_data(data, key, new_data, token): +## if new_data or len(data[key]) == 0: +## data[key].append(token) +## else: +## data[key][-1] += token +## +## while token: +## if token in ['\n']: +## if last_token not in ['\\']: +## key_token = True +## elif token in ['\\']: +## pass +## elif key_token: +## key = token +## key_token = False +## else: +## if token == "+=": +## if not data.has_key(key): +## data[key] = list() +## elif token == "=": +## data[key] = list() +## else: +## append_data( data, key, new_data, token ) +## new_data = True +## +## last_token = token +## token = lex.get_token() +## +## if last_token == '\\' and token != '\n': +## new_data = False +## append_data( data, key, new_data, '\\' ) +## +## # compress lists of len 1 into single strings +## for (k, v) in data.items(): +## if len(v) == 0: +## data.pop(k) +## +## # items in the following list will be kept as lists and not converted to strings +## if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS"]: +## continue +## +## if len(v) == 1: +## data[k] = v[0] +## +## return data +## +##def DoxySourceScan(node, env, path): +## """ +## Doxygen Doxyfile source scanner. This should scan the Doxygen file and add +## any files used to generate docs to the list of source files. +## """ +## default_file_patterns = [ +## '*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx', +## '*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++', +## '*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm', +## '*.py', +## ] +## +## default_exclude_patterns = [ +## '*~', +## ] +## +## sources = [] +## +## data = DoxyfileParse(node.get_contents()) +## +## if data.get("RECURSIVE", "NO") == "YES": +## recursive = True +## else: +## recursive = False +## +## file_patterns = data.get("FILE_PATTERNS", default_file_patterns) +## exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns) +## +## for node in data.get("INPUT", []): +## if os.path.isfile(node): +## sources.add(node) +## elif os.path.isdir(node): +## if recursive: +## for root, dirs, files in os.walk(node): +## for f in files: +## filename = os.path.join(root, f) +## +## pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False) +## exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True) +## +## if pattern_check and not exclude_check: +## sources.append(filename) +## else: +## for pattern in file_patterns: +## sources.extend(glob.glob("/".join([node, pattern]))) +## sources = map( lambda path: env.File(path), sources ) +## return sources +## +## +##def DoxySourceScanCheck(node, env): +## """Check if we should scan this file""" +## return os.path.isfile(node.path) + +def srcDistEmitter(source, target, env): +## """Doxygen Doxyfile emitter""" +## # possible output formats and their default values and output locations +## output_formats = { +## "HTML": ("YES", "html"), +## "LATEX": ("YES", "latex"), +## "RTF": ("NO", "rtf"), +## "MAN": ("YES", "man"), +## "XML": ("NO", "xml"), +## } +## +## data = DoxyfileParse(source[0].get_contents()) +## +## targets = [] +## out_dir = data.get("OUTPUT_DIRECTORY", ".") +## +## # add our output locations +## for (k, v) in output_formats.items(): +## if data.get("GENERATE_" + k, v[0]) == "YES": +## targets.append(env.Dir( os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) ) +## +## # don't clobber targets +## for node in targets: +## env.Precious(node) +## +## # set up cleaning stuff +## for node in targets: +## env.Clean(node, node) +## +## return (targets, source) + return (target,source) + +def generate(env): + """ + Add builders and construction variables for the + SrcDist tool. + """ +## doxyfile_scanner = env.Scanner( +## DoxySourceScan, +## "DoxySourceScan", +## scan_check = DoxySourceScanCheck, +## ) + + if targz.exists(env): + srcdist_builder = targz.makeBuilder( srcDistEmitter ) + + env['BUILDERS']['SrcDist'] = srcdist_builder + +def exists(env): + """ + Make sure srcdist exists. + """ + return targz.exists(env) diff --git a/lib/jsoncpp/jsoncpp/scons-tools/substinfile.py b/lib/jsoncpp/jsoncpp/scons-tools/substinfile.py new file mode 100644 index 0000000000..4d305851bb --- /dev/null +++ b/lib/jsoncpp/jsoncpp/scons-tools/substinfile.py @@ -0,0 +1,79 @@ +import re +from SCons.Script import * # the usual scons stuff you get in a SConscript + +def generate(env): + """ + Add builders and construction variables for the + SubstInFile tool. + + Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT + from the source to the target. + The values of SUBST_DICT first have any construction variables expanded + (its keys are not expanded). + If a value of SUBST_DICT is a python callable function, it is called and + the result is expanded as the value. + If there's more than one source and more than one target, each target gets + substituted from the corresponding source. + """ + def do_subst_in_file(targetfile, sourcefile, dict): + """Replace all instances of the keys of dict with their values. + For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'}, + then all instances of %VERSION% in the file will be replaced with 1.2345 etc. + """ + try: + f = open(sourcefile, 'rb') + contents = f.read() + f.close() + except: + raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile + for (k,v) in dict.items(): + contents = re.sub(k, v, contents) + try: + f = open(targetfile, 'wb') + f.write(contents) + f.close() + except: + raise SCons.Errors.UserError, "Can't write target file %s"%targetfile + return 0 # success + + def subst_in_file(target, source, env): + if not env.has_key('SUBST_DICT'): + raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set." + d = dict(env['SUBST_DICT']) # copy it + for (k,v) in d.items(): + if callable(v): + d[k] = env.subst(v()).replace('\\','\\\\') + elif SCons.Util.is_String(v): + d[k] = env.subst(v).replace('\\','\\\\') + else: + raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)) + for (t,s) in zip(target, source): + return do_subst_in_file(str(t), str(s), d) + + def subst_in_file_string(target, source, env): + """This is what gets printed on the console.""" + return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t)) + for (t,s) in zip(target, source)]) + + def subst_emitter(target, source, env): + """Add dependency from substituted SUBST_DICT to target. + Returns original target, source tuple unchanged. + """ + d = env['SUBST_DICT'].copy() # copy it + for (k,v) in d.items(): + if callable(v): + d[k] = env.subst(v()) + elif SCons.Util.is_String(v): + d[k]=env.subst(v) + Depends(target, SCons.Node.Python.Value(d)) + return target, source + +## env.Append(TOOLS = 'substinfile') # this should be automaticaly done by Scons ?!? + subst_action = SCons.Action.Action( subst_in_file, subst_in_file_string ) + env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter) + +def exists(env): + """ + Make sure tool exists. + """ + return True diff --git a/lib/jsoncpp/jsoncpp/scons-tools/targz.py b/lib/jsoncpp/jsoncpp/scons-tools/targz.py new file mode 100644 index 0000000000..f5432003df --- /dev/null +++ b/lib/jsoncpp/jsoncpp/scons-tools/targz.py @@ -0,0 +1,82 @@ +"""tarball + +Tool-specific initialization for tarball. + +""" + +## Commands to tackle a command based implementation: +##to unpack on the fly... +##gunzip < FILE.tar.gz | tar xvf - +##to pack on the fly... +##tar cvf - FILE-LIST | gzip -c > FILE.tar.gz + +import os.path + +import SCons.Builder +import SCons.Node.FS +import SCons.Util + +try: + import gzip + import tarfile + internal_targz = 1 +except ImportError: + internal_targz = 0 + +TARGZ_DEFAULT_COMPRESSION_LEVEL = 9 + +if internal_targz: + def targz(target, source, env): + def archive_name( path ): + path = os.path.normpath( os.path.abspath( path ) ) + common_path = os.path.commonprefix( (base_dir, path) ) + archive_name = path[len(common_path):] + return archive_name + + def visit(tar, dirname, names): + for name in names: + path = os.path.join(dirname, name) + if os.path.isfile(path): + tar.add(path, archive_name(path) ) + compression = env.get('TARGZ_COMPRESSION_LEVEL',TARGZ_DEFAULT_COMPRESSION_LEVEL) + base_dir = os.path.normpath( env.get('TARGZ_BASEDIR', env.Dir('.')).abspath ) + target_path = str(target[0]) + fileobj = gzip.GzipFile( target_path, 'wb', compression ) + tar = tarfile.TarFile(os.path.splitext(target_path)[0], 'w', fileobj) + for source in source: + source_path = str(source) + if source.isdir(): + os.path.walk(source_path, visit, tar) + else: + tar.add(source_path, archive_name(source_path) ) # filename, arcname + tar.close() + + targzAction = SCons.Action.Action(targz, varlist=['TARGZ_COMPRESSION_LEVEL','TARGZ_BASEDIR']) + + def makeBuilder( emitter = None ): + return SCons.Builder.Builder(action = SCons.Action.Action('$TARGZ_COM', '$TARGZ_COMSTR'), + source_factory = SCons.Node.FS.Entry, + source_scanner = SCons.Defaults.DirScanner, + suffix = '$TARGZ_SUFFIX', + multi = 1) + TarGzBuilder = makeBuilder() + + def generate(env): + """Add Builders and construction variables for zip to an Environment. + The following environnement variables may be set: + TARGZ_COMPRESSION_LEVEL: integer, [0-9]. 0: no compression, 9: best compression (same as gzip compression level). + TARGZ_BASEDIR: base-directory used to determine archive name (this allow archive name to be relative + to something other than top-dir). + """ + env['BUILDERS']['TarGz'] = TarGzBuilder + env['TARGZ_COM'] = targzAction + env['TARGZ_COMPRESSION_LEVEL'] = TARGZ_DEFAULT_COMPRESSION_LEVEL # range 0-9 + env['TARGZ_SUFFIX'] = '.tar.gz' + env['TARGZ_BASEDIR'] = env.Dir('.') # Sources archive name are made relative to that directory. +else: + def generate(env): + pass + + +def exists(env): + return internal_targz diff --git a/lib/jsoncpp/jsoncpp/src/jsontestrunner/main.cpp b/lib/jsoncpp/jsoncpp/src/jsontestrunner/main.cpp new file mode 100644 index 0000000000..231ee0c44d --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/jsontestrunner/main.cpp @@ -0,0 +1,233 @@ +#include <json/json.h> +#include <algorithm> // sort +#include <stdio.h> + +#if defined(_MSC_VER) && _MSC_VER >= 1310 +# pragma warning( disable: 4996 ) // disable fopen deprecation warning +#endif + +static std::string +readInputTestFile( const char *path ) +{ + FILE *file = fopen( path, "rb" ); + if ( !file ) + return std::string(""); + fseek( file, 0, SEEK_END ); + long size = ftell( file ); + fseek( file, 0, SEEK_SET ); + std::string text; + char *buffer = new char[size+1]; + buffer[size] = 0; + if ( fread( buffer, 1, size, file ) == (unsigned long)size ) + text = buffer; + fclose( file ); + delete[] buffer; + return text; +} + + +static void +printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." ) +{ + switch ( value.type() ) + { + case Json::nullValue: + fprintf( fout, "%s=null\n", path.c_str() ); + break; + case Json::intValue: + fprintf( fout, "%s=%d\n", path.c_str(), value.asInt() ); + break; + case Json::uintValue: + fprintf( fout, "%s=%u\n", path.c_str(), value.asUInt() ); + break; + case Json::realValue: + fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() ); + break; + case Json::stringValue: + fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() ); + break; + case Json::booleanValue: + fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" ); + break; + case Json::arrayValue: + { + fprintf( fout, "%s=[]\n", path.c_str() ); + int size = value.size(); + for ( int index =0; index < size; ++index ) + { + static char buffer[16]; + sprintf( buffer, "[%d]", index ); + printValueTree( fout, value[index], path + buffer ); + } + } + break; + case Json::objectValue: + { + fprintf( fout, "%s={}\n", path.c_str() ); + Json::Value::Members members( value.getMemberNames() ); + std::sort( members.begin(), members.end() ); + std::string suffix = *(path.end()-1) == '.' ? "" : "."; + for ( Json::Value::Members::iterator it = members.begin(); + it != members.end(); + ++it ) + { + const std::string &name = *it; + printValueTree( fout, value[name], path + suffix + name ); + } + } + break; + default: + break; + } +} + + +static int +parseAndSaveValueTree( const std::string &input, + const std::string &actual, + const std::string &kind, + Json::Value &root, + const Json::Features &features, + bool parseOnly ) +{ + Json::Reader reader( features ); + bool parsingSuccessful = reader.parse( input, root ); + if ( !parsingSuccessful ) + { + printf( "Failed to parse %s file: \n%s\n", + kind.c_str(), + reader.getFormatedErrorMessages().c_str() ); + return 1; + } + + if ( !parseOnly ) + { + FILE *factual = fopen( actual.c_str(), "wt" ); + if ( !factual ) + { + printf( "Failed to create %s actual file.\n", kind.c_str() ); + return 2; + } + printValueTree( factual, root ); + fclose( factual ); + } + return 0; +} + + +static int +rewriteValueTree( const std::string &rewritePath, + const Json::Value &root, + std::string &rewrite ) +{ + //Json::FastWriter writer; + //writer.enableYAMLCompatibility(); + Json::StyledWriter writer; + rewrite = writer.write( root ); + FILE *fout = fopen( rewritePath.c_str(), "wt" ); + if ( !fout ) + { + printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() ); + return 2; + } + fprintf( fout, "%s\n", rewrite.c_str() ); + fclose( fout ); + return 0; +} + + +static std::string +removeSuffix( const std::string &path, + const std::string &extension ) +{ + if ( extension.length() >= path.length() ) + return std::string(""); + std::string suffix = path.substr( path.length() - extension.length() ); + if ( suffix != extension ) + return std::string(""); + return path.substr( 0, path.length() - extension.length() ); +} + +static int +printUsage( const char *argv[] ) +{ + printf( "Usage: %s [--strict] input-json-file", argv[0] ); + return 3; +} + + +int +parseCommandLine( int argc, const char *argv[], + Json::Features &features, std::string &path, + bool &parseOnly ) +{ + parseOnly = false; + if ( argc < 2 ) + { + return printUsage( argv ); + } + + int index = 1; + if ( std::string(argv[1]) == "--json-checker" ) + { + features = Json::Features::strictMode(); + parseOnly = true; + ++index; + } + + if ( index == argc || index + 1 < argc ) + { + return printUsage( argv ); + } + + path = argv[index]; + return 0; +} + + +int main( int argc, const char *argv[] ) +{ + std::string path; + Json::Features features; + bool parseOnly; + int exitCode = parseCommandLine( argc, argv, features, path, parseOnly ); + if ( exitCode != 0 ) + { + return exitCode; + } + + std::string input = readInputTestFile( path.c_str() ); + if ( input.empty() ) + { + printf( "Failed to read input or empty input: %s\n", path.c_str() ); + return 3; + } + + std::string basePath = removeSuffix( argv[1], ".json" ); + if ( !parseOnly && basePath.empty() ) + { + printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() ); + return 3; + } + + std::string actualPath = basePath + ".actual"; + std::string rewritePath = basePath + ".rewrite"; + std::string rewriteActualPath = basePath + ".actual-rewrite"; + + Json::Value root; + exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly ); + if ( exitCode == 0 && !parseOnly ) + { + std::string rewrite; + exitCode = rewriteValueTree( rewritePath, root, rewrite ); + if ( exitCode == 0 ) + { + Json::Value rewriteRoot; + exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath, + "rewrite", rewriteRoot, features, parseOnly ); + } + } + + return exitCode; +} + diff --git a/lib/jsoncpp/jsoncpp/src/jsontestrunner/sconscript b/lib/jsoncpp/jsoncpp/src/jsontestrunner/sconscript new file mode 100644 index 0000000000..6e68e31533 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/jsontestrunner/sconscript @@ -0,0 +1,9 @@ +Import( 'env_testing buildJSONTests' ) + +buildJSONTests( env_testing, Split( """ + main.cpp + """ ), + 'jsontestrunner' ) + +# For 'check' to work, 'libs' must be built first. +env_testing.Depends('jsontestrunner', '#libs') diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/json_batchallocator.h b/lib/jsoncpp/jsoncpp/src/lib_json/json_batchallocator.h new file mode 100644 index 0000000000..87ea5ed807 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/json_batchallocator.h @@ -0,0 +1,125 @@ +#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED +# define JSONCPP_BATCHALLOCATOR_H_INCLUDED + +# include <stdlib.h> +# include <assert.h> + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +namespace Json { + +/* Fast memory allocator. + * + * This memory allocator allocates memory for a batch of object (specified by + * the page size, the number of object in each page). + * + * It does not allow the destruction of a single object. All the allocated objects + * can be destroyed at once. The memory can be either released or reused for future + * allocation. + * + * The in-place new operator must be used to construct the object using the pointer + * returned by allocate. + */ +template<typename AllocatedType + ,const unsigned int objectPerAllocation> +class BatchAllocator +{ +public: + typedef AllocatedType Type; + + BatchAllocator( unsigned int objectsPerPage = 255 ) + : freeHead_( 0 ) + , objectsPerPage_( objectsPerPage ) + { +// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); + assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. + assert( objectsPerPage >= 16 ); + batches_ = allocateBatch( 0 ); // allocated a dummy page + currentBatch_ = batches_; + } + + ~BatchAllocator() + { + for ( BatchInfo *batch = batches_; batch; ) + { + BatchInfo *nextBatch = batch->next_; + free( batch ); + batch = nextBatch; + } + } + + /// allocate space for an array of objectPerAllocation object. + /// @warning it is the responsability of the caller to call objects constructors. + AllocatedType *allocate() + { + if ( freeHead_ ) // returns node from free list. + { + AllocatedType *object = freeHead_; + freeHead_ = *(AllocatedType **)object; + return object; + } + if ( currentBatch_->used_ == currentBatch_->end_ ) + { + currentBatch_ = currentBatch_->next_; + while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) + currentBatch_ = currentBatch_->next_; + + if ( !currentBatch_ ) // no free batch found, allocate a new one + { + currentBatch_ = allocateBatch( objectsPerPage_ ); + currentBatch_->next_ = batches_; // insert at the head of the list + batches_ = currentBatch_; + } + } + AllocatedType *allocated = currentBatch_->used_; + currentBatch_->used_ += objectPerAllocation; + return allocated; + } + + /// Release the object. + /// @warning it is the responsability of the caller to actually destruct the object. + void release( AllocatedType *object ) + { + assert( object != 0 ); + *(AllocatedType **)object = freeHead_; + freeHead_ = object; + } + +private: + struct BatchInfo + { + BatchInfo *next_; + AllocatedType *used_; + AllocatedType *end_; + AllocatedType buffer_[objectPerAllocation]; + }; + + // disabled copy constructor and assignement operator. + BatchAllocator( const BatchAllocator & ); + void operator =( const BatchAllocator &); + + static BatchInfo *allocateBatch( unsigned int objectsPerPage ) + { + const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation + + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; + BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) ); + batch->next_ = 0; + batch->used_ = batch->buffer_; + batch->end_ = batch->buffer_ + objectsPerPage; + return batch; + } + + BatchInfo *batches_; + BatchInfo *currentBatch_; + /// Head of a single linked list within the allocated space of freeed object + AllocatedType *freeHead_; + unsigned int objectsPerPage_; +}; + + +} // namespace Json + +# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION + +#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED + diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/json_internalarray.inl b/lib/jsoncpp/jsoncpp/src/lib_json/json_internalarray.inl new file mode 100644 index 0000000000..9b985d2585 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/json_internalarray.inl @@ -0,0 +1,448 @@ +// included by json_value.cpp +// everything is within Json namespace + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueInternalArray +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueArrayAllocator::~ValueArrayAllocator() +{ +} + +// ////////////////////////////////////////////////////////////////// +// class DefaultValueArrayAllocator +// ////////////////////////////////////////////////////////////////// +#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destructArray( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast<Value **>( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + +#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +/// @todo make this thread-safe (lock when accessign batch allocator) +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + ValueInternalArray *array = arraysAllocator_.allocate(); + new (array) ValueInternalArray(); // placement new + return array; + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + ValueInternalArray *array = arraysAllocator_.allocate(); + new (array) ValueInternalArray( other ); // placement new + return array; + } + + virtual void destructArray( ValueInternalArray *array ) + { + if ( array ) + { + array->~ValueInternalArray(); + arraysAllocator_.release( array ); + } + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast<Value **>( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast<Value *>( pagesAllocator_.allocate() ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + pagesAllocator_.release( value ); + } +private: + BatchAllocator<ValueInternalArray,1> arraysAllocator_; + BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_; +}; +#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR + +static ValueArrayAllocator *&arrayAllocator() +{ + static DefaultValueArrayAllocator defaultAllocator; + static ValueArrayAllocator *arrayAllocator = &defaultAllocator; + return arrayAllocator; +} + +static struct DummyArrayAllocatorInitializer { + DummyArrayAllocatorInitializer() + { + arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). + } +} dummyArrayAllocatorInitializer; + +// ////////////////////////////////////////////////////////////////// +// class ValueInternalArray +// ////////////////////////////////////////////////////////////////// +bool +ValueInternalArray::equals( const IteratorState &x, + const IteratorState &other ) +{ + return x.array_ == other.array_ + && x.currentItemIndex_ == other.currentItemIndex_ + && x.currentPageIndex_ == other.currentPageIndex_; +} + + +void +ValueInternalArray::increment( IteratorState &it ) +{ + JSON_ASSERT_MESSAGE( it.array_ && + (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ + != it.array_->size_, + "ValueInternalArray::increment(): moving iterator beyond end" ); + ++(it.currentItemIndex_); + if ( it.currentItemIndex_ == itemsPerPage ) + { + it.currentItemIndex_ = 0; + ++(it.currentPageIndex_); + } +} + + +void +ValueInternalArray::decrement( IteratorState &it ) +{ + JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ + && it.currentItemIndex_ == 0, + "ValueInternalArray::decrement(): moving iterator beyond end" ); + if ( it.currentItemIndex_ == 0 ) + { + it.currentItemIndex_ = itemsPerPage-1; + --(it.currentPageIndex_); + } + else + { + --(it.currentItemIndex_); + } +} + + +Value & +ValueInternalArray::unsafeDereference( const IteratorState &it ) +{ + return (*(it.currentPageIndex_))[it.currentItemIndex_]; +} + + +Value & +ValueInternalArray::dereference( const IteratorState &it ) +{ + JSON_ASSERT_MESSAGE( it.array_ && + (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ + < it.array_->size_, + "ValueInternalArray::dereference(): dereferencing invalid iterator" ); + return unsafeDereference( it ); +} + +void +ValueInternalArray::makeBeginIterator( IteratorState &it ) const +{ + it.array_ = const_cast<ValueInternalArray *>( this ); + it.currentItemIndex_ = 0; + it.currentPageIndex_ = pages_; +} + + +void +ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const +{ + it.array_ = const_cast<ValueInternalArray *>( this ); + it.currentItemIndex_ = index % itemsPerPage; + it.currentPageIndex_ = pages_ + index / itemsPerPage; +} + + +void +ValueInternalArray::makeEndIterator( IteratorState &it ) const +{ + makeIterator( it, size_ ); +} + + +ValueInternalArray::ValueInternalArray() + : pages_( 0 ) + , size_( 0 ) + , pageCount_( 0 ) +{ +} + + +ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) + : pages_( 0 ) + , pageCount_( 0 ) + , size_( other.size_ ) +{ + PageIndex minNewPages = other.size_ / itemsPerPage; + arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); + JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, + "ValueInternalArray::reserve(): bad reallocation" ); + IteratorState itOther; + other.makeBeginIterator( itOther ); + Value *value; + for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) + { + if ( index % itemsPerPage == 0 ) + { + PageIndex pageIndex = index / itemsPerPage; + value = arrayAllocator()->allocateArrayPage(); + pages_[pageIndex] = value; + } + new (value) Value( dereference( itOther ) ); + } +} + + +ValueInternalArray & +ValueInternalArray::operator =( const ValueInternalArray &other ) +{ + ValueInternalArray temp( other ); + swap( temp ); + return *this; +} + + +ValueInternalArray::~ValueInternalArray() +{ + // destroy all constructed items + IteratorState it; + IteratorState itEnd; + makeBeginIterator( it); + makeEndIterator( itEnd ); + for ( ; !equals(it,itEnd); increment(it) ) + { + Value *value = &dereference(it); + value->~Value(); + } + // release all pages + PageIndex lastPageIndex = size_ / itemsPerPage; + for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) + arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); + // release pages index + arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); +} + + +void +ValueInternalArray::swap( ValueInternalArray &other ) +{ + Value **tempPages = pages_; + pages_ = other.pages_; + other.pages_ = tempPages; + ArrayIndex tempSize = size_; + size_ = other.size_; + other.size_ = tempSize; + PageIndex tempPageCount = pageCount_; + pageCount_ = other.pageCount_; + other.pageCount_ = tempPageCount; +} + +void +ValueInternalArray::clear() +{ + ValueInternalArray dummy; + swap( dummy ); +} + + +void +ValueInternalArray::resize( ArrayIndex newSize ) +{ + if ( newSize == 0 ) + clear(); + else if ( newSize < size_ ) + { + IteratorState it; + IteratorState itEnd; + makeIterator( it, newSize ); + makeIterator( itEnd, size_ ); + for ( ; !equals(it,itEnd); increment(it) ) + { + Value *value = &dereference(it); + value->~Value(); + } + PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; + PageIndex lastPageIndex = size_ / itemsPerPage; + for ( ; pageIndex < lastPageIndex; ++pageIndex ) + arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); + size_ = newSize; + } + else if ( newSize > size_ ) + resolveReference( newSize ); +} + + +void +ValueInternalArray::makeIndexValid( ArrayIndex index ) +{ + // Need to enlarge page index ? + if ( index >= pageCount_ * itemsPerPage ) + { + PageIndex minNewPages = (index + 1) / itemsPerPage; + arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); + JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); + } + + // Need to allocate new pages ? + ArrayIndex nextPageIndex = + (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage + : size_; + if ( nextPageIndex <= index ) + { + PageIndex pageIndex = nextPageIndex / itemsPerPage; + PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; + for ( ; pageToAllocate-- > 0; ++pageIndex ) + pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); + } + + // Initialize all new entries + IteratorState it; + IteratorState itEnd; + makeIterator( it, size_ ); + size_ = index + 1; + makeIterator( itEnd, size_ ); + for ( ; !equals(it,itEnd); increment(it) ) + { + Value *value = &dereference(it); + new (value) Value(); // Construct a default value using placement new + } +} + +Value & +ValueInternalArray::resolveReference( ArrayIndex index ) +{ + if ( index >= size_ ) + makeIndexValid( index ); + return pages_[index/itemsPerPage][index%itemsPerPage]; +} + +Value * +ValueInternalArray::find( ArrayIndex index ) const +{ + if ( index >= size_ ) + return 0; + return &(pages_[index/itemsPerPage][index%itemsPerPage]); +} + +ValueInternalArray::ArrayIndex +ValueInternalArray::size() const +{ + return size_; +} + +int +ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) +{ + return indexOf(y) - indexOf(x); +} + + +ValueInternalArray::ArrayIndex +ValueInternalArray::indexOf( const IteratorState &iterator ) +{ + if ( !iterator.array_ ) + return ArrayIndex(-1); + return ArrayIndex( + (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage + + iterator.currentItemIndex_ ); +} + + +int +ValueInternalArray::compare( const ValueInternalArray &other ) const +{ + int sizeDiff( size_ - other.size_ ); + if ( sizeDiff != 0 ) + return sizeDiff; + + for ( ArrayIndex index =0; index < size_; ++index ) + { + int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( + other.pages_[index/itemsPerPage][index%itemsPerPage] ); + if ( diff != 0 ) + return diff; + } + return 0; +} diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/json_internalmap.inl b/lib/jsoncpp/jsoncpp/src/lib_json/json_internalmap.inl new file mode 100644 index 0000000000..19771488d6 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/json_internalmap.inl @@ -0,0 +1,607 @@ +// included by json_value.cpp +// everything is within Json namespace + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueInternalMap +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); + * This optimization is used by the fast allocator. + */ +ValueInternalLink::ValueInternalLink() + : previous_( 0 ) + , next_( 0 ) +{ +} + +ValueInternalLink::~ValueInternalLink() +{ + for ( int index =0; index < itemPerLink; ++index ) + { + if ( !items_[index].isItemAvailable() ) + { + if ( !items_[index].isMemberNameStatic() ) + free( keys_[index] ); + } + else + break; + } +} + + + +ValueMapAllocator::~ValueMapAllocator() +{ +} + +#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +class DefaultValueMapAllocator : public ValueMapAllocator +{ +public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } +}; +#else +/// @todo make this thread-safe (lock when accessign batch allocator) +class DefaultValueMapAllocator : public ValueMapAllocator +{ +public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + ValueInternalMap *map = mapsAllocator_.allocate(); + new (map) ValueInternalMap(); // placement new + return map; + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + ValueInternalMap *map = mapsAllocator_.allocate(); + new (map) ValueInternalMap( other ); // placement new + return map; + } + + virtual void destructMap( ValueInternalMap *map ) + { + if ( map ) + { + map->~ValueInternalMap(); + mapsAllocator_.release( map ); + } + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + ValueInternalLink *link = linksAllocator_.allocate(); + memset( link, 0, sizeof(ValueInternalLink) ); + return link; + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + link->~ValueInternalLink(); + linksAllocator_.release( link ); + } +private: + BatchAllocator<ValueInternalMap,1> mapsAllocator_; + BatchAllocator<ValueInternalLink,1> linksAllocator_; +}; +#endif + +static ValueMapAllocator *&mapAllocator() +{ + static DefaultValueMapAllocator defaultAllocator; + static ValueMapAllocator *mapAllocator = &defaultAllocator; + return mapAllocator; +} + +static struct DummyMapAllocatorInitializer { + DummyMapAllocatorInitializer() + { + mapAllocator(); // ensure mapAllocator() statics are initialized before main(). + } +} dummyMapAllocatorInitializer; + + + +// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. + +/* +use linked list hash map. +buckets array is a container. +linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) +value have extra state: valid, available, deleted +*/ + + +ValueInternalMap::ValueInternalMap() + : buckets_( 0 ) + , tailLink_( 0 ) + , bucketsSize_( 0 ) + , itemCount_( 0 ) +{ +} + + +ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) + : buckets_( 0 ) + , tailLink_( 0 ) + , bucketsSize_( 0 ) + , itemCount_( 0 ) +{ + reserve( other.itemCount_ ); + IteratorState it; + IteratorState itEnd; + other.makeBeginIterator( it ); + other.makeEndIterator( itEnd ); + for ( ; !equals(it,itEnd); increment(it) ) + { + bool isStatic; + const char *memberName = key( it, isStatic ); + const Value &aValue = value( it ); + resolveReference(memberName, isStatic) = aValue; + } +} + + +ValueInternalMap & +ValueInternalMap::operator =( const ValueInternalMap &other ) +{ + ValueInternalMap dummy( other ); + swap( dummy ); + return *this; +} + + +ValueInternalMap::~ValueInternalMap() +{ + if ( buckets_ ) + { + for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) + { + ValueInternalLink *link = buckets_[bucketIndex].next_; + while ( link ) + { + ValueInternalLink *linkToRelease = link; + link = link->next_; + mapAllocator()->releaseMapLink( linkToRelease ); + } + } + mapAllocator()->releaseMapBuckets( buckets_ ); + } +} + + +void +ValueInternalMap::swap( ValueInternalMap &other ) +{ + ValueInternalLink *tempBuckets = buckets_; + buckets_ = other.buckets_; + other.buckets_ = tempBuckets; + ValueInternalLink *tempTailLink = tailLink_; + tailLink_ = other.tailLink_; + other.tailLink_ = tempTailLink; + BucketIndex tempBucketsSize = bucketsSize_; + bucketsSize_ = other.bucketsSize_; + other.bucketsSize_ = tempBucketsSize; + BucketIndex tempItemCount = itemCount_; + itemCount_ = other.itemCount_; + other.itemCount_ = tempItemCount; +} + + +void +ValueInternalMap::clear() +{ + ValueInternalMap dummy; + swap( dummy ); +} + + +ValueInternalMap::BucketIndex +ValueInternalMap::size() const +{ + return itemCount_; +} + +bool +ValueInternalMap::reserveDelta( BucketIndex growth ) +{ + return reserve( itemCount_ + growth ); +} + +bool +ValueInternalMap::reserve( BucketIndex newItemCount ) +{ + if ( !buckets_ && newItemCount > 0 ) + { + buckets_ = mapAllocator()->allocateMapBuckets( 1 ); + bucketsSize_ = 1; + tailLink_ = &buckets_[0]; + } +// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; + return true; +} + + +const Value * +ValueInternalMap::find( const char *key ) const +{ + if ( !bucketsSize_ ) + return 0; + HashKey hashedKey = hash( key ); + BucketIndex bucketIndex = hashedKey % bucketsSize_; + for ( const ValueInternalLink *current = &buckets_[bucketIndex]; + current != 0; + current = current->next_ ) + { + for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( current->items_[index].isItemAvailable() ) + return 0; + if ( strcmp( key, current->keys_[index] ) == 0 ) + return ¤t->items_[index]; + } + } + return 0; +} + + +Value * +ValueInternalMap::find( const char *key ) +{ + const ValueInternalMap *constThis = this; + return const_cast<Value *>( constThis->find( key ) ); +} + + +Value & +ValueInternalMap::resolveReference( const char *key, + bool isStatic ) +{ + HashKey hashedKey = hash( key ); + if ( bucketsSize_ ) + { + BucketIndex bucketIndex = hashedKey % bucketsSize_; + ValueInternalLink **previous = 0; + BucketIndex index; + for ( ValueInternalLink *current = &buckets_[bucketIndex]; + current != 0; + previous = ¤t->next_, current = current->next_ ) + { + for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( current->items_[index].isItemAvailable() ) + return setNewItem( key, isStatic, current, index ); + if ( strcmp( key, current->keys_[index] ) == 0 ) + return current->items_[index]; + } + } + } + + reserveDelta( 1 ); + return unsafeAdd( key, isStatic, hashedKey ); +} + + +void +ValueInternalMap::remove( const char *key ) +{ + HashKey hashedKey = hash( key ); + if ( !bucketsSize_ ) + return; + BucketIndex bucketIndex = hashedKey % bucketsSize_; + for ( ValueInternalLink *link = &buckets_[bucketIndex]; + link != 0; + link = link->next_ ) + { + BucketIndex index; + for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( link->items_[index].isItemAvailable() ) + return; + if ( strcmp( key, link->keys_[index] ) == 0 ) + { + doActualRemove( link, index, bucketIndex ); + return; + } + } + } +} + +void +ValueInternalMap::doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ) +{ + // find last item of the bucket and swap it with the 'removed' one. + // set removed items flags to 'available'. + // if last page only contains 'available' items, then desallocate it (it's empty) + ValueInternalLink *&lastLink = getLastLinkInBucket( index ); + BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 + for ( ; + lastItemIndex < ValueInternalLink::itemPerLink; + ++lastItemIndex ) // may be optimized with dicotomic search + { + if ( lastLink->items_[lastItemIndex].isItemAvailable() ) + break; + } + + BucketIndex lastUsedIndex = lastItemIndex - 1; + Value *valueToDelete = &link->items_[index]; + Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; + if ( valueToDelete != valueToPreserve ) + valueToDelete->swap( *valueToPreserve ); + if ( lastUsedIndex == 0 ) // page is now empty + { // remove it from bucket linked list and delete it. + ValueInternalLink *linkPreviousToLast = lastLink->previous_; + if ( linkPreviousToLast != 0 ) // can not deleted bucket link. + { + mapAllocator()->releaseMapLink( lastLink ); + linkPreviousToLast->next_ = 0; + lastLink = linkPreviousToLast; + } + } + else + { + Value dummy; + valueToPreserve->swap( dummy ); // restore deleted to default Value. + valueToPreserve->setItemUsed( false ); + } + --itemCount_; +} + + +ValueInternalLink *& +ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) +{ + if ( bucketIndex == bucketsSize_ - 1 ) + return tailLink_; + ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; + if ( !previous ) + previous = &buckets_[bucketIndex]; + return previous; +} + + +Value & +ValueInternalMap::setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ) +{ + char *duplicatedKey = valueAllocator()->makeMemberName( key ); + ++itemCount_; + link->keys_[index] = duplicatedKey; + link->items_[index].setItemUsed(); + link->items_[index].setMemberNameIsStatic( isStatic ); + return link->items_[index]; // items already default constructed. +} + + +Value & +ValueInternalMap::unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ) +{ + JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); + BucketIndex bucketIndex = hashedKey % bucketsSize_; + ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); + ValueInternalLink *link = previousLink; + BucketIndex index; + for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) + { + if ( link->items_[index].isItemAvailable() ) + break; + } + if ( index == ValueInternalLink::itemPerLink ) // need to add a new page + { + ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); + index = 0; + link->next_ = newLink; + previousLink = newLink; + link = newLink; + } + return setNewItem( key, isStatic, link, index ); +} + + +ValueInternalMap::HashKey +ValueInternalMap::hash( const char *key ) const +{ + HashKey hash = 0; + while ( *key ) + hash += *key++ * 37; + return hash; +} + + +int +ValueInternalMap::compare( const ValueInternalMap &other ) const +{ + int sizeDiff( itemCount_ - other.itemCount_ ); + if ( sizeDiff != 0 ) + return sizeDiff; + // Strict order guaranty is required. Compare all keys FIRST, then compare values. + IteratorState it; + IteratorState itEnd; + makeBeginIterator( it ); + makeEndIterator( itEnd ); + for ( ; !equals(it,itEnd); increment(it) ) + { + if ( !other.find( key( it ) ) ) + return 1; + } + + // All keys are equals, let's compare values + makeBeginIterator( it ); + for ( ; !equals(it,itEnd); increment(it) ) + { + const Value *otherValue = other.find( key( it ) ); + int valueDiff = value(it).compare( *otherValue ); + if ( valueDiff != 0 ) + return valueDiff; + } + return 0; +} + + +void +ValueInternalMap::makeBeginIterator( IteratorState &it ) const +{ + it.map_ = const_cast<ValueInternalMap *>( this ); + it.bucketIndex_ = 0; + it.itemIndex_ = 0; + it.link_ = buckets_; +} + + +void +ValueInternalMap::makeEndIterator( IteratorState &it ) const +{ + it.map_ = const_cast<ValueInternalMap *>( this ); + it.bucketIndex_ = bucketsSize_; + it.itemIndex_ = 0; + it.link_ = 0; +} + + +bool +ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) +{ + return x.map_ == other.map_ + && x.bucketIndex_ == other.bucketIndex_ + && x.link_ == other.link_ + && x.itemIndex_ == other.itemIndex_; +} + + +void +ValueInternalMap::incrementBucket( IteratorState &iterator ) +{ + ++iterator.bucketIndex_; + JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, + "ValueInternalMap::increment(): attempting to iterate beyond end." ); + if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) + iterator.link_ = 0; + else + iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); + iterator.itemIndex_ = 0; +} + + +void +ValueInternalMap::increment( IteratorState &iterator ) +{ + JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); + ++iterator.itemIndex_; + if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) + { + JSON_ASSERT_MESSAGE( iterator.link_ != 0, + "ValueInternalMap::increment(): attempting to iterate beyond end." ); + iterator.link_ = iterator.link_->next_; + if ( iterator.link_ == 0 ) + incrementBucket( iterator ); + } + else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) + { + incrementBucket( iterator ); + } +} + + +void +ValueInternalMap::decrement( IteratorState &iterator ) +{ + if ( iterator.itemIndex_ == 0 ) + { + JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); + if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) + { + JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); + --(iterator.bucketIndex_); + } + iterator.link_ = iterator.link_->previous_; + iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; + } +} + + +const char * +ValueInternalMap::key( const IteratorState &iterator ) +{ + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); + return iterator.link_->keys_[iterator.itemIndex_]; +} + +const char * +ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) +{ + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); + isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); + return iterator.link_->keys_[iterator.itemIndex_]; +} + + +Value & +ValueInternalMap::value( const IteratorState &iterator ) +{ + JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); + return iterator.link_->items_[iterator.itemIndex_]; +} + + +int +ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) +{ + int offset = 0; + IteratorState it = x; + while ( !equals( it, y ) ) + increment( it ); + return offset; +} diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/json_reader.cpp b/lib/jsoncpp/jsoncpp/src/lib_json/json_reader.cpp new file mode 100644 index 0000000000..4eb2d11fd3 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/json_reader.cpp @@ -0,0 +1,885 @@ +#include <json/reader.h> +#include <json/value.h> +#include <utility> +#include <cstdio> +#include <cassert> +#include <cstring> +#include <iostream> +#include <stdexcept> + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_( true ) + , strictRoot_( false ) +{ +} + + +Features +Features::all() +{ + return Features(); +} + + +Features +Features::strictMode() +{ + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4; +} + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; +} + + +static bool +containsNewLine( Reader::Location begin, + Reader::Location end ) +{ + for ( ;begin < end; ++begin ) + if ( *begin == '\n' || *begin == '\r' ) + return true; + return false; +} + +static std::string codePointToUTF8(unsigned int cp) +{ + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) + { + result.resize(1); + result[0] = static_cast<char>(cp); + } + else if (cp <= 0x7FF) + { + result.resize(2); + result[1] = static_cast<char>(0x80 | (0x3f & cp)); + result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); + } + else if (cp <= 0xFFFF) + { + result.resize(3); + result[2] = static_cast<char>(0x80 | (0x3f & cp)); + result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); + result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); + } + else if (cp <= 0x10FFFF) + { + result.resize(4); + result[3] = static_cast<char>(0x80 | (0x3f & cp)); + result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : features_( Features::all() ) +{ +} + + +Reader::Reader( const Features &features ) + : features_( features ) +{ +} + + +bool +Reader::parse( const std::string &document, + Value &root, + bool collectComments ) +{ + document_ = document; + const char *begin = document_.c_str(); + const char *end = begin + document_.length(); + return parse( begin, end, root, collectComments ); +} + + +bool +Reader::parse( std::istream& sin, + Value &root, + bool collectComments ) +{ + //std::istream_iterator<char> begin(sin); + //std::istream_iterator<char> end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, (char)EOF); + return parse( doc, root, collectComments ); +} + +bool +Reader::parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments ) +{ + if ( !features_.allowComments_ ) + { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while ( !nodes_.empty() ) + nodes_.pop(); + nodes_.push( &root ); + + bool successful = readValue(); + Token token; + skipCommentTokens( token ); + if ( collectComments_ && !commentsBefore_.empty() ) + root.setComment( commentsBefore_, commentAfter ); + if ( features_.strictRoot_ ) + { + if ( !root.isArray() && !root.isObject() ) + { + // Set error location to start of doc, ideally should be first token found in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( "A valid JSON document must be either an array or an object value.", + token ); + return false; + } + } + return successful; +} + + +bool +Reader::readValue() +{ + Token token; + skipCommentTokens( token ); + bool successful = true; + + if ( collectComments_ && !commentsBefore_.empty() ) + { + currentValue().setComment( commentsBefore_, commentBefore ); + commentsBefore_ = ""; + } + + + switch ( token.type_ ) + { + case tokenObjectBegin: + successful = readObject( token ); + break; + case tokenArrayBegin: + successful = readArray( token ); + break; + case tokenNumber: + successful = decodeNumber( token ); + break; + case tokenString: + successful = decodeString( token ); + break; + case tokenTrue: + currentValue() = true; + break; + case tokenFalse: + currentValue() = false; + break; + case tokenNull: + currentValue() = Value(); + break; + default: + return addError( "Syntax error: value, object or array expected.", token ); + } + + if ( collectComments_ ) + { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + + +void +Reader::skipCommentTokens( Token &token ) +{ + if ( features_.allowComments_ ) + { + do + { + readToken( token ); + } + while ( token.type_ == tokenComment ); + } + else + { + readToken( token ); + } +} + + +bool +Reader::expectToken( TokenType type, Token &token, const char *message ) +{ + readToken( token ); + if ( token.type_ != type ) + return addError( message, token ); + return true; +} + + +bool +Reader::readToken( Token &token ) +{ + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch ( c ) + { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match( "rue", 3 ); + break; + case 'f': + token.type_ = tokenFalse; + ok = match( "alse", 4 ); + break; + case 'n': + token.type_ = tokenNull; + ok = match( "ull", 3 ); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if ( !ok ) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + + +void +Reader::skipSpaces() +{ + while ( current_ != end_ ) + { + Char c = *current_; + if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) + ++current_; + else + break; + } +} + + +bool +Reader::match( Location pattern, + int patternLength ) +{ + if ( end_ - current_ < patternLength ) + return false; + int index = patternLength; + while ( index-- ) + if ( current_[index] != pattern[index] ) + return false; + current_ += patternLength; + return true; +} + + +bool +Reader::readComment() +{ + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if ( c == '*' ) + successful = readCStyleComment(); + else if ( c == '/' ) + successful = readCppStyleComment(); + if ( !successful ) + return false; + + if ( collectComments_ ) + { + CommentPlacement placement = commentBefore; + if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) + { + if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) + placement = commentAfterOnSameLine; + } + + addComment( commentBegin, current_, placement ); + } + return true; +} + + +void +Reader::addComment( Location begin, + Location end, + CommentPlacement placement ) +{ + assert( collectComments_ ); + if ( placement == commentAfterOnSameLine ) + { + assert( lastValue_ != 0 ); + lastValue_->setComment( std::string( begin, end ), placement ); + } + else + { + if ( !commentsBefore_.empty() ) + commentsBefore_ += "\n"; + commentsBefore_ += std::string( begin, end ); + } +} + + +bool +Reader::readCStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '*' && *current_ == '/' ) + break; + } + return getNextChar() == '/'; +} + + +bool +Reader::readCppStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '\r' || c == '\n' ) + break; + } + return true; +} + + +void +Reader::readNumber() +{ + while ( current_ != end_ ) + { + if ( !(*current_ >= '0' && *current_ <= '9') && + !in( *current_, '.', 'e', 'E', '+', '-' ) ) + break; + ++current_; + } +} + +bool +Reader::readString() +{ + Char c = 0; + while ( current_ != end_ ) + { + c = getNextChar(); + if ( c == '\\' ) + getNextChar(); + else if ( c == '"' ) + break; + } + return c == '"'; +} + + +bool +Reader::readObject( Token &tokenStart ) +{ + Token tokenName; + std::string name; + currentValue() = Value( objectValue ); + while ( readToken( tokenName ) ) + { + bool initialTokenOk = true; + while ( tokenName.type_ == tokenComment && initialTokenOk ) + initialTokenOk = readToken( tokenName ); + if ( !initialTokenOk ) + break; + if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object + return true; + if ( tokenName.type_ != tokenString ) + break; + + name = ""; + if ( !decodeString( tokenName, name ) ) + return recoverFromError( tokenObjectEnd ); + + Token colon; + if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) + { + return addErrorAndRecover( "Missing ':' after object member name", + colon, + tokenObjectEnd ); + } + Value &value = currentValue()[ name ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenObjectEnd ); + + Token comma; + if ( !readToken( comma ) + || ( comma.type_ != tokenObjectEnd && + comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment ) ) + { + return addErrorAndRecover( "Missing ',' or '}' in object declaration", + comma, + tokenObjectEnd ); + } + bool finalizeTokenOk = true; + while ( comma.type_ == tokenComment && + finalizeTokenOk ) + finalizeTokenOk = readToken( comma ); + if ( comma.type_ == tokenObjectEnd ) + return true; + } + return addErrorAndRecover( "Missing '}' or object member name", + tokenName, + tokenObjectEnd ); +} + + +bool +Reader::readArray( Token &tokenStart ) +{ + currentValue() = Value( arrayValue ); + skipSpaces(); + if ( *current_ == ']' ) // empty array + { + Token endArray; + readToken( endArray ); + return true; + } + int index = 0; + while ( true ) + { + Value &value = currentValue()[ index++ ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenArrayEnd ); + + Token token; + // Accept Comment after last item in the array. + ok = readToken( token ); + while ( token.type_ == tokenComment && ok ) + { + ok = readToken( token ); + } + bool badTokenType = ( token.type_ == tokenArraySeparator && + token.type_ == tokenArrayEnd ); + if ( !ok || badTokenType ) + { + return addErrorAndRecover( "Missing ',' or ']' in array declaration", + token, + tokenArrayEnd ); + } + if ( token.type_ == tokenArrayEnd ) + break; + } + return true; +} + + +bool +Reader::decodeNumber( Token &token ) +{ + bool isDouble = false; + for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) + { + isDouble = isDouble + || in( *inspect, '.', 'e', 'E', '+' ) + || ( *inspect == '-' && inspect != token.start_ ); + } + if ( isDouble ) + return decodeDouble( token ); + Location current = token.start_; + bool isNegative = *current == '-'; + if ( isNegative ) + ++current; + Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) + : Value::maxUInt) / 10; + Value::UInt value = 0; + while ( current < token.end_ ) + { + Char c = *current++; + if ( c < '0' || c > '9' ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + if ( value >= threshold ) + return decodeDouble( token ); + value = value * 10 + Value::UInt(c - '0'); + } + if ( isNegative ) + currentValue() = -Value::Int( value ); + else if ( value <= Value::UInt(Value::maxInt) ) + currentValue() = Value::Int( value ); + else + currentValue() = value; + return true; +} + + +bool +Reader::decodeDouble( Token &token ) +{ + double value = 0; + const int bufferSize = 32; + int count; + int length = int(token.end_ - token.start_); + if ( length <= bufferSize ) + { + Char buffer[bufferSize]; + memcpy( buffer, token.start_, length ); + buffer[length] = 0; + count = sscanf( buffer, "%lf", &value ); + } + else + { + std::string buffer( token.start_, token.end_ ); + count = sscanf( buffer.c_str(), "%lf", &value ); + } + + if ( count != 1 ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + currentValue() = value; + return true; +} + + +bool +Reader::decodeString( Token &token ) +{ + std::string decoded; + if ( !decodeString( token, decoded ) ) + return false; + currentValue() = decoded; + return true; +} + + +bool +Reader::decodeString( Token &token, std::string &decoded ) +{ + decoded.reserve( token.end_ - token.start_ - 2 ); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while ( current != end ) + { + Char c = *current++; + if ( c == '"' ) + break; + else if ( c == '\\' ) + { + if ( current == end ) + return addError( "Empty escape sequence in string", token, current ); + Char escape = *current++; + switch ( escape ) + { + case '"': decoded += '"'; break; + case '/': decoded += '/'; break; + case '\\': decoded += '\\'; break; + case 'b': decoded += '\b'; break; + case 'f': decoded += '\f'; break; + case 'n': decoded += '\n'; break; + case 'r': decoded += '\r'; break; + case 't': decoded += '\t'; break; + case 'u': + { + unsigned int unicode; + if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) + return false; + decoded += codePointToUTF8(unicode); + } + break; + default: + return addError( "Bad escape sequence in string", token, current ); + } + } + else + { + decoded += c; + } + } + return true; +} + +bool +Reader::decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + + if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) + { + // surrogate pairs + if (end - current < 6) + return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++)== 'u') + { + if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) + { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } + else + return false; + } + else + return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); + } + return true; +} + +bool +Reader::decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + if ( end - current < 4 ) + return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); + unicode = 0; + for ( int index =0; index < 4; ++index ) + { + Char c = *current++; + unicode *= 16; + if ( c >= '0' && c <= '9' ) + unicode += c - '0'; + else if ( c >= 'a' && c <= 'f' ) + unicode += c - 'a' + 10; + else if ( c >= 'A' && c <= 'F' ) + unicode += c - 'A' + 10; + else + return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); + } + return true; +} + + +bool +Reader::addError( const std::string &message, + Token &token, + Location extra ) +{ + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back( info ); + return false; +} + + +bool +Reader::recoverFromError( TokenType skipUntilToken ) +{ + int errorCount = int(errors_.size()); + Token skip; + while ( true ) + { + if ( !readToken(skip) ) + errors_.resize( errorCount ); // discard errors caused by recovery + if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) + break; + } + errors_.resize( errorCount ); + return false; +} + + +bool +Reader::addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ) +{ + addError( message, token ); + return recoverFromError( skipUntilToken ); +} + + +Value & +Reader::currentValue() +{ + return *(nodes_.top()); +} + + +Reader::Char +Reader::getNextChar() +{ + if ( current_ == end_ ) + return 0; + return *current_++; +} + + +void +Reader::getLocationLineAndColumn( Location location, + int &line, + int &column ) const +{ + Location current = begin_; + Location lastLineStart = current; + line = 0; + while ( current < location && current != end_ ) + { + Char c = *current++; + if ( c == '\r' ) + { + if ( *current == '\n' ) + ++current; + lastLineStart = current; + ++line; + } + else if ( c == '\n' ) + { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + + +std::string +Reader::getLocationLineAndColumn( Location location ) const +{ + int line, column; + getLocationLineAndColumn( location, line, column ); + char buffer[18+16+16+1]; + sprintf( buffer, "Line %d, Column %d", line, column ); + return buffer; +} + + +std::string +Reader::getFormatedErrorMessages() const +{ + std::string formattedMessage; + for ( Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError ) + { + const ErrorInfo &error = *itError; + formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if ( error.extra_ ) + formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; + } + return formattedMessage; +} + + +std::istream& operator>>( std::istream &sin, Value &root ) +{ + Json::Reader reader; + bool ok = reader.parse(sin, root, true); + //JSON_ASSERT( ok ); + if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); + return sin; +} + + +} // namespace Json diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/json_value.cpp b/lib/jsoncpp/jsoncpp/src/lib_json/json_value.cpp new file mode 100644 index 0000000000..734bf16252 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/json_value.cpp @@ -0,0 +1,1703 @@ +#include <iostream> +#include <json/value.h> +#include <json/writer.h> +#include <utility> +#include <stdexcept> +#include <cstring> +#include <cassert> +#ifdef JSON_USE_CPPTL +# include <cpptl/conststring.h> +#endif +#include <cstddef> // size_t +#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +# include "json_batchallocator.h" +#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR + +#define JSON_ASSERT_UNREACHABLE assert( false ) +#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw +#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); + +namespace Json { + +const Value Value::null; +const Value::Int Value::minInt = Value::Int( ~(Value::UInt(-1)/2) ); +const Value::Int Value::maxInt = Value::Int( Value::UInt(-1)/2 ); +const Value::UInt Value::maxUInt = Value::UInt(-1); + +// A "safe" implementation of strdup. Allow null pointer to be passed. +// Also avoid warning on msvc80. +// +//inline char *safeStringDup( const char *czstring ) +//{ +// if ( czstring ) +// { +// const size_t length = (unsigned int)( strlen(czstring) + 1 ); +// char *newString = static_cast<char *>( malloc( length ) ); +// memcpy( newString, czstring, length ); +// return newString; +// } +// return 0; +//} +// +//inline char *safeStringDup( const std::string &str ) +//{ +// if ( !str.empty() ) +// { +// const size_t length = str.length(); +// char *newString = static_cast<char *>( malloc( length + 1 ) ); +// memcpy( newString, str.c_str(), length ); +// newString[length] = 0; +// return newString; +// } +// return 0; +//} + +ValueAllocator::~ValueAllocator() +{ +} + +class DefaultValueAllocator : public ValueAllocator +{ +public: + virtual ~DefaultValueAllocator() + { + } + + virtual char *makeMemberName( const char *memberName ) + { + return duplicateStringValue( memberName ); + } + + virtual void releaseMemberName( char *memberName ) + { + releaseStringValue( memberName ); + } + + virtual char *duplicateStringValue( const char *value, + unsigned int length = unknown ) + { + //@todo invesgate this old optimization + //if ( !value || value[0] == 0 ) + // return 0; + + if ( length == unknown ) + length = (unsigned int)strlen(value); + char *newString = static_cast<char *>( malloc( length + 1 ) ); + memcpy( newString, value, length ); + newString[length] = 0; + return newString; + } + + virtual void releaseStringValue( char *value ) + { + if ( value ) + free( value ); + } +}; + +static ValueAllocator *&valueAllocator() +{ + static DefaultValueAllocator defaultAllocator; + static ValueAllocator *valueAllocator = &defaultAllocator; + return valueAllocator; +} + +static struct DummyValueAllocatorInitializer { + DummyValueAllocatorInitializer() + { + valueAllocator(); // ensure valueAllocator() statics are initialized before main(). + } +} dummyValueAllocatorInitializer; + + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#ifdef JSON_VALUE_USE_INTERNAL_MAP +# include "json_internalarray.inl" +# include "json_internalmap.inl" +#endif // JSON_VALUE_USE_INTERNAL_MAP + +# include "json_valueiterator.inl" + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + + +Value::CommentInfo::CommentInfo() + : comment_( 0 ) +{ +} + +Value::CommentInfo::~CommentInfo() +{ + if ( comment_ ) + valueAllocator()->releaseStringValue( comment_ ); +} + + +void +Value::CommentInfo::setComment( const char *text ) +{ + if ( comment_ ) + valueAllocator()->releaseStringValue( comment_ ); + JSON_ASSERT( text ); + JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = valueAllocator()->duplicateStringValue( text ); +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +# ifndef JSON_VALUE_USE_INTERNAL_MAP + +// Notes: index_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString( int index ) + : cstr_( 0 ) + , index_( index ) +{ +} + +Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) + : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) + : cstr ) + , index_( allocate ) +{ +} + +Value::CZString::CZString( const CZString &other ) +: cstr_( other.index_ != noDuplication && other.cstr_ != 0 + ? valueAllocator()->makeMemberName( other.cstr_ ) + : other.cstr_ ) + , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) + : other.index_ ) +{ +} + +Value::CZString::~CZString() +{ + if ( cstr_ && index_ == duplicate ) + valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) ); +} + +void +Value::CZString::swap( CZString &other ) +{ + std::swap( cstr_, other.cstr_ ); + std::swap( index_, other.index_ ); +} + +Value::CZString & +Value::CZString::operator =( const CZString &other ) +{ + CZString temp( other ); + swap( temp ); + return *this; +} + +bool +Value::CZString::operator<( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) < 0; + return index_ < other.index_; +} + +bool +Value::CZString::operator==( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) == 0; + return index_ == other.index_; +} + + +int +Value::CZString::index() const +{ + return index_; +} + + +const char * +Value::CZString::c_str() const +{ + return cstr_; +} + +bool +Value::CZString::isStaticString() const +{ + return index_ == noDuplication; +} + +#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value( ValueType type ) + : type_( type ) + , allocated_( 0 ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type ) + { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArray(); + break; + case objectValue: + value_.map_ = mapAllocator()->newMap(); + break; +#endif + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + + +Value::Value( Int value ) + : type_( intValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.int_ = value; +} + + +Value::Value( UInt value ) + : type_( uintValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.uint_ = value; +} + +Value::Value( double value ) + : type_( realValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.real_ = value; +} + +Value::Value( const char *value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value ); +} + +Value::Value( const std::string &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), + (unsigned int)value.length() ); + +} + +Value::Value( const StaticString &value ) + : type_( stringValue ) + , allocated_( false ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = const_cast<char *>( value.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +Value::Value( const CppTL::ConstString &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); +} +# endif + +Value::Value( bool value ) + : type_( booleanValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.bool_ = value; +} + + +Value::Value( const Value &other ) + : type_( other.type_ ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if ( other.value_.string_ ) + { + value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); + allocated_ = true; + } + else + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues( *other.value_.map_ ); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); + break; + case objectValue: + value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + if ( other.comments_ ) + { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) + { + const CommentInfo &otherComment = other.comments_[comment]; + if ( otherComment.comment_ ) + comments_[comment].setComment( otherComment.comment_ ); + } + } +} + + +Value::~Value() +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if ( allocated_ ) + valueAllocator()->releaseStringValue( value_.string_ ); + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + delete value_.map_; + break; +#else + case arrayValue: + arrayAllocator()->destructArray( value_.array_ ); + break; + case objectValue: + mapAllocator()->destructMap( value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + + if ( comments_ ) + delete[] comments_; +} + +Value & +Value::operator=( const Value &other ) +{ + Value temp( other ); + swap( temp ); + return *this; +} + +void +Value::swap( Value &other ) +{ + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap( value_, other.value_ ); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2; +} + +ValueType +Value::type() const +{ + return type_; +} + + +int +Value::compare( const Value &other ) +{ + /* + int typeDelta = other.type_ - type_; + switch ( type_ ) + { + case nullValue: + + return other.type_ == type_; + case intValue: + if ( other.type_.isNumeric() + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue, + break; + case arrayValue: + delete value_.array_; + break; + case objectValue: + delete value_.map_; + default: + JSON_ASSERT_UNREACHABLE; + } + */ + return 0; // unreachable +} + +bool +Value::operator <( const Value &other ) const +{ + int typeDelta = type_ - other.type_; + if ( typeDelta ) + return typeDelta < 0 ? true : false; + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + return ( value_.string_ == 0 && other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) < 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + { + int delta = int( value_.map_->size() - other.value_.map_->size() ); + if ( delta ) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) < 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) < 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable +} + +bool +Value::operator <=( const Value &other ) const +{ + return !(other > *this); +} + +bool +Value::operator >=( const Value &other ) const +{ + return !(*this < other); +} + +bool +Value::operator >( const Value &other ) const +{ + return other < *this; +} + +bool +Value::operator ==( const Value &other ) const +{ + //if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if ( type_ != temp ) + return false; + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + return ( value_.string_ == other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) == 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() + && (*value_.map_) == (*other.value_.map_); +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) == 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) == 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable +} + +bool +Value::operator !=( const Value &other ) const +{ + return !( *this == other ); +} + +const char * +Value::asCString() const +{ + JSON_ASSERT( type_ == stringValue ); + return value_.string_; +} + + +std::string +Value::asString() const +{ + switch ( type_ ) + { + case nullValue: + return ""; + case stringValue: + return value_.string_ ? value_.string_ : ""; + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + case uintValue: + case realValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return ""; // unreachable +} + +# ifdef JSON_USE_CPPTL +CppTL::ConstString +Value::asConstString() const +{ + return CppTL::ConstString( asString().c_str() ); +} +# endif + +Value::Int +Value::asInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + return value_.int_; + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); + return Int( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +Value::UInt +Value::asUInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); + return UInt( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +double +Value::asDouble() const +{ + switch ( type_ ) + { + case nullValue: + return 0.0; + case intValue: + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + return value_.real_; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +bool +Value::asBool() const +{ + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + case uintValue: + return value_.int_ != 0; + case realValue: + return value_.real_ != 0.0; + case booleanValue: + return value_.bool_; + case stringValue: + return value_.string_ && value_.string_[0] != 0; + case arrayValue: + case objectValue: + return value_.map_->size() != 0; + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +bool +Value::isConvertibleTo( ValueType other ) const +{ + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return ( other == nullValue && value_.int_ == 0 ) + || other == intValue + || ( other == uintValue && value_.int_ >= 0 ) + || other == realValue + || other == stringValue + || other == booleanValue; + case uintValue: + return ( other == nullValue && value_.uint_ == 0 ) + || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case realValue: + return ( other == nullValue && value_.real_ == 0.0 ) + || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) + || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) + || other == realValue + || other == stringValue + || other == booleanValue; + case booleanValue: + return ( other == nullValue && value_.bool_ == false ) + || other == intValue + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case stringValue: + return other == stringValue + || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); + case arrayValue: + return other == arrayValue + || ( other == nullValue && value_.map_->size() == 0 ); + case objectValue: + return other == objectValue + || ( other == nullValue && value_.map_->size() == 0 ); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +/// Number of values in array or object +Value::UInt +Value::size() const +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: // size of the array is highest index + 1 + if ( !value_.map_->empty() ) + { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index()+1; + } + return 0; + case objectValue: + return Int( value_.map_->size() ); +#else + case arrayValue: + return Int( value_.array_->size() ); + case objectValue: + return Int( value_.map_->size() ); +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +bool +Value::empty() const +{ + if ( isNull() || isArray() || isObject() ) + return size() == 0u; + else + return false; +} + + +bool +Value::operator!() const +{ + return isNull(); +} + + +void +Value::clear() +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); + + switch ( type_ ) + { +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_->clear(); + break; +#else + case arrayValue: + value_.array_->clear(); + break; + case objectValue: + value_.map_->clear(); + break; +#endif + default: + break; + } +} + +void +Value::resize( UInt newSize ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + UInt oldSize = size(); + if ( newSize == 0 ) + clear(); + else if ( newSize > oldSize ) + (*this)[ newSize - 1 ]; + else + { + for ( UInt index = newSize; index < oldSize; ++index ) + value_.map_->erase( index ); + assert( size() == newSize ); + } +#else + value_.array_->resize( newSize ); +#endif +} + + +Value & +Value::operator[]( UInt index ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::iterator it = value_.map_->lower_bound( key ); + if ( it != value_.map_->end() && (*it).first == key ) + return (*it).second; + + ObjectValues::value_type defaultValue( key, null ); + it = value_.map_->insert( it, defaultValue ); + return (*it).second; +#else + return value_.array_->resolveReference( index ); +#endif +} + + +const Value & +Value::operator[]( UInt index ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::const_iterator it = value_.map_->find( key ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + Value *value = value_.array_->find( index ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const char *key ) +{ + return resolveReference( key, false ); +} + + +Value & +Value::resolveReference( const char *key, + bool isStatic ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + *this = Value( objectValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, isStatic ? CZString::noDuplication + : CZString::duplicateOnCopy ); + ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); + if ( it != value_.map_->end() && (*it).first == actualKey ) + return (*it).second; + + ObjectValues::value_type defaultValue( actualKey, null ); + it = value_.map_->insert( it, defaultValue ); + Value &value = (*it).second; + return value; +#else + return value_.map_->resolveReference( key, isStatic ); +#endif +} + + +Value +Value::get( UInt index, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[index]); + return value == &null ? defaultValue : *value; +} + + +bool +Value::isValidIndex( UInt index ) const +{ + return index < size(); +} + + + +const Value & +Value::operator[]( const char *key ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::const_iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + const Value *value = value_.map_->find( key ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const std::string &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const std::string &key ) const +{ + return (*this)[ key.c_str() ]; +} + +Value & +Value::operator[]( const StaticString &key ) +{ + return resolveReference( key, true ); +} + + +# ifdef JSON_USE_CPPTL +Value & +Value::operator[]( const CppTL::ConstString &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const CppTL::ConstString &key ) const +{ + return (*this)[ key.c_str() ]; +} +# endif + + +Value & +Value::append( const Value &value ) +{ + return (*this)[size()] = value; +} + + +Value +Value::get( const char *key, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[key]); + return value == &null ? defaultValue : *value; +} + + +Value +Value::get( const std::string &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} + +Value +Value::removeMember( const char* key ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + Value old(it->second); + value_.map_->erase(it); + return old; +#else + Value *value = value_.map_->find( key ); + if (value){ + Value old(*value); + value_.map_.remove( key ); + return old; + } else { + return null; + } +#endif +} + +Value +Value::removeMember( const std::string &key ) +{ + return removeMember( key.c_str() ); +} + +# ifdef JSON_USE_CPPTL +Value +Value::get( const CppTL::ConstString &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} +# endif + +bool +Value::isMember( const char *key ) const +{ + const Value *value = &((*this)[key]); + return value != &null; +} + + +bool +Value::isMember( const std::string &key ) const +{ + return isMember( key.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +bool +Value::isMember( const CppTL::ConstString &key ) const +{ + return isMember( key.c_str() ); +} +#endif + +Value::Members +Value::getMemberNames() const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return Value::Members(); + Members members; + members.reserve( value_.map_->size() ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for ( ; it != itEnd; ++it ) + members.push_back( std::string( (*it).first.c_str() ) ); +#else + ValueInternalMap::IteratorState it; + ValueInternalMap::IteratorState itEnd; + value_.map_->makeBeginIterator( it ); + value_.map_->makeEndIterator( itEnd ); + for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) + members.push_back( std::string( ValueInternalMap::key( it ) ) ); +#endif + return members; +} +// +//# ifdef JSON_USE_CPPTL +//EnumMemberNames +//Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +//EnumValues +//Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type<const Value &>() ); +// return EnumValues(); +//} +// +//# endif + + +bool +Value::isNull() const +{ + return type_ == nullValue; +} + + +bool +Value::isBool() const +{ + return type_ == booleanValue; +} + + +bool +Value::isInt() const +{ + return type_ == intValue; +} + + +bool +Value::isUInt() const +{ + return type_ == uintValue; +} + + +bool +Value::isIntegral() const +{ + return type_ == intValue + || type_ == uintValue + || type_ == booleanValue; +} + + +bool +Value::isDouble() const +{ + return type_ == realValue; +} + + +bool +Value::isNumeric() const +{ + return isIntegral() || isDouble(); +} + + +bool +Value::isString() const +{ + return type_ == stringValue; +} + + +bool +Value::isArray() const +{ + return type_ == nullValue || type_ == arrayValue; +} + + +bool +Value::isObject() const +{ + return type_ == nullValue || type_ == objectValue; +} + + +void +Value::setComment( const char *comment, + CommentPlacement placement ) +{ + if ( !comments_ ) + comments_ = new CommentInfo[numberOfCommentPlacement]; + comments_[placement].setComment( comment ); +} + + +void +Value::setComment( const std::string &comment, + CommentPlacement placement ) +{ + setComment( comment.c_str(), placement ); +} + + +bool +Value::hasComment( CommentPlacement placement ) const +{ + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +std::string +Value::getComment( CommentPlacement placement ) const +{ + if ( hasComment(placement) ) + return comments_[placement].comment_; + return ""; +} + + +std::string +Value::toStyledString() const +{ + StyledWriter writer; + return writer.write( *this ); +} + + +Value::const_iterator +Value::begin() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + +Value::const_iterator +Value::end() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + + +Value::iterator +Value::begin() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return iterator(); +} + +Value::iterator +Value::end() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return iterator(); +} + + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() + : kind_( kindNone ) +{ +} + + +PathArgument::PathArgument( Value::UInt index ) + : index_( index ) + , kind_( kindIndex ) +{ +} + + +PathArgument::PathArgument( const char *key ) + : key_( key ) + , kind_( kindKey ) +{ +} + + +PathArgument::PathArgument( const std::string &key ) + : key_( key.c_str() ) + , kind_( kindKey ) +{ +} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path( const std::string &path, + const PathArgument &a1, + const PathArgument &a2, + const PathArgument &a3, + const PathArgument &a4, + const PathArgument &a5 ) +{ + InArgs in; + in.push_back( &a1 ); + in.push_back( &a2 ); + in.push_back( &a3 ); + in.push_back( &a4 ); + in.push_back( &a5 ); + makePath( path, in ); +} + + +void +Path::makePath( const std::string &path, + const InArgs &in ) +{ + const char *current = path.c_str(); + const char *end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while ( current != end ) + { + if ( *current == '[' ) + { + ++current; + if ( *current == '%' ) + addPathInArg( path, in, itInArg, PathArgument::kindIndex ); + else + { + Value::UInt index = 0; + for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) + index = index * 10 + Value::UInt(*current - '0'); + args_.push_back( index ); + } + if ( current == end || *current++ != ']' ) + invalidPath( path, int(current - path.c_str()) ); + } + else if ( *current == '%' ) + { + addPathInArg( path, in, itInArg, PathArgument::kindKey ); + ++current; + } + else if ( *current == '.' ) + { + ++current; + } + else + { + const char *beginName = current; + while ( current != end && !strchr( "[.", *current ) ) + ++current; + args_.push_back( std::string( beginName, current ) ); + } + } +} + + +void +Path::addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ) +{ + if ( itInArg == in.end() ) + { + // Error: missing argument %d + } + else if ( (*itInArg)->kind_ != kind ) + { + // Error: bad argument type + } + else + { + args_.push_back( **itInArg ); + } +} + + +void +Path::invalidPath( const std::string &path, + int location ) +{ + // Error: invalid path. +} + + +const Value & +Path::resolve( const Value &root ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + { + // Error: unable to resolve path (object has no member named '' at position...) + } + } + } + return *node; +} + + +Value +Path::resolve( const Value &root, + const Value &defaultValue ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + return defaultValue; + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + return defaultValue; + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + return defaultValue; + } + } + return *node; +} + + +Value & +Path::make( Value &root ) const +{ + Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() ) + { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + + +} // namespace Json diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/json_valueiterator.inl b/lib/jsoncpp/jsoncpp/src/lib_json/json_valueiterator.inl new file mode 100644 index 0000000000..898c35895b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/json_valueiterator.inl @@ -0,0 +1,292 @@ +// included by json_value.cpp +// everything is within Json namespace + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() +#ifndef JSON_VALUE_USE_INTERNAL_MAP + : current_() + , isNull_( true ) +{ +} +#else + : isArray_( true ) + , isNull_( true ) +{ + iterator_.array_ = ValueInternalArray::IteratorState(); +} +#endif + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) + : current_( current ) + , isNull_( false ) +{ +} +#else +ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) + : isArray_( true ) +{ + iterator_.array_ = state; +} + + +ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) + : isArray_( false ) +{ + iterator_.map_ = state; +} +#endif + +Value & +ValueIteratorBase::deref() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + return current_->second; +#else + if ( isArray_ ) + return ValueInternalArray::dereference( iterator_.array_ ); + return ValueInternalMap::value( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::increment() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ++current_; +#else + if ( isArray_ ) + ValueInternalArray::increment( iterator_.array_ ); + ValueInternalMap::increment( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::decrement() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + --current_; +#else + if ( isArray_ ) + ValueInternalArray::decrement( iterator_.array_ ); + ValueInternalMap::decrement( iterator_.map_ ); +#endif +} + + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP +# ifdef JSON_USE_CPPTL_SMALLMAP + return current_ - other.current_; +# else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if ( isNull_ && other.isNull_ ) + { + return 0; + } + + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) + { + ++myDistance; + } + return myDistance; +# endif +#else + if ( isArray_ ) + return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); + return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +bool +ValueIteratorBase::isEqual( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + if ( isNull_ ) + { + return other.isNull_; + } + return current_ == other.current_; +#else + if ( isArray_ ) + return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); + return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::copy( const SelfType &other ) +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + current_ = other.current_; +#else + if ( isArray_ ) + iterator_.array_ = other.iterator_.array_; + iterator_.map_ = other.iterator_.map_; +#endif +} + + +Value +ValueIteratorBase::key() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( czstring.c_str() ) + { + if ( czstring.isStaticString() ) + return Value( StaticString( czstring.c_str() ) ); + return Value( czstring.c_str() ); + } + return Value( czstring.index() ); +#else + if ( isArray_ ) + return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); + bool isStatic; + const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); + if ( isStatic ) + return Value( StaticString( memberName ) ); + return Value( memberName ); +#endif +} + + +Value::UInt +ValueIteratorBase::index() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( !czstring.c_str() ) + return czstring.index(); + return Value::UInt( -1 ); +#else + if ( isArray_ ) + return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); + return Value::UInt( -1 ); +#endif +} + + +const char * +ValueIteratorBase::memberName() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const char *name = (*current_).first.c_str(); + return name ? name : ""; +#else + if ( !isArray_ ) + return ValueInternalMap::key( iterator_.map_ ); + return ""; +#endif +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueConstIterator & +ValueConstIterator::operator =( const ValueIteratorBase &other ) +{ + copy( other ); + return *this; +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueIterator::ValueIterator( const ValueConstIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator::ValueIterator( const ValueIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator & +ValueIterator::operator =( const SelfType &other ) +{ + copy( other ); + return *this; +} diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/json_writer.cpp b/lib/jsoncpp/jsoncpp/src/lib_json/json_writer.cpp new file mode 100644 index 0000000000..f2f8311514 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/json_writer.cpp @@ -0,0 +1,829 @@ +#include <json/writer.h> +#include <utility> +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <sstream> +#include <iomanip> + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +static bool isControlCharacter(char ch) +{ + return ch > 0 && ch <= 0x1F; +} + +static bool containsControlCharacter( const char* str ) +{ + while ( *str ) + { + if ( isControlCharacter( *(str++) ) ) + return true; + } + return false; +} +static void uintToString( unsigned int value, + char *¤t ) +{ + *--current = 0; + do + { + *--current = (value % 10) + '0'; + value /= 10; + } + while ( value != 0 ); +} + +std::string valueToString( Value::Int value ) +{ + char buffer[32]; + char *current = buffer + sizeof(buffer); + bool isNegative = value < 0; + if ( isNegative ) + value = -value; + uintToString( Value::UInt(value), current ); + if ( isNegative ) + *--current = '-'; + assert( current >= buffer ); + return current; +} + + +std::string valueToString( Value::UInt value ) +{ + char buffer[32]; + char *current = buffer + sizeof(buffer); + uintToString( value, current ); + assert( current >= buffer ); + return current; +} + +std::string valueToString( double value ) +{ + char buffer[32]; +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. + sprintf_s(buffer, sizeof(buffer), "%#.16g", value); +#else + sprintf(buffer, "%#.16g", value); +#endif + char* ch = buffer + strlen(buffer) - 1; + if (*ch != '0') return buffer; // nothing to truncate, so save time + while(ch > buffer && *ch == '0'){ + --ch; + } + char* last_nonzero = ch; + while(ch >= buffer){ + switch(*ch){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --ch; + continue; + case '.': + // Truncate zeroes to save bytes in output, but keep one. + *(last_nonzero+2) = '\0'; + return buffer; + default: + return buffer; + } + } + return buffer; +} + + +std::string valueToString( bool value ) +{ + return value ? "true" : "false"; +} + +std::string valueToQuotedString( const char *value ) +{ + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c=value; *c != 0; ++c) + { + switch(*c) + { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + //case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if ( isControlCharacter( *c ) ) + { + std::ostringstream oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } + else + { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() +{ +} + + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_( false ) +{ +} + + +void +FastWriter::enableYAMLCompatibility() +{ + yamlCompatiblityEnabled_ = true; +} + + +std::string +FastWriter::write( const Value &root ) +{ + document_ = ""; + writeValue( root ); + document_ += "\n"; + return document_; +} + + +void +FastWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString( value.asInt() ); + break; + case uintValue: + document_ += valueToString( value.asUInt() ); + break; + case realValue: + document_ += valueToString( value.asDouble() ); + break; + case stringValue: + document_ += valueToQuotedString( value.asCString() ); + break; + case booleanValue: + document_ += valueToString( value.asBool() ); + break; + case arrayValue: + { + document_ += "["; + int size = value.size(); + for ( int index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ","; + writeValue( value[index] ); + } + document_ += "]"; + } + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + document_ += "{"; + for ( Value::Members::iterator it = members.begin(); + it != members.end(); + ++it ) + { + const std::string &name = *it; + if ( it != members.begin() ) + document_ += ","; + document_ += valueToQuotedString( name.c_str() ); + document_ += yamlCompatiblityEnabled_ ? ": " + : ":"; + writeValue( value[name] ); + } + document_ += "}"; + } + break; + } +} + + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_( 74 ) + , indentSize_( 3 ) +{ +} + + +std::string +StyledWriter::write( const Value &root ) +{ + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + document_ += "\n"; + return document_; +} + + +void +StyledWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + while ( true ) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + document_ += " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + while ( true ) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + document_ += "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + + +bool +StyledWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + document_ += value; +} + + +void +StyledWriter::writeIndent() +{ + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + + +void +StyledWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + document_ += value; +} + + +void +StyledWriter::indent() +{ + indentString_ += std::string( indentSize_, ' ' ); +} + + +void +StyledWriter::unindent() +{ + assert( int(indentString_.size()) >= indentSize_ ); + indentString_.resize( indentString_.size() - indentSize_ ); +} + + +void +StyledWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + document_ += normalizeEOL( root.getComment( commentBefore ) ); + document_ += "\n"; +} + + +void +StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + document_ += "\n"; + document_ += normalizeEOL( root.getComment( commentAfter ) ); + document_ += "\n"; + } +} + + +bool +StyledWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter( std::string indentation ) + : document_(NULL) + , rightMargin_( 74 ) + , indentation_( indentation ) +{ +} + + +void +StyledStreamWriter::write( std::ostream &out, const Value &root ) +{ + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + + +void +StyledStreamWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + while ( true ) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + *document_ << " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledStreamWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + while ( true ) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + *document_ << "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + + +bool +StyledStreamWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledStreamWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + *document_ << value; +} + + +void +StyledStreamWriter::writeIndent() +{ + /* + Some comments in this method would have been nice. ;-) + + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + *document_ << '\n'; + } + */ + *document_ << '\n' << indentString_; +} + + +void +StyledStreamWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + *document_ << value; +} + + +void +StyledStreamWriter::indent() +{ + indentString_ += indentation_; +} + + +void +StyledStreamWriter::unindent() +{ + assert( indentString_.size() >= indentation_.size() ); + indentString_.resize( indentString_.size() - indentation_.size() ); +} + + +void +StyledStreamWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + *document_ << normalizeEOL( root.getComment( commentBefore ) ); + *document_ << "\n"; +} + + +void +StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + *document_ << "\n"; + *document_ << normalizeEOL( root.getComment( commentAfter ) ); + *document_ << "\n"; + } +} + + +bool +StyledStreamWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledStreamWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +std::ostream& operator<<( std::ostream &sout, const Value &root ) +{ + Json::StyledStreamWriter writer; + writer.write(sout, root); + return sout; +} + + +} // namespace Json diff --git a/lib/jsoncpp/jsoncpp/src/lib_json/sconscript b/lib/jsoncpp/jsoncpp/src/lib_json/sconscript new file mode 100644 index 0000000000..6e7c6c8a07 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/lib_json/sconscript @@ -0,0 +1,8 @@ +Import( 'env buildLibrary' ) + +buildLibrary( env, Split( """ + json_reader.cpp + json_value.cpp + json_writer.cpp + """ ), + 'json' ) diff --git a/lib/jsoncpp/jsoncpp/src/test_lib_json/jsontest.cpp b/lib/jsoncpp/jsoncpp/src/test_lib_json/jsontest.cpp new file mode 100644 index 0000000000..dfd2b5c77d --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/test_lib_json/jsontest.cpp @@ -0,0 +1,598 @@ +#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC +#include "jsontest.h" +#include <stdio.h> +#include <string> + +#if defined(_MSC_VER) +// Used to install a report hook that prevent dialog on assertion and error. +# include <crtdbg.h> +#endif // if defined(_MSC_VER) + +#if defined(_WIN32) +// Used to prevent dialog on memory fault. +// Limits headers included by Windows.h +# define WIN32_LEAN_AND_MEAN +# define NOSERVICE +# define NOMCX +# define NOIME +# define NOSOUND +# define NOCOMM +# define NORPC +# define NOGDI +# define NOUSER +# define NODRIVERS +# define NOLOGERROR +# define NOPROFILER +# define NOMEMMGR +# define NOLFILEIO +# define NOOPENFILE +# define NORESOURCE +# define NOATOM +# define NOLANGUAGE +# define NOLSTRING +# define NODBCS +# define NOKEYBOARDINFO +# define NOGDICAPMASKS +# define NOCOLOR +# define NOGDIOBJ +# define NODRAWTEXT +# define NOTEXTMETRIC +# define NOSCALABLEFONT +# define NOBITMAP +# define NORASTEROPS +# define NOMETAFILE +# define NOSYSMETRICS +# define NOSYSTEMPARAMSINFO +# define NOMSG +# define NOWINSTYLES +# define NOWINOFFSETS +# define NOSHOWWINDOW +# define NODEFERWINDOWPOS +# define NOVIRTUALKEYCODES +# define NOKEYSTATES +# define NOWH +# define NOMENUS +# define NOSCROLL +# define NOCLIPBOARD +# define NOICONS +# define NOMB +# define NOSYSCOMMANDS +# define NOMDI +# define NOCTLMGR +# define NOWINMESSAGES +# include <windows.h> +#endif // if defined(_WIN32) + +namespace JsonTest { + + +// class TestResult +// ////////////////////////////////////////////////////////////////// + +TestResult::TestResult() + : predicateId_( 1 ) + , lastUsedPredicateId_( 0 ) + , messageTarget_( 0 ) +{ + // The root predicate has id 0 + rootPredicateNode_.id_ = 0; + rootPredicateNode_.next_ = 0; + predicateStackTail_ = &rootPredicateNode_; +} + + +void +TestResult::setTestName( const std::string &name ) +{ + name_ = name; +} + +TestResult & +TestResult::addFailure( const char *file, unsigned int line, + const char *expr ) +{ + /// Walks the PredicateContext stack adding them to failures_ if not already added. + unsigned int nestingLevel = 0; + PredicateContext *lastNode = rootPredicateNode_.next_; + for ( ; lastNode != 0; lastNode = lastNode->next_ ) + { + if ( lastNode->id_ > lastUsedPredicateId_ ) // new PredicateContext + { + lastUsedPredicateId_ = lastNode->id_; + addFailureInfo( lastNode->file_, lastNode->line_, lastNode->expr_, + nestingLevel ); + // Link the PredicateContext to the failure for message target when + // popping the PredicateContext. + lastNode->failure_ = &( failures_.back() ); + } + ++nestingLevel; + } + + // Adds the failed assertion + addFailureInfo( file, line, expr, nestingLevel ); + messageTarget_ = &( failures_.back() ); + return *this; +} + + +void +TestResult::addFailureInfo( const char *file, unsigned int line, + const char *expr, unsigned int nestingLevel ) +{ + Failure failure; + failure.file_ = file; + failure.line_ = line; + if ( expr ) + { + failure.expr_ = expr; + } + failure.nestingLevel_ = nestingLevel; + failures_.push_back( failure ); +} + + +TestResult & +TestResult::popPredicateContext() +{ + PredicateContext *lastNode = &rootPredicateNode_; + while ( lastNode->next_ != 0 && lastNode->next_->next_ != 0 ) + { + lastNode = lastNode->next_; + } + // Set message target to popped failure + PredicateContext *tail = lastNode->next_; + if ( tail != 0 && tail->failure_ != 0 ) + { + messageTarget_ = tail->failure_; + } + // Remove tail from list + predicateStackTail_ = lastNode; + lastNode->next_ = 0; + return *this; +} + + +bool +TestResult::failed() const +{ + return !failures_.empty(); +} + + +unsigned int +TestResult::getAssertionNestingLevel() const +{ + unsigned int level = 0; + const PredicateContext *lastNode = &rootPredicateNode_; + while ( lastNode->next_ != 0 ) + { + lastNode = lastNode->next_; + ++level; + } + return level; +} + + +void +TestResult::printFailure( bool printTestName ) const +{ + if ( failures_.empty() ) + { + return; + } + + if ( printTestName ) + { + printf( "* Detail of %s test failure:\n", name_.c_str() ); + } + + // Print in reverse to display the callstack in the right order + Failures::const_iterator itEnd = failures_.end(); + for ( Failures::const_iterator it = failures_.begin(); it != itEnd; ++it ) + { + const Failure &failure = *it; + std::string indent( failure.nestingLevel_ * 2, ' ' ); + if ( failure.file_ ) + { + printf( "%s%s(%d): ", indent.c_str(), failure.file_, failure.line_ ); + } + if ( !failure.expr_.empty() ) + { + printf( "%s\n", failure.expr_.c_str() ); + } + else if ( failure.file_ ) + { + printf( "\n" ); + } + if ( !failure.message_.empty() ) + { + std::string reindented = indentText( failure.message_, indent + " " ); + printf( "%s\n", reindented.c_str() ); + } + } +} + + +std::string +TestResult::indentText( const std::string &text, + const std::string &indent ) +{ + std::string reindented; + std::string::size_type lastIndex = 0; + while ( lastIndex < text.size() ) + { + std::string::size_type nextIndex = text.find( '\n', lastIndex ); + if ( nextIndex == std::string::npos ) + { + nextIndex = text.size() - 1; + } + reindented += indent; + reindented += text.substr( lastIndex, nextIndex - lastIndex + 1 ); + lastIndex = nextIndex + 1; + } + return reindented; +} + + +TestResult & +TestResult::addToLastFailure( const std::string &message ) +{ + if ( messageTarget_ != 0 ) + { + messageTarget_->message_ += message; + } + return *this; +} + + +TestResult & +TestResult::operator << ( bool value ) +{ + return addToLastFailure( value ? "true" : "false" ); +} + + +TestResult & +TestResult::operator << ( int value ) +{ + char buffer[32]; + sprintf( buffer, "%d", value ); + return addToLastFailure( buffer ); +} + + +TestResult & +TestResult::operator << ( unsigned int value ) +{ + char buffer[32]; + sprintf( buffer, "%u", value ); + return addToLastFailure( buffer ); +} + + +TestResult & +TestResult::operator << ( double value ) +{ + char buffer[32]; + sprintf( buffer, "%16g", value ); + return addToLastFailure( buffer ); +} + + +TestResult & +TestResult::operator << ( const char *value ) +{ + return addToLastFailure( value ? value + : "<NULL>" ); +} + + +TestResult & +TestResult::operator << ( const std::string &value ) +{ + return addToLastFailure( value ); +} + + + +// class TestCase +// ////////////////////////////////////////////////////////////////// + +TestCase::TestCase() + : result_( 0 ) +{ +} + + +void +TestCase::run( TestResult &result ) +{ + result_ = &result; + runTestCase(); +} + + + +// class Runner +// ////////////////////////////////////////////////////////////////// + +Runner::Runner() +{ +} + + +Runner & +Runner::add( TestCaseFactory factory ) +{ + tests_.push_back( factory ); + return *this; +} + + +unsigned int +Runner::testCount() const +{ + return static_cast<unsigned int>( tests_.size() ); +} + + +std::string +Runner::testNameAt( unsigned int index ) const +{ + TestCase *test = tests_[index](); + std::string name = test->testName(); + delete test; + return name; +} + + +void +Runner::runTestAt( unsigned int index, TestResult &result ) const +{ + TestCase *test = tests_[index](); + result.setTestName( test->testName() ); + printf( "Testing %s: ", test->testName() ); + fflush( stdout ); +#if JSON_USE_EXCEPTION + try + { +#endif // if JSON_USE_EXCEPTION + test->run( result ); +#if JSON_USE_EXCEPTION + } + catch ( const std::exception &e ) + { + result.addFailure( __FILE__, __LINE__, + "Unexpected exception caugth:" ) << e.what(); + } +#endif // if JSON_USE_EXCEPTION + delete test; + const char *status = result.failed() ? "FAILED" + : "OK"; + printf( "%s\n", status ); + fflush( stdout ); +} + + +bool +Runner::runAllTest( bool printSummary ) const +{ + unsigned int count = testCount(); + std::deque<TestResult> failures; + for ( unsigned int index = 0; index < count; ++index ) + { + TestResult result; + runTestAt( index, result ); + if ( result.failed() ) + { + failures.push_back( result ); + } + } + + if ( failures.empty() ) + { + if ( printSummary ) + { + printf( "All %d tests passed\n", count ); + } + return true; + } + else + { + for ( unsigned int index = 0; index < failures.size(); ++index ) + { + TestResult &result = failures[index]; + result.printFailure( count > 1 ); + } + + if ( printSummary ) + { + unsigned int failedCount = static_cast<unsigned int>( failures.size() ); + unsigned int passedCount = count - failedCount; + printf( "%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount ); + } + return false; + } +} + + +bool +Runner::testIndex( const std::string &testName, + unsigned int &indexOut ) const +{ + unsigned int count = testCount(); + for ( unsigned int index = 0; index < count; ++index ) + { + if ( testNameAt(index) == testName ) + { + indexOut = index; + return true; + } + } + return false; +} + + +void +Runner::listTests() const +{ + unsigned int count = testCount(); + for ( unsigned int index = 0; index < count; ++index ) + { + printf( "%s\n", testNameAt( index ).c_str() ); + } +} + + +int +Runner::runCommandLine( int argc, const char *argv[] ) const +{ + typedef std::deque<std::string> TestNames; + Runner subrunner; + for ( int index = 1; index < argc; ++index ) + { + std::string opt = argv[index]; + if ( opt == "--list-tests" ) + { + listTests(); + return 0; + } + else if ( opt == "--test-auto" ) + { + preventDialogOnCrash(); + } + else if ( opt == "--test" ) + { + ++index; + if ( index < argc ) + { + unsigned int testNameIndex; + if ( testIndex( argv[index], testNameIndex ) ) + { + subrunner.add( tests_[testNameIndex] ); + } + else + { + fprintf( stderr, "Test '%s' does not exist!\n", argv[index] ); + return 2; + } + } + else + { + printUsage( argv[0] ); + return 2; + } + } + else + { + printUsage( argv[0] ); + return 2; + } + } + bool succeeded; + if ( subrunner.testCount() > 0 ) + { + succeeded = subrunner.runAllTest( subrunner.testCount() > 1 ); + } + else + { + succeeded = runAllTest( true ); + } + return succeeded ? 0 + : 1; +} + + +#if defined(_MSC_VER) +// Hook MSVCRT assertions to prevent dialog from appearing +static int +msvcrtSilentReportHook( int reportType, char *message, int *returnValue ) +{ + // The default CRT handling of error and assertion is to display + // an error dialog to the user. + // Instead, when an error or an assertion occurs, we force the + // application to terminate using abort() after display + // the message on stderr. + if ( reportType == _CRT_ERROR || + reportType == _CRT_ASSERT ) + { + // calling abort() cause the ReportHook to be called + // The following is used to detect this case and let's the + // error handler fallback on its default behaviour ( + // display a warning message) + static volatile bool isAborting = false; + if ( isAborting ) + { + return TRUE; + } + isAborting = true; + + fprintf( stderr, "CRT Error/Assert:\n%s\n", message ); + fflush( stderr ); + abort(); + } + // Let's other reportType (_CRT_WARNING) be handled as they would by default + return FALSE; +} +#endif // if defined(_MSC_VER) + + +void +Runner::preventDialogOnCrash() +{ +#if defined(_MSC_VER) + // Install a hook to prevent MSVCRT error and assertion from + // popping a dialog. + _CrtSetReportHook( &msvcrtSilentReportHook ); +#endif // if defined(_MSC_VER) + + // @todo investiguate this handler (for buffer overflow) + // _set_security_error_handler + +#if defined(_WIN32) + // Prevents the system from popping a dialog for debugging if the + // application fails due to invalid memory access. + SetErrorMode( SEM_FAILCRITICALERRORS + | SEM_NOGPFAULTERRORBOX + | SEM_NOOPENFILEERRORBOX ); +#endif // if defined(_WIN32) +} + +void +Runner::printUsage( const char *appName ) +{ + printf( + "Usage: %s [options]\n" + "\n" + "If --test is not specified, then all the test cases be run.\n" + "\n" + "Valid options:\n" + "--list-tests: print the name of all test cases on the standard\n" + " output and exit.\n" + "--test TESTNAME: executes the test case with the specified name.\n" + " May be repeated.\n" + "--test-auto: prevent dialog prompting for debugging on crash.\n" + , appName ); +} + + + +// Assertion functions +// ////////////////////////////////////////////////////////////////// + +TestResult & +checkStringEqual( TestResult &result, + const std::string &expected, const std::string &actual, + const char *file, unsigned int line, const char *expr ) +{ + if ( expected != actual ) + { + result.addFailure( file, line, expr ); + result << "Expected: '" << expected << "'\n"; + result << "Actual : '" << actual << "'"; + } + return result; +} + + +} // namespace JsonTest diff --git a/lib/jsoncpp/jsoncpp/src/test_lib_json/jsontest.h b/lib/jsoncpp/jsoncpp/src/test_lib_json/jsontest.h new file mode 100644 index 0000000000..7abba56cb4 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/test_lib_json/jsontest.h @@ -0,0 +1,252 @@ +#ifndef JSONTEST_H_INCLUDED
+# define JSONTEST_H_INCLUDED
+
+# include <json/config.h>
+# include <stdio.h>
+# include <deque>
+# include <string>
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// Mini Unit Testing framework
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+
+
+/** \brief Unit testing framework.
+ * \warning: all assertions are non-aborting, test case execution will continue
+ * even if an assertion namespace.
+ * This constraint is for portability: the framework needs to compile
+ * on Visual Studio 6 and must not require exception usage.
+ */
+namespace JsonTest {
+
+
+ class Failure
+ {
+ public:
+ const char *file_;
+ unsigned int line_;
+ std::string expr_;
+ std::string message_;
+ unsigned int nestingLevel_;
+ };
+
+
+ /// Context used to create the assertion callstack on failure.
+ /// Must be a POD to allow inline initialisation without stepping
+ /// into the debugger.
+ struct PredicateContext
+ {
+ typedef unsigned int Id;
+ Id id_;
+ const char *file_;
+ unsigned int line_;
+ const char *expr_;
+ PredicateContext *next_;
+ /// Related Failure, set when the PredicateContext is converted
+ /// into a Failure.
+ Failure *failure_;
+ };
+
+ class TestResult
+ {
+ public:
+ TestResult();
+
+ /// \internal Implementation detail for assertion macros
+ /// Not encapsulated to prevent step into when debugging failed assertions
+ /// Incremented by one on assertion predicate entry, decreased by one
+ /// by addPredicateContext().
+ PredicateContext::Id predicateId_;
+
+ /// \internal Implementation detail for predicate macros
+ PredicateContext *predicateStackTail_;
+
+ void setTestName( const std::string &name );
+
+ /// Adds an assertion failure.
+ TestResult &addFailure( const char *file, unsigned int line,
+ const char *expr = 0 );
+
+ /// Removes the last PredicateContext added to the predicate stack
+ /// chained list.
+ /// Next messages will be targed at the PredicateContext that was removed.
+ TestResult &popPredicateContext();
+
+ bool failed() const;
+
+ void printFailure( bool printTestName ) const;
+
+ TestResult &operator << ( bool value );
+ TestResult &operator << ( int value );
+ TestResult &operator << ( unsigned int value );
+ TestResult &operator << ( double value );
+ TestResult &operator << ( const char *value );
+ TestResult &operator << ( const std::string &value );
+
+ private:
+ TestResult &addToLastFailure( const std::string &message );
+ unsigned int getAssertionNestingLevel() const;
+ /// Adds a failure or a predicate context
+ void addFailureInfo( const char *file, unsigned int line,
+ const char *expr, unsigned int nestingLevel );
+ static std::string indentText( const std::string &text,
+ const std::string &indent );
+
+ typedef std::deque<Failure> Failures;
+ Failures failures_;
+ std::string name_;
+ PredicateContext rootPredicateNode_;
+ PredicateContext::Id lastUsedPredicateId_;
+ /// Failure which is the target of the messages added using operator <<
+ Failure *messageTarget_;
+ };
+
+
+ class TestCase
+ {
+ public:
+ TestCase();
+
+ void run( TestResult &result );
+
+ virtual const char *testName() const = 0;
+
+ protected:
+ TestResult *result_;
+
+ private:
+ virtual void runTestCase() = 0;
+ };
+
+ /// Function pointer type for TestCase factory
+ typedef TestCase *(*TestCaseFactory)();
+
+ class Runner
+ {
+ public:
+ Runner();
+
+ /// Adds a test to the suite
+ Runner &add( TestCaseFactory factory );
+
+ /// Runs test as specified on the command-line
+ /// If no command-line arguments are provided, run all tests.
+ /// If --list-tests is provided, then print the list of all test cases
+ /// If --test <testname> is provided, then run test testname.
+ int runCommandLine( int argc, const char *argv[] ) const;
+
+ /// Runs all the test cases
+ bool runAllTest( bool printSummary ) const;
+
+ /// Returns the number of test case in the suite
+ unsigned int testCount() const;
+
+ /// Returns the name of the test case at the specified index
+ std::string testNameAt( unsigned int index ) const;
+
+ /// Runs the test case at the specified index using the specified TestResult
+ void runTestAt( unsigned int index, TestResult &result ) const;
+
+ static void printUsage( const char *appName );
+
+ private: // prevents copy construction and assignment
+ Runner( const Runner &other );
+ Runner &operator =( const Runner &other );
+
+ private:
+ void listTests() const;
+ bool testIndex( const std::string &testName, unsigned int &index ) const;
+ static void preventDialogOnCrash();
+
+ private:
+ typedef std::deque<TestCaseFactory> Factories;
+ Factories tests_;
+ };
+
+ template<typename T>
+ TestResult &
+ checkEqual( TestResult &result, const T &expected, const T &actual,
+ const char *file, unsigned int line, const char *expr )
+ {
+ if ( expected != actual )
+ {
+ result.addFailure( file, line, expr );
+ result << "Expected: " << expected << "\n";
+ result << "Actual : " << actual;
+ }
+ return result;
+ }
+
+ TestResult &
+ checkStringEqual( TestResult &result,
+ const std::string &expected, const std::string &actual,
+ const char *file, unsigned int line, const char *expr );
+
+} // namespace JsonTest
+
+
+/// \brief Asserts that the given expression is true.
+/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
+/// JSONTEST_ASSERT( x == y );
+#define JSONTEST_ASSERT( expr ) \
+ if ( condition ) \
+ { \
+ } \
+ else \
+ result_->addFailure( __FILE__, __LINE__, #expr )
+
+/// \brief Asserts that the given predicate is true.
+/// The predicate may do other assertions and be a member function of the fixture.
+#define JSONTEST_ASSERT_PRED( expr ) \
+ { \
+ JsonTest::PredicateContext _minitest_Context = { \
+ result_->predicateId_, __FILE__, __LINE__, #expr }; \
+ result_->predicateStackTail_->next_ = &_minitest_Context; \
+ result_->predicateId_ += 1; \
+ result_->predicateStackTail_ = &_minitest_Context; \
+ (expr); \
+ result_->popPredicateContext(); \
+ } \
+ *result_
+
+/// \brief Asserts that two values are equals.
+#define JSONTEST_ASSERT_EQUAL( expected, actual ) \
+ JsonTest::checkEqual( *result_, expected, actual, \
+ __FILE__, __LINE__, \
+ #expected " == " #actual )
+
+/// \brief Asserts that two values are equals.
+#define JSONTEST_ASSERT_STRING_EQUAL( expected, actual ) \
+ JsonTest::checkStringEqual( *result_, \
+ std::string(expected), std::string(actual), \
+ #expected " == " #actual )
+
+/// \brief Begin a fixture test case.
+#define JSONTEST_FIXTURE( FixtureType, name ) \
+ class Test##FixtureType##name : public FixtureType \
+ { \
+ public: \
+ static JsonTest::TestCase *factory() \
+ { \
+ return new Test##FixtureType##name(); \
+ } \
+ public: /* overidden from TestCase */ \
+ virtual const char *testName() const \
+ { \
+ return #FixtureType "/" #name; \
+ } \
+ virtual void runTestCase(); \
+ }; \
+ \
+ void Test##FixtureType##name::runTestCase()
+
+#define JSONTEST_FIXTURE_FACTORY( FixtureType, name ) \
+ &Test##FixtureType##name::factory
+
+#define JSONTEST_REGISTER_FIXTURE( runner, FixtureType, name ) \
+ (runner).add( JSONTEST_FIXTURE_FACTORY( FixtureType, name ) )
+
+#endif // ifndef JSONTEST_H_INCLUDED
diff --git a/lib/jsoncpp/jsoncpp/src/test_lib_json/main.cpp b/lib/jsoncpp/jsoncpp/src/test_lib_json/main.cpp new file mode 100644 index 0000000000..9864178f66 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/test_lib_json/main.cpp @@ -0,0 +1,244 @@ +#include <json/json.h>
+#include "jsontest.h"
+
+
+// TODO:
+// - boolean value returns that they are integral. Should not be.
+// - unsigned integer in integer range are not considered to be valid integer. Should check range.
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// Json Library test cases
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+
+struct ValueTest : JsonTest::TestCase
+{
+ Json::Value null_;
+ Json::Value emptyArray_;
+ Json::Value emptyObject_;
+ Json::Value integer_;
+ Json::Value unsignedInteger_;
+ Json::Value smallUnsignedInteger_;
+ Json::Value real_;
+ Json::Value array1_;
+ Json::Value object1_;
+ Json::Value emptyString_;
+ Json::Value string1_;
+ Json::Value string_;
+ Json::Value true_;
+ Json::Value false_;
+
+ ValueTest()
+ : emptyArray_( Json::arrayValue )
+ , emptyObject_( Json::objectValue )
+ , integer_( 123456789 )
+ , smallUnsignedInteger_( Json::Value::UInt( Json::Value::maxInt ) )
+ , unsignedInteger_( 34567890u )
+ , real_( 1234.56789 )
+ , emptyString_( "" )
+ , string1_( "a" )
+ , string_( "sometext with space" )
+ , true_( true )
+ , false_( false )
+ {
+ array1_.append( 1234 );
+ object1_["id"] = 1234;
+ }
+
+ struct IsCheck
+ {
+ /// Initialize all checks to \c false by default.
+ IsCheck();
+
+ bool isObject_;
+ bool isArray_;
+ bool isBool_;
+ bool isDouble_;
+ bool isInt_;
+ bool isUInt_;
+ bool isIntegral_;
+ bool isNumeric_;
+ bool isString_;
+ bool isNull_;
+ };
+
+ void checkConstMemberCount( const Json::Value &value, unsigned int expectedCount );
+
+ void checkMemberCount( Json::Value &value, unsigned int expectedCount );
+
+ void checkIs( const Json::Value &value, const IsCheck &check );
+};
+
+
+JSONTEST_FIXTURE( ValueTest, size )
+{
+ JSONTEST_ASSERT_PRED( checkMemberCount(emptyArray_, 0) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(emptyObject_, 0) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(array1_, 1) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(object1_, 1) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(null_, 0) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(integer_, 0) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(real_, 0) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(emptyString_, 0) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(string_, 0) );
+ JSONTEST_ASSERT_PRED( checkMemberCount(true_, 0) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isObject )
+{
+ IsCheck checks;
+ checks.isObject_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( emptyObject_, checks ) );
+ JSONTEST_ASSERT_PRED( checkIs( object1_, checks ) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isArray )
+{
+ IsCheck checks;
+ checks.isArray_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( emptyArray_, checks ) );
+ JSONTEST_ASSERT_PRED( checkIs( array1_, checks ) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isNull )
+{
+ IsCheck checks;
+ checks.isNull_ = true;
+ checks.isObject_ = true;
+ checks.isArray_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( null_, checks ) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isString )
+{
+ IsCheck checks;
+ checks.isString_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( emptyString_, checks ) );
+ JSONTEST_ASSERT_PRED( checkIs( string_, checks ) );
+ JSONTEST_ASSERT_PRED( checkIs( string1_, checks ) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isBool )
+{
+ IsCheck checks;
+ checks.isBool_ = true;
+ checks.isIntegral_ = true;
+ checks.isNumeric_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( false_, checks ) );
+ JSONTEST_ASSERT_PRED( checkIs( true_, checks ) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isDouble )
+{
+ IsCheck checks;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( real_, checks ) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isInt )
+{
+ IsCheck checks;
+ checks.isInt_ = true;
+ checks.isNumeric_ = true;
+ checks.isIntegral_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( integer_, checks ) );
+}
+
+
+JSONTEST_FIXTURE( ValueTest, isUInt )
+{
+ IsCheck checks;
+ checks.isUInt_ = true;
+ checks.isNumeric_ = true;
+ checks.isIntegral_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( unsignedInteger_, checks ) );
+ JSONTEST_ASSERT_PRED( checkIs( smallUnsignedInteger_, checks ) );
+}
+
+
+void
+ValueTest::checkConstMemberCount( const Json::Value &value, unsigned int expectedCount )
+{
+ unsigned int count = 0;
+ Json::Value::const_iterator itEnd = value.end();
+ for ( Json::Value::const_iterator it = value.begin(); it != itEnd; ++it )
+ {
+ ++count;
+ }
+ JSONTEST_ASSERT_EQUAL( expectedCount, count ) << "Json::Value::const_iterator";
+}
+
+void
+ValueTest::checkMemberCount( Json::Value &value, unsigned int expectedCount )
+{
+ JSONTEST_ASSERT_EQUAL( expectedCount, value.size() );
+
+ unsigned int count = 0;
+ Json::Value::iterator itEnd = value.end();
+ for ( Json::Value::iterator it = value.begin(); it != itEnd; ++it )
+ {
+ ++count;
+ }
+ JSONTEST_ASSERT_EQUAL( expectedCount, count ) << "Json::Value::iterator";
+
+ JSONTEST_ASSERT_PRED( checkConstMemberCount(value, expectedCount) );
+}
+
+
+ValueTest::IsCheck::IsCheck()
+ : isObject_( false )
+ , isArray_( false )
+ , isBool_( false )
+ , isDouble_( false )
+ , isInt_( false )
+ , isUInt_( false )
+ , isIntegral_( false )
+ , isNumeric_( false )
+ , isString_( false )
+ , isNull_( false )
+{
+}
+
+
+void
+ValueTest::checkIs( const Json::Value &value, const IsCheck &check )
+{
+ JSONTEST_ASSERT_EQUAL( check.isObject_, value.isObject() );
+ JSONTEST_ASSERT_EQUAL( check.isArray_, value.isArray() );
+ JSONTEST_ASSERT_EQUAL( check.isBool_, value.isBool() );
+ JSONTEST_ASSERT_EQUAL( check.isDouble_, value.isDouble() );
+ JSONTEST_ASSERT_EQUAL( check.isInt_, value.isInt() );
+ JSONTEST_ASSERT_EQUAL( check.isUInt_, value.isUInt() );
+ JSONTEST_ASSERT_EQUAL( check.isIntegral_, value.isIntegral() );
+ JSONTEST_ASSERT_EQUAL( check.isNumeric_, value.isNumeric() );
+ JSONTEST_ASSERT_EQUAL( check.isString_, value.isString() );
+ JSONTEST_ASSERT_EQUAL( check.isNull_, value.isNull() );
+}
+
+
+
+int main( int argc, const char *argv[] )
+{
+ JsonTest::Runner runner;
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, size );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isObject );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isArray );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isBool );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isInt );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isUInt );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isDouble );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isString );
+ JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isNull );
+ return runner.runCommandLine( argc, argv );
+}
diff --git a/lib/jsoncpp/jsoncpp/src/test_lib_json/sconscript b/lib/jsoncpp/jsoncpp/src/test_lib_json/sconscript new file mode 100644 index 0000000000..84f56b6a02 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/src/test_lib_json/sconscript @@ -0,0 +1,10 @@ +Import( 'env_testing buildUnitTests' )
+
+buildUnitTests( env_testing, Split( """
+ main.cpp
+ jsontest.cpp
+ """ ),
+ 'test_lib_json' )
+
+# For 'check' to work, 'libs' must be built first.
+env_testing.Depends('test_lib_json', '#libs')
diff --git a/lib/jsoncpp/jsoncpp/test/cleantests.py b/lib/jsoncpp/jsoncpp/test/cleantests.py new file mode 100644 index 0000000000..c38fd8ffdd --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/cleantests.py @@ -0,0 +1,10 @@ +# removes all files created during testing +import glob +import os + +paths = [] +for pattern in [ '*.actual', '*.actual-rewrite', '*.rewrite', '*.process-output' ]: + paths += glob.glob( 'data/' + pattern ) + +for path in paths: + os.unlink( path ) diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_array_01.expected new file mode 100644 index 0000000000..a341ff753c --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_01.expected @@ -0,0 +1 @@ +.=[] diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_01.json b/lib/jsoncpp/jsoncpp/test/data/test_array_01.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_01.json @@ -0,0 +1 @@ +[] diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_02.expected b/lib/jsoncpp/jsoncpp/test/data/test_array_02.expected new file mode 100644 index 0000000000..ef1f2623de --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_02.expected @@ -0,0 +1,2 @@ +.=[] +.[0]=1 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_02.json b/lib/jsoncpp/jsoncpp/test/data/test_array_02.json new file mode 100644 index 0000000000..7660873d10 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_02.json @@ -0,0 +1 @@ +[1] diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_03.expected b/lib/jsoncpp/jsoncpp/test/data/test_array_03.expected new file mode 100644 index 0000000000..3d8dc18eb1 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_03.expected @@ -0,0 +1,6 @@ +.=[] +.[0]=1 +.[1]=2 +.[2]=3 +.[3]=4 +.[4]=5 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_03.json b/lib/jsoncpp/jsoncpp/test/data/test_array_03.json new file mode 100644 index 0000000000..9b3f924755 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_03.json @@ -0,0 +1 @@ +[ 1, 2 , 3,4,5] diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_04.expected b/lib/jsoncpp/jsoncpp/test/data/test_array_04.expected new file mode 100644 index 0000000000..ad4add9794 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_04.expected @@ -0,0 +1,5 @@ +.=[] +.[0]=1 +.[1]="abc" +.[2]=12.3 +.[3]=-4 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_04.json b/lib/jsoncpp/jsoncpp/test/data/test_array_04.json new file mode 100644 index 0000000000..ecca546b2c --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_04.json @@ -0,0 +1 @@ +[1, "abc" , 12.3, -4] diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_05.expected b/lib/jsoncpp/jsoncpp/test/data/test_array_05.expected new file mode 100644 index 0000000000..76cff87c2a --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_05.expected @@ -0,0 +1,100 @@ +.=[] +.[0]=1 +.[1]=2 +.[2]=3 +.[3]=4 +.[4]=5 +.[5]=6 +.[6]=7 +.[7]=8 +.[8]=9 +.[9]=10 +.[10]=11 +.[11]=12 +.[12]=13 +.[13]=14 +.[14]=15 +.[15]=16 +.[16]=17 +.[17]=18 +.[18]=19 +.[19]=20 +.[20]=21 +.[21]=22 +.[22]=23 +.[23]=24 +.[24]=25 +.[25]=26 +.[26]=27 +.[27]=28 +.[28]=29 +.[29]=30 +.[30]=31 +.[31]=32 +.[32]=33 +.[33]=34 +.[34]=35 +.[35]=36 +.[36]=37 +.[37]=38 +.[38]=39 +.[39]=40 +.[40]=41 +.[41]=42 +.[42]=43 +.[43]=44 +.[44]=45 +.[45]=46 +.[46]=47 +.[47]=48 +.[48]=49 +.[49]=50 +.[50]=51 +.[51]=52 +.[52]=53 +.[53]=54 +.[54]=55 +.[55]=56 +.[56]=57 +.[57]=58 +.[58]=59 +.[59]=60 +.[60]=61 +.[61]=62 +.[62]=63 +.[63]=64 +.[64]=65 +.[65]=66 +.[66]=67 +.[67]=68 +.[68]=69 +.[69]=70 +.[70]=71 +.[71]=72 +.[72]=73 +.[73]=74 +.[74]=75 +.[75]=76 +.[76]=77 +.[77]=78 +.[78]=79 +.[79]=80 +.[80]=81 +.[81]=82 +.[82]=83 +.[83]=84 +.[84]=85 +.[85]=86 +.[86]=87 +.[87]=88 +.[88]=89 +.[89]=90 +.[90]=91 +.[91]=92 +.[92]=93 +.[93]=94 +.[94]=95 +.[95]=96 +.[96]=97 +.[97]=98 +.[98]=99 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_05.json b/lib/jsoncpp/jsoncpp/test/data/test_array_05.json new file mode 100644 index 0000000000..7809d6c9a1 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_05.json @@ -0,0 +1 @@ +[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_06.expected b/lib/jsoncpp/jsoncpp/test/data/test_array_06.expected new file mode 100644 index 0000000000..5c9f48eaac --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_06.expected @@ -0,0 +1,5 @@ +.=[] +.[0]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +.[1]="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +.[2]="ccccccccccccccccccccccc" +.[3]="dddddddddddddddddddddddddddddddddddddddddddddddddddd" diff --git a/lib/jsoncpp/jsoncpp/test/data/test_array_06.json b/lib/jsoncpp/jsoncpp/test/data/test_array_06.json new file mode 100644 index 0000000000..7f6c516afd --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_array_06.json @@ -0,0 +1,4 @@ +[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "ccccccccccccccccccccccc", + "dddddddddddddddddddddddddddddddddddddddddddddddddddd" ]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_01.expected new file mode 100644 index 0000000000..d761fce1cc --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_01.expected @@ -0,0 +1 @@ +.=123456789 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_01.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_01.json new file mode 100644 index 0000000000..11f11f9be3 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_01.json @@ -0,0 +1 @@ +0123456789 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_02.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_02.expected new file mode 100644 index 0000000000..650e37cbaa --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_02.expected @@ -0,0 +1 @@ +.=-123456789 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_02.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_02.json new file mode 100644 index 0000000000..bf11bceac7 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_02.json @@ -0,0 +1 @@ +-0123456789 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_03.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_03.expected new file mode 100644 index 0000000000..1da2d395b8 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_03.expected @@ -0,0 +1,3 @@ +.=1.2345678 + + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_03.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_03.json new file mode 100644 index 0000000000..a92b6bd28b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_03.json @@ -0,0 +1,3 @@ +1.2345678 + + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_04.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_04.expected new file mode 100644 index 0000000000..013f424f93 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_04.expected @@ -0,0 +1,2 @@ +.="abcdef" + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_04.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_04.json new file mode 100644 index 0000000000..17eeb99e0b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_04.json @@ -0,0 +1,2 @@ +"abcdef" + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_05.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_05.expected new file mode 100644 index 0000000000..c8db822e58 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_05.expected @@ -0,0 +1,2 @@ +.=null + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_05.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_05.json new file mode 100644 index 0000000000..d0aaea2126 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_05.json @@ -0,0 +1,2 @@ +null + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_06.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_06.expected new file mode 100644 index 0000000000..49be55a965 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_06.expected @@ -0,0 +1,2 @@ +.=true + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_06.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_06.json new file mode 100644 index 0000000000..7eead1ee75 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_06.json @@ -0,0 +1,2 @@ +true + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_07.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_07.expected new file mode 100644 index 0000000000..fe55a6a854 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_07.expected @@ -0,0 +1,2 @@ +.=false + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_07.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_07.json new file mode 100644 index 0000000000..a864bc487d --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_07.json @@ -0,0 +1,2 @@ +false + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_08.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_08.expected new file mode 100644 index 0000000000..c8db822e58 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_08.expected @@ -0,0 +1,2 @@ +.=null + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_08.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_08.json new file mode 100644 index 0000000000..fd78837c0c --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_08.json @@ -0,0 +1,3 @@ +// C++ style comment +null + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_09.expected b/lib/jsoncpp/jsoncpp/test/data/test_basic_09.expected new file mode 100644 index 0000000000..c8db822e58 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_09.expected @@ -0,0 +1,2 @@ +.=null + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_basic_09.json b/lib/jsoncpp/jsoncpp/test/data/test_basic_09.json new file mode 100644 index 0000000000..fc95f0f514 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_basic_09.json @@ -0,0 +1,4 @@ +/* C style comment + */ +null + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_comment_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_comment_01.expected new file mode 100644 index 0000000000..0b8f42d504 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_comment_01.expected @@ -0,0 +1,8 @@ +.={}
+.test=[]
+.test[0]={}
+.test[0].a="aaa"
+.test[1]={}
+.test[1].b="bbb"
+.test[2]={}
+.test[2].c="ccc"
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_comment_01.json b/lib/jsoncpp/jsoncpp/test/data/test_comment_01.json new file mode 100644 index 0000000000..0de8f9cf73 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_comment_01.json @@ -0,0 +1,8 @@ +{
+ "test":
+ [
+ { "a" : "aaa" }, // Comment for a
+ { "b" : "bbb" }, // Comment for b
+ { "c" : "ccc" } // Comment for c
+ ]
+}
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_complex_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_complex_01.expected new file mode 100644 index 0000000000..7573c8812d --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_complex_01.expected @@ -0,0 +1,20 @@ +.={} +.attribute=[] +.attribute[0]="random" +.attribute[1]="short" +.attribute[2]="bold" +.attribute[3]=12 +.attribute[4]={} +.attribute[4].height=7 +.attribute[4].width=64 +.count=1234 +.name={} +.name.aka="T.E.S.T." +.name.id=123987 +.test={} +.test.1={} +.test.1.2={} +.test.1.2.3={} +.test.1.2.3.coord=[] +.test.1.2.3.coord[0]=1 +.test.1.2.3.coord[1]=2 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_complex_01.json b/lib/jsoncpp/jsoncpp/test/data/test_complex_01.json new file mode 100644 index 0000000000..cc0f30f5c3 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_complex_01.json @@ -0,0 +1,17 @@ +{ + "count" : 1234, + "name" : { "aka" : "T.E.S.T.", "id" : 123987 }, + "attribute" : [ + "random", + "short", + "bold", + 12, + { "height" : 7, "width" : 64 } + ], + "test": { "1" : + { "2" : + { "3" : { "coord" : [ 1,2] } + } + } + } +} diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_integer_01.expected new file mode 100644 index 0000000000..593f1db32b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_01.expected @@ -0,0 +1 @@ +.=2147483647 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_01.json b/lib/jsoncpp/jsoncpp/test/data/test_integer_01.json new file mode 100644 index 0000000000..5ab12ffee4 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_01.json @@ -0,0 +1,2 @@ +// Max signed integer +2147483647 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_02.expected b/lib/jsoncpp/jsoncpp/test/data/test_integer_02.expected new file mode 100644 index 0000000000..4b83bd7cae --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_02.expected @@ -0,0 +1 @@ +.=-2147483648 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_02.json b/lib/jsoncpp/jsoncpp/test/data/test_integer_02.json new file mode 100644 index 0000000000..056c850065 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_02.json @@ -0,0 +1,2 @@ +// Min signed integer +-2147483648 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_03.expected b/lib/jsoncpp/jsoncpp/test/data/test_integer_03.expected new file mode 100644 index 0000000000..37c1cb146b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_03.expected @@ -0,0 +1 @@ +.=4294967295 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_03.json b/lib/jsoncpp/jsoncpp/test/data/test_integer_03.json new file mode 100644 index 0000000000..12ef3fbb89 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_03.json @@ -0,0 +1,2 @@ +// Max unsigned integer +4294967295 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_04.expected b/lib/jsoncpp/jsoncpp/test/data/test_integer_04.expected new file mode 100644 index 0000000000..b7b548e3d3 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_04.expected @@ -0,0 +1,2 @@ +.=0 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_04.json b/lib/jsoncpp/jsoncpp/test/data/test_integer_04.json new file mode 100644 index 0000000000..bf81499453 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_04.json @@ -0,0 +1,3 @@ +// Min unsigned integer +0 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_05.expected b/lib/jsoncpp/jsoncpp/test/data/test_integer_05.expected new file mode 100644 index 0000000000..0caea9d3fd --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_05.expected @@ -0,0 +1,2 @@ +.=1 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_integer_05.json b/lib/jsoncpp/jsoncpp/test/data/test_integer_05.json new file mode 100644 index 0000000000..d474e1b4d6 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_integer_05.json @@ -0,0 +1,2 @@ +1 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_object_01.expected new file mode 100644 index 0000000000..67444e5794 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_01.expected @@ -0,0 +1 @@ +.={} diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_01.json b/lib/jsoncpp/jsoncpp/test/data/test_object_01.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_01.json @@ -0,0 +1 @@ +{} diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_02.expected b/lib/jsoncpp/jsoncpp/test/data/test_object_02.expected new file mode 100644 index 0000000000..79391c2a6c --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_02.expected @@ -0,0 +1,2 @@ +.={} +.count=1234 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_02.json b/lib/jsoncpp/jsoncpp/test/data/test_object_02.json new file mode 100644 index 0000000000..d0f2facac3 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_02.json @@ -0,0 +1 @@ +{ "count" : 1234 } diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_03.expected b/lib/jsoncpp/jsoncpp/test/data/test_object_03.expected new file mode 100644 index 0000000000..5e96113792 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_03.expected @@ -0,0 +1,4 @@ +.={} +.attribute="random" +.count=1234 +.name="test" diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_03.json b/lib/jsoncpp/jsoncpp/test/data/test_object_03.json new file mode 100644 index 0000000000..4fcd4d821d --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_03.json @@ -0,0 +1,5 @@ +{ + "count" : 1234, + "name" : "test", + "attribute" : "random" +} diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_04.expected b/lib/jsoncpp/jsoncpp/test/data/test_object_04.expected new file mode 100644 index 0000000000..812965b0ca --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_04.expected @@ -0,0 +1,2 @@ +.={} +.=1234 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_object_04.json b/lib/jsoncpp/jsoncpp/test/data/test_object_04.json new file mode 100644 index 0000000000..450762d71e --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_object_04.json @@ -0,0 +1,3 @@ +{ + "" : 1234 +} diff --git a/lib/jsoncpp/jsoncpp/test/data/test_preserve_comment_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_preserve_comment_01.expected new file mode 100644 index 0000000000..8d88041086 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_preserve_comment_01.expected @@ -0,0 +1,3 @@ +.={} +.first=1 +.second=2 diff --git a/lib/jsoncpp/jsoncpp/test/data/test_preserve_comment_01.json b/lib/jsoncpp/jsoncpp/test/data/test_preserve_comment_01.json new file mode 100644 index 0000000000..fabd55dd96 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_preserve_comment_01.json @@ -0,0 +1,14 @@ +/* A comment + at the beginning of the file. + */ +{ + "first" : 1, // comment after 'first' on the same line + +/* Comment before 'second' + */ + "second" : 2 +} + +/* A comment at + the end of the file. + */ diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_real_01.expected new file mode 100644 index 0000000000..ae2357231e --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_01.expected @@ -0,0 +1,2 @@ +.=8589934592 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_01.json b/lib/jsoncpp/jsoncpp/test/data/test_real_01.json new file mode 100644 index 0000000000..358452d387 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_01.json @@ -0,0 +1,3 @@ +// 2^33 => out of integer range, switch to double +8589934592 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_02.expected b/lib/jsoncpp/jsoncpp/test/data/test_real_02.expected new file mode 100644 index 0000000000..df8de42109 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_02.expected @@ -0,0 +1,2 @@ +.=-4294967295 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_02.json b/lib/jsoncpp/jsoncpp/test/data/test_real_02.json new file mode 100644 index 0000000000..936c706b68 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_02.json @@ -0,0 +1,3 @@ +// -2^32 => out of signed integer range, switch to double +-4294967295 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_03.expected b/lib/jsoncpp/jsoncpp/test/data/test_real_03.expected new file mode 100644 index 0000000000..df8de42109 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_03.expected @@ -0,0 +1,2 @@ +.=-4294967295 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_03.json b/lib/jsoncpp/jsoncpp/test/data/test_real_03.json new file mode 100644 index 0000000000..936c706b68 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_03.json @@ -0,0 +1,3 @@ +// -2^32 => out of signed integer range, switch to double +-4294967295 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_04.expected b/lib/jsoncpp/jsoncpp/test/data/test_real_04.expected new file mode 100644 index 0000000000..d726abe40b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_04.expected @@ -0,0 +1,2 @@ +.=1.2345678 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_04.json b/lib/jsoncpp/jsoncpp/test/data/test_real_04.json new file mode 100644 index 0000000000..a8eb6d0c92 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_04.json @@ -0,0 +1,3 @@ +// 1.2345678 +12345678e-7 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_05.expected b/lib/jsoncpp/jsoncpp/test/data/test_real_05.expected new file mode 100644 index 0000000000..949fd8f55d --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_05.expected @@ -0,0 +1,3 @@ +.=1234567.8 + + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_05.json b/lib/jsoncpp/jsoncpp/test/data/test_real_05.json new file mode 100644 index 0000000000..f7923bab89 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_05.json @@ -0,0 +1,3 @@ +// 1234567.8 +0.12345678e7 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_06.expected b/lib/jsoncpp/jsoncpp/test/data/test_real_06.expected new file mode 100644 index 0000000000..03b7d7f987 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_06.expected @@ -0,0 +1,3 @@ +.=-1.2345678 + + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_06.json b/lib/jsoncpp/jsoncpp/test/data/test_real_06.json new file mode 100644 index 0000000000..485419a276 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_06.json @@ -0,0 +1,3 @@ +// -1.2345678 +-12345678e-7 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_07.expected b/lib/jsoncpp/jsoncpp/test/data/test_real_07.expected new file mode 100644 index 0000000000..12025a404b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_07.expected @@ -0,0 +1,3 @@ +.=-1234567.8 + + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_real_07.json b/lib/jsoncpp/jsoncpp/test/data/test_real_07.json new file mode 100644 index 0000000000..8013eb5c9a --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_real_07.json @@ -0,0 +1,3 @@ +// -1234567.8 +-0.12345678e7 + diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_string_01.expected new file mode 100644 index 0000000000..8fd37b1e0e --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_01.expected @@ -0,0 +1 @@ +.="!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_01.json b/lib/jsoncpp/jsoncpp/test/data/test_string_01.json new file mode 100644 index 0000000000..c8c059ba5e --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_01.json @@ -0,0 +1 @@ +"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_02.expected b/lib/jsoncpp/jsoncpp/test/data/test_string_02.expected new file mode 100644 index 0000000000..0443bc3649 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_02.expected @@ -0,0 +1 @@ +.="!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_02.json b/lib/jsoncpp/jsoncpp/test/data/test_string_02.json new file mode 100644 index 0000000000..f0fe56a650 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_02.json @@ -0,0 +1 @@ +"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_01.expected b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_01.expected new file mode 100644 index 0000000000..447f85a30f --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_01.expected @@ -0,0 +1 @@ +.="a"
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_01.json b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_01.json new file mode 100644 index 0000000000..024114bc09 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_01.json @@ -0,0 +1 @@ +"\u0061"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_02.expected b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_02.expected new file mode 100644 index 0000000000..c0b3b43ba3 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_02.expected @@ -0,0 +1 @@ +.="¢"
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_02.json b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_02.json new file mode 100644 index 0000000000..4961024fab --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_02.json @@ -0,0 +1 @@ +"\u00A2"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_03.expected b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_03.expected new file mode 100644 index 0000000000..7289743ecf --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_03.expected @@ -0,0 +1 @@ +.="€"
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_03.json b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_03.json new file mode 100644 index 0000000000..e7e1a9e138 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_03.json @@ -0,0 +1 @@ +"\u20AC"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_04.expected b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_04.expected new file mode 100644 index 0000000000..868fbc3309 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_04.expected @@ -0,0 +1 @@ +.="𝄞"
diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_04.json b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_04.json new file mode 100644 index 0000000000..dae65c5155 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_04.json @@ -0,0 +1 @@ +"\uD834\uDD1E"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_05.expected b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_05.expected new file mode 100644 index 0000000000..e78506524c --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_05.expected @@ -0,0 +1 @@ +.="za\u017c\u00f3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_05.json b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_05.json new file mode 100644 index 0000000000..8770410946 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/data/test_string_unicode_05.json @@ -0,0 +1 @@ +"Zażółć gęślą jaźń"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/generate_expected.py b/lib/jsoncpp/jsoncpp/test/generate_expected.py new file mode 100644 index 0000000000..5b215c4670 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/generate_expected.py @@ -0,0 +1,11 @@ +import glob +import os.path +for path in glob.glob( '*.json' ): + text = file(path,'rt').read() + target = os.path.splitext(path)[0] + '.expected' + if os.path.exists( target ): + print 'skipping:', target + else: + print 'creating:', target + file(target,'wt').write(text) + diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail1.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail1.json new file mode 100644 index 0000000000..6216b865f1 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail1.json @@ -0,0 +1 @@ +"A JSON payload should be an object or array, not a string."
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail10.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail10.json new file mode 100644 index 0000000000..5d8c0047bd --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail11.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail11.json new file mode 100644 index 0000000000..76eb95b458 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail12.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail12.json new file mode 100644 index 0000000000..77580a4522 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail13.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail13.json new file mode 100644 index 0000000000..379406b59b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail14.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail14.json new file mode 100644 index 0000000000..0ed366b38a --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail15.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail15.json new file mode 100644 index 0000000000..fc8376b605 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail16.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail16.json new file mode 100644 index 0000000000..3fe21d4b53 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail16.json @@ -0,0 +1 @@ +[\naked]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail17.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail17.json new file mode 100644 index 0000000000..62b9214aed --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail18.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail18.json new file mode 100644 index 0000000000..edac92716f --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail18.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail19.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail19.json new file mode 100644 index 0000000000..3b9c46fa9a --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail19.json @@ -0,0 +1 @@ +{"Missing colon" null}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail2.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail2.json new file mode 100644 index 0000000000..6b7c11e5a5 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail2.json @@ -0,0 +1 @@ +["Unclosed array"
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail20.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail20.json new file mode 100644 index 0000000000..27c1af3e72 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail20.json @@ -0,0 +1 @@ +{"Double colon":: null}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail21.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail21.json new file mode 100644 index 0000000000..62474573b2 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail22.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail22.json new file mode 100644 index 0000000000..a7752581bc --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail23.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail23.json new file mode 100644 index 0000000000..494add1ca1 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail23.json @@ -0,0 +1 @@ +["Bad value", truth]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail24.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail24.json new file mode 100644 index 0000000000..caff239bfc --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail24.json @@ -0,0 +1 @@ +['single quote']
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail25.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail25.json new file mode 100644 index 0000000000..8b7ad23e01 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail25.json @@ -0,0 +1 @@ +[" tab character in string "]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail26.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail26.json new file mode 100644 index 0000000000..845d26a6a5 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail27.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail27.json new file mode 100644 index 0000000000..6b01a2ca4a --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail27.json @@ -0,0 +1,2 @@ +["line +break"]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail28.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail28.json new file mode 100644 index 0000000000..621a0101c6 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail28.json @@ -0,0 +1,2 @@ +["line\ +break"]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail29.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail29.json new file mode 100644 index 0000000000..47ec421bb6 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail29.json @@ -0,0 +1 @@ +[0e]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail3.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail3.json new file mode 100644 index 0000000000..168c81eb78 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail3.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail30.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail30.json new file mode 100644 index 0000000000..8ab0bc4b8b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail30.json @@ -0,0 +1 @@ +[0e+]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail31.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail31.json new file mode 100644 index 0000000000..1cce602b51 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail31.json @@ -0,0 +1 @@ +[0e+-1]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail32.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail32.json new file mode 100644 index 0000000000..45cba7396f --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true,
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail33.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail33.json new file mode 100644 index 0000000000..ca5eb19dc9 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail33.json @@ -0,0 +1 @@ +["mismatch"}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail4.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail4.json new file mode 100644 index 0000000000..9de168bf34 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail4.json @@ -0,0 +1 @@ +["extra comma",]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail5.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail5.json new file mode 100644 index 0000000000..ddf3ce3d24 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail5.json @@ -0,0 +1 @@ +["double extra comma",,]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail6.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail6.json new file mode 100644 index 0000000000..ed91580e1b --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail6.json @@ -0,0 +1 @@ +[ , "<-- missing value"]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail7.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail7.json new file mode 100644 index 0000000000..8a96af3e4e --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail7.json @@ -0,0 +1 @@ +["Comma after the close"],
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail8.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail8.json new file mode 100644 index 0000000000..b28479c6ec --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail8.json @@ -0,0 +1 @@ +["Extra close"]]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/fail9.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail9.json new file mode 100644 index 0000000000..5815574f36 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/fail9.json @@ -0,0 +1 @@ +{"Extra comma": true,}
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/pass1.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/pass1.json new file mode 100644 index 0000000000..70e2685436 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/pass1.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* <!-- --", + "# -- --> */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/pass2.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/pass2.json new file mode 100644 index 0000000000..d3c63c7ad8 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/pass2.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
\ No newline at end of file diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/pass3.json b/lib/jsoncpp/jsoncpp/test/jsonchecker/pass3.json new file mode 100644 index 0000000000..4528d51f1a --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/pass3.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/lib/jsoncpp/jsoncpp/test/jsonchecker/readme.txt b/lib/jsoncpp/jsoncpp/test/jsonchecker/readme.txt new file mode 100644 index 0000000000..0efc2a4477 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsonchecker/readme.txt @@ -0,0 +1,3 @@ +Test suite from http://json.org/JSON_checker/.
+
+If the JSON_checker is working correctly, it must accept all of the pass*.json files and reject all of the fail*.json files.
diff --git a/lib/jsoncpp/jsoncpp/test/jsontestrunner.py b/lib/jsoncpp/jsoncpp/test/jsontestrunner.py new file mode 100644 index 0000000000..504f3db2e7 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/jsontestrunner.py @@ -0,0 +1,64 @@ +# Simple implementation of a json test runner to run the test against json-py. + +import sys +import os.path +import json +import types + +if len(sys.argv) != 2: + print "Usage: %s input-json-file", sys.argv[0] + sys.exit(3) + +input_path = sys.argv[1] +base_path = os.path.splitext(input_path)[0] +actual_path = base_path + '.actual' +rewrite_path = base_path + '.rewrite' +rewrite_actual_path = base_path + '.actual-rewrite' + +def valueTreeToString( fout, value, path = '.' ): + ty = type(value) + if ty is types.DictType: + fout.write( '%s={}\n' % path ) + suffix = path[-1] != '.' and '.' or '' + names = value.keys() + names.sort() + for name in names: + valueTreeToString( fout, value[name], path + suffix + name ) + elif ty is types.ListType: + fout.write( '%s=[]\n' % path ) + for index, childValue in zip( xrange(0,len(value)), value ): + valueTreeToString( fout, childValue, path + '[%d]' % index ) + elif ty is types.StringType: + fout.write( '%s="%s"\n' % (path,value) ) + elif ty is types.IntType: + fout.write( '%s=%d\n' % (path,value) ) + elif ty is types.FloatType: + fout.write( '%s=%.16g\n' % (path,value) ) + elif value is True: + fout.write( '%s=true\n' % path ) + elif value is False: + fout.write( '%s=false\n' % path ) + elif value is None: + fout.write( '%s=null\n' % path ) + else: + assert False and "Unexpected value type" + +def parseAndSaveValueTree( input, actual_path ): + root = json.loads( input ) + fout = file( actual_path, 'wt' ) + valueTreeToString( fout, root ) + fout.close() + return root + +def rewriteValueTree( value, rewrite_path ): + rewrite = json.dumps( value ) + #rewrite = rewrite[1:-1] # Somehow the string is quoted ! jsonpy bug ? + file( rewrite_path, 'wt').write( rewrite + '\n' ) + return rewrite + +input = file( input_path, 'rt' ).read() +root = parseAndSaveValueTree( input, actual_path ) +rewrite = rewriteValueTree( json.write( root ), rewrite_path ) +rewrite_root = parseAndSaveValueTree( rewrite, rewrite_actual_path ) + +sys.exit( 0 ) diff --git a/lib/jsoncpp/jsoncpp/test/runjsontests.py b/lib/jsoncpp/jsoncpp/test/runjsontests.py new file mode 100644 index 0000000000..e05bd52b48 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/runjsontests.py @@ -0,0 +1,132 @@ +import sys +import os +import os.path +from glob import glob +import optparse + +RUN_JSONCHECKER = False +VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes ' + +def compareOutputs( expected, actual, message ): + expected = expected.strip().replace('\r','').split('\n') + actual = actual.strip().replace('\r','').split('\n') + diff_line = 0 + max_line_to_compare = min( len(expected), len(actual) ) + for index in xrange(0,max_line_to_compare): + if expected[index].strip() != actual[index].strip(): + diff_line = index + 1 + break + if diff_line == 0 and len(expected) != len(actual): + diff_line = max_line_to_compare+1 + if diff_line == 0: + return None + def safeGetLine( lines, index ): + index += -1 + if index >= len(lines): + return '' + return lines[index].strip() + return """ Difference in %s at line %d: + Expected: '%s' + Actual: '%s' +""" % (message, diff_line, + safeGetLine(expected,diff_line), + safeGetLine(actual,diff_line) ) + +def safeReadFile( path ): + try: + return file( path, 'rt' ).read() + except IOError, e: + return '<File "%s" is missing: %s>' % (path,e) + +def runAllTests( jsontest_executable_path, input_dir = None, + use_valgrind=False ): + if not input_dir: + input_dir = os.path.join( os.getcwd(), 'data' ) + tests = glob( os.path.join( input_dir, '*.json' ) ) + if RUN_JSONCHECKER: + test_jsonchecker = glob( os.path.join( input_dir, 'jsonchecker', '*.json' ) ) + else: + test_jsonchecker = [] + failed_tests = [] + valgrind_path = use_valgrind and VALGRIND_CMD or '' + for input_path in tests + test_jsonchecker: + is_json_checker_test = input_path in test_jsonchecker + print 'TESTING:', input_path, + options = is_json_checker_test and '--json-checker' or '' + pipe = os.popen( "%s%s %s %s" % ( + valgrind_path, jsontest_executable_path, options, + input_path) ) + process_output = pipe.read() + status = pipe.close() + if is_json_checker_test: + expect_failure = os.path.basename( input_path ).startswith( 'fail' ) + if expect_failure: + if status is None: + print 'FAILED' + failed_tests.append( (input_path, 'Parsing should have failed:\n%s' % + safeReadFile(input_path)) ) + else: + print 'OK' + else: + if status is not None: + print 'FAILED' + failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) ) + else: + print 'OK' + else: + base_path = os.path.splitext(input_path)[0] + actual_output = safeReadFile( base_path + '.actual' ) + actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' ) + file(base_path + '.process-output','wt').write( process_output ) + if status: + print 'parsing failed' + failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) ) + else: + expected_output_path = os.path.splitext(input_path)[0] + '.expected' + expected_output = file( expected_output_path, 'rt' ).read() + detail = ( compareOutputs( expected_output, actual_output, 'input' ) + or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) ) + if detail: + print 'FAILED' + failed_tests.append( (input_path, detail) ) + else: + print 'OK' + + if failed_tests: + print + print 'Failure details:' + for failed_test in failed_tests: + print '* Test', failed_test[0] + print failed_test[1] + print + print 'Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests), + len(failed_tests) ) + return 1 + else: + print 'All %d tests passed.' % len(tests) + return 0 + +def main(): + from optparse import OptionParser + parser = OptionParser( usage="%prog [options] <path to jsontestrunner.exe> [test case directory]" ) + parser.add_option("--valgrind", + action="store_true", dest="valgrind", default=False, + help="run all the tests using valgrind to detect memory leaks") + parser.enable_interspersed_args() + options, args = parser.parse_args() + + if len(args) < 1 or len(args) > 2: + parser.error( 'Must provides at least path to jsontestrunner executable.' ) + sys.exit( 1 ) + + jsontest_executable_path = os.path.normpath( os.path.abspath( args[0] ) ) + if len(args) > 1: + input_path = os.path.normpath( os.path.abspath( args[1] ) ) + else: + input_path = None + status = runAllTests( jsontest_executable_path, input_path, + use_valgrind=options.valgrind ) + sys.exit( status ) + +if __name__ == '__main__': + main() diff --git a/lib/jsoncpp/jsoncpp/test/rununittests.py b/lib/jsoncpp/jsoncpp/test/rununittests.py new file mode 100644 index 0000000000..ccc54e45a3 --- /dev/null +++ b/lib/jsoncpp/jsoncpp/test/rununittests.py @@ -0,0 +1,73 @@ +import sys
+import os
+import os.path
+import subprocess
+from glob import glob
+import optparse
+
+VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes'
+
+class TestProxy(object):
+ def __init__( self, test_exe_path, use_valgrind=False ):
+ self.test_exe_path = os.path.normpath( os.path.abspath( test_exe_path ) )
+ self.use_valgrind = use_valgrind
+
+ def run( self, options ):
+ if self.use_valgrind:
+ cmd = VALGRIND_CMD.split()
+ else:
+ cmd = []
+ cmd.extend( [self.test_exe_path, '--test-auto'] + options )
+ process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
+ stdout = process.communicate()[0]
+ if process.returncode:
+ return False, stdout
+ return True, stdout
+
+def runAllTests( exe_path, use_valgrind=False ):
+ test_proxy = TestProxy( exe_path, use_valgrind=use_valgrind )
+ status, test_names = test_proxy.run( ['--list-tests'] )
+ if not status:
+ print >> sys.stderr, "Failed to obtain unit tests list:\n" + test_names
+ return 1
+ test_names = [name.strip() for name in test_names.strip().split('\n')]
+ failures = []
+ for name in test_names:
+ print 'TESTING %s:' % name,
+ succeed, result = test_proxy.run( ['--test', name] )
+ if succeed:
+ print 'OK'
+ else:
+ failures.append( (name, result) )
+ print 'FAILED'
+ failed_count = len(failures)
+ pass_count = len(test_names) - failed_count
+ if failed_count:
+ print
+ for name, result in failures:
+ print result
+ print '%d/%d tests passed (%d failure(s))' % (
+ pass_count, len(test_names), failed_count)
+ return 1
+ else:
+ print 'All %d tests passed' % len(test_names)
+ return 0
+
+def main():
+ from optparse import OptionParser
+ parser = OptionParser( usage="%prog [options] <path to test_lib_json.exe>" )
+ parser.add_option("--valgrind",
+ action="store_true", dest="valgrind", default=False,
+ help="run all the tests using valgrind to detect memory leaks")
+ parser.enable_interspersed_args()
+ options, args = parser.parse_args()
+
+ if len(args) != 1:
+ parser.error( 'Must provides at least path to test_lib_json executable.' )
+ sys.exit( 1 )
+
+ exit_code = runAllTests( args[0], use_valgrind=options.valgrind )
+ sys.exit( exit_code )
+
+if __name__ == '__main__':
+ main()
|