[Cmake-commits] CMake branch, next, updated. v3.1.0-1844-g3352c05
Brad King
brad.king at kitware.com
Tue Jan 13 14:48:48 EST 2015
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".
The branch, next has been updated
via 3352c05b873c03505d877acf7dbc922319e1f6a2 (commit)
via 534c69261080277d213c3e344987266a92501363 (commit)
via 71ec1d16980b2ea507536976a098d7c246a663eb (commit)
via 0a3e091f3be9f882c6c6ba1255a1cfe52881f589 (commit)
via 60218d5e51cc31fb3179434bb1aaefba910458bc (commit)
via 8345ddb7ae431c6aeafbd24a368886b70e162bd0 (commit)
via be2c3ac78174ed0a9d5b23e51719cc3ff220ed3a (commit)
via a263d519fffab082fc31f8e3f454726e3fbd8363 (commit)
via 53f6ccb0ee76a2b9ac40abd5ec5e07aa55fbb393 (commit)
via 32fd56b066c28758e31ae97d4b16216b3633a843 (commit)
from 20bd919dd9d9f4f0f79054f976b50eb0cd272217 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3352c05b873c03505d877acf7dbc922319e1f6a2
commit 3352c05b873c03505d877acf7dbc922319e1f6a2
Merge: 20bd919 534c692
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 14:48:45 2015 -0500
Commit: CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Tue Jan 13 14:48:45 2015 -0500
Merge topic 'cdash_upload_file_mode' into next
534c6926 Add support to ctest_submit to upload files to cdash with CDASH_UPLOAD.
71ec1d16 jsoncpp: Add README-CMake.txt
0a3e091f jsoncpp: Definen isfinite when not available on ancient glibc
60218d5e jsoncpp: Add missing <iosfwd> include in json/writer.h
8345ddb7 jsoncpp: Disable warnings to avoid changing 3rd party code
be2c3ac7 jsoncpp: Build the library within CMake
a263d519 Merge branch 'jsoncpp-upstream' into import-jsoncpp
53f6ccb0 JsonCpp 1.0.0 (reduced)
32fd56b0 jsoncpp: Add .gitattributes to skip whitespace checks
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=534c69261080277d213c3e344987266a92501363
commit 534c69261080277d213c3e344987266a92501363
Author: Bill Hoffman <bill.hoffman at kitware.com>
AuthorDate: Tue Dec 23 11:03:14 2014 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:45:54 2015 -0500
Add support to ctest_submit to upload files to cdash with CDASH_UPLOAD.
This adds support for the new cdash API where arbitrary files can be
uploaded to the CDash server. This CDash API communicates via json
files so the json parser jsoncpp was added to the Utilities directory.
In addition since CDash tracks the md5 sum of the files uploaded the
--mtime option was added to cmake -E tar so that tar files could be
created that would have the same md5sum with the same content. The first
supported file upload type to CDash is a GCOV with branches coverage
tar file. To support this a Modules/CTestGCOV.cmake was added to run
gcov for a project via a CMake function.
diff --git a/Help/command/ctest_submit.rst b/Help/command/ctest_submit.rst
index d9b0b78..316a43d 100644
--- a/Help/command/ctest_submit.rst
+++ b/Help/command/ctest_submit.rst
@@ -37,3 +37,14 @@ timed-out submission before attempting to re-submit.
The RETRY_COUNT option specifies how many times to retry a timed-out
submission.
+
+::
+
+ ctest_submit([CDASH_UPLOAD file]
+ [CDASH_UPLOAD_TYPE type_string])
+
+This second signature is used to upload files to CDash via the CDash
+file upload API. The api first sends a request to upload to CDash along
+with the md5 sum of the file. If CDash does not already have the file,
+then it is uploaded. Along with the file, a CDash type string is specified
+to tell CDash which handler to use to process the data.
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index 5196485..d96b96f 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -63,6 +63,7 @@ All Modules
/module/CPack
/module/CPackWIX
/module/CTest
+ /module/CTestGCOV
/module/CTestScriptMode
/module/CTestUseLaunchers
/module/Dart
diff --git a/Help/module/CTestGCOV.rst b/Help/module/CTestGCOV.rst
new file mode 100644
index 0000000..b1077fe
--- /dev/null
+++ b/Help/module/CTestGCOV.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CTestGCOV.cmake
diff --git a/Modules/CTestGCOV.cmake b/Modules/CTestGCOV.cmake
new file mode 100644
index 0000000..f505159
--- /dev/null
+++ b/Modules/CTestGCOV.cmake
@@ -0,0 +1,72 @@
+#.rst:
+# CTestGCOV
+# ---------
+#
+# This module provides the function ``run_gcov_and_package_for_cdash``.
+# The function will run gcov on the .gcda files in a binary tree and then
+# package all of the .gcov files into a tar file with a data.json.
+# This file can be sent to a CDash server for display with the
+# :command:`ctest_submit(CDASH_UPLOAD)` command.
+#
+# .. command:: run_gcov_and_package_for_cdash
+#
+# ::
+#
+# run_gcov_and_package_for_cdash(<tarfile> <source_dir> <binary_dir>
+# <gcov_command>)
+#
+# Run gcov and package a tar gz file for cdash. ``<tarfile>`` is the name
+# of the tarfile that is created and it will be placed in ``<binary_dir>``.
+# ``<source_dir>`` is the source directory for the build and ``<binary_dir>``
+# is the binary directory for the build. The ``<gcov_command>`` is a full
+# path to ``gcov`` for the machine.
+
+#=============================================================================
+# Copyright 2014-2015 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+function(run_gcov_and_package_for_cdash tarfile source_dir binary_dir
+ gcov_command)
+ # run gcov on each gcda file in the binary tree
+ file(GLOB_RECURSE GCDA_FILES RELATIVE ${binary_dir} "*.gcda")
+
+ # return early if no coverage files were found
+ list(LENGTH GCDA_FILES len)
+ if(len EQUAL 0)
+ message("CTestGCOV: No .gcda files found, ignoring coverage request.")
+ return()
+ endif()
+
+ foreach (gcda_file ${GCDA_FILES})
+ # get the directory of the gcda file
+ get_filename_component(gcov_dir ${gcda_file} DIRECTORY)
+ # run gcov
+ execute_process(COMMAND
+ ${gcov_command} -b -o ${gcov_dir} ${gcda_file}
+ OUTPUT_VARIABLE out
+ WORKING_DIRECTORY ${binary_dir})
+ endforeach()
+ # create json file with project information
+ file(WRITE ${binary_dir}/data.json
+ "{
+ \"Source\": \"${source_dir}\",
+ \"Binary\": \"${binary_dir}\"
+}"
+ )
+ # collect the gcov files
+ file(GLOB_RECURSE gcov_files RELATIVE ${binary_dir} "*.gcov")
+ # tar up the coverage info
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar cvf ${tarfile}
+ --mtime=1970-01-01\ 0:0:0\ UTC ${gcov_files} data.json
+ WORKING_DIRECTORY ${binary_dir})
+endfunction()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 96f4709..78bef91 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -533,6 +533,7 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmCTestConfigureHandler.cxx
CTest/cmCTestCoverageCommand.cxx
CTest/cmCTestCoverageHandler.cxx
+ CTest/cmCTestCurl.cxx
CTest/cmParseMumpsCoverage.cxx
CTest/cmParseCacheCoverage.cxx
CTest/cmParseGTMCoverage.cxx
@@ -583,7 +584,7 @@ set(CTEST_SRCS cmCTest.cxx
# Build CTestLib
add_library(CTestLib ${CTEST_SRCS})
-target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES} ${CMAKE_XMLRPC_LIBRARIES})
+target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES} ${CMAKE_XMLRPC_LIBRARIES} cmjsoncpp)
#
# Sources for CPack
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
new file mode 100644
index 0000000..b354592
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -0,0 +1,258 @@
+#include "cmCTestCurl.h"
+#include "cmSystemTools.h"
+#include "cmCTest.h"
+
+cmCTestCurl::cmCTestCurl(cmCTest* ctest)
+{
+ this->CTest = ctest;
+ this->SetProxyType();
+ this->UseHttp10 = false;
+ // In windows, this will init the winsock stuff
+ ::curl_global_init(CURL_GLOBAL_ALL);
+ // default is to verify https
+ this->VerifyPeerOff = false;
+ this->VerifyHostOff = false;
+ this->TimeOutSeconds = 0;
+}
+
+namespace
+{
+static size_t
+curlWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
+ void *data)
+{
+ int realsize = (int)(size * nmemb);
+
+ std::vector<char> *vec
+ = static_cast<std::vector<char>* >(data);
+ const char* chPtr = static_cast<char*>(ptr);
+ vec->insert(vec->end(), chPtr, chPtr + realsize);
+ return realsize;
+}
+
+static size_t
+curlDebugCallback(CURL *, curl_infotype, char *chPtr,
+ size_t size, void *data)
+{
+ std::vector<char> *vec
+ = static_cast<std::vector<char>* >(data);
+ vec->insert(vec->end(), chPtr, chPtr + size);
+
+ return size;
+}
+
+}
+void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args)
+{
+ for( std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i)
+ {
+ if(*i == "CURLOPT_SSL_VERIFYPEER_OFF")
+ {
+ this->VerifyPeerOff = true;
+ }
+ if(*i == "CURLOPT_SSL_VERIFYHOST_OFF")
+ {
+ this->VerifyHostOff = true;
+ }
+ }
+}
+
+bool cmCTestCurl::InitCurl()
+{
+ this->Curl = curl_easy_init();
+ if(!this->Curl)
+ {
+ return false;
+ }
+ if(this->VerifyPeerOff)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);
+ }
+ if(this->VerifyHostOff)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+ if(this->HTTPProxy.size())
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);
+ if (this->HTTPProxyAuth.size() > 0)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ if(this->UseHttp10)
+ {
+ curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ // enable HTTP ERROR parsing
+ curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ return true;
+}
+
+
+bool cmCTestCurl::UploadFile(std::string const& local_file,
+ std::string const& url,
+ std::string const& fields,
+ std::string& response)
+{
+ response = "";
+ if(!this->InitCurl())
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ /* enable uploading */
+ curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);
+ // if there is little to no activity for too long stop submitting
+ if(this->TimeOutSeconds)
+ {
+ ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME,
+ this->TimeOutSeconds);
+ }
+ /* HTTP PUT please */
+ ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);
+
+ FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ if(!ftpfile)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not open file for upload: " << local_file << "\n");
+ return false;
+ }
+ // set the url
+ std::string upload_url = url;
+ upload_url += "?";
+ upload_url += fields;
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());
+ // now specify which file to upload
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,
+ static_cast<long>(filelen));
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION,
+ curlDebugCallback);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void *)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void *)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ // Now run off and do what you've been told!
+ ::curl_easy_perform(this->Curl);
+ ::fclose(ftpfile);
+ ::curl_global_cleanup();
+
+ if ( responseData.size() > 0 )
+ {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Curl response: [" << response << "]\n");
+ }
+ std::string curlDebug;
+ if ( debugData.size() > 0 )
+ {
+ curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
+ }
+ if(response.size() == 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "No response from server.\n" <<
+ curlDebug);
+ return false;
+ }
+ return true;
+}
+
+bool cmCTestCurl::HttpRequest(std::string const& url,
+ std::string const& fields,
+ std::string& response)
+{
+ response = "";
+ cmCTestLog(this->CTest, DEBUG, "HttpRequest\n"
+ << "url: " << url << "\n"
+ << "fields " << fields << "\n");
+ if(!this->InitCurl())
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
+ curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);
+ //set response options
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION,
+ curlDebugCallback);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void *)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void *)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+
+ CURLcode res = ::curl_easy_perform(this->Curl);
+
+ ::curl_easy_cleanup(this->Curl);
+ ::curl_global_cleanup();
+ if ( responseData.size() > 0 )
+ {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl response: [" << response << "]\n");
+ }
+ if ( debugData.size() > 0 )
+ {
+ std::string curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
+ }
+ cmCTestLog(this->CTest, DEBUG, "Curl res: " << res << "\n");
+ return (res == 0);
+}
+
+void cmCTestCurl::SetProxyType()
+{
+ if ( cmSystemTools::GetEnv("HTTP_PROXY") )
+ {
+ this->HTTPProxy = cmSystemTools::GetEnv("HTTP_PROXY");
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_PORT") )
+ {
+ this->HTTPProxy += ":";
+ this->HTTPProxy += cmSystemTools::GetEnv("HTTP_PROXY_PORT");
+ }
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_TYPE") )
+ {
+ // this is the default
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ std::string type = cmSystemTools::GetEnv("HTTP_PROXY_TYPE");
+ // HTTP/SOCKS4/SOCKS5
+ if ( type == "HTTP" )
+ {
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ }
+ else if ( type == "SOCKS4" )
+ {
+ this->HTTPProxyType = CURLPROXY_SOCKS4;
+ }
+ else if ( type == "SOCKS5" )
+ {
+ this->HTTPProxyType = CURLPROXY_SOCKS5;
+ }
+ }
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_USER") )
+ {
+ this->HTTPProxyAuth = cmSystemTools::GetEnv("HTTP_PROXY_USER");
+ }
+ if ( cmSystemTools::GetEnv("HTTP_PROXY_PASSWD") )
+ {
+ this->HTTPProxyAuth += ":";
+ this->HTTPProxyAuth += cmSystemTools::GetEnv("HTTP_PROXY_PASSWD");
+ }
+ }
+}
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
new file mode 100644
index 0000000..bb5c74a
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.h
@@ -0,0 +1,50 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmCTestCurl_h
+#define cmCTestCurl_h
+#include "cm_curl.h"
+#include "cmStandardIncludes.h"
+class cmCTest;
+
+class cmCTestCurl
+{
+public:
+ cmCTestCurl(cmCTest*);
+ bool UploadFile(std::string const& url,
+ std::string const& file,
+ std::string const& fields,
+ std::string& response);
+ bool HttpRequest(std::string const& url,
+ std::string const& fields,
+ std::string& response);
+ // currently only supports CURLOPT_SSL_VERIFYPEER_OFF
+ // and CURLOPT_SSL_VERIFYHOST_OFF
+ void SetCurlOptions(std::vector<std::string> const& args);
+ void SetUseHttp10On() { this->UseHttp10 = true;}
+ void SetTimeOutSeconds(int s) { this->TimeOutSeconds = s;}
+protected:
+ void SetProxyType();
+ bool InitCurl();
+private:
+ cmCTest* CTest;
+ CURL* Curl;
+ std::string HTTPProxyAuth;
+ std::string HTTPProxy;
+ curl_proxytype HTTPProxyType;
+ bool VerifyHostOff;
+ bool VerifyPeerOff;
+ bool UseHttp10;
+ int TimeOutSeconds;
+};
+
+
+#endif
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 4005a63..dcd7982 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -27,7 +27,8 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
= this->Makefile->GetDefinition("CTEST_TRIGGER_SITE");
bool ctestDropSiteCDash
= this->Makefile->IsOn("CTEST_DROP_SITE_CDASH");
-
+ const char* ctestProjectName
+ = this->Makefile->GetDefinition("CTEST_PROJECT_NAME");
if ( !ctestDropMethod )
{
ctestDropMethod = "http";
@@ -43,7 +44,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// error: CDash requires CTEST_DROP_LOCATION definition
// in CTestConfig.cmake
}
-
+ this->CTest->SetCTestConfiguration("ProjectName", ctestProjectName);
this->CTest->SetCTestConfiguration("DropMethod", ctestDropMethod);
this->CTest->SetCTestConfiguration("DropSite", ctestDropSite);
this->CTest->SetCTestConfiguration("DropLocation", ctestDropLocation);
@@ -144,6 +145,13 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
static_cast<cmCTestSubmitHandler*>(handler)->SetOption("InternalTest",
this->InternalTest ? "ON" : "OFF");
+ if(this->CDashUploadFile.size())
+ {
+ static_cast<cmCTestSubmitHandler*>(handler)->
+ SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
+ static_cast<cmCTestSubmitHandler*>(handler)->
+ SetOption("CDashUploadType", this->CDashUploadType.c_str());
+ }
return handler;
}
@@ -178,6 +186,16 @@ bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
return true;
}
+ if(arg == "CDASH_UPLOAD")
+ {
+ this->ArgumentDoing = ArgumentDoingCDashUpload;
+ return true;
+ }
+ if(arg == "CDASH_UPLOAD_TYPE")
+ {
+ this->ArgumentDoing = ArgumentDoingCDashUploadType;
+ return true;
+ }
if(arg == "INTERNAL_TEST_CHECKSUM")
{
this->InternalTest = true;
@@ -240,6 +258,17 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg)
return true;
}
+ if(this->ArgumentDoing == ArgumentDoingCDashUpload)
+ {
+ this->CDashUploadFile = arg;
+ return true;
+ }
+ if(this->ArgumentDoing == ArgumentDoingCDashUploadType)
+ {
+ this->CDashUploadType = arg;
+ return true;
+ }
+
// Look for other arguments.
return this->Superclass::CheckArgumentValue(arg);
}
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index 3673fbd..cb0ac61 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -64,6 +64,8 @@ protected:
ArgumentDoingFiles,
ArgumentDoingRetryDelay,
ArgumentDoingRetryCount,
+ ArgumentDoingCDashUpload,
+ ArgumentDoingCDashUploadType,
ArgumentDoingLast2
};
@@ -74,6 +76,8 @@ protected:
cmCTest::SetOfStrings Files;
std::string RetryCount;
std::string RetryDelay;
+ std::string CDashUploadFile;
+ std::string CDashUploadType;
};
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index fea94ba..3e5fa38 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -10,7 +10,8 @@
See the License for more information.
============================================================================*/
#include "cmCTestSubmitHandler.h"
-
+#include "cmCTestScriptHandler.h"
+#include "cmake.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
#include "cmGeneratedFileStream.h"
@@ -23,8 +24,10 @@
// For XML-RPC submission
#include "cm_xmlrpc.h"
+#include <cm_jsoncpp_reader.h>
// For curl submission
#include "cm_curl.h"
+#include "cmCTestCurl.h"
#include <sys/stat.h>
@@ -1055,9 +1058,164 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC(std::string const&,
}
#endif
+void cmCTestSubmitHandler::ConstructCDashURL(std::string& dropMethod,
+ std::string& url)
+{
+ dropMethod = this->CTest->GetCTestConfiguration("DropMethod");
+ url = dropMethod;
+ url += "://";
+ if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
+ {
+ url += this->CTest->GetCTestConfiguration("DropSiteUser");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str());
+ if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
+ {
+ url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
+ }
+ url += "@";
+ }
+ url += this->CTest->GetCTestConfiguration("DropSite") +
+ this->CTest->GetCTestConfiguration("DropLocation");
+}
+
+
+int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
+ std::string const& typeString)
+{
+ if(!cmSystemTools::FileExists(file))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Upload file not found: " << file << "\n");
+ }
+ cmCTestCurl curl(this->CTest);
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::vector<std::string> args;
+ cmSystemTools::ExpandListArgument(curlopt, args);
+ curl.SetCurlOptions(args);
+ curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+ std::string dropMethod;
+ std::string url;
+ this->ConstructCDashURL(dropMethod, url);
+ std::string::size_type pos = url.find("submit.php?");
+ url = url.substr(0, pos+10);
+ if ( ! (dropMethod == "http" || dropMethod == "https" ) )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Only http and https are supported for CDASH_UPLOAD\n");
+ return -1;
+ }
+ char md5sum[33];
+ md5sum[32] = 0;
+ cmSystemTools::ComputeFileMD5(file, md5sum);
+ // 1. request the buildid and check to see if the file
+ // has already been uploaded
+ // TODO I added support for subproject. You would need to add
+ // a "&subproject=subprojectname" to the first POST.
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script"));
+ cmake* cm = ch->GetCMake();
+ const char* subproject = cm->GetProperty("SubProject", cmProperty::GLOBAL);
+ std::ostringstream str;
+ str << "project="
+ << this->CTest->GetCTestConfiguration("ProjectName") << "&";
+ if(subproject)
+ {
+ str << "subproject=" << subproject << "&";
+ }
+ str << "stamp=" << this->CTest->GetCurrentTag() << "-"
+ << this->CTest->GetTestModelString() << "&"
+ << "model=" << this->CTest->GetTestModelString() << "&"
+ << "build=" << this->CTest->GetCTestConfiguration("BuildName") << "&"
+ << "site=" << this->CTest->GetCTestConfiguration("Site") << "&"
+ << "track=" << this->CTest->GetTestModelString() << "&"
+ << "starttime=" << (int)cmSystemTools::GetTime() << "&"
+ << "endtime=" << (int)cmSystemTools::GetTime() << "&"
+ << "datafilesmd5[0]=" << md5sum << "&"
+ << "type=" << typeString;
+ std::string fields = str.str();
+ cmCTestLog(this->CTest, DEBUG, "fields: " << fields << "\nurl:"
+ << url << "\nfile: " << file << "\n");
+ std::string response;
+ if(!curl.HttpRequest(url, fields, response))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error in HttpRequest\n" << response);
+ return -1;
+ }
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Request upload response: [" << response << "]\n");
+ Json::Value json;
+ Json::Reader reader;
+ if(!reader.parse(response, json))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error parsing json string [" << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ if(json["status"].asInt() != 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad status returned from CDash: "
+ << json["status"].asInt());
+ return -1;
+ }
+ if(json["datafilesmd5"].isArray())
+ {
+ int datares = json["datafilesmd5"][0].asInt();
+ if(datares == 1)
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File already exists on CDash, skip upload "
+ << file << "\n");
+ return 0;
+ }
+ }
+ else
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "bad datafilesmd5 value in response "
+ << response << "\n");
+ return -1;
+ }
+
+ std::string upload_as = cmSystemTools::GetFilenameName(file);
+ std::ostringstream fstr;
+ fstr << "type=" << typeString << "&"
+ << "md5=" << md5sum << "&"
+ << "filename=" << upload_as << "&"
+ << "buildid=" << json["buildid"].asString();
+ if(!curl.UploadFile(file, url, fstr.str(), response))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error uploading to CDash. "
+ << file << " " << url << " " << fstr.str());
+ return -1;
+ }
+ if(!reader.parse(response, json))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error parsing json string [" << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Upload file response: [" << response << "]\n");
+ return 0;
+}
+
//----------------------------------------------------------------------------
int cmCTestSubmitHandler::ProcessHandler()
{
+ const char* cdashUploadFile = this->GetOption("CDashUploadFile");
+ const char* cdashUploadType = this->GetOption("CDashUploadType");
+ if(cdashUploadFile && cdashUploadType)
+ {
+ return this->HandleCDashUploadFile(std::string(cdashUploadFile),
+ std::string(cdashUploadType));
+ }
std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
// cdash does not need to trigger so just return true
if(iscdash.size())
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
index accabd1..f9cd894 100644
--- a/Source/CTest/cmCTestSubmitHandler.h
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -41,6 +41,11 @@ public:
/** Specify a set of files to submit. */
void SelectFiles(cmCTest::SetOfStrings const& files);
+ // handle the cdash file upload protocol
+ int HandleCDashUploadFile(std::string const& file, std::string const& type);
+
+ void ConstructCDashURL(std::string& dropMethod, std::string& url);
+
private:
void SetLogFile(std::ostream* ost) { this->LogFile = ost; }
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index a2aecac..fc4c40d 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -247,6 +247,11 @@ bool cmArchiveWrite::AddPath(const char* path,
return true;
}
+// function from libarchive
+extern "C"
+{
+ time_t __archive_get_date(time_t, const char*);
+}
//----------------------------------------------------------------------------
bool cmArchiveWrite::AddFile(const char* file,
size_t skip, const char* prefix)
@@ -275,6 +280,17 @@ bool cmArchiveWrite::AddFile(const char* file,
this->Error += cm_archive_error_string(this->Disk);
return false;
}
+ if(this->MTime.size())
+ {
+ time_t t = __archive_get_date(0, this->MTime.c_str());
+ if (t == -1)
+ {
+ this->Error = "__archive_get_date: Unable to parse mtime: ";
+ this->Error += "[" + this->MTime + "]";
+ return false;
+ }
+ archive_entry_set_mtime(e, t, 0);
+ }
// Clear acl and xattr fields not useful for distribution.
archive_entry_acl_clear(e);
archive_entry_xattr_clear(e);
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
index a6dcc0e..987e95c 100644
--- a/Source/cmArchiveWrite.h
+++ b/Source/cmArchiveWrite.h
@@ -74,6 +74,7 @@ public:
// std::cout.
void SetVerbose(bool v) { this->Verbose = v; }
+ void SetMTime(const char* t) { if(t) {this->MTime = t;}}
private:
bool Okay() const { return this->Error.empty(); }
bool AddPath(const char* path, size_t skip, const char* prefix);
@@ -90,6 +91,7 @@ private:
struct archive* Disk;
bool Verbose;
std::string Error;
+ std::string MTime;
};
#endif
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index c769154..372d41c 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1469,7 +1469,7 @@ bool cmSystemTools::IsPathToFramework(const char* path)
bool cmSystemTools::CreateTar(const char* outFileName,
const std::vector<std::string>& files,
cmTarCompression compressType,
- bool verbose)
+ bool verbose, const char* mtime)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
@@ -1501,6 +1501,10 @@ bool cmSystemTools::CreateTar(const char* outFileName,
}
cmArchiveWrite a(fout, compress,
cmArchiveWrite::TypeTAR);
+ if(mtime)
+ {
+ a.SetMTime(mtime);
+ }
a.SetVerbose(verbose);
for(std::vector<std::string>::const_iterator i = files.begin();
i != files.end(); ++i)
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 09ceea6..1c7208f 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -394,9 +394,9 @@ public:
bool verbose);
static bool CreateTar(const char* outFileName,
const std::vector<std::string>& files,
- cmTarCompression compressType, bool verbose);
- static bool ExtractTar(const char* inFileName,
- bool verbose);
+ cmTarCompression compressType, bool verbose,
+ const char* mtime=0);
+ static bool ExtractTar(const char* inFileName, bool verbose);
// This should be called first thing in main
// it will keep child processes from inheriting the
// stdin and stdout of this process. This is important
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 70d98d2..3465e55 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -729,9 +729,21 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
std::string flags = args[2];
std::string outFile = args[3];
std::vector<std::string> files;
+ std::string mtime;
for (std::string::size_type cc = 4; cc < args.size(); cc ++)
{
- files.push_back(args[cc]);
+ // if the first 8 chars of an arg are --mtime= and that arg
+ // is not a file on disk, treat it is the --mtime= flag and
+ // not a file
+ if( (args[cc].substr(0, 8) == "--mtime=") &&
+ !cmSystemTools::FileExists(args[cc]))
+ {
+ mtime = args[cc].substr(8);
+ }
+ else
+ {
+ files.push_back(args[cc]);
+ }
}
cmSystemTools::cmTarCompression compress =
cmSystemTools::TarCompressNone;
@@ -773,8 +785,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
else if ( flags.find_first_of('c') != flags.npos )
{
+ const char* mtimestr = 0;
+ if(mtime.size())
+ {
+ mtimestr = mtime.c_str();
+ }
if ( !cmSystemTools::CreateTar(
- outFile.c_str(), files, compress, verbose) )
+ outFile.c_str(), files, compress, verbose, mtimestr) )
{
cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
return 1;
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=71ec1d16980b2ea507536976a098d7c246a663eb
commit 71ec1d16980b2ea507536976a098d7c246a663eb
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 12:00:16 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:45:48 2015 -0500
jsoncpp: Add README-CMake.txt
Describe how to update jsoncpp from upstream.
diff --git a/Utilities/cmjsoncpp/README-CMake.txt b/Utilities/cmjsoncpp/README-CMake.txt
new file mode 100644
index 0000000..bf74094
--- /dev/null
+++ b/Utilities/cmjsoncpp/README-CMake.txt
@@ -0,0 +1,66 @@
+The Utilities/cmjsoncpp directory contains a reduced distribution
+of the jsoncpp source tree with only the library source code and
+CMake build system. It is not a submodule; the actual content is part
+of our source tree and changes can be made and committed directly.
+
+We update from upstream using Git's "subtree" merge strategy. A
+special branch contains commits of upstream jsoncpp snapshots and
+nothing else. No Git ref points explicitly to the head of this
+branch, but it is merged into our history.
+
+Update jsoncpp from upstream as follows. Create a local branch to
+explicitly reference the upstream snapshot branch head:
+
+ git branch jsoncpp-upstream 53f6ccb0
+
+Use a temporary directory to checkout the branch:
+
+ mkdir jsoncpp-tmp
+ cd jsoncpp-tmp
+ git init
+ git pull .. jsoncpp-upstream
+ rm -rf *
+
+Now place the (reduced) jsoncpp content in this directory. See
+instructions shown by
+
+ git log 53f6ccb0
+
+for help extracting the content from the upstream svn repo. Then run
+the following commands to commit the new version. Substitute the
+appropriate date and version number:
+
+ git add --all
+
+ GIT_AUTHOR_NAME='JsonCpp Upstream' \
+ GIT_AUTHOR_EMAIL='kwrobot at kitware.com' \
+ GIT_AUTHOR_DATE='Thu Nov 20 08:45:58 2014 -0600' \
+ git commit -m 'JsonCpp 1.0.0 (reduced)' &&
+ git commit --amend
+
+Edit the commit message to describe the procedure used to obtain the
+content. Then push the changes back up to the main local repository:
+
+ git push .. HEAD:jsoncpp-upstream
+ cd ..
+ rm -rf jsoncpp-tmp
+
+Create a topic in the main repository on which to perform the update:
+
+ git checkout -b update-jsoncpp master
+
+Merge the jsoncpp-upstream branch as a subtree:
+
+ git merge -s recursive -X subtree=Utilities/cmjsoncpp \
+ jsoncpp-upstream
+
+If there are conflicts, resolve them and commit. Build and test the
+tree. Commit any additional changes needed to succeed.
+
+Finally, run
+
+ git rev-parse --short=8 jsoncpp-upstream
+
+to get the commit from which the jsoncpp-upstream branch must be started
+on the next update. Edit the "git branch jsoncpp-upstream" line above to
+record it, and commit this file.
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0a3e091f3be9f882c6c6ba1255a1cfe52881f589
commit 0a3e091f3be9f882c6c6ba1255a1cfe52881f589
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 11:54:06 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:42:31 2015 -0500
jsoncpp: Definen isfinite when not available on ancient glibc
The glibc 2.1 headers provide isfinite only in C99 mode.
Add its definition ourselves.
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp b/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
index 89964ea..0a42cc4 100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
+++ b/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
@@ -21,6 +21,13 @@
#define snprintf _snprintf
#endif
+// Ancient glibc
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
+# if !defined(isfinite)
+# define isfinite __finite
+# endif
+#endif
+
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
// Disable warning about strdup being deprecated.
#pragma warning(disable : 4996)
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=60218d5e51cc31fb3179434bb1aaefba910458bc
commit 60218d5e51cc31fb3179434bb1aaefba910458bc
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 11:27:43 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:42:26 2015 -0500
jsoncpp: Add missing <iosfwd> include in json/writer.h
The header uses std::ostream, so it must be declared.
diff --git a/Utilities/cmjsoncpp/include/json/writer.h b/Utilities/cmjsoncpp/include/json/writer.h
index dc9e46f..397bf6a 100644
--- a/Utilities/cmjsoncpp/include/json/writer.h
+++ b/Utilities/cmjsoncpp/include/json/writer.h
@@ -9,6 +9,7 @@
#if !defined(JSON_IS_AMALGAMATION)
#include "value.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <iosfwd>
#include <vector>
#include <string>
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8345ddb7ae431c6aeafbd24a368886b70e162bd0
commit 8345ddb7ae431c6aeafbd24a368886b70e162bd0
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 10:45:23 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:42:20 2015 -0500
jsoncpp: Disable warnings to avoid changing 3rd party code
Add '-w' or equivalent flag on compilers supporting it.
Tell MSVC to use its lowest warning level inside jsoncpp sources.
diff --git a/Utilities/cmjsoncpp/CMakeLists.txt b/Utilities/cmjsoncpp/CMakeLists.txt
index 8938f4f..1a10295 100644
--- a/Utilities/cmjsoncpp/CMakeLists.txt
+++ b/Utilities/cmjsoncpp/CMakeLists.txt
@@ -1,5 +1,13 @@
project(JsonCpp CXX)
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_CXX_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
set(JSONCPP_SOURCES
src/lib_json/json_batchallocator.h
src/lib_json/json_reader.cpp
diff --git a/Utilities/cmjsoncpp/include/json/config.h b/Utilities/cmjsoncpp/include/json/config.h
index afd3a45..5c711e3 100644
--- a/Utilities/cmjsoncpp/include/json/config.h
+++ b/Utilities/cmjsoncpp/include/json/config.h
@@ -6,6 +6,10 @@
#ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED
+#if defined(_MSC_VER)
+# pragma warning(push,1)
+#endif
+
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=be2c3ac78174ed0a9d5b23e51719cc3ff220ed3a
commit be2c3ac78174ed0a9d5b23e51719cc3ff220ed3a
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 10:45:04 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:42:09 2015 -0500
jsoncpp: Build the library within CMake
Update json/json.h to account for our lack of autolink.h. Add a
cm_jsoncpp_reader.h header to include the CMake-provided copy of the
json/reader.h header.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1812b27..1847600 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -372,6 +372,11 @@ macro (CMAKE_BUILD_UTILITIES)
endif()
#---------------------------------------------------------------------
+ # Build jsoncpp library.
+ add_subdirectory(Utilities/cmjsoncpp)
+ CMAKE_SET_TARGET_FOLDER(cmjsoncpp "Utilities/3rdParty")
+
+ #---------------------------------------------------------------------
# Build XMLRPC library for CMake and CTest.
if(CTEST_USE_XMLRPC)
find_package(XMLRPC QUIET REQUIRED libwww-client)
diff --git a/Utilities/cm_jsoncpp_reader.h b/Utilities/cm_jsoncpp_reader.h
new file mode 100644
index 0000000..d7cb50e
--- /dev/null
+++ b/Utilities/cm_jsoncpp_reader.h
@@ -0,0 +1,18 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cm_jsoncpp_reader_h
+#define cm_jsoncpp_reader_h
+
+/* Use the jsoncpp library configured for CMake. */
+#include <cmjsoncpp/include/json/reader.h>
+
+#endif
diff --git a/Utilities/cmjsoncpp/CMakeLists.txt b/Utilities/cmjsoncpp/CMakeLists.txt
new file mode 100644
index 0000000..8938f4f
--- /dev/null
+++ b/Utilities/cmjsoncpp/CMakeLists.txt
@@ -0,0 +1,14 @@
+project(JsonCpp CXX)
+
+set(JSONCPP_SOURCES
+ src/lib_json/json_batchallocator.h
+ src/lib_json/json_reader.cpp
+ src/lib_json/json_tool.h
+ src/lib_json/json_value.cpp
+ src/lib_json/json_valueiterator.inl
+ src/lib_json/json_writer.cpp
+ )
+
+include_directories(${JsonCpp_SOURCE_DIR}/include)
+
+add_library(cmjsoncpp ${JSONCPP_SOURCES})
diff --git a/Utilities/cmjsoncpp/include/json/json.h b/Utilities/cmjsoncpp/include/json/json.h
index 8f10ac2..f89bc62 100644
--- a/Utilities/cmjsoncpp/include/json/json.h
+++ b/Utilities/cmjsoncpp/include/json/json.h
@@ -6,7 +6,6 @@
#ifndef JSON_JSON_H_INCLUDED
#define JSON_JSON_H_INCLUDED
-#include "autolink.h"
#include "value.h"
#include "reader.h"
#include "writer.h"
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a263d519fffab082fc31f8e3f454726e3fbd8363
commit a263d519fffab082fc31f8e3f454726e3fbd8363
Merge: 32fd56b 53f6ccb
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 10:36:49 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:42:00 2015 -0500
Merge branch 'jsoncpp-upstream' into import-jsoncpp
Use a subtree merge to place the upstream content in the
Utilities/cmjsoncpp directory.
diff --cc Utilities/cmjsoncpp/LICENSE
index 0000000,ca2bfe1..ca2bfe1
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/LICENSE
+++ b/Utilities/cmjsoncpp/LICENSE
diff --cc Utilities/cmjsoncpp/include/json/assertions.h
index 0000000,5ef7e7b..5ef7e7b
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/assertions.h
+++ b/Utilities/cmjsoncpp/include/json/assertions.h
diff --cc Utilities/cmjsoncpp/include/json/config.h
index 0000000,afd3a45..afd3a45
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/config.h
+++ b/Utilities/cmjsoncpp/include/json/config.h
diff --cc Utilities/cmjsoncpp/include/json/features.h
index 0000000,1bb7bb6..1bb7bb6
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/features.h
+++ b/Utilities/cmjsoncpp/include/json/features.h
diff --cc Utilities/cmjsoncpp/include/json/forwards.h
index 0000000,84a26cd..84a26cd
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/forwards.h
+++ b/Utilities/cmjsoncpp/include/json/forwards.h
diff --cc Utilities/cmjsoncpp/include/json/json.h
index 0000000,8f10ac2..8f10ac2
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/json.h
+++ b/Utilities/cmjsoncpp/include/json/json.h
diff --cc Utilities/cmjsoncpp/include/json/reader.h
index 0000000,98814d5..98814d5
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/reader.h
+++ b/Utilities/cmjsoncpp/include/json/reader.h
diff --cc Utilities/cmjsoncpp/include/json/value.h
index 0000000,197a856..197a856
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/value.h
+++ b/Utilities/cmjsoncpp/include/json/value.h
diff --cc Utilities/cmjsoncpp/include/json/version.h
index 0000000,6fe0682..6fe0682
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/version.h
+++ b/Utilities/cmjsoncpp/include/json/version.h
diff --cc Utilities/cmjsoncpp/include/json/writer.h
index 0000000,dc9e46f..dc9e46f
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/include/json/writer.h
+++ b/Utilities/cmjsoncpp/include/json/writer.h
diff --cc Utilities/cmjsoncpp/src/lib_json/json_batchallocator.h
index 0000000,2fbef7a..2fbef7a
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_batchallocator.h
+++ b/Utilities/cmjsoncpp/src/lib_json/json_batchallocator.h
diff --cc Utilities/cmjsoncpp/src/lib_json/json_internalarray.inl
index 0000000,9ee15e9..9ee15e9
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_internalarray.inl
+++ b/Utilities/cmjsoncpp/src/lib_json/json_internalarray.inl
diff --cc Utilities/cmjsoncpp/src/lib_json/json_internalmap.inl
index 0000000,ef3f330..ef3f330
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_internalmap.inl
+++ b/Utilities/cmjsoncpp/src/lib_json/json_internalmap.inl
diff --cc Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
index 0000000,c5111f8..c5111f8
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
+++ b/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
diff --cc Utilities/cmjsoncpp/src/lib_json/json_tool.h
index 0000000,f9b61c3..f9b61c3
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_tool.h
+++ b/Utilities/cmjsoncpp/src/lib_json/json_tool.h
diff --cc Utilities/cmjsoncpp/src/lib_json/json_value.cpp
index 0000000,b73deac..b73deac
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_value.cpp
+++ b/Utilities/cmjsoncpp/src/lib_json/json_value.cpp
diff --cc Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl
index 0000000,a9f7df6..a9f7df6
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl
+++ b/Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl
diff --cc Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
index 0000000,89964ea..89964ea
mode 000000,100644..100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
+++ b/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=53f6ccb0ee76a2b9ac40abd5ec5e07aa55fbb393
commit 53f6ccb0ee76a2b9ac40abd5ec5e07aa55fbb393
Author: JsonCpp Upstream <kwrobot at kitware.com>
AuthorDate: Thu Nov 20 08:45:58 2014 -0600
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 14:41:08 2015 -0500
JsonCpp 1.0.0 (reduced)
Extract upstream JsonCpp using the following shell code.
url=https://github.com/open-source-parsers/jsoncpp &&
v=1.0.0 &&
r=7165f6ac &&
paths="
LICENSE
include/json
src/lib_json
" &&
remove="
include/json/autolink.h
src/lib_json/CMakeLists.txt
src/lib_json/sconscript
src/lib_json/version.h.in
" &&
mkdir jsoncpp-$v-g$r-reduced &&
git clone $url jsoncpp-git &&
date=$(cd jsoncpp-git && git log -n 1 --format='%cd' $r) &&
(cd jsoncpp-git && git checkout $r &&
git archive --format=tar $r -- $paths) |
(cd jsoncpp-$v-g$r-reduced && tar xv && rm -f $remove) &&
echo "g$r date: $date"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ca2bfe1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,55 @@
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
diff --git a/include/json/assertions.h b/include/json/assertions.h
new file mode 100644
index 0000000..5ef7e7b
--- /dev/null
+++ b/include/json/assertions.h
@@ -0,0 +1,41 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+#include <stdlib.h>
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+#if JSON_USE_EXCEPTION
+#include <stdexcept>
+#define JSON_ASSERT(condition) \
+ assert(condition); // @todo <= change this into an exception throw
+#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
+#else // JSON_USE_EXCEPTION
+#define JSON_ASSERT(condition) assert(condition);
+
+// The call to assert() will show the failure message in debug builds. In
+// release bugs we write to invalid memory in order to crash hard, so that a
+// debugger or crash reporter gets the chance to take over. We still call exit()
+// afterward in order to tell the compiler that this macro doesn't return.
+#define JSON_FAIL_MESSAGE(message) \
+ { \
+ assert(false&& message); \
+ strcpy(reinterpret_cast<char*>(666), message); \
+ exit(123); \
+ }
+
+#endif
+
+#define JSON_ASSERT_MESSAGE(condition, message) \
+ if (!(condition)) { \
+ JSON_FAIL_MESSAGE(message) \
+ }
+
+#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
diff --git a/include/json/config.h b/include/json/config.h
new file mode 100644
index 0000000..afd3a45
--- /dev/null
+++ b/include/json/config.h
@@ -0,0 +1,112 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+/// If defined, indicates that Json specific container should be used
+/// (hash table & simple deque container with customizable allocator).
+/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
+//# define JSON_VALUE_USE_INTERNAL_MAP 1
+/// Force usage of standard new/malloc based allocator instead of memory pool
+/// based allocator.
+/// The memory pools allocator used optimization (initializing Value and
+/// ValueInternalLink
+/// as if it was a POD) that may cause some validation tool to report errors.
+/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
+//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include <cpptl/config.h>
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
+// Microsoft Visual Studio 6 only support conversion from __int64 to double
+// (no conversion from unsigned __int64).
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+// characters in the debug information)
+// All projects I've ever seen with VS6 were using this globally (not bothering
+// with pragma push/pop).
+#pragma warning(disable : 4786)
+#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
+
+#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
+/// Indicates that the following function is deprecated.
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
diff --git a/include/json/features.h b/include/json/features.h
new file mode 100644
index 0000000..1bb7bb6
--- /dev/null
+++ b/include/json/features.h
@@ -0,0 +1,57 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+#define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features {
+public:
+ /** \brief A configuration that allows all features and assumes all strings
+ * are UTF-8.
+ * - C & C++ comments are allowed
+ * - Root object can be any JSON value
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features all();
+
+ /** \brief A configuration that is strictly compatible with the JSON
+ * specification.
+ * - Comments are forbidden.
+ * - Root object must be either an array or an object value.
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features strictMode();
+
+ /** \brief Initialize the configuration like JsonConfig::allFeatures;
+ */
+ Features();
+
+ /// \c true if comments are allowed. Default: \c true.
+ bool allowComments_;
+
+ /// \c true if root must be either an array or an object value. Default: \c
+ /// false.
+ bool strictRoot_;
+
+ /// \c true if dropped null placeholders are allowed. Default: \c false.
+ bool allowDroppedNullPlaceholders_;
+
+ /// \c true if numeric object key are allowed. Default: \c false.
+ bool allowNumericKeys_;
+};
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
diff --git a/include/json/forwards.h b/include/json/forwards.h
new file mode 100644
index 0000000..84a26cd
--- /dev/null
+++ b/include/json/forwards.h
@@ -0,0 +1,43 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+class ValueMapAllocator;
+class ValueInternalLink;
+class ValueInternalArray;
+class ValueInternalMap;
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
diff --git a/include/json/json.h b/include/json/json.h
new file mode 100644
index 0000000..8f10ac2
--- /dev/null
+++ b/include/json/json.h
@@ -0,0 +1,15 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_JSON_H_INCLUDED
+#define JSON_JSON_H_INCLUDED
+
+#include "autolink.h"
+#include "value.h"
+#include "reader.h"
+#include "writer.h"
+#include "features.h"
+
+#endif // JSON_JSON_H_INCLUDED
diff --git a/include/json/reader.h b/include/json/reader.h
new file mode 100644
index 0000000..98814d5
--- /dev/null
+++ b/include/json/reader.h
@@ -0,0 +1,276 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+#define CPPTL_JSON_READER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "features.h"
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <deque>
+#include <iosfwd>
+#include <stack>
+#include <string>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
+ *Value.
+ *
+ */
+class JSON_API Reader {
+public:
+ typedef char Char;
+ typedef const Char* Location;
+
+ /** \brief An error tagged with where in the JSON text it was encountered.
+ *
+ * The offsets give the [start, limit) range of bytes within the text. Note
+ * that this is bytes, not codepoints.
+ *
+ */
+ struct StructuredError {
+ size_t offset_start;
+ size_t offset_limit;
+ std::string message;
+ };
+
+ /** \brief Constructs a Reader allowing all features
+ * for parsing.
+ */
+ Reader();
+
+ /** \brief Constructs a Reader allowing the specified feature set
+ * for parsing.
+ */
+ Reader(const Features& features);
+
+ /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+ * document.
+ * \param document UTF-8 encoded string containing the document to read.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them
+ * back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if
+ * Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an
+ * error occurred.
+ */
+ bool
+ parse(const std::string& document, Value& root, bool collectComments = true);
+
+ /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+ document.
+ * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+ document to read.
+ * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+ document to read.
+ \ Must be >= beginDoc.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them
+ back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if
+ Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an
+ error occurred.
+ */
+ bool parse(const char* beginDoc,
+ const char* endDoc,
+ Value& root,
+ bool collectComments = true);
+
+ /// \brief Parse from input stream.
+ /// \see Json::operator>>(std::istream&, Json::Value&).
+ bool parse(std::istream& is, Value& root, bool collectComments = true);
+
+ /** \brief Returns a user friendly string that list errors in the parsed
+ * document.
+ * \return Formatted error message with the list of errors with their location
+ * in
+ * the parsed document. An empty string is returned if no error
+ * occurred
+ * during parsing.
+ * \deprecated Use getFormattedErrorMessages() instead (typo fix).
+ */
+ JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
+ std::string getFormatedErrorMessages() const;
+
+ /** \brief Returns a user friendly string that list errors in the parsed
+ * document.
+ * \return Formatted error message with the list of errors with their location
+ * in
+ * the parsed document. An empty string is returned if no error
+ * occurred
+ * during parsing.
+ */
+ std::string getFormattedErrorMessages() const;
+
+ /** \brief Returns a vector of structured erros encounted while parsing.
+ * \return A (possibly empty) vector of StructuredError objects. Currently
+ * only one error can be returned, but the caller should tolerate
+ * multiple
+ * errors. This can occur if the parser recovers from a non-fatal
+ * parse error and then encounters additional errors.
+ */
+ std::vector<StructuredError> getStructuredErrors() const;
+
+ /** \brief Add a semantic error message.
+ * \param value JSON Value location associated with the error
+ * \param message The error message.
+ * \return \c true if the error was successfully added, \c false if the
+ * Value offset exceeds the document size.
+ */
+ bool pushError(const Value& value, const std::string& message);
+
+ /** \brief Add a semantic error message with extra context.
+ * \param value JSON Value location associated with the error
+ * \param message The error message.
+ * \param extra Additional JSON Value location to contextualize the error
+ * \return \c true if the error was successfully added, \c false if either
+ * Value offset exceeds the document size.
+ */
+ bool pushError(const Value& value, const std::string& message, const Value& extra);
+
+ /** \brief Return whether there are any errors.
+ * \return \c true if there are no errors to report \c false if
+ * errors have occurred.
+ */
+ bool good() const;
+
+private:
+ enum TokenType {
+ tokenEndOfStream = 0,
+ tokenObjectBegin,
+ tokenObjectEnd,
+ tokenArrayBegin,
+ tokenArrayEnd,
+ tokenString,
+ tokenNumber,
+ tokenTrue,
+ tokenFalse,
+ tokenNull,
+ tokenArraySeparator,
+ tokenMemberSeparator,
+ tokenComment,
+ tokenError
+ };
+
+ class Token {
+ public:
+ TokenType type_;
+ Location start_;
+ Location end_;
+ };
+
+ class ErrorInfo {
+ public:
+ Token token_;
+ std::string message_;
+ Location extra_;
+ };
+
+ typedef std::deque<ErrorInfo> Errors;
+
+ bool expectToken(TokenType type, Token& token, const char* message);
+ bool readToken(Token& token);
+ void skipSpaces();
+ bool match(Location pattern, int patternLength);
+ bool readComment();
+ bool readCStyleComment();
+ bool readCppStyleComment();
+ bool readString();
+ void readNumber();
+ bool readValue();
+ bool readObject(Token& token);
+ bool readArray(Token& token);
+ bool decodeNumber(Token& token);
+ bool decodeNumber(Token& token, Value& decoded);
+ bool decodeString(Token& token);
+ bool decodeString(Token& token, std::string& decoded);
+ bool decodeDouble(Token& token);
+ bool decodeDouble(Token& token, Value& decoded);
+ bool decodeUnicodeCodePoint(Token& token,
+ Location& current,
+ Location end,
+ unsigned int& unicode);
+ bool decodeUnicodeEscapeSequence(Token& token,
+ Location& current,
+ Location end,
+ unsigned int& unicode);
+ bool addError(const std::string& message, Token& token, Location extra = 0);
+ bool recoverFromError(TokenType skipUntilToken);
+ bool addErrorAndRecover(const std::string& message,
+ Token& token,
+ TokenType skipUntilToken);
+ void skipUntilSpace();
+ Value& currentValue();
+ Char getNextChar();
+ void
+ getLocationLineAndColumn(Location location, int& line, int& column) const;
+ std::string getLocationLineAndColumn(Location location) const;
+ void addComment(Location begin, Location end, CommentPlacement placement);
+ void skipCommentTokens(Token& token);
+
+ typedef std::stack<Value*> Nodes;
+ Nodes nodes_;
+ Errors errors_;
+ std::string document_;
+ Location begin_;
+ Location end_;
+ Location current_;
+ Location lastValueEnd_;
+ Value* lastValue_;
+ std::string commentsBefore_;
+ Features features_;
+ bool collectComments_;
+};
+
+/** \brief Read from 'sin' into 'root'.
+
+ Always keep comments from the input JSON.
+
+ This can be used to read a file into a particular sub-object.
+ For example:
+ \code
+ Json::Value root;
+ cin >> root["dir"]["file"];
+ cout << root;
+ \endcode
+ Result:
+ \verbatim
+ {
+ "dir": {
+ "file": {
+ // The input stream JSON would be nested here.
+ }
+ }
+ }
+ \endverbatim
+ \throw std::exception on parse error.
+ \see Json::operator<<()
+*/
+JSON_API std::istream& operator>>(std::istream&, Value&);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
diff --git a/include/json/value.h b/include/json/value.h
new file mode 100644
index 0000000..197a856
--- /dev/null
+++ b/include/json/value.h
@@ -0,0 +1,1088 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+#define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <string>
+#include <vector>
+
+#ifndef JSON_USE_CPPTL_SMALLMAP
+#include <map>
+#else
+#include <cpptl/smallmap.h>
+#endif
+#ifdef JSON_USE_CPPTL
+#include <cpptl/forwards.h>
+#endif
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+/** \brief Type of the value held by a Value object.
+ */
+enum ValueType {
+ nullValue = 0, ///< 'null' value
+ intValue, ///< signed integer value
+ uintValue, ///< unsigned integer value
+ realValue, ///< double value
+ stringValue, ///< UTF-8 string value
+ booleanValue, ///< bool value
+ arrayValue, ///< array value (ordered list)
+ objectValue ///< object value (collection of name/value pairs).
+};
+
+enum CommentPlacement {
+ commentBefore = 0, ///< a comment placed on the line before a value
+ commentAfterOnSameLine, ///< a comment just after a value on the same line
+ commentAfter, ///< a comment on the line after a value (only make sense for
+ /// root value)
+ numberOfCommentPlacement
+};
+
+//# ifdef JSON_USE_CPPTL
+// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+/** \brief Lightweight wrapper to tag static string.
+ *
+ * Value constructor and objectValue member assignement takes advantage of the
+ * StaticString and avoid the cost of string duplication when storing the
+ * string or the member name.
+ *
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+class JSON_API StaticString {
+public:
+ explicit StaticString(const char* czstring) : str_(czstring) {}
+
+ operator const char*() const { return str_; }
+
+ const char* c_str() const { return str_; }
+
+private:
+ const char* str_;
+};
+
+/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+ *
+ * This class is a discriminated union wrapper that can represents a:
+ * - signed integer [range: Value::minInt - Value::maxInt]
+ * - unsigned integer (range: 0 - Value::maxUInt)
+ * - double
+ * - UTF-8 string
+ * - boolean
+ * - 'null'
+ * - an ordered list of Value
+ * - collection of name/value pairs (javascript object)
+ *
+ * The type of the held value is represented by a #ValueType and
+ * can be obtained using type().
+ *
+ * values of an #objectValue or #arrayValue can be accessed using operator[]()
+ *methods.
+ * Non const methods will automatically create the a #nullValue element
+ * if it does not exist.
+ * The sequence of an #arrayValue will be automatically resize and initialized
+ * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+ *
+ * The get() methods can be used to obtanis default value in the case the
+ *required element
+ * does not exist.
+ *
+ * It is possible to iterate over the list of a #objectValue values using
+ * the getMemberNames() method.
+ */
+class JSON_API Value {
+ friend class ValueIteratorBase;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ friend class ValueInternalLink;
+ friend class ValueInternalMap;
+#endif
+public:
+ typedef std::vector<std::string> Members;
+ typedef ValueIterator iterator;
+ typedef ValueConstIterator const_iterator;
+ typedef Json::UInt UInt;
+ typedef Json::Int Int;
+#if defined(JSON_HAS_INT64)
+ typedef Json::UInt64 UInt64;
+ typedef Json::Int64 Int64;
+#endif // defined(JSON_HAS_INT64)
+ typedef Json::LargestInt LargestInt;
+ typedef Json::LargestUInt LargestUInt;
+ typedef Json::ArrayIndex ArrayIndex;
+
+ static const Value& null;
+ /// Minimum signed integer value that can be stored in a Json::Value.
+ static const LargestInt minLargestInt;
+ /// Maximum signed integer value that can be stored in a Json::Value.
+ static const LargestInt maxLargestInt;
+ /// Maximum unsigned integer value that can be stored in a Json::Value.
+ static const LargestUInt maxLargestUInt;
+
+ /// Minimum signed int value that can be stored in a Json::Value.
+ static const Int minInt;
+ /// Maximum signed int value that can be stored in a Json::Value.
+ static const Int maxInt;
+ /// Maximum unsigned int value that can be stored in a Json::Value.
+ static const UInt maxUInt;
+
+#if defined(JSON_HAS_INT64)
+ /// Minimum signed 64 bits int value that can be stored in a Json::Value.
+ static const Int64 minInt64;
+ /// Maximum signed 64 bits int value that can be stored in a Json::Value.
+ static const Int64 maxInt64;
+ /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
+ static const UInt64 maxUInt64;
+#endif // defined(JSON_HAS_INT64)
+
+private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ class CZString {
+ public:
+ enum DuplicationPolicy {
+ noDuplication = 0,
+ duplicate,
+ duplicateOnCopy
+ };
+ CZString(ArrayIndex index);
+ CZString(const char* cstr, DuplicationPolicy allocate);
+ CZString(const CZString& other);
+ ~CZString();
+ CZString& operator=(CZString other);
+ bool operator<(const CZString& other) const;
+ bool operator==(const CZString& other) const;
+ ArrayIndex index() const;
+ const char* c_str() const;
+ bool isStaticString() const;
+
+ private:
+ void swap(CZString& other);
+ const char* cstr_;
+ ArrayIndex index_;
+ };
+
+public:
+#ifndef JSON_USE_CPPTL_SMALLMAP
+ typedef std::map<CZString, Value> ObjectValues;
+#else
+ typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#endif // ifndef JSON_USE_CPPTL_SMALLMAP
+#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+public:
+ /** \brief Create a default Value of the given type.
+
+ This is a very useful constructor.
+ To create an empty array, pass arrayValue.
+ To create an empty object, pass objectValue.
+ Another Value can then be set to this one by assignment.
+This is useful since clear() and resize() will not alter types.
+
+ Examples:
+\code
+Json::Value null_value; // null
+Json::Value arr_value(Json::arrayValue); // []
+Json::Value obj_value(Json::objectValue); // {}
+\endcode
+ */
+ Value(ValueType type = nullValue);
+ Value(Int value);
+ Value(UInt value);
+#if defined(JSON_HAS_INT64)
+ Value(Int64 value);
+ Value(UInt64 value);
+#endif // if defined(JSON_HAS_INT64)
+ Value(double value);
+ Value(const char* value);
+ Value(const char* beginValue, const char* endValue);
+ /** \brief Constructs a value from a static string.
+
+ * Like other value string constructor but do not duplicate the string for
+ * internal storage. The given string must remain alive after the call to this
+ * constructor.
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * \endcode
+ */
+ Value(const StaticString& value);
+ Value(const std::string& value);
+#ifdef JSON_USE_CPPTL
+ Value(const CppTL::ConstString& value);
+#endif
+ Value(bool value);
+ Value(const Value& other);
+ ~Value();
+
+ Value& operator=(Value other);
+ /// Swap values.
+ /// \note Currently, comments are intentionally not swapped, for
+ /// both logic and efficiency.
+ void swap(Value& other);
+
+ ValueType type() const;
+
+ bool operator<(const Value& other) const;
+ bool operator<=(const Value& other) const;
+ bool operator>=(const Value& other) const;
+ bool operator>(const Value& other) const;
+
+ bool operator==(const Value& other) const;
+ bool operator!=(const Value& other) const;
+
+ int compare(const Value& other) const;
+
+ const char* asCString() const;
+ std::string asString() const;
+#ifdef JSON_USE_CPPTL
+ CppTL::ConstString asConstString() const;
+#endif
+ Int asInt() const;
+ UInt asUInt() const;
+#if defined(JSON_HAS_INT64)
+ Int64 asInt64() const;
+ UInt64 asUInt64() const;
+#endif // if defined(JSON_HAS_INT64)
+ LargestInt asLargestInt() const;
+ LargestUInt asLargestUInt() const;
+ float asFloat() const;
+ double asDouble() const;
+ bool asBool() const;
+
+ bool isNull() const;
+ bool isBool() const;
+ bool isInt() const;
+ bool isInt64() const;
+ bool isUInt() const;
+ bool isUInt64() const;
+ bool isIntegral() const;
+ bool isDouble() const;
+ bool isNumeric() const;
+ bool isString() const;
+ bool isArray() const;
+ bool isObject() const;
+
+ bool isConvertibleTo(ValueType other) const;
+
+ /// Number of values in array or object
+ ArrayIndex size() const;
+
+ /// \brief Return true if empty array, empty object, or null;
+ /// otherwise, false.
+ bool empty() const;
+
+ /// Return isNull()
+ bool operator!() const;
+
+ /// Remove all object members and array elements.
+ /// \pre type() is arrayValue, objectValue, or nullValue
+ /// \post type() is unchanged
+ void clear();
+
+ /// Resize the array to size elements.
+ /// New elements are initialized to null.
+ /// May only be called on nullValue or arrayValue.
+ /// \pre type() is arrayValue or nullValue
+ /// \post type() is arrayValue
+ void resize(ArrayIndex size);
+
+ /// Access an array element (zero based index ).
+ /// If the array contains less than index element, then null value are
+ /// inserted
+ /// in the array so that its size is index+1.
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ Value& operator[](ArrayIndex index);
+
+ /// Access an array element (zero based index ).
+ /// If the array contains less than index element, then null value are
+ /// inserted
+ /// in the array so that its size is index+1.
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ Value& operator[](int index);
+
+ /// Access an array element (zero based index )
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ const Value& operator[](ArrayIndex index) const;
+
+ /// Access an array element (zero based index )
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ const Value& operator[](int index) const;
+
+ /// If the array contains at least index+1 elements, returns the element
+ /// value,
+ /// otherwise returns defaultValue.
+ Value get(ArrayIndex index, const Value& defaultValue) const;
+ /// Return true if index < size().
+ bool isValidIndex(ArrayIndex index) const;
+ /// \brief Append value to array at the end.
+ ///
+ /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+ Value& append(const Value& value);
+
+ /// Access an object value by name, create a null member if it does not exist.
+ Value& operator[](const char* key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value& operator[](const char* key) const;
+ /// Access an object value by name, create a null member if it does not exist.
+ Value& operator[](const std::string& key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value& operator[](const std::string& key) const;
+ /** \brief Access an object value by name, create a null member if it does not
+ exist.
+
+ * If the object as no entry for that name, then the member name used to store
+ * the new entry is not duplicated.
+ * Example of use:
+ * \code
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+ Value& operator[](const StaticString& key);
+#ifdef JSON_USE_CPPTL
+ /// Access an object value by name, create a null member if it does not exist.
+ Value& operator[](const CppTL::ConstString& key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value& operator[](const CppTL::ConstString& key) const;
+#endif
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get(const char* key, const Value& defaultValue) const;
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get(const std::string& key, const Value& defaultValue) const;
+#ifdef JSON_USE_CPPTL
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
+#endif
+ /// \brief Remove and return the named member.
+ ///
+ /// Do nothing if it did not exist.
+ /// \return the removed Value, or null.
+ /// \pre type() is objectValue or nullValue
+ /// \post type() is unchanged
+ Value removeMember(const char* key);
+ /// Same as removeMember(const char*)
+ Value removeMember(const std::string& key);
+
+ /// Return true if the object has a member named key.
+ bool isMember(const char* key) const;
+ /// Return true if the object has a member named key.
+ bool isMember(const std::string& key) const;
+#ifdef JSON_USE_CPPTL
+ /// Return true if the object has a member named key.
+ bool isMember(const CppTL::ConstString& key) const;
+#endif
+
+ /// \brief Return a list of the member names.
+ ///
+ /// If null, return an empty list.
+ /// \pre type() is objectValue or nullValue
+ /// \post if type() was nullValue, it remains nullValue
+ Members getMemberNames() const;
+
+ //# ifdef JSON_USE_CPPTL
+ // EnumMemberNames enumMemberNames() const;
+ // EnumValues enumValues() const;
+ //# endif
+
+ /// Comments must be //... or /* ... */
+ void setComment(const char* comment, CommentPlacement placement);
+ /// Comments must be //... or /* ... */
+ void setComment(const std::string& comment, CommentPlacement placement);
+ bool hasComment(CommentPlacement placement) const;
+ /// Include delimiters and embedded newlines.
+ std::string getComment(CommentPlacement placement) const;
+
+ std::string toStyledString() const;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator begin();
+ iterator end();
+
+ // Accessors for the [start, limit) range of bytes within the JSON text from
+ // which this value was parsed, if any.
+ void setOffsetStart(size_t start);
+ void setOffsetLimit(size_t limit);
+ size_t getOffsetStart() const;
+ size_t getOffsetLimit() const;
+
+private:
+ void initBasic(ValueType type, bool allocated = false);
+
+ Value& resolveReference(const char* key, bool isStatic);
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ inline bool isItemAvailable() const { return itemIsUsed_ == 0; }
+
+ inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; }
+
+ inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; }
+
+ inline void setMemberNameIsStatic(bool isStatic) {
+ memberNameIsStatic_ = isStatic ? 1 : 0;
+ }
+#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+private:
+ struct CommentInfo {
+ CommentInfo();
+ ~CommentInfo();
+
+ void setComment(const char* text);
+
+ char* comment_;
+ };
+
+ // struct MemberNamesTransform
+ //{
+ // typedef const char *result_type;
+ // const char *operator()( const CZString &name ) const
+ // {
+ // return name.c_str();
+ // }
+ //};
+
+ union ValueHolder {
+ LargestInt int_;
+ LargestUInt uint_;
+ double real_;
+ bool bool_;
+ char* string_;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ ValueInternalArray* array_;
+ ValueInternalMap* map_;
+#else
+ ObjectValues* map_;
+#endif
+ } value_;
+ ValueType type_ : 8;
+ int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
+ int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
+#endif
+ CommentInfo* comments_;
+
+ // [start, limit) byte offsets in the source JSON text from which this Value
+ // was extracted.
+ size_t start_;
+ size_t limit_;
+};
+
+/** \brief Experimental and untested: represents an element of the "path" to
+ * access a node.
+ */
+class JSON_API PathArgument {
+public:
+ friend class Path;
+
+ PathArgument();
+ PathArgument(ArrayIndex index);
+ PathArgument(const char* key);
+ PathArgument(const std::string& key);
+
+private:
+ enum Kind {
+ kindNone = 0,
+ kindIndex,
+ kindKey
+ };
+ std::string key_;
+ ArrayIndex index_;
+ Kind kind_;
+};
+
+/** \brief Experimental and untested: represents a "path" to access a node.
+ *
+ * Syntax:
+ * - "." => root node
+ * - ".[n]" => elements at index 'n' of root node (an array value)
+ * - ".name" => member named 'name' of root node (an object value)
+ * - ".name1.name2.name3"
+ * - ".[0][1][2].name1[3]"
+ * - ".%" => member name is provided as parameter
+ * - ".[%]" => index is provied as parameter
+ */
+class JSON_API Path {
+public:
+ Path(const std::string& path,
+ const PathArgument& a1 = PathArgument(),
+ const PathArgument& a2 = PathArgument(),
+ const PathArgument& a3 = PathArgument(),
+ const PathArgument& a4 = PathArgument(),
+ const PathArgument& a5 = PathArgument());
+
+ const Value& resolve(const Value& root) const;
+ Value resolve(const Value& root, const Value& defaultValue) const;
+ /// Creates the "path" to access the specified node and returns a reference on
+ /// the node.
+ Value& make(Value& root) const;
+
+private:
+ typedef std::vector<const PathArgument*> InArgs;
+ typedef std::vector<PathArgument> Args;
+
+ void makePath(const std::string& path, const InArgs& in);
+ void addPathInArg(const std::string& path,
+ const InArgs& in,
+ InArgs::const_iterator& itInArg,
+ PathArgument::Kind kind);
+ void invalidPath(const std::string& path, int location);
+
+ Args args_;
+};
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+/** \brief Allocator to customize Value internal map.
+ * Below is an example of a simple implementation (default implementation
+ actually
+ * use memory pool for speed).
+ * \code
+ class DefaultValueMapAllocator : public ValueMapAllocator
+ {
+ public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap *newMap()
+ {
+ return new ValueInternalMap();
+ }
+
+ virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+ {
+ return new ValueInternalMap( other );
+ }
+
+ virtual void destructMap( ValueInternalMap *map )
+ {
+ delete map;
+ }
+
+ virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+ {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets( ValueInternalLink *links )
+ {
+ delete [] links;
+ }
+
+ virtual ValueInternalLink *allocateMapLink()
+ {
+ return new ValueInternalLink();
+ }
+
+ virtual void releaseMapLink( ValueInternalLink *link )
+ {
+ delete link;
+ }
+ };
+ * \endcode
+ */
+class JSON_API ValueMapAllocator {
+public:
+ virtual ~ValueMapAllocator();
+ virtual ValueInternalMap* newMap() = 0;
+ virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) = 0;
+ virtual void destructMap(ValueInternalMap* map) = 0;
+ virtual ValueInternalLink* allocateMapBuckets(unsigned int size) = 0;
+ virtual void releaseMapBuckets(ValueInternalLink* links) = 0;
+ virtual ValueInternalLink* allocateMapLink() = 0;
+ virtual void releaseMapLink(ValueInternalLink* link) = 0;
+};
+
+/** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
+ * \internal previous_ & next_ allows for bidirectional traversal.
+ */
+class JSON_API ValueInternalLink {
+public:
+ enum {
+ itemPerLink = 6
+ }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
+ enum InternalFlags {
+ flagAvailable = 0,
+ flagUsed = 1
+ };
+
+ ValueInternalLink();
+
+ ~ValueInternalLink();
+
+ Value items_[itemPerLink];
+ char* keys_[itemPerLink];
+ ValueInternalLink* previous_;
+ ValueInternalLink* next_;
+};
+
+/** \brief A linked page based hash-table implementation used internally by
+ *Value.
+ * \internal ValueInternalMap is a tradional bucket based hash-table, with a
+ *linked
+ * list in each bucket to handle collision. There is an addional twist in that
+ * each node of the collision linked list is a page containing a fixed amount of
+ * value. This provides a better compromise between memory usage and speed.
+ *
+ * Each bucket is made up of a chained list of ValueInternalLink. The last
+ * link of a given bucket can be found in the 'previous_' field of the following
+ *bucket.
+ * The last link of the last bucket is stored in tailLink_ as it has no
+ *following bucket.
+ * Only the last link of a bucket may contains 'available' item. The last link
+ *always
+ * contains at least one element unless is it the bucket one very first link.
+ */
+class JSON_API ValueInternalMap {
+ friend class ValueIteratorBase;
+ friend class Value;
+
+public:
+ typedef unsigned int HashKey;
+ typedef unsigned int BucketIndex;
+
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+ struct IteratorState {
+ IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {}
+ ValueInternalMap* map_;
+ ValueInternalLink* link_;
+ BucketIndex itemIndex_;
+ BucketIndex bucketIndex_;
+ };
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+ ValueInternalMap();
+ ValueInternalMap(const ValueInternalMap& other);
+ ValueInternalMap& operator=(ValueInternalMap other);
+ ~ValueInternalMap();
+
+ void swap(ValueInternalMap& other);
+
+ BucketIndex size() const;
+
+ void clear();
+
+ bool reserveDelta(BucketIndex growth);
+
+ bool reserve(BucketIndex newItemCount);
+
+ const Value* find(const char* key) const;
+
+ Value* find(const char* key);
+
+ Value& resolveReference(const char* key, bool isStatic);
+
+ void remove(const char* key);
+
+ void doActualRemove(ValueInternalLink* link,
+ BucketIndex index,
+ BucketIndex bucketIndex);
+
+ ValueInternalLink*& getLastLinkInBucket(BucketIndex bucketIndex);
+
+ Value& setNewItem(const char* key,
+ bool isStatic,
+ ValueInternalLink* link,
+ BucketIndex index);
+
+ Value& unsafeAdd(const char* key, bool isStatic, HashKey hashedKey);
+
+ HashKey hash(const char* key) const;
+
+ int compare(const ValueInternalMap& other) const;
+
+private:
+ void makeBeginIterator(IteratorState& it) const;
+ void makeEndIterator(IteratorState& it) const;
+ static bool equals(const IteratorState& x, const IteratorState& other);
+ static void increment(IteratorState& iterator);
+ static void incrementBucket(IteratorState& iterator);
+ static void decrement(IteratorState& iterator);
+ static const char* key(const IteratorState& iterator);
+ static const char* key(const IteratorState& iterator, bool& isStatic);
+ static Value& value(const IteratorState& iterator);
+ static int distance(const IteratorState& x, const IteratorState& y);
+
+private:
+ ValueInternalLink* buckets_;
+ ValueInternalLink* tailLink_;
+ BucketIndex bucketsSize_;
+ BucketIndex itemCount_;
+};
+
+/** \brief A simplified deque implementation used internally by Value.
+* \internal
+* It is based on a list of fixed "page", each page contains a fixed number of
+*items.
+* Instead of using a linked-list, a array of pointer is used for fast item
+*look-up.
+* Look-up for an element is as follow:
+* - compute page index: pageIndex = itemIndex / itemsPerPage
+* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
+*
+* Insertion is amortized constant time (only the array containing the index of
+*pointers
+* need to be reallocated when items are appended).
+*/
+class JSON_API ValueInternalArray {
+ friend class Value;
+ friend class ValueIteratorBase;
+
+public:
+ enum {
+ itemsPerPage = 8
+ }; // should be a power of 2 for fast divide and modulo.
+ typedef Value::ArrayIndex ArrayIndex;
+ typedef unsigned int PageIndex;
+
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+ struct IteratorState // Must be a POD
+ {
+ IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {}
+ ValueInternalArray* array_;
+ Value** currentPageIndex_;
+ unsigned int currentItemIndex_;
+ };
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+ ValueInternalArray();
+ ValueInternalArray(const ValueInternalArray& other);
+ ValueInternalArray& operator=(ValueInternalArray other);
+ ~ValueInternalArray();
+ void swap(ValueInternalArray& other);
+
+ void clear();
+ void resize(ArrayIndex newSize);
+
+ Value& resolveReference(ArrayIndex index);
+
+ Value* find(ArrayIndex index) const;
+
+ ArrayIndex size() const;
+
+ int compare(const ValueInternalArray& other) const;
+
+private:
+ static bool equals(const IteratorState& x, const IteratorState& other);
+ static void increment(IteratorState& iterator);
+ static void decrement(IteratorState& iterator);
+ static Value& dereference(const IteratorState& iterator);
+ static Value& unsafeDereference(const IteratorState& iterator);
+ static int distance(const IteratorState& x, const IteratorState& y);
+ static ArrayIndex indexOf(const IteratorState& iterator);
+ void makeBeginIterator(IteratorState& it) const;
+ void makeEndIterator(IteratorState& it) const;
+ void makeIterator(IteratorState& it, ArrayIndex index) const;
+
+ void makeIndexValid(ArrayIndex index);
+
+ Value** pages_;
+ ArrayIndex size_;
+ PageIndex pageCount_;
+};
+
+/** \brief Experimental: do not use. Allocator to customize Value internal
+array.
+ * Below is an example of a simple implementation (actual implementation use
+ * memory pool).
+ \code
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+virtual ~DefaultValueArrayAllocator()
+{
+}
+
+virtual ValueInternalArray *newArray()
+{
+ return new ValueInternalArray();
+}
+
+virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+{
+ return new ValueInternalArray( other );
+}
+
+virtual void destruct( ValueInternalArray *array )
+{
+ delete array;
+}
+
+virtual void reallocateArrayPageIndex( Value **&indexes,
+ ValueInternalArray::PageIndex
+&indexCount,
+ ValueInternalArray::PageIndex
+minNewIndexCount )
+{
+ ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+ if ( minNewIndexCount > newIndexCount )
+ newIndexCount = minNewIndexCount;
+ void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+ if ( !newIndexes )
+ throw std::bad_alloc();
+ indexCount = newIndexCount;
+ indexes = static_cast<Value **>( newIndexes );
+}
+virtual void releaseArrayPageIndex( Value **indexes,
+ ValueInternalArray::PageIndex indexCount )
+{
+ if ( indexes )
+ free( indexes );
+}
+
+virtual Value *allocateArrayPage()
+{
+ return static_cast<Value *>( malloc( sizeof(Value) *
+ValueInternalArray::itemsPerPage ) );
+}
+
+virtual void releaseArrayPage( Value *value )
+{
+ if ( value )
+ free( value );
+}
+};
+ \endcode
+ */
+class JSON_API ValueArrayAllocator {
+public:
+ virtual ~ValueArrayAllocator();
+ virtual ValueInternalArray* newArray() = 0;
+ virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) = 0;
+ virtual void destructArray(ValueInternalArray* array) = 0;
+ /** \brief Reallocate array page index.
+ * Reallocates an array of pointer on each page.
+ * \param indexes [input] pointer on the current index. May be \c NULL.
+ * [output] pointer on the new index of at least
+ * \a minNewIndexCount pages.
+ * \param indexCount [input] current number of pages in the index.
+ * [output] number of page the reallocated index can handle.
+ * \b MUST be >= \a minNewIndexCount.
+ * \param minNewIndexCount Minimum number of page the new index must be able
+ * to
+ * handle.
+ */
+ virtual void
+ reallocateArrayPageIndex(Value**& indexes,
+ ValueInternalArray::PageIndex& indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount) = 0;
+ virtual void
+ releaseArrayPageIndex(Value** indexes,
+ ValueInternalArray::PageIndex indexCount) = 0;
+ virtual Value* allocateArrayPage() = 0;
+ virtual void releaseArrayPage(Value* value) = 0;
+};
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+/** \brief base class for Value iterators.
+ *
+ */
+class JSON_API ValueIteratorBase {
+public:
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef ValueIteratorBase SelfType;
+
+ ValueIteratorBase();
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
+#else
+ ValueIteratorBase(const ValueInternalArray::IteratorState& state);
+ ValueIteratorBase(const ValueInternalMap::IteratorState& state);
+#endif
+
+ bool operator==(const SelfType& other) const { return isEqual(other); }
+
+ bool operator!=(const SelfType& other) const { return !isEqual(other); }
+
+ difference_type operator-(const SelfType& other) const {
+ return computeDistance(other);
+ }
+
+ /// Return either the index or the member name of the referenced value as a
+ /// Value.
+ Value key() const;
+
+ /// Return the index of the referenced Value. -1 if it is not an arrayValue.
+ UInt index() const;
+
+ /// Return the member name of the referenced Value. "" if it is not an
+ /// objectValue.
+ const char* memberName() const;
+
+protected:
+ Value& deref() const;
+
+ void increment();
+
+ void decrement();
+
+ difference_type computeDistance(const SelfType& other) const;
+
+ bool isEqual(const SelfType& other) const;
+
+ void copy(const SelfType& other);
+
+private:
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ Value::ObjectValues::iterator current_;
+ // Indicates that iterator is for a null value.
+ bool isNull_;
+#else
+ union {
+ ValueInternalArray::IteratorState array_;
+ ValueInternalMap::IteratorState map_;
+ } iterator_;
+ bool isArray_;
+#endif
+};
+
+/** \brief const iterator for object and array value.
+ *
+ */
+class JSON_API ValueConstIterator : public ValueIteratorBase {
+ friend class Value;
+
+public:
+ typedef const Value value_type;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef const Value& reference;
+ typedef const Value* pointer;
+ typedef ValueConstIterator SelfType;
+
+ ValueConstIterator();
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
+#else
+ ValueConstIterator(const ValueInternalArray::IteratorState& state);
+ ValueConstIterator(const ValueInternalMap::IteratorState& state);
+#endif
+public:
+ SelfType& operator=(const ValueIteratorBase& other);
+
+ SelfType operator++(int) {
+ SelfType temp(*this);
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--(int) {
+ SelfType temp(*this);
+ --*this;
+ return temp;
+ }
+
+ SelfType& operator--() {
+ decrement();
+ return *this;
+ }
+
+ SelfType& operator++() {
+ increment();
+ return *this;
+ }
+
+ reference operator*() const { return deref(); }
+
+ pointer operator->() const { return &deref(); }
+};
+
+/** \brief Iterator for object and array value.
+ */
+class JSON_API ValueIterator : public ValueIteratorBase {
+ friend class Value;
+
+public:
+ typedef Value value_type;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef Value& reference;
+ typedef Value* pointer;
+ typedef ValueIterator SelfType;
+
+ ValueIterator();
+ ValueIterator(const ValueConstIterator& other);
+ ValueIterator(const ValueIterator& other);
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueIterator(const Value::ObjectValues::iterator& current);
+#else
+ ValueIterator(const ValueInternalArray::IteratorState& state);
+ ValueIterator(const ValueInternalMap::IteratorState& state);
+#endif
+public:
+ SelfType& operator=(const SelfType& other);
+
+ SelfType operator++(int) {
+ SelfType temp(*this);
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--(int) {
+ SelfType temp(*this);
+ --*this;
+ return temp;
+ }
+
+ SelfType& operator--() {
+ decrement();
+ return *this;
+ }
+
+ SelfType& operator++() {
+ increment();
+ return *this;
+ }
+
+ reference operator*() const { return deref(); }
+
+ pointer operator->() const { return &deref(); }
+};
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_H_INCLUDED
diff --git a/include/json/version.h b/include/json/version.h
new file mode 100644
index 0000000..6fe0682
--- /dev/null
+++ b/include/json/version.h
@@ -0,0 +1,14 @@
+// DO NOT EDIT. This file is generated by CMake from "version"
+// and "version.h.in" files.
+// Run CMake configure step to update it.
+#ifndef JSON_VERSION_H_INCLUDED
+# define JSON_VERSION_H_INCLUDED
+
+# define JSONCPP_VERSION_STRING "1.0.0"
+# define JSONCPP_VERSION_MAJOR 1
+# define JSONCPP_VERSION_MINOR 0
+# define JSONCPP_VERSION_PATCH 0
+# define JSONCPP_VERSION_QUALIFIER
+# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
+
+#endif // JSON_VERSION_H_INCLUDED
diff --git a/include/json/writer.h b/include/json/writer.h
new file mode 100644
index 0000000..dc9e46f
--- /dev/null
+++ b/include/json/writer.h
@@ -0,0 +1,213 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_WRITER_H_INCLUDED
+#define JSON_WRITER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <vector>
+#include <string>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+class Value;
+
+/** \brief Abstract class for writers.
+ */
+class JSON_API Writer {
+public:
+ virtual ~Writer();
+
+ virtual std::string write(const Value& root) = 0;
+};
+
+/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
+ *without formatting (not human friendly).
+ *
+ * The JSON document is written in a single line. It is not intended for 'human'
+ *consumption,
+ * but may be usefull to support feature such as RPC where bandwith is limited.
+ * \sa Reader, Value
+ */
+class JSON_API FastWriter : public Writer {
+public:
+ FastWriter();
+ virtual ~FastWriter() {}
+
+ void enableYAMLCompatibility();
+
+ /** \brief Drop the "null" string from the writer's output for nullValues.
+ * Strictly speaking, this is not valid JSON. But when the output is being
+ * fed to a browser's Javascript, it makes for smaller output and the
+ * browser can handle the output just fine.
+ */
+ void dropNullPlaceholders();
+
+ void omitEndingLineFeed();
+
+public: // overridden from Writer
+ virtual std::string write(const Value& root);
+
+private:
+ void writeValue(const Value& value);
+
+ std::string document_;
+ bool yamlCompatiblityEnabled_;
+ bool dropNullPlaceholders_;
+ bool omitEndingLineFeed_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ *human friendly way.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per
+ *line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value
+ *types,
+ * and all the values fit on one lines, then print the array on a single
+ *line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ *#CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ */
+class JSON_API StyledWriter : public Writer {
+public:
+ StyledWriter();
+ virtual ~StyledWriter() {}
+
+public: // overridden from Writer
+ /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+ * \param root Value to serialize.
+ * \return String containing the JSON document that represents the root value.
+ */
+ virtual std::string write(const Value& root);
+
+private:
+ void writeValue(const Value& value);
+ void writeArrayValue(const Value& value);
+ bool isMultineArray(const Value& value);
+ void pushValue(const std::string& value);
+ void writeIndent();
+ void writeWithIndent(const std::string& value);
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue(const Value& root);
+ void writeCommentAfterValueOnSameLine(const Value& root);
+ bool hasCommentForValue(const Value& value);
+ static std::string normalizeEOL(const std::string& text);
+
+ typedef std::vector<std::string> ChildValues;
+
+ ChildValues childValues_;
+ std::string document_;
+ std::string indentString_;
+ int rightMargin_;
+ int indentSize_;
+ bool addChildValues_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ human friendly way,
+ to a stream rather than to a string.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per
+ line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value
+ types,
+ * and all the values fit on one lines, then print the array on a single
+ line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ #CommentPlacement.
+ *
+ * \param indentation Each level will be indented by this amount extra.
+ * \sa Reader, Value, Value::setComment()
+ */
+class JSON_API StyledStreamWriter {
+public:
+ StyledStreamWriter(std::string indentation = "\t");
+ ~StyledStreamWriter() {}
+
+public:
+ /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+ * \param out Stream to write to. (Can be ostringstream, e.g.)
+ * \param root Value to serialize.
+ * \note There is no point in deriving from Writer, since write() should not
+ * return a value.
+ */
+ void write(std::ostream& out, const Value& root);
+
+private:
+ void writeValue(const Value& value);
+ void writeArrayValue(const Value& value);
+ bool isMultineArray(const Value& value);
+ void pushValue(const std::string& value);
+ void writeIndent();
+ void writeWithIndent(const std::string& value);
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue(const Value& root);
+ void writeCommentAfterValueOnSameLine(const Value& root);
+ bool hasCommentForValue(const Value& value);
+ static std::string normalizeEOL(const std::string& text);
+
+ typedef std::vector<std::string> ChildValues;
+
+ ChildValues childValues_;
+ std::ostream* document_;
+ std::string indentString_;
+ int rightMargin_;
+ std::string indentation_;
+ bool addChildValues_;
+};
+
+#if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(Int value);
+std::string JSON_API valueToString(UInt value);
+#endif // if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(LargestInt value);
+std::string JSON_API valueToString(LargestUInt value);
+std::string JSON_API valueToString(double value);
+std::string JSON_API valueToString(bool value);
+std::string JSON_API valueToQuotedString(const char* value);
+
+/// \brief Output using the StyledStreamWriter.
+/// \see Json::operator>>()
+JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // JSON_WRITER_H_INCLUDED
diff --git a/src/lib_json/json_batchallocator.h b/src/lib_json/json_batchallocator.h
new file mode 100644
index 0000000..2fbef7a
--- /dev/null
+++ b/src/lib_json/json_batchallocator.h
@@ -0,0 +1,121 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#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:
+ 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..9ee15e9
--- /dev/null
+++ b/src/lib_json/json_internalarray.inl
@@ -0,0 +1,360 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// 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);
+ JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
+ 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);
+ JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
+ 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), size_(other.size_), pageCount_(0) {
+ 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=(ValueInternalArray other) {
+ swap(other);
+ 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;
+}
+
+} // namespace Json
diff --git a/src/lib_json/json_internalmap.inl b/src/lib_json/json_internalmap.inl
new file mode 100644
index 0000000..ef3f330
--- /dev/null
+++ b/src/lib_json/json_internalmap.inl
@@ -0,0 +1,473 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// 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=(ValueInternalMap other) {
+ swap(other);
+ return *this;
+}
+
+ValueInternalMap::~ValueInternalMap() {
+ if (buckets_) {
+ for (BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_;
+ ++bucketIndex) {
+ ValueInternalLink* link = buckets_[bucketIndex].next_;
+ while (link) {
+ ValueInternalLink* linkToRelease = link;
+ link = link->next_;
+ mapAllocator()->releaseMapLink(linkToRelease);
+ }
+ }
+ mapAllocator()->releaseMapBuckets(buckets_);
+ }
+}
+
+void ValueInternalMap::swap(ValueInternalMap& other) {
+ ValueInternalLink* tempBuckets = buckets_;
+ buckets_ = other.buckets_;
+ other.buckets_ = tempBuckets;
+ ValueInternalLink* tempTailLink = tailLink_;
+ tailLink_ = other.tailLink_;
+ other.tailLink_ = tempTailLink;
+ BucketIndex tempBucketsSize = bucketsSize_;
+ bucketsSize_ = other.bucketsSize_;
+ other.bucketsSize_ = tempBucketsSize;
+ BucketIndex tempItemCount = itemCount_;
+ itemCount_ = other.itemCount_;
+ other.itemCount_ = tempItemCount;
+}
+
+void ValueInternalMap::clear() {
+ ValueInternalMap dummy;
+ swap(dummy);
+}
+
+ValueInternalMap::BucketIndex ValueInternalMap::size() const {
+ return itemCount_;
+}
+
+bool ValueInternalMap::reserveDelta(BucketIndex growth) {
+ return reserve(itemCount_ + growth);
+}
+
+bool ValueInternalMap::reserve(BucketIndex newItemCount) {
+ if (!buckets_ && newItemCount > 0) {
+ buckets_ = mapAllocator()->allocateMapBuckets(1);
+ bucketsSize_ = 1;
+ tailLink_ = &buckets_[0];
+ }
+ // BucketIndex idealBucketCount = (newItemCount +
+ // ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
+ return true;
+}
+
+const Value* ValueInternalMap::find(const char* key) const {
+ if (!bucketsSize_)
+ return 0;
+ HashKey hashedKey = hash(key);
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ for (const ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
+ current = current->next_) {
+ for (BucketIndex index = 0; index < ValueInternalLink::itemPerLink;
+ ++index) {
+ if (current->items_[index].isItemAvailable())
+ return 0;
+ if (strcmp(key, current->keys_[index]) == 0)
+ return ¤t->items_[index];
+ }
+ }
+ return 0;
+}
+
+Value* ValueInternalMap::find(const char* key) {
+ const ValueInternalMap* constThis = this;
+ return const_cast<Value*>(constThis->find(key));
+}
+
+Value& ValueInternalMap::resolveReference(const char* key, bool isStatic) {
+ HashKey hashedKey = hash(key);
+ if (bucketsSize_) {
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ ValueInternalLink** previous = 0;
+ BucketIndex index;
+ for (ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
+ previous = ¤t->next_, current = current->next_) {
+ for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
+ if (current->items_[index].isItemAvailable())
+ return setNewItem(key, isStatic, current, index);
+ if (strcmp(key, current->keys_[index]) == 0)
+ return current->items_[index];
+ }
+ }
+ }
+
+ reserveDelta(1);
+ return unsafeAdd(key, isStatic, hashedKey);
+}
+
+void ValueInternalMap::remove(const char* key) {
+ HashKey hashedKey = hash(key);
+ if (!bucketsSize_)
+ return;
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ for (ValueInternalLink* link = &buckets_[bucketIndex]; link != 0;
+ link = link->next_) {
+ BucketIndex index;
+ for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
+ if (link->items_[index].isItemAvailable())
+ return;
+ if (strcmp(key, link->keys_[index]) == 0) {
+ doActualRemove(link, index, bucketIndex);
+ return;
+ }
+ }
+ }
+}
+
+void ValueInternalMap::doActualRemove(ValueInternalLink* link,
+ BucketIndex index,
+ BucketIndex bucketIndex) {
+ // find last item of the bucket and swap it with the 'removed' one.
+ // set removed items flags to 'available'.
+ // if last page only contains 'available' items, then desallocate it (it's
+ // empty)
+ ValueInternalLink*& lastLink = getLastLinkInBucket(index);
+ BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
+ for (; lastItemIndex < ValueInternalLink::itemPerLink;
+ ++lastItemIndex) // may be optimized with dicotomic search
+ {
+ if (lastLink->items_[lastItemIndex].isItemAvailable())
+ break;
+ }
+
+ BucketIndex lastUsedIndex = lastItemIndex - 1;
+ Value* valueToDelete = &link->items_[index];
+ Value* valueToPreserve = &lastLink->items_[lastUsedIndex];
+ if (valueToDelete != valueToPreserve)
+ valueToDelete->swap(*valueToPreserve);
+ if (lastUsedIndex == 0) // page is now empty
+ { // remove it from bucket linked list and delete it.
+ ValueInternalLink* linkPreviousToLast = lastLink->previous_;
+ if (linkPreviousToLast != 0) // can not deleted bucket link.
+ {
+ mapAllocator()->releaseMapLink(lastLink);
+ linkPreviousToLast->next_ = 0;
+ lastLink = linkPreviousToLast;
+ }
+ } else {
+ Value dummy;
+ valueToPreserve->swap(dummy); // restore deleted to default Value.
+ valueToPreserve->setItemUsed(false);
+ }
+ --itemCount_;
+}
+
+ValueInternalLink*&
+ValueInternalMap::getLastLinkInBucket(BucketIndex bucketIndex) {
+ if (bucketIndex == bucketsSize_ - 1)
+ return tailLink_;
+ ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_;
+ if (!previous)
+ previous = &buckets_[bucketIndex];
+ return previous;
+}
+
+Value& ValueInternalMap::setNewItem(const char* key,
+ bool isStatic,
+ ValueInternalLink* link,
+ BucketIndex index) {
+ char* duplicatedKey = 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;
+}
+
+} // namespace Json
diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp
new file mode 100644
index 0000000..c5111f8
--- /dev/null
+++ b/src/lib_json/json_reader.cpp
@@ -0,0 +1,885 @@
+// Copyright 2007-2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/reader.h>
+#include <json/value.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <cstdio>
+#include <cassert>
+#include <cstring>
+#include <istream>
+
+#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
+#define snprintf _snprintf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json {
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+ : allowComments_(true), strictRoot_(false),
+ allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
+
+Features Features::all() { return Features(); }
+
+Features Features::strictMode() {
+ Features features;
+ features.allowComments_ = false;
+ features.strictRoot_ = true;
+ features.allowDroppedNullPlaceholders_ = false;
+ features.allowNumericKeys_ = false;
+ return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+static inline bool in(Reader::Char c,
+ Reader::Char c1,
+ Reader::Char c2,
+ Reader::Char c3,
+ Reader::Char c4) {
+ return c == c1 || c == c2 || c == c3 || c == c4;
+}
+
+static inline bool in(Reader::Char c,
+ Reader::Char c1,
+ Reader::Char c2,
+ Reader::Char c3,
+ Reader::Char c4,
+ Reader::Char c5) {
+ return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
+}
+
+static bool containsNewLine(Reader::Location begin, Reader::Location end) {
+ for (; begin < end; ++begin)
+ if (*begin == '\n' || *begin == '\r')
+ return true;
+ return false;
+}
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+ : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+ lastValue_(), commentsBefore_(), features_(Features::all()),
+ collectComments_() {}
+
+Reader::Reader(const Features& features)
+ : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+ lastValue_(), commentsBefore_(), features_(features), collectComments_() {
+}
+
+bool
+Reader::parse(const std::string& document, Value& root, bool collectComments) {
+ document_ = document;
+ const char* begin = document_.c_str();
+ const char* end = begin + document_.length();
+ return parse(begin, end, root, collectComments);
+}
+
+bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
+ // std::istream_iterator<char> begin(sin);
+ // std::istream_iterator<char> end;
+ // Those would allow streamed input from a file, if parse() were a
+ // template function.
+
+ // Since std::string is reference-counted, this at least does not
+ // create an extra copy.
+ std::string doc;
+ std::getline(sin, doc, (char)EOF);
+ return parse(doc, root, collectComments);
+}
+
+bool Reader::parse(const char* beginDoc,
+ const char* endDoc,
+ Value& root,
+ bool collectComments) {
+ if (!features_.allowComments_) {
+ collectComments = false;
+ }
+
+ begin_ = beginDoc;
+ end_ = endDoc;
+ collectComments_ = collectComments;
+ current_ = begin_;
+ lastValueEnd_ = 0;
+ lastValue_ = 0;
+ commentsBefore_ = "";
+ errors_.clear();
+ while (!nodes_.empty())
+ nodes_.pop();
+ nodes_.push(&root);
+
+ bool successful = readValue();
+ Token token;
+ skipCommentTokens(token);
+ if (collectComments_ && !commentsBefore_.empty())
+ root.setComment(commentsBefore_, commentAfter);
+ if (features_.strictRoot_) {
+ if (!root.isArray() && !root.isObject()) {
+ // Set error location to start of doc, ideally should be first token found
+ // in doc
+ token.type_ = tokenError;
+ token.start_ = beginDoc;
+ token.end_ = endDoc;
+ addError(
+ "A valid JSON document must be either an array or an object value.",
+ token);
+ return false;
+ }
+ }
+ return successful;
+}
+
+bool Reader::readValue() {
+ Token token;
+ skipCommentTokens(token);
+ bool successful = true;
+
+ if (collectComments_ && !commentsBefore_.empty()) {
+ // Remove newline characters at the end of the comments
+ size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n");
+ if (lastNonNewline != std::string::npos) {
+ commentsBefore_.erase(lastNonNewline + 1);
+ } else {
+ commentsBefore_.clear();
+ }
+
+ currentValue().setComment(commentsBefore_, commentBefore);
+ commentsBefore_ = "";
+ }
+
+ switch (token.type_) {
+ case tokenObjectBegin:
+ successful = readObject(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenArrayBegin:
+ successful = readArray(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenNumber:
+ successful = decodeNumber(token);
+ break;
+ case tokenString:
+ successful = decodeString(token);
+ break;
+ case tokenTrue:
+ currentValue() = true;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ break;
+ case tokenFalse:
+ currentValue() = false;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ break;
+ case tokenNull:
+ currentValue() = Value();
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ break;
+ case tokenArraySeparator:
+ if (features_.allowDroppedNullPlaceholders_) {
+ // "Un-read" the current token and mark the current value as a null
+ // token.
+ current_--;
+ currentValue() = Value();
+ currentValue().setOffsetStart(current_ - begin_ - 1);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ }
+ // Else, fall through...
+ default:
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return addError("Syntax error: value, object or array expected.", token);
+ }
+
+ if (collectComments_) {
+ lastValueEnd_ = current_;
+ lastValue_ = ¤tValue();
+ }
+
+ return successful;
+}
+
+void Reader::skipCommentTokens(Token& token) {
+ if (features_.allowComments_) {
+ do {
+ readToken(token);
+ } while (token.type_ == tokenComment);
+ } else {
+ readToken(token);
+ }
+}
+
+bool Reader::expectToken(TokenType type, Token& token, const char* message) {
+ readToken(token);
+ if (token.type_ != type)
+ return addError(message, token);
+ return true;
+}
+
+bool Reader::readToken(Token& token) {
+ skipSpaces();
+ token.start_ = current_;
+ Char c = getNextChar();
+ bool ok = true;
+ switch (c) {
+ case '{':
+ token.type_ = tokenObjectBegin;
+ break;
+ case '}':
+ token.type_ = tokenObjectEnd;
+ break;
+ case '[':
+ token.type_ = tokenArrayBegin;
+ break;
+ case ']':
+ token.type_ = tokenArrayEnd;
+ break;
+ case '"':
+ token.type_ = tokenString;
+ ok = readString();
+ break;
+ case '/':
+ token.type_ = tokenComment;
+ ok = readComment();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ token.type_ = tokenNumber;
+ readNumber();
+ break;
+ case 't':
+ token.type_ = tokenTrue;
+ ok = match("rue", 3);
+ break;
+ case 'f':
+ token.type_ = tokenFalse;
+ ok = match("alse", 4);
+ break;
+ case 'n':
+ token.type_ = tokenNull;
+ ok = match("ull", 3);
+ break;
+ case ',':
+ token.type_ = tokenArraySeparator;
+ break;
+ case ':':
+ token.type_ = tokenMemberSeparator;
+ break;
+ case 0:
+ token.type_ = tokenEndOfStream;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if (!ok)
+ token.type_ = tokenError;
+ token.end_ = current_;
+ return true;
+}
+
+void Reader::skipSpaces() {
+ while (current_ != end_) {
+ Char c = *current_;
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ ++current_;
+ else
+ break;
+ }
+}
+
+bool Reader::match(Location pattern, int patternLength) {
+ if (end_ - current_ < patternLength)
+ return false;
+ int index = patternLength;
+ while (index--)
+ if (current_[index] != pattern[index])
+ return false;
+ current_ += patternLength;
+ return true;
+}
+
+bool Reader::readComment() {
+ Location commentBegin = current_ - 1;
+ Char c = getNextChar();
+ bool successful = false;
+ if (c == '*')
+ successful = readCStyleComment();
+ else if (c == '/')
+ successful = readCppStyleComment();
+ if (!successful)
+ return false;
+
+ if (collectComments_) {
+ CommentPlacement placement = commentBefore;
+ if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+ if (c != '*' || !containsNewLine(commentBegin, current_))
+ placement = commentAfterOnSameLine;
+ }
+
+ addComment(commentBegin, current_, placement);
+ }
+ return true;
+}
+
+void
+Reader::addComment(Location begin, Location end, CommentPlacement placement) {
+ assert(collectComments_);
+ if (placement == commentAfterOnSameLine) {
+ assert(lastValue_ != 0);
+ lastValue_->setComment(std::string(begin, end), placement);
+ } else {
+ 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);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ 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;
+ name = "";
+ if (tokenName.type_ == tokenString) {
+ if (!decodeString(tokenName, name))
+ return recoverFromError(tokenObjectEnd);
+ } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+ Value numberName;
+ if (!decodeNumber(tokenName, numberName))
+ return recoverFromError(tokenObjectEnd);
+ name = numberName.asString();
+ } else {
+ break;
+ }
+
+ Token colon;
+ if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+ return addErrorAndRecover(
+ "Missing ':' after object member name", colon, tokenObjectEnd);
+ }
+ Value& value = currentValue()[name];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenObjectEnd);
+
+ Token comma;
+ if (!readToken(comma) ||
+ (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+ comma.type_ != tokenComment)) {
+ return addErrorAndRecover(
+ "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+ }
+ bool finalizeTokenOk = true;
+ while (comma.type_ == tokenComment && finalizeTokenOk)
+ finalizeTokenOk = readToken(comma);
+ if (comma.type_ == tokenObjectEnd)
+ return true;
+ }
+ return addErrorAndRecover(
+ "Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool Reader::readArray(Token& tokenStart) {
+ currentValue() = Value(arrayValue);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ skipSpaces();
+ if (*current_ == ']') // empty array
+ {
+ Token endArray;
+ readToken(endArray);
+ return true;
+ }
+ int index = 0;
+ for (;;) {
+ Value& value = currentValue()[index++];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenArrayEnd);
+
+ Token token;
+ // Accept Comment after last item in the array.
+ ok = readToken(token);
+ while (token.type_ == tokenComment && ok) {
+ ok = readToken(token);
+ }
+ bool badTokenType =
+ (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+ if (!ok || badTokenType) {
+ return addErrorAndRecover(
+ "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+ }
+ if (token.type_ == tokenArrayEnd)
+ break;
+ }
+ return true;
+}
+
+bool Reader::decodeNumber(Token& token) {
+ Value decoded;
+ if (!decodeNumber(token, decoded))
+ return false;
+ currentValue() = decoded;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeNumber(Token& token, Value& decoded) {
+ 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, decoded);
+ // Attempts to parse the number as an integer. If the number is
+ // larger than the maximum supported value of an integer then
+ // we decode the number as a double.
+ Location current = token.start_;
+ bool isNegative = *current == '-';
+ if (isNegative)
+ ++current;
+ Value::LargestUInt maxIntegerValue =
+ isNegative ? Value::LargestUInt(-Value::minLargestInt)
+ : Value::maxLargestUInt;
+ Value::LargestUInt threshold = maxIntegerValue / 10;
+ Value::LargestUInt 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);
+ Value::UInt digit(c - '0');
+ if (value >= threshold) {
+ // We've hit or exceeded the max value divided by 10 (rounded down). If
+ // a) we've only just touched the limit, b) this is the last digit, and
+ // c) it's small enough to fit in that rounding delta, we're okay.
+ // Otherwise treat this number as a double to avoid overflow.
+ if (value > threshold || current != token.end_ ||
+ digit > maxIntegerValue % 10) {
+ return decodeDouble(token, decoded);
+ }
+ }
+ value = value * 10 + digit;
+ }
+ if (isNegative)
+ decoded = -Value::LargestInt(value);
+ else if (value <= Value::LargestUInt(Value::maxInt))
+ decoded = Value::LargestInt(value);
+ else
+ decoded = value;
+ return true;
+}
+
+bool Reader::decodeDouble(Token& token) {
+ Value decoded;
+ if (!decodeDouble(token, decoded))
+ return false;
+ currentValue() = decoded;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeDouble(Token& token, Value& decoded) {
+ double value = 0;
+ const int bufferSize = 32;
+ int count;
+ int length = int(token.end_ - token.start_);
+
+ // Sanity check to avoid buffer overflow exploits.
+ if (length < 0) {
+ return addError("Unable to parse token length", token);
+ }
+
+ // Avoid using a string constant for the format control string given to
+ // sscanf, as this can cause hard to debug crashes on OS X. See here for more
+ // info:
+ //
+ // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
+ char format[] = "%lf";
+
+ if (length <= bufferSize) {
+ Char buffer[bufferSize + 1];
+ memcpy(buffer, token.start_, length);
+ buffer[length] = 0;
+ count = sscanf(buffer, format, &value);
+ } else {
+ std::string buffer(token.start_, token.end_);
+ count = sscanf(buffer.c_str(), format, &value);
+ }
+
+ if (count != 1)
+ return addError("'" + std::string(token.start_, token.end_) +
+ "' is not a number.",
+ token);
+ decoded = value;
+ return true;
+}
+
+bool Reader::decodeString(Token& token) {
+ std::string decoded;
+ if (!decodeString(token, decoded))
+ return false;
+ currentValue() = decoded;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeString(Token& token, std::string& decoded) {
+ decoded.reserve(token.end_ - token.start_ - 2);
+ Location current = token.start_ + 1; // skip '"'
+ Location end = token.end_ - 1; // do not include '"'
+ while (current != end) {
+ Char c = *current++;
+ if (c == '"')
+ break;
+ else if (c == '\\') {
+ if (current == end)
+ return addError("Empty escape sequence in string", token, current);
+ Char escape = *current++;
+ switch (escape) {
+ case '"':
+ decoded += '"';
+ break;
+ case '/':
+ decoded += '/';
+ break;
+ case '\\':
+ decoded += '\\';
+ break;
+ case 'b':
+ decoded += '\b';
+ break;
+ case 'f':
+ decoded += '\f';
+ break;
+ case 'n':
+ decoded += '\n';
+ break;
+ case 'r':
+ decoded += '\r';
+ break;
+ case 't':
+ decoded += '\t';
+ break;
+ case 'u': {
+ unsigned int unicode;
+ if (!decodeUnicodeCodePoint(token, current, end, unicode))
+ return false;
+ decoded += codePointToUTF8(unicode);
+ } break;
+ default:
+ return addError("Bad escape sequence in string", token, current);
+ }
+ } else {
+ decoded += c;
+ }
+ }
+ return true;
+}
+
+bool Reader::decodeUnicodeCodePoint(Token& token,
+ Location& current,
+ Location end,
+ unsigned int& unicode) {
+
+ if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+ return false;
+ if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+ // surrogate pairs
+ if (end - current < 6)
+ return addError(
+ "additional six characters expected to parse unicode surrogate pair.",
+ token,
+ current);
+ unsigned int surrogatePair;
+ if (*(current++) == '\\' && *(current++) == 'u') {
+ if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+ unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+ } else
+ return false;
+ } else
+ return addError("expecting another \\u token to begin the second half of "
+ "a unicode surrogate pair",
+ token,
+ current);
+ }
+ return true;
+}
+
+bool Reader::decodeUnicodeEscapeSequence(Token& token,
+ Location& 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;
+ for (;;) {
+ 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];
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
+#if defined(WINCE)
+ _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+#else
+ sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+#endif
+#else
+ snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+#endif
+ return buffer;
+}
+
+// Deprecated. Preserved for backward compatibility
+std::string Reader::getFormatedErrorMessages() const {
+ return getFormattedErrorMessages();
+}
+
+std::string Reader::getFormattedErrorMessages() const {
+ std::string formattedMessage;
+ for (Errors::const_iterator itError = errors_.begin();
+ itError != errors_.end();
+ ++itError) {
+ const ErrorInfo& error = *itError;
+ formattedMessage +=
+ "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+ formattedMessage += " " + error.message_ + "\n";
+ if (error.extra_)
+ formattedMessage +=
+ "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+ }
+ return formattedMessage;
+}
+
+std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
+ std::vector<Reader::StructuredError> allErrors;
+ for (Errors::const_iterator itError = errors_.begin();
+ itError != errors_.end();
+ ++itError) {
+ const ErrorInfo& error = *itError;
+ Reader::StructuredError structured;
+ structured.offset_start = error.token_.start_ - begin_;
+ structured.offset_limit = error.token_.end_ - begin_;
+ structured.message = error.message_;
+ allErrors.push_back(structured);
+ }
+ return allErrors;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message) {
+ size_t length = end_ - begin_;
+ if(value.getOffsetStart() > length
+ || value.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = end_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = 0;
+ errors_.push_back(info);
+ return true;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
+ size_t length = end_ - begin_;
+ if(value.getOffsetStart() > length
+ || value.getOffsetLimit() > length
+ || extra.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = begin_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = begin_ + extra.getOffsetStart();
+ errors_.push_back(info);
+ return true;
+}
+
+bool Reader::good() const {
+ return !errors_.size();
+}
+
+std::istream& operator>>(std::istream& sin, Value& root) {
+ Json::Reader reader;
+ bool ok = reader.parse(sin, root, true);
+ if (!ok) {
+ fprintf(stderr,
+ "Error from reader: %s",
+ reader.getFormattedErrorMessages().c_str());
+
+ JSON_FAIL_MESSAGE("reader error");
+ }
+ return sin;
+}
+
+} // namespace Json
diff --git a/src/lib_json/json_tool.h b/src/lib_json/json_tool.h
new file mode 100644
index 0000000..f9b61c3
--- /dev/null
+++ b/src/lib_json/json_tool.h
@@ -0,0 +1,87 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+/* This header provides common string manipulation support, such as UTF-8,
+ * portable conversion from/to string...
+ *
+ * It is an internal header that must not be exposed.
+ */
+
+namespace Json {
+
+/// Converts a unicode code-point to UTF-8.
+static inline std::string codePointToUTF8(unsigned int cp) {
+ std::string result;
+
+ // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+ if (cp <= 0x7f) {
+ result.resize(1);
+ result[0] = static_cast<char>(cp);
+ } else if (cp <= 0x7FF) {
+ result.resize(2);
+ result[1] = static_cast<char>(0x80 | (0x3f & cp));
+ result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+ } else if (cp <= 0xFFFF) {
+ result.resize(3);
+ result[2] = static_cast<char>(0x80 | (0x3f & cp));
+ result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
+ result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
+ } else if (cp <= 0x10FFFF) {
+ result.resize(4);
+ result[3] = static_cast<char>(0x80 | (0x3f & cp));
+ result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+ result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+ result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+ }
+
+ return result;
+}
+
+/// Returns true if ch is a control character (in range [0,32[).
+static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
+
+enum {
+ /// Constant that specify the size of the buffer that must be passed to
+ /// uintToString.
+ uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
+};
+
+// Defines a char buffer for use with uintToString().
+typedef char UIntToStringBuffer[uintToStringBufferSize];
+
+/** Converts an unsigned integer to string.
+ * @param value Unsigned interger to convert to string
+ * @param current Input/Output string buffer.
+ * Must have at least uintToStringBufferSize chars free.
+ */
+static inline void uintToString(LargestUInt value, char*& current) {
+ *--current = 0;
+ do {
+ *--current = char(value % 10) + '0';
+ value /= 10;
+ } while (value != 0);
+}
+
+/** Change ',' to '.' everywhere in buffer.
+ *
+ * We had a sophisticated way, but it did not work in WinCE.
+ * @see https://github.com/open-source-parsers/jsoncpp/pull/9
+ */
+static inline void fixNumericLocale(char* begin, char* end) {
+ while (begin < end) {
+ if (*begin == ',') {
+ *begin = '.';
+ }
+ ++begin;
+ }
+}
+
+} // namespace Json {
+
+#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp
new file mode 100644
index 0000000..b73deac
--- /dev/null
+++ b/src/lib_json/json_value.cpp
@@ -0,0 +1,1478 @@
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/value.h>
+#include <json/writer.h>
+#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+#include "json_batchallocator.h"
+#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <math.h>
+#include <sstream>
+#include <utility>
+#include <cstring>
+#include <cassert>
+#ifdef JSON_USE_CPPTL
+#include <cpptl/conststring.h>
+#endif
+#include <cstddef> // size_t
+
+#define JSON_ASSERT_UNREACHABLE assert(false)
+
+namespace Json {
+
+// This is a walkaround to avoid the static initialization of Value::null.
+// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
+// 8 (instead of 4) as a bit of future-proofing.
+#if defined(__ARMEL__)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#else
+#define ALIGNAS(byte_alignment)
+#endif
+static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
+const unsigned char& kNullRef = kNull[0];
+const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
+
+const Int Value::minInt = Int(~(UInt(-1) / 2));
+const Int Value::maxInt = Int(UInt(-1) / 2);
+const UInt Value::maxUInt = UInt(-1);
+#if defined(JSON_HAS_INT64)
+const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
+const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
+const UInt64 Value::maxUInt64 = UInt64(-1);
+// The constant is hard-coded because some compiler have trouble
+// converting Value::maxUInt64 to a double correctly (AIX/xlC).
+// Assumes that UInt64 is a 64 bits integer.
+static const double maxUInt64AsDouble = 18446744073709551615.0;
+#endif // defined(JSON_HAS_INT64)
+const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
+const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
+const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
+
+/// Unknown size marker
+static const unsigned int unknown = (unsigned)-1;
+
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+ return d >= min && d <= max;
+}
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+static inline double integerToDouble(Json::UInt64 value) {
+ return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
+}
+
+template <typename T> static inline double integerToDouble(T value) {
+ return static_cast<double>(value);
+}
+
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+ return d >= integerToDouble(min) && d <= integerToDouble(max);
+}
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+
+/** Duplicates the specified string value.
+ * @param value Pointer to the string to duplicate. Must be zero-terminated if
+ * length is "unknown".
+ * @param length Length of the value. if equals to unknown, then it will be
+ * computed using strlen(value).
+ * @return Pointer on the duplicate instance of string.
+ */
+static inline char* duplicateStringValue(const char* value,
+ unsigned int length = unknown) {
+ if (length == unknown)
+ length = (unsigned int)strlen(value);
+
+ // Avoid an integer overflow in the call to malloc below by limiting length
+ // to a sane value.
+ if (length >= (unsigned)Value::maxInt)
+ length = Value::maxInt - 1;
+
+ char* newString = static_cast<char*>(malloc(length + 1));
+ JSON_ASSERT_MESSAGE(newString != 0,
+ "in Json::Value::duplicateStringValue(): "
+ "Failed to allocate string value buffer");
+ memcpy(newString, value, length);
+ newString[length] = 0;
+ return newString;
+}
+
+/** Free the string duplicated by duplicateStringValue().
+ */
+static inline void releaseStringValue(char* value) { free(value); }
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#if !defined(JSON_IS_AMALGAMATION)
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+#include "json_internalarray.inl"
+#include "json_internalmap.inl"
+#endif // JSON_VALUE_USE_INTERNAL_MAP
+
+#include "json_valueiterator.inl"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+Value::CommentInfo::CommentInfo() : comment_(0) {}
+
+Value::CommentInfo::~CommentInfo() {
+ if (comment_)
+ releaseStringValue(comment_);
+}
+
+void Value::CommentInfo::setComment(const char* text) {
+ if (comment_)
+ releaseStringValue(comment_);
+ JSON_ASSERT(text != 0);
+ JSON_ASSERT_MESSAGE(
+ text[0] == '\0' || text[0] == '/',
+ "in Json::Value::setComment(): Comments must start with /");
+ // It seems that /**/ style comments are acceptable as well.
+ comment_ = 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(ArrayIndex index) : cstr_(0), index_(index) {}
+
+Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate)
+ : cstr_(allocate == duplicate ? duplicateStringValue(cstr) : cstr),
+ index_(allocate) {}
+
+Value::CZString::CZString(const CZString& other)
+ : cstr_(other.index_ != noDuplication && other.cstr_ != 0
+ ? duplicateStringValue(other.cstr_)
+ : other.cstr_),
+ index_(other.cstr_
+ ? static_cast<ArrayIndex>(other.index_ == noDuplication
+ ? noDuplication : duplicate)
+ : other.index_) {}
+
+Value::CZString::~CZString() {
+ if (cstr_ && index_ == duplicate)
+ releaseStringValue(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=(CZString other) {
+ swap(other);
+ 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_;
+}
+
+ArrayIndex 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) {
+ initBasic(type);
+ 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) {
+ initBasic(intValue);
+ value_.int_ = value;
+}
+
+Value::Value(UInt value) {
+ initBasic(uintValue);
+ value_.uint_ = value;
+}
+#if defined(JSON_HAS_INT64)
+Value::Value(Int64 value) {
+ initBasic(intValue);
+ value_.int_ = value;
+}
+Value::Value(UInt64 value) {
+ initBasic(uintValue);
+ value_.uint_ = value;
+}
+#endif // defined(JSON_HAS_INT64)
+
+Value::Value(double value) {
+ initBasic(realValue);
+ value_.real_ = value;
+}
+
+Value::Value(const char* value) {
+ initBasic(stringValue, true);
+ value_.string_ = duplicateStringValue(value);
+}
+
+Value::Value(const char* beginValue, const char* endValue) {
+ initBasic(stringValue, true);
+ value_.string_ =
+ duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue));
+}
+
+Value::Value(const std::string& value) {
+ initBasic(stringValue, true);
+ value_.string_ =
+ duplicateStringValue(value.c_str(), (unsigned int)value.length());
+}
+
+Value::Value(const StaticString& value) {
+ initBasic(stringValue);
+ value_.string_ = const_cast<char*>(value.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value::Value(const CppTL::ConstString& value) {
+ initBasic(stringValue, true);
+ value_.string_ = duplicateStringValue(value, value.length());
+}
+#endif
+
+Value::Value(bool value) {
+ initBasic(booleanValue);
+ value_.bool_ = value;
+}
+
+Value::Value(const Value& other)
+ : type_(other.type_), allocated_(false)
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ ,
+ itemIsUsed_(0)
+#endif
+ ,
+ comments_(0), start_(other.start_), limit_(other.limit_) {
+ switch (type_) {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ value_ = other.value_;
+ break;
+ case stringValue:
+ if (other.value_.string_) {
+ value_.string_ = duplicateStringValue(other.value_.string_);
+ allocated_ = true;
+ } else {
+ value_.string_ = 0;
+ allocated_ = false;
+ }
+ 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_)
+ 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=(Value other) {
+ swap(other);
+ 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;
+ std::swap(start_, other.start_);
+ std::swap(limit_, other.limit_);
+}
+
+ValueType Value::type() const { return type_; }
+
+int Value::compare(const Value& other) const {
+ if (*this < other)
+ return -1;
+ if (*this > other)
+ return 1;
+ return 0;
+}
+
+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 false; // unreachable
+}
+
+bool Value::operator<=(const Value& other) const { return !(other < *this); }
+
+bool Value::operator>=(const Value& other) const { return !(*this < other); }
+
+bool Value::operator>(const Value& other) const { return other < *this; }
+
+bool Value::operator==(const Value& other) const {
+ // if ( type_ != other.type_ )
+ // GCC 2.95.3 says:
+ // attempt to take address of bit-field structure member `Json::Value::type_'
+ // Beats me, but a temp solves the problem.
+ int temp = other.type_;
+ if (type_ != temp)
+ return false;
+ switch (type_) {
+ case nullValue:
+ return true;
+ case intValue:
+ return value_.int_ == other.value_.int_;
+ case uintValue:
+ return value_.uint_ == other.value_.uint_;
+ case realValue:
+ return value_.real_ == other.value_.real_;
+ case booleanValue:
+ return value_.bool_ == other.value_.bool_;
+ case stringValue:
+ return (value_.string_ == other.value_.string_) ||
+ (other.value_.string_ && value_.string_ &&
+ strcmp(value_.string_, other.value_.string_) == 0);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ return value_.map_->size() == other.value_.map_->size() &&
+ (*value_.map_) == (*other.value_.map_);
+#else
+ case arrayValue:
+ return value_.array_->compare(*(other.value_.array_)) == 0;
+ case objectValue:
+ return value_.map_->compare(*(other.value_.map_)) == 0;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return false; // unreachable
+}
+
+bool Value::operator!=(const Value& other) const { return !(*this == other); }
+
+const char* Value::asCString() const {
+ JSON_ASSERT_MESSAGE(type_ == stringValue,
+ "in Json::Value::asCString(): requires 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:
+ return valueToString(value_.int_);
+ case uintValue:
+ return valueToString(value_.uint_);
+ case realValue:
+ return valueToString(value_.real_);
+ default:
+ JSON_FAIL_MESSAGE("Type is not convertible to string");
+ }
+}
+
+#ifdef JSON_USE_CPPTL
+CppTL::ConstString Value::asConstString() const {
+ return CppTL::ConstString(asString().c_str());
+}
+#endif
+
+Value::Int Value::asInt() const {
+ switch (type_) {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+ return Int(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+ return Int(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
+ "double out of Int range");
+ return Int(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to Int.");
+}
+
+Value::UInt Value::asUInt() const {
+ switch (type_) {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+ return UInt(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+ return UInt(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
+ "double out of UInt range");
+ return UInt(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
+}
+
+#if defined(JSON_HAS_INT64)
+
+Value::Int64 Value::asInt64() const {
+ switch (type_) {
+ case intValue:
+ return Int64(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+ return Int64(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
+ "double out of Int64 range");
+ return Int64(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
+}
+
+Value::UInt64 Value::asUInt64() const {
+ switch (type_) {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+ return UInt64(value_.int_);
+ case uintValue:
+ return UInt64(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
+ "double out of UInt64 range");
+ return UInt64(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
+}
+#endif // if defined(JSON_HAS_INT64)
+
+LargestInt Value::asLargestInt() const {
+#if defined(JSON_NO_INT64)
+ return asInt();
+#else
+ return asInt64();
+#endif
+}
+
+LargestUInt Value::asLargestUInt() const {
+#if defined(JSON_NO_INT64)
+ return asUInt();
+#else
+ return asUInt64();
+#endif
+}
+
+double Value::asDouble() const {
+ switch (type_) {
+ case intValue:
+ return static_cast<double>(value_.int_);
+ case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return static_cast<double>(value_.uint_);
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ case realValue:
+ return value_.real_;
+ case nullValue:
+ return 0.0;
+ case booleanValue:
+ return value_.bool_ ? 1.0 : 0.0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to double.");
+}
+
+float Value::asFloat() const {
+ switch (type_) {
+ case intValue:
+ return static_cast<float>(value_.int_);
+ case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return static_cast<float>(value_.uint_);
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ case realValue:
+ return static_cast<float>(value_.real_);
+ case nullValue:
+ return 0.0;
+ case booleanValue:
+ return value_.bool_ ? 1.0f : 0.0f;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to float.");
+}
+
+bool Value::asBool() const {
+ switch (type_) {
+ case booleanValue:
+ return value_.bool_;
+ case nullValue:
+ return false;
+ case intValue:
+ return value_.int_ ? true : false;
+ case uintValue:
+ return value_.uint_ ? true : false;
+ case realValue:
+ return value_.real_ ? true : false;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to bool.");
+}
+
+bool Value::isConvertibleTo(ValueType other) const {
+ switch (other) {
+ case nullValue:
+ return (isNumeric() && asDouble() == 0.0) ||
+ (type_ == booleanValue && value_.bool_ == false) ||
+ (type_ == stringValue && asString() == "") ||
+ (type_ == arrayValue && value_.map_->size() == 0) ||
+ (type_ == objectValue && value_.map_->size() == 0) ||
+ type_ == nullValue;
+ case intValue:
+ return isInt() ||
+ (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
+ type_ == booleanValue || type_ == nullValue;
+ case uintValue:
+ return isUInt() ||
+ (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
+ type_ == booleanValue || type_ == nullValue;
+ case realValue:
+ return isNumeric() || type_ == booleanValue || type_ == nullValue;
+ case booleanValue:
+ return isNumeric() || type_ == booleanValue || type_ == nullValue;
+ case stringValue:
+ return isNumeric() || type_ == booleanValue || type_ == stringValue ||
+ type_ == nullValue;
+ case arrayValue:
+ return type_ == arrayValue || type_ == nullValue;
+ case objectValue:
+ return type_ == objectValue || type_ == nullValue;
+ }
+ JSON_ASSERT_UNREACHABLE;
+ return false;
+}
+
+/// Number of values in array or object
+ArrayIndex 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 ArrayIndex(value_.map_->size());
+#else
+ case arrayValue:
+ return Int(value_.array_->size());
+ case objectValue:
+ return Int(value_.map_->size());
+#endif
+ }
+ JSON_ASSERT_UNREACHABLE;
+ return 0; // unreachable;
+}
+
+bool Value::empty() const {
+ if (isNull() || isArray() || isObject())
+ return size() == 0u;
+ else
+ return false;
+}
+
+bool Value::operator!() const { return isNull(); }
+
+void Value::clear() {
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
+ type_ == objectValue,
+ "in Json::Value::clear(): requires complex value");
+ start_ = 0;
+ limit_ = 0;
+ 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(ArrayIndex newSize) {
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::resize(): requires arrayValue");
+ if (type_ == nullValue)
+ *this = Value(arrayValue);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ArrayIndex oldSize = size();
+ if (newSize == 0)
+ clear();
+ else if (newSize > oldSize)
+ (*this)[newSize - 1];
+ else {
+ for (ArrayIndex index = newSize; index < oldSize; ++index) {
+ value_.map_->erase(index);
+ }
+ assert(size() == newSize);
+ }
+#else
+ value_.array_->resize(newSize);
+#endif
+}
+
+Value& Value::operator[](ArrayIndex index) {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::operator[](ArrayIndex): requires 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
+}
+
+Value& Value::operator[](int index) {
+ JSON_ASSERT_MESSAGE(
+ index >= 0,
+ "in Json::Value::operator[](int index): index cannot be negative");
+ return (*this)[ArrayIndex(index)];
+}
+
+const Value& Value::operator[](ArrayIndex index) const {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::operator[](ArrayIndex)const: requires 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
+}
+
+const Value& Value::operator[](int index) const {
+ JSON_ASSERT_MESSAGE(
+ index >= 0,
+ "in Json::Value::operator[](int index) const: index cannot be negative");
+ return (*this)[ArrayIndex(index)];
+}
+
+Value& Value::operator[](const char* key) {
+ return resolveReference(key, false);
+}
+
+void Value::initBasic(ValueType type, bool allocated) {
+ type_ = type;
+ allocated_ = allocated;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ itemIsUsed_ = 0;
+#endif
+ comments_ = 0;
+ start_ = 0;
+ limit_ = 0;
+}
+
+Value& Value::resolveReference(const char* key, bool isStatic) {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == objectValue,
+ "in Json::Value::resolveReference(): requires 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(ArrayIndex index, const Value& defaultValue) const {
+ const Value* value = &((*this)[index]);
+ return value == &null ? defaultValue : *value;
+}
+
+bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
+
+const Value& Value::operator[](const char* key) const {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == objectValue,
+ "in Json::Value::operator[](char const*)const: requires objectValue");
+ if (type_ == nullValue)
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey(key, CZString::noDuplication);
+ ObjectValues::const_iterator it = value_.map_->find(actualKey);
+ if (it == value_.map_->end())
+ return null;
+ return (*it).second;
+#else
+ const Value* value = value_.map_->find(key);
+ return value ? *value : null;
+#endif
+}
+
+Value& Value::operator[](const std::string& key) {
+ return (*this)[key.c_str()];
+}
+
+const Value& Value::operator[](const std::string& key) const {
+ return (*this)[key.c_str()];
+}
+
+Value& Value::operator[](const StaticString& key) {
+ return resolveReference(key, true);
+}
+
+#ifdef JSON_USE_CPPTL
+Value& Value::operator[](const CppTL::ConstString& key) {
+ return (*this)[key.c_str()];
+}
+
+const Value& Value::operator[](const CppTL::ConstString& key) const {
+ return (*this)[key.c_str()];
+}
+#endif
+
+Value& Value::append(const Value& value) { return (*this)[size()] = value; }
+
+Value Value::get(const char* key, const Value& defaultValue) const {
+ const Value* value = &((*this)[key]);
+ return value == &null ? defaultValue : *value;
+}
+
+Value Value::get(const std::string& key, const Value& defaultValue) const {
+ return get(key.c_str(), defaultValue);
+}
+
+Value Value::removeMember(const char* key) {
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+ "in Json::Value::removeMember(): requires objectValue");
+ if (type_ == nullValue)
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey(key, CZString::noDuplication);
+ ObjectValues::iterator it = value_.map_->find(actualKey);
+ if (it == value_.map_->end())
+ return null;
+ Value old(it->second);
+ value_.map_->erase(it);
+ return old;
+#else
+ Value* value = value_.map_->find(key);
+ if (value) {
+ Value old(*value);
+ value_.map_.remove(key);
+ return old;
+ } else {
+ return null;
+ }
+#endif
+}
+
+Value Value::removeMember(const std::string& key) {
+ return removeMember(key.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value Value::get(const CppTL::ConstString& key,
+ const Value& defaultValue) const {
+ return get(key.c_str(), defaultValue);
+}
+#endif
+
+bool Value::isMember(const char* key) const {
+ const Value* value = &((*this)[key]);
+ return value != &null;
+}
+
+bool Value::isMember(const std::string& key) const {
+ return isMember(key.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+bool Value::isMember(const CppTL::ConstString& key) const {
+ return isMember(key.c_str());
+}
+#endif
+
+Value::Members Value::getMemberNames() const {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == objectValue,
+ "in Json::Value::getMemberNames(), value must be objectValue");
+ if (type_ == nullValue)
+ return Value::Members();
+ Members members;
+ members.reserve(value_.map_->size());
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ObjectValues::const_iterator it = value_.map_->begin();
+ ObjectValues::const_iterator itEnd = value_.map_->end();
+ for (; it != itEnd; ++it)
+ members.push_back(std::string((*it).first.c_str()));
+#else
+ ValueInternalMap::IteratorState it;
+ ValueInternalMap::IteratorState itEnd;
+ value_.map_->makeBeginIterator(it);
+ value_.map_->makeEndIterator(itEnd);
+ for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it))
+ members.push_back(std::string(ValueInternalMap::key(it)));
+#endif
+ return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+// EnumMemberNames
+// Value::enumMemberNames() const
+//{
+// if ( type_ == objectValue )
+// {
+// return CppTL::Enum::any( CppTL::Enum::transform(
+// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+// MemberNamesTransform() ) );
+// }
+// return EnumMemberNames();
+//}
+//
+//
+// EnumValues
+// Value::enumValues() const
+//{
+// if ( type_ == objectValue || type_ == arrayValue )
+// return CppTL::Enum::anyValues( *(value_.map_),
+// CppTL::Type<const Value &>() );
+// return EnumValues();
+//}
+//
+//# endif
+
+static bool IsIntegral(double d) {
+ double integral_part;
+ return modf(d, &integral_part) == 0.0;
+}
+
+bool Value::isNull() const { return type_ == nullValue; }
+
+bool Value::isBool() const { return type_ == booleanValue; }
+
+bool Value::isInt() const {
+ switch (type_) {
+ case intValue:
+ return value_.int_ >= minInt && value_.int_ <= maxInt;
+ case uintValue:
+ return value_.uint_ <= UInt(maxInt);
+ case realValue:
+ return value_.real_ >= minInt && value_.real_ <= maxInt &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Value::isUInt() const {
+ switch (type_) {
+ case intValue:
+ return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+ case uintValue:
+ return value_.uint_ <= maxUInt;
+ case realValue:
+ return value_.real_ >= 0 && value_.real_ <= maxUInt &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Value::isInt64() const {
+#if defined(JSON_HAS_INT64)
+ switch (type_) {
+ case intValue:
+ return true;
+ case uintValue:
+ return value_.uint_ <= UInt64(maxInt64);
+ case realValue:
+ // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+ // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= double(minInt64) &&
+ value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
+ default:
+ break;
+ }
+#endif // JSON_HAS_INT64
+ return false;
+}
+
+bool Value::isUInt64() const {
+#if defined(JSON_HAS_INT64)
+ switch (type_) {
+ case intValue:
+ return value_.int_ >= 0;
+ case uintValue:
+ return true;
+ case realValue:
+ // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+ // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+#endif // JSON_HAS_INT64
+ return false;
+}
+
+bool Value::isIntegral() const {
+#if defined(JSON_HAS_INT64)
+ return isInt64() || isUInt64();
+#else
+ return isInt() || isUInt();
+#endif
+}
+
+bool Value::isDouble() const { return type_ == realValue || isIntegral(); }
+
+bool Value::isNumeric() const { return isIntegral() || isDouble(); }
+
+bool Value::isString() const { return type_ == stringValue; }
+
+bool Value::isArray() const { return type_ == arrayValue; }
+
+bool Value::isObject() const { return 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 "";
+}
+
+void Value::setOffsetStart(size_t start) { start_ = start; }
+
+void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
+
+size_t Value::getOffsetStart() const { return start_; }
+
+size_t Value::getOffsetLimit() const { return limit_; }
+
+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() : key_(), index_(), kind_(kindNone) {}
+
+PathArgument::PathArgument(ArrayIndex index)
+ : key_(), index_(index), kind_(kindIndex) {}
+
+PathArgument::PathArgument(const char* key)
+ : key_(key), index_(), kind_(kindKey) {}
+
+PathArgument::PathArgument(const std::string& key)
+ : key_(key.c_str()), index_(), kind_(kindKey) {}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path(const std::string& path,
+ const PathArgument& a1,
+ const PathArgument& a2,
+ const PathArgument& a3,
+ const PathArgument& a4,
+ const PathArgument& a5) {
+ InArgs in;
+ in.push_back(&a1);
+ in.push_back(&a2);
+ in.push_back(&a3);
+ in.push_back(&a4);
+ in.push_back(&a5);
+ makePath(path, in);
+}
+
+void Path::makePath(const std::string& path, const InArgs& in) {
+ const char* current = path.c_str();
+ const char* end = current + path.length();
+ InArgs::const_iterator itInArg = in.begin();
+ while (current != end) {
+ if (*current == '[') {
+ ++current;
+ if (*current == '%')
+ addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+ else {
+ ArrayIndex index = 0;
+ for (; current != end && *current >= '0' && *current <= '9'; ++current)
+ index = index * 10 + ArrayIndex(*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..a9f7df6
--- /dev/null
+++ b/src/lib_json/json_valueiterator.inl
@@ -0,0 +1,241 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ : current_(), isNull_(true) {
+}
+#else
+ : isArray_(true), isNull_(true) {
+ iterator_.array_ = ValueInternalArray::IteratorState();
+}
+#endif
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIteratorBase::ValueIteratorBase(
+ const Value::ObjectValues::iterator& current)
+ : current_(current), isNull_(false) {}
+#else
+ValueIteratorBase::ValueIteratorBase(
+ const ValueInternalArray::IteratorState& state)
+ : isArray_(true) {
+ iterator_.array_ = state;
+}
+
+ValueIteratorBase::ValueIteratorBase(
+ const ValueInternalMap::IteratorState& state)
+ : isArray_(false) {
+ iterator_.map_ = state;
+}
+#endif
+
+Value& ValueIteratorBase::deref() const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ return current_->second;
+#else
+ if (isArray_)
+ return ValueInternalArray::dereference(iterator_.array_);
+ return ValueInternalMap::value(iterator_.map_);
+#endif
+}
+
+void ValueIteratorBase::increment() {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ++current_;
+#else
+ if (isArray_)
+ ValueInternalArray::increment(iterator_.array_);
+ ValueInternalMap::increment(iterator_.map_);
+#endif
+}
+
+void ValueIteratorBase::decrement() {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ --current_;
+#else
+ if (isArray_)
+ ValueInternalArray::decrement(iterator_.array_);
+ ValueInternalMap::decrement(iterator_.map_);
+#endif
+}
+
+ValueIteratorBase::difference_type
+ValueIteratorBase::computeDistance(const SelfType& other) const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+#ifdef JSON_USE_CPPTL_SMALLMAP
+ return current_ - other.current_;
+#else
+ // Iterator for null value are initialized using the default
+ // constructor, which initialize current_ to the default
+ // std::map::iterator. As begin() and end() are two instance
+ // of the default std::map::iterator, they can not be compared.
+ // To allow this, we handle this comparison specifically.
+ if (isNull_ && other.isNull_) {
+ return 0;
+ }
+
+ // Usage of std::distance is not portable (does not compile with Sun Studio 12
+ // RogueWave STL,
+ // which is the one used by default).
+ // Using a portable hand-made version for non random iterator instead:
+ // return difference_type( std::distance( current_, other.current_ ) );
+ difference_type myDistance = 0;
+ for (Value::ObjectValues::iterator it = current_; it != other.current_;
+ ++it) {
+ ++myDistance;
+ }
+ return myDistance;
+#endif
+#else
+ if (isArray_)
+ return ValueInternalArray::distance(iterator_.array_,
+ other.iterator_.array_);
+ return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_);
+#endif
+}
+
+bool ValueIteratorBase::isEqual(const SelfType& other) const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ if (isNull_) {
+ return other.isNull_;
+ }
+ return current_ == other.current_;
+#else
+ if (isArray_)
+ return ValueInternalArray::equals(iterator_.array_, other.iterator_.array_);
+ return ValueInternalMap::equals(iterator_.map_, other.iterator_.map_);
+#endif
+}
+
+void ValueIteratorBase::copy(const SelfType& other) {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ current_ = other.current_;
+ isNull_ = other.isNull_;
+#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
+}
+
+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;
+}
+
+} // namespace Json
diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp
new file mode 100644
index 0000000..89964ea
--- /dev/null
+++ b/src/lib_json/json_writer.cpp
@@ -0,0 +1,690 @@
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/writer.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <iomanip>
+#include <math.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
+#include <float.h>
+#define isfinite _finite
+#define snprintf _snprintf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json {
+
+static bool containsControlCharacter(const char* str) {
+ while (*str) {
+ if (isControlCharacter(*(str++)))
+ return true;
+ }
+ return false;
+}
+
+std::string valueToString(LargestInt value) {
+ UIntToStringBuffer buffer;
+ char* current = buffer + sizeof(buffer);
+ bool isNegative = value < 0;
+ if (isNegative)
+ value = -value;
+ uintToString(LargestUInt(value), current);
+ if (isNegative)
+ *--current = '-';
+ assert(current >= buffer);
+ return current;
+}
+
+std::string valueToString(LargestUInt value) {
+ UIntToStringBuffer buffer;
+ char* current = buffer + sizeof(buffer);
+ uintToString(value, current);
+ assert(current >= buffer);
+ return current;
+}
+
+#if defined(JSON_HAS_INT64)
+
+std::string valueToString(Int value) {
+ return valueToString(LargestInt(value));
+}
+
+std::string valueToString(UInt value) {
+ return valueToString(LargestUInt(value));
+}
+
+#endif // # if defined(JSON_HAS_INT64)
+
+std::string valueToString(double value) {
+ // Allocate a buffer that is more than large enough to store the 16 digits of
+ // precision requested below.
+ char buffer[32];
+ int len = -1;
+
+// Print into the buffer. We need not request the alternative representation
+// that always has a decimal point because JSON doesn't distingish the
+// concepts of reals and integers.
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with
+ // visual studio 2005 to
+ // avoid warning.
+#if defined(WINCE)
+ len = _snprintf(buffer, sizeof(buffer), "%.16g", value);
+#else
+ len = sprintf_s(buffer, sizeof(buffer), "%.16g", value);
+#endif
+#else
+ if (isfinite(value)) {
+ len = snprintf(buffer, sizeof(buffer), "%.16g", value);
+ } else {
+ // IEEE standard states that NaN values will not compare to themselves
+ if (value != value) {
+ len = snprintf(buffer, sizeof(buffer), "null");
+ } else if (value < 0) {
+ len = snprintf(buffer, sizeof(buffer), "-1e+9999");
+ } else {
+ len = snprintf(buffer, sizeof(buffer), "1e+9999");
+ }
+ // For those, we do not need to call fixNumLoc, but it is fast.
+ }
+#endif
+ assert(len >= 0);
+ fixNumericLocale(buffer, buffer + len);
+ return buffer;
+}
+
+std::string valueToString(bool value) { return value ? "true" : "false"; }
+
+std::string valueToQuotedString(const char* value) {
+ if (value == NULL)
+ return "";
+ // Not sure how to handle unicode...
+ if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
+ !containsControlCharacter(value))
+ return std::string("\"") + value + "\"";
+ // We have to walk value and escape any special characters.
+ // Appending to std::string is not efficient, but this should be rare.
+ // (Note: forward slashes are *not* rare, but I am not escaping them.)
+ std::string::size_type maxsize =
+ strlen(value) * 2 + 3; // allescaped+quotes+NULL
+ std::string result;
+ result.reserve(maxsize); // to avoid lots of mallocs
+ result += "\"";
+ for (const char* c = value; *c != 0; ++c) {
+ switch (*c) {
+ case '\"':
+ result += "\\\"";
+ break;
+ case '\\':
+ result += "\\\\";
+ break;
+ case '\b':
+ result += "\\b";
+ break;
+ case '\f':
+ result += "\\f";
+ break;
+ case '\n':
+ result += "\\n";
+ break;
+ case '\r':
+ result += "\\r";
+ break;
+ case '\t':
+ result += "\\t";
+ break;
+ // case '/':
+ // Even though \/ is considered a legal escape in JSON, a bare
+ // slash is also legal, so I see no reason to escape it.
+ // (I hope I am not misunderstanding something.
+ // blep notes: actually escaping \/ may be useful in javascript to avoid </
+ // sequence.
+ // Should add a flag to allow this compatibility mode and prevent this
+ // sequence from occurring.
+ default:
+ if (isControlCharacter(*c)) {
+ std::ostringstream oss;
+ oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+ << std::setw(4) << static_cast<int>(*c);
+ result += oss.str();
+ } else {
+ result += *c;
+ }
+ break;
+ }
+ }
+ result += "\"";
+ return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer() {}
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+ : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
+ omitEndingLineFeed_(false) {}
+
+void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
+
+void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
+
+void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
+
+std::string FastWriter::write(const Value& root) {
+ document_ = "";
+ writeValue(root);
+ if (!omitEndingLineFeed_)
+ document_ += "\n";
+ return document_;
+}
+
+void FastWriter::writeValue(const Value& value) {
+ switch (value.type()) {
+ case nullValue:
+ if (!dropNullPlaceholders_)
+ document_ += "null";
+ break;
+ case intValue:
+ document_ += valueToString(value.asLargestInt());
+ break;
+ case uintValue:
+ document_ += valueToString(value.asLargestUInt());
+ break;
+ case realValue:
+ document_ += valueToString(value.asDouble());
+ break;
+ case stringValue:
+ document_ += valueToQuotedString(value.asCString());
+ break;
+ case booleanValue:
+ document_ += valueToString(value.asBool());
+ break;
+ case arrayValue: {
+ document_ += '[';
+ int size = value.size();
+ for (int index = 0; index < size; ++index) {
+ if (index > 0)
+ document_ += ',';
+ writeValue(value[index]);
+ }
+ document_ += ']';
+ } break;
+ case objectValue: {
+ Value::Members members(value.getMemberNames());
+ document_ += '{';
+ for (Value::Members::iterator it = members.begin(); it != members.end();
+ ++it) {
+ const std::string& name = *it;
+ if (it != members.begin())
+ document_ += ',';
+ document_ += valueToQuotedString(name.c_str());
+ document_ += yamlCompatiblityEnabled_ ? ": " : ":";
+ writeValue(value[name]);
+ }
+ document_ += '}';
+ } break;
+ }
+}
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+ : rightMargin_(74), indentSize_(3), addChildValues_() {}
+
+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.asLargestInt()));
+ break;
+ case uintValue:
+ pushValue(valueToString(value.asLargestUInt()));
+ 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();
+ for (;;) {
+ const std::string& name = *it;
+ const Value& childValue = value[name];
+ writeCommentBeforeValue(childValue);
+ writeWithIndent(valueToQuotedString(name.c_str()));
+ document_ += " : ";
+ writeValue(childValue);
+ if (++it == members.end()) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ document_ += ',';
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("}");
+ }
+ } break;
+ }
+}
+
+void StyledWriter::writeArrayValue(const Value& value) {
+ unsigned size = value.size();
+ if (size == 0)
+ pushValue("[]");
+ else {
+ bool isArrayMultiLine = isMultineArray(value);
+ if (isArrayMultiLine) {
+ writeWithIndent("[");
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index = 0;
+ for (;;) {
+ const Value& childValue = value[index];
+ writeCommentBeforeValue(childValue);
+ if (hasChildValue)
+ writeWithIndent(childValues_[index]);
+ else {
+ writeIndent();
+ writeValue(childValue);
+ }
+ if (++index == size) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ document_ += ',';
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("]");
+ } else // output on a single line
+ {
+ assert(childValues_.size() == size);
+ document_ += "[ ";
+ for (unsigned index = 0; index < size; ++index) {
+ if (index > 0)
+ document_ += ", ";
+ document_ += childValues_[index];
+ }
+ document_ += " ]";
+ }
+ }
+}
+
+bool StyledWriter::isMultineArray(const Value& value) {
+ int size = value.size();
+ bool isMultiLine = size * 3 >= rightMargin_;
+ childValues_.clear();
+ for (int index = 0; index < size && !isMultiLine; ++index) {
+ const Value& childValue = value[index];
+ isMultiLine =
+ isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
+ childValue.size() > 0);
+ }
+ if (!isMultiLine) // check if line length > max line length
+ {
+ childValues_.reserve(size);
+ addChildValues_ = true;
+ int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+ for (int index = 0; index < size; ++index) {
+ writeValue(value[index]);
+ lineLength += int(childValues_[index].length());
+ }
+ 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_ += "\n";
+ writeIndent();
+ std::string normalizedComment = normalizeEOL(root.getComment(commentBefore));
+ std::string::const_iterator iter = normalizedComment.begin();
+ while (iter != normalizedComment.end()) {
+ document_ += *iter;
+ if (*iter == '\n' && *(iter + 1) == '/')
+ writeIndent();
+ ++iter;
+ }
+
+ // Comments are stripped of newlines, so add one here
+ document_ += "\n";
+}
+
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+ if (root.hasComment(commentAfterOnSameLine))
+ document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
+
+ if (root.hasComment(commentAfter)) {
+ document_ += "\n";
+ document_ += normalizeEOL(root.getComment(commentAfter));
+ document_ += "\n";
+ }
+}
+
+bool StyledWriter::hasCommentForValue(const Value& value) {
+ return value.hasComment(commentBefore) ||
+ value.hasComment(commentAfterOnSameLine) ||
+ value.hasComment(commentAfter);
+}
+
+std::string StyledWriter::normalizeEOL(const std::string& text) {
+ std::string normalized;
+ normalized.reserve(text.length());
+ const char* begin = text.c_str();
+ const char* end = begin + text.length();
+ const char* current = begin;
+ while (current != end) {
+ char c = *current++;
+ if (c == '\r') // mac or dos EOL
+ {
+ if (*current == '\n') // convert dos EOL
+ ++current;
+ normalized += '\n';
+ } else // handle unix EOL & other char
+ normalized += c;
+ }
+ return normalized;
+}
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter(std::string indentation)
+ : document_(NULL), rightMargin_(74), indentation_(indentation),
+ addChildValues_() {}
+
+void StyledStreamWriter::write(std::ostream& out, const Value& root) {
+ document_ = &out;
+ addChildValues_ = false;
+ indentString_ = "";
+ writeCommentBeforeValue(root);
+ writeValue(root);
+ writeCommentAfterValueOnSameLine(root);
+ *document_ << "\n";
+ document_ = NULL; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value& value) {
+ switch (value.type()) {
+ case nullValue:
+ pushValue("null");
+ break;
+ case intValue:
+ pushValue(valueToString(value.asLargestInt()));
+ break;
+ case uintValue:
+ pushValue(valueToString(value.asLargestUInt()));
+ 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();
+ for (;;) {
+ const std::string& name = *it;
+ const Value& childValue = value[name];
+ writeCommentBeforeValue(childValue);
+ writeWithIndent(valueToQuotedString(name.c_str()));
+ *document_ << " : ";
+ writeValue(childValue);
+ if (++it == members.end()) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("}");
+ }
+ } break;
+ }
+}
+
+void StyledStreamWriter::writeArrayValue(const Value& value) {
+ unsigned size = value.size();
+ if (size == 0)
+ pushValue("[]");
+ else {
+ bool isArrayMultiLine = isMultineArray(value);
+ if (isArrayMultiLine) {
+ writeWithIndent("[");
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index = 0;
+ for (;;) {
+ const Value& childValue = value[index];
+ writeCommentBeforeValue(childValue);
+ if (hasChildValue)
+ writeWithIndent(childValues_[index]);
+ else {
+ writeIndent();
+ writeValue(childValue);
+ }
+ if (++index == size) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("]");
+ } else // output on a single line
+ {
+ assert(childValues_.size() == size);
+ *document_ << "[ ";
+ for (unsigned index = 0; index < size; ++index) {
+ if (index > 0)
+ *document_ << ", ";
+ *document_ << childValues_[index];
+ }
+ *document_ << " ]";
+ }
+ }
+}
+
+bool StyledStreamWriter::isMultineArray(const Value& value) {
+ int size = value.size();
+ bool isMultiLine = size * 3 >= rightMargin_;
+ childValues_.clear();
+ for (int index = 0; index < size && !isMultiLine; ++index) {
+ const Value& childValue = value[index];
+ isMultiLine =
+ isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
+ childValue.size() > 0);
+ }
+ if (!isMultiLine) // check if line length > max line length
+ {
+ childValues_.reserve(size);
+ addChildValues_ = true;
+ int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+ for (int index = 0; index < size; ++index) {
+ writeValue(value[index]);
+ lineLength += int(childValues_[index].length());
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+void StyledStreamWriter::pushValue(const std::string& value) {
+ if (addChildValues_)
+ childValues_.push_back(value);
+ else
+ *document_ << value;
+}
+
+void StyledStreamWriter::writeIndent() {
+ /*
+ Some comments in this method would have been nice. ;-)
+
+ if ( !document_.empty() )
+ {
+ char last = document_[document_.length()-1];
+ if ( last == ' ' ) // already indented
+ return;
+ if ( last != '\n' ) // Comments may add new-line
+ *document_ << '\n';
+ }
+ */
+ *document_ << '\n' << indentString_;
+}
+
+void StyledStreamWriter::writeWithIndent(const std::string& value) {
+ writeIndent();
+ *document_ << value;
+}
+
+void StyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void StyledStreamWriter::unindent() {
+ assert(indentString_.size() >= indentation_.size());
+ indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
+ if (!root.hasComment(commentBefore))
+ return;
+ *document_ << normalizeEOL(root.getComment(commentBefore));
+ *document_ << "\n";
+}
+
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+ if (root.hasComment(commentAfterOnSameLine))
+ *document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
+
+ if (root.hasComment(commentAfter)) {
+ *document_ << "\n";
+ *document_ << normalizeEOL(root.getComment(commentAfter));
+ *document_ << "\n";
+ }
+}
+
+bool StyledStreamWriter::hasCommentForValue(const Value& value) {
+ return value.hasComment(commentBefore) ||
+ value.hasComment(commentAfterOnSameLine) ||
+ value.hasComment(commentAfter);
+}
+
+std::string StyledStreamWriter::normalizeEOL(const std::string& text) {
+ std::string normalized;
+ normalized.reserve(text.length());
+ const char* begin = text.c_str();
+ const char* end = begin + text.length();
+ const char* current = begin;
+ while (current != end) {
+ char c = *current++;
+ if (c == '\r') // mac or dos EOL
+ {
+ if (*current == '\n') // convert dos EOL
+ ++current;
+ normalized += '\n';
+ } else // handle unix EOL & other char
+ normalized += c;
+ }
+ return normalized;
+}
+
+std::ostream& operator<<(std::ostream& sout, const Value& root) {
+ Json::StyledStreamWriter writer;
+ writer.write(sout, root);
+ return sout;
+}
+
+} // namespace Json
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=32fd56b066c28758e31ae97d4b16216b3633a843
commit 32fd56b066c28758e31ae97d4b16216b3633a843
Author: Brad King <brad.king at kitware.com>
AuthorDate: Tue Jan 13 10:36:19 2015 -0500
Commit: Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 13 10:36:19 2015 -0500
jsoncpp: Add .gitattributes to skip whitespace checks
diff --git a/Utilities/cmjsoncpp/.gitattributes b/Utilities/cmjsoncpp/.gitattributes
new file mode 100644
index 0000000..562b12e
--- /dev/null
+++ b/Utilities/cmjsoncpp/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
-----------------------------------------------------------------------
Summary of changes:
hooks/post-receive
--
CMake
More information about the Cmake-commits
mailing list