Merge pull request #180 from pah/cleanup/doxygen-thirdparty
Drop thirdparty libraries and minor cleanups
This commit is contained in:
commit
dea1cdca62
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,5 +6,6 @@
|
||||
/build/gmake
|
||||
/build/vs*/
|
||||
/doc/html
|
||||
/doc/doxygen_*.db
|
||||
/thirdparty/lib
|
||||
/intermediate
|
||||
|
@ -114,7 +114,6 @@ solution "test"
|
||||
files {
|
||||
"../include/**.h",
|
||||
"../test/perftest/**.cpp",
|
||||
"../test/perftest/**.c",
|
||||
"../test/perftest/**.h",
|
||||
}
|
||||
|
||||
@ -122,9 +121,6 @@ solution "test"
|
||||
"../include/",
|
||||
"../thirdparty/gtest/include/",
|
||||
"../thirdparty/",
|
||||
"../thirdparty/jsoncpp/include/",
|
||||
"../thirdparty/libjson/",
|
||||
"../thirdparty/yajl/include/",
|
||||
}
|
||||
|
||||
libdirs "../thirdparty/lib"
|
||||
|
1
doc/diagram/.gitignore
vendored
1
doc/diagram/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.pdf
|
@ -2,9 +2,15 @@
|
||||
|
||||
The old performance article for RapidJSON 0.1 is provided [here](https://code.google.com/p/rapidjson/wiki/Performance).
|
||||
|
||||
This file will be updated with new version and better procedures.
|
||||
The (third-party) performance tests have been removed from this repository
|
||||
and are now part of a dedicated [native JSON benchmark collection] [1].
|
||||
|
||||
In the meantime, you may also refer to the following third-party benchmarks.
|
||||
This file will be updated with a summary of benchmarking results based on
|
||||
the above benchmark collection in the future.
|
||||
|
||||
[1]: https://github.com/miloyip/nativejson-benchmark
|
||||
|
||||
Additionally, you may refer to the following third-party benchmarks.
|
||||
|
||||
## Third-party benchmarks
|
||||
|
||||
|
@ -1,77 +0,0 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_JSONCPP
|
||||
|
||||
#include "jsoncpp/src/lib_json/json_reader.cpp"
|
||||
#include "jsoncpp/src/lib_json/json_value.cpp"
|
||||
#include "jsoncpp/src/lib_json/json_writer.cpp"
|
||||
|
||||
using namespace Json;
|
||||
|
||||
class JsonCpp : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
Reader reader;
|
||||
ASSERT_TRUE(reader.parse(json_, root_));
|
||||
}
|
||||
|
||||
protected:
|
||||
Value root_;
|
||||
};
|
||||
|
||||
TEST_F(JsonCpp, ReaderParse) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
Value root;
|
||||
Reader reader;
|
||||
ASSERT_TRUE(reader.parse(json_, root));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JsonCpp, FastWriter) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
FastWriter writer;
|
||||
std::string str = writer.write(root_);
|
||||
//if (i == 0)
|
||||
// std::cout << str.length() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JsonCpp, StyledWriter) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
StyledWriter writer;
|
||||
std::string str = writer.write(root_);
|
||||
//if (i == 0)
|
||||
// std::cout << str.length() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JsonCpp, Whitespace) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
Value root;
|
||||
Reader reader;
|
||||
ASSERT_TRUE(reader.parse(whitespace_, root));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_JSONCPP
|
@ -22,9 +22,6 @@
|
||||
#define PERFTEST_H_
|
||||
|
||||
#define TEST_RAPIDJSON 1
|
||||
#define TEST_JSONCPP 0
|
||||
#define TEST_YAJL 0
|
||||
#define TEST_ULTRAJSON 0
|
||||
#define TEST_PLATFORM 0
|
||||
#define TEST_MISC 0
|
||||
|
||||
@ -39,12 +36,6 @@
|
||||
# define RAPIDJSON_SSE2
|
||||
#endif
|
||||
|
||||
#if TEST_YAJL
|
||||
#include "yajl/yajl_common.h"
|
||||
#undef YAJL_MAX_DEPTH
|
||||
#define YAJL_MAX_DEPTH 1024
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Google Test
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_ULTRAJSON
|
||||
|
||||
#include "ultrajson/ultrajsondec.c"
|
||||
#include "ultrajson/ultrajsonenc.c"
|
||||
|
||||
class UltraJson : public PerfTest {
|
||||
};
|
||||
|
||||
static char dummy = 0;
|
||||
|
||||
static void Object_objectAddKey(JSOBJ obj, JSOBJ name, JSOBJ value) {}
|
||||
static void Object_arrayAddItem(JSOBJ obj, JSOBJ value) {}
|
||||
|
||||
static JSOBJ Object_newString(wchar_t *start, wchar_t *end) { return &dummy; }
|
||||
static JSOBJ Object_newTrue(void) { return &dummy; }
|
||||
static JSOBJ Object_newFalse(void) { return &dummy; }
|
||||
static JSOBJ Object_newNull(void) { return &dummy; }
|
||||
static JSOBJ Object_newObject(void) { return &dummy; }
|
||||
static JSOBJ Object_newArray(void) { return &dummy; }
|
||||
static JSOBJ Object_newInteger(JSINT32 value) { return &dummy; }
|
||||
static JSOBJ Object_newLong(JSINT64 value) { return &dummy; }
|
||||
static JSOBJ Object_newDouble(double value) { return &dummy; }
|
||||
|
||||
static void Object_releaseObject(JSOBJ obj) {}
|
||||
|
||||
static JSONObjectDecoder decoder = {
|
||||
Object_newString,
|
||||
Object_objectAddKey,
|
||||
Object_arrayAddItem,
|
||||
Object_newTrue,
|
||||
Object_newFalse,
|
||||
Object_newNull,
|
||||
Object_newObject,
|
||||
Object_newArray,
|
||||
Object_newInteger,
|
||||
Object_newLong,
|
||||
Object_newDouble,
|
||||
Object_releaseObject,
|
||||
malloc,
|
||||
free,
|
||||
realloc
|
||||
};
|
||||
|
||||
TEST_F(UltraJson, Decode) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
decoder.errorStr = NULL;
|
||||
decoder.errorOffset = NULL;
|
||||
void *ret = JSON_DecodeObject(&decoder, json_, length_);
|
||||
ASSERT_TRUE(ret != 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(UltraJson, Whitespace) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
decoder.errorStr = NULL;
|
||||
decoder.errorOffset = NULL;
|
||||
void *ret = JSON_DecodeObject(&decoder, whitespace_, whitespace_length_);
|
||||
ASSERT_TRUE(ret != 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_ULTRAJSON
|
@ -1,22 +0,0 @@
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_YAJL
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <float.h>
|
||||
#define isinf !_finite
|
||||
#define isnan _isnan
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include "yajl/src/yajl.c"
|
||||
#include "yajl/src/yajl_alloc.c"
|
||||
#include "yajl/src/yajl_buf.c"
|
||||
#include "yajl/src/yajl_encode.c"
|
||||
#include "yajl/src/yajl_gen.c"
|
||||
#include "yajl/src/yajl_lex.c"
|
||||
#include "yajl/src/yajl_parser.c"
|
||||
#include "yajl/src/yajl_tree.c"
|
||||
#include "yajl/src/yajl_version.c"
|
||||
|
||||
#endif // TEST_YAJL
|
@ -1,208 +0,0 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_YAJL
|
||||
|
||||
extern "C" {
|
||||
#include "yajl/yajl_gen.h"
|
||||
#include "yajl/yajl_parse.h"
|
||||
#include "yajl/yajl_tree.h"
|
||||
};
|
||||
|
||||
class Yajl : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
root_ = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root_ != NULL);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
yajl_tree_free(root_);
|
||||
}
|
||||
|
||||
protected:
|
||||
yajl_val root_;
|
||||
};
|
||||
|
||||
static int null_null(void *) { return 1; }
|
||||
static int null_boolean(void *, int) { return 1; }
|
||||
static int null_integer(void *, long long) { return 1; }
|
||||
static int null_double(void *, double) { return 1; }
|
||||
static int null_string(void *, const unsigned char*, size_t) { return 1; }
|
||||
static int null_start_map(void *) { return 1; }
|
||||
static int null_map_key(void *, const unsigned char*, size_t) { return 1; }
|
||||
static int null_end_map(void *) { return 1; }
|
||||
static int null_start_array(void*) { return 1; }
|
||||
static int null_end_array(void *) { return 1; }
|
||||
|
||||
static yajl_callbacks nullcallbacks = {
|
||||
null_null,
|
||||
null_boolean,
|
||||
null_integer,
|
||||
null_double,
|
||||
NULL, // yajl_number(). Here we want to test full-parsing performance.
|
||||
null_string,
|
||||
null_start_map,
|
||||
null_map_key,
|
||||
null_end_map,
|
||||
null_start_array,
|
||||
null_end_array
|
||||
};
|
||||
|
||||
TEST_F(Yajl, yajl_parse_nullcallbacks) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_handle hand = yajl_alloc(&nullcallbacks, NULL, NULL);
|
||||
yajl_status stat = yajl_parse(hand, (unsigned char*)json_, length_);
|
||||
//ASSERT_EQ(yajl_status_ok, stat);
|
||||
if (stat != yajl_status_ok) {
|
||||
unsigned char * str = yajl_get_error(hand, 1, (unsigned char*)json_, length_);
|
||||
fprintf(stderr, "%s", (const char *) str);
|
||||
}
|
||||
stat = yajl_complete_parse(hand);
|
||||
ASSERT_EQ(yajl_status_ok, stat);
|
||||
yajl_free(hand);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_tree_parse) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
}
|
||||
|
||||
yajl_gen_status GenVal(yajl_gen g, yajl_val v) {
|
||||
yajl_gen_status status;
|
||||
switch (v->type) {
|
||||
case yajl_t_string: return yajl_gen_string(g, (unsigned char*)v->u.string, strlen(v->u.string));
|
||||
|
||||
case yajl_t_number:
|
||||
{
|
||||
char buffer[100];
|
||||
char *num = buffer;
|
||||
size_t len;
|
||||
//if (YAJL_IS_INTEGER(v)) // buggy
|
||||
if (v->u.number.flags & YAJL_NUMBER_INT_VALID)
|
||||
#if _MSC_VER
|
||||
len = sprintf(num, "%I64d", YAJL_GET_INTEGER(v));
|
||||
#else
|
||||
len = sprintf(num, "%lld", YAJL_GET_INTEGER(v));
|
||||
#endif
|
||||
//else if (YAJL_IS_DOUBLE(v)) // buggy
|
||||
else if (v->u.number.flags & YAJL_NUMBER_DOUBLE_VALID)
|
||||
len = sprintf(num, "%g", YAJL_GET_DOUBLE(v));
|
||||
else {
|
||||
num = YAJL_GET_NUMBER(v);
|
||||
len = strlen(buffer);
|
||||
}
|
||||
return yajl_gen_number(g, num, len);
|
||||
}
|
||||
|
||||
case yajl_t_object:
|
||||
status = yajl_gen_map_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.object.len; i++) {
|
||||
status = yajl_gen_string(g, (unsigned char *)v->u.object.keys[i], strlen(v->u.object.keys[i]));
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
status = GenVal(g, v->u.object.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
return yajl_gen_map_close(g);
|
||||
|
||||
case yajl_t_array:
|
||||
status = yajl_gen_array_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.array.len; i++) {
|
||||
status = GenVal(g, v->u.array.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
|
||||
return yajl_gen_array_close(g);
|
||||
|
||||
case yajl_t_true: return yajl_gen_bool(g, 1);
|
||||
case yajl_t_false: return yajl_gen_bool(g, 0);
|
||||
case yajl_t_null: return yajl_gen_null(g);
|
||||
}
|
||||
return yajl_gen_in_error_state;
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_gen) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_gen_beautify) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
yajl_gen_config(g, yajl_gen_beautify, 1);
|
||||
yajl_gen_config(g, yajl_gen_indent_string, " ");
|
||||
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, Whitespace) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(whitespace_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_YAJL
|
1
thirdparty/jsoncpp/AUTHORS
vendored
1
thirdparty/jsoncpp/AUTHORS
vendored
@ -1 +0,0 @@
|
||||
Baptiste Lepilleur <blep@users.sourceforge.net>
|
1
thirdparty/jsoncpp/LICENSE
vendored
1
thirdparty/jsoncpp/LICENSE
vendored
@ -1 +0,0 @@
|
||||
The json-cpp library and this documentation are in Public Domain.
|
117
thirdparty/jsoncpp/README.txt
vendored
117
thirdparty/jsoncpp/README.txt
vendored
@ -1,117 +0,0 @@
|
||||
* Introduction:
|
||||
=============
|
||||
|
||||
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
|
||||
It can represent integer, real number, string, an ordered sequence of
|
||||
value, and a collection of name/value pairs.
|
||||
|
||||
JsonCpp is a simple API to manipulate JSON value, handle serialization
|
||||
and unserialization to string.
|
||||
|
||||
It can also preserve existing comment in unserialization/serialization steps,
|
||||
making it a convenient format to store user input files.
|
||||
|
||||
Unserialization parsing is user friendly and provides precise error reports.
|
||||
|
||||
|
||||
* Building/Testing:
|
||||
=================
|
||||
|
||||
JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires
|
||||
python to be installed (http://www.python.org).
|
||||
|
||||
You download scons-local distribution from the following url:
|
||||
http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375
|
||||
|
||||
Unzip it in the directory where you found this README file. scons.py Should be
|
||||
at the same level as README.
|
||||
|
||||
python scons.py platform=PLTFRM [TARGET]
|
||||
where PLTFRM may be one of:
|
||||
suncc Sun C++ (Solaris)
|
||||
vacpp Visual Age C++ (AIX)
|
||||
mingw
|
||||
msvc6 Microsoft Visual Studio 6 service pack 5-6
|
||||
msvc70 Microsoft Visual Studio 2002
|
||||
msvc71 Microsoft Visual Studio 2003
|
||||
msvc80 Microsoft Visual Studio 2005
|
||||
linux-gcc Gnu C++ (linux, also reported to work for Mac OS X)
|
||||
|
||||
adding platform is fairly simple. You need to change the Sconstruct file
|
||||
to do so.
|
||||
|
||||
and TARGET may be:
|
||||
check: build library and run unit tests.
|
||||
|
||||
|
||||
* Running the test manually:
|
||||
==========================
|
||||
|
||||
cd test
|
||||
# This will run the Reader/Writer tests
|
||||
python runjsontests.py "path to jsontest.exe"
|
||||
|
||||
# This will run the Reader/Writer tests, using JSONChecker test suite
|
||||
# (http://www.json.org/JSON_checker/).
|
||||
# Notes: not all tests pass: JsonCpp is too lenient (for example,
|
||||
# it allows an integer to start with '0'). The goal is to improve
|
||||
# strict mode parsing to get all tests to pass.
|
||||
python runjsontests.py --with-json-checker "path to jsontest.exe"
|
||||
|
||||
# This will run the unit tests (mostly Value)
|
||||
python rununittests.py "path to test_lib_json.exe"
|
||||
|
||||
You can run the tests using valgrind:
|
||||
python rununittests.py --valgrind "path to test_lib_json.exe"
|
||||
|
||||
|
||||
* Building the documentation:
|
||||
===========================
|
||||
|
||||
Run the python script doxybuild.py from the top directory:
|
||||
|
||||
python doxybuild.py --open --with-dot
|
||||
|
||||
See doxybuild.py --help for options.
|
||||
|
||||
|
||||
* Adding a reader/writer test:
|
||||
============================
|
||||
|
||||
To add a test, you need to create two files in test/data:
|
||||
- a TESTNAME.json file, that contains the input document in JSON format.
|
||||
- a TESTNAME.expected file, that contains a flatened representation of
|
||||
the input document.
|
||||
|
||||
TESTNAME.expected file format:
|
||||
- each line represents a JSON element of the element tree represented
|
||||
by the input document.
|
||||
- each line has two parts: the path to access the element separated from
|
||||
the element value by '='. Array and object values are always empty
|
||||
(e.g. represented by either [] or {}).
|
||||
- element path: '.' represented the root element, and is used to separate
|
||||
object members. [N] is used to specify the value of an array element
|
||||
at index N.
|
||||
See test_complex_01.json and test_complex_01.expected to better understand
|
||||
element path.
|
||||
|
||||
|
||||
* Understanding reader/writer test output:
|
||||
========================================
|
||||
|
||||
When a test is run, output files are generated aside the input test files.
|
||||
Below is a short description of the content of each file:
|
||||
|
||||
- test_complex_01.json: input JSON document
|
||||
- test_complex_01.expected: flattened JSON element tree used to check if
|
||||
parsing was corrected.
|
||||
|
||||
- test_complex_01.actual: flattened JSON element tree produced by
|
||||
jsontest.exe from reading test_complex_01.json
|
||||
- test_complex_01.rewrite: JSON document written by jsontest.exe using the
|
||||
Json::Value parsed from test_complex_01.json and serialized using
|
||||
Json::StyledWritter.
|
||||
- test_complex_01.actual-rewrite: flattened JSON element tree produced by
|
||||
jsontest.exe from reading test_complex_01.rewrite.
|
||||
test_complex_01.process-output: jsontest.exe output, typically useful to
|
||||
understand parsing error.
|
19
thirdparty/jsoncpp/include/json/autolink.h
vendored
19
thirdparty/jsoncpp/include/json/autolink.h
vendored
@ -1,19 +0,0 @@
|
||||
#ifndef JSON_AUTOLINK_H_INCLUDED
|
||||
# define JSON_AUTOLINK_H_INCLUDED
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# include <cpptl/cpptl_autolink.h>
|
||||
# endif
|
||||
|
||||
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
|
||||
# define CPPTL_AUTOLINK_NAME "json"
|
||||
# undef CPPTL_AUTOLINK_DLL
|
||||
# ifdef JSON_DLL
|
||||
# define CPPTL_AUTOLINK_DLL
|
||||
# endif
|
||||
# include "autolink.h"
|
||||
# endif
|
||||
|
||||
#endif // JSON_AUTOLINK_H_INCLUDED
|
43
thirdparty/jsoncpp/include/json/config.h
vendored
43
thirdparty/jsoncpp/include/json/config.h
vendored
@ -1,43 +0,0 @@
|
||||
#ifndef JSON_CONFIG_H_INCLUDED
|
||||
# define JSON_CONFIG_H_INCLUDED
|
||||
|
||||
/// If defined, indicates that json library is embedded in CppTL library.
|
||||
//# define JSON_IN_CPPTL 1
|
||||
|
||||
/// If defined, indicates that json may leverage CppTL library
|
||||
//# define JSON_USE_CPPTL 1
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of std::map
|
||||
/// as Value container.
|
||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||
/// If defined, indicates that Json specific container should be used
|
||||
/// (hash table & simple deque container with customizable allocator).
|
||||
/// THIS FEATURE IS STILL EXPERIMENTAL!
|
||||
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
||||
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
|
||||
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
|
||||
/// as if it was a POD) that may cause some validation tool to report errors.
|
||||
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
||||
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
||||
|
||||
/// If defined, indicates that Json use exception to report invalid type manipulation
|
||||
/// instead of C assert macro.
|
||||
# define JSON_USE_EXCEPTION 1
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# include <cpptl/config.h>
|
||||
# ifndef JSON_USE_CPPTL
|
||||
# define JSON_USE_CPPTL 1
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# define JSON_API CPPTL_API
|
||||
# elif defined(JSON_DLL_BUILD)
|
||||
# define JSON_API __declspec(dllexport)
|
||||
# elif defined(JSON_DLL)
|
||||
# define JSON_API __declspec(dllimport)
|
||||
# else
|
||||
# define JSON_API
|
||||
# endif
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
42
thirdparty/jsoncpp/include/json/features.h
vendored
42
thirdparty/jsoncpp/include/json/features.h
vendored
@ -1,42 +0,0 @@
|
||||
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
||||
# define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||
|
||||
# include "forwards.h"
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Configuration passed to reader and writer.
|
||||
* This configuration object can be used to force the Reader or Writer
|
||||
* to behave in a standard conforming way.
|
||||
*/
|
||||
class JSON_API Features
|
||||
{
|
||||
public:
|
||||
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
||||
* - C & C++ comments are allowed
|
||||
* - Root object can be any JSON value
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features all();
|
||||
|
||||
/** \brief A configuration that is strictly compatible with the JSON specification.
|
||||
* - Comments are forbidden.
|
||||
* - Root object must be either an array or an object value.
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features strictMode();
|
||||
|
||||
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||
*/
|
||||
Features();
|
||||
|
||||
/// \c true if comments are allowed. Default: \c true.
|
||||
bool allowComments_;
|
||||
|
||||
/// \c true if root must be either an array or an object value. Default: \c false.
|
||||
bool strictRoot_;
|
||||
};
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
|
39
thirdparty/jsoncpp/include/json/forwards.h
vendored
39
thirdparty/jsoncpp/include/json/forwards.h
vendored
@ -1,39 +0,0 @@
|
||||
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||
# define JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
# include "config.h"
|
||||
|
||||
namespace Json {
|
||||
|
||||
// writer.h
|
||||
class FastWriter;
|
||||
class StyledWriter;
|
||||
|
||||
// reader.h
|
||||
class Reader;
|
||||
|
||||
// features.h
|
||||
class Features;
|
||||
|
||||
// value.h
|
||||
typedef int Int;
|
||||
typedef unsigned int UInt;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
class Value;
|
||||
class ValueIteratorBase;
|
||||
class ValueIterator;
|
||||
class ValueConstIterator;
|
||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
class ValueAllocator;
|
||||
class ValueMapAllocator;
|
||||
class ValueInternalLink;
|
||||
class ValueInternalArray;
|
||||
class ValueInternalMap;
|
||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
#endif // JSON_FORWARDS_H_INCLUDED
|
10
thirdparty/jsoncpp/include/json/json.h
vendored
10
thirdparty/jsoncpp/include/json/json.h
vendored
@ -1,10 +0,0 @@
|
||||
#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
|
196
thirdparty/jsoncpp/include/json/reader.h
vendored
196
thirdparty/jsoncpp/include/json/reader.h
vendored
@ -1,196 +0,0 @@
|
||||
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
||||
# define CPPTL_JSON_READER_H_INCLUDED
|
||||
|
||||
# include "features.h"
|
||||
# include "value.h"
|
||||
# include <deque>
|
||||
# include <stack>
|
||||
# include <string>
|
||||
# include <iostream>
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||
*
|
||||
*/
|
||||
class JSON_API Reader
|
||||
{
|
||||
public:
|
||||
typedef char Char;
|
||||
typedef const Char *Location;
|
||||
|
||||
/** \brief Constructs a Reader allowing all features
|
||||
* for parsing.
|
||||
*/
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set
|
||||
* for parsing.
|
||||
*/
|
||||
Reader( const Features &features );
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
* \param document UTF-8 encoded string containing the document to read.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
*/
|
||||
bool parse( const std::string &document,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
* \param document UTF-8 encoded string containing the document to read.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
*/
|
||||
bool parse( const char *beginDoc, const char *endDoc,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/// \brief Parse from input stream.
|
||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||
bool parse( std::istream &is,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||
* \return Formatted error message with the list of errors with their location in
|
||||
* the parsed document. An empty string is returned if no error occurred
|
||||
* during parsing.
|
||||
*/
|
||||
std::string getFormatedErrorMessages() const;
|
||||
|
||||
private:
|
||||
enum TokenType
|
||||
{
|
||||
tokenEndOfStream = 0,
|
||||
tokenObjectBegin,
|
||||
tokenObjectEnd,
|
||||
tokenArrayBegin,
|
||||
tokenArrayEnd,
|
||||
tokenString,
|
||||
tokenNumber,
|
||||
tokenTrue,
|
||||
tokenFalse,
|
||||
tokenNull,
|
||||
tokenArraySeparator,
|
||||
tokenMemberSeparator,
|
||||
tokenComment,
|
||||
tokenError
|
||||
};
|
||||
|
||||
class Token
|
||||
{
|
||||
public:
|
||||
TokenType type_;
|
||||
Location start_;
|
||||
Location end_;
|
||||
};
|
||||
|
||||
class ErrorInfo
|
||||
{
|
||||
public:
|
||||
Token token_;
|
||||
std::string message_;
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
typedef std::deque<ErrorInfo> Errors;
|
||||
|
||||
bool expectToken( TokenType type, Token &token, const char *message );
|
||||
bool readToken( Token &token );
|
||||
void skipSpaces();
|
||||
bool match( Location pattern,
|
||||
int patternLength );
|
||||
bool readComment();
|
||||
bool readCStyleComment();
|
||||
bool readCppStyleComment();
|
||||
bool readString();
|
||||
void readNumber();
|
||||
bool readValue();
|
||||
bool readObject( Token &token );
|
||||
bool readArray( Token &token );
|
||||
bool decodeNumber( Token &token );
|
||||
bool decodeString( Token &token );
|
||||
bool decodeString( Token &token, std::string &decoded );
|
||||
bool decodeDouble( Token &token );
|
||||
bool decodeUnicodeCodePoint( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool decodeUnicodeEscapeSequence( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool addError( const std::string &message,
|
||||
Token &token,
|
||||
Location extra = 0 );
|
||||
bool recoverFromError( TokenType skipUntilToken );
|
||||
bool addErrorAndRecover( const std::string &message,
|
||||
Token &token,
|
||||
TokenType skipUntilToken );
|
||||
void skipUntilSpace();
|
||||
Value ¤tValue();
|
||||
Char getNextChar();
|
||||
void getLocationLineAndColumn( Location location,
|
||||
int &line,
|
||||
int &column ) const;
|
||||
std::string getLocationLineAndColumn( Location location ) const;
|
||||
void addComment( Location begin,
|
||||
Location end,
|
||||
CommentPlacement placement );
|
||||
void skipCommentTokens( Token &token );
|
||||
|
||||
typedef std::stack<Value *> Nodes;
|
||||
Nodes nodes_;
|
||||
Errors errors_;
|
||||
std::string document_;
|
||||
Location begin_;
|
||||
Location end_;
|
||||
Location current_;
|
||||
Location lastValueEnd_;
|
||||
Value *lastValue_;
|
||||
std::string commentsBefore_;
|
||||
Features features_;
|
||||
bool collectComments_;
|
||||
};
|
||||
|
||||
/** \brief Read from 'sin' into 'root'.
|
||||
|
||||
Always keep comments from the input JSON.
|
||||
|
||||
This can be used to read a file into a particular sub-object.
|
||||
For example:
|
||||
\code
|
||||
Json::Value root;
|
||||
cin >> root["dir"]["file"];
|
||||
cout << root;
|
||||
\endcode
|
||||
Result:
|
||||
\verbatim
|
||||
{
|
||||
"dir": {
|
||||
"file": {
|
||||
// The input stream JSON would be nested here.
|
||||
}
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
\throw std::exception on parse error.
|
||||
\see Json::operator<<()
|
||||
*/
|
||||
std::istream& operator>>( std::istream&, Value& );
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // CPPTL_JSON_READER_H_INCLUDED
|
1069
thirdparty/jsoncpp/include/json/value.h
vendored
1069
thirdparty/jsoncpp/include/json/value.h
vendored
File diff suppressed because it is too large
Load Diff
174
thirdparty/jsoncpp/include/json/writer.h
vendored
174
thirdparty/jsoncpp/include/json/writer.h
vendored
@ -1,174 +0,0 @@
|
||||
#ifndef JSON_WRITER_H_INCLUDED
|
||||
# define JSON_WRITER_H_INCLUDED
|
||||
|
||||
# include "value.h"
|
||||
# include <vector>
|
||||
# include <string>
|
||||
# include <iostream>
|
||||
|
||||
namespace Json {
|
||||
|
||||
class Value;
|
||||
|
||||
/** \brief Abstract class for writers.
|
||||
*/
|
||||
class JSON_API Writer
|
||||
{
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
virtual std::string write( const Value &root ) = 0;
|
||||
};
|
||||
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
|
||||
*
|
||||
* The JSON document is written in a single line. It is not intended for 'human' consumption,
|
||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||
* \sa Reader, Value
|
||||
*/
|
||||
class JSON_API FastWriter : public Writer
|
||||
{
|
||||
public:
|
||||
FastWriter();
|
||||
virtual ~FastWriter(){}
|
||||
|
||||
void enableYAMLCompatibility();
|
||||
|
||||
public: // overridden from Writer
|
||||
virtual std::string write( const Value &root );
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
|
||||
std::string document_;
|
||||
bool yamlCompatiblityEnabled_;
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledWriter: public Writer
|
||||
{
|
||||
public:
|
||||
StyledWriter();
|
||||
virtual ~StyledWriter(){}
|
||||
|
||||
public: // overridden from Writer
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param root Value to serialize.
|
||||
* \return String containing the JSON document that represents the root value.
|
||||
*/
|
||||
virtual std::string write( const Value &root );
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
void writeArrayValue( const Value &value );
|
||||
bool isMultineArray( const Value &value );
|
||||
void pushValue( const std::string &value );
|
||||
void writeIndent();
|
||||
void writeWithIndent( const std::string &value );
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue( const Value &root );
|
||||
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||
bool hasCommentForValue( const Value &value );
|
||||
static std::string normalizeEOL( const std::string &text );
|
||||
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
|
||||
ChildValues childValues_;
|
||||
std::string document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
int indentSize_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
|
||||
to a stream rather than to a string.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
*
|
||||
* \param indentation Each level will be indented by this amount extra.
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledStreamWriter
|
||||
{
|
||||
public:
|
||||
StyledStreamWriter( std::string indentation="\t" );
|
||||
~StyledStreamWriter(){}
|
||||
|
||||
public:
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||
* \param root Value to serialize.
|
||||
* \note There is no point in deriving from Writer, since write() should not return a value.
|
||||
*/
|
||||
void write( std::ostream &out, const Value &root );
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
void writeArrayValue( const Value &value );
|
||||
bool isMultineArray( const Value &value );
|
||||
void pushValue( const std::string &value );
|
||||
void writeIndent();
|
||||
void writeWithIndent( const std::string &value );
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue( const Value &root );
|
||||
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||
bool hasCommentForValue( const Value &value );
|
||||
static std::string normalizeEOL( const std::string &text );
|
||||
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
|
||||
ChildValues childValues_;
|
||||
std::ostream* document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
std::string indentation_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
|
||||
std::string JSON_API valueToString( Int value );
|
||||
std::string JSON_API valueToString( UInt value );
|
||||
std::string JSON_API valueToString( double value );
|
||||
std::string JSON_API valueToString( bool value );
|
||||
std::string JSON_API valueToQuotedString( const char *value );
|
||||
|
||||
/// \brief Output using the StyledStreamWriter.
|
||||
/// \see Json::operator>>()
|
||||
std::ostream& operator<<( std::ostream&, const Value &root );
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
|
||||
#endif // JSON_WRITER_H_INCLUDED
|
233
thirdparty/jsoncpp/src/jsontestrunner/main.cpp
vendored
233
thirdparty/jsoncpp/src/jsontestrunner/main.cpp
vendored
@ -1,233 +0,0 @@
|
||||
#include <json/json.h>
|
||||
#include <algorithm> // sort
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
||||
# pragma warning( disable: 4996 ) // disable fopen deprecation warning
|
||||
#endif
|
||||
|
||||
static std::string
|
||||
readInputTestFile( const char *path )
|
||||
{
|
||||
FILE *file = fopen( path, "rb" );
|
||||
if ( !file )
|
||||
return std::string("");
|
||||
fseek( file, 0, SEEK_END );
|
||||
long size = ftell( file );
|
||||
fseek( file, 0, SEEK_SET );
|
||||
std::string text;
|
||||
char *buffer = new char[size+1];
|
||||
buffer[size] = 0;
|
||||
if ( fread( buffer, 1, size, file ) == (unsigned long)size )
|
||||
text = buffer;
|
||||
fclose( file );
|
||||
delete[] buffer;
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case Json::nullValue:
|
||||
fprintf( fout, "%s=null\n", path.c_str() );
|
||||
break;
|
||||
case Json::intValue:
|
||||
fprintf( fout, "%s=%d\n", path.c_str(), value.asInt() );
|
||||
break;
|
||||
case Json::uintValue:
|
||||
fprintf( fout, "%s=%u\n", path.c_str(), value.asUInt() );
|
||||
break;
|
||||
case Json::realValue:
|
||||
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
|
||||
break;
|
||||
case Json::stringValue:
|
||||
fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() );
|
||||
break;
|
||||
case Json::booleanValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" );
|
||||
break;
|
||||
case Json::arrayValue:
|
||||
{
|
||||
fprintf( fout, "%s=[]\n", path.c_str() );
|
||||
int size = value.size();
|
||||
for ( int index =0; index < size; ++index )
|
||||
{
|
||||
static char buffer[16];
|
||||
sprintf( buffer, "[%d]", index );
|
||||
printValueTree( fout, value[index], path + buffer );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Json::objectValue:
|
||||
{
|
||||
fprintf( fout, "%s={}\n", path.c_str() );
|
||||
Json::Value::Members members( value.getMemberNames() );
|
||||
std::sort( members.begin(), members.end() );
|
||||
std::string suffix = *(path.end()-1) == '.' ? "" : ".";
|
||||
for ( Json::Value::Members::iterator it = members.begin();
|
||||
it != members.end();
|
||||
++it )
|
||||
{
|
||||
const std::string &name = *it;
|
||||
printValueTree( fout, value[name], path + suffix + name );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parseAndSaveValueTree( const std::string &input,
|
||||
const std::string &actual,
|
||||
const std::string &kind,
|
||||
Json::Value &root,
|
||||
const Json::Features &features,
|
||||
bool parseOnly )
|
||||
{
|
||||
Json::Reader reader( features );
|
||||
bool parsingSuccessful = reader.parse( input, root );
|
||||
if ( !parsingSuccessful )
|
||||
{
|
||||
printf( "Failed to parse %s file: \n%s\n",
|
||||
kind.c_str(),
|
||||
reader.getFormatedErrorMessages().c_str() );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( !parseOnly )
|
||||
{
|
||||
FILE *factual = fopen( actual.c_str(), "wt" );
|
||||
if ( !factual )
|
||||
{
|
||||
printf( "Failed to create %s actual file.\n", kind.c_str() );
|
||||
return 2;
|
||||
}
|
||||
printValueTree( factual, root );
|
||||
fclose( factual );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rewriteValueTree( const std::string &rewritePath,
|
||||
const Json::Value &root,
|
||||
std::string &rewrite )
|
||||
{
|
||||
//Json::FastWriter writer;
|
||||
//writer.enableYAMLCompatibility();
|
||||
Json::StyledWriter writer;
|
||||
rewrite = writer.write( root );
|
||||
FILE *fout = fopen( rewritePath.c_str(), "wt" );
|
||||
if ( !fout )
|
||||
{
|
||||
printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() );
|
||||
return 2;
|
||||
}
|
||||
fprintf( fout, "%s\n", rewrite.c_str() );
|
||||
fclose( fout );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static std::string
|
||||
removeSuffix( const std::string &path,
|
||||
const std::string &extension )
|
||||
{
|
||||
if ( extension.length() >= path.length() )
|
||||
return std::string("");
|
||||
std::string suffix = path.substr( path.length() - extension.length() );
|
||||
if ( suffix != extension )
|
||||
return std::string("");
|
||||
return path.substr( 0, path.length() - extension.length() );
|
||||
}
|
||||
|
||||
static int
|
||||
printUsage( const char *argv[] )
|
||||
{
|
||||
printf( "Usage: %s [--strict] input-json-file", argv[0] );
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
parseCommandLine( int argc, const char *argv[],
|
||||
Json::Features &features, std::string &path,
|
||||
bool &parseOnly )
|
||||
{
|
||||
parseOnly = false;
|
||||
if ( argc < 2 )
|
||||
{
|
||||
return printUsage( argv );
|
||||
}
|
||||
|
||||
int index = 1;
|
||||
if ( std::string(argv[1]) == "--json-checker" )
|
||||
{
|
||||
features = Json::Features::strictMode();
|
||||
parseOnly = true;
|
||||
++index;
|
||||
}
|
||||
|
||||
if ( index == argc || index + 1 < argc )
|
||||
{
|
||||
return printUsage( argv );
|
||||
}
|
||||
|
||||
path = argv[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, const char *argv[] )
|
||||
{
|
||||
std::string path;
|
||||
Json::Features features;
|
||||
bool parseOnly;
|
||||
int exitCode = parseCommandLine( argc, argv, features, path, parseOnly );
|
||||
if ( exitCode != 0 )
|
||||
{
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
std::string input = readInputTestFile( path.c_str() );
|
||||
if ( input.empty() )
|
||||
{
|
||||
printf( "Failed to read input or empty input: %s\n", path.c_str() );
|
||||
return 3;
|
||||
}
|
||||
|
||||
std::string basePath = removeSuffix( argv[1], ".json" );
|
||||
if ( !parseOnly && basePath.empty() )
|
||||
{
|
||||
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
|
||||
return 3;
|
||||
}
|
||||
|
||||
std::string actualPath = basePath + ".actual";
|
||||
std::string rewritePath = basePath + ".rewrite";
|
||||
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
||||
|
||||
Json::Value root;
|
||||
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
|
||||
if ( exitCode == 0 && !parseOnly )
|
||||
{
|
||||
std::string rewrite;
|
||||
exitCode = rewriteValueTree( rewritePath, root, rewrite );
|
||||
if ( exitCode == 0 )
|
||||
{
|
||||
Json::Value rewriteRoot;
|
||||
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
|
||||
"rewrite", rewriteRoot, features, parseOnly );
|
||||
}
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
Import( 'env_testing buildJSONTests' )
|
||||
|
||||
buildJSONTests( env_testing, Split( """
|
||||
main.cpp
|
||||
""" ),
|
||||
'jsontestrunner' )
|
||||
|
||||
# For 'check' to work, 'libs' must be built first.
|
||||
env_testing.Depends('jsontestrunner', '#libs')
|
@ -1,125 +0,0 @@
|
||||
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
|
||||
namespace Json {
|
||||
|
||||
/* Fast memory allocator.
|
||||
*
|
||||
* This memory allocator allocates memory for a batch of object (specified by
|
||||
* the page size, the number of object in each page).
|
||||
*
|
||||
* It does not allow the destruction of a single object. All the allocated objects
|
||||
* can be destroyed at once. The memory can be either released or reused for future
|
||||
* allocation.
|
||||
*
|
||||
* The in-place new operator must be used to construct the object using the pointer
|
||||
* returned by allocate.
|
||||
*/
|
||||
template<typename AllocatedType
|
||||
,const unsigned int objectPerAllocation>
|
||||
class BatchAllocator
|
||||
{
|
||||
public:
|
||||
typedef AllocatedType Type;
|
||||
|
||||
BatchAllocator( unsigned int objectsPerPage = 255 )
|
||||
: freeHead_( 0 )
|
||||
, objectsPerPage_( objectsPerPage )
|
||||
{
|
||||
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
|
||||
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
|
||||
assert( objectsPerPage >= 16 );
|
||||
batches_ = allocateBatch( 0 ); // allocated a dummy page
|
||||
currentBatch_ = batches_;
|
||||
}
|
||||
|
||||
~BatchAllocator()
|
||||
{
|
||||
for ( BatchInfo *batch = batches_; batch; )
|
||||
{
|
||||
BatchInfo *nextBatch = batch->next_;
|
||||
free( batch );
|
||||
batch = nextBatch;
|
||||
}
|
||||
}
|
||||
|
||||
/// allocate space for an array of objectPerAllocation object.
|
||||
/// @warning it is the responsability of the caller to call objects constructors.
|
||||
AllocatedType *allocate()
|
||||
{
|
||||
if ( freeHead_ ) // returns node from free list.
|
||||
{
|
||||
AllocatedType *object = freeHead_;
|
||||
freeHead_ = *(AllocatedType **)object;
|
||||
return object;
|
||||
}
|
||||
if ( currentBatch_->used_ == currentBatch_->end_ )
|
||||
{
|
||||
currentBatch_ = currentBatch_->next_;
|
||||
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
|
||||
currentBatch_ = currentBatch_->next_;
|
||||
|
||||
if ( !currentBatch_ ) // no free batch found, allocate a new one
|
||||
{
|
||||
currentBatch_ = allocateBatch( objectsPerPage_ );
|
||||
currentBatch_->next_ = batches_; // insert at the head of the list
|
||||
batches_ = currentBatch_;
|
||||
}
|
||||
}
|
||||
AllocatedType *allocated = currentBatch_->used_;
|
||||
currentBatch_->used_ += objectPerAllocation;
|
||||
return allocated;
|
||||
}
|
||||
|
||||
/// Release the object.
|
||||
/// @warning it is the responsability of the caller to actually destruct the object.
|
||||
void release( AllocatedType *object )
|
||||
{
|
||||
assert( object != 0 );
|
||||
*(AllocatedType **)object = freeHead_;
|
||||
freeHead_ = object;
|
||||
}
|
||||
|
||||
private:
|
||||
struct BatchInfo
|
||||
{
|
||||
BatchInfo *next_;
|
||||
AllocatedType *used_;
|
||||
AllocatedType *end_;
|
||||
AllocatedType buffer_[objectPerAllocation];
|
||||
};
|
||||
|
||||
// disabled copy constructor and assignement operator.
|
||||
BatchAllocator( const BatchAllocator & );
|
||||
void operator =( const BatchAllocator &);
|
||||
|
||||
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
|
||||
{
|
||||
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
|
||||
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
||||
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
|
||||
batch->next_ = 0;
|
||||
batch->used_ = batch->buffer_;
|
||||
batch->end_ = batch->buffer_ + objectsPerPage;
|
||||
return batch;
|
||||
}
|
||||
|
||||
BatchInfo *batches_;
|
||||
BatchInfo *currentBatch_;
|
||||
/// Head of a single linked list within the allocated space of freeed object
|
||||
AllocatedType *freeHead_;
|
||||
unsigned int objectsPerPage_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Json
|
||||
|
||||
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
||||
|
||||
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
|
@ -1,448 +0,0 @@
|
||||
// included by json_value.cpp
|
||||
// everything is within Json namespace
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueInternalArray
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueArrayAllocator::~ValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class DefaultValueArrayAllocator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||
{
|
||||
public: // overridden from ValueArrayAllocator
|
||||
virtual ~DefaultValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArray()
|
||||
{
|
||||
return new ValueInternalArray();
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||
{
|
||||
return new ValueInternalArray( other );
|
||||
}
|
||||
|
||||
virtual void destructArray( ValueInternalArray *array )
|
||||
{
|
||||
delete array;
|
||||
}
|
||||
|
||||
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||
ValueInternalArray::PageIndex &indexCount,
|
||||
ValueInternalArray::PageIndex minNewIndexCount )
|
||||
{
|
||||
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||
if ( minNewIndexCount > newIndexCount )
|
||||
newIndexCount = minNewIndexCount;
|
||||
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||
if ( !newIndexes )
|
||||
throw std::bad_alloc();
|
||||
indexCount = newIndexCount;
|
||||
indexes = static_cast<Value **>( newIndexes );
|
||||
}
|
||||
virtual void releaseArrayPageIndex( Value **indexes,
|
||||
ValueInternalArray::PageIndex indexCount )
|
||||
{
|
||||
if ( indexes )
|
||||
free( indexes );
|
||||
}
|
||||
|
||||
virtual Value *allocateArrayPage()
|
||||
{
|
||||
return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage( Value *value )
|
||||
{
|
||||
if ( value )
|
||||
free( value );
|
||||
}
|
||||
};
|
||||
|
||||
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||
{
|
||||
public: // overridden from ValueArrayAllocator
|
||||
virtual ~DefaultValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArray()
|
||||
{
|
||||
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||
new (array) ValueInternalArray(); // placement new
|
||||
return array;
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||
{
|
||||
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||
new (array) ValueInternalArray( other ); // placement new
|
||||
return array;
|
||||
}
|
||||
|
||||
virtual void destructArray( ValueInternalArray *array )
|
||||
{
|
||||
if ( array )
|
||||
{
|
||||
array->~ValueInternalArray();
|
||||
arraysAllocator_.release( array );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||
ValueInternalArray::PageIndex &indexCount,
|
||||
ValueInternalArray::PageIndex minNewIndexCount )
|
||||
{
|
||||
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||
if ( minNewIndexCount > newIndexCount )
|
||||
newIndexCount = minNewIndexCount;
|
||||
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||
if ( !newIndexes )
|
||||
throw std::bad_alloc();
|
||||
indexCount = newIndexCount;
|
||||
indexes = static_cast<Value **>( newIndexes );
|
||||
}
|
||||
virtual void releaseArrayPageIndex( Value **indexes,
|
||||
ValueInternalArray::PageIndex indexCount )
|
||||
{
|
||||
if ( indexes )
|
||||
free( indexes );
|
||||
}
|
||||
|
||||
virtual Value *allocateArrayPage()
|
||||
{
|
||||
return static_cast<Value *>( pagesAllocator_.allocate() );
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage( Value *value )
|
||||
{
|
||||
if ( value )
|
||||
pagesAllocator_.release( value );
|
||||
}
|
||||
private:
|
||||
BatchAllocator<ValueInternalArray,1> arraysAllocator_;
|
||||
BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
|
||||
};
|
||||
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
|
||||
static ValueArrayAllocator *&arrayAllocator()
|
||||
{
|
||||
static DefaultValueArrayAllocator defaultAllocator;
|
||||
static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
|
||||
return arrayAllocator;
|
||||
}
|
||||
|
||||
static struct DummyArrayAllocatorInitializer {
|
||||
DummyArrayAllocatorInitializer()
|
||||
{
|
||||
arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
|
||||
}
|
||||
} dummyArrayAllocatorInitializer;
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueInternalArray
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
ValueInternalArray::equals( const IteratorState &x,
|
||||
const IteratorState &other )
|
||||
{
|
||||
return x.array_ == other.array_
|
||||
&& x.currentItemIndex_ == other.currentItemIndex_
|
||||
&& x.currentPageIndex_ == other.currentPageIndex_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::increment( IteratorState &it )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||
!= it.array_->size_,
|
||||
"ValueInternalArray::increment(): moving iterator beyond end" );
|
||||
++(it.currentItemIndex_);
|
||||
if ( it.currentItemIndex_ == itemsPerPage )
|
||||
{
|
||||
it.currentItemIndex_ = 0;
|
||||
++(it.currentPageIndex_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::decrement( IteratorState &it )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
|
||||
&& it.currentItemIndex_ == 0,
|
||||
"ValueInternalArray::decrement(): moving iterator beyond end" );
|
||||
if ( it.currentItemIndex_ == 0 )
|
||||
{
|
||||
it.currentItemIndex_ = itemsPerPage-1;
|
||||
--(it.currentPageIndex_);
|
||||
}
|
||||
else
|
||||
{
|
||||
--(it.currentItemIndex_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalArray::unsafeDereference( const IteratorState &it )
|
||||
{
|
||||
return (*(it.currentPageIndex_))[it.currentItemIndex_];
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalArray::dereference( const IteratorState &it )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||
< it.array_->size_,
|
||||
"ValueInternalArray::dereference(): dereferencing invalid iterator" );
|
||||
return unsafeDereference( it );
|
||||
}
|
||||
|
||||
void
|
||||
ValueInternalArray::makeBeginIterator( IteratorState &it ) const
|
||||
{
|
||||
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||
it.currentItemIndex_ = 0;
|
||||
it.currentPageIndex_ = pages_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
|
||||
{
|
||||
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||
it.currentItemIndex_ = index % itemsPerPage;
|
||||
it.currentPageIndex_ = pages_ + index / itemsPerPage;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::makeEndIterator( IteratorState &it ) const
|
||||
{
|
||||
makeIterator( it, size_ );
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::ValueInternalArray()
|
||||
: pages_( 0 )
|
||||
, size_( 0 )
|
||||
, pageCount_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
|
||||
: pages_( 0 )
|
||||
, pageCount_( 0 )
|
||||
, size_( other.size_ )
|
||||
{
|
||||
PageIndex minNewPages = other.size_ / itemsPerPage;
|
||||
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
|
||||
"ValueInternalArray::reserve(): bad reallocation" );
|
||||
IteratorState itOther;
|
||||
other.makeBeginIterator( itOther );
|
||||
Value *value;
|
||||
for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
|
||||
{
|
||||
if ( index % itemsPerPage == 0 )
|
||||
{
|
||||
PageIndex pageIndex = index / itemsPerPage;
|
||||
value = arrayAllocator()->allocateArrayPage();
|
||||
pages_[pageIndex] = value;
|
||||
}
|
||||
new (value) Value( dereference( itOther ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray &
|
||||
ValueInternalArray::operator =( const ValueInternalArray &other )
|
||||
{
|
||||
ValueInternalArray temp( other );
|
||||
swap( temp );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::~ValueInternalArray()
|
||||
{
|
||||
// destroy all constructed items
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeBeginIterator( it);
|
||||
makeEndIterator( itEnd );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
Value *value = &dereference(it);
|
||||
value->~Value();
|
||||
}
|
||||
// release all pages
|
||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||
for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
|
||||
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||
// release pages index
|
||||
arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::swap( ValueInternalArray &other )
|
||||
{
|
||||
Value **tempPages = pages_;
|
||||
pages_ = other.pages_;
|
||||
other.pages_ = tempPages;
|
||||
ArrayIndex tempSize = size_;
|
||||
size_ = other.size_;
|
||||
other.size_ = tempSize;
|
||||
PageIndex tempPageCount = pageCount_;
|
||||
pageCount_ = other.pageCount_;
|
||||
other.pageCount_ = tempPageCount;
|
||||
}
|
||||
|
||||
void
|
||||
ValueInternalArray::clear()
|
||||
{
|
||||
ValueInternalArray dummy;
|
||||
swap( dummy );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::resize( ArrayIndex newSize )
|
||||
{
|
||||
if ( newSize == 0 )
|
||||
clear();
|
||||
else if ( newSize < size_ )
|
||||
{
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeIterator( it, newSize );
|
||||
makeIterator( itEnd, size_ );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
Value *value = &dereference(it);
|
||||
value->~Value();
|
||||
}
|
||||
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
|
||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||
for ( ; pageIndex < lastPageIndex; ++pageIndex )
|
||||
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||
size_ = newSize;
|
||||
}
|
||||
else if ( newSize > size_ )
|
||||
resolveReference( newSize );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::makeIndexValid( ArrayIndex index )
|
||||
{
|
||||
// Need to enlarge page index ?
|
||||
if ( index >= pageCount_ * itemsPerPage )
|
||||
{
|
||||
PageIndex minNewPages = (index + 1) / itemsPerPage;
|
||||
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
|
||||
}
|
||||
|
||||
// Need to allocate new pages ?
|
||||
ArrayIndex nextPageIndex =
|
||||
(size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
|
||||
: size_;
|
||||
if ( nextPageIndex <= index )
|
||||
{
|
||||
PageIndex pageIndex = nextPageIndex / itemsPerPage;
|
||||
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
|
||||
for ( ; pageToAllocate-- > 0; ++pageIndex )
|
||||
pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
|
||||
}
|
||||
|
||||
// Initialize all new entries
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeIterator( it, size_ );
|
||||
size_ = index + 1;
|
||||
makeIterator( itEnd, size_ );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
Value *value = &dereference(it);
|
||||
new (value) Value(); // Construct a default value using placement new
|
||||
}
|
||||
}
|
||||
|
||||
Value &
|
||||
ValueInternalArray::resolveReference( ArrayIndex index )
|
||||
{
|
||||
if ( index >= size_ )
|
||||
makeIndexValid( index );
|
||||
return pages_[index/itemsPerPage][index%itemsPerPage];
|
||||
}
|
||||
|
||||
Value *
|
||||
ValueInternalArray::find( ArrayIndex index ) const
|
||||
{
|
||||
if ( index >= size_ )
|
||||
return 0;
|
||||
return &(pages_[index/itemsPerPage][index%itemsPerPage]);
|
||||
}
|
||||
|
||||
ValueInternalArray::ArrayIndex
|
||||
ValueInternalArray::size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
int
|
||||
ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
|
||||
{
|
||||
return indexOf(y) - indexOf(x);
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::ArrayIndex
|
||||
ValueInternalArray::indexOf( const IteratorState &iterator )
|
||||
{
|
||||
if ( !iterator.array_ )
|
||||
return ArrayIndex(-1);
|
||||
return ArrayIndex(
|
||||
(iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
|
||||
+ iterator.currentItemIndex_ );
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ValueInternalArray::compare( const ValueInternalArray &other ) const
|
||||
{
|
||||
int sizeDiff( size_ - other.size_ );
|
||||
if ( sizeDiff != 0 )
|
||||
return sizeDiff;
|
||||
|
||||
for ( ArrayIndex index =0; index < size_; ++index )
|
||||
{
|
||||
int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
|
||||
other.pages_[index/itemsPerPage][index%itemsPerPage] );
|
||||
if ( diff != 0 )
|
||||
return diff;
|
||||
}
|
||||
return 0;
|
||||
}
|
607
thirdparty/jsoncpp/src/lib_json/json_internalmap.inl
vendored
607
thirdparty/jsoncpp/src/lib_json/json_internalmap.inl
vendored
@ -1,607 +0,0 @@
|
||||
// included by json_value.cpp
|
||||
// everything is within Json namespace
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueInternalMap
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
|
||||
* This optimization is used by the fast allocator.
|
||||
*/
|
||||
ValueInternalLink::ValueInternalLink()
|
||||
: previous_( 0 )
|
||||
, next_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
ValueInternalLink::~ValueInternalLink()
|
||||
{
|
||||
for ( int index =0; index < itemPerLink; ++index )
|
||||
{
|
||||
if ( !items_[index].isItemAvailable() )
|
||||
{
|
||||
if ( !items_[index].isMemberNameStatic() )
|
||||
free( keys_[index] );
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ValueMapAllocator::~ValueMapAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||
{
|
||||
public: // overridden from ValueMapAllocator
|
||||
virtual ValueInternalMap *newMap()
|
||||
{
|
||||
return new ValueInternalMap();
|
||||
}
|
||||
|
||||
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||
{
|
||||
return new ValueInternalMap( other );
|
||||
}
|
||||
|
||||
virtual void destructMap( ValueInternalMap *map )
|
||||
{
|
||||
delete map;
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||
{
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
|
||||
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||
{
|
||||
delete [] links;
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapLink()
|
||||
{
|
||||
return new ValueInternalLink();
|
||||
}
|
||||
|
||||
virtual void releaseMapLink( ValueInternalLink *link )
|
||||
{
|
||||
delete link;
|
||||
}
|
||||
};
|
||||
#else
|
||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||
{
|
||||
public: // overridden from ValueMapAllocator
|
||||
virtual ValueInternalMap *newMap()
|
||||
{
|
||||
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||
new (map) ValueInternalMap(); // placement new
|
||||
return map;
|
||||
}
|
||||
|
||||
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||
{
|
||||
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||
new (map) ValueInternalMap( other ); // placement new
|
||||
return map;
|
||||
}
|
||||
|
||||
virtual void destructMap( ValueInternalMap *map )
|
||||
{
|
||||
if ( map )
|
||||
{
|
||||
map->~ValueInternalMap();
|
||||
mapsAllocator_.release( map );
|
||||
}
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||
{
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
|
||||
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||
{
|
||||
delete [] links;
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapLink()
|
||||
{
|
||||
ValueInternalLink *link = linksAllocator_.allocate();
|
||||
memset( link, 0, sizeof(ValueInternalLink) );
|
||||
return link;
|
||||
}
|
||||
|
||||
virtual void releaseMapLink( ValueInternalLink *link )
|
||||
{
|
||||
link->~ValueInternalLink();
|
||||
linksAllocator_.release( link );
|
||||
}
|
||||
private:
|
||||
BatchAllocator<ValueInternalMap,1> mapsAllocator_;
|
||||
BatchAllocator<ValueInternalLink,1> linksAllocator_;
|
||||
};
|
||||
#endif
|
||||
|
||||
static ValueMapAllocator *&mapAllocator()
|
||||
{
|
||||
static DefaultValueMapAllocator defaultAllocator;
|
||||
static ValueMapAllocator *mapAllocator = &defaultAllocator;
|
||||
return mapAllocator;
|
||||
}
|
||||
|
||||
static struct DummyMapAllocatorInitializer {
|
||||
DummyMapAllocatorInitializer()
|
||||
{
|
||||
mapAllocator(); // ensure mapAllocator() statics are initialized before main().
|
||||
}
|
||||
} dummyMapAllocatorInitializer;
|
||||
|
||||
|
||||
|
||||
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
||||
|
||||
/*
|
||||
use linked list hash map.
|
||||
buckets array is a container.
|
||||
linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
|
||||
value have extra state: valid, available, deleted
|
||||
*/
|
||||
|
||||
|
||||
ValueInternalMap::ValueInternalMap()
|
||||
: buckets_( 0 )
|
||||
, tailLink_( 0 )
|
||||
, bucketsSize_( 0 )
|
||||
, itemCount_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
|
||||
: buckets_( 0 )
|
||||
, tailLink_( 0 )
|
||||
, bucketsSize_( 0 )
|
||||
, itemCount_( 0 )
|
||||
{
|
||||
reserve( other.itemCount_ );
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
other.makeBeginIterator( it );
|
||||
other.makeEndIterator( itEnd );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
bool isStatic;
|
||||
const char *memberName = key( it, isStatic );
|
||||
const Value &aValue = value( it );
|
||||
resolveReference(memberName, isStatic) = aValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap &
|
||||
ValueInternalMap::operator =( const ValueInternalMap &other )
|
||||
{
|
||||
ValueInternalMap dummy( other );
|
||||
swap( dummy );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::~ValueInternalMap()
|
||||
{
|
||||
if ( buckets_ )
|
||||
{
|
||||
for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
|
||||
{
|
||||
ValueInternalLink *link = buckets_[bucketIndex].next_;
|
||||
while ( link )
|
||||
{
|
||||
ValueInternalLink *linkToRelease = link;
|
||||
link = link->next_;
|
||||
mapAllocator()->releaseMapLink( linkToRelease );
|
||||
}
|
||||
}
|
||||
mapAllocator()->releaseMapBuckets( buckets_ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::swap( ValueInternalMap &other )
|
||||
{
|
||||
ValueInternalLink *tempBuckets = buckets_;
|
||||
buckets_ = other.buckets_;
|
||||
other.buckets_ = tempBuckets;
|
||||
ValueInternalLink *tempTailLink = tailLink_;
|
||||
tailLink_ = other.tailLink_;
|
||||
other.tailLink_ = tempTailLink;
|
||||
BucketIndex tempBucketsSize = bucketsSize_;
|
||||
bucketsSize_ = other.bucketsSize_;
|
||||
other.bucketsSize_ = tempBucketsSize;
|
||||
BucketIndex tempItemCount = itemCount_;
|
||||
itemCount_ = other.itemCount_;
|
||||
other.itemCount_ = tempItemCount;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::clear()
|
||||
{
|
||||
ValueInternalMap dummy;
|
||||
swap( dummy );
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::BucketIndex
|
||||
ValueInternalMap::size() const
|
||||
{
|
||||
return itemCount_;
|
||||
}
|
||||
|
||||
bool
|
||||
ValueInternalMap::reserveDelta( BucketIndex growth )
|
||||
{
|
||||
return reserve( itemCount_ + growth );
|
||||
}
|
||||
|
||||
bool
|
||||
ValueInternalMap::reserve( BucketIndex newItemCount )
|
||||
{
|
||||
if ( !buckets_ && newItemCount > 0 )
|
||||
{
|
||||
buckets_ = mapAllocator()->allocateMapBuckets( 1 );
|
||||
bucketsSize_ = 1;
|
||||
tailLink_ = &buckets_[0];
|
||||
}
|
||||
// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const Value *
|
||||
ValueInternalMap::find( const char *key ) const
|
||||
{
|
||||
if ( !bucketsSize_ )
|
||||
return 0;
|
||||
HashKey hashedKey = hash( key );
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
for ( const ValueInternalLink *current = &buckets_[bucketIndex];
|
||||
current != 0;
|
||||
current = current->next_ )
|
||||
{
|
||||
for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( current->items_[index].isItemAvailable() )
|
||||
return 0;
|
||||
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||
return ¤t->items_[index];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Value *
|
||||
ValueInternalMap::find( const char *key )
|
||||
{
|
||||
const ValueInternalMap *constThis = this;
|
||||
return const_cast<Value *>( constThis->find( key ) );
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::resolveReference( const char *key,
|
||||
bool isStatic )
|
||||
{
|
||||
HashKey hashedKey = hash( key );
|
||||
if ( bucketsSize_ )
|
||||
{
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
ValueInternalLink **previous = 0;
|
||||
BucketIndex index;
|
||||
for ( ValueInternalLink *current = &buckets_[bucketIndex];
|
||||
current != 0;
|
||||
previous = ¤t->next_, current = current->next_ )
|
||||
{
|
||||
for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( current->items_[index].isItemAvailable() )
|
||||
return setNewItem( key, isStatic, current, index );
|
||||
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||
return current->items_[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reserveDelta( 1 );
|
||||
return unsafeAdd( key, isStatic, hashedKey );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::remove( const char *key )
|
||||
{
|
||||
HashKey hashedKey = hash( key );
|
||||
if ( !bucketsSize_ )
|
||||
return;
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
for ( ValueInternalLink *link = &buckets_[bucketIndex];
|
||||
link != 0;
|
||||
link = link->next_ )
|
||||
{
|
||||
BucketIndex index;
|
||||
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( link->items_[index].isItemAvailable() )
|
||||
return;
|
||||
if ( strcmp( key, link->keys_[index] ) == 0 )
|
||||
{
|
||||
doActualRemove( link, index, bucketIndex );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ValueInternalMap::doActualRemove( ValueInternalLink *link,
|
||||
BucketIndex index,
|
||||
BucketIndex bucketIndex )
|
||||
{
|
||||
// find last item of the bucket and swap it with the 'removed' one.
|
||||
// set removed items flags to 'available'.
|
||||
// if last page only contains 'available' items, then desallocate it (it's empty)
|
||||
ValueInternalLink *&lastLink = getLastLinkInBucket( index );
|
||||
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
||||
for ( ;
|
||||
lastItemIndex < ValueInternalLink::itemPerLink;
|
||||
++lastItemIndex ) // may be optimized with dicotomic search
|
||||
{
|
||||
if ( lastLink->items_[lastItemIndex].isItemAvailable() )
|
||||
break;
|
||||
}
|
||||
|
||||
BucketIndex lastUsedIndex = lastItemIndex - 1;
|
||||
Value *valueToDelete = &link->items_[index];
|
||||
Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
|
||||
if ( valueToDelete != valueToPreserve )
|
||||
valueToDelete->swap( *valueToPreserve );
|
||||
if ( lastUsedIndex == 0 ) // page is now empty
|
||||
{ // remove it from bucket linked list and delete it.
|
||||
ValueInternalLink *linkPreviousToLast = lastLink->previous_;
|
||||
if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
|
||||
{
|
||||
mapAllocator()->releaseMapLink( lastLink );
|
||||
linkPreviousToLast->next_ = 0;
|
||||
lastLink = linkPreviousToLast;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Value dummy;
|
||||
valueToPreserve->swap( dummy ); // restore deleted to default Value.
|
||||
valueToPreserve->setItemUsed( false );
|
||||
}
|
||||
--itemCount_;
|
||||
}
|
||||
|
||||
|
||||
ValueInternalLink *&
|
||||
ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
|
||||
{
|
||||
if ( bucketIndex == bucketsSize_ - 1 )
|
||||
return tailLink_;
|
||||
ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
|
||||
if ( !previous )
|
||||
previous = &buckets_[bucketIndex];
|
||||
return previous;
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::setNewItem( const char *key,
|
||||
bool isStatic,
|
||||
ValueInternalLink *link,
|
||||
BucketIndex index )
|
||||
{
|
||||
char *duplicatedKey = valueAllocator()->makeMemberName( key );
|
||||
++itemCount_;
|
||||
link->keys_[index] = duplicatedKey;
|
||||
link->items_[index].setItemUsed();
|
||||
link->items_[index].setMemberNameIsStatic( isStatic );
|
||||
return link->items_[index]; // items already default constructed.
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::unsafeAdd( const char *key,
|
||||
bool isStatic,
|
||||
HashKey hashedKey )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
|
||||
ValueInternalLink *link = previousLink;
|
||||
BucketIndex index;
|
||||
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( link->items_[index].isItemAvailable() )
|
||||
break;
|
||||
}
|
||||
if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
|
||||
{
|
||||
ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
|
||||
index = 0;
|
||||
link->next_ = newLink;
|
||||
previousLink = newLink;
|
||||
link = newLink;
|
||||
}
|
||||
return setNewItem( key, isStatic, link, index );
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::HashKey
|
||||
ValueInternalMap::hash( const char *key ) const
|
||||
{
|
||||
HashKey hash = 0;
|
||||
while ( *key )
|
||||
hash += *key++ * 37;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ValueInternalMap::compare( const ValueInternalMap &other ) const
|
||||
{
|
||||
int sizeDiff( itemCount_ - other.itemCount_ );
|
||||
if ( sizeDiff != 0 )
|
||||
return sizeDiff;
|
||||
// Strict order guaranty is required. Compare all keys FIRST, then compare values.
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeBeginIterator( it );
|
||||
makeEndIterator( itEnd );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
if ( !other.find( key( it ) ) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
// All keys are equals, let's compare values
|
||||
makeBeginIterator( it );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
const Value *otherValue = other.find( key( it ) );
|
||||
int valueDiff = value(it).compare( *otherValue );
|
||||
if ( valueDiff != 0 )
|
||||
return valueDiff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::makeBeginIterator( IteratorState &it ) const
|
||||
{
|
||||
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||
it.bucketIndex_ = 0;
|
||||
it.itemIndex_ = 0;
|
||||
it.link_ = buckets_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::makeEndIterator( IteratorState &it ) const
|
||||
{
|
||||
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||
it.bucketIndex_ = bucketsSize_;
|
||||
it.itemIndex_ = 0;
|
||||
it.link_ = 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
|
||||
{
|
||||
return x.map_ == other.map_
|
||||
&& x.bucketIndex_ == other.bucketIndex_
|
||||
&& x.link_ == other.link_
|
||||
&& x.itemIndex_ == other.itemIndex_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::incrementBucket( IteratorState &iterator )
|
||||
{
|
||||
++iterator.bucketIndex_;
|
||||
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
||||
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||
if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
|
||||
iterator.link_ = 0;
|
||||
else
|
||||
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
||||
iterator.itemIndex_ = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::increment( IteratorState &iterator )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
|
||||
++iterator.itemIndex_;
|
||||
if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_ != 0,
|
||||
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||
iterator.link_ = iterator.link_->next_;
|
||||
if ( iterator.link_ == 0 )
|
||||
incrementBucket( iterator );
|
||||
}
|
||||
else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
|
||||
{
|
||||
incrementBucket( iterator );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::decrement( IteratorState &iterator )
|
||||
{
|
||||
if ( iterator.itemIndex_ == 0 )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
|
||||
if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
|
||||
--(iterator.bucketIndex_);
|
||||
}
|
||||
iterator.link_ = iterator.link_->previous_;
|
||||
iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ValueInternalMap::key( const IteratorState &iterator )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||
return iterator.link_->keys_[iterator.itemIndex_];
|
||||
}
|
||||
|
||||
const char *
|
||||
ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
||||
return iterator.link_->keys_[iterator.itemIndex_];
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::value( const IteratorState &iterator )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||
return iterator.link_->items_[iterator.itemIndex_];
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
|
||||
{
|
||||
int offset = 0;
|
||||
IteratorState it = x;
|
||||
while ( !equals( it, y ) )
|
||||
increment( it );
|
||||
return offset;
|
||||
}
|
885
thirdparty/jsoncpp/src/lib_json/json_reader.cpp
vendored
885
thirdparty/jsoncpp/src/lib_json/json_reader.cpp
vendored
@ -1,885 +0,0 @@
|
||||
#include <json/reader.h>
|
||||
#include <json/value.h>
|
||||
#include <utility>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#if _MSC_VER >= 1400 // VC++ 8.0
|
||||
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||
#endif
|
||||
|
||||
namespace Json {
|
||||
|
||||
// Implementation of class Features
|
||||
// ////////////////////////////////
|
||||
|
||||
Features::Features()
|
||||
: allowComments_( true )
|
||||
, strictRoot_( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Features
|
||||
Features::all()
|
||||
{
|
||||
return Features();
|
||||
}
|
||||
|
||||
|
||||
Features
|
||||
Features::strictMode()
|
||||
{
|
||||
Features features;
|
||||
features.allowComments_ = false;
|
||||
features.strictRoot_ = true;
|
||||
return features;
|
||||
}
|
||||
|
||||
// Implementation of class Reader
|
||||
// ////////////////////////////////
|
||||
|
||||
|
||||
static inline bool
|
||||
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
||||
{
|
||||
return c == c1 || c == c2 || c == c3 || c == c4;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
|
||||
{
|
||||
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
containsNewLine( Reader::Location begin,
|
||||
Reader::Location end )
|
||||
{
|
||||
for ( ;begin < end; ++begin )
|
||||
if ( *begin == '\n' || *begin == '\r' )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string codePointToUTF8(unsigned int cp)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||
|
||||
if (cp <= 0x7f)
|
||||
{
|
||||
result.resize(1);
|
||||
result[0] = static_cast<char>(cp);
|
||||
}
|
||||
else if (cp <= 0x7FF)
|
||||
{
|
||||
result.resize(2);
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||
}
|
||||
else if (cp <= 0xFFFF)
|
||||
{
|
||||
result.resize(3);
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||
}
|
||||
else if (cp <= 0x10FFFF)
|
||||
{
|
||||
result.resize(4);
|
||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Class Reader
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Reader::Reader()
|
||||
: features_( Features::all() )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Reader::Reader( const Features &features )
|
||||
: features_( features )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::parse( const std::string &document,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
document_ = document;
|
||||
const char *begin = document_.c_str();
|
||||
const char *end = begin + document_.length();
|
||||
return parse( begin, end, root, collectComments );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::parse( std::istream& sin,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
//std::istream_iterator<char> begin(sin);
|
||||
//std::istream_iterator<char> end;
|
||||
// Those would allow streamed input from a file, if parse() were a
|
||||
// template function.
|
||||
|
||||
// Since std::string is reference-counted, this at least does not
|
||||
// create an extra copy.
|
||||
std::string doc;
|
||||
std::getline(sin, doc, (char)EOF);
|
||||
return parse( doc, root, collectComments );
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::parse( const char *beginDoc, const char *endDoc,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
if ( !features_.allowComments_ )
|
||||
{
|
||||
collectComments = false;
|
||||
}
|
||||
|
||||
begin_ = beginDoc;
|
||||
end_ = endDoc;
|
||||
collectComments_ = collectComments;
|
||||
current_ = begin_;
|
||||
lastValueEnd_ = 0;
|
||||
lastValue_ = 0;
|
||||
commentsBefore_ = "";
|
||||
errors_.clear();
|
||||
while ( !nodes_.empty() )
|
||||
nodes_.pop();
|
||||
nodes_.push( &root );
|
||||
|
||||
bool successful = readValue();
|
||||
Token token;
|
||||
skipCommentTokens( token );
|
||||
if ( collectComments_ && !commentsBefore_.empty() )
|
||||
root.setComment( commentsBefore_, commentAfter );
|
||||
if ( features_.strictRoot_ )
|
||||
{
|
||||
if ( !root.isArray() && !root.isObject() )
|
||||
{
|
||||
// Set error location to start of doc, ideally should be first token found in doc
|
||||
token.type_ = tokenError;
|
||||
token.start_ = beginDoc;
|
||||
token.end_ = endDoc;
|
||||
addError( "A valid JSON document must be either an array or an object value.",
|
||||
token );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readValue()
|
||||
{
|
||||
Token token;
|
||||
skipCommentTokens( token );
|
||||
bool successful = true;
|
||||
|
||||
if ( collectComments_ && !commentsBefore_.empty() )
|
||||
{
|
||||
currentValue().setComment( commentsBefore_, commentBefore );
|
||||
commentsBefore_ = "";
|
||||
}
|
||||
|
||||
|
||||
switch ( token.type_ )
|
||||
{
|
||||
case tokenObjectBegin:
|
||||
successful = readObject( token );
|
||||
break;
|
||||
case tokenArrayBegin:
|
||||
successful = readArray( token );
|
||||
break;
|
||||
case tokenNumber:
|
||||
successful = decodeNumber( token );
|
||||
break;
|
||||
case tokenString:
|
||||
successful = decodeString( token );
|
||||
break;
|
||||
case tokenTrue:
|
||||
currentValue() = true;
|
||||
break;
|
||||
case tokenFalse:
|
||||
currentValue() = false;
|
||||
break;
|
||||
case tokenNull:
|
||||
currentValue() = Value();
|
||||
break;
|
||||
default:
|
||||
return addError( "Syntax error: value, object or array expected.", token );
|
||||
}
|
||||
|
||||
if ( collectComments_ )
|
||||
{
|
||||
lastValueEnd_ = current_;
|
||||
lastValue_ = ¤tValue();
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::skipCommentTokens( Token &token )
|
||||
{
|
||||
if ( features_.allowComments_ )
|
||||
{
|
||||
do
|
||||
{
|
||||
readToken( token );
|
||||
}
|
||||
while ( token.type_ == tokenComment );
|
||||
}
|
||||
else
|
||||
{
|
||||
readToken( token );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::expectToken( TokenType type, Token &token, const char *message )
|
||||
{
|
||||
readToken( token );
|
||||
if ( token.type_ != type )
|
||||
return addError( message, token );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readToken( Token &token )
|
||||
{
|
||||
skipSpaces();
|
||||
token.start_ = current_;
|
||||
Char c = getNextChar();
|
||||
bool ok = true;
|
||||
switch ( c )
|
||||
{
|
||||
case '{':
|
||||
token.type_ = tokenObjectBegin;
|
||||
break;
|
||||
case '}':
|
||||
token.type_ = tokenObjectEnd;
|
||||
break;
|
||||
case '[':
|
||||
token.type_ = tokenArrayBegin;
|
||||
break;
|
||||
case ']':
|
||||
token.type_ = tokenArrayEnd;
|
||||
break;
|
||||
case '"':
|
||||
token.type_ = tokenString;
|
||||
ok = readString();
|
||||
break;
|
||||
case '/':
|
||||
token.type_ = tokenComment;
|
||||
ok = readComment();
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
token.type_ = tokenNumber;
|
||||
readNumber();
|
||||
break;
|
||||
case 't':
|
||||
token.type_ = tokenTrue;
|
||||
ok = match( "rue", 3 );
|
||||
break;
|
||||
case 'f':
|
||||
token.type_ = tokenFalse;
|
||||
ok = match( "alse", 4 );
|
||||
break;
|
||||
case 'n':
|
||||
token.type_ = tokenNull;
|
||||
ok = match( "ull", 3 );
|
||||
break;
|
||||
case ',':
|
||||
token.type_ = tokenArraySeparator;
|
||||
break;
|
||||
case ':':
|
||||
token.type_ = tokenMemberSeparator;
|
||||
break;
|
||||
case 0:
|
||||
token.type_ = tokenEndOfStream;
|
||||
break;
|
||||
default:
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if ( !ok )
|
||||
token.type_ = tokenError;
|
||||
token.end_ = current_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::skipSpaces()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
Char c = *current_;
|
||||
if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
|
||||
++current_;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::match( Location pattern,
|
||||
int patternLength )
|
||||
{
|
||||
if ( end_ - current_ < patternLength )
|
||||
return false;
|
||||
int index = patternLength;
|
||||
while ( index-- )
|
||||
if ( current_[index] != pattern[index] )
|
||||
return false;
|
||||
current_ += patternLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readComment()
|
||||
{
|
||||
Location commentBegin = current_ - 1;
|
||||
Char c = getNextChar();
|
||||
bool successful = false;
|
||||
if ( c == '*' )
|
||||
successful = readCStyleComment();
|
||||
else if ( c == '/' )
|
||||
successful = readCppStyleComment();
|
||||
if ( !successful )
|
||||
return false;
|
||||
|
||||
if ( collectComments_ )
|
||||
{
|
||||
CommentPlacement placement = commentBefore;
|
||||
if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
|
||||
{
|
||||
if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
|
||||
placement = commentAfterOnSameLine;
|
||||
}
|
||||
|
||||
addComment( commentBegin, current_, placement );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::addComment( Location begin,
|
||||
Location end,
|
||||
CommentPlacement placement )
|
||||
{
|
||||
assert( collectComments_ );
|
||||
if ( placement == commentAfterOnSameLine )
|
||||
{
|
||||
assert( lastValue_ != 0 );
|
||||
lastValue_->setComment( std::string( begin, end ), placement );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !commentsBefore_.empty() )
|
||||
commentsBefore_ += "\n";
|
||||
commentsBefore_ += std::string( begin, end );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readCStyleComment()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
Char c = getNextChar();
|
||||
if ( c == '*' && *current_ == '/' )
|
||||
break;
|
||||
}
|
||||
return getNextChar() == '/';
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readCppStyleComment()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
Char c = getNextChar();
|
||||
if ( c == '\r' || c == '\n' )
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::readNumber()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
if ( !(*current_ >= '0' && *current_ <= '9') &&
|
||||
!in( *current_, '.', 'e', 'E', '+', '-' ) )
|
||||
break;
|
||||
++current_;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::readString()
|
||||
{
|
||||
Char c = 0;
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
c = getNextChar();
|
||||
if ( c == '\\' )
|
||||
getNextChar();
|
||||
else if ( c == '"' )
|
||||
break;
|
||||
}
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readObject( Token &tokenStart )
|
||||
{
|
||||
Token tokenName;
|
||||
std::string name;
|
||||
currentValue() = Value( objectValue );
|
||||
while ( readToken( tokenName ) )
|
||||
{
|
||||
bool initialTokenOk = true;
|
||||
while ( tokenName.type_ == tokenComment && initialTokenOk )
|
||||
initialTokenOk = readToken( tokenName );
|
||||
if ( !initialTokenOk )
|
||||
break;
|
||||
if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
|
||||
return true;
|
||||
if ( tokenName.type_ != tokenString )
|
||||
break;
|
||||
|
||||
name = "";
|
||||
if ( !decodeString( tokenName, name ) )
|
||||
return recoverFromError( tokenObjectEnd );
|
||||
|
||||
Token colon;
|
||||
if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ':' after object member name",
|
||||
colon,
|
||||
tokenObjectEnd );
|
||||
}
|
||||
Value &value = currentValue()[ name ];
|
||||
nodes_.push( &value );
|
||||
bool ok = readValue();
|
||||
nodes_.pop();
|
||||
if ( !ok ) // error already set
|
||||
return recoverFromError( tokenObjectEnd );
|
||||
|
||||
Token comma;
|
||||
if ( !readToken( comma )
|
||||
|| ( comma.type_ != tokenObjectEnd &&
|
||||
comma.type_ != tokenArraySeparator &&
|
||||
comma.type_ != tokenComment ) )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ',' or '}' in object declaration",
|
||||
comma,
|
||||
tokenObjectEnd );
|
||||
}
|
||||
bool finalizeTokenOk = true;
|
||||
while ( comma.type_ == tokenComment &&
|
||||
finalizeTokenOk )
|
||||
finalizeTokenOk = readToken( comma );
|
||||
if ( comma.type_ == tokenObjectEnd )
|
||||
return true;
|
||||
}
|
||||
return addErrorAndRecover( "Missing '}' or object member name",
|
||||
tokenName,
|
||||
tokenObjectEnd );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readArray( Token &tokenStart )
|
||||
{
|
||||
currentValue() = Value( arrayValue );
|
||||
skipSpaces();
|
||||
if ( *current_ == ']' ) // empty array
|
||||
{
|
||||
Token endArray;
|
||||
readToken( endArray );
|
||||
return true;
|
||||
}
|
||||
int index = 0;
|
||||
while ( true )
|
||||
{
|
||||
Value &value = currentValue()[ index++ ];
|
||||
nodes_.push( &value );
|
||||
bool ok = readValue();
|
||||
nodes_.pop();
|
||||
if ( !ok ) // error already set
|
||||
return recoverFromError( tokenArrayEnd );
|
||||
|
||||
Token token;
|
||||
// Accept Comment after last item in the array.
|
||||
ok = readToken( token );
|
||||
while ( token.type_ == tokenComment && ok )
|
||||
{
|
||||
ok = readToken( token );
|
||||
}
|
||||
bool badTokenType = ( token.type_ == tokenArraySeparator &&
|
||||
token.type_ == tokenArrayEnd );
|
||||
if ( !ok || badTokenType )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ',' or ']' in array declaration",
|
||||
token,
|
||||
tokenArrayEnd );
|
||||
}
|
||||
if ( token.type_ == tokenArrayEnd )
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeNumber( Token &token )
|
||||
{
|
||||
bool isDouble = false;
|
||||
for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
|
||||
{
|
||||
isDouble = isDouble
|
||||
|| in( *inspect, '.', 'e', 'E', '+' )
|
||||
|| ( *inspect == '-' && inspect != token.start_ );
|
||||
}
|
||||
if ( isDouble )
|
||||
return decodeDouble( token );
|
||||
Location current = token.start_;
|
||||
bool isNegative = *current == '-';
|
||||
if ( isNegative )
|
||||
++current;
|
||||
Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
|
||||
: Value::maxUInt) / 10;
|
||||
Value::UInt value = 0;
|
||||
while ( current < token.end_ )
|
||||
{
|
||||
Char c = *current++;
|
||||
if ( c < '0' || c > '9' )
|
||||
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||
if ( value >= threshold )
|
||||
return decodeDouble( token );
|
||||
value = value * 10 + Value::UInt(c - '0');
|
||||
}
|
||||
if ( isNegative )
|
||||
currentValue() = -Value::Int( value );
|
||||
else if ( value <= Value::UInt(Value::maxInt) )
|
||||
currentValue() = Value::Int( value );
|
||||
else
|
||||
currentValue() = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeDouble( Token &token )
|
||||
{
|
||||
double value = 0;
|
||||
const int bufferSize = 32;
|
||||
int count;
|
||||
int length = int(token.end_ - token.start_);
|
||||
if ( length <= bufferSize )
|
||||
{
|
||||
Char buffer[bufferSize];
|
||||
memcpy( buffer, token.start_, length );
|
||||
buffer[length] = 0;
|
||||
count = sscanf( buffer, "%lf", &value );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string buffer( token.start_, token.end_ );
|
||||
count = sscanf( buffer.c_str(), "%lf", &value );
|
||||
}
|
||||
|
||||
if ( count != 1 )
|
||||
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||
currentValue() = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeString( Token &token )
|
||||
{
|
||||
std::string decoded;
|
||||
if ( !decodeString( token, decoded ) )
|
||||
return false;
|
||||
currentValue() = decoded;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeString( Token &token, std::string &decoded )
|
||||
{
|
||||
decoded.reserve( token.end_ - token.start_ - 2 );
|
||||
Location current = token.start_ + 1; // skip '"'
|
||||
Location end = token.end_ - 1; // do not include '"'
|
||||
while ( current != end )
|
||||
{
|
||||
Char c = *current++;
|
||||
if ( c == '"' )
|
||||
break;
|
||||
else if ( c == '\\' )
|
||||
{
|
||||
if ( current == end )
|
||||
return addError( "Empty escape sequence in string", token, current );
|
||||
Char escape = *current++;
|
||||
switch ( escape )
|
||||
{
|
||||
case '"': decoded += '"'; break;
|
||||
case '/': decoded += '/'; break;
|
||||
case '\\': decoded += '\\'; break;
|
||||
case 'b': decoded += '\b'; break;
|
||||
case 'f': decoded += '\f'; break;
|
||||
case 'n': decoded += '\n'; break;
|
||||
case 'r': decoded += '\r'; break;
|
||||
case 't': decoded += '\t'; break;
|
||||
case 'u':
|
||||
{
|
||||
unsigned int unicode;
|
||||
if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
|
||||
return false;
|
||||
decoded += codePointToUTF8(unicode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return addError( "Bad escape sequence in string", token, current );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
decoded += c;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::decodeUnicodeCodePoint( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode )
|
||||
{
|
||||
|
||||
if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
|
||||
return false;
|
||||
if (unicode >= 0xD800 && unicode <= 0xDBFF)
|
||||
{
|
||||
// surrogate pairs
|
||||
if (end - current < 6)
|
||||
return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
|
||||
unsigned int surrogatePair;
|
||||
if (*(current++) == '\\' && *(current++)== 'u')
|
||||
{
|
||||
if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
|
||||
{
|
||||
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::decodeUnicodeEscapeSequence( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode )
|
||||
{
|
||||
if ( end - current < 4 )
|
||||
return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
|
||||
unicode = 0;
|
||||
for ( int index =0; index < 4; ++index )
|
||||
{
|
||||
Char c = *current++;
|
||||
unicode *= 16;
|
||||
if ( c >= '0' && c <= '9' )
|
||||
unicode += c - '0';
|
||||
else if ( c >= 'a' && c <= 'f' )
|
||||
unicode += c - 'a' + 10;
|
||||
else if ( c >= 'A' && c <= 'F' )
|
||||
unicode += c - 'A' + 10;
|
||||
else
|
||||
return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::addError( const std::string &message,
|
||||
Token &token,
|
||||
Location extra )
|
||||
{
|
||||
ErrorInfo info;
|
||||
info.token_ = token;
|
||||
info.message_ = message;
|
||||
info.extra_ = extra;
|
||||
errors_.push_back( info );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::recoverFromError( TokenType skipUntilToken )
|
||||
{
|
||||
int errorCount = int(errors_.size());
|
||||
Token skip;
|
||||
while ( true )
|
||||
{
|
||||
if ( !readToken(skip) )
|
||||
errors_.resize( errorCount ); // discard errors caused by recovery
|
||||
if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
|
||||
break;
|
||||
}
|
||||
errors_.resize( errorCount );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::addErrorAndRecover( const std::string &message,
|
||||
Token &token,
|
||||
TokenType skipUntilToken )
|
||||
{
|
||||
addError( message, token );
|
||||
return recoverFromError( skipUntilToken );
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
Reader::currentValue()
|
||||
{
|
||||
return *(nodes_.top());
|
||||
}
|
||||
|
||||
|
||||
Reader::Char
|
||||
Reader::getNextChar()
|
||||
{
|
||||
if ( current_ == end_ )
|
||||
return 0;
|
||||
return *current_++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::getLocationLineAndColumn( Location location,
|
||||
int &line,
|
||||
int &column ) const
|
||||
{
|
||||
Location current = begin_;
|
||||
Location lastLineStart = current;
|
||||
line = 0;
|
||||
while ( current < location && current != end_ )
|
||||
{
|
||||
Char c = *current++;
|
||||
if ( c == '\r' )
|
||||
{
|
||||
if ( *current == '\n' )
|
||||
++current;
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
}
|
||||
else if ( c == '\n' )
|
||||
{
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
}
|
||||
}
|
||||
// column & line start at 1
|
||||
column = int(location - lastLineStart) + 1;
|
||||
++line;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Reader::getLocationLineAndColumn( Location location ) const
|
||||
{
|
||||
int line, column;
|
||||
getLocationLineAndColumn( location, line, column );
|
||||
char buffer[18+16+16+1];
|
||||
sprintf( buffer, "Line %d, Column %d", line, column );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Reader::getFormatedErrorMessages() const
|
||||
{
|
||||
std::string formattedMessage;
|
||||
for ( Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end();
|
||||
++itError )
|
||||
{
|
||||
const ErrorInfo &error = *itError;
|
||||
formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
|
||||
formattedMessage += " " + error.message_ + "\n";
|
||||
if ( error.extra_ )
|
||||
formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
|
||||
}
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
|
||||
std::istream& operator>>( std::istream &sin, Value &root )
|
||||
{
|
||||
Json::Reader reader;
|
||||
bool ok = reader.parse(sin, root, true);
|
||||
//JSON_ASSERT( ok );
|
||||
if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
|
||||
return sin;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Json
|
1718
thirdparty/jsoncpp/src/lib_json/json_value.cpp
vendored
1718
thirdparty/jsoncpp/src/lib_json/json_value.cpp
vendored
File diff suppressed because it is too large
Load Diff
@ -1,292 +0,0 @@
|
||||
// included by json_value.cpp
|
||||
// everything is within Json namespace
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueIteratorBase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase()
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
: current_()
|
||||
, isNull_( true )
|
||||
{
|
||||
}
|
||||
#else
|
||||
: isArray_( true )
|
||||
, isNull_( true )
|
||||
{
|
||||
iterator_.array_ = ValueInternalArray::IteratorState();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t )
|
||||
: current_( current )
|
||||
, isNull_( false )
|
||||
{
|
||||
}
|
||||
#else
|
||||
ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
|
||||
: isArray_( true )
|
||||
{
|
||||
iterator_.array_ = state;
|
||||
}
|
||||
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
|
||||
: isArray_( false )
|
||||
{
|
||||
iterator_.map_ = state;
|
||||
}
|
||||
#endif
|
||||
|
||||
Value &
|
||||
ValueIteratorBase::deref() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
return current_->second;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::dereference( iterator_.array_ );
|
||||
return ValueInternalMap::value( iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueIteratorBase::increment()
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
++current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
ValueInternalArray::increment( iterator_.array_ );
|
||||
ValueInternalMap::increment( iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueIteratorBase::decrement()
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
--current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
ValueInternalArray::decrement( iterator_.array_ );
|
||||
ValueInternalMap::decrement( iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ValueIteratorBase::difference_type
|
||||
ValueIteratorBase::computeDistance( const SelfType &other ) const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
# ifdef JSON_USE_CPPTL_SMALLMAP
|
||||
return current_ - other.current_;
|
||||
# else
|
||||
// Iterator for null value are initialized using the default
|
||||
// constructor, which initialize current_ to the default
|
||||
// std::map::iterator. As begin() and end() are two instance
|
||||
// of the default std::map::iterator, they can not be compared.
|
||||
// To allow this, we handle this comparison specifically.
|
||||
if ( isNull_ && other.isNull_ )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
|
||||
// which is the one used by default).
|
||||
// Using a portable hand-made version for non random iterator instead:
|
||||
// return difference_type( std::distance( current_, other.current_ ) );
|
||||
difference_type myDistance = 0;
|
||||
for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
|
||||
{
|
||||
++myDistance;
|
||||
}
|
||||
return myDistance;
|
||||
# endif
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
|
||||
return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ValueIteratorBase::isEqual( const SelfType &other ) const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
if ( isNull_ )
|
||||
{
|
||||
return other.isNull_;
|
||||
}
|
||||
return current_ == other.current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
|
||||
return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueIteratorBase::copy( const SelfType &other )
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
current_ = other.current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
iterator_.array_ = other.iterator_.array_;
|
||||
iterator_.map_ = other.iterator_.map_;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Value
|
||||
ValueIteratorBase::key() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if ( czstring.c_str() )
|
||||
{
|
||||
if ( czstring.isStaticString() )
|
||||
return Value( StaticString( czstring.c_str() ) );
|
||||
return Value( czstring.c_str() );
|
||||
}
|
||||
return Value( czstring.index() );
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||
bool isStatic;
|
||||
const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
|
||||
if ( isStatic )
|
||||
return Value( StaticString( memberName ) );
|
||||
return Value( memberName );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
UInt
|
||||
ValueIteratorBase::index() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if ( !czstring.c_str() )
|
||||
return czstring.index();
|
||||
return Value::UInt( -1 );
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||
return Value::UInt( -1 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ValueIteratorBase::memberName() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
const char *name = (*current_).first.c_str();
|
||||
return name ? name : "";
|
||||
#else
|
||||
if ( !isArray_ )
|
||||
return ValueInternalMap::key( iterator_.map_ );
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueConstIterator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueConstIterator::ValueConstIterator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t )
|
||||
: ValueIteratorBase( current )
|
||||
{
|
||||
}
|
||||
#else
|
||||
ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
|
||||
ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
ValueConstIterator &
|
||||
ValueConstIterator::operator =( const ValueIteratorBase &other )
|
||||
{
|
||||
copy( other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueIterator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIterator::ValueIterator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t )
|
||||
: ValueIteratorBase( current )
|
||||
{
|
||||
}
|
||||
#else
|
||||
ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
ValueIterator::ValueIterator( const ValueConstIterator &other )
|
||||
: ValueIteratorBase( other )
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator( const ValueIterator &other )
|
||||
: ValueIteratorBase( other )
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator &
|
||||
ValueIterator::operator =( const SelfType &other )
|
||||
{
|
||||
copy( other );
|
||||
return *this;
|
||||
}
|
829
thirdparty/jsoncpp/src/lib_json/json_writer.cpp
vendored
829
thirdparty/jsoncpp/src/lib_json/json_writer.cpp
vendored
@ -1,829 +0,0 @@
|
||||
#include <json/writer.h>
|
||||
#include <utility>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#if _MSC_VER >= 1400 // VC++ 8.0
|
||||
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||
#endif
|
||||
|
||||
namespace Json {
|
||||
|
||||
static bool isControlCharacter(char ch)
|
||||
{
|
||||
return ch > 0 && ch <= 0x1F;
|
||||
}
|
||||
|
||||
static bool containsControlCharacter( const char* str )
|
||||
{
|
||||
while ( *str )
|
||||
{
|
||||
if ( isControlCharacter( *(str++) ) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static void uintToString( unsigned int value,
|
||||
char *¤t )
|
||||
{
|
||||
*--current = 0;
|
||||
do
|
||||
{
|
||||
*--current = (value % 10) + '0';
|
||||
value /= 10;
|
||||
}
|
||||
while ( value != 0 );
|
||||
}
|
||||
|
||||
std::string valueToString( Int value )
|
||||
{
|
||||
char buffer[32];
|
||||
char *current = buffer + sizeof(buffer);
|
||||
bool isNegative = value < 0;
|
||||
if ( isNegative )
|
||||
value = -value;
|
||||
uintToString( UInt(value), current );
|
||||
if ( isNegative )
|
||||
*--current = '-';
|
||||
assert( current >= buffer );
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( UInt value )
|
||||
{
|
||||
char buffer[32];
|
||||
char *current = buffer + sizeof(buffer);
|
||||
uintToString( value, current );
|
||||
assert( current >= buffer );
|
||||
return current;
|
||||
}
|
||||
|
||||
std::string valueToString( double value )
|
||||
{
|
||||
char buffer[32];
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
|
||||
sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
|
||||
#else
|
||||
sprintf(buffer, "%#.16g", value);
|
||||
#endif
|
||||
char* ch = buffer + strlen(buffer) - 1;
|
||||
if (*ch != '0') return buffer; // nothing to truncate, so save time
|
||||
while(ch > buffer && *ch == '0'){
|
||||
--ch;
|
||||
}
|
||||
char* last_nonzero = ch;
|
||||
while(ch >= buffer){
|
||||
switch(*ch){
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
--ch;
|
||||
continue;
|
||||
case '.':
|
||||
// Truncate zeroes to save bytes in output, but keep one.
|
||||
*(last_nonzero+2) = '\0';
|
||||
return buffer;
|
||||
default:
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( bool value )
|
||||
{
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
std::string valueToQuotedString( const char *value )
|
||||
{
|
||||
// Not sure how to handle unicode...
|
||||
if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
|
||||
return std::string("\"") + value + "\"";
|
||||
// We have to walk value and escape any special characters.
|
||||
// Appending to std::string is not efficient, but this should be rare.
|
||||
// (Note: forward slashes are *not* rare, but I am not escaping them.)
|
||||
unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
|
||||
std::string result;
|
||||
result.reserve(maxsize); // to avoid lots of mallocs
|
||||
result += "\"";
|
||||
for (const char* c=value; *c != 0; ++c)
|
||||
{
|
||||
switch(*c)
|
||||
{
|
||||
case '\"':
|
||||
result += "\\\"";
|
||||
break;
|
||||
case '\\':
|
||||
result += "\\\\";
|
||||
break;
|
||||
case '\b':
|
||||
result += "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
result += "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
result += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
result += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
result += "\\t";
|
||||
break;
|
||||
//case '/':
|
||||
// Even though \/ is considered a legal escape in JSON, a bare
|
||||
// slash is also legal, so I see no reason to escape it.
|
||||
// (I hope I am not misunderstanding something.
|
||||
// blep notes: actually escaping \/ may be useful in javascript to avoid </
|
||||
// sequence.
|
||||
// Should add a flag to allow this compatibility mode and prevent this
|
||||
// sequence from occurring.
|
||||
default:
|
||||
if ( isControlCharacter( *c ) )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
|
||||
result += oss.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
result += *c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
result += "\"";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Class Writer
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
Writer::~Writer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Class FastWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
FastWriter::FastWriter()
|
||||
: yamlCompatiblityEnabled_( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FastWriter::enableYAMLCompatibility()
|
||||
{
|
||||
yamlCompatiblityEnabled_ = true;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
FastWriter::write( const Value &root )
|
||||
{
|
||||
document_ = "";
|
||||
writeValue( root );
|
||||
document_ += "\n";
|
||||
return document_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FastWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case nullValue:
|
||||
document_ += "null";
|
||||
break;
|
||||
case intValue:
|
||||
document_ += valueToString( value.asInt() );
|
||||
break;
|
||||
case uintValue:
|
||||
document_ += valueToString( value.asUInt() );
|
||||
break;
|
||||
case realValue:
|
||||
document_ += valueToString( value.asDouble() );
|
||||
break;
|
||||
case stringValue:
|
||||
document_ += valueToQuotedString( value.asCString() );
|
||||
break;
|
||||
case booleanValue:
|
||||
document_ += valueToString( value.asBool() );
|
||||
break;
|
||||
case arrayValue:
|
||||
{
|
||||
document_ += "[";
|
||||
int size = value.size();
|
||||
for ( int index =0; index < size; ++index )
|
||||
{
|
||||
if ( index > 0 )
|
||||
document_ += ",";
|
||||
writeValue( value[index] );
|
||||
}
|
||||
document_ += "]";
|
||||
}
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
Value::Members members( value.getMemberNames() );
|
||||
document_ += "{";
|
||||
for ( Value::Members::iterator it = members.begin();
|
||||
it != members.end();
|
||||
++it )
|
||||
{
|
||||
const std::string &name = *it;
|
||||
if ( it != members.begin() )
|
||||
document_ += ",";
|
||||
document_ += valueToQuotedString( name.c_str() );
|
||||
document_ += yamlCompatiblityEnabled_ ? ": "
|
||||
: ":";
|
||||
writeValue( value[name] );
|
||||
}
|
||||
document_ += "}";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Class StyledWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledWriter::StyledWriter()
|
||||
: rightMargin_( 74 )
|
||||
, indentSize_( 3 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledWriter::write( const Value &root )
|
||||
{
|
||||
document_ = "";
|
||||
addChildValues_ = false;
|
||||
indentString_ = "";
|
||||
writeCommentBeforeValue( root );
|
||||
writeValue( root );
|
||||
writeCommentAfterValueOnSameLine( root );
|
||||
document_ += "\n";
|
||||
return document_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case nullValue:
|
||||
pushValue( "null" );
|
||||
break;
|
||||
case intValue:
|
||||
pushValue( valueToString( value.asInt() ) );
|
||||
break;
|
||||
case uintValue:
|
||||
pushValue( valueToString( value.asUInt() ) );
|
||||
break;
|
||||
case realValue:
|
||||
pushValue( valueToString( value.asDouble() ) );
|
||||
break;
|
||||
case stringValue:
|
||||
pushValue( valueToQuotedString( value.asCString() ) );
|
||||
break;
|
||||
case booleanValue:
|
||||
pushValue( valueToString( value.asBool() ) );
|
||||
break;
|
||||
case arrayValue:
|
||||
writeArrayValue( value);
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
Value::Members members( value.getMemberNames() );
|
||||
if ( members.empty() )
|
||||
pushValue( "{}" );
|
||||
else
|
||||
{
|
||||
writeWithIndent( "{" );
|
||||
indent();
|
||||
Value::Members::iterator it = members.begin();
|
||||
while ( true )
|
||||
{
|
||||
const std::string &name = *it;
|
||||
const Value &childValue = value[name];
|
||||
writeCommentBeforeValue( childValue );
|
||||
writeWithIndent( valueToQuotedString( name.c_str() ) );
|
||||
document_ += " : ";
|
||||
writeValue( childValue );
|
||||
if ( ++it == members.end() )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
document_ += ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "}" );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeArrayValue( const Value &value )
|
||||
{
|
||||
unsigned size = value.size();
|
||||
if ( size == 0 )
|
||||
pushValue( "[]" );
|
||||
else
|
||||
{
|
||||
bool isArrayMultiLine = isMultineArray( value );
|
||||
if ( isArrayMultiLine )
|
||||
{
|
||||
writeWithIndent( "[" );
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index =0;
|
||||
while ( true )
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
writeCommentBeforeValue( childValue );
|
||||
if ( hasChildValue )
|
||||
writeWithIndent( childValues_[index] );
|
||||
else
|
||||
{
|
||||
writeIndent();
|
||||
writeValue( childValue );
|
||||
}
|
||||
if ( ++index == size )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
document_ += ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "]" );
|
||||
}
|
||||
else // output on a single line
|
||||
{
|
||||
assert( childValues_.size() == size );
|
||||
document_ += "[ ";
|
||||
for ( unsigned index =0; index < size; ++index )
|
||||
{
|
||||
if ( index > 0 )
|
||||
document_ += ", ";
|
||||
document_ += childValues_[index];
|
||||
}
|
||||
document_ += " ]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledWriter::isMultineArray( const Value &value )
|
||||
{
|
||||
int size = value.size();
|
||||
bool isMultiLine = size*3 >= rightMargin_ ;
|
||||
childValues_.clear();
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
( (childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0 );
|
||||
}
|
||||
if ( !isMultiLine ) // check if line length > max line length
|
||||
{
|
||||
childValues_.reserve( size );
|
||||
addChildValues_ = true;
|
||||
int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
writeValue( value[index] );
|
||||
lineLength += int( childValues_[index].length() );
|
||||
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
|
||||
}
|
||||
addChildValues_ = false;
|
||||
isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
||||
}
|
||||
return isMultiLine;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::pushValue( const std::string &value )
|
||||
{
|
||||
if ( addChildValues_ )
|
||||
childValues_.push_back( value );
|
||||
else
|
||||
document_ += value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeIndent()
|
||||
{
|
||||
if ( !document_.empty() )
|
||||
{
|
||||
char last = document_[document_.length()-1];
|
||||
if ( last == ' ' ) // already indented
|
||||
return;
|
||||
if ( last != '\n' ) // Comments may add new-line
|
||||
document_ += '\n';
|
||||
}
|
||||
document_ += indentString_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeWithIndent( const std::string &value )
|
||||
{
|
||||
writeIndent();
|
||||
document_ += value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::indent()
|
||||
{
|
||||
indentString_ += std::string( indentSize_, ' ' );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::unindent()
|
||||
{
|
||||
assert( int(indentString_.size()) >= indentSize_ );
|
||||
indentString_.resize( indentString_.size() - indentSize_ );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeCommentBeforeValue( const Value &root )
|
||||
{
|
||||
if ( !root.hasComment( commentBefore ) )
|
||||
return;
|
||||
document_ += normalizeEOL( root.getComment( commentBefore ) );
|
||||
document_ += "\n";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||
{
|
||||
if ( root.hasComment( commentAfterOnSameLine ) )
|
||||
document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
|
||||
|
||||
if ( root.hasComment( commentAfter ) )
|
||||
{
|
||||
document_ += "\n";
|
||||
document_ += normalizeEOL( root.getComment( commentAfter ) );
|
||||
document_ += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledWriter::hasCommentForValue( const Value &value )
|
||||
{
|
||||
return value.hasComment( commentBefore )
|
||||
|| value.hasComment( commentAfterOnSameLine )
|
||||
|| value.hasComment( commentAfter );
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledWriter::normalizeEOL( const std::string &text )
|
||||
{
|
||||
std::string normalized;
|
||||
normalized.reserve( text.length() );
|
||||
const char *begin = text.c_str();
|
||||
const char *end = begin + text.length();
|
||||
const char *current = begin;
|
||||
while ( current != end )
|
||||
{
|
||||
char c = *current++;
|
||||
if ( c == '\r' ) // mac or dos EOL
|
||||
{
|
||||
if ( *current == '\n' ) // convert dos EOL
|
||||
++current;
|
||||
normalized += '\n';
|
||||
}
|
||||
else // handle unix EOL & other char
|
||||
normalized += c;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
// Class StyledStreamWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledStreamWriter::StyledStreamWriter( std::string indentation )
|
||||
: document_(NULL)
|
||||
, rightMargin_( 74 )
|
||||
, indentation_( indentation )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::write( std::ostream &out, const Value &root )
|
||||
{
|
||||
document_ = &out;
|
||||
addChildValues_ = false;
|
||||
indentString_ = "";
|
||||
writeCommentBeforeValue( root );
|
||||
writeValue( root );
|
||||
writeCommentAfterValueOnSameLine( root );
|
||||
*document_ << "\n";
|
||||
document_ = NULL; // Forget the stream, for safety.
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case nullValue:
|
||||
pushValue( "null" );
|
||||
break;
|
||||
case intValue:
|
||||
pushValue( valueToString( value.asInt() ) );
|
||||
break;
|
||||
case uintValue:
|
||||
pushValue( valueToString( value.asUInt() ) );
|
||||
break;
|
||||
case realValue:
|
||||
pushValue( valueToString( value.asDouble() ) );
|
||||
break;
|
||||
case stringValue:
|
||||
pushValue( valueToQuotedString( value.asCString() ) );
|
||||
break;
|
||||
case booleanValue:
|
||||
pushValue( valueToString( value.asBool() ) );
|
||||
break;
|
||||
case arrayValue:
|
||||
writeArrayValue( value);
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
Value::Members members( value.getMemberNames() );
|
||||
if ( members.empty() )
|
||||
pushValue( "{}" );
|
||||
else
|
||||
{
|
||||
writeWithIndent( "{" );
|
||||
indent();
|
||||
Value::Members::iterator it = members.begin();
|
||||
while ( true )
|
||||
{
|
||||
const std::string &name = *it;
|
||||
const Value &childValue = value[name];
|
||||
writeCommentBeforeValue( childValue );
|
||||
writeWithIndent( valueToQuotedString( name.c_str() ) );
|
||||
*document_ << " : ";
|
||||
writeValue( childValue );
|
||||
if ( ++it == members.end() )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
*document_ << ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "}" );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeArrayValue( const Value &value )
|
||||
{
|
||||
unsigned size = value.size();
|
||||
if ( size == 0 )
|
||||
pushValue( "[]" );
|
||||
else
|
||||
{
|
||||
bool isArrayMultiLine = isMultineArray( value );
|
||||
if ( isArrayMultiLine )
|
||||
{
|
||||
writeWithIndent( "[" );
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index =0;
|
||||
while ( true )
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
writeCommentBeforeValue( childValue );
|
||||
if ( hasChildValue )
|
||||
writeWithIndent( childValues_[index] );
|
||||
else
|
||||
{
|
||||
writeIndent();
|
||||
writeValue( childValue );
|
||||
}
|
||||
if ( ++index == size )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
*document_ << ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "]" );
|
||||
}
|
||||
else // output on a single line
|
||||
{
|
||||
assert( childValues_.size() == size );
|
||||
*document_ << "[ ";
|
||||
for ( unsigned index =0; index < size; ++index )
|
||||
{
|
||||
if ( index > 0 )
|
||||
*document_ << ", ";
|
||||
*document_ << childValues_[index];
|
||||
}
|
||||
*document_ << " ]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledStreamWriter::isMultineArray( const Value &value )
|
||||
{
|
||||
int size = value.size();
|
||||
bool isMultiLine = size*3 >= rightMargin_ ;
|
||||
childValues_.clear();
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
( (childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0 );
|
||||
}
|
||||
if ( !isMultiLine ) // check if line length > max line length
|
||||
{
|
||||
childValues_.reserve( size );
|
||||
addChildValues_ = true;
|
||||
int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
writeValue( value[index] );
|
||||
lineLength += int( childValues_[index].length() );
|
||||
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
|
||||
}
|
||||
addChildValues_ = false;
|
||||
isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
||||
}
|
||||
return isMultiLine;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::pushValue( const std::string &value )
|
||||
{
|
||||
if ( addChildValues_ )
|
||||
childValues_.push_back( value );
|
||||
else
|
||||
*document_ << value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeIndent()
|
||||
{
|
||||
/*
|
||||
Some comments in this method would have been nice. ;-)
|
||||
|
||||
if ( !document_.empty() )
|
||||
{
|
||||
char last = document_[document_.length()-1];
|
||||
if ( last == ' ' ) // already indented
|
||||
return;
|
||||
if ( last != '\n' ) // Comments may add new-line
|
||||
*document_ << '\n';
|
||||
}
|
||||
*/
|
||||
*document_ << '\n' << indentString_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeWithIndent( const std::string &value )
|
||||
{
|
||||
writeIndent();
|
||||
*document_ << value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::indent()
|
||||
{
|
||||
indentString_ += indentation_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::unindent()
|
||||
{
|
||||
assert( indentString_.size() >= indentation_.size() );
|
||||
indentString_.resize( indentString_.size() - indentation_.size() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeCommentBeforeValue( const Value &root )
|
||||
{
|
||||
if ( !root.hasComment( commentBefore ) )
|
||||
return;
|
||||
*document_ << normalizeEOL( root.getComment( commentBefore ) );
|
||||
*document_ << "\n";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||
{
|
||||
if ( root.hasComment( commentAfterOnSameLine ) )
|
||||
*document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
|
||||
|
||||
if ( root.hasComment( commentAfter ) )
|
||||
{
|
||||
*document_ << "\n";
|
||||
*document_ << normalizeEOL( root.getComment( commentAfter ) );
|
||||
*document_ << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledStreamWriter::hasCommentForValue( const Value &value )
|
||||
{
|
||||
return value.hasComment( commentBefore )
|
||||
|| value.hasComment( commentAfterOnSameLine )
|
||||
|| value.hasComment( commentAfter );
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledStreamWriter::normalizeEOL( const std::string &text )
|
||||
{
|
||||
std::string normalized;
|
||||
normalized.reserve( text.length() );
|
||||
const char *begin = text.c_str();
|
||||
const char *end = begin + text.length();
|
||||
const char *current = begin;
|
||||
while ( current != end )
|
||||
{
|
||||
char c = *current++;
|
||||
if ( c == '\r' ) // mac or dos EOL
|
||||
{
|
||||
if ( *current == '\n' ) // convert dos EOL
|
||||
++current;
|
||||
normalized += '\n';
|
||||
}
|
||||
else // handle unix EOL & other char
|
||||
normalized += c;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream &sout, const Value &root )
|
||||
{
|
||||
Json::StyledStreamWriter writer;
|
||||
writer.write(sout, root);
|
||||
return sout;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Json
|
8
thirdparty/jsoncpp/src/lib_json/sconscript
vendored
8
thirdparty/jsoncpp/src/lib_json/sconscript
vendored
@ -1,8 +0,0 @@
|
||||
Import( 'env buildLibrary' )
|
||||
|
||||
buildLibrary( env, Split( """
|
||||
json_reader.cpp
|
||||
json_value.cpp
|
||||
json_writer.cpp
|
||||
""" ),
|
||||
'json' )
|
603
thirdparty/jsoncpp/src/test_lib_json/jsontest.cpp
vendored
603
thirdparty/jsoncpp/src/test_lib_json/jsontest.cpp
vendored
@ -1,603 +0,0 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC
|
||||
#include "jsontest.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Used to install a report hook that prevent dialog on assertion and error.
|
||||
# include <crtdbg.h>
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Used to prevent dialog on memory fault.
|
||||
// Limits headers included by Windows.h
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOSERVICE
|
||||
# define NOMCX
|
||||
# define NOIME
|
||||
# define NOSOUND
|
||||
# define NOCOMM
|
||||
# define NORPC
|
||||
# define NOGDI
|
||||
# define NOUSER
|
||||
# define NODRIVERS
|
||||
# define NOLOGERROR
|
||||
# define NOPROFILER
|
||||
# define NOMEMMGR
|
||||
# define NOLFILEIO
|
||||
# define NOOPENFILE
|
||||
# define NORESOURCE
|
||||
# define NOATOM
|
||||
# define NOLANGUAGE
|
||||
# define NOLSTRING
|
||||
# define NODBCS
|
||||
# define NOKEYBOARDINFO
|
||||
# define NOGDICAPMASKS
|
||||
# define NOCOLOR
|
||||
# define NOGDIOBJ
|
||||
# define NODRAWTEXT
|
||||
# define NOTEXTMETRIC
|
||||
# define NOSCALABLEFONT
|
||||
# define NOBITMAP
|
||||
# define NORASTEROPS
|
||||
# define NOMETAFILE
|
||||
# define NOSYSMETRICS
|
||||
# define NOSYSTEMPARAMSINFO
|
||||
# define NOMSG
|
||||
# define NOWINSTYLES
|
||||
# define NOWINOFFSETS
|
||||
# define NOSHOWWINDOW
|
||||
# define NODEFERWINDOWPOS
|
||||
# define NOVIRTUALKEYCODES
|
||||
# define NOKEYSTATES
|
||||
# define NOWH
|
||||
# define NOMENUS
|
||||
# define NOSCROLL
|
||||
# define NOCLIPBOARD
|
||||
# define NOICONS
|
||||
# define NOMB
|
||||
# define NOSYSCOMMANDS
|
||||
# define NOMDI
|
||||
# define NOCTLMGR
|
||||
# define NOWINMESSAGES
|
||||
# include <windows.h>
|
||||
#endif // if defined(_WIN32)
|
||||
|
||||
namespace JsonTest {
|
||||
|
||||
|
||||
// class TestResult
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult::TestResult()
|
||||
: predicateId_( 1 )
|
||||
, lastUsedPredicateId_( 0 )
|
||||
, messageTarget_( 0 )
|
||||
{
|
||||
// The root predicate has id 0
|
||||
rootPredicateNode_.id_ = 0;
|
||||
rootPredicateNode_.next_ = 0;
|
||||
predicateStackTail_ = &rootPredicateNode_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::setTestName( const std::string &name )
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
TestResult &
|
||||
TestResult::addFailure( const char *file, unsigned int line,
|
||||
const char *expr )
|
||||
{
|
||||
/// Walks the PredicateContext stack adding them to failures_ if not already added.
|
||||
unsigned int nestingLevel = 0;
|
||||
PredicateContext *lastNode = rootPredicateNode_.next_;
|
||||
for ( ; lastNode != 0; lastNode = lastNode->next_ )
|
||||
{
|
||||
if ( lastNode->id_ > lastUsedPredicateId_ ) // new PredicateContext
|
||||
{
|
||||
lastUsedPredicateId_ = lastNode->id_;
|
||||
addFailureInfo( lastNode->file_, lastNode->line_, lastNode->expr_,
|
||||
nestingLevel );
|
||||
// Link the PredicateContext to the failure for message target when
|
||||
// popping the PredicateContext.
|
||||
lastNode->failure_ = &( failures_.back() );
|
||||
}
|
||||
++nestingLevel;
|
||||
}
|
||||
|
||||
// Adds the failed assertion
|
||||
addFailureInfo( file, line, expr, nestingLevel );
|
||||
messageTarget_ = &( failures_.back() );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::addFailureInfo( const char *file, unsigned int line,
|
||||
const char *expr, unsigned int nestingLevel )
|
||||
{
|
||||
Failure failure;
|
||||
failure.file_ = file;
|
||||
failure.line_ = line;
|
||||
if ( expr )
|
||||
{
|
||||
failure.expr_ = expr;
|
||||
}
|
||||
failure.nestingLevel_ = nestingLevel;
|
||||
failures_.push_back( failure );
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::popPredicateContext()
|
||||
{
|
||||
PredicateContext *lastNode = &rootPredicateNode_;
|
||||
while ( lastNode->next_ != 0 && lastNode->next_->next_ != 0 )
|
||||
{
|
||||
lastNode = lastNode->next_;
|
||||
}
|
||||
// Set message target to popped failure
|
||||
PredicateContext *tail = lastNode->next_;
|
||||
if ( tail != 0 && tail->failure_ != 0 )
|
||||
{
|
||||
messageTarget_ = tail->failure_;
|
||||
}
|
||||
// Remove tail from list
|
||||
predicateStackTail_ = lastNode;
|
||||
lastNode->next_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TestResult::failed() const
|
||||
{
|
||||
return !failures_.empty();
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
TestResult::getAssertionNestingLevel() const
|
||||
{
|
||||
unsigned int level = 0;
|
||||
const PredicateContext *lastNode = &rootPredicateNode_;
|
||||
while ( lastNode->next_ != 0 )
|
||||
{
|
||||
lastNode = lastNode->next_;
|
||||
++level;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::printFailure( bool printTestName ) const
|
||||
{
|
||||
if ( failures_.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( printTestName )
|
||||
{
|
||||
printf( "* Detail of %s test failure:\n", name_.c_str() );
|
||||
}
|
||||
|
||||
// Print in reverse to display the callstack in the right order
|
||||
Failures::const_iterator itEnd = failures_.end();
|
||||
for ( Failures::const_iterator it = failures_.begin(); it != itEnd; ++it )
|
||||
{
|
||||
const Failure &failure = *it;
|
||||
std::string indent( failure.nestingLevel_ * 2, ' ' );
|
||||
if ( failure.file_ )
|
||||
{
|
||||
printf( "%s%s(%d): ", indent.c_str(), failure.file_, failure.line_ );
|
||||
}
|
||||
if ( !failure.expr_.empty() )
|
||||
{
|
||||
printf( "%s\n", failure.expr_.c_str() );
|
||||
}
|
||||
else if ( failure.file_ )
|
||||
{
|
||||
printf( "\n" );
|
||||
}
|
||||
if ( !failure.message_.empty() )
|
||||
{
|
||||
std::string reindented = indentText( failure.message_, indent + " " );
|
||||
printf( "%s\n", reindented.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
TestResult::indentText( const std::string &text,
|
||||
const std::string &indent )
|
||||
{
|
||||
std::string reindented;
|
||||
std::string::size_type lastIndex = 0;
|
||||
while ( lastIndex < text.size() )
|
||||
{
|
||||
std::string::size_type nextIndex = text.find( '\n', lastIndex );
|
||||
if ( nextIndex == std::string::npos )
|
||||
{
|
||||
nextIndex = text.size() - 1;
|
||||
}
|
||||
reindented += indent;
|
||||
reindented += text.substr( lastIndex, nextIndex - lastIndex + 1 );
|
||||
lastIndex = nextIndex + 1;
|
||||
}
|
||||
return reindented;
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::addToLastFailure( const std::string &message )
|
||||
{
|
||||
if ( messageTarget_ != 0 )
|
||||
{
|
||||
messageTarget_->message_ += message;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( bool value )
|
||||
{
|
||||
return addToLastFailure( value ? "true" : "false" );
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( int value )
|
||||
{
|
||||
char buffer[32];
|
||||
sprintf( buffer, "%d", value );
|
||||
return addToLastFailure( buffer );
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( unsigned int value )
|
||||
{
|
||||
char buffer[32];
|
||||
sprintf( buffer, "%u", value );
|
||||
return addToLastFailure( buffer );
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( double value )
|
||||
{
|
||||
char buffer[32];
|
||||
sprintf( buffer, "%16g", value );
|
||||
return addToLastFailure( buffer );
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( const char *value )
|
||||
{
|
||||
return addToLastFailure( value ? value
|
||||
: "<NULL>" );
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( const std::string &value )
|
||||
{
|
||||
return addToLastFailure( value );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// class TestCase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestCase::TestCase()
|
||||
: result_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TestCase::~TestCase()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestCase::run( TestResult &result )
|
||||
{
|
||||
result_ = &result;
|
||||
runTestCase();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// class Runner
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Runner::Runner()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Runner &
|
||||
Runner::add( TestCaseFactory factory )
|
||||
{
|
||||
tests_.push_back( factory );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
Runner::testCount() const
|
||||
{
|
||||
return static_cast<unsigned int>( tests_.size() );
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Runner::testNameAt( unsigned int index ) const
|
||||
{
|
||||
TestCase *test = tests_[index]();
|
||||
std::string name = test->testName();
|
||||
delete test;
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Runner::runTestAt( unsigned int index, TestResult &result ) const
|
||||
{
|
||||
TestCase *test = tests_[index]();
|
||||
result.setTestName( test->testName() );
|
||||
printf( "Testing %s: ", test->testName() );
|
||||
fflush( stdout );
|
||||
#if JSON_USE_EXCEPTION
|
||||
try
|
||||
{
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
test->run( result );
|
||||
#if JSON_USE_EXCEPTION
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
result.addFailure( __FILE__, __LINE__,
|
||||
"Unexpected exception caugth:" ) << e.what();
|
||||
}
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
delete test;
|
||||
const char *status = result.failed() ? "FAILED"
|
||||
: "OK";
|
||||
printf( "%s\n", status );
|
||||
fflush( stdout );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Runner::runAllTest( bool printSummary ) const
|
||||
{
|
||||
unsigned int count = testCount();
|
||||
std::deque<TestResult> failures;
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
TestResult result;
|
||||
runTestAt( index, result );
|
||||
if ( result.failed() )
|
||||
{
|
||||
failures.push_back( result );
|
||||
}
|
||||
}
|
||||
|
||||
if ( failures.empty() )
|
||||
{
|
||||
if ( printSummary )
|
||||
{
|
||||
printf( "All %d tests passed\n", count );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( unsigned int index = 0; index < failures.size(); ++index )
|
||||
{
|
||||
TestResult &result = failures[index];
|
||||
result.printFailure( count > 1 );
|
||||
}
|
||||
|
||||
if ( printSummary )
|
||||
{
|
||||
unsigned int failedCount = static_cast<unsigned int>( failures.size() );
|
||||
unsigned int passedCount = count - failedCount;
|
||||
printf( "%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Runner::testIndex( const std::string &testName,
|
||||
unsigned int &indexOut ) const
|
||||
{
|
||||
unsigned int count = testCount();
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
if ( testNameAt(index) == testName )
|
||||
{
|
||||
indexOut = index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Runner::listTests() const
|
||||
{
|
||||
unsigned int count = testCount();
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
printf( "%s\n", testNameAt( index ).c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Runner::runCommandLine( int argc, const char *argv[] ) const
|
||||
{
|
||||
typedef std::deque<std::string> TestNames;
|
||||
Runner subrunner;
|
||||
for ( int index = 1; index < argc; ++index )
|
||||
{
|
||||
std::string opt = argv[index];
|
||||
if ( opt == "--list-tests" )
|
||||
{
|
||||
listTests();
|
||||
return 0;
|
||||
}
|
||||
else if ( opt == "--test-auto" )
|
||||
{
|
||||
preventDialogOnCrash();
|
||||
}
|
||||
else if ( opt == "--test" )
|
||||
{
|
||||
++index;
|
||||
if ( index < argc )
|
||||
{
|
||||
unsigned int testNameIndex;
|
||||
if ( testIndex( argv[index], testNameIndex ) )
|
||||
{
|
||||
subrunner.add( tests_[testNameIndex] );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( stderr, "Test '%s' does not exist!\n", argv[index] );
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printUsage( argv[0] );
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printUsage( argv[0] );
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
bool succeeded;
|
||||
if ( subrunner.testCount() > 0 )
|
||||
{
|
||||
succeeded = subrunner.runAllTest( subrunner.testCount() > 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
succeeded = runAllTest( true );
|
||||
}
|
||||
return succeeded ? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Hook MSVCRT assertions to prevent dialog from appearing
|
||||
static int
|
||||
msvcrtSilentReportHook( int reportType, char *message, int *returnValue )
|
||||
{
|
||||
// The default CRT handling of error and assertion is to display
|
||||
// an error dialog to the user.
|
||||
// Instead, when an error or an assertion occurs, we force the
|
||||
// application to terminate using abort() after display
|
||||
// the message on stderr.
|
||||
if ( reportType == _CRT_ERROR ||
|
||||
reportType == _CRT_ASSERT )
|
||||
{
|
||||
// calling abort() cause the ReportHook to be called
|
||||
// The following is used to detect this case and let's the
|
||||
// error handler fallback on its default behaviour (
|
||||
// display a warning message)
|
||||
static volatile bool isAborting = false;
|
||||
if ( isAborting )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
isAborting = true;
|
||||
|
||||
fprintf( stderr, "CRT Error/Assert:\n%s\n", message );
|
||||
fflush( stderr );
|
||||
abort();
|
||||
}
|
||||
// Let's other reportType (_CRT_WARNING) be handled as they would by default
|
||||
return FALSE;
|
||||
}
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
|
||||
void
|
||||
Runner::preventDialogOnCrash()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
// Install a hook to prevent MSVCRT error and assertion from
|
||||
// popping a dialog.
|
||||
_CrtSetReportHook( &msvcrtSilentReportHook );
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
// @todo investiguate this handler (for buffer overflow)
|
||||
// _set_security_error_handler
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Prevents the system from popping a dialog for debugging if the
|
||||
// application fails due to invalid memory access.
|
||||
SetErrorMode( SEM_FAILCRITICALERRORS
|
||||
| SEM_NOGPFAULTERRORBOX
|
||||
| SEM_NOOPENFILEERRORBOX );
|
||||
#endif // if defined(_WIN32)
|
||||
}
|
||||
|
||||
void
|
||||
Runner::printUsage( const char *appName )
|
||||
{
|
||||
printf(
|
||||
"Usage: %s [options]\n"
|
||||
"\n"
|
||||
"If --test is not specified, then all the test cases be run.\n"
|
||||
"\n"
|
||||
"Valid options:\n"
|
||||
"--list-tests: print the name of all test cases on the standard\n"
|
||||
" output and exit.\n"
|
||||
"--test TESTNAME: executes the test case with the specified name.\n"
|
||||
" May be repeated.\n"
|
||||
"--test-auto: prevent dialog prompting for debugging on crash.\n"
|
||||
, appName );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Assertion functions
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult &
|
||||
checkStringEqual( TestResult &result,
|
||||
const std::string &expected, const std::string &actual,
|
||||
const char *file, unsigned int line, const char *expr )
|
||||
{
|
||||
if ( expected != actual )
|
||||
{
|
||||
result.addFailure( file, line, expr );
|
||||
result << "Expected: '" << expected << "'\n";
|
||||
result << "Actual : '" << actual << "'";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace JsonTest
|
254
thirdparty/jsoncpp/src/test_lib_json/jsontest.h
vendored
254
thirdparty/jsoncpp/src/test_lib_json/jsontest.h
vendored
@ -1,254 +0,0 @@
|
||||
#ifndef JSONTEST_H_INCLUDED
|
||||
# define JSONTEST_H_INCLUDED
|
||||
|
||||
# include <json/config.h>
|
||||
# include <stdio.h>
|
||||
# include <deque>
|
||||
# include <string>
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// Mini Unit Testing framework
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/** \brief Unit testing framework.
|
||||
* \warning: all assertions are non-aborting, test case execution will continue
|
||||
* even if an assertion namespace.
|
||||
* This constraint is for portability: the framework needs to compile
|
||||
* on Visual Studio 6 and must not require exception usage.
|
||||
*/
|
||||
namespace JsonTest {
|
||||
|
||||
|
||||
class Failure
|
||||
{
|
||||
public:
|
||||
const char *file_;
|
||||
unsigned int line_;
|
||||
std::string expr_;
|
||||
std::string message_;
|
||||
unsigned int nestingLevel_;
|
||||
};
|
||||
|
||||
|
||||
/// Context used to create the assertion callstack on failure.
|
||||
/// Must be a POD to allow inline initialisation without stepping
|
||||
/// into the debugger.
|
||||
struct PredicateContext
|
||||
{
|
||||
typedef unsigned int Id;
|
||||
Id id_;
|
||||
const char *file_;
|
||||
unsigned int line_;
|
||||
const char *expr_;
|
||||
PredicateContext *next_;
|
||||
/// Related Failure, set when the PredicateContext is converted
|
||||
/// into a Failure.
|
||||
Failure *failure_;
|
||||
};
|
||||
|
||||
class TestResult
|
||||
{
|
||||
public:
|
||||
TestResult();
|
||||
|
||||
/// \internal Implementation detail for assertion macros
|
||||
/// Not encapsulated to prevent step into when debugging failed assertions
|
||||
/// Incremented by one on assertion predicate entry, decreased by one
|
||||
/// by addPredicateContext().
|
||||
PredicateContext::Id predicateId_;
|
||||
|
||||
/// \internal Implementation detail for predicate macros
|
||||
PredicateContext *predicateStackTail_;
|
||||
|
||||
void setTestName( const std::string &name );
|
||||
|
||||
/// Adds an assertion failure.
|
||||
TestResult &addFailure( const char *file, unsigned int line,
|
||||
const char *expr = 0 );
|
||||
|
||||
/// Removes the last PredicateContext added to the predicate stack
|
||||
/// chained list.
|
||||
/// Next messages will be targed at the PredicateContext that was removed.
|
||||
TestResult &popPredicateContext();
|
||||
|
||||
bool failed() const;
|
||||
|
||||
void printFailure( bool printTestName ) const;
|
||||
|
||||
TestResult &operator << ( bool value );
|
||||
TestResult &operator << ( int value );
|
||||
TestResult &operator << ( unsigned int value );
|
||||
TestResult &operator << ( double value );
|
||||
TestResult &operator << ( const char *value );
|
||||
TestResult &operator << ( const std::string &value );
|
||||
|
||||
private:
|
||||
TestResult &addToLastFailure( const std::string &message );
|
||||
unsigned int getAssertionNestingLevel() const;
|
||||
/// Adds a failure or a predicate context
|
||||
void addFailureInfo( const char *file, unsigned int line,
|
||||
const char *expr, unsigned int nestingLevel );
|
||||
static std::string indentText( const std::string &text,
|
||||
const std::string &indent );
|
||||
|
||||
typedef std::deque<Failure> Failures;
|
||||
Failures failures_;
|
||||
std::string name_;
|
||||
PredicateContext rootPredicateNode_;
|
||||
PredicateContext::Id lastUsedPredicateId_;
|
||||
/// Failure which is the target of the messages added using operator <<
|
||||
Failure *messageTarget_;
|
||||
};
|
||||
|
||||
|
||||
class TestCase
|
||||
{
|
||||
public:
|
||||
TestCase();
|
||||
|
||||
virtual ~TestCase();
|
||||
|
||||
void run( TestResult &result );
|
||||
|
||||
virtual const char *testName() const = 0;
|
||||
|
||||
protected:
|
||||
TestResult *result_;
|
||||
|
||||
private:
|
||||
virtual void runTestCase() = 0;
|
||||
};
|
||||
|
||||
/// Function pointer type for TestCase factory
|
||||
typedef TestCase *(*TestCaseFactory)();
|
||||
|
||||
class Runner
|
||||
{
|
||||
public:
|
||||
Runner();
|
||||
|
||||
/// Adds a test to the suite
|
||||
Runner &add( TestCaseFactory factory );
|
||||
|
||||
/// Runs test as specified on the command-line
|
||||
/// If no command-line arguments are provided, run all tests.
|
||||
/// If --list-tests is provided, then print the list of all test cases
|
||||
/// If --test <testname> is provided, then run test testname.
|
||||
int runCommandLine( int argc, const char *argv[] ) const;
|
||||
|
||||
/// Runs all the test cases
|
||||
bool runAllTest( bool printSummary ) const;
|
||||
|
||||
/// Returns the number of test case in the suite
|
||||
unsigned int testCount() const;
|
||||
|
||||
/// Returns the name of the test case at the specified index
|
||||
std::string testNameAt( unsigned int index ) const;
|
||||
|
||||
/// Runs the test case at the specified index using the specified TestResult
|
||||
void runTestAt( unsigned int index, TestResult &result ) const;
|
||||
|
||||
static void printUsage( const char *appName );
|
||||
|
||||
private: // prevents copy construction and assignment
|
||||
Runner( const Runner &other );
|
||||
Runner &operator =( const Runner &other );
|
||||
|
||||
private:
|
||||
void listTests() const;
|
||||
bool testIndex( const std::string &testName, unsigned int &index ) const;
|
||||
static void preventDialogOnCrash();
|
||||
|
||||
private:
|
||||
typedef std::deque<TestCaseFactory> Factories;
|
||||
Factories tests_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
TestResult &
|
||||
checkEqual( TestResult &result, const T &expected, const T &actual,
|
||||
const char *file, unsigned int line, const char *expr )
|
||||
{
|
||||
if ( expected != actual )
|
||||
{
|
||||
result.addFailure( file, line, expr );
|
||||
result << "Expected: " << expected << "\n";
|
||||
result << "Actual : " << actual;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TestResult &
|
||||
checkStringEqual( TestResult &result,
|
||||
const std::string &expected, const std::string &actual,
|
||||
const char *file, unsigned int line, const char *expr );
|
||||
|
||||
} // namespace JsonTest
|
||||
|
||||
|
||||
/// \brief Asserts that the given expression is true.
|
||||
/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
|
||||
/// JSONTEST_ASSERT( x == y );
|
||||
#define JSONTEST_ASSERT( expr ) \
|
||||
if ( condition ) \
|
||||
{ \
|
||||
} \
|
||||
else \
|
||||
result_->addFailure( __FILE__, __LINE__, #expr )
|
||||
|
||||
/// \brief Asserts that the given predicate is true.
|
||||
/// The predicate may do other assertions and be a member function of the fixture.
|
||||
#define JSONTEST_ASSERT_PRED( expr ) \
|
||||
{ \
|
||||
JsonTest::PredicateContext _minitest_Context = { \
|
||||
result_->predicateId_, __FILE__, __LINE__, #expr }; \
|
||||
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
||||
result_->predicateId_ += 1; \
|
||||
result_->predicateStackTail_ = &_minitest_Context; \
|
||||
(expr); \
|
||||
result_->popPredicateContext(); \
|
||||
} \
|
||||
*result_
|
||||
|
||||
/// \brief Asserts that two values are equals.
|
||||
#define JSONTEST_ASSERT_EQUAL( expected, actual ) \
|
||||
JsonTest::checkEqual( *result_, expected, actual, \
|
||||
__FILE__, __LINE__, \
|
||||
#expected " == " #actual )
|
||||
|
||||
/// \brief Asserts that two values are equals.
|
||||
#define JSONTEST_ASSERT_STRING_EQUAL( expected, actual ) \
|
||||
JsonTest::checkStringEqual( *result_, \
|
||||
std::string(expected), std::string(actual), \
|
||||
#expected " == " #actual )
|
||||
|
||||
/// \brief Begin a fixture test case.
|
||||
#define JSONTEST_FIXTURE( FixtureType, name ) \
|
||||
class Test##FixtureType##name : public FixtureType \
|
||||
{ \
|
||||
public: \
|
||||
static JsonTest::TestCase *factory() \
|
||||
{ \
|
||||
return new Test##FixtureType##name(); \
|
||||
} \
|
||||
public: /* overidden from TestCase */ \
|
||||
virtual const char *testName() const \
|
||||
{ \
|
||||
return #FixtureType "/" #name; \
|
||||
} \
|
||||
virtual void runTestCase(); \
|
||||
}; \
|
||||
\
|
||||
void Test##FixtureType##name::runTestCase()
|
||||
|
||||
#define JSONTEST_FIXTURE_FACTORY( FixtureType, name ) \
|
||||
&Test##FixtureType##name::factory
|
||||
|
||||
#define JSONTEST_REGISTER_FIXTURE( runner, FixtureType, name ) \
|
||||
(runner).add( JSONTEST_FIXTURE_FACTORY( FixtureType, name ) )
|
||||
|
||||
#endif // ifndef JSONTEST_H_INCLUDED
|
244
thirdparty/jsoncpp/src/test_lib_json/main.cpp
vendored
244
thirdparty/jsoncpp/src/test_lib_json/main.cpp
vendored
@ -1,244 +0,0 @@
|
||||
#include <json/json.h>
|
||||
#include "jsontest.h"
|
||||
|
||||
|
||||
// TODO:
|
||||
// - boolean value returns that they are integral. Should not be.
|
||||
// - unsigned integer in integer range are not considered to be valid integer. Should check range.
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// Json Library test cases
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
struct ValueTest : JsonTest::TestCase
|
||||
{
|
||||
Json::Value null_;
|
||||
Json::Value emptyArray_;
|
||||
Json::Value emptyObject_;
|
||||
Json::Value integer_;
|
||||
Json::Value unsignedInteger_;
|
||||
Json::Value smallUnsignedInteger_;
|
||||
Json::Value real_;
|
||||
Json::Value array1_;
|
||||
Json::Value object1_;
|
||||
Json::Value emptyString_;
|
||||
Json::Value string1_;
|
||||
Json::Value string_;
|
||||
Json::Value true_;
|
||||
Json::Value false_;
|
||||
|
||||
ValueTest()
|
||||
: emptyArray_( Json::arrayValue )
|
||||
, emptyObject_( Json::objectValue )
|
||||
, integer_( 123456789 )
|
||||
, smallUnsignedInteger_( Json::Value::UInt( Json::Value::maxInt ) )
|
||||
, unsignedInteger_( 34567890u )
|
||||
, real_( 1234.56789 )
|
||||
, emptyString_( "" )
|
||||
, string1_( "a" )
|
||||
, string_( "sometext with space" )
|
||||
, true_( true )
|
||||
, false_( false )
|
||||
{
|
||||
array1_.append( 1234 );
|
||||
object1_["id"] = 1234;
|
||||
}
|
||||
|
||||
struct IsCheck
|
||||
{
|
||||
/// Initialize all checks to \c false by default.
|
||||
IsCheck();
|
||||
|
||||
bool isObject_;
|
||||
bool isArray_;
|
||||
bool isBool_;
|
||||
bool isDouble_;
|
||||
bool isInt_;
|
||||
bool isUInt_;
|
||||
bool isIntegral_;
|
||||
bool isNumeric_;
|
||||
bool isString_;
|
||||
bool isNull_;
|
||||
};
|
||||
|
||||
void checkConstMemberCount( const Json::Value &value, unsigned int expectedCount );
|
||||
|
||||
void checkMemberCount( Json::Value &value, unsigned int expectedCount );
|
||||
|
||||
void checkIs( const Json::Value &value, const IsCheck &check );
|
||||
};
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, size )
|
||||
{
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(emptyArray_, 0) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(emptyObject_, 0) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(array1_, 1) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(object1_, 1) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(null_, 0) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(integer_, 0) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(real_, 0) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(emptyString_, 0) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(string_, 0) );
|
||||
JSONTEST_ASSERT_PRED( checkMemberCount(true_, 0) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isObject )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isObject_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( emptyObject_, checks ) );
|
||||
JSONTEST_ASSERT_PRED( checkIs( object1_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isArray )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isArray_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( emptyArray_, checks ) );
|
||||
JSONTEST_ASSERT_PRED( checkIs( array1_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isNull )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isNull_ = true;
|
||||
checks.isObject_ = true;
|
||||
checks.isArray_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( null_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isString )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isString_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( emptyString_, checks ) );
|
||||
JSONTEST_ASSERT_PRED( checkIs( string_, checks ) );
|
||||
JSONTEST_ASSERT_PRED( checkIs( string1_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isBool )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isBool_ = true;
|
||||
checks.isIntegral_ = true;
|
||||
checks.isNumeric_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( false_, checks ) );
|
||||
JSONTEST_ASSERT_PRED( checkIs( true_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isDouble )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isDouble_ = true;
|
||||
checks.isNumeric_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( real_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isInt )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isInt_ = true;
|
||||
checks.isNumeric_ = true;
|
||||
checks.isIntegral_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( integer_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, isUInt )
|
||||
{
|
||||
IsCheck checks;
|
||||
checks.isUInt_ = true;
|
||||
checks.isNumeric_ = true;
|
||||
checks.isIntegral_ = true;
|
||||
JSONTEST_ASSERT_PRED( checkIs( unsignedInteger_, checks ) );
|
||||
JSONTEST_ASSERT_PRED( checkIs( smallUnsignedInteger_, checks ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueTest::checkConstMemberCount( const Json::Value &value, unsigned int expectedCount )
|
||||
{
|
||||
unsigned int count = 0;
|
||||
Json::Value::const_iterator itEnd = value.end();
|
||||
for ( Json::Value::const_iterator it = value.begin(); it != itEnd; ++it )
|
||||
{
|
||||
++count;
|
||||
}
|
||||
JSONTEST_ASSERT_EQUAL( expectedCount, count ) << "Json::Value::const_iterator";
|
||||
}
|
||||
|
||||
void
|
||||
ValueTest::checkMemberCount( Json::Value &value, unsigned int expectedCount )
|
||||
{
|
||||
JSONTEST_ASSERT_EQUAL( expectedCount, value.size() );
|
||||
|
||||
unsigned int count = 0;
|
||||
Json::Value::iterator itEnd = value.end();
|
||||
for ( Json::Value::iterator it = value.begin(); it != itEnd; ++it )
|
||||
{
|
||||
++count;
|
||||
}
|
||||
JSONTEST_ASSERT_EQUAL( expectedCount, count ) << "Json::Value::iterator";
|
||||
|
||||
JSONTEST_ASSERT_PRED( checkConstMemberCount(value, expectedCount) );
|
||||
}
|
||||
|
||||
|
||||
ValueTest::IsCheck::IsCheck()
|
||||
: isObject_( false )
|
||||
, isArray_( false )
|
||||
, isBool_( false )
|
||||
, isDouble_( false )
|
||||
, isInt_( false )
|
||||
, isUInt_( false )
|
||||
, isIntegral_( false )
|
||||
, isNumeric_( false )
|
||||
, isString_( false )
|
||||
, isNull_( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueTest::checkIs( const Json::Value &value, const IsCheck &check )
|
||||
{
|
||||
JSONTEST_ASSERT_EQUAL( check.isObject_, value.isObject() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isArray_, value.isArray() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isBool_, value.isBool() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isDouble_, value.isDouble() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isInt_, value.isInt() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isUInt_, value.isUInt() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isIntegral_, value.isIntegral() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isNumeric_, value.isNumeric() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isString_, value.isString() );
|
||||
JSONTEST_ASSERT_EQUAL( check.isNull_, value.isNull() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main( int argc, const char *argv[] )
|
||||
{
|
||||
JsonTest::Runner runner;
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, size );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isObject );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isArray );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isBool );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isInt );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isUInt );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isDouble );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isString );
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, isNull );
|
||||
return runner.runCommandLine( argc, argv );
|
||||
}
|
10
thirdparty/jsoncpp/src/test_lib_json/sconscript
vendored
10
thirdparty/jsoncpp/src/test_lib_json/sconscript
vendored
@ -1,10 +0,0 @@
|
||||
Import( 'env_testing buildUnitTests' )
|
||||
|
||||
buildUnitTests( env_testing, Split( """
|
||||
main.cpp
|
||||
jsontest.cpp
|
||||
""" ),
|
||||
'test_lib_json' )
|
||||
|
||||
# For 'check' to work, 'libs' must be built first.
|
||||
env_testing.Depends('test_lib_json', '#libs')
|
1
thirdparty/jsoncpp/version
vendored
1
thirdparty/jsoncpp/version
vendored
@ -1 +0,0 @@
|
||||
0.5.0
|
221
thirdparty/ultrajson/README
vendored
221
thirdparty/ultrajson/README
vendored
@ -1,221 +0,0 @@
|
||||
UltraJSON is a fast and extendable JSON encoder and decoder written in pure C
|
||||
|
||||
Python bindings are available as the module ujson (through easy_install / pypi):
|
||||
http://pypi.python.org/pypi/ujson/
|
||||
|
||||
|
||||
Installation instructions:
|
||||
|
||||
1. Build and install ujson Python extension (requires root)
|
||||
Go to <root>/python
|
||||
Type: python setup.py build install
|
||||
|
||||
2. Run tests (as needed)
|
||||
Type: python tests.py
|
||||
|
||||
Same instructions applies for Windows except that step 1) isn't necessary since
|
||||
a prebuilt static library is included.
|
||||
|
||||
Preliminary benchmarks:
|
||||
|
||||
64-bit benchmarks Linux
|
||||
Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56)
|
||||
OS Version: Ubuntu 10.10
|
||||
System Type: x64-based PC
|
||||
Processor: Intel(R) Core(TM) i5-2300 CPU @ 2.80GHz
|
||||
Total Physical Memory: 4096 MB
|
||||
|
||||
Array with 256 utf-8 strings:
|
||||
ujson encode : 2714.66499 calls/sec
|
||||
simplejson encode : 1542.63718 calls/sec
|
||||
cjson encode : 132.23604 calls/sec
|
||||
|
||||
ujson decode : 2079.17287 calls/sec
|
||||
cjson decode : 992.21602 calls/sec
|
||||
simplejson decode : 278.92061 calls/sec
|
||||
|
||||
Medium complex object:
|
||||
ujson encode : 17849.80356 calls/sec
|
||||
simplejson encode : 3524.32372 calls/sec
|
||||
cjson encode : 2967.34656 calls/sec
|
||||
|
||||
ujson decode : 11685.87610 calls/sec
|
||||
cjson decode : 8206.67906 calls/sec
|
||||
simplejson decode : 6549.99750 calls/sec
|
||||
|
||||
Array with 256 strings:
|
||||
ujson encode : 38543.50303 calls/sec
|
||||
simplejson encode : 19436.45772 calls/sec
|
||||
cjson encode : 12392.55614 calls/sec
|
||||
|
||||
ujson decode : 27207.33157 calls/sec
|
||||
cjson decode : 30237.60827 calls/sec
|
||||
simplejson decode : 25271.93073 calls/sec
|
||||
|
||||
Array with 256 doubles:
|
||||
ujson encode : 6027.45931 calls/sec
|
||||
simplejson encode : 2915.54871 calls/sec
|
||||
cjson encode : 3546.88804 calls/sec
|
||||
|
||||
ujson decode : 28045.13375 calls/sec
|
||||
cjson decode : 15066.73209 calls/sec
|
||||
simplejson decode : 15604.98222 calls/sec
|
||||
|
||||
Array with 256 True values:
|
||||
ujson encode : 187342.39634 calls/sec
|
||||
simplejson encode : 48972.93887 calls/sec
|
||||
cjson encode : 67274.93082 calls/sec
|
||||
|
||||
ujson decode : 158103.79663 calls/sec
|
||||
cjson decode : 83237.88990 calls/sec
|
||||
simplejson decode : 115645.98241 calls/sec
|
||||
|
||||
Array with 256 dict{string, int} pairs:
|
||||
ujson encode : 25301.85690 calls/sec
|
||||
simplejson encode : 5734.29472 calls/sec
|
||||
cjson encode : 4447.73411 calls/sec
|
||||
|
||||
ujson decode : 16290.72288 calls/sec
|
||||
cjson decode : 12528.56060 calls/sec
|
||||
simplejson decode : 10394.23358 calls/sec
|
||||
|
||||
Dict with 256 arrays with 256 dict{string, int} pairs:
|
||||
ujson encode : 87.40865 calls/sec
|
||||
simplejson encode : 17.07889 calls/sec
|
||||
cjson encode : 17.25164 calls/sec
|
||||
|
||||
ujson decode : 45.94026 calls/sec
|
||||
cjson decode : 34.60225 calls/sec
|
||||
simplejson decode : 26.92238 calls/sec
|
||||
|
||||
32-bit benchmarks Windows
|
||||
Python 2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)]
|
||||
OS Version: 6.1.7601 Service Pack 1 Build 7601
|
||||
System Type: x64-based PC
|
||||
Processor: Intel(R) Core(TM)2 Quad CPU Q9550 @ 2.83GHz 2.83 GHz
|
||||
Total Physical Memory: 8191 MB
|
||||
|
||||
Array with 256 utf-8 strings:
|
||||
ujson encode : 1191.98175 calls/sec
|
||||
simplejson encode : 1013.98279 calls/sec
|
||||
cjson encode : 1040.66063 calls/sec
|
||||
|
||||
ujson decode : 1215.66875 calls/sec
|
||||
cjson decode : 493.30484 calls/sec
|
||||
simplejson decode : 269.85512 calls/sec
|
||||
|
||||
Medium complex object:
|
||||
ujson encode : 10307.63723 calls/sec
|
||||
simplejson encode : 2534.94769 calls/sec
|
||||
cjson encode : 2047.95118 calls/sec
|
||||
|
||||
ujson decode : 7274.10026 calls/sec
|
||||
cjson decode : 3575.39307 calls/sec
|
||||
simplejson decode : 3565.51252 calls/sec
|
||||
|
||||
Array with 256 strings:
|
||||
ujson encode : 21348.25210 calls/sec
|
||||
simplejson encode : 15736.74638 calls/sec
|
||||
cjson encode : 6371.26334 calls/sec
|
||||
|
||||
ujson decode : 26050.25316 calls/sec
|
||||
cjson decode : 16468.88215 calls/sec
|
||||
simplejson decode : 21115.75770 calls/sec
|
||||
|
||||
Array with 256 doubles:
|
||||
ujson encode : 26975.49110 calls/sec
|
||||
simplejson encode : 2046.29746 calls/sec
|
||||
cjson encode : 2133.56594 calls/sec
|
||||
|
||||
ujson decode : 28430.33722 calls/sec
|
||||
cjson decode : 4114.36400 calls/sec
|
||||
simplejson decode : 4419.08507 calls/sec
|
||||
|
||||
Array with 256 True values:
|
||||
ujson encode : 89846.12897 calls/sec
|
||||
simplejson encode : 34288.36862 calls/sec
|
||||
cjson encode : 47168.35849 calls/sec
|
||||
|
||||
ujson decode : 99423.47549 calls/sec
|
||||
cjson decode : 58795.91460 calls/sec
|
||||
simplejson decode : 76296.14699 calls/sec
|
||||
|
||||
Array with 256 dict{string, int} pairs:
|
||||
ujson encode : 14776.41614 calls/sec
|
||||
simplejson encode : 3876.86634 calls/sec
|
||||
cjson encode : 3050.65343 calls/sec
|
||||
|
||||
ujson decode : 12934.39432 calls/sec
|
||||
cjson decode : 7993.04345 calls/sec
|
||||
simplejson decode : 7152.09475 calls/sec
|
||||
|
||||
Here is the benchmark run from a 32bit CentOS 5.6 (Python 2.4) machine:
|
||||
|
||||
Array with 256 utf-8 strings:
|
||||
ujson encode : 1453.30891 calls/sec
|
||||
simplejson encode : 658.31181 calls/sec
|
||||
cjson encode : 62.18416 calls/sec
|
||||
|
||||
ujson decode : 1016.58767 calls/sec
|
||||
cjson decode : 455.28550 calls/sec
|
||||
simplejson decode : 124.20439 calls/sec
|
||||
|
||||
Medium complex object:
|
||||
ujson encode : 6010.21634 calls/sec
|
||||
simplejson encode : 1418.77823 calls/sec
|
||||
cjson encode : 1252.92530 calls/sec
|
||||
|
||||
ujson decode : 4637.52630 calls/sec
|
||||
cjson decode : 3444.13604 calls/sec
|
||||
simplejson decode : 2166.18641 calls/sec
|
||||
|
||||
Array with 256 strings:
|
||||
ujson encode : 12252.28889 calls/sec
|
||||
simplejson encode : 9351.67532 calls/sec
|
||||
cjson encode : 7786.13697 calls/sec
|
||||
|
||||
ujson decode : 10951.17394 calls/sec
|
||||
cjson decode : 15971.02425 calls/sec
|
||||
simplejson decode : 6796.77480 calls/sec
|
||||
|
||||
Array with 256 doubles:
|
||||
ujson encode : 16300.61218 calls/sec
|
||||
simplejson encode : 1613.39428 calls/sec
|
||||
cjson encode : 2035.58937 calls/sec
|
||||
|
||||
ujson decode : 17301.00746 calls/sec
|
||||
cjson decode : 5785.33627 calls/sec
|
||||
simplejson decode : 6199.49364 calls/sec
|
||||
|
||||
Array with 256 True values:
|
||||
ujson encode : 72618.15350 calls/sec
|
||||
simplejson encode : 18707.57593 calls/sec
|
||||
cjson encode : 24150.26201 calls/sec
|
||||
|
||||
ujson decode : 53650.94162 calls/sec
|
||||
cjson decode : 48069.53050 calls/sec
|
||||
simplejson decode : 47098.40293 calls/sec
|
||||
|
||||
Array with 256 dict{string, int} pairs:
|
||||
ujson encode : 8811.85922 calls/sec
|
||||
simplejson encode : 2756.91262 calls/sec
|
||||
cjson encode : 1758.26962 calls/sec
|
||||
|
||||
ujson decode : 6490.36358 calls/sec
|
||||
cjson decode : 6330.77263 calls/sec
|
||||
simplejson decode : 4161.97048 calls/sec
|
||||
|
||||
Dict with 256 arrays with 256 dict{string, int} pairs:
|
||||
ujson encode : 31.08834 calls/sec
|
||||
simplejson encode : 10.41434 calls/sec
|
||||
cjson encode : 6.93790 calls/sec
|
||||
|
||||
ujson decode : 19.81373 calls/sec
|
||||
cjson decode : 20.31727 calls/sec
|
||||
simplejson decode : 15.05690 calls/sec
|
||||
|
||||
|
||||
See (python/benchmark.py) for further information.
|
||||
|
||||
NOTE: These benchmarks are preliminary!
|
||||
|
298
thirdparty/ultrajson/ultrajson.h
vendored
298
thirdparty/ultrajson/ultrajson.h
vendored
@ -1,298 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. All advertising materials mentioning features or use of this software
|
||||
must display the following acknowledgement:
|
||||
This product includes software developed by ESN Social Software AB (www.esn.me).
|
||||
4. Neither the name of the ESN Social Software AB nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ESN SOCIAL SOFTWARE AB ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ESN SOCIAL SOFTWARE AB BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Portions of code from:
|
||||
MODP_ASCII - Ascii transformations (upper/lower, etc)
|
||||
http://code.google.com/p/stringencoders/
|
||||
Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Ultra fast JSON encoder and decoder
|
||||
Developed by Jonas Tarnstrom (jonas@esn.me).
|
||||
|
||||
Encoder notes:
|
||||
------------------
|
||||
|
||||
:: Cyclic references ::
|
||||
Cyclic referenced objects are not detected.
|
||||
Set JSONObjectEncoder.recursionMax to suitable value or make sure input object
|
||||
tree doesn't have cyclic references.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ULTRAJSON_H__
|
||||
#define __ULTRAJSON_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
//#define JSON_DECODE_NUMERIC_AS_DOUBLE
|
||||
|
||||
// Don't output any extra whitespaces when encoding
|
||||
#define JSON_NO_EXTRA_WHITESPACE
|
||||
|
||||
// Max decimals to encode double floating point numbers with
|
||||
#ifndef JSON_DOUBLE_MAX_DECIMALS
|
||||
#define JSON_DOUBLE_MAX_DECIMALS 9
|
||||
#endif
|
||||
|
||||
// Max recursion depth, default for encoder
|
||||
#ifndef JSON_MAX_RECURSION_DEPTH
|
||||
#define JSON_MAX_RECURSION_DEPTH 256
|
||||
#endif
|
||||
|
||||
/*
|
||||
Dictates and limits how much stack space for buffers UltraJSON will use before resorting to provided heap functions */
|
||||
#ifndef JSON_MAX_STACK_BUFFER_SIZE
|
||||
#define JSON_MAX_STACK_BUFFER_SIZE 131072
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef __int64 JSINT64;
|
||||
typedef unsigned __int64 JSUINT64;
|
||||
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int32 JSINT32;
|
||||
typedef uint32_t JSUINT32;
|
||||
typedef unsigned __int8 JSUINT8;
|
||||
typedef unsigned __int16 JSUTF16;
|
||||
typedef unsigned __int32 JSUTF32;
|
||||
typedef __int64 JSLONG;
|
||||
|
||||
#define EXPORTFUNCTION __declspec(dllexport)
|
||||
|
||||
#define FASTCALL_MSVC __fastcall
|
||||
#define FASTCALL_ATTR
|
||||
#define INLINE_PREFIX __inline
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
typedef int64_t JSINT64;
|
||||
typedef u_int64_t JSUINT64;
|
||||
|
||||
typedef int32_t JSINT32;
|
||||
typedef u_int32_t JSUINT32;
|
||||
|
||||
#define FASTCALL_MSVC
|
||||
#define FASTCALL_ATTR __attribute__((fastcall))
|
||||
#define INLINE_PREFIX inline
|
||||
|
||||
typedef u_int32_t uint32_t;
|
||||
|
||||
typedef u_int8_t JSUINT8;
|
||||
typedef u_int16_t JSUTF16;
|
||||
typedef u_int32_t JSUTF32;
|
||||
|
||||
typedef int64_t JSLONG;
|
||||
|
||||
#define EXPORTFUNCTION
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define __LITTLE_ENDIAN__
|
||||
#else
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define __BIG_ENDIAN__
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
|
||||
#error "Endianess not supported"
|
||||
#endif
|
||||
|
||||
enum JSTYPES
|
||||
{
|
||||
JT_NULL, // NULL
|
||||
JT_TRUE, //boolean true
|
||||
JT_FALSE, //boolean false
|
||||
JT_INT, //(JSINT32 (signed 32-bit))
|
||||
JT_LONG, //(JSINT64 (signed 64-bit))
|
||||
JT_DOUBLE, //(double)
|
||||
JT_UTF8, //(char 8-bit)
|
||||
JT_ARRAY, // Array structure
|
||||
JT_OBJECT, // Key/Value structure
|
||||
JT_INVALID, // Internal, do not return nor expect
|
||||
};
|
||||
|
||||
typedef void * JSOBJ;
|
||||
typedef void * JSITER;
|
||||
|
||||
typedef struct __JSONTypeContext
|
||||
{
|
||||
int type;
|
||||
void *prv[32];
|
||||
} JSONTypeContext;
|
||||
|
||||
/*
|
||||
Function pointer declarations, suitable for implementing UltraJSON */
|
||||
typedef void (*JSPFN_ITERBEGIN)(JSOBJ obj, JSONTypeContext *tc);
|
||||
typedef int (*JSPFN_ITERNEXT)(JSOBJ obj, JSONTypeContext *tc);
|
||||
typedef void (*JSPFN_ITEREND)(JSOBJ obj, JSONTypeContext *tc);
|
||||
typedef JSOBJ (*JSPFN_ITERGETVALUE)(JSOBJ obj, JSONTypeContext *tc);
|
||||
typedef char *(*JSPFN_ITERGETNAME)(JSOBJ obj, JSONTypeContext *tc, size_t *outLen);
|
||||
typedef void *(*JSPFN_MALLOC)(size_t size);
|
||||
typedef void (*JSPFN_FREE)(void *pptr);
|
||||
typedef void *(*JSPFN_REALLOC)(void *base, size_t size);
|
||||
|
||||
typedef struct __JSONObjectEncoder
|
||||
{
|
||||
void (*beginTypeContext)(JSOBJ obj, JSONTypeContext *tc);
|
||||
void (*endTypeContext)(JSOBJ obj, JSONTypeContext *tc);
|
||||
const char *(*getStringValue)(JSOBJ obj, JSONTypeContext *tc, size_t *_outLen);
|
||||
JSINT64 (*getLongValue)(JSOBJ obj, JSONTypeContext *tc);
|
||||
JSINT32 (*getIntValue)(JSOBJ obj, JSONTypeContext *tc);
|
||||
double (*getDoubleValue)(JSOBJ obj, JSONTypeContext *tc);
|
||||
|
||||
/*
|
||||
Begin iteration of an iteratable object (JS_ARRAY or JS_OBJECT)
|
||||
Implementor should setup iteration state in ti->prv
|
||||
*/
|
||||
JSPFN_ITERBEGIN iterBegin;
|
||||
|
||||
/*
|
||||
Retrieve next object in an iteration. Should return 0 to indicate iteration has reached end or 1 if there are more items.
|
||||
Implementor is responsible for keeping state of the iteration. Use ti->prv fields for this
|
||||
*/
|
||||
JSPFN_ITERNEXT iterNext;
|
||||
|
||||
/*
|
||||
Ends the iteration of an iteratable object.
|
||||
Any iteration state stored in ti->prv can be freed here
|
||||
*/
|
||||
JSPFN_ITEREND iterEnd;
|
||||
|
||||
/*
|
||||
Returns a reference to the value object of an iterator
|
||||
The is responsible for the life-cycle of the returned string. Use iterNext/iterEnd and ti->prv to keep track of current object
|
||||
*/
|
||||
JSPFN_ITERGETVALUE iterGetValue;
|
||||
|
||||
/*
|
||||
Return name of iterator.
|
||||
The is responsible for the life-cycle of the returned string. Use iterNext/iterEnd and ti->prv to keep track of current object
|
||||
*/
|
||||
JSPFN_ITERGETNAME iterGetName;
|
||||
|
||||
/*
|
||||
Release a value as indicated by setting ti->release = 1 in the previous getValue call.
|
||||
The ti->prv array should contain the necessary context to release the value
|
||||
*/
|
||||
void (*releaseObject)(JSOBJ obj);
|
||||
|
||||
/* Library functions
|
||||
Set to NULL to use STDLIB malloc,realloc,free */
|
||||
JSPFN_MALLOC malloc;
|
||||
JSPFN_REALLOC realloc;
|
||||
JSPFN_FREE free;
|
||||
|
||||
/*
|
||||
Configuration for max recursion, set to 0 to use default (see JSON_MAX_RECURSION_DEPTH)*/
|
||||
int recursionMax;
|
||||
|
||||
/*
|
||||
Configuration for max decimals of double floating poiunt numbers to encode (0-9) */
|
||||
int doublePrecision;
|
||||
|
||||
/*
|
||||
If true output will be ASCII with all characters above 127 encoded as \uXXXX. If false output will be UTF-8 or what ever charset strings are brought as */
|
||||
int forceASCII;
|
||||
|
||||
|
||||
/*
|
||||
Set to an error message if error occured */
|
||||
const char *errorMsg;
|
||||
JSOBJ errorObj;
|
||||
|
||||
/* Buffer stuff */
|
||||
char *start;
|
||||
char *offset;
|
||||
char *end;
|
||||
int heap;
|
||||
int level;
|
||||
|
||||
} JSONObjectEncoder;
|
||||
|
||||
|
||||
/*
|
||||
Encode an object structure into JSON.
|
||||
|
||||
Arguments:
|
||||
obj - An anonymous type representing the object
|
||||
enc - Function definitions for querying JSOBJ type
|
||||
buffer - Preallocated buffer to store result in. If NULL function allocates own buffer
|
||||
cbBuffer - Length of buffer (ignored if buffer is NULL)
|
||||
|
||||
Returns:
|
||||
Encoded JSON object as a null terminated char string.
|
||||
|
||||
NOTE:
|
||||
If the supplied buffer wasn't enough to hold the result the function will allocate a new buffer.
|
||||
Life cycle of the provided buffer must still be handled by caller.
|
||||
|
||||
If the return value doesn't equal the specified buffer caller must release the memory using
|
||||
JSONObjectEncoder.free or free() as specified when calling this function.
|
||||
*/
|
||||
EXPORTFUNCTION char *JSON_EncodeObject(JSOBJ obj, JSONObjectEncoder *enc, char *buffer, size_t cbBuffer);
|
||||
|
||||
|
||||
|
||||
typedef struct __JSONObjectDecoder
|
||||
{
|
||||
JSOBJ (*newString)(wchar_t *start, wchar_t *end);
|
||||
void (*objectAddKey)(JSOBJ obj, JSOBJ name, JSOBJ value);
|
||||
void (*arrayAddItem)(JSOBJ obj, JSOBJ value);
|
||||
JSOBJ (*newTrue)(void);
|
||||
JSOBJ (*newFalse)(void);
|
||||
JSOBJ (*newNull)(void);
|
||||
JSOBJ (*newObject)(void);
|
||||
JSOBJ (*newArray)(void);
|
||||
JSOBJ (*newInt)(JSINT32 value);
|
||||
JSOBJ (*newLong)(JSINT64 value);
|
||||
JSOBJ (*newDouble)(double value);
|
||||
void (*releaseObject)(JSOBJ obj);
|
||||
JSPFN_MALLOC malloc;
|
||||
JSPFN_FREE free;
|
||||
JSPFN_REALLOC realloc;
|
||||
|
||||
char *errorStr;
|
||||
char *errorOffset;
|
||||
|
||||
|
||||
|
||||
} JSONObjectDecoder;
|
||||
|
||||
EXPORTFUNCTION JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer);
|
||||
|
||||
#endif
|
816
thirdparty/ultrajson/ultrajsondec.c
vendored
816
thirdparty/ultrajson/ultrajsondec.c
vendored
@ -1,816 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. All advertising materials mentioning features or use of this software
|
||||
must display the following acknowledgement:
|
||||
This product includes software developed by ESN Social Software AB (www.esn.me).
|
||||
4. Neither the name of the ESN Social Software AB nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ESN SOCIAL SOFTWARE AB ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ESN SOCIAL SOFTWARE AB BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Portions of code from:
|
||||
MODP_ASCII - Ascii transformations (upper/lower, etc)
|
||||
http://code.google.com/p/stringencoders/
|
||||
Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "ultrajson.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <wchar.h>
|
||||
|
||||
struct DecoderState
|
||||
{
|
||||
char *start;
|
||||
char *end;
|
||||
wchar_t *escStart;
|
||||
wchar_t *escEnd;
|
||||
int escHeap;
|
||||
int lastType;
|
||||
JSONObjectDecoder *dec;
|
||||
};
|
||||
|
||||
JSOBJ FASTCALL_MSVC decode_any( struct DecoderState *ds) FASTCALL_ATTR;
|
||||
typedef JSOBJ (*PFN_DECODER)( struct DecoderState *ds);
|
||||
#define RETURN_JSOBJ_NULLCHECK(_expr) return(_expr);
|
||||
|
||||
double createDouble(double intNeg, double intValue, double frcValue, int frcDecimalCount)
|
||||
{
|
||||
static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
|
||||
|
||||
return (intValue + (frcValue / g_pow10[frcDecimalCount])) * intNeg;
|
||||
}
|
||||
|
||||
static JSOBJ SetError( struct DecoderState *ds, int offset, const char *message)
|
||||
{
|
||||
ds->dec->errorOffset = ds->start + offset;
|
||||
ds->dec->errorStr = (char *) message;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric ( struct DecoderState *ds)
|
||||
{
|
||||
#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
|
||||
double intNeg = 1;
|
||||
double intValue;
|
||||
#else
|
||||
int intNeg = 1;
|
||||
JSLONG intValue;
|
||||
#endif
|
||||
|
||||
double expNeg;
|
||||
int chr;
|
||||
int decimalCount = 0;
|
||||
double frcValue = 0.0;
|
||||
double expValue;
|
||||
|
||||
if (*(ds->start) == '-')
|
||||
{
|
||||
ds->start ++;
|
||||
intNeg = -1;
|
||||
}
|
||||
|
||||
// Scan integer part
|
||||
intValue = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
chr = (int) (unsigned char) *(ds->start);
|
||||
|
||||
switch (chr)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
//FIXME: Check for arithemtic overflow here
|
||||
//PERF: Don't do 64-bit arithmetic here unless we know we have to
|
||||
#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
|
||||
intValue = intValue * 10.0 + (double) (chr - 48);
|
||||
#else
|
||||
intValue = intValue * 10LL + (JSLONG) (chr - 48);
|
||||
#endif
|
||||
ds->start ++;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
ds->start ++;
|
||||
goto DECODE_FRACTION;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
ds->start ++;
|
||||
goto DECODE_EXPONENT;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto BREAK_INT_LOOP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BREAK_INT_LOOP:
|
||||
|
||||
ds->lastType = JT_INT;
|
||||
|
||||
//If input string is LONGLONG_MIN here the value is already negative so we should not flip it
|
||||
|
||||
#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
|
||||
#else
|
||||
if (intValue < 0)
|
||||
{
|
||||
intNeg = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//dbg1 = (intValue * intNeg);
|
||||
//dbg2 = (JSLONG) dbg1;
|
||||
|
||||
#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
|
||||
if (intValue > (double) INT_MAX || intValue < (double) INT_MIN)
|
||||
#else
|
||||
if ( (intValue >> 32))
|
||||
#endif
|
||||
{
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newLong( (JSINT64) (intValue * (JSINT64) intNeg)));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newInt( (JSINT32) (intValue * intNeg)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
DECODE_FRACTION:
|
||||
|
||||
// Scan fraction part
|
||||
frcValue = 0.0;
|
||||
while (1)
|
||||
{
|
||||
chr = (int) (unsigned char) *(ds->start);
|
||||
|
||||
switch (chr)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (decimalCount < JSON_DOUBLE_MAX_DECIMALS)
|
||||
{
|
||||
frcValue = frcValue * 10.0 + (double) (chr - 48);
|
||||
decimalCount ++;
|
||||
}
|
||||
ds->start ++;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
ds->start ++;
|
||||
goto DECODE_EXPONENT;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto BREAK_FRC_LOOP;
|
||||
}
|
||||
}
|
||||
|
||||
BREAK_FRC_LOOP:
|
||||
|
||||
if (intValue < 0)
|
||||
{
|
||||
intNeg = 1;
|
||||
}
|
||||
|
||||
//FIXME: Check for arithemtic overflow here
|
||||
ds->lastType = JT_DOUBLE;
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (createDouble( (double) intNeg, (double) intValue, frcValue, decimalCount)));
|
||||
|
||||
DECODE_EXPONENT:
|
||||
expNeg = 1.0;
|
||||
|
||||
if (*(ds->start) == '-')
|
||||
{
|
||||
expNeg = -1.0;
|
||||
ds->start ++;
|
||||
}
|
||||
else
|
||||
if (*(ds->start) == '+')
|
||||
{
|
||||
expNeg = +1.0;
|
||||
ds->start ++;
|
||||
}
|
||||
|
||||
expValue = 0.0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
chr = (int) (unsigned char) *(ds->start);
|
||||
|
||||
switch (chr)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
expValue = expValue * 10.0 + (double) (chr - 48);
|
||||
ds->start ++;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto BREAK_EXP_LOOP;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BREAK_EXP_LOOP:
|
||||
|
||||
#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
|
||||
#else
|
||||
if (intValue < 0)
|
||||
{
|
||||
intNeg = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//FIXME: Check for arithemtic overflow here
|
||||
ds->lastType = JT_DOUBLE;
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (createDouble( (double) intNeg, (double) intValue , frcValue, decimalCount) * pow(10.0, expValue * expNeg)));
|
||||
}
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_true ( struct DecoderState *ds)
|
||||
{
|
||||
ds->start ++;
|
||||
|
||||
if (*(ds->start++) != 'r')
|
||||
goto SETERROR;
|
||||
if (*(ds->start++) != 'u')
|
||||
goto SETERROR;
|
||||
if (*(ds->start++) != 'e')
|
||||
goto SETERROR;
|
||||
|
||||
ds->lastType = JT_TRUE;
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newTrue());
|
||||
|
||||
SETERROR:
|
||||
return SetError(ds, -1, "Unexpected character found when decoding 'true'");
|
||||
}
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_false ( struct DecoderState *ds)
|
||||
{
|
||||
ds->start ++;
|
||||
|
||||
if (*(ds->start++) != 'a')
|
||||
goto SETERROR;
|
||||
if (*(ds->start++) != 'l')
|
||||
goto SETERROR;
|
||||
if (*(ds->start++) != 's')
|
||||
goto SETERROR;
|
||||
if (*(ds->start++) != 'e')
|
||||
goto SETERROR;
|
||||
|
||||
ds->lastType = JT_FALSE;
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newFalse());
|
||||
|
||||
SETERROR:
|
||||
return SetError(ds, -1, "Unexpected character found when decoding 'false'");
|
||||
|
||||
}
|
||||
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_null ( struct DecoderState *ds)
|
||||
{
|
||||
ds->start ++;
|
||||
|
||||
if (*(ds->start++) != 'u')
|
||||
goto SETERROR;
|
||||
if (*(ds->start++) != 'l')
|
||||
goto SETERROR;
|
||||
if (*(ds->start++) != 'l')
|
||||
goto SETERROR;
|
||||
|
||||
ds->lastType = JT_NULL;
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newNull());
|
||||
|
||||
SETERROR:
|
||||
return SetError(ds, -1, "Unexpected character found when decoding 'null'");
|
||||
}
|
||||
|
||||
FASTCALL_ATTR void FASTCALL_MSVC SkipWhitespace(struct DecoderState *ds)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
switch (*ds->start)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
ds->start ++;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum DECODESTRINGSTATE
|
||||
{
|
||||
DS_ISNULL = 0x32,
|
||||
DS_ISQUOTE,
|
||||
DS_ISESCAPE,
|
||||
DS_UTFLENERROR,
|
||||
|
||||
};
|
||||
|
||||
static const JSUINT8 g_decoderLookup[256] =
|
||||
{
|
||||
/* 0x00 */ DS_ISNULL, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x10 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x20 */ 1, 1, DS_ISQUOTE, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, DS_ISESCAPE, 1, 1, 1,
|
||||
/* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x90 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0xa0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0xb0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0xc0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 0xd0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 0xe0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
/* 0xf0 */ 4, 4, 4, 4, 4, 4, 4, 4, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR,
|
||||
};
|
||||
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_string ( struct DecoderState *ds)
|
||||
{
|
||||
JSUTF16 sur[2] = { 0 };
|
||||
int iSur = 0;
|
||||
int index;
|
||||
wchar_t *escOffset;
|
||||
size_t escLen = (ds->escEnd - ds->escStart);
|
||||
JSUINT8 *inputOffset;
|
||||
JSUINT8 oct;
|
||||
JSUTF32 ucs;
|
||||
ds->lastType = JT_INVALID;
|
||||
ds->start ++;
|
||||
|
||||
if ( (ds->end - ds->start) > escLen)
|
||||
{
|
||||
size_t newSize = (ds->end - ds->start);
|
||||
|
||||
if (ds->escHeap)
|
||||
{
|
||||
ds->escStart = (wchar_t *) ds->dec->realloc (ds->escStart, newSize * sizeof(wchar_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t *oldStart = ds->escStart;
|
||||
ds->escHeap = 1;
|
||||
ds->escStart = (wchar_t *) ds->dec->malloc (newSize * sizeof(wchar_t));
|
||||
memcpy (ds->escStart, oldStart, escLen * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
ds->escEnd = ds->escStart + newSize;
|
||||
}
|
||||
|
||||
escOffset = ds->escStart;
|
||||
|
||||
//inputOffset = ds->start;
|
||||
inputOffset = (JSUINT8*)ds->start; // miloyip
|
||||
|
||||
while(1)
|
||||
{
|
||||
switch (g_decoderLookup[(JSUINT8)(*inputOffset)])
|
||||
{
|
||||
case DS_ISNULL:
|
||||
return SetError(ds, -1, "Unmatched ''\"' when when decoding 'string'");
|
||||
|
||||
case DS_ISQUOTE:
|
||||
ds->lastType = JT_UTF8;
|
||||
inputOffset ++;
|
||||
ds->start += ( (char *) inputOffset - (ds->start));
|
||||
RETURN_JSOBJ_NULLCHECK(ds->dec->newString(ds->escStart, escOffset));
|
||||
|
||||
case DS_UTFLENERROR:
|
||||
return SetError (ds, -1, "Invalid UTF-8 sequence length when decoding 'string'");
|
||||
|
||||
case DS_ISESCAPE:
|
||||
inputOffset ++;
|
||||
switch (*inputOffset)
|
||||
{
|
||||
case '\\': *(escOffset++) = L'\\'; inputOffset++; continue;
|
||||
case '\"': *(escOffset++) = L'\"'; inputOffset++; continue;
|
||||
case '/': *(escOffset++) = L'/'; inputOffset++; continue;
|
||||
case 'b': *(escOffset++) = L'\b'; inputOffset++; continue;
|
||||
case 'f': *(escOffset++) = L'\f'; inputOffset++; continue;
|
||||
case 'n': *(escOffset++) = L'\n'; inputOffset++; continue;
|
||||
case 'r': *(escOffset++) = L'\r'; inputOffset++; continue;
|
||||
case 't': *(escOffset++) = L'\t'; inputOffset++; continue;
|
||||
|
||||
case 'u':
|
||||
{
|
||||
int index;
|
||||
inputOffset ++;
|
||||
|
||||
for (index = 0; index < 4; index ++)
|
||||
{
|
||||
switch (*inputOffset)
|
||||
{
|
||||
case '\0': return SetError (ds, -1, "Unterminated unicode escape sequence when decoding 'string'");
|
||||
default: return SetError (ds, -1, "Unexpected character in unicode escape sequence when decoding 'string'");
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
sur[iSur] = (sur[iSur] << 4) + (JSUTF16) (*inputOffset - '0');
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
sur[iSur] = (sur[iSur] << 4) + 10 + (JSUTF16) (*inputOffset - 'a');
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
sur[iSur] = (sur[iSur] << 4) + 10 + (JSUTF16) (*inputOffset - 'A');
|
||||
break;
|
||||
}
|
||||
|
||||
inputOffset ++;
|
||||
}
|
||||
|
||||
|
||||
if (iSur == 0)
|
||||
{
|
||||
if((sur[iSur] & 0xfc00) == 0xd800)
|
||||
{
|
||||
// First of a surrogate pair, continue parsing
|
||||
iSur ++;
|
||||
break;
|
||||
}
|
||||
(*escOffset++) = (wchar_t) sur[iSur];
|
||||
iSur = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decode pair
|
||||
if ((sur[1] & 0xfc00) != 0xdc00)
|
||||
{
|
||||
return SetError (ds, -1, "Unpaired high surrogate when decoding 'string'");
|
||||
}
|
||||
|
||||
#if WCHAR_MAX == 0xffff
|
||||
(*escOffset++) = (wchar_t) sur[0];
|
||||
(*escOffset++) = (wchar_t) sur[1];
|
||||
#else
|
||||
(*escOffset++) = (wchar_t) 0x10000 + (((sur[0] - 0xd800) << 10) | (sur[1] - 0xdc00));
|
||||
#endif
|
||||
iSur = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case '\0': return SetError(ds, -1, "Unterminated escape sequence when decoding 'string'");
|
||||
default: return SetError(ds, -1, "Unrecognized escape sequence when decoding 'string'");
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*(escOffset++) = (wchar_t) (*inputOffset++);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
ucs = (*inputOffset++) & 0x1f;
|
||||
ucs <<= 6;
|
||||
if (((*inputOffset) & 0x80) != 0x80)
|
||||
{
|
||||
return SetError(ds, -1, "Invalid octet in UTF-8 sequence when decoding 'string'");
|
||||
}
|
||||
ucs |= (*inputOffset++) & 0x3f;
|
||||
if (ucs < 0x80) return SetError (ds, -1, "Overlong 2 byte UTF-8 sequence detected when decoding 'string'");
|
||||
*(escOffset++) = (wchar_t) ucs;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
JSUTF32 ucs = 0;
|
||||
ucs |= (*inputOffset++) & 0x0f;
|
||||
|
||||
for (index = 0; index < 2; index ++)
|
||||
{
|
||||
ucs <<= 6;
|
||||
oct = (*inputOffset++);
|
||||
|
||||
if ((oct & 0x80) != 0x80)
|
||||
{
|
||||
return SetError(ds, -1, "Invalid octet in UTF-8 sequence when decoding 'string'");
|
||||
}
|
||||
|
||||
ucs |= oct & 0x3f;
|
||||
}
|
||||
|
||||
if (ucs < 0x800) return SetError (ds, -1, "Overlong 3 byte UTF-8 sequence detected when encoding string");
|
||||
*(escOffset++) = (wchar_t) ucs;
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
JSUTF32 ucs = 0;
|
||||
ucs |= (*inputOffset++) & 0x07;
|
||||
|
||||
for (index = 0; index < 3; index ++)
|
||||
{
|
||||
ucs <<= 6;
|
||||
oct = (*inputOffset++);
|
||||
|
||||
if ((oct & 0x80) != 0x80)
|
||||
{
|
||||
return SetError(ds, -1, "Invalid octet in UTF-8 sequence when decoding 'string'");
|
||||
}
|
||||
|
||||
ucs |= oct & 0x3f;
|
||||
}
|
||||
|
||||
if (ucs < 0x10000) return SetError (ds, -1, "Overlong 4 byte UTF-8 sequence detected when decoding 'string'");
|
||||
|
||||
#if WCHAR_MAX == 0xffff
|
||||
if (ucs >= 0x10000)
|
||||
{
|
||||
ucs -= 0x10000;
|
||||
*(escOffset++) = (ucs >> 10) + 0xd800;
|
||||
*(escOffset++) = (ucs & 0x3ff) + 0xdc00;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(escOffset++) = (wchar_t) ucs;
|
||||
}
|
||||
#else
|
||||
*(escOffset++) = (wchar_t) ucs;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_array( struct DecoderState *ds)
|
||||
{
|
||||
JSOBJ itemValue;
|
||||
JSOBJ newObj = ds->dec->newArray();
|
||||
|
||||
ds->lastType = JT_INVALID;
|
||||
ds->start ++;
|
||||
|
||||
while (1)//(*ds->start) != '\0')
|
||||
{
|
||||
SkipWhitespace(ds);
|
||||
|
||||
if ((*ds->start) == ']')
|
||||
{
|
||||
*ds->start ++;
|
||||
return newObj;
|
||||
}
|
||||
|
||||
itemValue = decode_any(ds);
|
||||
|
||||
if (itemValue == NULL)
|
||||
{
|
||||
ds->dec->releaseObject(newObj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ds->dec->arrayAddItem (newObj, itemValue);
|
||||
|
||||
SkipWhitespace(ds);
|
||||
|
||||
switch (*(ds->start++))
|
||||
{
|
||||
case ']':
|
||||
return newObj;
|
||||
|
||||
case ',':
|
||||
break;
|
||||
|
||||
default:
|
||||
ds->dec->releaseObject(newObj);
|
||||
return SetError(ds, -1, "Unexpected character in found when decoding array value");
|
||||
}
|
||||
}
|
||||
|
||||
ds->dec->releaseObject(newObj);
|
||||
return SetError(ds, -1, "Unmatched ']' when decoding 'array'");
|
||||
}
|
||||
|
||||
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_object( struct DecoderState *ds)
|
||||
{
|
||||
JSOBJ itemName;
|
||||
JSOBJ itemValue;
|
||||
JSOBJ newObj = ds->dec->newObject();
|
||||
|
||||
ds->start ++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
SkipWhitespace(ds);
|
||||
|
||||
if ((*ds->start) == '}')
|
||||
{
|
||||
ds->start ++;
|
||||
return newObj;
|
||||
}
|
||||
|
||||
ds->lastType = JT_INVALID;
|
||||
itemName = decode_any(ds);
|
||||
|
||||
if (itemName == NULL)
|
||||
{
|
||||
ds->dec->releaseObject(newObj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ds->lastType != JT_UTF8)
|
||||
{
|
||||
ds->dec->releaseObject(newObj);
|
||||
ds->dec->releaseObject(itemName);
|
||||
return SetError(ds, -1, "Key name of object must be 'string' when decoding 'object'");
|
||||
}
|
||||
|
||||
SkipWhitespace(ds);
|
||||
|
||||
if (*(ds->start++) != ':')
|
||||
{
|
||||
ds->dec->releaseObject(newObj);
|
||||
ds->dec->releaseObject(itemName);
|
||||
return SetError(ds, -1, "No ':' found when decoding object value");
|
||||
}
|
||||
|
||||
SkipWhitespace(ds);
|
||||
|
||||
itemValue = decode_any(ds);
|
||||
|
||||
if (itemValue == NULL)
|
||||
{
|
||||
ds->dec->releaseObject(newObj);
|
||||
ds->dec->releaseObject(itemName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ds->dec->objectAddKey (newObj, itemName, itemValue);
|
||||
|
||||
SkipWhitespace(ds);
|
||||
|
||||
switch (*(ds->start++))
|
||||
{
|
||||
case '}':
|
||||
return newObj;
|
||||
|
||||
case ',':
|
||||
break;
|
||||
|
||||
default:
|
||||
ds->dec->releaseObject(newObj);
|
||||
return SetError(ds, -1, "Unexpected character in found when decoding object value");
|
||||
}
|
||||
}
|
||||
|
||||
ds->dec->releaseObject(newObj);
|
||||
return SetError(ds, -1, "Unmatched '}' when decoding object");
|
||||
}
|
||||
|
||||
FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_any(struct DecoderState *ds)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
switch (*ds->start)
|
||||
{
|
||||
case '\"':
|
||||
return decode_string (ds);
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
return decode_numeric (ds);
|
||||
|
||||
case '[': return decode_array (ds);
|
||||
case '{': return decode_object (ds);
|
||||
case 't': return decode_true (ds);
|
||||
case 'f': return decode_false (ds);
|
||||
case 'n': return decode_null (ds);
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
// White space
|
||||
ds->start ++;
|
||||
break;
|
||||
|
||||
default:
|
||||
return SetError(ds, -1, "Expected object or value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer)
|
||||
{
|
||||
|
||||
/*
|
||||
FIXME: Base the size of escBuffer of that of cbBuffer so that the unicode escaping doesn't run into the wall each time */
|
||||
struct DecoderState ds;
|
||||
wchar_t escBuffer[(JSON_MAX_STACK_BUFFER_SIZE / sizeof(wchar_t))];
|
||||
JSOBJ ret;
|
||||
|
||||
ds.start = (char *) buffer;
|
||||
ds.end = ds.start + cbBuffer;
|
||||
|
||||
ds.escStart = escBuffer;
|
||||
ds.escEnd = ds.escStart + (JSON_MAX_STACK_BUFFER_SIZE / sizeof(wchar_t));
|
||||
ds.escHeap = 0;
|
||||
ds.dec = dec;
|
||||
ds.dec->errorStr = NULL;
|
||||
ds.dec->errorOffset = NULL;
|
||||
|
||||
ds.dec = dec;
|
||||
|
||||
ret = decode_any (&ds);
|
||||
|
||||
if (ds.escHeap)
|
||||
{
|
||||
dec->free(ds.escStart);
|
||||
}
|
||||
return ret;
|
||||
}
|
830
thirdparty/ultrajson/ultrajsonenc.c
vendored
830
thirdparty/ultrajson/ultrajsonenc.c
vendored
@ -1,830 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. All advertising materials mentioning features or use of this software
|
||||
must display the following acknowledgement:
|
||||
This product includes software developed by ESN Social Software AB (www.esn.me).
|
||||
4. Neither the name of the ESN Social Software AB nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ESN SOCIAL SOFTWARE AB ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ESN SOCIAL SOFTWARE AB BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Portions of code from:
|
||||
MODP_ASCII - Ascii transformations (upper/lower, etc)
|
||||
http://code.google.com/p/stringencoders/
|
||||
Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "ultrajson.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
|
||||
static const char g_hexChars[] = "0123456789abcdef";
|
||||
static const char g_escapeChars[] = "0123456789\\b\\t\\n\\f\\r\\\"\\\\\\/";
|
||||
|
||||
|
||||
/*
|
||||
FIXME: While this is fine dandy and working it's a magic value mess which probably only the author understands.
|
||||
Needs a cleanup and more documentation */
|
||||
|
||||
/*
|
||||
Table for pure ascii output escaping all characters above 127 to \uXXXX */
|
||||
static const JSUINT8 g_asciiOutputTable[256] =
|
||||
{
|
||||
/* 0x00 */ 0, 30, 30, 30, 30, 30, 30, 30, 10, 12, 14, 30, 16, 18, 30, 30,
|
||||
/* 0x10 */ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
||||
/* 0x20 */ 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1/*24*/,
|
||||
/* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 1, 1, 1,
|
||||
/* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0x90 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0xa0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0xb0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 0xc0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 0xd0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
/* 0xe0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
/* 0xf0 */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
|
||||
};
|
||||
|
||||
|
||||
static void SetError (JSOBJ obj, JSONObjectEncoder *enc, const char *message)
|
||||
{
|
||||
enc->errorMsg = message;
|
||||
enc->errorObj = obj;
|
||||
}
|
||||
|
||||
/*
|
||||
FIXME: Keep track of how big these get across several encoder calls and try to make an estimate
|
||||
That way we won't run our head into the wall each call */
|
||||
void Buffer_Realloc (JSONObjectEncoder *enc, size_t cbNeeded)
|
||||
{
|
||||
size_t curSize = enc->end - enc->start;
|
||||
size_t newSize = curSize * 2;
|
||||
size_t offset = enc->offset - enc->start;
|
||||
|
||||
while (newSize < curSize + cbNeeded)
|
||||
{
|
||||
newSize *= 2;
|
||||
}
|
||||
|
||||
if (enc->heap)
|
||||
{
|
||||
enc->start = (char *) enc->realloc (enc->start, newSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *oldStart = enc->start;
|
||||
enc->heap = 1;
|
||||
enc->start = (char *) enc->malloc (newSize);
|
||||
memcpy (enc->start, oldStart, offset);
|
||||
}
|
||||
enc->offset = enc->start + offset;
|
||||
enc->end = enc->start + newSize;
|
||||
}
|
||||
|
||||
FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC Buffer_AppendShortHexUnchecked (char *outputOffset, unsigned short value)
|
||||
{
|
||||
*(outputOffset++) = g_hexChars[(value & 0xf000) >> 12];
|
||||
*(outputOffset++) = g_hexChars[(value & 0x0f00) >> 8];
|
||||
*(outputOffset++) = g_hexChars[(value & 0x00f0) >> 4];
|
||||
*(outputOffset++) = g_hexChars[(value & 0x000f) >> 0];
|
||||
}
|
||||
|
||||
int Buffer_EscapeStringUnvalidated (JSOBJ obj, JSONObjectEncoder *enc, const char *io, const char *end)
|
||||
{
|
||||
char *of = (char *) enc->offset;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (*io)
|
||||
{
|
||||
case 0x00:
|
||||
enc->offset += (of - enc->offset);
|
||||
return TRUE;
|
||||
|
||||
case '\"': (*of++) = '\\'; (*of++) = '\"'; break;
|
||||
case '\\': (*of++) = '\\'; (*of++) = '\\'; break;
|
||||
//case '/': (*of++) = '\\'; (*of++) = '/'; break;
|
||||
case '\b': (*of++) = '\\'; (*of++) = 'b'; break;
|
||||
case '\f': (*of++) = '\\'; (*of++) = 'f'; break;
|
||||
case '\n': (*of++) = '\\'; (*of++) = 'n'; break;
|
||||
case '\r': (*of++) = '\\'; (*of++) = 'r'; break;
|
||||
case '\t': (*of++) = '\\'; (*of++) = 't'; break;
|
||||
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x0b:
|
||||
case 0x0e:
|
||||
case 0x0f:
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1a:
|
||||
case 0x1b:
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
case 0x1f:
|
||||
*(of++) = '\\';
|
||||
*(of++) = 'u';
|
||||
*(of++) = '0';
|
||||
*(of++) = '0';
|
||||
*(of++) = g_hexChars[ (unsigned char) (((*io) & 0xf0) >> 4)];
|
||||
*(of++) = g_hexChars[ (unsigned char) ((*io) & 0x0f)];
|
||||
break;
|
||||
|
||||
default: (*of++) = (*io); break;
|
||||
}
|
||||
|
||||
*io++;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
FIXME:
|
||||
This code only works with Little and Big Endian
|
||||
|
||||
FIXME: The JSON spec says escape "/" but non of the others do and we don't
|
||||
want to be left alone doing it so we don't :)
|
||||
|
||||
*/
|
||||
int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, const char *io, const char *end)
|
||||
{
|
||||
JSUTF32 ucs;
|
||||
char *of = (char *) enc->offset;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
//JSUINT8 chr = (unsigned char) *io;
|
||||
JSUINT8 utflen = g_asciiOutputTable[(unsigned char) *io];
|
||||
|
||||
switch (utflen)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
enc->offset += (of - enc->offset);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
*(of++)= (*io++);
|
||||
continue;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
JSUTF32 in;
|
||||
|
||||
if (io + 1 > end)
|
||||
{
|
||||
enc->offset += (of - enc->offset);
|
||||
SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
in = *((JSUTF16 *) io);
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
ucs = ((in & 0x1f) << 6) | ((in >> 8) & 0x3f);
|
||||
#else
|
||||
ucs = ((in & 0x1f00) >> 2) | (in & 0x3f);
|
||||
#endif
|
||||
|
||||
if (ucs < 0x80)
|
||||
{
|
||||
enc->offset += (of - enc->offset);
|
||||
SetError (obj, enc, "Overlong 2 byte UTF-8 sequence detected when encoding string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
io += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
JSUTF32 in;
|
||||
|
||||
if (io + 2 > end)
|
||||
{
|
||||
enc->offset += (of - enc->offset);
|
||||
SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
in = *((JSUTF16 *) io);
|
||||
in |= *((JSUINT8 *) io + 2) << 16;
|
||||
ucs = ((in & 0x0f) << 12) | ((in & 0x3f00) >> 2) | ((in & 0x3f0000) >> 16);
|
||||
#else
|
||||
in = *((JSUTF16 *) io) << 8;
|
||||
in |= *((JSUINT8 *) io + 2);
|
||||
ucs = ((in & 0x0f0000) >> 4) | ((in & 0x3f00) >> 2) | (in & 0x3f);
|
||||
#endif
|
||||
|
||||
|
||||
if (ucs < 0x800)
|
||||
{
|
||||
enc->offset += (of - enc->offset);
|
||||
SetError (obj, enc, "Overlong 3 byte UTF-8 sequence detected when encoding string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
io += 3;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
JSUTF32 in;
|
||||
|
||||
if (io + 3 > end)
|
||||
{
|
||||
enc->offset += (of - enc->offset);
|
||||
SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
in = *((JSUTF32 *) io);
|
||||
ucs = ((in & 0x07) << 18) | ((in & 0x3f00) << 4) | ((in & 0x3f0000) >> 10) | ((in & 0x3f000000) >> 24);
|
||||
#else
|
||||
in = *((JSUTF32 *) io);
|
||||
ucs = ((in & 0x07000000) >> 6) | ((in & 0x3f0000) >> 4) | ((in & 0x3f00) >> 2) | (in & 0x3f);
|
||||
#endif
|
||||
if (ucs < 0x10000)
|
||||
{
|
||||
enc->offset += (of - enc->offset);
|
||||
SetError (obj, enc, "Overlong 4 byte UTF-8 sequence detected when encoding string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
io += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 5:
|
||||
case 6:
|
||||
enc->offset += (of - enc->offset);
|
||||
SetError (obj, enc, "Unsupported UTF-8 sequence length when encoding string");
|
||||
return FALSE;
|
||||
|
||||
case 30:
|
||||
// \uXXXX encode
|
||||
*(of++) = '\\';
|
||||
*(of++) = 'u';
|
||||
*(of++) = '0';
|
||||
*(of++) = '0';
|
||||
*(of++) = g_hexChars[ (unsigned char) (((*io) & 0xf0) >> 4)];
|
||||
*(of++) = g_hexChars[ (unsigned char) ((*io) & 0x0f)];
|
||||
io ++;
|
||||
continue;
|
||||
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
case 18:
|
||||
case 20:
|
||||
case 22:
|
||||
//case 24: (enable for / escaping)
|
||||
*(of++) = *( (char *) (g_escapeChars + utflen + 0));
|
||||
*(of++) = *( (char *) (g_escapeChars + utflen + 1));
|
||||
io ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
If the character is a UTF8 sequence of length > 1 we end up here */
|
||||
if (ucs >= 0x10000)
|
||||
{
|
||||
ucs -= 0x10000;
|
||||
*(of++) = '\\';
|
||||
*(of++) = 'u';
|
||||
Buffer_AppendShortHexUnchecked(of, (ucs >> 10) + 0xd800);
|
||||
of += 4;
|
||||
|
||||
*(of++) = '\\';
|
||||
*(of++) = 'u';
|
||||
Buffer_AppendShortHexUnchecked(of, (ucs & 0x3ff) + 0xdc00);
|
||||
of += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(of++) = '\\';
|
||||
*(of++) = 'u';
|
||||
Buffer_AppendShortHexUnchecked(of, ucs);
|
||||
of += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define Buffer_Reserve(__enc, __len) \
|
||||
if ((__enc)->offset + (__len) > (__enc)->end) \
|
||||
{ \
|
||||
Buffer_Realloc((__enc), (__len));\
|
||||
} \
|
||||
|
||||
|
||||
#define Buffer_AppendCharUnchecked(__enc, __chr) \
|
||||
*((__enc)->offset++) = __chr; \
|
||||
|
||||
FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC strreverse(char* begin, char* end)
|
||||
{
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
}
|
||||
|
||||
void Buffer_AppendIntUnchecked(JSONObjectEncoder *enc, JSINT32 value)
|
||||
{
|
||||
char* wstr;
|
||||
JSUINT32 uvalue = (value < 0) ? -value : value;
|
||||
|
||||
wstr = enc->offset;
|
||||
// Conversion. Number is reversed.
|
||||
|
||||
do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
|
||||
if (value < 0) *wstr++ = '-';
|
||||
|
||||
// Reverse string
|
||||
strreverse(enc->offset,wstr - 1);
|
||||
enc->offset += (wstr - (enc->offset));
|
||||
}
|
||||
|
||||
void Buffer_AppendLongUnchecked(JSONObjectEncoder *enc, JSINT64 value)
|
||||
{
|
||||
char* wstr;
|
||||
JSUINT64 uvalue = (value < 0) ? -value : value;
|
||||
|
||||
wstr = enc->offset;
|
||||
// Conversion. Number is reversed.
|
||||
|
||||
do *wstr++ = (char)(48 + (uvalue % 10ULL)); while(uvalue /= 10ULL);
|
||||
if (value < 0) *wstr++ = '-';
|
||||
|
||||
// Reverse string
|
||||
strreverse(enc->offset,wstr - 1);
|
||||
enc->offset += (wstr - (enc->offset));
|
||||
}
|
||||
|
||||
int Buffer_AppendDoubleUnchecked(JSOBJ obj, JSONObjectEncoder *enc, double value)
|
||||
{
|
||||
/* if input is larger than thres_max, revert to exponential */
|
||||
const double thres_max = (double)(0x7FFFFFFF);
|
||||
int count;
|
||||
double diff = 0.0;
|
||||
char* str = enc->offset;
|
||||
char* wstr = str;
|
||||
int whole;
|
||||
double tmp;
|
||||
uint32_t frac;
|
||||
int neg;
|
||||
double pow10;
|
||||
|
||||
if (value == HUGE_VAL || value == -HUGE_VAL)
|
||||
{
|
||||
SetError (obj, enc, "Invalid Inf value when encoding double");
|
||||
return FALSE;
|
||||
}
|
||||
if (! (value == value))
|
||||
{
|
||||
SetError (obj, enc, "Invalid Nan value when encoding double");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* we'll work in positive values and deal with the
|
||||
negative sign issue later */
|
||||
neg = 0;
|
||||
if (value < 0)
|
||||
{
|
||||
neg = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
pow10 = g_pow10[enc->doublePrecision];
|
||||
|
||||
whole = (int) value;
|
||||
tmp = (value - whole) * pow10;
|
||||
frac = (uint32_t)(tmp);
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5)
|
||||
{
|
||||
++frac;
|
||||
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
|
||||
if (frac >= pow10)
|
||||
{
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (diff == 0.5 && ((frac == 0) || (frac & 1)))
|
||||
{
|
||||
/* if halfway, round up if odd, OR
|
||||
if last digit is 0. That last part is strange */
|
||||
++frac;
|
||||
}
|
||||
|
||||
/* for very large numbers switch back to native sprintf for exponentials.
|
||||
anyone want to write code to replace this? */
|
||||
/*
|
||||
normal printf behavior is to print EVERY whole number digit
|
||||
which can be 100s of characters overflowing your buffers == bad
|
||||
*/
|
||||
if (value > thres_max)
|
||||
{
|
||||
enc->offset += sprintf(str, "%e", neg ? -value : value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (enc->doublePrecision == 0)
|
||||
{
|
||||
diff = value - whole;
|
||||
|
||||
if (diff > 0.5)
|
||||
{
|
||||
/* greater than 0.5, round up, e.g. 1.6 -> 2 */
|
||||
++whole;
|
||||
}
|
||||
else
|
||||
if (diff == 0.5 && (whole & 1))
|
||||
{
|
||||
/* exactly 0.5 and ODD, then round up */
|
||||
/* 1.5 -> 2, but 2.5 -> 2 */
|
||||
++whole;
|
||||
}
|
||||
|
||||
//vvvvvvvvvvvvvvvvvvv Diff from modp_dto2
|
||||
}
|
||||
else
|
||||
if (frac)
|
||||
{
|
||||
count = enc->doublePrecision;
|
||||
// now do fractional part, as an unsigned number
|
||||
// we know it is not 0 but we can have leading zeros, these
|
||||
// should be removed
|
||||
while (!(frac % 10))
|
||||
{
|
||||
--count;
|
||||
frac /= 10;
|
||||
}
|
||||
//^^^^^^^^^^^^^^^^^^^ Diff from modp_dto2
|
||||
|
||||
// now do fractional part, as an unsigned number
|
||||
do
|
||||
{
|
||||
--count;
|
||||
*wstr++ = (char)(48 + (frac % 10));
|
||||
} while (frac /= 10);
|
||||
// add extra 0s
|
||||
while (count-- > 0)
|
||||
{
|
||||
*wstr++ = '0';
|
||||
}
|
||||
// add decimal
|
||||
*wstr++ = '.';
|
||||
}
|
||||
else
|
||||
{
|
||||
*wstr++ = '0';
|
||||
*wstr++ = '.';
|
||||
}
|
||||
|
||||
// do whole part
|
||||
// Take care of sign
|
||||
// Conversion. Number is reversed.
|
||||
do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
|
||||
|
||||
if (neg)
|
||||
{
|
||||
*wstr++ = '-';
|
||||
}
|
||||
strreverse(str, wstr-1);
|
||||
enc->offset += (wstr - (enc->offset));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
FIXME:
|
||||
Handle integration functions returning NULL here */
|
||||
|
||||
/*
|
||||
FIXME:
|
||||
Perhaps implement recursion detection */
|
||||
|
||||
void encode(JSOBJ obj, JSONObjectEncoder *enc, const char *name, size_t cbName)
|
||||
{
|
||||
JSONTypeContext tc;
|
||||
size_t szlen;
|
||||
|
||||
if (enc->level > enc->recursionMax)
|
||||
{
|
||||
SetError (obj, enc, "Maximum recursion level reached");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
This reservation must hold
|
||||
|
||||
length of _name as encoded worst case +
|
||||
maxLength of double to string OR maxLength of JSLONG to string
|
||||
|
||||
Since input is assumed to be UTF-8 the worst character length is:
|
||||
|
||||
4 bytes (of UTF-8) => "\uXXXX\uXXXX" (12 bytes)
|
||||
*/
|
||||
|
||||
Buffer_Reserve(enc, 256 + (((cbName / 4) + 1) * 12));
|
||||
|
||||
if (name)
|
||||
{
|
||||
Buffer_AppendCharUnchecked(enc, '\"');
|
||||
|
||||
if (enc->forceASCII)
|
||||
{
|
||||
if (!Buffer_EscapeStringValidated(obj, enc, name, name + cbName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Buffer_EscapeStringUnvalidated(obj, enc, name, name + cbName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Buffer_AppendCharUnchecked(enc, '\"');
|
||||
|
||||
Buffer_AppendCharUnchecked (enc, ':');
|
||||
#ifndef JSON_NO_EXTRA_WHITESPACE
|
||||
Buffer_AppendCharUnchecked (enc, ' ');
|
||||
#endif
|
||||
}
|
||||
|
||||
enc->beginTypeContext(obj, &tc);
|
||||
|
||||
switch (tc.type)
|
||||
{
|
||||
case JT_INVALID:
|
||||
return;
|
||||
|
||||
case JT_ARRAY:
|
||||
{
|
||||
int count = 0;
|
||||
JSOBJ iterObj;
|
||||
enc->iterBegin(obj, &tc);
|
||||
|
||||
Buffer_AppendCharUnchecked (enc, '[');
|
||||
|
||||
while (enc->iterNext(obj, &tc))
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
Buffer_AppendCharUnchecked (enc, ',');
|
||||
#ifndef JSON_NO_EXTRA_WHITESPACE
|
||||
Buffer_AppendCharUnchecked (buffer, ' ');
|
||||
#endif
|
||||
}
|
||||
|
||||
iterObj = enc->iterGetValue(obj, &tc);
|
||||
|
||||
enc->level ++;
|
||||
encode (iterObj, enc, NULL, 0);
|
||||
count ++;
|
||||
}
|
||||
|
||||
enc->iterEnd(obj, &tc);
|
||||
Buffer_AppendCharUnchecked (enc, ']');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_OBJECT:
|
||||
{
|
||||
int count = 0;
|
||||
JSOBJ iterObj;
|
||||
char *objName;
|
||||
|
||||
enc->iterBegin(obj, &tc);
|
||||
|
||||
Buffer_AppendCharUnchecked (enc, '{');
|
||||
|
||||
while (enc->iterNext(obj, &tc))
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
Buffer_AppendCharUnchecked (enc, ',');
|
||||
#ifndef JSON_NO_EXTRA_WHITESPACE
|
||||
Buffer_AppendCharUnchecked (enc, ' ');
|
||||
#endif
|
||||
}
|
||||
|
||||
iterObj = enc->iterGetValue(obj, &tc);
|
||||
objName = enc->iterGetName(obj, &tc, &szlen);
|
||||
|
||||
enc->level ++;
|
||||
encode (iterObj, enc, objName, szlen);
|
||||
count ++;
|
||||
}
|
||||
|
||||
enc->iterEnd(obj, &tc);
|
||||
Buffer_AppendCharUnchecked (enc, '}');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_LONG:
|
||||
{
|
||||
Buffer_AppendLongUnchecked (enc, enc->getLongValue(obj, &tc));
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_INT:
|
||||
{
|
||||
Buffer_AppendIntUnchecked (enc, enc->getIntValue(obj, &tc));
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_TRUE:
|
||||
{
|
||||
Buffer_AppendCharUnchecked (enc, 't');
|
||||
Buffer_AppendCharUnchecked (enc, 'r');
|
||||
Buffer_AppendCharUnchecked (enc, 'u');
|
||||
Buffer_AppendCharUnchecked (enc, 'e');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_FALSE:
|
||||
{
|
||||
Buffer_AppendCharUnchecked (enc, 'f');
|
||||
Buffer_AppendCharUnchecked (enc, 'a');
|
||||
Buffer_AppendCharUnchecked (enc, 'l');
|
||||
Buffer_AppendCharUnchecked (enc, 's');
|
||||
Buffer_AppendCharUnchecked (enc, 'e');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case JT_NULL:
|
||||
{
|
||||
Buffer_AppendCharUnchecked (enc, 'n');
|
||||
Buffer_AppendCharUnchecked (enc, 'u');
|
||||
Buffer_AppendCharUnchecked (enc, 'l');
|
||||
Buffer_AppendCharUnchecked (enc, 'l');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_DOUBLE:
|
||||
{
|
||||
if (!Buffer_AppendDoubleUnchecked (obj, enc, enc->getDoubleValue(obj, &tc)))
|
||||
{
|
||||
enc->endTypeContext(obj, &tc);
|
||||
enc->level --;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_UTF8:
|
||||
{
|
||||
const char *value = enc->getStringValue(obj, &tc, &szlen);
|
||||
Buffer_Reserve(enc, ((szlen / 4) + 1) * 12);
|
||||
Buffer_AppendCharUnchecked (enc, '\"');
|
||||
|
||||
|
||||
if (enc->forceASCII)
|
||||
{
|
||||
if (!Buffer_EscapeStringValidated(obj, enc, value, value + szlen))
|
||||
{
|
||||
enc->endTypeContext(obj, &tc);
|
||||
enc->level --;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Buffer_EscapeStringUnvalidated(obj, enc, value, value + szlen))
|
||||
{
|
||||
enc->endTypeContext(obj, &tc);
|
||||
enc->level --;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer_AppendCharUnchecked (enc, '\"');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enc->endTypeContext(obj, &tc);
|
||||
enc->level --;
|
||||
|
||||
}
|
||||
|
||||
char *JSON_EncodeObject(JSOBJ obj, JSONObjectEncoder *enc, char *_buffer, size_t _cbBuffer)
|
||||
{
|
||||
enc->malloc = enc->malloc ? enc->malloc : malloc;
|
||||
enc->free = enc->free ? enc->free : free;
|
||||
enc->realloc = enc->realloc ? enc->realloc : realloc;
|
||||
enc->errorMsg = NULL;
|
||||
enc->errorObj = NULL;
|
||||
enc->level = 0;
|
||||
|
||||
if (enc->recursionMax < 1)
|
||||
{
|
||||
enc->recursionMax = JSON_MAX_RECURSION_DEPTH;
|
||||
}
|
||||
|
||||
if (enc->doublePrecision < 0 ||
|
||||
enc->doublePrecision > JSON_DOUBLE_MAX_DECIMALS)
|
||||
{
|
||||
enc->doublePrecision = JSON_DOUBLE_MAX_DECIMALS;
|
||||
}
|
||||
|
||||
if (_buffer == NULL)
|
||||
{
|
||||
_cbBuffer = 32768;
|
||||
enc->start = (char *) enc->malloc (_cbBuffer);
|
||||
enc->heap = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
enc->start = _buffer;
|
||||
enc->heap = 0;
|
||||
}
|
||||
|
||||
enc->end = enc->start + _cbBuffer;
|
||||
enc->offset = enc->start;
|
||||
|
||||
|
||||
encode (obj, enc, NULL, 0);
|
||||
|
||||
Buffer_Reserve(enc, 1);
|
||||
Buffer_AppendCharUnchecked(enc, '\0');
|
||||
|
||||
return enc->start;
|
||||
}
|
13
thirdparty/yajl/COPYING
vendored
13
thirdparty/yajl/COPYING
vendored
@ -1,13 +0,0 @@
|
||||
Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
157
thirdparty/yajl/ChangeLog
vendored
157
thirdparty/yajl/ChangeLog
vendored
@ -1,157 +0,0 @@
|
||||
2.0.1
|
||||
* lth generator flag to allow client to specify they want
|
||||
escaped solidi '/'. issue #28
|
||||
* lth crash fix when yajl_parse() is never called. issue #27
|
||||
|
||||
2.0.0
|
||||
* lth YAJL is now ISC licensed: http://en.wikipedia.org/wiki/ISC_license
|
||||
* lth 20-35% (osx and linux respectively) parsing performance
|
||||
improvement attained by tweaking string scanning (idea: @michaelrhanson).
|
||||
* Florian Forster & lth - yajl_tree interface introduced as a higher level
|
||||
interface to the parser (eats JSON, poops a memory representation)
|
||||
* lth require a C99 compiler
|
||||
* lth integers are now represented with long long (64bit+) on all platforms.
|
||||
* lth size_t now used throughout to represent buffer lengths, so you can
|
||||
safely manage buffers greater than 4GB.
|
||||
* gno semantic improvements to yajl's API regarding partial value parsing and
|
||||
trailing garbage
|
||||
* lth new configuration mechanism for yajl, see yajl_config() and
|
||||
yajl_gen_config()
|
||||
* gno more allocation checking in more places
|
||||
* gno remove usage of strtol, replace with custom implementation that cares
|
||||
not about your locale.
|
||||
* lth yajl_parse_complete renamed to yajl_complete_parse.
|
||||
* lth add a switch to validate utf8 strings as they are generated.
|
||||
* lth tests are a lot quieter in their output.
|
||||
* lth addition of a little in tree performance benchmark, `perftest` in
|
||||
perf/perftest.c
|
||||
|
||||
1.0.12
|
||||
* Conrad Irwin - Parse null bytes correctly
|
||||
* Mirek Rusin - fix LLVM warnings
|
||||
* gno - Don't generate numbers for keys. closes #13
|
||||
* lth - various win32 fixes, including build documentation improvements
|
||||
* John Stamp - Don't export private symbols.
|
||||
* John Stamp - Install yajl_version.h, not the template.
|
||||
* John Stamp - Don't use -fPIC for static lib. Cmake will automatically add it for the shared.
|
||||
* lth 0 fix paths embedded in dylib upon installation on osx. closes #11
|
||||
|
||||
1.0.11
|
||||
* lth remove -Wno-missing-field-initializers for greater gcc compat (3.4.6)
|
||||
|
||||
1.0.10
|
||||
* Brian Maher - yajl is now buildable without a c++ compiler present
|
||||
* Brian Maher - fix header installation on OSX with cmake 2.8.0 installed
|
||||
* lth & vitali - allow builder to specify alternate lib directory
|
||||
for installation (i.e. lib64)
|
||||
* Vitali Lovich - yajl version number now programatically accessible
|
||||
* lth - prevent cmake from embedding rpaths in binaries. Static linking
|
||||
makes this unneccesary.
|
||||
|
||||
1.0.9
|
||||
* lth - fix inverted logic causing yajl_gen_double() to always fail on
|
||||
win32 (thanks to Fredrik Kihlander for the report)
|
||||
|
||||
1.0.8
|
||||
* Randall E. Barker - move dllexport defnitions so dlls with proper
|
||||
exports can again be generated on windows
|
||||
* lth - add yajl_get_bytes_consumed() which allows the client to
|
||||
determine the offset as an error, as well as determine how
|
||||
many bytes of an input buffer were consumed.
|
||||
* lth - fixes to keep "error offset" up to date (like when the
|
||||
client callback returns 0)
|
||||
* Brian Maher - allow client to specify a printing function in
|
||||
generation
|
||||
|
||||
1.0.7
|
||||
* lth fix win32 build (isinf and isnan)
|
||||
|
||||
1.0.6
|
||||
* lth fix several compiler warnings
|
||||
* lth fix generation of invalid json from yajl_gen_double
|
||||
(NaN is not JSON)
|
||||
* jstamp support for combining short options in tools
|
||||
* jstamp exit properly on errors from tools
|
||||
* octo test success no longer depends on integer size
|
||||
* max fix configure --prefix
|
||||
|
||||
1.0.5
|
||||
* lth several performance improvements related to function
|
||||
inlinin'
|
||||
|
||||
1.0.4
|
||||
* lth fix broken utf8 validation for three & four byte represenations.
|
||||
thanks to http://github.com/brianmario and
|
||||
http://github.com/technoweenie
|
||||
|
||||
1.0.3
|
||||
* lth fix syntax error in cplusplus extern "C" statements for wider
|
||||
compiler support
|
||||
|
||||
1.0.2
|
||||
* lth update doxygen documentation with new sample code, passing NULL
|
||||
for allocation functions added in 1.0.0
|
||||
|
||||
1.0.1
|
||||
* lth resolve crash in json_reformatter due to incorrectly ordered
|
||||
parameters.
|
||||
|
||||
1.0.0
|
||||
* lth add 'make install' rules, thaks to Andrei Soroker for the
|
||||
contribution.
|
||||
* lth client may override allocation routines at generator or parser
|
||||
allocation time
|
||||
* tjw add yajl_parse_complete routine to allow client to explicitly
|
||||
specify end-of-input, solving the "lonely number" case, where
|
||||
json text consists only of an element with no explicit syntactic
|
||||
end.
|
||||
* tjw many new test cases
|
||||
* tjw cleanup of code for symmetry and ease of reading
|
||||
* lth integration of patches from Robert Varga which cleanup
|
||||
compilation warnings on 64 bit linux
|
||||
|
||||
0.4.0
|
||||
* lth buffer overflow bug in yajl_gen_double s/%lf/%g/ - thanks to
|
||||
Eric Bergstrome
|
||||
* lth yajl_number callback to allow passthrough of arbitrary precision
|
||||
numbers to client. Thanks to Hatem Nassrat.
|
||||
* lth yajl_integer now deals in long, instead of long long. This
|
||||
combined with yajl_number improves compiler compatibility while
|
||||
maintaining precision.
|
||||
* lth better ./configure && make experience (still requires cmake and
|
||||
ruby)
|
||||
* lth fix handling of special characters hex 0F and 1F in yajl_encode
|
||||
(thanks to Robert Geiger)
|
||||
* lth allow leading zeros in exponents (thanks to Hatem Nassrat)
|
||||
|
||||
0.3.0
|
||||
* lth doxygen documentation (html & man) generated as part of the
|
||||
build
|
||||
* lth many documentation updates.
|
||||
* lth fix to work with older versions of cmake (don't use LOOSE_LOOP
|
||||
constructs)
|
||||
* lth work around different behavior of freebsd 4 scanf. initialize
|
||||
parameter to scanf to zero.
|
||||
* lth all tests run 32x with ranging buffer sizes to stress stream
|
||||
parsing
|
||||
* lth yajl_test accepts -b option to allow read buffer size to be
|
||||
set
|
||||
* lth option to validate UTF8 added to parser (argument in
|
||||
yajl_parser_cfg)
|
||||
* lth fix buffer overrun when chunk ends inside \u escaped text
|
||||
* lth support client cancelation
|
||||
|
||||
0.2.2
|
||||
* lth on windows build debug with C7 symbols and no pdb files.
|
||||
|
||||
0.2.1
|
||||
* fix yajl_reformat and yajl_verify to work on arbitrarily sized
|
||||
inputs.
|
||||
* fix win32 build break, clean up all errors and warnings.
|
||||
* fix optimized build flags.
|
||||
|
||||
0.2.0
|
||||
* optionally support comments in input text
|
||||
|
||||
0.1.0
|
||||
* Initial release
|
74
thirdparty/yajl/README
vendored
74
thirdparty/yajl/README
vendored
@ -1,74 +0,0 @@
|
||||
**********************************************************************
|
||||
This is YAJL 2, for the legacy version of YAJL. see
|
||||
https://github.com/lloyd/yajl/tree/1.x
|
||||
**********************************************************************
|
||||
|
||||
Welcome to Yet Another JSON Library (YAJL)
|
||||
|
||||
## Why does the world need another C library for parsing JSON?
|
||||
|
||||
Good question. In a review of current C JSON parsing libraries I was
|
||||
unable to find one that satisfies my requirements. Those are,
|
||||
0. written in C
|
||||
1. portable
|
||||
2. robust -- as close to "crash proof" as possible
|
||||
3. data representation independent
|
||||
4. fast
|
||||
5. generates verbose, useful error messages including context of where
|
||||
the error occurs in the input text.
|
||||
6. can parse JSON data off a stream, incrementally
|
||||
7. simple to use
|
||||
8. tiny
|
||||
|
||||
Numbers 3, 5, 6, and 7 where particularly hard to find, and were what
|
||||
caused me to ultimately create YAJL. This document is a tour of some
|
||||
of the more important aspects of YAJL.
|
||||
|
||||
## YAJL is Free.
|
||||
|
||||
Permissive licensing means you can use it in open source and
|
||||
commercial products alike without any fees. My request beyond the
|
||||
licensing is that if you find bugs drop me a email, or better yet,
|
||||
fork and fix.
|
||||
|
||||
Porting YAJL should be trivial, the implementation is ANSI C. If you
|
||||
port to new systems I'd love to hear of it and integrate your patches.
|
||||
|
||||
## YAJL is data representation independent.
|
||||
|
||||
BYODR! Many JSON libraries impose a structure based data representation
|
||||
on you. This is a benefit in some cases and a drawback in others.
|
||||
YAJL uses callbacks to remain agnostic of the in-memory representation.
|
||||
So if you wish to build up an in-memory representation, you may do so
|
||||
using YAJL, but you must bring the code that defines and populates the
|
||||
in memory structure.
|
||||
|
||||
This also means that YAJL can be used by other (higher level) JSON
|
||||
libraries if so desired.
|
||||
|
||||
## YAJL supports stream parsing
|
||||
|
||||
This means you do not need to hold the whole JSON representation in
|
||||
textual form in memory. This makes YAJL ideal for filtering projects,
|
||||
where you're converting YAJL from one form to another (i.e. XML). The
|
||||
included JSON pretty printer is an example of such a filter program.
|
||||
|
||||
## YAJL is fast
|
||||
|
||||
Minimal memory copying is performed. YAJL, when possible, returns
|
||||
pointers into the client provided text (i.e. for strings that have no
|
||||
embedded escape chars, hopefully the common case). I've put a lot of
|
||||
effort into profiling and tuning performance, but I have ignored a
|
||||
couple possible performance improvements to keep the interface clean,
|
||||
small, and flexible. My hope is that YAJL will perform comparably to
|
||||
the fastest JSON parser out there.
|
||||
|
||||
YAJL should impose both minimal CPU and memory requirements on your
|
||||
application.
|
||||
|
||||
## YAJL is tiny.
|
||||
|
||||
Fat free. No whip.
|
||||
|
||||
enjoy,
|
||||
Lloyd - July, 2007
|
9
thirdparty/yajl/TODO
vendored
9
thirdparty/yajl/TODO
vendored
@ -1,9 +0,0 @@
|
||||
* add a test for 0x1F bug
|
||||
* numeric overflow in integers and double
|
||||
* line and char offsets in the lexer and in error messages
|
||||
* testing:
|
||||
a. the permuter
|
||||
b. some performance comparison against json_checker.
|
||||
* investigate pull instead of push parsing
|
||||
* Handle memory allocation failures gracefully
|
||||
* cygwin/msys support on win32
|
75
thirdparty/yajl/include/yajl/yajl_common.h
vendored
75
thirdparty/yajl/include/yajl/yajl_common.h
vendored
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_COMMON_H__
|
||||
#define __YAJL_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define YAJL_MAX_DEPTH 128
|
||||
|
||||
/* msft dll export gunk. To build a DLL on windows, you
|
||||
* must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared
|
||||
* DLL, you must define YAJL_SHARED and WIN32 */
|
||||
#if defined(WIN32) && defined(YAJL_SHARED)
|
||||
# ifdef YAJL_BUILD
|
||||
# define YAJL_API __declspec(dllexport)
|
||||
# else
|
||||
# define YAJL_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303
|
||||
# define YAJL_API __attribute__ ((visibility("default")))
|
||||
# else
|
||||
# define YAJL_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** pointer to a malloc function, supporting client overriding memory
|
||||
* allocation routines */
|
||||
typedef void * (*yajl_malloc_func)(void *ctx, size_t sz);
|
||||
|
||||
/** pointer to a free function, supporting client overriding memory
|
||||
* allocation routines */
|
||||
typedef void (*yajl_free_func)(void *ctx, void * ptr);
|
||||
|
||||
/** pointer to a realloc function which can resize an allocation. */
|
||||
typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, size_t sz);
|
||||
|
||||
/** A structure which can be passed to yajl_*_alloc routines to allow the
|
||||
* client to specify memory allocation functions to be used. */
|
||||
typedef struct
|
||||
{
|
||||
/** pointer to a function that can allocate uninitialized memory */
|
||||
yajl_malloc_func malloc;
|
||||
/** pointer to a function that can resize memory allocations */
|
||||
yajl_realloc_func realloc;
|
||||
/** pointer to a function that can free memory allocated using
|
||||
* reallocFunction or mallocFunction */
|
||||
yajl_free_func free;
|
||||
/** a context pointer that will be passed to above allocation routines */
|
||||
void * ctx;
|
||||
} yajl_alloc_funcs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
157
thirdparty/yajl/include/yajl/yajl_gen.h
vendored
157
thirdparty/yajl/include/yajl/yajl_gen.h
vendored
@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_gen.h
|
||||
* Interface to YAJL's JSON generation facilities.
|
||||
*/
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#ifndef __YAJL_GEN_H__
|
||||
#define __YAJL_GEN_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/** generator status codes */
|
||||
typedef enum {
|
||||
/** no error */
|
||||
yajl_gen_status_ok = 0,
|
||||
/** at a point where a map key is generated, a function other than
|
||||
* yajl_gen_string was called */
|
||||
yajl_gen_keys_must_be_strings,
|
||||
/** YAJL's maximum generation depth was exceeded. see
|
||||
* YAJL_MAX_DEPTH */
|
||||
yajl_max_depth_exceeded,
|
||||
/** A generator function (yajl_gen_XXX) was called while in an error
|
||||
* state */
|
||||
yajl_gen_in_error_state,
|
||||
/** A complete JSON document has been generated */
|
||||
yajl_gen_generation_complete,
|
||||
/** yajl_gen_double was passed an invalid floating point value
|
||||
* (infinity or NaN). */
|
||||
yajl_gen_invalid_number,
|
||||
/** A print callback was passed in, so there is no internal
|
||||
* buffer to get from */
|
||||
yajl_gen_no_buf,
|
||||
/** returned from yajl_gen_string() when the yajl_gen_validate_utf8
|
||||
* option is enabled and an invalid was passed by client code.
|
||||
*/
|
||||
yajl_gen_invalid_string
|
||||
} yajl_gen_status;
|
||||
|
||||
/** an opaque handle to a generator */
|
||||
typedef struct yajl_gen_t * yajl_gen;
|
||||
|
||||
/** a callback used for "printing" the results. */
|
||||
typedef void (*yajl_print_t)(void * ctx,
|
||||
const char * str,
|
||||
size_t len);
|
||||
|
||||
/** configuration parameters for the parser, these may be passed to
|
||||
* yajl_gen_config() along with option specific argument(s). In general,
|
||||
* all configuration parameters default to *off*. */
|
||||
typedef enum {
|
||||
/** generate indented (beautiful) output */
|
||||
yajl_gen_beautify = 0x01,
|
||||
/**
|
||||
* Set an indent string which is used when yajl_gen_beautify
|
||||
* is enabled. Maybe something like \\t or some number of
|
||||
* spaces. The default is four spaces ' '.
|
||||
*/
|
||||
yajl_gen_indent_string = 0x02,
|
||||
/**
|
||||
* Set a function and context argument that should be used to
|
||||
* output generated json. the function should conform to the
|
||||
* yajl_print_t prototype while the context argument is a
|
||||
* void * of your choosing.
|
||||
*
|
||||
* example:
|
||||
* yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr);
|
||||
*/
|
||||
yajl_gen_print_callback = 0x04,
|
||||
/**
|
||||
* Normally the generator does not validate that strings you
|
||||
* pass to it via yajl_gen_string() are valid UTF8. Enabling
|
||||
* this option will cause it to do so.
|
||||
*/
|
||||
yajl_gen_validate_utf8 = 0x08,
|
||||
/**
|
||||
* the forward solidus (slash or '/' in human) is not required to be
|
||||
* escaped in json text. By default, YAJL will not escape it in the
|
||||
* iterest of saving bytes. Setting this flag will cause YAJL to
|
||||
* always escape '/' in generated JSON strings.
|
||||
*/
|
||||
yajl_gen_escape_solidus = 0x10
|
||||
} yajl_gen_option;
|
||||
|
||||
/** allow the modification of generator options subsequent to handle
|
||||
* allocation (via yajl_alloc)
|
||||
* \returns zero in case of errors, non-zero otherwise
|
||||
*/
|
||||
YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...);
|
||||
|
||||
/** allocate a generator handle
|
||||
* \param allocFuncs an optional pointer to a structure which allows
|
||||
* the client to overide the memory allocation
|
||||
* used by yajl. May be NULL, in which case
|
||||
* malloc/free/realloc will be used.
|
||||
*
|
||||
* \returns an allocated handle on success, NULL on failure (bad params)
|
||||
*/
|
||||
YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs);
|
||||
|
||||
/** free a generator handle */
|
||||
YAJL_API void yajl_gen_free(yajl_gen handle);
|
||||
|
||||
YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number);
|
||||
/** generate a floating point number. number may not be infinity or
|
||||
* NaN, as these have no representation in JSON. In these cases the
|
||||
* generator will return 'yajl_gen_invalid_number' */
|
||||
YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number);
|
||||
YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand,
|
||||
const char * num,
|
||||
size_t len);
|
||||
YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand,
|
||||
const unsigned char * str,
|
||||
size_t len);
|
||||
YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean);
|
||||
YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand);
|
||||
|
||||
/** access the null terminated generator buffer. If incrementally
|
||||
* outputing JSON, one should call yajl_gen_clear to clear the
|
||||
* buffer. This allows stream generation. */
|
||||
YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand,
|
||||
const unsigned char ** buf,
|
||||
size_t * len);
|
||||
|
||||
/** clear yajl's output buffer, but maintain all internal generation
|
||||
* state. This function will not "reset" the generator state, and is
|
||||
* intended to enable incremental JSON outputing. */
|
||||
YAJL_API void yajl_gen_clear(yajl_gen hand);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
226
thirdparty/yajl/include/yajl/yajl_parse.h
vendored
226
thirdparty/yajl/include/yajl/yajl_parse.h
vendored
@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_parse.h
|
||||
* Interface to YAJL's JSON stream parsing facilities.
|
||||
*/
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#ifndef __YAJL_PARSE_H__
|
||||
#define __YAJL_PARSE_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/** error codes returned from this interface */
|
||||
typedef enum {
|
||||
/** no error was encountered */
|
||||
yajl_status_ok,
|
||||
/** a client callback returned zero, stopping the parse */
|
||||
yajl_status_client_canceled,
|
||||
/** An error occured during the parse. Call yajl_get_error for
|
||||
* more information about the encountered error */
|
||||
yajl_status_error
|
||||
} yajl_status;
|
||||
|
||||
/** attain a human readable, english, string for an error */
|
||||
YAJL_API const char * yajl_status_to_string(yajl_status code);
|
||||
|
||||
/** an opaque handle to a parser */
|
||||
typedef struct yajl_handle_t * yajl_handle;
|
||||
|
||||
/** yajl is an event driven parser. this means as json elements are
|
||||
* parsed, you are called back to do something with the data. The
|
||||
* functions in this table indicate the various events for which
|
||||
* you will be called back. Each callback accepts a "context"
|
||||
* pointer, this is a void * that is passed into the yajl_parse
|
||||
* function which the client code may use to pass around context.
|
||||
*
|
||||
* All callbacks return an integer. If non-zero, the parse will
|
||||
* continue. If zero, the parse will be canceled and
|
||||
* yajl_status_client_canceled will be returned from the parse.
|
||||
*
|
||||
* \attention {
|
||||
* A note about the handling of numbers:
|
||||
*
|
||||
* yajl will only convert numbers that can be represented in a
|
||||
* double or a 64 bit (long long) int. All other numbers will
|
||||
* be passed to the client in string form using the yajl_number
|
||||
* callback. Furthermore, if yajl_number is not NULL, it will
|
||||
* always be used to return numbers, that is yajl_integer and
|
||||
* yajl_double will be ignored. If yajl_number is NULL but one
|
||||
* of yajl_integer or yajl_double are defined, parsing of a
|
||||
* number larger than is representable in a double or 64 bit
|
||||
* integer will result in a parse error.
|
||||
* }
|
||||
*/
|
||||
typedef struct {
|
||||
int (* yajl_null)(void * ctx);
|
||||
int (* yajl_boolean)(void * ctx, int boolVal);
|
||||
int (* yajl_integer)(void * ctx, long long integerVal);
|
||||
int (* yajl_double)(void * ctx, double doubleVal);
|
||||
/** A callback which passes the string representation of the number
|
||||
* back to the client. Will be used for all numbers when present */
|
||||
int (* yajl_number)(void * ctx, const char * numberVal,
|
||||
size_t numberLen);
|
||||
|
||||
/** strings are returned as pointers into the JSON text when,
|
||||
* possible, as a result, they are _not_ null padded */
|
||||
int (* yajl_string)(void * ctx, const unsigned char * stringVal,
|
||||
size_t stringLen);
|
||||
|
||||
int (* yajl_start_map)(void * ctx);
|
||||
int (* yajl_map_key)(void * ctx, const unsigned char * key,
|
||||
size_t stringLen);
|
||||
int (* yajl_end_map)(void * ctx);
|
||||
|
||||
int (* yajl_start_array)(void * ctx);
|
||||
int (* yajl_end_array)(void * ctx);
|
||||
} yajl_callbacks;
|
||||
|
||||
/** allocate a parser handle
|
||||
* \param callbacks a yajl callbacks structure specifying the
|
||||
* functions to call when different JSON entities
|
||||
* are encountered in the input text. May be NULL,
|
||||
* which is only useful for validation.
|
||||
* \param afs memory allocation functions, may be NULL for to use
|
||||
* C runtime library routines (malloc and friends)
|
||||
* \param ctx a context pointer that will be passed to callbacks.
|
||||
*/
|
||||
YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks,
|
||||
yajl_alloc_funcs * afs,
|
||||
void * ctx);
|
||||
|
||||
|
||||
/** configuration parameters for the parser, these may be passed to
|
||||
* yajl_config() along with option specific argument(s). In general,
|
||||
* all configuration parameters default to *off*. */
|
||||
typedef enum {
|
||||
/** Ignore javascript style comments present in
|
||||
* JSON input. Non-standard, but rather fun
|
||||
* arguments: toggled off with integer zero, on otherwise.
|
||||
*
|
||||
* example:
|
||||
* yajl_config(h, yajl_allow_comments, 1); // turn comment support on
|
||||
*/
|
||||
yajl_allow_comments = 0x01,
|
||||
/**
|
||||
* When set the parser will verify that all strings in JSON input are
|
||||
* valid UTF8 and will emit a parse error if this is not so. When set,
|
||||
* this option makes parsing slightly more expensive (~7% depending
|
||||
* on processor and compiler in use)
|
||||
*
|
||||
* example:
|
||||
* yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking
|
||||
*/
|
||||
yajl_dont_validate_strings = 0x02,
|
||||
/**
|
||||
* By default, upon calls to yajl_complete_parse(), yajl will
|
||||
* ensure the entire input text was consumed and will raise an error
|
||||
* otherwise. Enabling this flag will cause yajl to disable this
|
||||
* check. This can be useful when parsing json out of a that contains more
|
||||
* than a single JSON document.
|
||||
*/
|
||||
yajl_allow_trailing_garbage = 0x04,
|
||||
/**
|
||||
* Allow multiple values to be parsed by a single handle. The
|
||||
* entire text must be valid JSON, and values can be seperated
|
||||
* by any kind of whitespace. This flag will change the
|
||||
* behavior of the parser, and cause it continue parsing after
|
||||
* a value is parsed, rather than transitioning into a
|
||||
* complete state. This option can be useful when parsing multiple
|
||||
* values from an input stream.
|
||||
*/
|
||||
yajl_allow_multiple_values = 0x08,
|
||||
/**
|
||||
* When yajl_complete_parse() is called the parser will
|
||||
* check that the top level value was completely consumed. I.E.,
|
||||
* if called whilst in the middle of parsing a value
|
||||
* yajl will enter an error state (premature EOF). Setting this
|
||||
* flag suppresses that check and the corresponding error.
|
||||
*/
|
||||
yajl_allow_partial_values = 0x10
|
||||
} yajl_option;
|
||||
|
||||
/** allow the modification of parser options subsequent to handle
|
||||
* allocation (via yajl_alloc)
|
||||
* \returns zero in case of errors, non-zero otherwise
|
||||
*/
|
||||
YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...);
|
||||
|
||||
/** free a parser handle */
|
||||
YAJL_API void yajl_free(yajl_handle handle);
|
||||
|
||||
/** Parse some json!
|
||||
* \param hand - a handle to the json parser allocated with yajl_alloc
|
||||
* \param jsonText - a pointer to the UTF8 json text to be parsed
|
||||
* \param jsonTextLength - the length, in bytes, of input text
|
||||
*/
|
||||
YAJL_API yajl_status yajl_parse(yajl_handle hand,
|
||||
const unsigned char * jsonText,
|
||||
size_t jsonTextLength);
|
||||
|
||||
/** Parse any remaining buffered json.
|
||||
* Since yajl is a stream-based parser, without an explicit end of
|
||||
* input, yajl sometimes can't decide if content at the end of the
|
||||
* stream is valid or not. For example, if "1" has been fed in,
|
||||
* yajl can't know whether another digit is next or some character
|
||||
* that would terminate the integer token.
|
||||
*
|
||||
* \param hand - a handle to the json parser allocated with yajl_alloc
|
||||
*/
|
||||
YAJL_API yajl_status yajl_complete_parse(yajl_handle hand);
|
||||
|
||||
/** get an error string describing the state of the
|
||||
* parse.
|
||||
*
|
||||
* If verbose is non-zero, the message will include the JSON
|
||||
* text where the error occured, along with an arrow pointing to
|
||||
* the specific char.
|
||||
*
|
||||
* \returns A dynamically allocated string will be returned which should
|
||||
* be freed with yajl_free_error
|
||||
*/
|
||||
YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose,
|
||||
const unsigned char * jsonText,
|
||||
size_t jsonTextLength);
|
||||
|
||||
/**
|
||||
* get the amount of data consumed from the last chunk passed to YAJL.
|
||||
*
|
||||
* In the case of a successful parse this can help you understand if
|
||||
* the entire buffer was consumed (which will allow you to handle
|
||||
* "junk at end of input").
|
||||
*
|
||||
* In the event an error is encountered during parsing, this function
|
||||
* affords the client a way to get the offset into the most recent
|
||||
* chunk where the error occured. 0 will be returned if no error
|
||||
* was encountered.
|
||||
*/
|
||||
YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand);
|
||||
|
||||
/** free an error returned from yajl_get_error */
|
||||
YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
177
thirdparty/yajl/include/yajl/yajl_tree.h
vendored
177
thirdparty/yajl/include/yajl/yajl_tree.h
vendored
@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 Florian Forster <ff at octo.it>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_tree.h
|
||||
*
|
||||
* Parses JSON data and returns the data in tree form.
|
||||
*
|
||||
* \author Florian Forster
|
||||
* \date August 2010
|
||||
*
|
||||
* This interface makes quick parsing and extraction of
|
||||
* smallish JSON docs trivial:
|
||||
*
|
||||
* \include example/parse_config.c
|
||||
*/
|
||||
|
||||
#ifndef YAJL_TREE_H
|
||||
#define YAJL_TREE_H 1
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
/** possible data types that a yajl_val_s can hold */
|
||||
typedef enum {
|
||||
yajl_t_string = 1,
|
||||
yajl_t_number = 2,
|
||||
yajl_t_object = 3,
|
||||
yajl_t_array = 4,
|
||||
yajl_t_true = 5,
|
||||
yajl_t_false = 6,
|
||||
yajl_t_null = 7,
|
||||
/** The any type isn't valid for yajl_val_s.type, but can be
|
||||
* used as an argument to routines like yajl_tree_get().
|
||||
*/
|
||||
yajl_t_any = 8
|
||||
} yajl_type;
|
||||
|
||||
#define YAJL_NUMBER_INT_VALID 0x01
|
||||
#define YAJL_NUMBER_DOUBLE_VALID 0x02
|
||||
|
||||
/** A pointer to a node in the parse tree */
|
||||
typedef struct yajl_val_s * yajl_val;
|
||||
|
||||
/**
|
||||
* A JSON value representation capable of holding one of the seven
|
||||
* types above. For "string", "number", "object", and "array"
|
||||
* additional data is available in the union. The "YAJL_IS_*"
|
||||
* and "YAJL_GET_*" macros below allow type checking and convenient
|
||||
* value extraction.
|
||||
*/
|
||||
struct yajl_val_s
|
||||
{
|
||||
/** Type of the value contained. Use the "YAJL_IS_*" macors to check for a
|
||||
* specific type. */
|
||||
yajl_type type;
|
||||
/** Type-specific data. You may use the "YAJL_GET_*" macros to access these
|
||||
* members. */
|
||||
union
|
||||
{
|
||||
char * string;
|
||||
struct {
|
||||
long long i; /*< integer value, if representable. */
|
||||
double d; /*< double value, if representable. */
|
||||
/** Signals whether the \em i and \em d members are
|
||||
* valid. See \c YAJL_NUMBER_INT_VALID and
|
||||
* \c YAJL_NUMBER_DOUBLE_VALID. */
|
||||
char *r; /*< unparsed number in string form. */
|
||||
unsigned int flags;
|
||||
} number;
|
||||
struct {
|
||||
const char **keys; /*< Array of keys */
|
||||
yajl_val *values; /*< Array of values. */
|
||||
size_t len; /*< Number of key-value-pairs. */
|
||||
} object;
|
||||
struct {
|
||||
yajl_val *values; /*< Array of elements. */
|
||||
size_t len; /*< Number of elements. */
|
||||
} array;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a string.
|
||||
*
|
||||
* Parses an null-terminated string containing JSON data and returns a pointer
|
||||
* to the top-level value (root of the parse tree).
|
||||
*
|
||||
* \param input Pointer to a null-terminated utf8 string containing
|
||||
* JSON data.
|
||||
* \param error_buffer Pointer to a buffer in which an error message will
|
||||
* be stored if \em yajl_tree_parse fails, or
|
||||
* \c NULL. The buffer will be initialized before
|
||||
* parsing, so its content will be destroyed even if
|
||||
* \em yajl_tree_parse succeeds.
|
||||
* \param error_buffer_size Size of the memory area pointed to by
|
||||
* \em error_buffer_size. If \em error_buffer_size is
|
||||
* \c NULL, this argument is ignored.
|
||||
*
|
||||
* \returns Pointer to the top-level value or \c NULL on error. The memory
|
||||
* pointed to must be freed using \em yajl_tree_free. In case of an error, a
|
||||
* null terminated message describing the error in more detail is stored in
|
||||
* \em error_buffer if it is not \c NULL.
|
||||
*/
|
||||
YAJL_API yajl_val yajl_tree_parse (const char *input,
|
||||
char *error_buffer, size_t error_buffer_size);
|
||||
|
||||
/**
|
||||
* Free a parse tree returned by "yajl_tree_parse".
|
||||
*
|
||||
* \param v Pointer to a JSON value returned by "yajl_tree_parse". Passing NULL
|
||||
* is valid and results in a no-op.
|
||||
*/
|
||||
YAJL_API void yajl_tree_free (yajl_val v);
|
||||
|
||||
/**
|
||||
* Access a nested value inside a tree.
|
||||
*
|
||||
* \param parent the node under which you'd like to extract values.
|
||||
* \param path A null terminated array of strings, each the name of an object key
|
||||
* \param type the yajl_type of the object you seek, or yajl_t_any if any will do.
|
||||
*
|
||||
* \returns a pointer to the found value, or NULL if we came up empty.
|
||||
*
|
||||
* Future Ideas: it'd be nice to move path to a string and implement support for
|
||||
* a teeny tiny micro language here, so you can extract array elements, do things
|
||||
* like .first and .last, even .length. Inspiration from JSONPath and css selectors?
|
||||
* No it wouldn't be fast, but that's not what this API is about.
|
||||
*/
|
||||
YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type type);
|
||||
|
||||
/* Various convenience macros to check the type of a `yajl_val` */
|
||||
#define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string))
|
||||
#define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number))
|
||||
#define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_INT_VALID))
|
||||
#define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_DOUBLE_VALID))
|
||||
#define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object))
|
||||
#define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array ))
|
||||
#define YAJL_IS_TRUE(v) (((v) != NULL) && ((v)->type == yajl_t_true ))
|
||||
#define YAJL_IS_FALSE(v) (((v) != NULL) && ((v)->type == yajl_t_false ))
|
||||
#define YAJL_IS_NULL(v) (((v) != NULL) && ((v)->type == yajl_t_null ))
|
||||
|
||||
/** Given a yajl_val_string return a ptr to the bare string it contains,
|
||||
* or NULL if the value is not a string. */
|
||||
#define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->u.string : NULL)
|
||||
|
||||
/** Get the string representation of a number. You should check type first,
|
||||
* perhaps using YAJL_IS_NUMBER */
|
||||
#define YAJL_GET_NUMBER(v) ((v)->u.number.r)
|
||||
|
||||
/** Get the double representation of a number. You should check type first,
|
||||
* perhaps using YAJL_IS_DOUBLE */
|
||||
#define YAJL_GET_DOUBLE(v) ((v)->u.number.d)
|
||||
|
||||
/** Get the 64bit (long long) integer representation of a number. You should
|
||||
* check type first, perhaps using YAJL_IS_INTEGER */
|
||||
#define YAJL_GET_INTEGER(v) ((v)->u.number.i)
|
||||
|
||||
/** Get a pointer to a yajl_val_object or NULL if the value is not an object. */
|
||||
#define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL)
|
||||
|
||||
/** Get a pointer to a yajl_val_array or NULL if the value is not an object. */
|
||||
#define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL)
|
||||
|
||||
#endif /* YAJL_TREE_H */
|
23
thirdparty/yajl/include/yajl/yajl_version.h
vendored
23
thirdparty/yajl/include/yajl/yajl_version.h
vendored
@ -1,23 +0,0 @@
|
||||
#ifndef YAJL_VERSION_H_
|
||||
#define YAJL_VERSION_H_
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#define YAJL_MAJOR 2
|
||||
#define YAJL_MINOR 0
|
||||
#define YAJL_MICRO 1
|
||||
|
||||
#define YAJL_VERSION ((YAJL_MAJOR * 10000) + (YAJL_MINOR * 100) + YAJL_MICRO)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int YAJL_API yajl_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* YAJL_VERSION_H_ */
|
||||
|
82
thirdparty/yajl/src/CMakeLists.txt
vendored
82
thirdparty/yajl/src/CMakeLists.txt
vendored
@ -1,82 +0,0 @@
|
||||
# Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
SET (SRCS yajl.c yajl_lex.c yajl_parser.c yajl_buf.c
|
||||
yajl_encode.c yajl_gen.c yajl_alloc.c
|
||||
yajl_tree.c yajl_version.c
|
||||
)
|
||||
SET (HDRS yajl_parser.h yajl_lex.h yajl_buf.h yajl_encode.h yajl_alloc.h)
|
||||
SET (PUB_HDRS api/yajl_parse.h api/yajl_gen.h api/yajl_common.h api/yajl_tree.h)
|
||||
|
||||
# useful when fixing lexer bugs.
|
||||
#ADD_DEFINITIONS(-DYAJL_LEXER_DEBUG)
|
||||
|
||||
# Ensure defined when building YAJL (as opposed to using it from
|
||||
# another project). Used to ensure correct function export when
|
||||
# building win32 DLL.
|
||||
ADD_DEFINITIONS(-DYAJL_BUILD)
|
||||
|
||||
# set up some paths
|
||||
SET (libDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/lib)
|
||||
SET (incDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include/yajl)
|
||||
|
||||
# set the output path for libraries
|
||||
SET(LIBRARY_OUTPUT_PATH ${libDir})
|
||||
|
||||
ADD_LIBRARY(yajl_s STATIC ${SRCS} ${HDRS} ${PUB_HDRS})
|
||||
|
||||
ADD_LIBRARY(yajl SHARED ${SRCS} ${HDRS} ${PUB_HDRS})
|
||||
|
||||
#### setup shared library version number
|
||||
SET_TARGET_PROPERTIES(yajl PROPERTIES
|
||||
DEFINE_SYMBOL YAJL_SHARED
|
||||
SOVERSION ${YAJL_MAJOR}
|
||||
VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO})
|
||||
|
||||
#### ensure a .dylib has correct absolute installation paths upon installation
|
||||
IF(APPLE)
|
||||
MESSAGE("INSTALL_NAME_DIR: ${CMAKE_INSTALL_PREFIX}/lib")
|
||||
SET_TARGET_PROPERTIES(yajl PROPERTIES
|
||||
INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
ENDIF(APPLE)
|
||||
|
||||
#### build up an sdk as a post build step
|
||||
|
||||
# create some directories
|
||||
FILE(MAKE_DIRECTORY ${libDir})
|
||||
FILE(MAKE_DIRECTORY ${incDir})
|
||||
|
||||
# generate build-time source
|
||||
CONFIGURE_FILE(api/yajl_version.h.cmake ${incDir}/yajl_version.h)
|
||||
|
||||
# copy public headers to output directory
|
||||
FOREACH (header ${PUB_HDRS})
|
||||
SET (header ${CMAKE_CURRENT_SOURCE_DIR}/${header})
|
||||
|
||||
EXEC_PROGRAM(${CMAKE_COMMAND} ARGS -E copy_if_different ${header} ${incDir})
|
||||
|
||||
ADD_CUSTOM_COMMAND(TARGET yajl_s POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${header} ${incDir})
|
||||
ENDFOREACH (header ${PUB_HDRS})
|
||||
|
||||
INCLUDE_DIRECTORIES(${incDir}/..)
|
||||
|
||||
IF(NOT WIN32)
|
||||
# at build time you may specify the cmake variable LIB_SUFFIX to handle
|
||||
# 64-bit systems which use 'lib64'
|
||||
INSTALL(TARGETS yajl LIBRARY DESTINATION lib${LIB_SUFFIX})
|
||||
INSTALL(TARGETS yajl_s ARCHIVE DESTINATION lib${LIB_SUFFIX})
|
||||
INSTALL(FILES ${PUB_HDRS} DESTINATION include/yajl)
|
||||
INSTALL(FILES ${incDir}/yajl_version.h DESTINATION include/yajl)
|
||||
ENDIF()
|
1258
thirdparty/yajl/src/YAJL.dxy
vendored
1258
thirdparty/yajl/src/YAJL.dxy
vendored
File diff suppressed because it is too large
Load Diff
75
thirdparty/yajl/src/api/yajl_common.h
vendored
75
thirdparty/yajl/src/api/yajl_common.h
vendored
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_COMMON_H__
|
||||
#define __YAJL_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define YAJL_MAX_DEPTH 128
|
||||
|
||||
/* msft dll export gunk. To build a DLL on windows, you
|
||||
* must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared
|
||||
* DLL, you must define YAJL_SHARED and WIN32 */
|
||||
#if defined(WIN32) && defined(YAJL_SHARED)
|
||||
# ifdef YAJL_BUILD
|
||||
# define YAJL_API __declspec(dllexport)
|
||||
# else
|
||||
# define YAJL_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303
|
||||
# define YAJL_API __attribute__ ((visibility("default")))
|
||||
# else
|
||||
# define YAJL_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** pointer to a malloc function, supporting client overriding memory
|
||||
* allocation routines */
|
||||
typedef void * (*yajl_malloc_func)(void *ctx, size_t sz);
|
||||
|
||||
/** pointer to a free function, supporting client overriding memory
|
||||
* allocation routines */
|
||||
typedef void (*yajl_free_func)(void *ctx, void * ptr);
|
||||
|
||||
/** pointer to a realloc function which can resize an allocation. */
|
||||
typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, size_t sz);
|
||||
|
||||
/** A structure which can be passed to yajl_*_alloc routines to allow the
|
||||
* client to specify memory allocation functions to be used. */
|
||||
typedef struct
|
||||
{
|
||||
/** pointer to a function that can allocate uninitialized memory */
|
||||
yajl_malloc_func malloc;
|
||||
/** pointer to a function that can resize memory allocations */
|
||||
yajl_realloc_func realloc;
|
||||
/** pointer to a function that can free memory allocated using
|
||||
* reallocFunction or mallocFunction */
|
||||
yajl_free_func free;
|
||||
/** a context pointer that will be passed to above allocation routines */
|
||||
void * ctx;
|
||||
} yajl_alloc_funcs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
157
thirdparty/yajl/src/api/yajl_gen.h
vendored
157
thirdparty/yajl/src/api/yajl_gen.h
vendored
@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_gen.h
|
||||
* Interface to YAJL's JSON generation facilities.
|
||||
*/
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#ifndef __YAJL_GEN_H__
|
||||
#define __YAJL_GEN_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/** generator status codes */
|
||||
typedef enum {
|
||||
/** no error */
|
||||
yajl_gen_status_ok = 0,
|
||||
/** at a point where a map key is generated, a function other than
|
||||
* yajl_gen_string was called */
|
||||
yajl_gen_keys_must_be_strings,
|
||||
/** YAJL's maximum generation depth was exceeded. see
|
||||
* YAJL_MAX_DEPTH */
|
||||
yajl_max_depth_exceeded,
|
||||
/** A generator function (yajl_gen_XXX) was called while in an error
|
||||
* state */
|
||||
yajl_gen_in_error_state,
|
||||
/** A complete JSON document has been generated */
|
||||
yajl_gen_generation_complete,
|
||||
/** yajl_gen_double was passed an invalid floating point value
|
||||
* (infinity or NaN). */
|
||||
yajl_gen_invalid_number,
|
||||
/** A print callback was passed in, so there is no internal
|
||||
* buffer to get from */
|
||||
yajl_gen_no_buf,
|
||||
/** returned from yajl_gen_string() when the yajl_gen_validate_utf8
|
||||
* option is enabled and an invalid was passed by client code.
|
||||
*/
|
||||
yajl_gen_invalid_string
|
||||
} yajl_gen_status;
|
||||
|
||||
/** an opaque handle to a generator */
|
||||
typedef struct yajl_gen_t * yajl_gen;
|
||||
|
||||
/** a callback used for "printing" the results. */
|
||||
typedef void (*yajl_print_t)(void * ctx,
|
||||
const char * str,
|
||||
size_t len);
|
||||
|
||||
/** configuration parameters for the parser, these may be passed to
|
||||
* yajl_gen_config() along with option specific argument(s). In general,
|
||||
* all configuration parameters default to *off*. */
|
||||
typedef enum {
|
||||
/** generate indented (beautiful) output */
|
||||
yajl_gen_beautify = 0x01,
|
||||
/**
|
||||
* Set an indent string which is used when yajl_gen_beautify
|
||||
* is enabled. Maybe something like \\t or some number of
|
||||
* spaces. The default is four spaces ' '.
|
||||
*/
|
||||
yajl_gen_indent_string = 0x02,
|
||||
/**
|
||||
* Set a function and context argument that should be used to
|
||||
* output generated json. the function should conform to the
|
||||
* yajl_print_t prototype while the context argument is a
|
||||
* void * of your choosing.
|
||||
*
|
||||
* example:
|
||||
* yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr);
|
||||
*/
|
||||
yajl_gen_print_callback = 0x04,
|
||||
/**
|
||||
* Normally the generator does not validate that strings you
|
||||
* pass to it via yajl_gen_string() are valid UTF8. Enabling
|
||||
* this option will cause it to do so.
|
||||
*/
|
||||
yajl_gen_validate_utf8 = 0x08,
|
||||
/**
|
||||
* the forward solidus (slash or '/' in human) is not required to be
|
||||
* escaped in json text. By default, YAJL will not escape it in the
|
||||
* iterest of saving bytes. Setting this flag will cause YAJL to
|
||||
* always escape '/' in generated JSON strings.
|
||||
*/
|
||||
yajl_gen_escape_solidus = 0x10
|
||||
} yajl_gen_option;
|
||||
|
||||
/** allow the modification of generator options subsequent to handle
|
||||
* allocation (via yajl_alloc)
|
||||
* \returns zero in case of errors, non-zero otherwise
|
||||
*/
|
||||
YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...);
|
||||
|
||||
/** allocate a generator handle
|
||||
* \param allocFuncs an optional pointer to a structure which allows
|
||||
* the client to overide the memory allocation
|
||||
* used by yajl. May be NULL, in which case
|
||||
* malloc/free/realloc will be used.
|
||||
*
|
||||
* \returns an allocated handle on success, NULL on failure (bad params)
|
||||
*/
|
||||
YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs);
|
||||
|
||||
/** free a generator handle */
|
||||
YAJL_API void yajl_gen_free(yajl_gen handle);
|
||||
|
||||
YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number);
|
||||
/** generate a floating point number. number may not be infinity or
|
||||
* NaN, as these have no representation in JSON. In these cases the
|
||||
* generator will return 'yajl_gen_invalid_number' */
|
||||
YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number);
|
||||
YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand,
|
||||
const char * num,
|
||||
size_t len);
|
||||
YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand,
|
||||
const unsigned char * str,
|
||||
size_t len);
|
||||
YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean);
|
||||
YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand);
|
||||
|
||||
/** access the null terminated generator buffer. If incrementally
|
||||
* outputing JSON, one should call yajl_gen_clear to clear the
|
||||
* buffer. This allows stream generation. */
|
||||
YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand,
|
||||
const unsigned char ** buf,
|
||||
size_t * len);
|
||||
|
||||
/** clear yajl's output buffer, but maintain all internal generation
|
||||
* state. This function will not "reset" the generator state, and is
|
||||
* intended to enable incremental JSON outputing. */
|
||||
YAJL_API void yajl_gen_clear(yajl_gen hand);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
226
thirdparty/yajl/src/api/yajl_parse.h
vendored
226
thirdparty/yajl/src/api/yajl_parse.h
vendored
@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_parse.h
|
||||
* Interface to YAJL's JSON stream parsing facilities.
|
||||
*/
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#ifndef __YAJL_PARSE_H__
|
||||
#define __YAJL_PARSE_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/** error codes returned from this interface */
|
||||
typedef enum {
|
||||
/** no error was encountered */
|
||||
yajl_status_ok,
|
||||
/** a client callback returned zero, stopping the parse */
|
||||
yajl_status_client_canceled,
|
||||
/** An error occured during the parse. Call yajl_get_error for
|
||||
* more information about the encountered error */
|
||||
yajl_status_error
|
||||
} yajl_status;
|
||||
|
||||
/** attain a human readable, english, string for an error */
|
||||
YAJL_API const char * yajl_status_to_string(yajl_status code);
|
||||
|
||||
/** an opaque handle to a parser */
|
||||
typedef struct yajl_handle_t * yajl_handle;
|
||||
|
||||
/** yajl is an event driven parser. this means as json elements are
|
||||
* parsed, you are called back to do something with the data. The
|
||||
* functions in this table indicate the various events for which
|
||||
* you will be called back. Each callback accepts a "context"
|
||||
* pointer, this is a void * that is passed into the yajl_parse
|
||||
* function which the client code may use to pass around context.
|
||||
*
|
||||
* All callbacks return an integer. If non-zero, the parse will
|
||||
* continue. If zero, the parse will be canceled and
|
||||
* yajl_status_client_canceled will be returned from the parse.
|
||||
*
|
||||
* \attention {
|
||||
* A note about the handling of numbers:
|
||||
*
|
||||
* yajl will only convert numbers that can be represented in a
|
||||
* double or a 64 bit (long long) int. All other numbers will
|
||||
* be passed to the client in string form using the yajl_number
|
||||
* callback. Furthermore, if yajl_number is not NULL, it will
|
||||
* always be used to return numbers, that is yajl_integer and
|
||||
* yajl_double will be ignored. If yajl_number is NULL but one
|
||||
* of yajl_integer or yajl_double are defined, parsing of a
|
||||
* number larger than is representable in a double or 64 bit
|
||||
* integer will result in a parse error.
|
||||
* }
|
||||
*/
|
||||
typedef struct {
|
||||
int (* yajl_null)(void * ctx);
|
||||
int (* yajl_boolean)(void * ctx, int boolVal);
|
||||
int (* yajl_integer)(void * ctx, long long integerVal);
|
||||
int (* yajl_double)(void * ctx, double doubleVal);
|
||||
/** A callback which passes the string representation of the number
|
||||
* back to the client. Will be used for all numbers when present */
|
||||
int (* yajl_number)(void * ctx, const char * numberVal,
|
||||
size_t numberLen);
|
||||
|
||||
/** strings are returned as pointers into the JSON text when,
|
||||
* possible, as a result, they are _not_ null padded */
|
||||
int (* yajl_string)(void * ctx, const unsigned char * stringVal,
|
||||
size_t stringLen);
|
||||
|
||||
int (* yajl_start_map)(void * ctx);
|
||||
int (* yajl_map_key)(void * ctx, const unsigned char * key,
|
||||
size_t stringLen);
|
||||
int (* yajl_end_map)(void * ctx);
|
||||
|
||||
int (* yajl_start_array)(void * ctx);
|
||||
int (* yajl_end_array)(void * ctx);
|
||||
} yajl_callbacks;
|
||||
|
||||
/** allocate a parser handle
|
||||
* \param callbacks a yajl callbacks structure specifying the
|
||||
* functions to call when different JSON entities
|
||||
* are encountered in the input text. May be NULL,
|
||||
* which is only useful for validation.
|
||||
* \param afs memory allocation functions, may be NULL for to use
|
||||
* C runtime library routines (malloc and friends)
|
||||
* \param ctx a context pointer that will be passed to callbacks.
|
||||
*/
|
||||
YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks,
|
||||
yajl_alloc_funcs * afs,
|
||||
void * ctx);
|
||||
|
||||
|
||||
/** configuration parameters for the parser, these may be passed to
|
||||
* yajl_config() along with option specific argument(s). In general,
|
||||
* all configuration parameters default to *off*. */
|
||||
typedef enum {
|
||||
/** Ignore javascript style comments present in
|
||||
* JSON input. Non-standard, but rather fun
|
||||
* arguments: toggled off with integer zero, on otherwise.
|
||||
*
|
||||
* example:
|
||||
* yajl_config(h, yajl_allow_comments, 1); // turn comment support on
|
||||
*/
|
||||
yajl_allow_comments = 0x01,
|
||||
/**
|
||||
* When set the parser will verify that all strings in JSON input are
|
||||
* valid UTF8 and will emit a parse error if this is not so. When set,
|
||||
* this option makes parsing slightly more expensive (~7% depending
|
||||
* on processor and compiler in use)
|
||||
*
|
||||
* example:
|
||||
* yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking
|
||||
*/
|
||||
yajl_dont_validate_strings = 0x02,
|
||||
/**
|
||||
* By default, upon calls to yajl_complete_parse(), yajl will
|
||||
* ensure the entire input text was consumed and will raise an error
|
||||
* otherwise. Enabling this flag will cause yajl to disable this
|
||||
* check. This can be useful when parsing json out of a that contains more
|
||||
* than a single JSON document.
|
||||
*/
|
||||
yajl_allow_trailing_garbage = 0x04,
|
||||
/**
|
||||
* Allow multiple values to be parsed by a single handle. The
|
||||
* entire text must be valid JSON, and values can be seperated
|
||||
* by any kind of whitespace. This flag will change the
|
||||
* behavior of the parser, and cause it continue parsing after
|
||||
* a value is parsed, rather than transitioning into a
|
||||
* complete state. This option can be useful when parsing multiple
|
||||
* values from an input stream.
|
||||
*/
|
||||
yajl_allow_multiple_values = 0x08,
|
||||
/**
|
||||
* When yajl_complete_parse() is called the parser will
|
||||
* check that the top level value was completely consumed. I.E.,
|
||||
* if called whilst in the middle of parsing a value
|
||||
* yajl will enter an error state (premature EOF). Setting this
|
||||
* flag suppresses that check and the corresponding error.
|
||||
*/
|
||||
yajl_allow_partial_values = 0x10
|
||||
} yajl_option;
|
||||
|
||||
/** allow the modification of parser options subsequent to handle
|
||||
* allocation (via yajl_alloc)
|
||||
* \returns zero in case of errors, non-zero otherwise
|
||||
*/
|
||||
YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...);
|
||||
|
||||
/** free a parser handle */
|
||||
YAJL_API void yajl_free(yajl_handle handle);
|
||||
|
||||
/** Parse some json!
|
||||
* \param hand - a handle to the json parser allocated with yajl_alloc
|
||||
* \param jsonText - a pointer to the UTF8 json text to be parsed
|
||||
* \param jsonTextLength - the length, in bytes, of input text
|
||||
*/
|
||||
YAJL_API yajl_status yajl_parse(yajl_handle hand,
|
||||
const unsigned char * jsonText,
|
||||
size_t jsonTextLength);
|
||||
|
||||
/** Parse any remaining buffered json.
|
||||
* Since yajl is a stream-based parser, without an explicit end of
|
||||
* input, yajl sometimes can't decide if content at the end of the
|
||||
* stream is valid or not. For example, if "1" has been fed in,
|
||||
* yajl can't know whether another digit is next or some character
|
||||
* that would terminate the integer token.
|
||||
*
|
||||
* \param hand - a handle to the json parser allocated with yajl_alloc
|
||||
*/
|
||||
YAJL_API yajl_status yajl_complete_parse(yajl_handle hand);
|
||||
|
||||
/** get an error string describing the state of the
|
||||
* parse.
|
||||
*
|
||||
* If verbose is non-zero, the message will include the JSON
|
||||
* text where the error occured, along with an arrow pointing to
|
||||
* the specific char.
|
||||
*
|
||||
* \returns A dynamically allocated string will be returned which should
|
||||
* be freed with yajl_free_error
|
||||
*/
|
||||
YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose,
|
||||
const unsigned char * jsonText,
|
||||
size_t jsonTextLength);
|
||||
|
||||
/**
|
||||
* get the amount of data consumed from the last chunk passed to YAJL.
|
||||
*
|
||||
* In the case of a successful parse this can help you understand if
|
||||
* the entire buffer was consumed (which will allow you to handle
|
||||
* "junk at end of input").
|
||||
*
|
||||
* In the event an error is encountered during parsing, this function
|
||||
* affords the client a way to get the offset into the most recent
|
||||
* chunk where the error occured. 0 will be returned if no error
|
||||
* was encountered.
|
||||
*/
|
||||
YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand);
|
||||
|
||||
/** free an error returned from yajl_get_error */
|
||||
YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
177
thirdparty/yajl/src/api/yajl_tree.h
vendored
177
thirdparty/yajl/src/api/yajl_tree.h
vendored
@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 Florian Forster <ff at octo.it>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_tree.h
|
||||
*
|
||||
* Parses JSON data and returns the data in tree form.
|
||||
*
|
||||
* \author Florian Forster
|
||||
* \date August 2010
|
||||
*
|
||||
* This interface makes quick parsing and extraction of
|
||||
* smallish JSON docs trivial:
|
||||
*
|
||||
* \include example/parse_config.c
|
||||
*/
|
||||
|
||||
#ifndef YAJL_TREE_H
|
||||
#define YAJL_TREE_H 1
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
/** possible data types that a yajl_val_s can hold */
|
||||
typedef enum {
|
||||
yajl_t_string = 1,
|
||||
yajl_t_number = 2,
|
||||
yajl_t_object = 3,
|
||||
yajl_t_array = 4,
|
||||
yajl_t_true = 5,
|
||||
yajl_t_false = 6,
|
||||
yajl_t_null = 7,
|
||||
/** The any type isn't valid for yajl_val_s.type, but can be
|
||||
* used as an argument to routines like yajl_tree_get().
|
||||
*/
|
||||
yajl_t_any = 8
|
||||
} yajl_type;
|
||||
|
||||
#define YAJL_NUMBER_INT_VALID 0x01
|
||||
#define YAJL_NUMBER_DOUBLE_VALID 0x02
|
||||
|
||||
/** A pointer to a node in the parse tree */
|
||||
typedef struct yajl_val_s * yajl_val;
|
||||
|
||||
/**
|
||||
* A JSON value representation capable of holding one of the seven
|
||||
* types above. For "string", "number", "object", and "array"
|
||||
* additional data is available in the union. The "YAJL_IS_*"
|
||||
* and "YAJL_GET_*" macros below allow type checking and convenient
|
||||
* value extraction.
|
||||
*/
|
||||
struct yajl_val_s
|
||||
{
|
||||
/** Type of the value contained. Use the "YAJL_IS_*" macors to check for a
|
||||
* specific type. */
|
||||
yajl_type type;
|
||||
/** Type-specific data. You may use the "YAJL_GET_*" macros to access these
|
||||
* members. */
|
||||
union
|
||||
{
|
||||
char * string;
|
||||
struct {
|
||||
long long i; /*< integer value, if representable. */
|
||||
double d; /*< double value, if representable. */
|
||||
/** Signals whether the \em i and \em d members are
|
||||
* valid. See \c YAJL_NUMBER_INT_VALID and
|
||||
* \c YAJL_NUMBER_DOUBLE_VALID. */
|
||||
char *r; /*< unparsed number in string form. */
|
||||
unsigned int flags;
|
||||
} number;
|
||||
struct {
|
||||
const char **keys; /*< Array of keys */
|
||||
yajl_val *values; /*< Array of values. */
|
||||
size_t len; /*< Number of key-value-pairs. */
|
||||
} object;
|
||||
struct {
|
||||
yajl_val *values; /*< Array of elements. */
|
||||
size_t len; /*< Number of elements. */
|
||||
} array;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a string.
|
||||
*
|
||||
* Parses an null-terminated string containing JSON data and returns a pointer
|
||||
* to the top-level value (root of the parse tree).
|
||||
*
|
||||
* \param input Pointer to a null-terminated utf8 string containing
|
||||
* JSON data.
|
||||
* \param error_buffer Pointer to a buffer in which an error message will
|
||||
* be stored if \em yajl_tree_parse fails, or
|
||||
* \c NULL. The buffer will be initialized before
|
||||
* parsing, so its content will be destroyed even if
|
||||
* \em yajl_tree_parse succeeds.
|
||||
* \param error_buffer_size Size of the memory area pointed to by
|
||||
* \em error_buffer_size. If \em error_buffer_size is
|
||||
* \c NULL, this argument is ignored.
|
||||
*
|
||||
* \returns Pointer to the top-level value or \c NULL on error. The memory
|
||||
* pointed to must be freed using \em yajl_tree_free. In case of an error, a
|
||||
* null terminated message describing the error in more detail is stored in
|
||||
* \em error_buffer if it is not \c NULL.
|
||||
*/
|
||||
YAJL_API yajl_val yajl_tree_parse (const char *input,
|
||||
char *error_buffer, size_t error_buffer_size);
|
||||
|
||||
/**
|
||||
* Free a parse tree returned by "yajl_tree_parse".
|
||||
*
|
||||
* \param v Pointer to a JSON value returned by "yajl_tree_parse". Passing NULL
|
||||
* is valid and results in a no-op.
|
||||
*/
|
||||
YAJL_API void yajl_tree_free (yajl_val v);
|
||||
|
||||
/**
|
||||
* Access a nested value inside a tree.
|
||||
*
|
||||
* \param parent the node under which you'd like to extract values.
|
||||
* \param path A null terminated array of strings, each the name of an object key
|
||||
* \param type the yajl_type of the object you seek, or yajl_t_any if any will do.
|
||||
*
|
||||
* \returns a pointer to the found value, or NULL if we came up empty.
|
||||
*
|
||||
* Future Ideas: it'd be nice to move path to a string and implement support for
|
||||
* a teeny tiny micro language here, so you can extract array elements, do things
|
||||
* like .first and .last, even .length. Inspiration from JSONPath and css selectors?
|
||||
* No it wouldn't be fast, but that's not what this API is about.
|
||||
*/
|
||||
YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type type);
|
||||
|
||||
/* Various convenience macros to check the type of a `yajl_val` */
|
||||
#define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string))
|
||||
#define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number))
|
||||
#define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_INT_VALID))
|
||||
#define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_DOUBLE_VALID))
|
||||
#define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object))
|
||||
#define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array ))
|
||||
#define YAJL_IS_TRUE(v) (((v) != NULL) && ((v)->type == yajl_t_true ))
|
||||
#define YAJL_IS_FALSE(v) (((v) != NULL) && ((v)->type == yajl_t_false ))
|
||||
#define YAJL_IS_NULL(v) (((v) != NULL) && ((v)->type == yajl_t_null ))
|
||||
|
||||
/** Given a yajl_val_string return a ptr to the bare string it contains,
|
||||
* or NULL if the value is not a string. */
|
||||
#define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->u.string : NULL)
|
||||
|
||||
/** Get the string representation of a number. You should check type first,
|
||||
* perhaps using YAJL_IS_NUMBER */
|
||||
#define YAJL_GET_NUMBER(v) ((v)->u.number.r)
|
||||
|
||||
/** Get the double representation of a number. You should check type first,
|
||||
* perhaps using YAJL_IS_DOUBLE */
|
||||
#define YAJL_GET_DOUBLE(v) ((v)->u.number.d)
|
||||
|
||||
/** Get the 64bit (long long) integer representation of a number. You should
|
||||
* check type first, perhaps using YAJL_IS_INTEGER */
|
||||
#define YAJL_GET_INTEGER(v) ((v)->u.number.i)
|
||||
|
||||
/** Get a pointer to a yajl_val_object or NULL if the value is not an object. */
|
||||
#define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL)
|
||||
|
||||
/** Get a pointer to a yajl_val_array or NULL if the value is not an object. */
|
||||
#define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL)
|
||||
|
||||
#endif /* YAJL_TREE_H */
|
23
thirdparty/yajl/src/api/yajl_version.h.cmake
vendored
23
thirdparty/yajl/src/api/yajl_version.h.cmake
vendored
@ -1,23 +0,0 @@
|
||||
#ifndef YAJL_VERSION_H_
|
||||
#define YAJL_VERSION_H_
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#define YAJL_MAJOR ${YAJL_MAJOR}
|
||||
#define YAJL_MINOR ${YAJL_MINOR}
|
||||
#define YAJL_MICRO ${YAJL_MICRO}
|
||||
|
||||
#define YAJL_VERSION ((YAJL_MAJOR * 10000) + (YAJL_MINOR * 100) + YAJL_MICRO)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int YAJL_API yajl_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* YAJL_VERSION_H_ */
|
||||
|
33
thirdparty/yajl/src/yajl
vendored
33
thirdparty/yajl/src/yajl
vendored
@ -1,33 +0,0 @@
|
||||
/**
|
||||
\example reformatter/json_reformat.c
|
||||
\example example/parse_config.c
|
||||
*/
|
||||
|
||||
/*!
|
||||
\mainpage Yet Another JSON Library (YAJL)
|
||||
\author Lloyd Hilaiel
|
||||
\date 2007-2011
|
||||
|
||||
Yet Another JSON Library (YAJL) is a small event-driven (SAX-style)
|
||||
JSON parser written in ANSI C, and a small validating JSON
|
||||
generator. YAJL is released under the permissive ISC license.
|
||||
|
||||
\section features Features
|
||||
|
||||
-# Stream (incremental) parsing and generation of JSON
|
||||
-# ANSI C
|
||||
-# Human readable error messages with context
|
||||
-# tiny
|
||||
-# event driven
|
||||
-# support for generating "beautified" JSON
|
||||
-# includes
|
||||
It also includes a small simplified tree interface for
|
||||
simplified parsing and extraction of data from smallish JSON documents.
|
||||
|
||||
\section usage Usage
|
||||
|
||||
See <a href="reformatter_2json_reformat_8c-example.html">json_reformat.c</a> for a complete example of stream based parsing
|
||||
and generation of JSON. See <a href="example_2parse_config_8c-example.html">parse_config.c</a> for an example of the
|
||||
simplified tree interface.
|
||||
|
||||
*/
|
175
thirdparty/yajl/src/yajl.c
vendored
175
thirdparty/yajl/src/yajl.c
vendored
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "api/yajl_parse.h"
|
||||
#include "yajl_lex.h"
|
||||
#include "yajl_parser.h"
|
||||
#include "yajl_alloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
const char *
|
||||
yajl_status_to_string(yajl_status stat)
|
||||
{
|
||||
const char * statStr = "unknown";
|
||||
switch (stat) {
|
||||
case yajl_status_ok:
|
||||
statStr = "ok, no error";
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
statStr = "client canceled parse";
|
||||
break;
|
||||
case yajl_status_error:
|
||||
statStr = "parse error";
|
||||
break;
|
||||
}
|
||||
return statStr;
|
||||
}
|
||||
|
||||
yajl_handle
|
||||
yajl_alloc(const yajl_callbacks * callbacks,
|
||||
yajl_alloc_funcs * afs,
|
||||
void * ctx)
|
||||
{
|
||||
yajl_handle hand = NULL;
|
||||
yajl_alloc_funcs afsBuffer;
|
||||
|
||||
/* first order of business is to set up memory allocation routines */
|
||||
if (afs != NULL) {
|
||||
if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
yajl_set_default_alloc_funcs(&afsBuffer);
|
||||
afs = &afsBuffer;
|
||||
}
|
||||
|
||||
hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
|
||||
|
||||
/* copy in pointers to allocation routines */
|
||||
memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
|
||||
|
||||
hand->callbacks = callbacks;
|
||||
hand->ctx = ctx;
|
||||
hand->lexer = NULL;
|
||||
hand->bytesConsumed = 0;
|
||||
hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
|
||||
hand->flags = 0;
|
||||
yajl_bs_init(hand->stateStack, &(hand->alloc));
|
||||
yajl_bs_push(hand->stateStack, yajl_state_start);
|
||||
|
||||
return hand;
|
||||
}
|
||||
|
||||
int
|
||||
yajl_config(yajl_handle h, yajl_option opt, ...)
|
||||
{
|
||||
int rv = 1;
|
||||
va_list ap;
|
||||
va_start(ap, opt);
|
||||
|
||||
switch(opt) {
|
||||
case yajl_allow_comments:
|
||||
case yajl_dont_validate_strings:
|
||||
case yajl_allow_trailing_garbage:
|
||||
case yajl_allow_multiple_values:
|
||||
case yajl_allow_partial_values:
|
||||
if (va_arg(ap, int)) h->flags |= opt;
|
||||
else h->flags &= ~opt;
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_free(yajl_handle handle)
|
||||
{
|
||||
yajl_bs_free(handle->stateStack);
|
||||
yajl_buf_free(handle->decodeBuf);
|
||||
if (handle->lexer) {
|
||||
yajl_lex_free(handle->lexer);
|
||||
handle->lexer = NULL;
|
||||
}
|
||||
YA_FREE(&(handle->alloc), handle);
|
||||
}
|
||||
|
||||
yajl_status
|
||||
yajl_parse(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen)
|
||||
{
|
||||
yajl_status status;
|
||||
|
||||
/* lazy allocation of the lexer */
|
||||
if (hand->lexer == NULL) {
|
||||
hand->lexer = yajl_lex_alloc(&(hand->alloc),
|
||||
hand->flags & yajl_allow_comments,
|
||||
!(hand->flags & yajl_dont_validate_strings));
|
||||
}
|
||||
|
||||
status = yajl_do_parse(hand, jsonText, jsonTextLen);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
yajl_status
|
||||
yajl_complete_parse(yajl_handle hand)
|
||||
{
|
||||
/* The lexer is lazy allocated in the first call to parse. if parse is
|
||||
* never called, then no data was provided to parse at all. This is a
|
||||
* "premature EOF" error unless yajl_allow_partial_values is specified.
|
||||
* allocating the lexer now is the simplest possible way to handle this
|
||||
* case while preserving all the other semantics of the parser
|
||||
* (multiple values, partial values, etc). */
|
||||
if (hand->lexer == NULL) {
|
||||
hand->lexer = yajl_lex_alloc(&(hand->alloc),
|
||||
hand->flags & yajl_allow_comments,
|
||||
!(hand->flags & yajl_dont_validate_strings));
|
||||
}
|
||||
|
||||
return yajl_do_finish(hand);
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
yajl_get_error(yajl_handle hand, int verbose,
|
||||
const unsigned char * jsonText, size_t jsonTextLen)
|
||||
{
|
||||
return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose);
|
||||
}
|
||||
|
||||
size_t
|
||||
yajl_get_bytes_consumed(yajl_handle hand)
|
||||
{
|
||||
if (!hand) return 0;
|
||||
else return hand->bytesConsumed;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
yajl_free_error(yajl_handle hand, unsigned char * str)
|
||||
{
|
||||
/* use memory allocation functions if set */
|
||||
YA_FREE(&(hand->alloc), str);
|
||||
}
|
||||
|
||||
/* XXX: add utility routines to parse from file */
|
49
thirdparty/yajl/src/yajl_alloc.c
vendored
49
thirdparty/yajl/src/yajl_alloc.c
vendored
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_alloc.h
|
||||
* default memory allocation routines for yajl which use malloc/realloc and
|
||||
* free
|
||||
*/
|
||||
|
||||
#include "yajl_alloc.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static void * yajl_internal_malloc(void *ctx, size_t sz)
|
||||
{
|
||||
return malloc(sz);
|
||||
}
|
||||
|
||||
static void * yajl_internal_realloc(void *ctx, void * previous,
|
||||
size_t sz)
|
||||
{
|
||||
return realloc(previous, sz);
|
||||
}
|
||||
|
||||
static void yajl_internal_free(void *ctx, void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf)
|
||||
{
|
||||
yaf->malloc = yajl_internal_malloc;
|
||||
yaf->free = yajl_internal_free;
|
||||
yaf->realloc = yajl_internal_realloc;
|
||||
yaf->ctx = NULL;
|
||||
}
|
||||
|
34
thirdparty/yajl/src/yajl_alloc.h
vendored
34
thirdparty/yajl/src/yajl_alloc.h
vendored
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_alloc.h
|
||||
* default memory allocation routines for yajl which use malloc/realloc and
|
||||
* free
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_ALLOC_H__
|
||||
#define __YAJL_ALLOC_H__
|
||||
|
||||
#include "api/yajl_common.h"
|
||||
|
||||
#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz))
|
||||
#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr))
|
||||
#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz))
|
||||
|
||||
void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf);
|
||||
|
||||
#endif
|
103
thirdparty/yajl/src/yajl_buf.c
vendored
103
thirdparty/yajl/src/yajl_buf.c
vendored
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_buf.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define YAJL_BUF_INIT_SIZE 2048
|
||||
|
||||
struct yajl_buf_t {
|
||||
size_t len;
|
||||
size_t used;
|
||||
unsigned char * data;
|
||||
yajl_alloc_funcs * alloc;
|
||||
};
|
||||
|
||||
static
|
||||
void yajl_buf_ensure_available(yajl_buf buf, size_t want)
|
||||
{
|
||||
size_t need;
|
||||
|
||||
assert(buf != NULL);
|
||||
|
||||
/* first call */
|
||||
if (buf->data == NULL) {
|
||||
buf->len = YAJL_BUF_INIT_SIZE;
|
||||
buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len);
|
||||
buf->data[0] = 0;
|
||||
}
|
||||
|
||||
need = buf->len;
|
||||
|
||||
while (want >= (need - buf->used)) need <<= 1;
|
||||
|
||||
if (need != buf->len) {
|
||||
buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need);
|
||||
buf->len = need;
|
||||
}
|
||||
}
|
||||
|
||||
yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc)
|
||||
{
|
||||
yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t));
|
||||
memset((void *) b, 0, sizeof(struct yajl_buf_t));
|
||||
b->alloc = alloc;
|
||||
return b;
|
||||
}
|
||||
|
||||
void yajl_buf_free(yajl_buf buf)
|
||||
{
|
||||
assert(buf != NULL);
|
||||
if (buf->data) YA_FREE(buf->alloc, buf->data);
|
||||
YA_FREE(buf->alloc, buf);
|
||||
}
|
||||
|
||||
void yajl_buf_append(yajl_buf buf, const void * data, size_t len)
|
||||
{
|
||||
yajl_buf_ensure_available(buf, len);
|
||||
if (len > 0) {
|
||||
assert(data != NULL);
|
||||
memcpy(buf->data + buf->used, data, len);
|
||||
buf->used += len;
|
||||
buf->data[buf->used] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void yajl_buf_clear(yajl_buf buf)
|
||||
{
|
||||
buf->used = 0;
|
||||
if (buf->data) buf->data[buf->used] = 0;
|
||||
}
|
||||
|
||||
const unsigned char * yajl_buf_data(yajl_buf buf)
|
||||
{
|
||||
return buf->data;
|
||||
}
|
||||
|
||||
size_t yajl_buf_len(yajl_buf buf)
|
||||
{
|
||||
return buf->used;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_buf_truncate(yajl_buf buf, size_t len)
|
||||
{
|
||||
assert(len <= buf->used);
|
||||
buf->used = len;
|
||||
}
|
57
thirdparty/yajl/src/yajl_buf.h
vendored
57
thirdparty/yajl/src/yajl_buf.h
vendored
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_BUF_H__
|
||||
#define __YAJL_BUF_H__
|
||||
|
||||
#include "api/yajl_common.h"
|
||||
#include "yajl_alloc.h"
|
||||
|
||||
/*
|
||||
* Implementation/performance notes. If this were moved to a header
|
||||
* only implementation using #define's where possible we might be
|
||||
* able to sqeeze a little performance out of the guy by killing function
|
||||
* call overhead. YMMV.
|
||||
*/
|
||||
|
||||
/**
|
||||
* yajl_buf is a buffer with exponential growth. the buffer ensures that
|
||||
* you are always null padded.
|
||||
*/
|
||||
typedef struct yajl_buf_t * yajl_buf;
|
||||
|
||||
/* allocate a new buffer */
|
||||
yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc);
|
||||
|
||||
/* free the buffer */
|
||||
void yajl_buf_free(yajl_buf buf);
|
||||
|
||||
/* append a number of bytes to the buffer */
|
||||
void yajl_buf_append(yajl_buf buf, const void * data, size_t len);
|
||||
|
||||
/* empty the buffer */
|
||||
void yajl_buf_clear(yajl_buf buf);
|
||||
|
||||
/* get a pointer to the beginning of the buffer */
|
||||
const unsigned char * yajl_buf_data(yajl_buf buf);
|
||||
|
||||
/* get the length of the buffer */
|
||||
size_t yajl_buf_len(yajl_buf buf);
|
||||
|
||||
/* truncate the buffer */
|
||||
void yajl_buf_truncate(yajl_buf buf, size_t len);
|
||||
|
||||
#endif
|
69
thirdparty/yajl/src/yajl_bytestack.h
vendored
69
thirdparty/yajl/src/yajl_bytestack.h
vendored
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A header only implementation of a simple stack of bytes, used in YAJL
|
||||
* to maintain parse state.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_BYTESTACK_H__
|
||||
#define __YAJL_BYTESTACK_H__
|
||||
|
||||
#include "api/yajl_common.h"
|
||||
|
||||
#define YAJL_BS_INC 128
|
||||
|
||||
typedef struct yajl_bytestack_t
|
||||
{
|
||||
unsigned char * stack;
|
||||
size_t size;
|
||||
size_t used;
|
||||
yajl_alloc_funcs * yaf;
|
||||
} yajl_bytestack;
|
||||
|
||||
/* initialize a bytestack */
|
||||
#define yajl_bs_init(obs, _yaf) { \
|
||||
(obs).stack = NULL; \
|
||||
(obs).size = 0; \
|
||||
(obs).used = 0; \
|
||||
(obs).yaf = (_yaf); \
|
||||
} \
|
||||
|
||||
|
||||
/* initialize a bytestack */
|
||||
#define yajl_bs_free(obs) \
|
||||
if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack);
|
||||
|
||||
#define yajl_bs_current(obs) \
|
||||
(assert((obs).used > 0), (obs).stack[(obs).used - 1])
|
||||
|
||||
#define yajl_bs_push(obs, byte) { \
|
||||
if (((obs).size - (obs).used) == 0) { \
|
||||
(obs).size += YAJL_BS_INC; \
|
||||
(obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\
|
||||
(void *) (obs).stack, (obs).size);\
|
||||
} \
|
||||
(obs).stack[((obs).used)++] = (byte); \
|
||||
}
|
||||
|
||||
/* removes the top item of the stack, returns nothing */
|
||||
#define yajl_bs_pop(obs) { ((obs).used)--; }
|
||||
|
||||
#define yajl_bs_set(obs, byte) \
|
||||
(obs).stack[((obs).used) - 1] = (byte);
|
||||
|
||||
|
||||
#endif
|
220
thirdparty/yajl/src/yajl_encode.c
vendored
220
thirdparty/yajl/src/yajl_encode.c
vendored
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_encode.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void CharToHex(unsigned char c, char * hexBuf)
|
||||
{
|
||||
const char * hexchar = "0123456789ABCDEF";
|
||||
hexBuf[0] = hexchar[c >> 4];
|
||||
hexBuf[1] = hexchar[c & 0x0F];
|
||||
}
|
||||
|
||||
void
|
||||
yajl_string_encode(const yajl_print_t print,
|
||||
void * ctx,
|
||||
const unsigned char * str,
|
||||
size_t len,
|
||||
int escape_solidus)
|
||||
{
|
||||
size_t beg = 0;
|
||||
size_t end = 0;
|
||||
char hexBuf[7];
|
||||
hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
|
||||
hexBuf[6] = 0;
|
||||
|
||||
while (end < len) {
|
||||
const char * escaped = NULL;
|
||||
switch (str[end]) {
|
||||
case '\r': escaped = "\\r"; break;
|
||||
case '\n': escaped = "\\n"; break;
|
||||
case '\\': escaped = "\\\\"; break;
|
||||
/* it is not required to escape a solidus in JSON:
|
||||
* read sec. 2.5: http://www.ietf.org/rfc/rfc4627.txt
|
||||
* specifically, this production from the grammar:
|
||||
* unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
*/
|
||||
case '/': if (escape_solidus) escaped = "\\/"; break;
|
||||
case '"': escaped = "\\\""; break;
|
||||
case '\f': escaped = "\\f"; break;
|
||||
case '\b': escaped = "\\b"; break;
|
||||
case '\t': escaped = "\\t"; break;
|
||||
default:
|
||||
if ((unsigned char) str[end] < 32) {
|
||||
CharToHex(str[end], hexBuf + 4);
|
||||
escaped = hexBuf;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (escaped != NULL) {
|
||||
print(ctx, (const char *) (str + beg), end - beg);
|
||||
print(ctx, escaped, (unsigned int)strlen(escaped));
|
||||
beg = ++end;
|
||||
} else {
|
||||
++end;
|
||||
}
|
||||
}
|
||||
print(ctx, (const char *) (str + beg), end - beg);
|
||||
}
|
||||
|
||||
static void hexToDigit(unsigned int * val, const unsigned char * hex)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i=0;i<4;i++) {
|
||||
unsigned char c = hex[i];
|
||||
if (c >= 'A') c = (c & ~0x20) - 7;
|
||||
c -= '0';
|
||||
assert(!(c & 0xF0));
|
||||
*val = (*val << 4) | c;
|
||||
}
|
||||
}
|
||||
|
||||
static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf)
|
||||
{
|
||||
if (codepoint < 0x80) {
|
||||
utf8Buf[0] = (char) codepoint;
|
||||
utf8Buf[1] = 0;
|
||||
} else if (codepoint < 0x0800) {
|
||||
utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0);
|
||||
utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80);
|
||||
utf8Buf[2] = 0;
|
||||
} else if (codepoint < 0x10000) {
|
||||
utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0);
|
||||
utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80);
|
||||
utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80);
|
||||
utf8Buf[3] = 0;
|
||||
} else if (codepoint < 0x200000) {
|
||||
utf8Buf[0] =(char)((codepoint >> 18) | 0xF0);
|
||||
utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80);
|
||||
utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80);
|
||||
utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80);
|
||||
utf8Buf[4] = 0;
|
||||
} else {
|
||||
utf8Buf[0] = '?';
|
||||
utf8Buf[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void yajl_string_decode(yajl_buf buf, const unsigned char * str,
|
||||
size_t len)
|
||||
{
|
||||
size_t beg = 0;
|
||||
size_t end = 0;
|
||||
|
||||
while (end < len) {
|
||||
if (str[end] == '\\') {
|
||||
char utf8Buf[5];
|
||||
const char * unescaped = "?";
|
||||
yajl_buf_append(buf, str + beg, end - beg);
|
||||
switch (str[++end]) {
|
||||
case 'r': unescaped = "\r"; break;
|
||||
case 'n': unescaped = "\n"; break;
|
||||
case '\\': unescaped = "\\"; break;
|
||||
case '/': unescaped = "/"; break;
|
||||
case '"': unescaped = "\""; break;
|
||||
case 'f': unescaped = "\f"; break;
|
||||
case 'b': unescaped = "\b"; break;
|
||||
case 't': unescaped = "\t"; break;
|
||||
case 'u': {
|
||||
unsigned int codepoint = 0;
|
||||
hexToDigit(&codepoint, str + ++end);
|
||||
end+=3;
|
||||
/* check if this is a surrogate */
|
||||
if ((codepoint & 0xFC00) == 0xD800) {
|
||||
end++;
|
||||
if (str[end] == '\\' && str[end + 1] == 'u') {
|
||||
unsigned int surrogate = 0;
|
||||
hexToDigit(&surrogate, str + end + 2);
|
||||
codepoint =
|
||||
(((codepoint & 0x3F) << 10) |
|
||||
((((codepoint >> 6) & 0xF) + 1) << 16) |
|
||||
(surrogate & 0x3FF));
|
||||
end += 5;
|
||||
} else {
|
||||
unescaped = "?";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Utf32toUtf8(codepoint, utf8Buf);
|
||||
unescaped = utf8Buf;
|
||||
|
||||
if (codepoint == 0) {
|
||||
yajl_buf_append(buf, unescaped, 1);
|
||||
beg = ++end;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert("this should never happen" == NULL);
|
||||
}
|
||||
yajl_buf_append(buf, unescaped, (unsigned int)strlen(unescaped));
|
||||
beg = ++end;
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
}
|
||||
yajl_buf_append(buf, str + beg, end - beg);
|
||||
}
|
||||
|
||||
#define ADV_PTR s++; if (!(len--)) return 0;
|
||||
|
||||
int yajl_string_validate_utf8(const unsigned char * s, size_t len)
|
||||
{
|
||||
if (!len) return 1;
|
||||
if (!s) return 0;
|
||||
|
||||
while (len--) {
|
||||
/* single byte */
|
||||
if (*s <= 0x7f) {
|
||||
/* noop */
|
||||
}
|
||||
/* two byte */
|
||||
else if ((*s >> 5) == 0x6) {
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
}
|
||||
/* three byte */
|
||||
else if ((*s >> 4) == 0x0e) {
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
}
|
||||
/* four byte */
|
||||
else if ((*s >> 3) == 0x1e) {
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
34
thirdparty/yajl/src/yajl_encode.h
vendored
34
thirdparty/yajl/src/yajl_encode.h
vendored
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_ENCODE_H__
|
||||
#define __YAJL_ENCODE_H__
|
||||
|
||||
#include "yajl_buf.h"
|
||||
#include "api/yajl_gen.h"
|
||||
|
||||
void yajl_string_encode(const yajl_print_t printer,
|
||||
void * ctx,
|
||||
const unsigned char * str,
|
||||
size_t length,
|
||||
int escape_solidus);
|
||||
|
||||
void yajl_string_decode(yajl_buf buf, const unsigned char * str,
|
||||
size_t length);
|
||||
|
||||
int yajl_string_validate_utf8(const unsigned char * s, size_t len);
|
||||
|
||||
#endif
|
350
thirdparty/yajl/src/yajl_gen.c
vendored
350
thirdparty/yajl/src/yajl_gen.c
vendored
@ -1,350 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "api/yajl_gen.h"
|
||||
#include "yajl_buf.h"
|
||||
#include "yajl_encode.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef enum {
|
||||
yajl_gen_start,
|
||||
yajl_gen_map_start,
|
||||
yajl_gen_map_key,
|
||||
yajl_gen_map_val,
|
||||
yajl_gen_array_start,
|
||||
yajl_gen_in_array,
|
||||
yajl_gen_complete,
|
||||
yajl_gen_error
|
||||
} yajl_gen_state;
|
||||
|
||||
struct yajl_gen_t
|
||||
{
|
||||
unsigned int flags;
|
||||
unsigned int depth;
|
||||
const char * indentString;
|
||||
yajl_gen_state state[YAJL_MAX_DEPTH];
|
||||
yajl_print_t print;
|
||||
void * ctx; /* yajl_buf */
|
||||
/* memory allocation routines */
|
||||
yajl_alloc_funcs alloc;
|
||||
};
|
||||
|
||||
int
|
||||
yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...)
|
||||
{
|
||||
int rv = 1;
|
||||
va_list ap;
|
||||
va_start(ap, opt);
|
||||
|
||||
switch(opt) {
|
||||
case yajl_gen_beautify:
|
||||
case yajl_gen_validate_utf8:
|
||||
if (va_arg(ap, int)) g->flags |= opt;
|
||||
else g->flags &= ~opt;
|
||||
break;
|
||||
case yajl_gen_indent_string: {
|
||||
const char *indent = va_arg(ap, const char *);
|
||||
g->indentString = indent;
|
||||
for (; *indent; indent++) {
|
||||
if (*indent != '\n'
|
||||
&& *indent != '\v'
|
||||
&& *indent != '\f'
|
||||
&& *indent != '\t'
|
||||
&& *indent != '\r'
|
||||
&& *indent != ' ')
|
||||
{
|
||||
g->indentString = NULL;
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case yajl_gen_print_callback:
|
||||
yajl_buf_free(g->ctx);
|
||||
g->print = va_arg(ap, const yajl_print_t);
|
||||
g->ctx = va_arg(ap, void *);
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
yajl_gen
|
||||
yajl_gen_alloc(const yajl_alloc_funcs * afs)
|
||||
{
|
||||
yajl_gen g = NULL;
|
||||
yajl_alloc_funcs afsBuffer;
|
||||
|
||||
/* first order of business is to set up memory allocation routines */
|
||||
if (afs != NULL) {
|
||||
if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
yajl_set_default_alloc_funcs(&afsBuffer);
|
||||
afs = &afsBuffer;
|
||||
}
|
||||
|
||||
g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t));
|
||||
if (!g) return NULL;
|
||||
|
||||
memset((void *) g, 0, sizeof(struct yajl_gen_t));
|
||||
/* copy in pointers to allocation routines */
|
||||
memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
|
||||
|
||||
g->print = (yajl_print_t)&yajl_buf_append;
|
||||
g->ctx = yajl_buf_alloc(&(g->alloc));
|
||||
g->indentString = " ";
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_gen_free(yajl_gen g)
|
||||
{
|
||||
if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx);
|
||||
YA_FREE(&(g->alloc), g);
|
||||
}
|
||||
|
||||
#define INSERT_SEP \
|
||||
if (g->state[g->depth] == yajl_gen_map_key || \
|
||||
g->state[g->depth] == yajl_gen_in_array) { \
|
||||
g->print(g->ctx, ",", 1); \
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); \
|
||||
} else if (g->state[g->depth] == yajl_gen_map_val) { \
|
||||
g->print(g->ctx, ":", 1); \
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1); \
|
||||
}
|
||||
|
||||
#define INSERT_WHITESPACE \
|
||||
if ((g->flags & yajl_gen_beautify)) { \
|
||||
if (g->state[g->depth] != yajl_gen_map_val) { \
|
||||
unsigned int _i; \
|
||||
for (_i=0;_i<g->depth;_i++) \
|
||||
g->print(g->ctx, \
|
||||
g->indentString, \
|
||||
(unsigned int)strlen(g->indentString)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENSURE_NOT_KEY \
|
||||
if (g->state[g->depth] == yajl_gen_map_key || \
|
||||
g->state[g->depth] == yajl_gen_map_start) { \
|
||||
return yajl_gen_keys_must_be_strings; \
|
||||
} \
|
||||
|
||||
/* check that we're not complete, or in error state. in a valid state
|
||||
* to be generating */
|
||||
#define ENSURE_VALID_STATE \
|
||||
if (g->state[g->depth] == yajl_gen_error) { \
|
||||
return yajl_gen_in_error_state;\
|
||||
} else if (g->state[g->depth] == yajl_gen_complete) { \
|
||||
return yajl_gen_generation_complete; \
|
||||
}
|
||||
|
||||
#define INCREMENT_DEPTH \
|
||||
if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
|
||||
|
||||
#define DECREMENT_DEPTH \
|
||||
if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_error;
|
||||
|
||||
#define APPENDED_ATOM \
|
||||
switch (g->state[g->depth]) { \
|
||||
case yajl_gen_start: \
|
||||
g->state[g->depth] = yajl_gen_complete; \
|
||||
break; \
|
||||
case yajl_gen_map_start: \
|
||||
case yajl_gen_map_key: \
|
||||
g->state[g->depth] = yajl_gen_map_val; \
|
||||
break; \
|
||||
case yajl_gen_array_start: \
|
||||
g->state[g->depth] = yajl_gen_in_array; \
|
||||
break; \
|
||||
case yajl_gen_map_val: \
|
||||
g->state[g->depth] = yajl_gen_map_key; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
|
||||
#define FINAL_NEWLINE \
|
||||
if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \
|
||||
g->print(g->ctx, "\n", 1);
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_integer(yajl_gen g, long long int number)
|
||||
{
|
||||
char i[32];
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
sprintf(i, "%lld", number);
|
||||
g->print(g->ctx, i, (unsigned int)strlen(i));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#include <float.h>
|
||||
#define isnan _isnan
|
||||
#define isinf !_finite
|
||||
#endif
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_double(yajl_gen g, double number)
|
||||
{
|
||||
char i[32];
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY;
|
||||
if (isnan(number) || isinf(number)) return yajl_gen_invalid_number;
|
||||
INSERT_SEP; INSERT_WHITESPACE;
|
||||
sprintf(i, "%.20g", number);
|
||||
g->print(g->ctx, i, (unsigned int)strlen(i));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_number(yajl_gen g, const char * s, size_t l)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, s, l);
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_string(yajl_gen g, const unsigned char * str,
|
||||
size_t len)
|
||||
{
|
||||
// if validation is enabled, check that the string is valid utf8
|
||||
// XXX: This checking could be done a little faster, in the same pass as
|
||||
// the string encoding
|
||||
if (g->flags & yajl_gen_validate_utf8) {
|
||||
if (!yajl_string_validate_utf8(str, len)) {
|
||||
return yajl_gen_invalid_string;
|
||||
}
|
||||
}
|
||||
ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "\"", 1);
|
||||
yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus);
|
||||
g->print(g->ctx, "\"", 1);
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_null(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "null", strlen("null"));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_bool(yajl_gen g, int boolean)
|
||||
{
|
||||
const char * val = boolean ? "true" : "false";
|
||||
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, val, (unsigned int)strlen(val));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_map_open(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
INCREMENT_DEPTH;
|
||||
|
||||
g->state[g->depth] = yajl_gen_map_start;
|
||||
g->print(g->ctx, "{", 1);
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_map_close(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE;
|
||||
DECREMENT_DEPTH;
|
||||
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
APPENDED_ATOM;
|
||||
INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "}", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_array_open(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
INCREMENT_DEPTH;
|
||||
g->state[g->depth] = yajl_gen_array_start;
|
||||
g->print(g->ctx, "[", 1);
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_array_close(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE;
|
||||
DECREMENT_DEPTH;
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
APPENDED_ATOM;
|
||||
INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "]", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf,
|
||||
size_t * len)
|
||||
{
|
||||
if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf;
|
||||
*buf = yajl_buf_data((yajl_buf)g->ctx);
|
||||
*len = yajl_buf_len((yajl_buf)g->ctx);
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_gen_clear(yajl_gen g)
|
||||
{
|
||||
if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx);
|
||||
}
|
763
thirdparty/yajl/src/yajl_lex.c
vendored
763
thirdparty/yajl/src/yajl_lex.c
vendored
@ -1,763 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_lex.h"
|
||||
#include "yajl_buf.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef YAJL_LEXER_DEBUG
|
||||
static const char *
|
||||
tokToStr(yajl_tok tok)
|
||||
{
|
||||
switch (tok) {
|
||||
case yajl_tok_bool: return "bool";
|
||||
case yajl_tok_colon: return "colon";
|
||||
case yajl_tok_comma: return "comma";
|
||||
case yajl_tok_eof: return "eof";
|
||||
case yajl_tok_error: return "error";
|
||||
case yajl_tok_left_brace: return "brace";
|
||||
case yajl_tok_left_bracket: return "bracket";
|
||||
case yajl_tok_null: return "null";
|
||||
case yajl_tok_integer: return "integer";
|
||||
case yajl_tok_double: return "double";
|
||||
case yajl_tok_right_brace: return "brace";
|
||||
case yajl_tok_right_bracket: return "bracket";
|
||||
case yajl_tok_string: return "string";
|
||||
case yajl_tok_string_with_escapes: return "string_with_escapes";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Impact of the stream parsing feature on the lexer:
|
||||
*
|
||||
* YAJL support stream parsing. That is, the ability to parse the first
|
||||
* bits of a chunk of JSON before the last bits are available (still on
|
||||
* the network or disk). This makes the lexer more complex. The
|
||||
* responsibility of the lexer is to handle transparently the case where
|
||||
* a chunk boundary falls in the middle of a token. This is
|
||||
* accomplished is via a buffer and a character reading abstraction.
|
||||
*
|
||||
* Overview of implementation
|
||||
*
|
||||
* When we lex to end of input string before end of token is hit, we
|
||||
* copy all of the input text composing the token into our lexBuf.
|
||||
*
|
||||
* Every time we read a character, we do so through the readChar function.
|
||||
* readChar's responsibility is to handle pulling all chars from the buffer
|
||||
* before pulling chars from input text
|
||||
*/
|
||||
|
||||
struct yajl_lexer_t {
|
||||
/* the overal line and char offset into the data */
|
||||
size_t lineOff;
|
||||
size_t charOff;
|
||||
|
||||
/* error */
|
||||
yajl_lex_error error;
|
||||
|
||||
/* a input buffer to handle the case where a token is spread over
|
||||
* multiple chunks */
|
||||
yajl_buf buf;
|
||||
|
||||
/* in the case where we have data in the lexBuf, bufOff holds
|
||||
* the current offset into the lexBuf. */
|
||||
size_t bufOff;
|
||||
|
||||
/* are we using the lex buf? */
|
||||
unsigned int bufInUse;
|
||||
|
||||
/* shall we allow comments? */
|
||||
unsigned int allowComments;
|
||||
|
||||
/* shall we validate utf8 inside strings? */
|
||||
unsigned int validateUTF8;
|
||||
|
||||
yajl_alloc_funcs * alloc;
|
||||
};
|
||||
|
||||
#define readChar(lxr, txt, off) \
|
||||
(((lxr)->bufInUse && yajl_buf_len((lxr)->buf) && lxr->bufOff < yajl_buf_len((lxr)->buf)) ? \
|
||||
(*((const unsigned char *) yajl_buf_data((lxr)->buf) + ((lxr)->bufOff)++)) : \
|
||||
((txt)[(*(off))++]))
|
||||
|
||||
#define unreadChar(lxr, off) ((*(off) > 0) ? (*(off))-- : ((lxr)->bufOff--))
|
||||
|
||||
yajl_lexer
|
||||
yajl_lex_alloc(yajl_alloc_funcs * alloc,
|
||||
unsigned int allowComments, unsigned int validateUTF8)
|
||||
{
|
||||
yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t));
|
||||
memset((void *) lxr, 0, sizeof(struct yajl_lexer_t));
|
||||
lxr->buf = yajl_buf_alloc(alloc);
|
||||
lxr->allowComments = allowComments;
|
||||
lxr->validateUTF8 = validateUTF8;
|
||||
lxr->alloc = alloc;
|
||||
return lxr;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_lex_free(yajl_lexer lxr)
|
||||
{
|
||||
yajl_buf_free(lxr->buf);
|
||||
YA_FREE(lxr->alloc, lxr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* a lookup table which lets us quickly determine three things:
|
||||
* VEC - valid escaped control char
|
||||
* note. the solidus '/' may be escaped or not.
|
||||
* IJC - invalid json char
|
||||
* VHC - valid hex char
|
||||
* NFP - needs further processing (from a string scanning perspective)
|
||||
* NUC - needs utf8 checking when enabled (from a string scanning perspective)
|
||||
*/
|
||||
#define VEC 0x01
|
||||
#define IJC 0x02
|
||||
#define VHC 0x04
|
||||
#define NFP 0x08
|
||||
#define NUC 0x10
|
||||
|
||||
static const char charLookupTable[256] =
|
||||
{
|
||||
/*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
/*08*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
/*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
/*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
|
||||
/*20*/ 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , 0 , 0 ,
|
||||
/*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC ,
|
||||
/*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC ,
|
||||
/*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
|
||||
/*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 ,
|
||||
/*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
/*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
/*58*/ 0 , 0 , 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 ,
|
||||
|
||||
/*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 ,
|
||||
/*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 ,
|
||||
/*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 ,
|
||||
/*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC
|
||||
};
|
||||
|
||||
/** process a variable length utf8 encoded codepoint.
|
||||
*
|
||||
* returns:
|
||||
* yajl_tok_string - if valid utf8 char was parsed and offset was
|
||||
* advanced
|
||||
* yajl_tok_eof - if end of input was hit before validation could
|
||||
* complete
|
||||
* yajl_tok_error - if invalid utf8 was encountered
|
||||
*
|
||||
* NOTE: on error the offset will point to the first char of the
|
||||
* invalid utf8 */
|
||||
#define UTF8_CHECK_EOF if (*offset >= jsonTextLen) { return yajl_tok_eof; }
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset,
|
||||
unsigned char curChar)
|
||||
{
|
||||
if (curChar <= 0x7f) {
|
||||
/* single byte */
|
||||
return yajl_tok_string;
|
||||
} else if ((curChar >> 5) == 0x6) {
|
||||
/* two byte */
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) return yajl_tok_string;
|
||||
} else if ((curChar >> 4) == 0x0e) {
|
||||
/* three byte */
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) {
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) return yajl_tok_string;
|
||||
}
|
||||
} else if ((curChar >> 3) == 0x1e) {
|
||||
/* four byte */
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) {
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) {
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) return yajl_tok_string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return yajl_tok_error;
|
||||
}
|
||||
|
||||
/* lex a string. input is the lexer, pointer to beginning of
|
||||
* json text, and start of string (offset).
|
||||
* a token is returned which has the following meanings:
|
||||
* yajl_tok_string: lex of string was successful. offset points to
|
||||
* terminating '"'.
|
||||
* yajl_tok_eof: end of text was encountered before we could complete
|
||||
* the lex.
|
||||
* yajl_tok_error: embedded in the string were unallowable chars. offset
|
||||
* points to the offending char
|
||||
*/
|
||||
#define STR_CHECK_EOF \
|
||||
if (*offset >= jsonTextLen) { \
|
||||
tok = yajl_tok_eof; \
|
||||
goto finish_string_lex; \
|
||||
}
|
||||
|
||||
/** scan a string for interesting characters that might need further
|
||||
* review. return the number of chars that are uninteresting and can
|
||||
* be skipped.
|
||||
* (lth) hi world, any thoughts on how to make this routine faster? */
|
||||
static size_t
|
||||
yajl_string_scan(const unsigned char * buf, size_t len, int utf8check)
|
||||
{
|
||||
unsigned char mask = IJC|NFP|(utf8check ? NUC : 0);
|
||||
size_t skip = 0;
|
||||
while (skip < len && !(charLookupTable[*buf] & mask))
|
||||
{
|
||||
skip++;
|
||||
buf++;
|
||||
}
|
||||
return skip;
|
||||
}
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset)
|
||||
{
|
||||
yajl_tok tok = yajl_tok_error;
|
||||
int hasEscapes = 0;
|
||||
|
||||
for (;;) {
|
||||
unsigned char curChar;
|
||||
|
||||
/* now jump into a faster scanning routine to skip as much
|
||||
* of the buffers as possible */
|
||||
{
|
||||
const unsigned char * p;
|
||||
size_t len;
|
||||
|
||||
if ((lexer->bufInUse && yajl_buf_len(lexer->buf) &&
|
||||
lexer->bufOff < yajl_buf_len(lexer->buf)))
|
||||
{
|
||||
p = ((const unsigned char *) yajl_buf_data(lexer->buf) +
|
||||
(lexer->bufOff));
|
||||
len = yajl_buf_len(lexer->buf) - lexer->bufOff;
|
||||
lexer->bufOff += yajl_string_scan(p, len, lexer->validateUTF8);
|
||||
}
|
||||
else if (*offset < jsonTextLen)
|
||||
{
|
||||
p = jsonText + *offset;
|
||||
len = jsonTextLen - *offset;
|
||||
*offset += yajl_string_scan(p, len, lexer->validateUTF8);
|
||||
}
|
||||
}
|
||||
|
||||
STR_CHECK_EOF;
|
||||
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* quote terminates */
|
||||
if (curChar == '"') {
|
||||
tok = yajl_tok_string;
|
||||
break;
|
||||
}
|
||||
/* backslash escapes a set of control chars, */
|
||||
else if (curChar == '\\') {
|
||||
hasEscapes = 1;
|
||||
STR_CHECK_EOF;
|
||||
|
||||
/* special case \u */
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if (curChar == 'u') {
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
STR_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if (!(charLookupTable[curChar] & VHC)) {
|
||||
/* back up to offending char */
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_string_invalid_hex_char;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
}
|
||||
} else if (!(charLookupTable[curChar] & VEC)) {
|
||||
/* back up to offending char */
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_string_invalid_escaped_char;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
}
|
||||
/* when not validating UTF8 it's a simple table lookup to determine
|
||||
* if the present character is invalid */
|
||||
else if(charLookupTable[curChar] & IJC) {
|
||||
/* back up to offending char */
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_string_invalid_json_char;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
/* when in validate UTF8 mode we need to do some extra work */
|
||||
else if (lexer->validateUTF8) {
|
||||
yajl_tok t = yajl_lex_utf8_char(lexer, jsonText, jsonTextLen,
|
||||
offset, curChar);
|
||||
|
||||
if (t == yajl_tok_eof) {
|
||||
tok = yajl_tok_eof;
|
||||
goto finish_string_lex;
|
||||
} else if (t == yajl_tok_error) {
|
||||
lexer->error = yajl_lex_string_invalid_utf8;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
}
|
||||
/* accept it, and move on */
|
||||
}
|
||||
finish_string_lex:
|
||||
/* tell our buddy, the parser, wether he needs to process this string
|
||||
* again */
|
||||
if (hasEscapes && tok == yajl_tok_string) {
|
||||
tok = yajl_tok_string_with_escapes;
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
#define RETURN_IF_EOF if (*offset >= jsonTextLen) return yajl_tok_eof;
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset)
|
||||
{
|
||||
/** XXX: numbers are the only entities in json that we must lex
|
||||
* _beyond_ in order to know that they are complete. There
|
||||
* is an ambiguous case for integers at EOF. */
|
||||
|
||||
unsigned char c;
|
||||
|
||||
yajl_tok tok = yajl_tok_integer;
|
||||
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* optional leading minus */
|
||||
if (c == '-') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
}
|
||||
|
||||
/* a single zero, or a series of integers */
|
||||
if (c == '0') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} else if (c >= '1' && c <= '9') {
|
||||
do {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} while (c >= '0' && c <= '9');
|
||||
} else {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_missing_integer_after_minus;
|
||||
return yajl_tok_error;
|
||||
}
|
||||
|
||||
/* optional fraction (indicates this is floating point) */
|
||||
if (c == '.') {
|
||||
int numRd = 0;
|
||||
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
while (c >= '0' && c <= '9') {
|
||||
numRd++;
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
}
|
||||
|
||||
if (!numRd) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_missing_integer_after_decimal;
|
||||
return yajl_tok_error;
|
||||
}
|
||||
tok = yajl_tok_double;
|
||||
}
|
||||
|
||||
/* optional exponent (indicates this is floating point) */
|
||||
if (c == 'e' || c == 'E') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* optional sign */
|
||||
if (c == '+' || c == '-') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
}
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
do {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} while (c >= '0' && c <= '9');
|
||||
} else {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_missing_integer_after_exponent;
|
||||
return yajl_tok_error;
|
||||
}
|
||||
tok = yajl_tok_double;
|
||||
}
|
||||
|
||||
/* we always go "one too far" */
|
||||
unreadChar(lexer, offset);
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
yajl_tok tok = yajl_tok_comment;
|
||||
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* either slash or star expected */
|
||||
if (c == '/') {
|
||||
/* now we throw away until end of line */
|
||||
do {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} while (c != '\n');
|
||||
} else if (c == '*') {
|
||||
/* now we throw away until end of comment */
|
||||
for (;;) {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c == '*') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c == '/') {
|
||||
break;
|
||||
} else {
|
||||
unreadChar(lexer, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lexer->error = yajl_lex_invalid_char;
|
||||
tok = yajl_tok_error;
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
yajl_tok
|
||||
yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset,
|
||||
const unsigned char ** outBuf, size_t * outLen)
|
||||
{
|
||||
yajl_tok tok = yajl_tok_error;
|
||||
unsigned char c;
|
||||
size_t startOffset = *offset;
|
||||
|
||||
*outBuf = NULL;
|
||||
*outLen = 0;
|
||||
|
||||
for (;;) {
|
||||
assert(*offset <= jsonTextLen);
|
||||
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
switch (c) {
|
||||
case '{':
|
||||
tok = yajl_tok_left_bracket;
|
||||
goto lexed;
|
||||
case '}':
|
||||
tok = yajl_tok_right_bracket;
|
||||
goto lexed;
|
||||
case '[':
|
||||
tok = yajl_tok_left_brace;
|
||||
goto lexed;
|
||||
case ']':
|
||||
tok = yajl_tok_right_brace;
|
||||
goto lexed;
|
||||
case ',':
|
||||
tok = yajl_tok_comma;
|
||||
goto lexed;
|
||||
case ':':
|
||||
tok = yajl_tok_colon;
|
||||
goto lexed;
|
||||
case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
|
||||
startOffset++;
|
||||
break;
|
||||
case 't': {
|
||||
const char * want = "rue";
|
||||
do {
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c != *want) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_invalid_string;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
} while (*(++want));
|
||||
tok = yajl_tok_bool;
|
||||
goto lexed;
|
||||
}
|
||||
case 'f': {
|
||||
const char * want = "alse";
|
||||
do {
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c != *want) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_invalid_string;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
} while (*(++want));
|
||||
tok = yajl_tok_bool;
|
||||
goto lexed;
|
||||
}
|
||||
case 'n': {
|
||||
const char * want = "ull";
|
||||
do {
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c != *want) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_invalid_string;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
} while (*(++want));
|
||||
tok = yajl_tok_null;
|
||||
goto lexed;
|
||||
}
|
||||
case '"': {
|
||||
tok = yajl_lex_string(lexer, (const unsigned char *) jsonText,
|
||||
jsonTextLen, offset);
|
||||
goto lexed;
|
||||
}
|
||||
case '-':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9': {
|
||||
/* integer parsing wants to start from the beginning */
|
||||
unreadChar(lexer, offset);
|
||||
tok = yajl_lex_number(lexer, (const unsigned char *) jsonText,
|
||||
jsonTextLen, offset);
|
||||
goto lexed;
|
||||
}
|
||||
case '/':
|
||||
/* hey, look, a probable comment! If comments are disabled
|
||||
* it's an error. */
|
||||
if (!lexer->allowComments) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_unallowed_comment;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
/* if comments are enabled, then we should try to lex
|
||||
* the thing. possible outcomes are
|
||||
* - successful lex (tok_comment, which means continue),
|
||||
* - malformed comment opening (slash not followed by
|
||||
* '*' or '/') (tok_error)
|
||||
* - eof hit. (tok_eof) */
|
||||
tok = yajl_lex_comment(lexer, (const unsigned char *) jsonText,
|
||||
jsonTextLen, offset);
|
||||
if (tok == yajl_tok_comment) {
|
||||
/* "error" is silly, but that's the initial
|
||||
* state of tok. guilty until proven innocent. */
|
||||
tok = yajl_tok_error;
|
||||
yajl_buf_clear(lexer->buf);
|
||||
lexer->bufInUse = 0;
|
||||
startOffset = *offset;
|
||||
break;
|
||||
}
|
||||
/* hit error or eof, bail */
|
||||
goto lexed;
|
||||
default:
|
||||
lexer->error = yajl_lex_invalid_char;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lexed:
|
||||
/* need to append to buffer if the buffer is in use or
|
||||
* if it's an EOF token */
|
||||
if (tok == yajl_tok_eof || lexer->bufInUse) {
|
||||
if (!lexer->bufInUse) yajl_buf_clear(lexer->buf);
|
||||
lexer->bufInUse = 1;
|
||||
yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset);
|
||||
lexer->bufOff = 0;
|
||||
|
||||
if (tok != yajl_tok_eof) {
|
||||
*outBuf = yajl_buf_data(lexer->buf);
|
||||
*outLen = yajl_buf_len(lexer->buf);
|
||||
lexer->bufInUse = 0;
|
||||
}
|
||||
} else if (tok != yajl_tok_error) {
|
||||
*outBuf = jsonText + startOffset;
|
||||
*outLen = *offset - startOffset;
|
||||
}
|
||||
|
||||
/* special case for strings. skip the quotes. */
|
||||
if (tok == yajl_tok_string || tok == yajl_tok_string_with_escapes)
|
||||
{
|
||||
assert(*outLen >= 2);
|
||||
(*outBuf)++;
|
||||
*outLen -= 2;
|
||||
}
|
||||
|
||||
|
||||
#ifdef YAJL_LEXER_DEBUG
|
||||
if (tok == yajl_tok_error) {
|
||||
printf("lexical error: %s\n",
|
||||
yajl_lex_error_to_string(yajl_lex_get_error(lexer)));
|
||||
} else if (tok == yajl_tok_eof) {
|
||||
printf("EOF hit\n");
|
||||
} else {
|
||||
printf("lexed %s: '", tokToStr(tok));
|
||||
fwrite(*outBuf, 1, *outLen, stdout);
|
||||
printf("'\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
const char *
|
||||
yajl_lex_error_to_string(yajl_lex_error error)
|
||||
{
|
||||
switch (error) {
|
||||
case yajl_lex_e_ok:
|
||||
return "ok, no error";
|
||||
case yajl_lex_string_invalid_utf8:
|
||||
return "invalid bytes in UTF8 string.";
|
||||
case yajl_lex_string_invalid_escaped_char:
|
||||
return "inside a string, '\\' occurs before a character "
|
||||
"which it may not.";
|
||||
case yajl_lex_string_invalid_json_char:
|
||||
return "invalid character inside string.";
|
||||
case yajl_lex_string_invalid_hex_char:
|
||||
return "invalid (non-hex) character occurs after '\\u' inside "
|
||||
"string.";
|
||||
case yajl_lex_invalid_char:
|
||||
return "invalid char in json text.";
|
||||
case yajl_lex_invalid_string:
|
||||
return "invalid string in json text.";
|
||||
case yajl_lex_missing_integer_after_exponent:
|
||||
return "malformed number, a digit is required after the exponent.";
|
||||
case yajl_lex_missing_integer_after_decimal:
|
||||
return "malformed number, a digit is required after the "
|
||||
"decimal point.";
|
||||
case yajl_lex_missing_integer_after_minus:
|
||||
return "malformed number, a digit is required after the "
|
||||
"minus sign.";
|
||||
case yajl_lex_unallowed_comment:
|
||||
return "probable comment found in input text, comments are "
|
||||
"not enabled.";
|
||||
}
|
||||
return "unknown error code";
|
||||
}
|
||||
|
||||
|
||||
/** allows access to more specific information about the lexical
|
||||
* error when yajl_lex_lex returns yajl_tok_error. */
|
||||
yajl_lex_error
|
||||
yajl_lex_get_error(yajl_lexer lexer)
|
||||
{
|
||||
if (lexer == NULL) return (yajl_lex_error) -1;
|
||||
return lexer->error;
|
||||
}
|
||||
|
||||
size_t yajl_lex_current_line(yajl_lexer lexer)
|
||||
{
|
||||
return lexer->lineOff;
|
||||
}
|
||||
|
||||
size_t yajl_lex_current_char(yajl_lexer lexer)
|
||||
{
|
||||
return lexer->charOff;
|
||||
}
|
||||
|
||||
yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t offset)
|
||||
{
|
||||
const unsigned char * outBuf;
|
||||
size_t outLen;
|
||||
size_t bufLen = yajl_buf_len(lexer->buf);
|
||||
size_t bufOff = lexer->bufOff;
|
||||
unsigned int bufInUse = lexer->bufInUse;
|
||||
yajl_tok tok;
|
||||
|
||||
tok = yajl_lex_lex(lexer, jsonText, jsonTextLen, &offset,
|
||||
&outBuf, &outLen);
|
||||
|
||||
lexer->bufOff = bufOff;
|
||||
lexer->bufInUse = bufInUse;
|
||||
yajl_buf_truncate(lexer->buf, bufLen);
|
||||
|
||||
return tok;
|
||||
}
|
117
thirdparty/yajl/src/yajl_lex.h
vendored
117
thirdparty/yajl/src/yajl_lex.h
vendored
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_LEX_H__
|
||||
#define __YAJL_LEX_H__
|
||||
|
||||
#include "api/yajl_common.h"
|
||||
|
||||
typedef enum {
|
||||
yajl_tok_bool,
|
||||
yajl_tok_colon,
|
||||
yajl_tok_comma,
|
||||
yajl_tok_eof,
|
||||
yajl_tok_error,
|
||||
yajl_tok_left_brace,
|
||||
yajl_tok_left_bracket,
|
||||
yajl_tok_null,
|
||||
yajl_tok_right_brace,
|
||||
yajl_tok_right_bracket,
|
||||
|
||||
/* we differentiate between integers and doubles to allow the
|
||||
* parser to interpret the number without re-scanning */
|
||||
yajl_tok_integer,
|
||||
yajl_tok_double,
|
||||
|
||||
/* we differentiate between strings which require further processing,
|
||||
* and strings that do not */
|
||||
yajl_tok_string,
|
||||
yajl_tok_string_with_escapes,
|
||||
|
||||
/* comment tokens are not currently returned to the parser, ever */
|
||||
yajl_tok_comment
|
||||
} yajl_tok;
|
||||
|
||||
typedef struct yajl_lexer_t * yajl_lexer;
|
||||
|
||||
yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc,
|
||||
unsigned int allowComments,
|
||||
unsigned int validateUTF8);
|
||||
|
||||
void yajl_lex_free(yajl_lexer lexer);
|
||||
|
||||
/**
|
||||
* run/continue a lex. "offset" is an input/output parameter.
|
||||
* It should be initialized to zero for a
|
||||
* new chunk of target text, and upon subsetquent calls with the same
|
||||
* target text should passed with the value of the previous invocation.
|
||||
*
|
||||
* the client may be interested in the value of offset when an error is
|
||||
* returned from the lexer. This allows the client to render useful
|
||||
n * error messages.
|
||||
*
|
||||
* When you pass the next chunk of data, context should be reinitialized
|
||||
* to zero.
|
||||
*
|
||||
* Finally, the output buffer is usually just a pointer into the jsonText,
|
||||
* however in cases where the entity being lexed spans multiple chunks,
|
||||
* the lexer will buffer the entity and the data returned will be
|
||||
* a pointer into that buffer.
|
||||
*
|
||||
* This behavior is abstracted from client code except for the performance
|
||||
* implications which require that the client choose a reasonable chunk
|
||||
* size to get adequate performance.
|
||||
*/
|
||||
yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset,
|
||||
const unsigned char ** outBuf, size_t * outLen);
|
||||
|
||||
/** have a peek at the next token, but don't move the lexer forward */
|
||||
yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t offset);
|
||||
|
||||
|
||||
typedef enum {
|
||||
yajl_lex_e_ok = 0,
|
||||
yajl_lex_string_invalid_utf8,
|
||||
yajl_lex_string_invalid_escaped_char,
|
||||
yajl_lex_string_invalid_json_char,
|
||||
yajl_lex_string_invalid_hex_char,
|
||||
yajl_lex_invalid_char,
|
||||
yajl_lex_invalid_string,
|
||||
yajl_lex_missing_integer_after_decimal,
|
||||
yajl_lex_missing_integer_after_exponent,
|
||||
yajl_lex_missing_integer_after_minus,
|
||||
yajl_lex_unallowed_comment
|
||||
} yajl_lex_error;
|
||||
|
||||
const char * yajl_lex_error_to_string(yajl_lex_error error);
|
||||
|
||||
/** allows access to more specific information about the lexical
|
||||
* error when yajl_lex_lex returns yajl_tok_error. */
|
||||
yajl_lex_error yajl_lex_get_error(yajl_lexer lexer);
|
||||
|
||||
/** get the current offset into the most recently lexed json string. */
|
||||
size_t yajl_lex_current_offset(yajl_lexer lexer);
|
||||
|
||||
/** get the number of lines lexed by this lexer instance */
|
||||
size_t yajl_lex_current_line(yajl_lexer lexer);
|
||||
|
||||
/** get the number of chars lexed by this lexer instance since the last
|
||||
* \n or \r */
|
||||
size_t yajl_lex_current_char(yajl_lexer lexer);
|
||||
|
||||
#endif
|
492
thirdparty/yajl/src/yajl_parser.c
vendored
492
thirdparty/yajl/src/yajl_parser.c
vendored
@ -1,492 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "api/yajl_parse.h"
|
||||
#include "yajl_lex.h"
|
||||
#include "yajl_parser.h"
|
||||
#include "yajl_encode.h"
|
||||
#include "yajl_bytestack.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10))
|
||||
|
||||
/* same semantics as strtol */
|
||||
long long
|
||||
yajl_parse_integer(const unsigned char *number, unsigned int length)
|
||||
{
|
||||
long long ret = 0;
|
||||
long sign = 1;
|
||||
const unsigned char *pos = number;
|
||||
if (*pos == '-') { pos++; sign = -1; }
|
||||
if (*pos == '+') { pos++; }
|
||||
|
||||
while (pos < number + length) {
|
||||
if ( ret > MAX_VALUE_TO_MULTIPLY ) {
|
||||
errno = ERANGE;
|
||||
return sign == 1 ? LLONG_MAX : LLONG_MIN;
|
||||
}
|
||||
ret *= 10;
|
||||
if (LLONG_MAX - ret < (*pos - '0')) {
|
||||
errno = ERANGE;
|
||||
return sign == 1 ? LLONG_MAX : LLONG_MIN;
|
||||
}
|
||||
ret += (*pos++ - '0');
|
||||
}
|
||||
|
||||
return sign * ret;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, int verbose)
|
||||
{
|
||||
size_t offset = hand->bytesConsumed;
|
||||
unsigned char * str;
|
||||
const char * errorType = NULL;
|
||||
const char * errorText = NULL;
|
||||
char text[72];
|
||||
const char * arrow = " (right here) ------^\n";
|
||||
|
||||
if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) {
|
||||
errorType = "parse";
|
||||
errorText = hand->parseError;
|
||||
} else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) {
|
||||
errorType = "lexical";
|
||||
errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer));
|
||||
} else {
|
||||
errorType = "unknown";
|
||||
}
|
||||
|
||||
{
|
||||
size_t memneeded = 0;
|
||||
memneeded += strlen(errorType);
|
||||
memneeded += strlen(" error");
|
||||
if (errorText != NULL) {
|
||||
memneeded += strlen(": ");
|
||||
memneeded += strlen(errorText);
|
||||
}
|
||||
str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2);
|
||||
if (!str) return NULL;
|
||||
str[0] = 0;
|
||||
strcat((char *) str, errorType);
|
||||
strcat((char *) str, " error");
|
||||
if (errorText != NULL) {
|
||||
strcat((char *) str, ": ");
|
||||
strcat((char *) str, errorText);
|
||||
}
|
||||
strcat((char *) str, "\n");
|
||||
}
|
||||
|
||||
/* now we append as many spaces as needed to make sure the error
|
||||
* falls at char 41, if verbose was specified */
|
||||
if (verbose) {
|
||||
size_t start, end, i;
|
||||
size_t spacesNeeded;
|
||||
|
||||
spacesNeeded = (offset < 30 ? 40 - offset : 10);
|
||||
start = (offset >= 30 ? offset - 30 : 0);
|
||||
end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30);
|
||||
|
||||
for (i=0;i<spacesNeeded;i++) text[i] = ' ';
|
||||
|
||||
for (;start < end;start++, i++) {
|
||||
if (jsonText[start] != '\n' && jsonText[start] != '\r')
|
||||
{
|
||||
text[i] = jsonText[start];
|
||||
}
|
||||
else
|
||||
{
|
||||
text[i] = ' ';
|
||||
}
|
||||
}
|
||||
assert(i <= 71);
|
||||
text[i++] = '\n';
|
||||
text[i] = 0;
|
||||
{
|
||||
char * newStr = (char *)
|
||||
YA_MALLOC(&(hand->alloc), (unsigned int)(strlen((char *) str) +
|
||||
strlen((char *) text) +
|
||||
strlen(arrow) + 1));
|
||||
if (newStr) {
|
||||
newStr[0] = 0;
|
||||
strcat((char *) newStr, (char *) str);
|
||||
strcat((char *) newStr, text);
|
||||
strcat((char *) newStr, arrow);
|
||||
}
|
||||
YA_FREE(&(hand->alloc), str);
|
||||
str = (unsigned char *) newStr;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* check for client cancelation */
|
||||
#define _CC_CHK(x) \
|
||||
if (!(x)) { \
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
|
||||
hand->parseError = \
|
||||
"client cancelled parse via callback return value"; \
|
||||
return yajl_status_client_canceled; \
|
||||
}
|
||||
|
||||
|
||||
yajl_status
|
||||
yajl_do_finish(yajl_handle hand)
|
||||
{
|
||||
yajl_status stat;
|
||||
stat = yajl_do_parse(hand,(const unsigned char *) " ",1);
|
||||
|
||||
if (stat != yajl_status_ok) return stat;
|
||||
|
||||
switch(yajl_bs_current(hand->stateStack))
|
||||
{
|
||||
case yajl_state_parse_error:
|
||||
case yajl_state_lexical_error:
|
||||
return yajl_status_error;
|
||||
case yajl_state_got_value:
|
||||
case yajl_state_parse_complete:
|
||||
return yajl_status_ok;
|
||||
default:
|
||||
if (!(hand->flags & yajl_allow_partial_values))
|
||||
{
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "premature EOF";
|
||||
return yajl_status_error;
|
||||
}
|
||||
return yajl_status_ok;
|
||||
}
|
||||
}
|
||||
|
||||
yajl_status
|
||||
yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen)
|
||||
{
|
||||
yajl_tok tok;
|
||||
const unsigned char * buf;
|
||||
size_t bufLen;
|
||||
size_t * offset = &(hand->bytesConsumed);
|
||||
|
||||
*offset = 0;
|
||||
|
||||
around_again:
|
||||
switch (yajl_bs_current(hand->stateStack)) {
|
||||
case yajl_state_parse_complete:
|
||||
if (hand->flags & yajl_allow_multiple_values) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_got_value);
|
||||
goto around_again;
|
||||
}
|
||||
if (!(hand->flags & yajl_allow_trailing_garbage)) {
|
||||
if (*offset != jsonTextLen) {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
if (tok != yajl_tok_eof) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "trailing garbage";
|
||||
}
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
return yajl_status_ok;
|
||||
case yajl_state_lexical_error:
|
||||
case yajl_state_parse_error:
|
||||
return yajl_status_error;
|
||||
case yajl_state_start:
|
||||
case yajl_state_got_value:
|
||||
case yajl_state_map_need_val:
|
||||
case yajl_state_array_need_val:
|
||||
case yajl_state_array_start: {
|
||||
/* for arrays and maps, we advance the state for this
|
||||
* depth, then push the state of the next depth.
|
||||
* If an error occurs during the parsing of the nesting
|
||||
* enitity, the state at this level will not matter.
|
||||
* a state that needs pushing will be anything other
|
||||
* than state_start */
|
||||
|
||||
yajl_state stateToPush = yajl_state_start;
|
||||
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
|
||||
switch (tok) {
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
case yajl_tok_string:
|
||||
if (hand->callbacks && hand->callbacks->yajl_string) {
|
||||
_CC_CHK(hand->callbacks->yajl_string(hand->ctx,
|
||||
buf, bufLen));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_string_with_escapes:
|
||||
if (hand->callbacks && hand->callbacks->yajl_string) {
|
||||
yajl_buf_clear(hand->decodeBuf);
|
||||
yajl_string_decode(hand->decodeBuf, buf, bufLen);
|
||||
_CC_CHK(hand->callbacks->yajl_string(
|
||||
hand->ctx, yajl_buf_data(hand->decodeBuf),
|
||||
yajl_buf_len(hand->decodeBuf)));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_bool:
|
||||
if (hand->callbacks && hand->callbacks->yajl_boolean) {
|
||||
_CC_CHK(hand->callbacks->yajl_boolean(hand->ctx,
|
||||
*buf == 't'));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_null:
|
||||
if (hand->callbacks && hand->callbacks->yajl_null) {
|
||||
_CC_CHK(hand->callbacks->yajl_null(hand->ctx));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_left_bracket:
|
||||
if (hand->callbacks && hand->callbacks->yajl_start_map) {
|
||||
_CC_CHK(hand->callbacks->yajl_start_map(hand->ctx));
|
||||
}
|
||||
stateToPush = yajl_state_map_start;
|
||||
break;
|
||||
case yajl_tok_left_brace:
|
||||
if (hand->callbacks && hand->callbacks->yajl_start_array) {
|
||||
_CC_CHK(hand->callbacks->yajl_start_array(hand->ctx));
|
||||
}
|
||||
stateToPush = yajl_state_array_start;
|
||||
break;
|
||||
case yajl_tok_integer:
|
||||
if (hand->callbacks) {
|
||||
if (hand->callbacks->yajl_number) {
|
||||
_CC_CHK(hand->callbacks->yajl_number(
|
||||
hand->ctx,(const char *) buf, bufLen));
|
||||
} else if (hand->callbacks->yajl_integer) {
|
||||
long long int i = 0;
|
||||
i = yajl_parse_integer(buf, bufLen);
|
||||
if ((i == LLONG_MIN || i == LLONG_MAX) &&
|
||||
errno == ERANGE)
|
||||
{
|
||||
yajl_bs_set(hand->stateStack,
|
||||
yajl_state_parse_error);
|
||||
hand->parseError = "integer overflow" ;
|
||||
/* try to restore error offset */
|
||||
if (*offset >= bufLen) *offset -= bufLen;
|
||||
else *offset = 0;
|
||||
goto around_again;
|
||||
}
|
||||
_CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
|
||||
i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case yajl_tok_double:
|
||||
if (hand->callbacks) {
|
||||
if (hand->callbacks->yajl_number) {
|
||||
_CC_CHK(hand->callbacks->yajl_number(
|
||||
hand->ctx, (const char *) buf, bufLen));
|
||||
} else if (hand->callbacks->yajl_double) {
|
||||
double d = 0.0;
|
||||
yajl_buf_clear(hand->decodeBuf);
|
||||
yajl_buf_append(hand->decodeBuf, buf, bufLen);
|
||||
buf = yajl_buf_data(hand->decodeBuf);
|
||||
d = strtod((char *) buf, NULL);
|
||||
if ((d == HUGE_VAL || d == -HUGE_VAL) &&
|
||||
errno == ERANGE)
|
||||
{
|
||||
yajl_bs_set(hand->stateStack,
|
||||
yajl_state_parse_error);
|
||||
hand->parseError = "numeric (floating point) "
|
||||
"overflow";
|
||||
/* try to restore error offset */
|
||||
if (*offset >= bufLen) *offset -= bufLen;
|
||||
else *offset = 0;
|
||||
goto around_again;
|
||||
}
|
||||
_CC_CHK(hand->callbacks->yajl_double(hand->ctx,
|
||||
d));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case yajl_tok_right_brace: {
|
||||
if (yajl_bs_current(hand->stateStack) ==
|
||||
yajl_state_array_start)
|
||||
{
|
||||
if (hand->callbacks &&
|
||||
hand->callbacks->yajl_end_array)
|
||||
{
|
||||
_CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
}
|
||||
/* intentional fall-through */
|
||||
}
|
||||
case yajl_tok_colon:
|
||||
case yajl_tok_comma:
|
||||
case yajl_tok_right_bracket:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError =
|
||||
"unallowed token at this point in JSON text";
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "invalid token, internal error";
|
||||
goto around_again;
|
||||
}
|
||||
/* got a value. transition depends on the state we're in. */
|
||||
{
|
||||
yajl_state s = yajl_bs_current(hand->stateStack);
|
||||
if (s == yajl_state_start || s == yajl_state_got_value) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_complete);
|
||||
} else if (s == yajl_state_map_need_val) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_got_val);
|
||||
} else {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_array_got_val);
|
||||
}
|
||||
}
|
||||
if (stateToPush != yajl_state_start) {
|
||||
yajl_bs_push(hand->stateStack, stateToPush);
|
||||
}
|
||||
|
||||
goto around_again;
|
||||
}
|
||||
case yajl_state_map_start:
|
||||
case yajl_state_map_need_key: {
|
||||
/* only difference between these two states is that in
|
||||
* start '}' is valid, whereas in need_key, we've parsed
|
||||
* a comma, and a string key _must_ follow */
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
case yajl_tok_string_with_escapes:
|
||||
if (hand->callbacks && hand->callbacks->yajl_map_key) {
|
||||
yajl_buf_clear(hand->decodeBuf);
|
||||
yajl_string_decode(hand->decodeBuf, buf, bufLen);
|
||||
buf = yajl_buf_data(hand->decodeBuf);
|
||||
bufLen = yajl_buf_len(hand->decodeBuf);
|
||||
}
|
||||
/* intentional fall-through */
|
||||
case yajl_tok_string:
|
||||
if (hand->callbacks && hand->callbacks->yajl_map_key) {
|
||||
_CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf,
|
||||
bufLen));
|
||||
}
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_sep);
|
||||
goto around_again;
|
||||
case yajl_tok_right_bracket:
|
||||
if (yajl_bs_current(hand->stateStack) ==
|
||||
yajl_state_map_start)
|
||||
{
|
||||
if (hand->callbacks && hand->callbacks->yajl_end_map) {
|
||||
_CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
}
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError =
|
||||
"invalid object key (must be a string)";
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
case yajl_state_map_sep: {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_colon:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_need_val);
|
||||
goto around_again;
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "object key and value must "
|
||||
"be separated by a colon (':')";
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
case yajl_state_map_got_val: {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_right_bracket:
|
||||
if (hand->callbacks && hand->callbacks->yajl_end_map) {
|
||||
_CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
case yajl_tok_comma:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_need_key);
|
||||
goto around_again;
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "after key and value, inside map, "
|
||||
"I expect ',' or '}'";
|
||||
/* try to restore error offset */
|
||||
if (*offset >= bufLen) *offset -= bufLen;
|
||||
else *offset = 0;
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
case yajl_state_array_got_val: {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_right_brace:
|
||||
if (hand->callbacks && hand->callbacks->yajl_end_array) {
|
||||
_CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
case yajl_tok_comma:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_array_need_val);
|
||||
goto around_again;
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError =
|
||||
"after array element, I expect ',' or ']'";
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abort();
|
||||
return yajl_status_error;
|
||||
}
|
||||
|
78
thirdparty/yajl/src/yajl_parser.h
vendored
78
thirdparty/yajl/src/yajl_parser.h
vendored
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_PARSER_H__
|
||||
#define __YAJL_PARSER_H__
|
||||
|
||||
#include "api/yajl_parse.h"
|
||||
#include "yajl_bytestack.h"
|
||||
#include "yajl_buf.h"
|
||||
#include "yajl_lex.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
yajl_state_start = 0,
|
||||
yajl_state_parse_complete,
|
||||
yajl_state_parse_error,
|
||||
yajl_state_lexical_error,
|
||||
yajl_state_map_start,
|
||||
yajl_state_map_sep,
|
||||
yajl_state_map_need_val,
|
||||
yajl_state_map_got_val,
|
||||
yajl_state_map_need_key,
|
||||
yajl_state_array_start,
|
||||
yajl_state_array_got_val,
|
||||
yajl_state_array_need_val,
|
||||
yajl_state_got_value,
|
||||
} yajl_state;
|
||||
|
||||
struct yajl_handle_t {
|
||||
const yajl_callbacks * callbacks;
|
||||
void * ctx;
|
||||
yajl_lexer lexer;
|
||||
const char * parseError;
|
||||
/* the number of bytes consumed from the last client buffer,
|
||||
* in the case of an error this will be an error offset, in the
|
||||
* case of an error this can be used as the error offset */
|
||||
size_t bytesConsumed;
|
||||
/* temporary storage for decoded strings */
|
||||
yajl_buf decodeBuf;
|
||||
/* a stack of states. access with yajl_state_XXX routines */
|
||||
yajl_bytestack stateStack;
|
||||
/* memory allocation routines */
|
||||
yajl_alloc_funcs alloc;
|
||||
/* bitfield */
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
yajl_status
|
||||
yajl_do_parse(yajl_handle handle, const unsigned char * jsonText,
|
||||
size_t jsonTextLen);
|
||||
|
||||
yajl_status
|
||||
yajl_do_finish(yajl_handle handle);
|
||||
|
||||
unsigned char *
|
||||
yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, int verbose);
|
||||
|
||||
/* A little built in integer parsing routine with the same semantics as strtol
|
||||
* that's unaffected by LOCALE. */
|
||||
long long
|
||||
yajl_parse_integer(const unsigned char *number, unsigned int length);
|
||||
|
||||
|
||||
#endif
|
501
thirdparty/yajl/src/yajl_tree.c
vendored
501
thirdparty/yajl/src/yajl_tree.c
vendored
@ -1,501 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 Florian Forster <ff at octo.it>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "api/yajl_tree.h"
|
||||
#include "api/yajl_parse.h"
|
||||
|
||||
#include "yajl_parser.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
#define STATUS_CONTINUE 1
|
||||
#define STATUS_ABORT 0
|
||||
|
||||
struct stack_elem_s;
|
||||
typedef struct stack_elem_s stack_elem_t;
|
||||
struct stack_elem_s
|
||||
{
|
||||
char * key;
|
||||
yajl_val value;
|
||||
stack_elem_t *next;
|
||||
};
|
||||
|
||||
struct context_s
|
||||
{
|
||||
stack_elem_t *stack;
|
||||
yajl_val root;
|
||||
char *errbuf;
|
||||
size_t errbuf_size;
|
||||
};
|
||||
typedef struct context_s context_t;
|
||||
|
||||
#define RETURN_ERROR(ctx,retval,...) { \
|
||||
if ((ctx)->errbuf != NULL) \
|
||||
snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__); \
|
||||
return (retval); \
|
||||
}
|
||||
|
||||
static yajl_val value_alloc (yajl_type type)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = malloc (sizeof (*v));
|
||||
if (v == NULL) return (NULL);
|
||||
memset (v, 0, sizeof (*v));
|
||||
v->type = type;
|
||||
|
||||
return (v);
|
||||
}
|
||||
|
||||
static void yajl_object_free (yajl_val v)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!YAJL_IS_OBJECT(v)) return;
|
||||
|
||||
for (i = 0; i < v->u.object.len; i++)
|
||||
{
|
||||
free((char *) v->u.object.keys[i]);
|
||||
v->u.object.keys[i] = NULL;
|
||||
yajl_tree_free (v->u.object.values[i]);
|
||||
v->u.object.values[i] = NULL;
|
||||
}
|
||||
|
||||
free((void*) v->u.object.keys);
|
||||
free(v->u.object.values);
|
||||
free(v);
|
||||
}
|
||||
|
||||
static void yajl_array_free (yajl_val v)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!YAJL_IS_ARRAY(v)) return;
|
||||
|
||||
for (i = 0; i < v->u.array.len; i++)
|
||||
{
|
||||
yajl_tree_free (v->u.array.values[i]);
|
||||
v->u.array.values[i] = NULL;
|
||||
}
|
||||
|
||||
free(v->u.array.values);
|
||||
free(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing nested objects and arrays is implemented using a stack. When a new
|
||||
* object or array starts (a curly or a square opening bracket is read), an
|
||||
* appropriate value is pushed on the stack. When the end of the object is
|
||||
* reached (an appropriate closing bracket has been read), the value is popped
|
||||
* off the stack and added to the enclosing object using "context_add_value".
|
||||
*/
|
||||
static int context_push(context_t *ctx, yajl_val v)
|
||||
{
|
||||
stack_elem_t *stack;
|
||||
|
||||
stack = malloc (sizeof (*stack));
|
||||
if (stack == NULL)
|
||||
RETURN_ERROR (ctx, ENOMEM, "Out of memory");
|
||||
memset (stack, 0, sizeof (*stack));
|
||||
|
||||
assert ((ctx->stack == NULL)
|
||||
|| YAJL_IS_OBJECT (v)
|
||||
|| YAJL_IS_ARRAY (v));
|
||||
|
||||
stack->value = v;
|
||||
stack->next = ctx->stack;
|
||||
ctx->stack = stack;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static yajl_val context_pop(context_t *ctx)
|
||||
{
|
||||
stack_elem_t *stack;
|
||||
yajl_val v;
|
||||
|
||||
if (ctx->stack == NULL)
|
||||
RETURN_ERROR (ctx, NULL, "context_pop: "
|
||||
"Bottom of stack reached prematurely");
|
||||
|
||||
stack = ctx->stack;
|
||||
ctx->stack = stack->next;
|
||||
|
||||
v = stack->value;
|
||||
|
||||
free (stack);
|
||||
|
||||
return (v);
|
||||
}
|
||||
|
||||
static int object_add_keyval(context_t *ctx,
|
||||
yajl_val obj, char *key, yajl_val value)
|
||||
{
|
||||
const char **tmpk;
|
||||
yajl_val *tmpv;
|
||||
|
||||
/* We're checking for NULL in "context_add_value" or its callers. */
|
||||
assert (ctx != NULL);
|
||||
assert (obj != NULL);
|
||||
assert (key != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
/* We're assuring that "obj" is an object in "context_add_value". */
|
||||
assert(YAJL_IS_OBJECT(obj));
|
||||
|
||||
tmpk = realloc((void *) obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1));
|
||||
if (tmpk == NULL)
|
||||
RETURN_ERROR(ctx, ENOMEM, "Out of memory");
|
||||
obj->u.object.keys = tmpk;
|
||||
|
||||
tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1));
|
||||
if (tmpv == NULL)
|
||||
RETURN_ERROR(ctx, ENOMEM, "Out of memory");
|
||||
obj->u.object.values = tmpv;
|
||||
|
||||
obj->u.object.keys[obj->u.object.len] = key;
|
||||
obj->u.object.values[obj->u.object.len] = value;
|
||||
obj->u.object.len++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int array_add_value (context_t *ctx,
|
||||
yajl_val array, yajl_val value)
|
||||
{
|
||||
yajl_val *tmp;
|
||||
|
||||
/* We're checking for NULL pointers in "context_add_value" or its
|
||||
* callers. */
|
||||
assert (ctx != NULL);
|
||||
assert (array != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
/* "context_add_value" will only call us with array values. */
|
||||
assert(YAJL_IS_ARRAY(array));
|
||||
|
||||
tmp = realloc(array->u.array.values,
|
||||
sizeof(*(array->u.array.values)) * (array->u.array.len + 1));
|
||||
if (tmp == NULL)
|
||||
RETURN_ERROR(ctx, ENOMEM, "Out of memory");
|
||||
array->u.array.values = tmp;
|
||||
array->u.array.values[array->u.array.len] = value;
|
||||
array->u.array.len++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a value to the value on top of the stack or the "root" member in the
|
||||
* context if the end of the parsing process is reached.
|
||||
*/
|
||||
static int context_add_value (context_t *ctx, yajl_val v)
|
||||
{
|
||||
/* We're checking for NULL values in all the calling functions. */
|
||||
assert (ctx != NULL);
|
||||
assert (v != NULL);
|
||||
|
||||
/*
|
||||
* There are three valid states in which this function may be called:
|
||||
* - There is no value on the stack => This is the only value. This is the
|
||||
* last step done when parsing a document. We assign the value to the
|
||||
* "root" member and return.
|
||||
* - The value on the stack is an object. In this case store the key on the
|
||||
* stack or, if the key has already been read, add key and value to the
|
||||
* object.
|
||||
* - The value on the stack is an array. In this case simply add the value
|
||||
* and return.
|
||||
*/
|
||||
if (ctx->stack == NULL)
|
||||
{
|
||||
assert (ctx->root == NULL);
|
||||
ctx->root = v;
|
||||
return (0);
|
||||
}
|
||||
else if (YAJL_IS_OBJECT (ctx->stack->value))
|
||||
{
|
||||
if (ctx->stack->key == NULL)
|
||||
{
|
||||
if (!YAJL_IS_STRING (v))
|
||||
RETURN_ERROR (ctx, EINVAL, "context_add_value: "
|
||||
"Object key is not a string (%#04x)",
|
||||
v->type);
|
||||
|
||||
ctx->stack->key = v->u.string;
|
||||
v->u.string = NULL;
|
||||
free(v);
|
||||
return (0);
|
||||
}
|
||||
else /* if (ctx->key != NULL) */
|
||||
{
|
||||
char * key;
|
||||
|
||||
key = ctx->stack->key;
|
||||
ctx->stack->key = NULL;
|
||||
return (object_add_keyval (ctx, ctx->stack->value, key, v));
|
||||
}
|
||||
}
|
||||
else if (YAJL_IS_ARRAY (ctx->stack->value))
|
||||
{
|
||||
return (array_add_value (ctx, ctx->stack->value, v));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_ERROR (ctx, EINVAL, "context_add_value: Cannot add value to "
|
||||
"a value of type %#04x (not a composite type)",
|
||||
ctx->stack->value->type);
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_string (void *ctx,
|
||||
const unsigned char *string, size_t string_length)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc (yajl_t_string);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.string = malloc (string_length + 1);
|
||||
if (v->u.string == NULL)
|
||||
{
|
||||
free (v);
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
}
|
||||
memcpy(v->u.string, string, string_length);
|
||||
v->u.string[string_length] = 0;
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_number (void *ctx, const char *string, size_t string_length)
|
||||
{
|
||||
yajl_val v;
|
||||
char *endptr;
|
||||
|
||||
v = value_alloc(yajl_t_number);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.number.r = malloc(string_length + 1);
|
||||
if (v->u.number.r == NULL)
|
||||
{
|
||||
free(v);
|
||||
RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
}
|
||||
memcpy(v->u.number.r, string, string_length);
|
||||
v->u.number.r[string_length] = 0;
|
||||
|
||||
v->u.number.flags = 0;
|
||||
|
||||
endptr = NULL;
|
||||
errno = 0;
|
||||
v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r,
|
||||
strlen(v->u.number.r));
|
||||
if ((errno == 0) && (endptr != NULL) && (*endptr == 0))
|
||||
v->u.number.flags |= YAJL_NUMBER_INT_VALID;
|
||||
|
||||
endptr = NULL;
|
||||
errno = 0;
|
||||
v->u.number.d = strtod(v->u.number.r, &endptr);
|
||||
if ((errno == 0) && (endptr != NULL) && (*endptr == 0))
|
||||
v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID;
|
||||
|
||||
return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_start_map (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc(yajl_t_object);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.object.keys = NULL;
|
||||
v->u.object.values = NULL;
|
||||
v->u.object.len = 0;
|
||||
|
||||
return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_end_map (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = context_pop (ctx);
|
||||
if (v == NULL)
|
||||
return (STATUS_ABORT);
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_start_array (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc(yajl_t_array);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.array.values = NULL;
|
||||
v->u.array.len = 0;
|
||||
|
||||
return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_end_array (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = context_pop (ctx);
|
||||
if (v == NULL)
|
||||
return (STATUS_ABORT);
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_boolean (void *ctx, int boolean_value)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc (boolean_value ? yajl_t_true : yajl_t_false);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_null (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc (yajl_t_null);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
yajl_val yajl_tree_parse (const char *input,
|
||||
char *error_buffer, size_t error_buffer_size)
|
||||
{
|
||||
static const yajl_callbacks callbacks =
|
||||
{
|
||||
/* null = */ handle_null,
|
||||
/* boolean = */ handle_boolean,
|
||||
/* integer = */ NULL,
|
||||
/* double = */ NULL,
|
||||
/* number = */ handle_number,
|
||||
/* string = */ handle_string,
|
||||
/* start map = */ handle_start_map,
|
||||
/* map key = */ handle_string,
|
||||
/* end map = */ handle_end_map,
|
||||
/* start array = */ handle_start_array,
|
||||
/* end array = */ handle_end_array
|
||||
};
|
||||
|
||||
yajl_handle handle;
|
||||
yajl_status status;
|
||||
context_t ctx = { NULL, NULL, NULL, 0 };
|
||||
|
||||
ctx.errbuf = error_buffer;
|
||||
ctx.errbuf_size = error_buffer_size;
|
||||
|
||||
if (error_buffer != NULL)
|
||||
memset (error_buffer, 0, error_buffer_size);
|
||||
|
||||
handle = yajl_alloc (&callbacks, NULL, &ctx);
|
||||
yajl_config(handle, yajl_allow_comments, 1);
|
||||
|
||||
status = yajl_parse(handle,
|
||||
(unsigned char *) input,
|
||||
strlen (input));
|
||||
status = yajl_complete_parse (handle);
|
||||
if (status != yajl_status_ok) {
|
||||
if (error_buffer != NULL && error_buffer_size > 0) {
|
||||
snprintf(
|
||||
error_buffer, error_buffer_size, "%s",
|
||||
(char *) yajl_get_error(handle, 1,
|
||||
(const unsigned char *) input,
|
||||
strlen(input)));
|
||||
}
|
||||
yajl_free (handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
yajl_free (handle);
|
||||
return (ctx.root);
|
||||
}
|
||||
|
||||
yajl_val yajl_tree_get(yajl_val n, const char ** path, yajl_type type)
|
||||
{
|
||||
if (!path) return NULL;
|
||||
while (n && *path) {
|
||||
unsigned int i;
|
||||
|
||||
if (n->type != yajl_t_object) return NULL;
|
||||
for (i = 0; i < n->u.object.len; i++) {
|
||||
if (!strcmp(*path, n->u.object.keys[i])) {
|
||||
n = n->u.object.values[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == n->u.object.len) return NULL;
|
||||
path++;
|
||||
}
|
||||
if (n && type != yajl_t_any && type != n->type) n = NULL;
|
||||
return n;
|
||||
}
|
||||
|
||||
void yajl_tree_free (yajl_val v)
|
||||
{
|
||||
if (v == NULL) return;
|
||||
|
||||
if (YAJL_IS_STRING(v))
|
||||
{
|
||||
free(v->u.string);
|
||||
free(v);
|
||||
}
|
||||
else if (YAJL_IS_NUMBER(v))
|
||||
{
|
||||
free(v->u.number.r);
|
||||
free(v);
|
||||
}
|
||||
else if (YAJL_GET_OBJECT(v))
|
||||
{
|
||||
yajl_object_free(v);
|
||||
}
|
||||
else if (YAJL_GET_ARRAY(v))
|
||||
{
|
||||
yajl_array_free(v);
|
||||
}
|
||||
else /* if (yajl_t_true or yajl_t_false or yajl_t_null) */
|
||||
{
|
||||
free(v);
|
||||
}
|
||||
}
|
7
thirdparty/yajl/src/yajl_version.c
vendored
7
thirdparty/yajl/src/yajl_version.c
vendored
@ -1,7 +0,0 @@
|
||||
#include <yajl/yajl_version.h>
|
||||
|
||||
int yajl_version(void)
|
||||
{
|
||||
return YAJL_VERSION;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user