- reorganized repository to match standard layout
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' )