- reorganized repository to match standard layout
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..333e120
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Baptiste Lepilleur <blep@users.sourceforge.net>

diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..65d3629
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,44 @@
+* 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

+

diff --git a/SConstruct b/SConstruct
new file mode 100644
index 0000000..d73b629
--- /dev/null
+++ b/SConstruct
@@ -0,0 +1,171 @@
+import os

+import os.path

+import sys

+

+JSONCPP_VERSION = '0.1'

+DIST_DIR = '#dist'

+

+options = Options()

+options.Add( EnumOption('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']

+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 )

+

+env = Environment( ENV = {'PATH' : os.environ['PATH']},

+                   toolpath = ['scons-tools'],

+                   tools=[] ) #, tools=['default'] )

+

+if platform == 'suncc':

+    env.Tool( 'sunc++' )

+    env.Tool( 'sunlink' )

+    env.Tool( 'sunar' )

+    env.Append( LIBS = ['pthreads'] )

+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 == 'linux-gcc':

+    env.Tool( 'default' )

+    env.Append( LIBS = ['pthread'] )

+else:

+    print "UNSUPPORTED PLATFORM."

+    env.Exit(1)

+

+env.Tool('doxygen')

+env.Tool('substinfile')

+env.Tool('targz')

+env.Tool('srcdist')

+

+env.Append( CPPPATH = ['#include'],

+            LIBPATH = lib_dir )

+short_platform = platform

+if short_platform.startswith('msvc'):

+    short_platform = short_platform[2:]

+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

+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_ADD'] = SrcDistAdder( env )

+env['SRCDIST_TARGET'] = os.path.join( DIST_DIR, 'jsoncpp-src-%s.tar.gz' % env['JSONCPP_VERSION'] )

+env['SRCDIST_BUILDER'] = env.TarGz

+                      

+env_testing = env.Copy( )

+env_testing.Append( LIBS = ['json_${LIB_NAME_SUFFIX}'] )

+

+def buildJSONExample( env, target_sources, target_name ):

+    env = env.Copy()

+    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 buildLibary( 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 )

+    env['SRCDIST_ADD']( source=[target_sources] )

+

+Export( 'env env_testing buildJSONExample buildLibary buildJSONTests' )

+

+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 )

+    import runjsontests

+    return runjsontests.runAllTests( os.path.abspath(source), jsontest_path )

+

+def runJSONTests_string( target, source = None, env = None ):

+    return 'RunJSONTests("%s")' % source

+

+##def buildDoc( doxyfile_path ):

+##    doc_cmd = env.Doxygen( doxyfile_path )

+

+import SCons.Action

+ActionFactory = SCons.Action.ActionFactory

+RunJSONTests = ActionFactory(runJSONTests_action, runJSONTests_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( 'doc' )

diff --git a/doc/doxyfile.in b/doc/doxyfile.in
new file mode 100644
index 0000000..15ec5bd
--- /dev/null
+++ b/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/doc/footer.html b/doc/footer.html
new file mode 100644
index 0000000..56df7a4
--- /dev/null
+++ b/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/doc/header.html b/doc/header.html
new file mode 100644
index 0000000..2288b04
--- /dev/null
+++ b/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/doc/jsoncpp.dox b/doc/jsoncpp.dox
new file mode 100644
index 0000000..5463463
--- /dev/null
+++ b/doc/jsoncpp.dox
@@ -0,0 +1,90 @@
+/**

+\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 );

+\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/doc/readme.txt b/doc/readme.txt
new file mode 100644
index 0000000..499422e
--- /dev/null
+++ b/doc/readme.txt
@@ -0,0 +1 @@
+The documentation is generated using doxygen (http://www.doxygen.org).

diff --git a/doc/sconscript b/doc/sconscript
new file mode 100644
index 0000000..d2e27a7
--- /dev/null
+++ b/doc/sconscript
@@ -0,0 +1,22 @@
+Import( 'env' )

+import os.path

+

+if 'doxygen' in env['TOOLS']:

+    doc_topdir = env['ROOTBUILD_DIR']

+    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 )

diff --git a/include/json/autolink.h b/include/json/autolink.h
new file mode 100644
index 0000000..ef5e0ab
--- /dev/null
+++ b/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/include/json/config.h b/include/json/config.h
new file mode 100644
index 0000000..c1bcb3f
--- /dev/null
+++ b/include/json/config.h
@@ -0,0 +1,40 @@
+#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

+

+

+# 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/include/json/forwards.h b/include/json/forwards.h
new file mode 100644
index 0000000..704d6e4
--- /dev/null
+++ b/include/json/forwards.h
@@ -0,0 +1,31 @@
+#ifndef JSON_FORWARDS_H_INCLUDED

+# define JSON_FORWARDS_H_INCLUDED

+

+# include "config.h"

+

+namespace Json {

+

+   class FastWriter;

+   class Reader;

+   class StyledWriter;

+

+   // 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/include/json/json.h b/include/json/json.h
new file mode 100644
index 0000000..c2a24ea
--- /dev/null
+++ b/include/json/json.h
@@ -0,0 +1,9 @@
+#ifndef JSON_JSON_H_INCLUDED

+# define JSON_JSON_H_INCLUDED

+

+# include "autolink.h"

+# include "value.h"

+# include "reader.h"

+# include "writer.h"

+

+#endif // JSON_JSON_H_INCLUDED

diff --git a/include/json/reader.h b/include/json/reader.h
new file mode 100644
index 0000000..60594d9
--- /dev/null
+++ b/include/json/reader.h
@@ -0,0 +1,150 @@
+#ifndef CPPTL_JSON_READER_H_INCLUDED

+# define CPPTL_JSON_READER_H_INCLUDED

+

+# include "forwards.h"

+# include "value.h"

+# include <deque>

+# include <stack>

+# include <string>

+

+namespace Json {

+

+   class Value;

+

+   /** \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;

+

+      Reader();

+

+      /** \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.

+       * \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.

+       * \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 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 decodeUnicodeEscapeSequence( Token &token, 

+                                        Location &current, 

+                                        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 &currentValue();

+      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_;

+      bool collectComments_;

+   };

+

+

+} // namespace Json

+

+#endif // CPPTL_JSON_READER_H_INCLUDED

diff --git a/include/json/value.h b/include/json/value.h
new file mode 100644
index 0000000..5b5e460
--- /dev/null
+++ b/include/json/value.h
@@ -0,0 +1,999 @@
+#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:

+      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 );

+      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 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;

+

+      /// Removes all object members and array elements.

+      void clear();

+

+      /// Resize the array to size elements. 

+      /// New elements are initialized to null.

+      /// May only be called on nullValue or 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.

+      Value &operator[]( UInt index );

+      /// Access an array element (zero based index )

+      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;

+      /// Returns true if index < size().

+      bool isValidIndex( UInt index ) const;

+      /// 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

+      /// Returns the member named key if it exist, defaultValue otherwise.

+      Value get( const char *key, 

+                 const Value &defaultValue ) const;

+      /// Returns the member named key if it exist, defaultValue otherwise.

+      Value get( const std::string &key,

+                 const Value &defaultValue ) const;

+# ifdef JSON_USE_CPPTL

+      /// Returns the member named key if it exist, defaultValue otherwise.

+      Value get( const CppTL::ConstString &key,

+                 const Value &defaultValue ) const;

+# endif

+      /// Returns true if the object has a member named key.

+      bool isMember( const char *key ) const;

+      /// Returns true if the object has a member named key.

+      bool isMember( const std::string &key ) const;

+# ifdef JSON_USE_CPPTL

+      /// Returns true if the object has a member named key.

+      bool isMember( const CppTL::ConstString &key ) const;

+# endif

+

+      // Returns a list of the member names.

+      Members getMemberNames() const;

+

+//# ifdef JSON_USE_CPPTL

+//      EnumMemberNames enumMemberNames() const;

+//      EnumValues enumValues() const;

+//# endif

+

+      void setComment( const char *comment,

+                       CommentPlacement placement );

+      void setComment( const std::string &comment,

+                       CommentPlacement placement );

+      bool hasComment( CommentPlacement placement ) const;

+      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 = -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

+      {

+         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

+      {

+         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 &current );

+#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 );

+      }

+

+      /// Returns either the index or the member name of the referenced value as a Value.

+      Value key() const;

+

+      /// Returns the index of the referenced Value. -1 if it is not an arrayValue.

+      Value::UInt index() const;

+

+      /// Returns 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_;

+#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 &current );

+#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 &current );

+#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/include/json/writer.h b/include/json/writer.h
new file mode 100644
index 0000000..3abf2ea
--- /dev/null
+++ b/include/json/writer.h
@@ -0,0 +1,92 @@
+#ifndef JSON_WRITER_H_INCLUDED

+# define JSON_WRITER_H_INCLUDED

+

+# include "value.h"

+# include <vector>

+# include <string>

+

+namespace Json {

+

+   class Value;

+

+   /** \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:

+      std::string write( const Value &root );

+

+   private:

+      void writeValue( const Value &value );

+

+      std::string document_;

+   };

+

+   /** \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:

+      StyledWriter();

+

+      /** \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 represent the root value.

+       */

+      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_;

+   };

+

+   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 );

+

+} // namespace Json

+

+

+

+#endif // JSON_WRITER_H_INCLUDED

diff --git a/makefiles/vs71/jsoncpp.sln b/makefiles/vs71/jsoncpp.sln
new file mode 100644
index 0000000..613c267
--- /dev/null
+++ b/makefiles/vs71/jsoncpp.sln
@@ -0,0 +1,30 @@
+Microsoft Visual Studio Solution File, Format Version 8.00

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_json", "..\..\src\lib_json\lib_json.vcproj", "{B84F7231-16CE-41D8-8C08-7B523FF4225B}"

+	ProjectSection(ProjectDependencies) = postProject

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsontest", "..\..\src\jsontestrunner\jsontest.vcproj", "{25AF2DD2-D396-4668-B188-488C33B8E620}"

+	ProjectSection(ProjectDependencies) = postProject

+		{B84F7231-16CE-41D8-8C08-7B523FF4225B} = {B84F7231-16CE-41D8-8C08-7B523FF4225B}

+	EndProjectSection

+EndProject

+Global

+	GlobalSection(SolutionConfiguration) = preSolution

+		Debug = Debug

+		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}.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}.Release.ActiveCfg = Release|Win32

+		{25AF2DD2-D396-4668-B188-488C33B8E620}.Release.Build.0 = Release|Win32

+	EndGlobalSection

+	GlobalSection(ExtensibilityGlobals) = postSolution

+	EndGlobalSection

+	GlobalSection(ExtensibilityAddIns) = postSolution

+	EndGlobalSection

+EndGlobal

diff --git a/scons-tools/doxygen.py b/scons-tools/doxygen.py
new file mode 100644
index 0000000..f85f4a3
--- /dev/null
+++ b/scons-tools/doxygen.py
@@ -0,0 +1,205 @@
+# Big issue:

+# emitter depends on doxyfile which is generated from doxyfile.in.

+# build fails after cleaning and relaunching the build.

+

+import os

+import os.path

+import glob

+from fnmatch import fnmatch

+

+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)

+

+   doxyfile_dir = str( node.dir )

+

+##   print 'running from', os.getcwd()

+   for node in data.get("INPUT", []):

+      node_real_path = os.path.normpath( os.path.join( doxyfile_dir, node ) )

+      if os.path.isfile(node_real_path):

+##         print str(node), 'is a file'

+         sources.append(node)

+      elif os.path.isdir(node_real_path):

+##         print str(node), 'is a directory'

+         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)

+##                     print '  adding source', os.path.abspath( filename )

+         else:

+            for pattern in file_patterns:

+               sources.extend(glob.glob(os.path.join( node, pattern)))

+##      else:

+##         print str(node), 'is neither a file nor a directory'

+   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 DoxyEmitter(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"),

+   }

+

+##   print '#### DoxyEmitter:', source[0].abspath, os.path.exists( source[0].abspath )

+   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:

+      clean_cmd = env.Clean(node, node)

+      env.Depends( clean_cmd, source )

+

+   return (targets, source)

+

+def generate(env):

+   """

+   Add builders and construction variables for the

+   Doxygen tool.  This is currently for Doxygen 1.4.6.

+   """

+   doxyfile_scanner = env.Scanner(

+      DoxySourceScan,

+      "DoxySourceScan",

+      scan_check = DoxySourceScanCheck,

+   )

+

+   doxyfile_builder = env.Builder(

+      action = env.Action("cd ${SOURCE.dir}  &&  ${DOXYGEN} ${SOURCE.file}",

+                          varlist=['$SOURCES']),

+      emitter = DoxyEmitter,

+      target_factory = env.fs.Entry,

+      single_source = True,

+      source_scanner =  doxyfile_scanner,

+   )

+

+   env.Append(BUILDERS = {

+      'Doxygen': doxyfile_builder,

+   })

+

+   env.AppendUnique(

+      DOXYGEN = 'doxygen',

+   )

+

+def exists(env):

+   """

+   Make sure doxygen exists.

+   """

+   return env.Detect("doxygen")

diff --git a/scons-tools/srcdist.py b/scons-tools/srcdist.py
new file mode 100644
index 0000000..cfc5407
--- /dev/null
+++ b/scons-tools/srcdist.py
@@ -0,0 +1,179 @@
+import os

+import os.path

+import glob

+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,

+##   )

+

+   srcdist_builder = targz.makeBuilder( srcDistEmitter )

+

+   env['BUILDERS']['SrcDist'] = srcdist_builder

+

+def exists(env):

+   """

+   Make sure srcdist exists.

+   """

+   return True

diff --git a/scons-tools/substinfile.py b/scons-tools/substinfile.py
new file mode 100644
index 0000000..2502262
--- /dev/null
+++ b/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/scons-tools/targz.py b/scons-tools/targz.py
new file mode 100644
index 0000000..2f21204
--- /dev/null
+++ b/scons-tools/targz.py
@@ -0,0 +1,78 @@
+"""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.
+
+def exists(env):
+    return internal_targz
diff --git a/src/jsontestrunner/jsontest.vcproj b/src/jsontestrunner/jsontest.vcproj
new file mode 100644
index 0000000..f86b27e
--- /dev/null
+++ b/src/jsontestrunner/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=".\main.cpp">

+		</File>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp
new file mode 100644
index 0000000..1d43720
--- /dev/null
+++ b/src/jsontestrunner/main.cpp
@@ -0,0 +1,185 @@
+#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 );

+   int 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 ) == 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 )

+{

+   Json::Reader reader;

+   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;

+   }

+

+   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;

+   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() );

+}

+

+int main( int argc, const char *argv[] )

+{

+   if ( argc != 2 )

+   {

+      printf( "Usage: %s input-json-file", argv[0] );

+      return 3;

+   }

+

+   std::string input = readInputTestFile( argv[1] );

+   if ( input.empty() )

+   {

+      printf( "Failed to read input or empty input: %s\n", argv[1] );

+      return 3;

+   }

+

+   std::string basePath = removeSuffix( argv[1], ".json" );

+   if ( basePath.empty() )

+   {

+      printf( "Bad input path. Path does not end with '.expected':\n%s\n", argv[1] );

+      return 3;

+   }

+

+   std::string actualPath = basePath + ".actual";

+   std::string rewritePath = basePath + ".rewrite";

+   std::string rewriteActualPath = basePath + ".actual-rewrite";

+

+   Json::Value root;

+   int exitCode = parseAndSaveValueTree( input, actualPath, "input", root );

+   if ( exitCode == 0 )

+   {

+      std::string rewrite;

+      exitCode = rewriteValueTree( rewritePath, root, rewrite );

+      if ( exitCode == 0 )

+      {

+         Json::Value rewriteRoot;

+         exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath, "rewrite", rewriteRoot );

+      }

+   }

+

+   return exitCode;

+}
\ No newline at end of file
diff --git a/src/jsontestrunner/sconscript b/src/jsontestrunner/sconscript
new file mode 100644
index 0000000..f81a2dc
--- /dev/null
+++ b/src/jsontestrunner/sconscript
@@ -0,0 +1,6 @@
+Import( 'env_testing buildJSONTests' )

+

+buildJSONTests( env_testing, Split( """

+    main.cpp

+     """ ),

+    'jsontestrunner' )

diff --git a/src/lib_json/json_batchallocator.h b/src/lib_json/json_batchallocator.h
new file mode 100644
index 0000000..1e35c19
--- /dev/null
+++ b/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/src/lib_json/json_internalarray.inl b/src/lib_json/json_internalarray.inl
new file mode 100644
index 0000000..2b3d859
--- /dev/null
+++ b/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/src/lib_json/json_internalmap.inl b/src/lib_json/json_internalmap.inl
new file mode 100644
index 0000000..8e60b46
--- /dev/null
+++ b/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 &current->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 = &current->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/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp
new file mode 100644
index 0000000..9d0e665
--- /dev/null
+++ b/src/lib_json/json_reader.cpp
@@ -0,0 +1,715 @@
+#include <json/reader.h>

+#include <json/value.h>

+#include <utility>

+#include <stdio.h>

+#include <assert.h>

+

+#if _MSC_VER >= 1400 // VC++ 8.0

+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.

+#endif

+

+namespace Json {

+

+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;

+}

+

+

+// Class Reader

+// //////////////////////////////////////////////////////////////////

+

+Reader::Reader()

+{

+}

+

+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( const char *beginDoc, const char *endDoc, 

+               Value &root,

+               bool collectComments )

+{

+   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 );

+   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_ = &currentValue();

+   }

+

+   return successful;

+}

+

+

+void 

+Reader::skipCommentTokens( Token &token )

+{

+   do

+   {

+      readToken( token );

+   }

+   while ( token.type_ == tokenComment );

+}

+

+

+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 ) )

+      {

+         return addErrorAndRecover( "Missing ',' or '}' in object declaration", 

+                                    comma, 

+                                    tokenObjectEnd );

+      }

+      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;

+      if ( !readToken( token ) 

+           ||  ( token.type_ != tokenArraySeparator  &&  

+                 token.type_ != tokenArrayEnd ) )

+      {

+         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 ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )

+                  return false;

+               // @todo encode unicode as utf8.

+            }

+            break;

+         default:

+            return addError( "Bad escape sequence in string", token, current );

+         }

+      }

+      else

+      {

+         decoded += c;

+      }

+   }

+   return true;

+}

+

+

+bool 

+Reader::decodeUnicodeEscapeSequence( Token &token, 

+                                     Location &current, 

+                                     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;

+}

+

+

+} // namespace Json

diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp
new file mode 100644
index 0000000..5a59956
--- /dev/null
+++ b/src/lib_json/json_value.cpp
@@ -0,0 +1,1635 @@
+#include <json/value.h>

+#include <json/writer.h>

+#include <utility>

+#include "assert.h"

+#ifdef JSON_USE_CPPTL

+# include <cpptl/conststring.h>

+#endif

+#include <stddef.h>    // 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 ) assert( condition &&  message );  // @todo <= change this into an exception throw

+

+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_ );

+   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 )

+   , comments_( 0 )

+   , allocated_( 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_ )

+      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( "Type is not convertible to double" && false );

+   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( value_.uint_ < maxInt  &&  "integer out of signed integer range" );

+      return value_.uint_;

+   case realValue:

+      JSON_ASSERT( 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( "Type is not convertible to double" && false );

+   default:

+      JSON_ASSERT_UNREACHABLE;

+   }

+   return 0; // unreachable;

+}

+

+Value::UInt 

+Value::asUInt() const

+{

+   switch ( type_ )

+   {

+   case nullValue:

+      return 0;

+   case intValue:

+      JSON_ASSERT( value_.int_ >= 0  &&  "Negative integer can not be converted to unsigned integer" );

+      return value_.int_;

+   case uintValue:

+      return value_.uint_;

+   case realValue:

+      JSON_ASSERT( 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( "Type is not convertible to double" && false );

+   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( "Type is not convertible to double" && false );

+   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_ <= 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;

+}

+

+

+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 );

+}

+

+

+# 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 );

+   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::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 )

+   : kind_( kindIndex )

+   , index_( index )

+{

+}

+

+

+PathArgument::PathArgument( const char *key )

+   : kind_( kindKey )

+   , key_( key )

+{

+}

+

+

+PathArgument::PathArgument( const std::string &key )

+   : kind_( kindKey )

+   , key_( key.c_str() )

+{

+}

+

+// 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/src/lib_json/json_valueiterator.inl b/src/lib_json/json_valueiterator.inl
new file mode 100644
index 0000000..c84c47d
--- /dev/null
+++ b/src/lib_json/json_valueiterator.inl
@@ -0,0 +1,257 @@
+// included by json_value.cpp

+// everything is within Json namespace

+

+

+// //////////////////////////////////////////////////////////////////

+// //////////////////////////////////////////////////////////////////

+// //////////////////////////////////////////////////////////////////

+// class ValueIteratorBase

+// //////////////////////////////////////////////////////////////////

+// //////////////////////////////////////////////////////////////////

+// //////////////////////////////////////////////////////////////////

+

+ValueIteratorBase::ValueIteratorBase()

+{

+}

+

+

+#ifndef JSON_VALUE_USE_INTERNAL_MAP

+ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current )

+   : current_( current )

+{

+}

+#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

+   return difference_type( std::distance( current_, other.current_ ) );

+# 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

+   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 &current )

+   : 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 &current )

+   : 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/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp
new file mode 100644
index 0000000..f1d8168
--- /dev/null
+++ b/src/lib_json/json_writer.cpp
@@ -0,0 +1,417 @@
+#include <json/writer.h>

+#include <utility>

+#include <assert.h>

+#include <stdio.h>

+

+#if _MSC_VER >= 1400 // VC++ 8.0

+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.

+#endif

+

+namespace Json {

+

+static void uintToString( unsigned int value, 

+                          char *&current )

+{

+   *--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];

+#ifdef __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

+   return buffer;

+}

+

+

+std::string valueToString( bool value )

+{

+   return value ? "true" : "false";

+}

+

+std::string valueToQuotedString( const char *value )

+{

+   return std::string("\"") + value + "\"";

+}

+

+

+// Class FastWriter

+// //////////////////////////////////////////////////////////////////

+

+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_ += " : ";

+            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 )

+{

+   int size = value.size();

+   if ( size == 0 )

+      pushValue( "[]" );

+   else

+   {

+      bool isArrayMultiLine = isMultineArray( value );

+      if ( isArrayMultiLine )

+      {

+         writeWithIndent( "[" );

+         indent();

+         bool hasChildValue = !childValues_.empty();

+         int 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 ( int 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;

+}

+

+

+} // namespace Json

diff --git a/src/lib_json/lib_json.vcproj b/src/lib_json/lib_json.vcproj
new file mode 100644
index 0000000..d1a6f05
--- /dev/null
+++ b/src/lib_json/lib_json.vcproj
@@ -0,0 +1,211 @@
+<?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\forwards.h">

+		</File>

+		<File

+			RelativePath="..\..\include\json\json.h">

+		</File>

+		<File

+			RelativePath=".\json_batchallocator.h">

+		</File>

+		<File

+			RelativePath=".\json_internalarray.inl">

+		</File>

+		<File

+			RelativePath=".\json_internalmap.inl">

+		</File>

+		<File

+			RelativePath=".\json_reader.cpp">

+		</File>

+		<File

+			RelativePath=".\json_value.cpp">

+		</File>

+		<File

+			RelativePath=".\json_valueiterator.inl">

+		</File>

+		<File

+			RelativePath=".\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/src/lib_json/sconscript b/src/lib_json/sconscript
new file mode 100644
index 0000000..cc044fb
--- /dev/null
+++ b/src/lib_json/sconscript
@@ -0,0 +1,8 @@
+Import( 'env buildLibary' )

+

+buildLibary( env, Split( """

+    json_reader.cpp 

+    json_value.cpp 

+    json_writer.cpp

+     """ ),

+    'json' )

diff --git a/test/cleantests.py b/test/cleantests.py
new file mode 100644
index 0000000..5872a87
--- /dev/null
+++ b/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( pattern )

+

+for path in paths:

+    os.unlink( path )

diff --git a/test/generate_expected.py b/test/generate_expected.py
new file mode 100644
index 0000000..a46e889
--- /dev/null
+++ b/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/test/jsontestrunner.py b/test/jsontestrunner.py
new file mode 100644
index 0000000..ec05a91
--- /dev/null
+++ b/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.read( input )

+    fout = file( actual_path, 'wt' )

+    valueTreeToString( fout, root )

+    fout.close()

+    return root

+

+def rewriteValueTree( value, rewrite_path ):

+    rewrite = json.write( 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/test/runjsontests.py b/test/runjsontests.py
new file mode 100644
index 0000000..a5284fb
--- /dev/null
+++ b/test/runjsontests.py
@@ -0,0 +1,91 @@
+import sys

+import os

+import os.path

+import glob

+

+

+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 ):

+    if not input_dir:

+        input_dir = os.getcwd()

+    tests = glob.glob( os.path.join( input_dir, '*.json' ) )

+    failed_tests = []

+    for input_path in tests:

+        print 'TESTING:', input_path,

+        pipe = os.popen( "%s %s" % (jsontest_executable_path, input_path) )

+        process_output = pipe.read()

+        status = pipe.close()

+        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

+

+if __name__ == '__main__':

+    if len(sys.argv) < 1 or len(sys.argv) > 2:

+        print "Usage: %s jsontest-executable-path [input-testcase-directory]" % sys.argv[0]

+        sys.exit( 1 )

+

+    jsontest_executable_path = os.path.normpath( os.path.abspath( sys.argv[1] ) )

+    if len(sys.argv) > 1:

+        input_path = os.path.normpath( os.path.abspath( sys.argv[2] ) )

+    else:

+        input_path = None

+    status = runAllTests( jsontest_executable_path, input_path )

+    sys.exit( status )
\ No newline at end of file
diff --git a/test/test_array_01.expected b/test/test_array_01.expected
new file mode 100644
index 0000000..4aa8fb3
--- /dev/null
+++ b/test/test_array_01.expected
@@ -0,0 +1 @@
+.=[]

diff --git a/test/test_array_01.json b/test/test_array_01.json
new file mode 100644
index 0000000..60b0742
--- /dev/null
+++ b/test/test_array_01.json
@@ -0,0 +1 @@
+[]

diff --git a/test/test_array_02.expected b/test/test_array_02.expected
new file mode 100644
index 0000000..5b7c72a
--- /dev/null
+++ b/test/test_array_02.expected
@@ -0,0 +1,2 @@
+.=[]

+.[0]=1

diff --git a/test/test_array_02.json b/test/test_array_02.json
new file mode 100644
index 0000000..c02be12
--- /dev/null
+++ b/test/test_array_02.json
@@ -0,0 +1 @@
+[1]

diff --git a/test/test_array_03.expected b/test/test_array_03.expected
new file mode 100644
index 0000000..0ba568e
--- /dev/null
+++ b/test/test_array_03.expected
@@ -0,0 +1,6 @@
+.=[]

+.[0]=1

+.[1]=2

+.[2]=3

+.[3]=4

+.[4]=5

diff --git a/test/test_array_03.json b/test/test_array_03.json
new file mode 100644
index 0000000..ac8f422
--- /dev/null
+++ b/test/test_array_03.json
@@ -0,0 +1 @@
+[ 1, 2 ,  3,4,5]

diff --git a/test/test_array_04.expected b/test/test_array_04.expected
new file mode 100644
index 0000000..db58c30
--- /dev/null
+++ b/test/test_array_04.expected
@@ -0,0 +1,5 @@
+.=[]

+.[0]=1

+.[1]="abc"

+.[2]=12.3

+.[3]=-4

diff --git a/test/test_array_04.json b/test/test_array_04.json
new file mode 100644
index 0000000..0755478
--- /dev/null
+++ b/test/test_array_04.json
@@ -0,0 +1 @@
+[1, "abc" , 12.3, -4]

diff --git a/test/test_array_05.expected b/test/test_array_05.expected
new file mode 100644
index 0000000..82ad484
--- /dev/null
+++ b/test/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/test/test_array_05.json b/test/test_array_05.json
new file mode 100644
index 0000000..7809d6c
--- /dev/null
+++ b/test/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/test/test_array_06.expected b/test/test_array_06.expected
new file mode 100644
index 0000000..e087b63
--- /dev/null
+++ b/test/test_array_06.expected
@@ -0,0 +1,5 @@
+.=[]

+.[0]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

+.[1]="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"

+.[2]="ccccccccccccccccccccccc"

+.[3]="dddddddddddddddddddddddddddddddddddddddddddddddddddd"

diff --git a/test/test_array_06.json b/test/test_array_06.json
new file mode 100644
index 0000000..9777a64
--- /dev/null
+++ b/test/test_array_06.json
@@ -0,0 +1,4 @@
+[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 

+  "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",

+  "ccccccccccccccccccccccc",

+  "dddddddddddddddddddddddddddddddddddddddddddddddddddd" ]
\ No newline at end of file
diff --git a/test/test_basic_01.expected b/test/test_basic_01.expected
new file mode 100644
index 0000000..0527387
--- /dev/null
+++ b/test/test_basic_01.expected
@@ -0,0 +1 @@
+.=123456789

diff --git a/test/test_basic_01.json b/test/test_basic_01.json
new file mode 100644
index 0000000..57cf9b9
--- /dev/null
+++ b/test/test_basic_01.json
@@ -0,0 +1 @@
+0123456789

diff --git a/test/test_basic_02.expected b/test/test_basic_02.expected
new file mode 100644
index 0000000..9040e84
--- /dev/null
+++ b/test/test_basic_02.expected
@@ -0,0 +1 @@
+.=-123456789

diff --git a/test/test_basic_02.json b/test/test_basic_02.json
new file mode 100644
index 0000000..fe84da4
--- /dev/null
+++ b/test/test_basic_02.json
@@ -0,0 +1 @@
+-0123456789

diff --git a/test/test_basic_03.expected b/test/test_basic_03.expected
new file mode 100644
index 0000000..494278d
--- /dev/null
+++ b/test/test_basic_03.expected
@@ -0,0 +1,3 @@
+.=1.2345678

+

+

diff --git a/test/test_basic_03.json b/test/test_basic_03.json
new file mode 100644
index 0000000..feac150
--- /dev/null
+++ b/test/test_basic_03.json
@@ -0,0 +1,3 @@
+1.2345678

+

+

diff --git a/test/test_basic_04.expected b/test/test_basic_04.expected
new file mode 100644
index 0000000..659f744
--- /dev/null
+++ b/test/test_basic_04.expected
@@ -0,0 +1,2 @@
+.="abcdef"

+

diff --git a/test/test_basic_04.json b/test/test_basic_04.json
new file mode 100644
index 0000000..01374bd
--- /dev/null
+++ b/test/test_basic_04.json
@@ -0,0 +1,2 @@
+"abcdef"

+

diff --git a/test/test_basic_05.expected b/test/test_basic_05.expected
new file mode 100644
index 0000000..cb1cdad
--- /dev/null
+++ b/test/test_basic_05.expected
@@ -0,0 +1,2 @@
+.=null

+

diff --git a/test/test_basic_05.json b/test/test_basic_05.json
new file mode 100644
index 0000000..a6d4f5a
--- /dev/null
+++ b/test/test_basic_05.json
@@ -0,0 +1,2 @@
+null

+

diff --git a/test/test_basic_06.expected b/test/test_basic_06.expected
new file mode 100644
index 0000000..8b22731
--- /dev/null
+++ b/test/test_basic_06.expected
@@ -0,0 +1,2 @@
+.=true

+

diff --git a/test/test_basic_06.json b/test/test_basic_06.json
new file mode 100644
index 0000000..5d967af
--- /dev/null
+++ b/test/test_basic_06.json
@@ -0,0 +1,2 @@
+true

+

diff --git a/test/test_basic_07.expected b/test/test_basic_07.expected
new file mode 100644
index 0000000..4979ed5
--- /dev/null
+++ b/test/test_basic_07.expected
@@ -0,0 +1,2 @@
+.=false

+

diff --git a/test/test_basic_07.json b/test/test_basic_07.json
new file mode 100644
index 0000000..b7ee6c5
--- /dev/null
+++ b/test/test_basic_07.json
@@ -0,0 +1,2 @@
+false

+

diff --git a/test/test_basic_08.expected b/test/test_basic_08.expected
new file mode 100644
index 0000000..cb1cdad
--- /dev/null
+++ b/test/test_basic_08.expected
@@ -0,0 +1,2 @@
+.=null

+

diff --git a/test/test_basic_08.json b/test/test_basic_08.json
new file mode 100644
index 0000000..fe107f4
--- /dev/null
+++ b/test/test_basic_08.json
@@ -0,0 +1,3 @@
+// C++ style comment

+null

+

diff --git a/test/test_basic_09.expected b/test/test_basic_09.expected
new file mode 100644
index 0000000..cb1cdad
--- /dev/null
+++ b/test/test_basic_09.expected
@@ -0,0 +1,2 @@
+.=null

+

diff --git a/test/test_basic_09.json b/test/test_basic_09.json
new file mode 100644
index 0000000..e0cb089
--- /dev/null
+++ b/test/test_basic_09.json
@@ -0,0 +1,4 @@
+/* C style comment

+ */

+null

+

diff --git a/test/test_complex_01.expected b/test/test_complex_01.expected
new file mode 100644
index 0000000..44e753b
--- /dev/null
+++ b/test/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/test/test_complex_01.json b/test/test_complex_01.json
new file mode 100644
index 0000000..fb2f86c
--- /dev/null
+++ b/test/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/test/test_integer_01.expected b/test/test_integer_01.expected
new file mode 100644
index 0000000..24aa29e
--- /dev/null
+++ b/test/test_integer_01.expected
@@ -0,0 +1 @@
+.=2147483647

diff --git a/test/test_integer_01.json b/test/test_integer_01.json
new file mode 100644
index 0000000..e82c7ad
--- /dev/null
+++ b/test/test_integer_01.json
@@ -0,0 +1,2 @@
+// Max signed integer

+2147483647

diff --git a/test/test_integer_02.expected b/test/test_integer_02.expected
new file mode 100644
index 0000000..dab99eb
--- /dev/null
+++ b/test/test_integer_02.expected
@@ -0,0 +1 @@
+.=-2147483648

diff --git a/test/test_integer_02.json b/test/test_integer_02.json
new file mode 100644
index 0000000..548764e
--- /dev/null
+++ b/test/test_integer_02.json
@@ -0,0 +1,2 @@
+// Min signed integer

+-2147483648

diff --git a/test/test_integer_03.expected b/test/test_integer_03.expected
new file mode 100644
index 0000000..dde3260
--- /dev/null
+++ b/test/test_integer_03.expected
@@ -0,0 +1 @@
+.=4294967295

diff --git a/test/test_integer_03.json b/test/test_integer_03.json
new file mode 100644
index 0000000..18aeaf6
--- /dev/null
+++ b/test/test_integer_03.json
@@ -0,0 +1,2 @@
+// Max unsigned integer

+4294967295

diff --git a/test/test_integer_04.expected b/test/test_integer_04.expected
new file mode 100644
index 0000000..8da9013
--- /dev/null
+++ b/test/test_integer_04.expected
@@ -0,0 +1,2 @@
+.=0

+

diff --git a/test/test_integer_04.json b/test/test_integer_04.json
new file mode 100644
index 0000000..8202483
--- /dev/null
+++ b/test/test_integer_04.json
@@ -0,0 +1,3 @@
+// Min unsigned integer

+0

+

diff --git a/test/test_integer_05.expected b/test/test_integer_05.expected
new file mode 100644
index 0000000..238d1d6
--- /dev/null
+++ b/test/test_integer_05.expected
@@ -0,0 +1,2 @@
+.=1

+

diff --git a/test/test_integer_05.json b/test/test_integer_05.json
new file mode 100644
index 0000000..4797790
--- /dev/null
+++ b/test/test_integer_05.json
@@ -0,0 +1,2 @@
+1

+

diff --git a/test/test_object_01.expected b/test/test_object_01.expected
new file mode 100644
index 0000000..8e0634e
--- /dev/null
+++ b/test/test_object_01.expected
@@ -0,0 +1 @@
+.={}

diff --git a/test/test_object_01.json b/test/test_object_01.json
new file mode 100644
index 0000000..69a88e3
--- /dev/null
+++ b/test/test_object_01.json
@@ -0,0 +1 @@
+{}

diff --git a/test/test_object_02.expected b/test/test_object_02.expected
new file mode 100644
index 0000000..2c9de06
--- /dev/null
+++ b/test/test_object_02.expected
@@ -0,0 +1,2 @@
+.={}

+.count=1234

diff --git a/test/test_object_02.json b/test/test_object_02.json
new file mode 100644
index 0000000..bd157ec
--- /dev/null
+++ b/test/test_object_02.json
@@ -0,0 +1 @@
+{ "count" : 1234 }

diff --git a/test/test_object_03.expected b/test/test_object_03.expected
new file mode 100644
index 0000000..235a28e
--- /dev/null
+++ b/test/test_object_03.expected
@@ -0,0 +1,4 @@
+.={}

+.attribute="random"

+.count=1234

+.name="test"

diff --git a/test/test_object_03.json b/test/test_object_03.json
new file mode 100644
index 0000000..0947a44
--- /dev/null
+++ b/test/test_object_03.json
@@ -0,0 +1,5 @@
+{ 

+	"count" : 1234,

+	"name" : "test",

+	"attribute" : "random"

+}

diff --git a/test/test_object_04.expected b/test/test_object_04.expected
new file mode 100644
index 0000000..cf4d7c3
--- /dev/null
+++ b/test/test_object_04.expected
@@ -0,0 +1,2 @@
+.={}

+.=1234

diff --git a/test/test_object_04.json b/test/test_object_04.json
new file mode 100644
index 0000000..f1e364a
--- /dev/null
+++ b/test/test_object_04.json
@@ -0,0 +1,3 @@
+{ 

+	"" : 1234

+}

diff --git a/test/test_preserve_comment_01.expected b/test/test_preserve_comment_01.expected
new file mode 100644
index 0000000..b5616a9
--- /dev/null
+++ b/test/test_preserve_comment_01.expected
@@ -0,0 +1,3 @@
+.={}

+.first=1

+.second=2

diff --git a/test/test_preserve_comment_01.json b/test/test_preserve_comment_01.json
new file mode 100644
index 0000000..0291fff
--- /dev/null
+++ b/test/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/test/test_real_01.expected b/test/test_real_01.expected
new file mode 100644
index 0000000..57dee39
--- /dev/null
+++ b/test/test_real_01.expected
@@ -0,0 +1,2 @@
+.=8589934592

+

diff --git a/test/test_real_01.json b/test/test_real_01.json
new file mode 100644
index 0000000..5cb1bbf
--- /dev/null
+++ b/test/test_real_01.json
@@ -0,0 +1,3 @@
+// 2^33 => out of integer range, switch to double

+8589934592

+

diff --git a/test/test_real_02.expected b/test/test_real_02.expected
new file mode 100644
index 0000000..181592a
--- /dev/null
+++ b/test/test_real_02.expected
@@ -0,0 +1,2 @@
+.=-4294967295

+

diff --git a/test/test_real_02.json b/test/test_real_02.json
new file mode 100644
index 0000000..45092ef
--- /dev/null
+++ b/test/test_real_02.json
@@ -0,0 +1,3 @@
+// -2^32 => out of signed integer range, switch to double

+-4294967295

+

diff --git a/test/test_real_03.expected b/test/test_real_03.expected
new file mode 100644
index 0000000..181592a
--- /dev/null
+++ b/test/test_real_03.expected
@@ -0,0 +1,2 @@
+.=-4294967295

+

diff --git a/test/test_real_03.json b/test/test_real_03.json
new file mode 100644
index 0000000..45092ef
--- /dev/null
+++ b/test/test_real_03.json
@@ -0,0 +1,3 @@
+// -2^32 => out of signed integer range, switch to double

+-4294967295

+

diff --git a/test/test_real_04.expected b/test/test_real_04.expected
new file mode 100644
index 0000000..2f84bf1
--- /dev/null
+++ b/test/test_real_04.expected
@@ -0,0 +1,2 @@
+.=1.2345678

+

diff --git a/test/test_real_04.json b/test/test_real_04.json
new file mode 100644
index 0000000..7e71794
--- /dev/null
+++ b/test/test_real_04.json
@@ -0,0 +1,3 @@
+// 1.2345678

+12345678e-7

+

diff --git a/test/test_real_05.expected b/test/test_real_05.expected
new file mode 100644
index 0000000..168f6e8
--- /dev/null
+++ b/test/test_real_05.expected
@@ -0,0 +1,3 @@
+.=1234567.8

+

+

diff --git a/test/test_real_05.json b/test/test_real_05.json
new file mode 100644
index 0000000..950f6a7
--- /dev/null
+++ b/test/test_real_05.json
@@ -0,0 +1,3 @@
+// 1234567.8

+0.12345678e7

+

diff --git a/test/test_real_06.expected b/test/test_real_06.expected
new file mode 100644
index 0000000..45906e3
--- /dev/null
+++ b/test/test_real_06.expected
@@ -0,0 +1,3 @@
+.=-1.2345678

+

+

diff --git a/test/test_real_06.json b/test/test_real_06.json
new file mode 100644
index 0000000..dde1916
--- /dev/null
+++ b/test/test_real_06.json
@@ -0,0 +1,3 @@
+// -1.2345678

+-12345678e-7

+

diff --git a/test/test_real_07.expected b/test/test_real_07.expected
new file mode 100644
index 0000000..f2922f9
--- /dev/null
+++ b/test/test_real_07.expected
@@ -0,0 +1,3 @@
+.=-1234567.8

+

+

diff --git a/test/test_real_07.json b/test/test_real_07.json
new file mode 100644
index 0000000..dd43ba7
--- /dev/null
+++ b/test/test_real_07.json
@@ -0,0 +1,3 @@
+// -1234567.8

+-0.12345678e7

+