http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/stream.zh-cn.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/stream.zh-cn.md 
b/thirdparty/rapidjson-1.1.0/doc/stream.zh-cn.md
new file mode 100644
index 0000000..f2c54f7
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/stream.zh-cn.md
@@ -0,0 +1,426 @@
+# 流
+
+在 RapidJSON 中,`rapidjson::Stream` 是用於读写 JSON 
的概念(概念是指 C++ 的 concept)。在这里我们å…
ˆä»‹ç»å¦‚何使用 RapidJSON 
提供的各种流。然后再看看如何自行定义流。
+
+[TOC]
+
+# 内存流 {#MemoryStreams}
+
+内存流把 JSON 存储在内存之中。
+
+## StringStream(输入){#StringStream}
+
+`StringStream` 是最基本的输å…
¥æµï¼Œå®ƒè¡¨ç¤ºä¸€ä¸ªå®Œæ•´çš„、只读的、存储于内存的 JSON。它在 
`rapidjson/rapidjson.h` 中定义。
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h" // 会包含 "rapidjson/rapidjson.h"
+
+using namespace rapidjson;
+
+// ...
+const char json[] = "[1, 2, 3, 4]";
+StringStream s(json);
+
+Document d;
+d.ParseStream(s);
+~~~~~~~~~~
+
+由于这是非常常用的用法,RapidJSON 提供 `Document::Parse(const 
char*)` 去做完全相同的事情:
+
+~~~~~~~~~~cpp
+// ...
+const char json[] = "[1, 2, 3, 4]";
+Document d;
+d.Parse(json);
+~~~~~~~~~~
+
+需要注意,`StringStream` 是 `GenericStringStream<UTF8<> >` 的 
typedef,使用者可用其他编码类去代表流所使用的字符集。
+
+## StringBuffer(输出){#StringBuffer}
+
+`StringBuffer` 是一个简单的输出流。它分配一个内
存缓冲区,供写入整个 JSON。可使用 `GetString()` 
来获取该缓冲区。
+
+~~~~~~~~~~cpp
+#include "rapidjson/stringbuffer.h"
+
+StringBuffer buffer;
+Writer<StringBuffer> writer(buffer);
+d.Accept(writer);
+
+const char* output = buffer.GetString();
+~~~~~~~~~~
+
+当缓冲区满溢,它将自动增加容量。缺省容量是 256 
个字符(UTF8 是 256 字节,UTF16 是 512 字节等)。使用者
能自行提供分配器及初始容量。
+
+~~~~~~~~~~cpp
+StringBuffer buffer1(0, 1024); // 使用它的分配器,初始大小 = 1024
+StringBuffer buffer2(allocator, 1024);
+~~~~~~~~~~
+
+如无设置分配器,`StringBuffer` 会自行实例化一个内部分é…
å™¨ã€‚
+
+相似地,`StringBuffer` 是 `GenericStringBuffer<UTF8<> >` 的 typedef。
+
+# 文件流 {#FileStreams}
+
+当要从文件解析一个 JSON,你可以把整个 JSON 读入内
存并使用上述的 `StringStream`。
+
+然而,若 JSON 很大,或是内存有限,你可以改用 
`FileReadStream`。它只会从文件读取一部分至缓冲区,然后让那部分被解析。若缓冲区的字符都被读完,它会再从文件读取下一部分。
+
+## FileReadStream(输入) {#FileReadStream}
+
+`FileReadStream` 通过 `FILE` 指针读取文件。使用者
需要提供一个缓冲区。
+
+~~~~~~~~~~cpp
+#include "rapidjson/filereadstream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("big.json", "rb"); // 非 Windows 平台使用 "r"
+
+char readBuffer[65536];
+FileReadStream is(fp, readBuffer, sizeof(readBuffer));
+
+Document d;
+d.ParseStream(is);
+
+fclose(fp);
+~~~~~~~~~~
+
+与 `StringStreams` 不一样,`FileReadStream` 
是一个字节流。它不处理编码。若文件并非 UTF-8 编ç 
ï¼Œå¯ä»¥æŠŠå­—节流用 `EncodedInputStream` 包装
。我们很快会讨论这个问题。
+
+除了读取文件,使用者也可以使用 `FileReadStream` 来读取 
`stdin`。
+
+## FileWriteStream(输出){#FileWriteStream}
+
+`FileWriteStream` 是一个含缓冲功能的输出流。它的用法与 
`FileReadStream` 非常相似。
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+Document d;
+d.Parse(json);
+// ...
+
+FILE* fp = fopen("output.json", "wb"); // 非 Windows 平台使用 "w"
+
+char writeBuffer[65536];
+FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
+
+Writer<FileWriteStream> writer(os);
+d.Accept(writer);
+
+fclose(fp);
+~~~~~~~~~~
+
+它也可以把输出导向 `stdout`。
+
+# iostream 包装类 {#iostreamWrapper}
+
+基于用户的要求,RapidJSON 提供了正式的 `std::basic_istream` 和 
`std::basic_ostream` 包装类。然而,请注意å…
¶æ€§èƒ½ä¼šå¤§å¤§ä½ŽäºŽä»¥ä¸Šçš„其他流。
+
+## IStreamWrapper {#IStreamWrapper}
+
+`IStreamWrapper` 把任何继承自 `std::istream` 的类(如 
`std::istringstream`、`std::stringstream`、`std::ifstream`、`std::fstream`)åŒ
…装成 RapidJSON 的输入流。
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/istreamwrapper.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+ifstream ifs("test.json");
+IStreamWrapper isw(ifs);
+
+Document d;
+d.ParseStream(isw);
+~~~
+
+对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。
+
+## OStreamWrapper {#OStreamWrapper}
+
+相似地,`OStreamWrapper` 把任何继承自 `std::ostream` 的类(如 
`std::ostringstream`、`std::stringstream`、`std::ofstream`、`std::fstream`)åŒ
…装成 RapidJSON 的输出流。
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/ostreamwrapper.h>
+#include <rapidjson/writer.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+Document d;
+d.Parse(json);
+
+// ...
+
+ofstream ofs("output.json");
+OStreamWrapper osw(ofs);
+
+Writer<OStreamWrapper> writer(osw);
+d.Accept(writer);
+~~~
+
+对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。
+
+# 编码流 {#EncodedStreams}
+
+编码流(encoded streams)本身不存储 JSON,它们是通过包装
字节流来提供基本的编码/解码功能。
+
+如上所述,我们可以直接读入 UTF-8 字节流。然而,UTF-16 及 
UTF-32 
有字节序(endian)问题。要正确地处理字节序,需要在读取时把字节转换成字符(如对
 UTF-16 使用 `wchar_t`),以及在写入时把字符转换为字节。
+
+除此以外,我们也需要处理 [字节顺序标记(byte order mark, 
BOM)](http://en.wikipedia.org/wiki/Byte_order_mark)。当从一个字节流读取时,需要检测
 BOM,或者仅仅是把存在的 BOM 消去。当把 JSON 写å…
¥å­—节流时,也可选择写入 BOM。
+
+若一个流的编码在编译期已知,你可使用 `EncodedInputStream` 
及 `EncodedOutputStream`。若一个流可能存储 
UTF-8、UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BE 的 JSON,并且编ç 
åªèƒ½åœ¨è¿è¡Œæ—¶å¾—知,你便可以使用 `AutoUTFInputStream` 及 
`AutoUTFOutputStream`。这些流定义在 `rapidjson/encodedstream.h`。
+
+注意到,这些编码流可以施于文件以外的流。例如,你
可以用编码流包装内存中的文件或自定义的字节流。
+
+## EncodedInputStream {#EncodedInputStream}
+
+`EncodedInputStream` 含两个模板参数。第一个是 `Encoding` 
类型,例如定义于 `rapidjson/encodings.h` 的 
`UTF8`、`UTF16LE`。第二个参数是被包装的流的类型。
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h"   // FileReadStream
+#include "rapidjson/encodedstream.h"    // EncodedInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("utf16le.json", "rb"); // 非 Windows 平台使用 "r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+EncodedInputStream<UTF16LE<>, FileReadStream> eis(bis);  // 用 eis 包装 bis
+
+Document d; // Document 为 GenericDocument<UTF8<> > 
+d.ParseStream<0, UTF16LE<> >(eis);  // 把 UTF-16LE 文件解析至内
存中的 UTF-8
+
+fclose(fp);
+~~~~~~~~~~
+
+## EncodedOutputStream {#EncodedOutputStream}
+
+`EncodedOutputStream` 也是相似的,但它的构造函数有一个 `bool 
putBOM` 参数,用于控制是否在输出字节流写入 BOM。
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h"  // FileWriteStream
+#include "rapidjson/encodedstream.h"    // EncodedOutputStream
+#include <cstdio>
+
+Document d;         // Document 为 GenericDocument<UTF8<> > 
+// ...
+
+FILE* fp = fopen("output_utf32le.json", "wb"); // 非 Windows 平台使用 "w"
+
+char writeBuffer[256];
+FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
+OutputStream eos(bos, true);   // 写入 BOM
+
+Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+d.Accept(writer);   // 这里从内存的 UTF-8 生成 UTF32-LE 文件
+
+fclose(fp);
+~~~~~~~~~~
+
+## AutoUTFInputStream {#AutoUTFInputStream}
+
+有时候,应用软件可能需要㲃理所有可支持的 JSON 编ç 
ã€‚`AutoUTFInputStream` 会先使用 BOM 来检测编码。若 BOM 
不存在,它便会使用合法 JSON 
的特性来检测。若两种方法都失败,它就会倒退至构造
函数提供的 UTF 类型。
+
+由于字符(编码单元/code unit)可能是 8 位、16 位或 32 
位,`AutoUTFInputStream` 需要一个能至少储存 32 
位的字符类型。我们可以使用 `unsigned` 作为模板参数:
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h"   // FileReadStream
+#include "rapidjson/encodedstream.h"    // AutoUTFInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("any.json", "rb"); // 非 Windows 平台使用 "r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+AutoUTFInputStream<unsigned, FileReadStream> eis(bis);  // 用 eis 包装 bis
+
+Document d;         // Document 为 GenericDocument<UTF8<> > 
+d.ParseStream<0, AutoUTF<unsigned> >(eis); // 把任何 UTF 编ç 
çš„文件解析至内存中的 UTF-8
+
+fclose(fp);
+~~~~~~~~~~
+
+当要指定流的编码,可使用上面例子中 `ParseStream()` 的参数 
`AutoUTF<CharType>`。
+
+你可以使用 `UTFType GetType()` 去获取 UTF 类型,并且用 
`HasBOM()` 检测输入流是否含有 BOM。
+
+## AutoUTFOutputStream {#AutoUTFOutputStream}
+
+相似地,要在运行时选择输出的编码,我们可使用 
`AutoUTFOutputStream`。这个类本身并非「自动」。你
需要在运行时指定 UTF 类型,以及是否写入 BOM。
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) {
+    char writeBuffer[256];
+    FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+    typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream;
+    OutputStream eos(bos, type, putBOM);
+    
+    Writer<OutputStream, UTF8<>, AutoUTF<> > writer;
+    d.Accept(writer);
+}
+~~~~~~~~~~
+
+`AutoUTFInputStream`/`AutoUTFOutputStream` 是比 
`EncodedInputStream`/`EncodedOutputStream` 方便。但前者
会产生一点运行期额外开销。
+
+# 自定义流 {#CustomStream}
+
+除了内存/文件流,使用者可创建自行定义适配 RapidJSON API 
的流类。例如,你
可以创建网络流、从压缩文件读取的流等等。
+
+RapidJSON 利用模板结合不同的类型。只要一个类包
含所有所需的接口,就可以作为一个流。流的接合定义在 
`rapidjson/rapidjson.h` 的注释里:
+
+~~~~~~~~~~cpp
+concept Stream {
+    typename Ch;    //!< 流的字符类型
+
+    //! 从流读取当前字符,不移动读取指针(read cursor)
+    Ch Peek() const;
+
+    //! 从流读取当前字符,移动读取指针至下一字符。
+    Ch Take();
+
+    //! 获取读取指针。
+    //! \return 从开始以来所读过的字符数量。
+    size_t Tell();
+
+    //! 从当前读取指针开始写入操作。
+    //! \return 返回开始写入的指针。
+    Ch* PutBegin();
+
+    //! 写入一个字符。
+    void Put(Ch c);
+
+    //! 清空缓冲区。
+    void Flush();
+
+    //! 完成写作操作。
+    //! \param begin PutBegin() 返回的开始写入指针。
+    //! \return 已写入的字符数量。
+    size_t PutEnd(Ch* begin);
+}
+~~~~~~~~~~
+
+输入流必须实现 `Peek()`、`Take()` 及 `Tell()`。
+输出流必须实现 `Put()` 及 `Flush()`。
+`PutBegin()` 及 `PutEnd()` 是特殊的接口,仅用于原位(*in 
situ*)解析。一般的流不需实现它们。然而,即使接口不需用于某些流,仍然需要提供空实现,否则会产生编译错误。
+
+## 例子:istream 的包装类 {#ExampleIStreamWrapper}
+
+以下的简单例子是 `std::istream` 的包装类,它只需现 3 
个函数。
+
+~~~~~~~~~~cpp
+class MyIStreamWrapper {
+public:
+    typedef char Ch;
+
+    MyIStreamWrapper(std::istream& is) : is_(is) {
+    }
+
+    Ch Peek() const { // 1
+        int c = is_.peek();
+        return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+    }
+
+    Ch Take() { // 2
+        int c = is_.get();
+        return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+    }
+
+    size_t Tell() const { return (size_t)is_.tellg(); } // 3
+
+    Ch* PutBegin() { assert(false); return 0; }
+    void Put(Ch) { assert(false); }
+    void Flush() { assert(false); }
+    size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+    MyIStreamWrapper(const MyIStreamWrapper&);
+    MyIStreamWrapper& operator=(const MyIStreamWrapper&);
+
+    std::istream& is_;
+};
+~~~~~~~~~~
+
+使用者能用它来包装 `std::stringstream`、`std::ifstream` 的实例。
+
+~~~~~~~~~~cpp
+const char* json = "[1,2,3,4]";
+std::stringstream ss(json);
+MyIStreamWrapper is(ss);
+
+Document d;
+d.ParseStream(is);
+~~~~~~~~~~
+
+但要注意,由于标准库的内
部开销问,此实现的性能可能不如 RapidJSON 的内存/文件流。
+
+## 例子:ostream 的包装类 {#ExampleOStreamWrapper}
+
+以下的例子是 `std::istream` 的包装类,它只需实现 2 个函数。
+
+~~~~~~~~~~cpp
+class MyOStreamWrapper {
+public:
+    typedef char Ch;
+
+    OStreamWrapper(std::ostream& os) : os_(os) {
+    }
+
+    Ch Peek() const { assert(false); return '\0'; }
+    Ch Take() { assert(false); return '\0'; }
+    size_t Tell() const {  }
+
+    Ch* PutBegin() { assert(false); return 0; }
+    void Put(Ch c) { os_.put(c); }                  // 1
+    void Flush() { os_.flush(); }                   // 2
+    size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+    MyOStreamWrapper(const MyOStreamWrapper&);
+    MyOStreamWrapper& operator=(const MyOStreamWrapper&);
+
+    std::ostream& os_;
+};
+~~~~~~~~~~
+
+使用者能用它来包装 `std::stringstream`、`std::ofstream` 的实例。
+
+~~~~~~~~~~cpp
+Document d;
+// ...
+
+std::stringstream ss;
+MyOStreamWrapper os(ss);
+
+Writer<MyOStreamWrapper> writer(os);
+d.Accept(writer);
+~~~~~~~~~~
+
+但要注意,由于标准库的内
部开销问,此实现的性能可能不如 RapidJSON 的内存/文件流。
+
+# 总结 {#Summary}
+
+本节描述了 RapidJSON 提供的各种流的类。内存流很简单。若 
JSON 存储在文件中,文件流可减少 JSON 解析及生成所需的内
存量。编码流在字节流和字符流之间作转换。最后,使用者
可使用一个简单接口创建自定义的流。

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/tutorial.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/tutorial.md 
b/thirdparty/rapidjson-1.1.0/doc/tutorial.md
new file mode 100644
index 0000000..cb76b4b
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/tutorial.md
@@ -0,0 +1,536 @@
+# Tutorial
+
+This tutorial introduces the basics of the Document Object Model(DOM) API.
+
+As shown in [Usage at a glance](@ref index), a JSON can be parsed into DOM, 
and then the DOM can be queried and modified easily, and finally be converted 
back to JSON.
+
+[TOC]
+
+# Value & Document {#ValueDocument}
+
+Each JSON value is stored in a type called `Value`. A `Document`, representing 
the DOM, contains the root `Value` of the DOM tree. All public types and 
functions of RapidJSON are defined in the `rapidjson` namespace.
+
+# Query Value {#QueryValue}
+
+In this section, we will use excerpt of `example/tutorial/tutorial.cpp`.
+
+Assumes we have a JSON stored in a C string (`const char* json`):
+~~~~~~~~~~js
+{
+    "hello": "world",
+    "t": true ,
+    "f": false,
+    "n": null,
+    "i": 123,
+    "pi": 3.1416,
+    "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+Parse it into a `Document`:
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+
+using namespace rapidjson;
+
+// ...
+Document document;
+document.Parse(json);
+~~~~~~~~~~
+
+The JSON is now parsed into `document` as a *DOM tree*:
+
+![DOM in the tutorial](diagram/tutorial.png)
+
+Since the update to RFC 7159, the root of a conforming JSON document can be 
any JSON value.  In earlier RFC 4627, only objects or arrays were allowed as 
root values. In this case, the root is an object.
+~~~~~~~~~~cpp
+assert(document.IsObject());
+~~~~~~~~~~
+
+Let's query whether a `"hello"` member exists in the root object. Since a 
`Value` can contain different types of value, we may need to verify its type 
and use suitable API to obtain the value. In this example, `"hello"` member 
associates with a JSON string.
+~~~~~~~~~~cpp
+assert(document.HasMember("hello"));
+assert(document["hello"].IsString());
+printf("hello = %s\n", document["hello"].GetString());
+~~~~~~~~~~
+
+~~~~~~~~~~
+world
+~~~~~~~~~~
+
+JSON true/false values are represented as `bool`.
+~~~~~~~~~~cpp
+assert(document["t"].IsBool());
+printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
+~~~~~~~~~~
+
+~~~~~~~~~~
+true
+~~~~~~~~~~
+
+JSON null can be queryed by `IsNull()`.
+~~~~~~~~~~cpp
+printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
+~~~~~~~~~~
+
+~~~~~~~~~~
+null
+~~~~~~~~~~
+
+JSON number type represents all numeric values. However, C++ needs more 
specific type for manipulation.
+
+~~~~~~~~~~cpp
+assert(document["i"].IsNumber());
+
+// In this case, IsUint()/IsInt64()/IsUInt64() also return true.
+assert(document["i"].IsInt());          
+printf("i = %d\n", document["i"].GetInt());
+// Alternative (int)document["i"]
+
+assert(document["pi"].IsNumber());
+assert(document["pi"].IsDouble());
+printf("pi = %g\n", document["pi"].GetDouble());
+~~~~~~~~~~
+
+~~~~~~~~~~
+i = 123
+pi = 3.1416
+~~~~~~~~~~
+
+JSON array contains a number of elements.
+~~~~~~~~~~cpp
+// Using a reference for consecutive access is handy and faster.
+const Value& a = document["a"];
+assert(a.IsArray());
+for (SizeType i = 0; i < a.Size(); i++) // Uses SizeType instead of size_t
+        printf("a[%d] = %d\n", i, a[i].GetInt());
+~~~~~~~~~~
+
+~~~~~~~~~~
+a[0] = 1
+a[1] = 2
+a[2] = 3
+a[3] = 4
+~~~~~~~~~~
+
+Note that, RapidJSON does not automatically convert values between JSON types. 
If a value is a string, it is invalid to call `GetInt()`, for example. In debug 
mode it will fail an assertion. In release mode, the behavior is undefined.
+
+In the following, details about querying individual types are discussed.
+
+## Query Array {#QueryArray}
+
+By default, `SizeType` is typedef of `unsigned`. In most systems, array is 
limited to store up to 2^32-1 elements.
+
+You may access the elements in array by integer literal, for example, `a[0]`, 
`a[1]`, `a[2]`.
+
+Array is similar to `std::vector`, instead of using indices, you may also use 
iterator to access all the elements.
+~~~~~~~~~~cpp
+for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+    printf("%d ", itr->GetInt());
+~~~~~~~~~~
+
+And other familiar query functions:
+* `SizeType Capacity() const`
+* `bool Empty() const`
+
+### Range-based For Loop (New in v1.1.0)
+
+When C++11 is enabled, you can use range-based for loop to access all elements 
in an array.
+
+~~~~~~~~~~cpp
+for (auto& v : a.GetArray())
+    printf("%d ", v.GetInt());
+~~~~~~~~~~
+
+## Query Object {#QueryObject}
+
+Similar to array, we can access all object members by iterator:
+
+~~~~~~~~~~cpp
+static const char* kTypeNames[] = 
+    { "Null", "False", "True", "Object", "Array", "String", "Number" };
+
+for (Value::ConstMemberIterator itr = document.MemberBegin();
+    itr != document.MemberEnd(); ++itr)
+{
+    printf("Type of member %s is %s\n",
+        itr->name.GetString(), kTypeNames[itr->value.GetType()]);
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+Type of member hello is String
+Type of member t is True
+Type of member f is False
+Type of member n is Null
+Type of member i is Number
+Type of member pi is Number
+Type of member a is Array
+~~~~~~~~~~
+
+Note that, when `operator[](const char*)` cannot find the member, it will fail 
an assertion.
+
+If we are unsure whether a member exists, we need to call `HasMember()` before 
calling `operator[](const char*)`. However, this incurs two lookup. A better 
way is to call `FindMember()`, which can check the existence of member and 
obtain its value at once:
+
+~~~~~~~~~~cpp
+Value::ConstMemberIterator itr = document.FindMember("hello");
+if (itr != document.MemberEnd())
+    printf("%s\n", itr->value.GetString());
+~~~~~~~~~~
+
+### Range-based For Loop (New in v1.1.0)
+
+When C++11 is enabled, you can use range-based for loop to access all members 
in an object.
+
+~~~~~~~~~~cpp
+for (auto& m : document.GetObject())
+    printf("Type of member %s is %s\n",
+        m.name.GetString(), kTypeNames[m.value.GetType()]);
+~~~~~~~~~~
+
+## Querying Number {#QueryNumber}
+
+JSON provide a single numerical type called Number. Number can be integer or 
real numbers. RFC 4627 says the range of Number is specified by parser.
+
+As C++ provides several integer and floating point number types, the DOM tries 
to handle these with widest possible range and good performance.
+
+When a Number is parsed, it is stored in the DOM as either one of the 
following type:
+
+Type       | Description
+-----------|---------------------------------------
+`unsigned` | 32-bit unsigned integer
+`int`      | 32-bit signed integer
+`uint64_t` | 64-bit unsigned integer
+`int64_t`  | 64-bit signed integer
+`double`   | 64-bit double precision floating point
+
+When querying a number, you can check whether the number can be obtained as 
target type:
+
+Checking          | Obtaining
+------------------|---------------------
+`bool IsNumber()` | N/A
+`bool IsUint()`   | `unsigned GetUint()`
+`bool IsInt()`    | `int GetInt()`
+`bool IsUint64()` | `uint64_t GetUint64()`
+`bool IsInt64()`  | `int64_t GetInt64()`
+`bool IsDouble()` | `double GetDouble()`
+
+Note that, an integer value may be obtained in various ways without 
conversion. For example, A value `x` containing 123 will make `x.IsInt() == 
x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing 
-3000000000 will only makes `x.IsInt64() == true`.
+
+When obtaining the numeric values, `GetDouble()` will convert internal integer 
representation to a `double`. Note that, `int` and `unsigned` can be safely 
convert to `double`, but `int64_t` and `uint64_t` may lose precision (since 
mantissa of `double` is only 52-bits).
+
+## Query String {#QueryString}
+
+In addition to `GetString()`, the `Value` class also contains 
`GetStringLength()`. Here explains why.
+
+According to RFC 4627, JSON strings can contain Unicode character `U+0000`, 
which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses 
null-terminated string, which treats ``\0'` as the terminator symbol.
+
+To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you 
need to handle this, you can use `GetStringLength()` API to obtain the correct 
length of string.
+
+For example, after parsing a the following JSON to `Document d`:
+
+~~~~~~~~~~js
+{ "s" :  "a\u0000b" }
+~~~~~~~~~~
+The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
+
+`GetStringLength()` can also improve performance, as user may often need to 
call `strlen()` for allocating buffer.
+
+Besides, `std::string` also support a constructor:
+
+~~~~~~~~~~cpp
+string(const char* s, size_t count);
+~~~~~~~~~~
+
+which accepts the length of string as parameter. This constructor supports 
storing null character within the string, and should also provide better 
performance.
+
+## Comparing values
+
+You can use `==` and `!=` to compare values. Two values are equal if and only 
if they are have same type and contents. You can also compare values with 
primitive types. Here is an example.
+
+~~~~~~~~~~cpp
+if (document["hello"] == document["n"]) /*...*/;    // Compare values
+if (document["hello"] == "world") /*...*/;          // Compare value with 
literal string
+if (document["i"] != 123) /*...*/;                  // Compare with integers
+if (document["pi"] != 3.14) /*...*/;                // Compare with double.
+~~~~~~~~~~
+
+Array/object compares their elements/members in order. They are equal if and 
only if their whole subtrees are equal.
+
+Note that, currently if an object contains duplicated named member, comparing 
equality with any object is always `false`.
+
+# Create/Modify Values {#CreateModifyValues}
+
+There are several ways to create values. After a DOM tree is created and/or 
modified, it can be saved as JSON again using `Writer`.
+
+## Change Value Type {#ChangeValueType}
+When creating a Value or Document by default constructor, its type is Null. To 
change its type, call `SetXXX()` or assignment operator, for example:
+
+~~~~~~~~~~cpp
+Document d; // Null
+d.SetObject();
+
+Value v;    // Null
+v.SetInt(10);
+v = 10;     // Shortcut, same as above
+~~~~~~~~~~
+
+### Overloaded Constructors
+There are also overloaded constructors for several types:
+
+~~~~~~~~~~cpp
+Value b(true);    // calls Value(bool)
+Value i(-123);    // calls Value(int)
+Value u(123u);    // calls Value(unsigned)
+Value d(1.5);     // calls Value(double)
+~~~~~~~~~~
+
+To create empty object or array, you may use `SetObject()`/`SetArray()` after 
default constructor, or using the `Value(Type)` in one shot:
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+Value a(kArrayType);
+~~~~~~~~~~
+
+## Move Semantics {#MoveSemantics}
+
+A very special decision during design of RapidJSON is that, assignment of 
value does not copy the source value to destination value. Instead, the value 
from source is moved to the destination. For example,
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b(456);
+b = a;         // a becomes a Null value, b becomes number 123.
+~~~~~~~~~~
+
+![Assignment with move semantics.](diagram/move1.png)
+
+Why? What is the advantage of this semantics?
+
+The simple answer is performance. For fixed size JSON types (Number, True, 
False, Null), copying them is fast and easy. However, For variable size JSON 
types (String, Array, Object), copying them will incur a lot of overheads. And 
these overheads are often unnoticed. Especially when we need to create 
temporary object, copy it to another variable, and then destruct it.
+
+For example, if normal *copy* semantics was used:
+
+~~~~~~~~~~cpp
+Document d;
+Value o(kObjectType);
+{
+    Value contacts(kArrayType);
+    // adding elements to contacts array.
+    // ...
+    o.AddMember("contacts", contacts, d.GetAllocator());  // deep clone 
contacts (may be with lots of allocations)
+    // destruct contacts.
+}
+~~~~~~~~~~
+
+![Copy semantics makes a lots of copy operations.](diagram/move2.png)
+
+The object `o` needs to allocate a buffer of same size as contacts, makes a 
deep clone of it, and then finally contacts is destructed. This will incur a 
lot of unnecessary allocations/deallocations and memory copying.
+
+There are solutions to prevent actual copying these data, such as reference 
counting and garbage collection(GC).
+
+To make RapidJSON simple and fast, we chose to use *move* semantics for 
assignment. It is similar to `std::auto_ptr` which transfer ownership during 
assignment. Move is much faster and simpler, it just destructs the original 
value, `memcpy()` the source to destination, and finally sets the source as 
Null type.
+
+So, with move semantics, the above example becomes:
+
+~~~~~~~~~~cpp
+Document d;
+Value o(kObjectType);
+{
+    Value contacts(kArrayType);
+    // adding elements to contacts array.
+    o.AddMember("contacts", contacts, d.GetAllocator());  // just memcpy() of 
contacts itself to the value of new member (16 bytes)
+    // contacts became Null here. Its destruction is trivial.
+}
+~~~~~~~~~~
+
+![Move semantics makes no copying.](diagram/move3.png)
+
+This is called move assignment operator in C++11. As RapidJSON supports C++03, 
it adopts move semantics using assignment operator, and all other modifying 
function like `AddMember()`, `PushBack()`.
+
+### Move semantics and temporary values {#TemporaryValues}
+
+Sometimes, it is convenient to construct a Value in place, before passing it 
to one of the "moving" functions, like `PushBack()` or `AddMember()`.  As 
temporary objects can't be converted to proper Value references, the 
convenience function `Move()` is available:
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+// a.PushBack(Value(42), allocator);       // will not compile
+a.PushBack(Value().SetInt(42), allocator); // fluent API
+a.PushBack(Value(42).Move(), allocator);   // same as above
+~~~~~~~~~~
+
+## Create String {#CreateString}
+RapidJSON provide two strategies for storing string.
+
+1. copy-string: allocates a buffer, and then copy the source data into it.
+2. const-string: simply store a pointer of string.
+
+Copy-string is always safe because it owns a copy of the data. Const-string 
can be used for storing string literal, and in-situ parsing which we will 
mentioned in Document section.
+
+To make memory allocation customizable, RapidJSON requires user to pass an 
instance of allocator, whenever an operation may require allocation. This 
design is needed to prevent storing a allocator (or Document) pointer per Value.
+
+Therefore, when we assign a copy-string, we call this overloaded `SetString()` 
with allocator:
+
+~~~~~~~~~~cpp
+Document document;
+Value author;
+char buffer[10];
+int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // dynamically created 
string.
+author.SetString(buffer, len, document.GetAllocator());
+memset(buffer, 0, sizeof(buffer));
+// author.GetString() still contains "Milo Yip" after buffer is destroyed
+~~~~~~~~~~
+
+In this example, we get the allocator from a `Document` instance. This is a 
common idiom when using RapidJSON. But you may use other instances of allocator.
+
+Besides, the above `SetString()` requires length. This can handle null 
characters within a string. There is another `SetString()` overloaded function 
without the length parameter. And it assumes the input is null-terminated and 
calls a `strlen()`-like function to obtain the length.
+
+Finally, for string literal or string with safe life-cycle can use 
const-string version of `SetString()`, which lacks allocator parameter.  For 
string literals (or constant character arrays), simply passing the literal as 
parameter is safe and efficient:
+
+~~~~~~~~~~cpp
+Value s;
+s.SetString("rapidjson");    // can contain null character, length derived at 
compile time
+s = "rapidjson";             // shortcut, same as above
+~~~~~~~~~~
+
+For character pointer, the RapidJSON requires to mark it as safe before using 
it without copying. This can be achieved by using the `StringRef` function:
+
+~~~~~~~~~cpp
+const char * cstr = getenv("USER");
+size_t cstr_len = ...;                 // in case length is available
+Value s;
+// s.SetString(cstr);                  // will not compile
+s.SetString(StringRef(cstr));          // ok, assume safe lifetime, 
null-terminated
+s = StringRef(cstr);                   // shortcut, same as above
+s.SetString(StringRef(cstr,cstr_len)); // faster, can contain null character
+s = StringRef(cstr,cstr_len);          // shortcut, same as above
+
+~~~~~~~~~
+
+## Modify Array {#ModifyArray}
+Value with array type provides similar APIs as `std::vector`.
+
+* `Clear()`
+* `Reserve(SizeType, Allocator&)`
+* `Value& PushBack(Value&, Allocator&)`
+* `template <typename T> GenericValue& PushBack(T, Allocator&)`
+* `Value& PopBack()`
+* `ValueIterator Erase(ConstValueIterator pos)`
+* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
+
+Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the 
array elements, therefore require an allocator.
+
+Here is an example of `PushBack()`:
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+
+for (int i = 5; i <= 10; i++)
+    a.PushBack(i, allocator);   // allocator is needed for potential realloc().
+
+// Fluent interface
+a.PushBack("Lua", allocator).PushBack("Mio", allocator);
+~~~~~~~~~~
+
+Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. 
This is called _fluent interface_.
+
+If you want to add a non-constant string or a string without sufficient 
lifetime (see [Create String](#CreateString)) to the array, you need to create 
a string Value by using the copy-string API.  To avoid the need for an 
intermediate variable, you can use a [temporary value](#TemporaryValues) in 
place:
+
+~~~~~~~~~~cpp
+// in-place Value parameter
+contact.PushBack(Value("copy", document.GetAllocator()).Move(), // copy string
+                 document.GetAllocator());
+
+// explicit parameters
+Value val("key", document.GetAllocator()); // copy string
+contact.PushBack(val, document.GetAllocator());
+~~~~~~~~~~
+
+## Modify Object {#ModifyObject}
+Object is a collection of key-value pairs (members). Each key must be a string 
value. To modify an object, either add or remove members. THe following APIs 
are for adding members:
+
+* `Value& AddMember(Value&, Value&, Allocator& allocator)`
+* `Value& AddMember(StringRefType, Value&, Allocator&)`
+* `template <typename T> Value& AddMember(StringRefType, T value, Allocator&)`
+
+Here is an example.
+
+~~~~~~~~~~cpp
+Value contact(kObject);
+contact.AddMember("name", "Milo", document.GetAllocator());
+contact.AddMember("married", true, document.GetAllocator());
+~~~~~~~~~~
+
+The name parameter with `StringRefType` is similar to the interface of 
`SetString` function for string values. These overloads are used to avoid the 
need for copying the `name` string, as constant key names are very common in 
JSON objects.
+
+If you need to create a name from a non-constant string or a string without 
sufficient lifetime (see [Create String](#CreateString)), you need to create a 
string Value by using the copy-string API.  To avoid the need for an 
intermediate variable, you can use a [temporary value](#TemporaryValues) in 
place:
+
+~~~~~~~~~~cpp
+// in-place Value parameter
+contact.AddMember(Value("copy", document.GetAllocator()).Move(), // copy string
+                  Value().Move(),                                // null value
+                  document.GetAllocator());
+
+// explicit parameters
+Value key("key", document.GetAllocator()); // copy string name
+Value val(42);                             // some value
+contact.AddMember(key, val, document.GetAllocator());
+~~~~~~~~~~
+
+For removing members, there are several choices: 
+
+* `bool RemoveMember(const Ch* name)`: Remove a member by search its name 
(linear time complexity).
+* `bool RemoveMember(const Value& name)`: same as above but `name` is a Value.
+* `MemberIterator RemoveMember(MemberIterator)`: Remove a member by iterator 
(_constant_ time complexity).
+* `MemberIterator EraseMember(MemberIterator)`: similar to the above but it 
preserves order of members (linear time complexity).
+* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`: 
remove a range of members, preserves order (linear time complexity).
+
+`MemberIterator RemoveMember(MemberIterator)` uses a "move-last" trick to 
achieve constant time complexity. Basically the member at iterator is 
destructed, and then the last element is moved to that position. So the order 
of the remaining members are changed.
+
+## Deep Copy Value {#DeepCopyValue}
+If we really need to copy a DOM tree, we can use two APIs for deep copy: 
constructor with allocator, and `CopyFrom()`.
+
+~~~~~~~~~~cpp
+Document d;
+Document::AllocatorType& a = d.GetAllocator();
+Value v1("foo");
+// Value v2(v1); // not allowed
+
+Value v2(v1, a);                      // make a copy
+assert(v1.IsString());                // v1 untouched
+d.SetArray().PushBack(v1, a).PushBack(v2, a);
+assert(v1.IsNull() && v2.IsNull());   // both moved to d
+
+v2.CopyFrom(d, a);                    // copy whole document to v2
+assert(d.IsArray() && d.Size() == 2); // d untouched
+v1.SetObject().AddMember("array", v2, a);
+d.PushBack(v1, a);
+~~~~~~~~~~
+
+## Swap Values {#SwapValues}
+
+`Swap()` is also provided.
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b("Hello");
+a.Swap(b);
+assert(a.IsString());
+assert(b.IsInt());
+~~~~~~~~~~
+
+Swapping two DOM trees is fast (constant time), despite the complexity of the 
trees.
+
+# What's next {#WhatsNext}
+
+This tutorial shows the basics of DOM tree query and manipulation. There are 
several important concepts in RapidJSON:
+
+1. [Streams](doc/stream.md) are channels for reading/writing JSON, which can 
be a in-memory string, or file stream, etc. User can also create their streams.
+2. [Encoding](doc/encoding.md) defines which character encoding is used in 
streams and memory. RapidJSON also provide Unicode conversion/validation 
internally.
+3. [DOM](doc/dom.md)'s basics are already covered in this tutorial. Uncover 
more advanced features such as *in situ* parsing, other parsing options and 
advanced usages.
+4. [SAX](doc/sax.md) is the foundation of parsing/generating facility in 
RapidJSON. Learn how to use `Reader`/`Writer` to implement even faster 
applications. Also try `PrettyWriter` to format the JSON.
+5. [Performance](doc/performance.md) shows some in-house and third-party 
benchmarks.
+6. [Internals](doc/internals.md) describes some internal designs and 
techniques of RapidJSON.
+
+You may also refer to the [FAQ](doc/faq.md), API documentation, examples and 
unit tests.

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/tutorial.zh-cn.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/tutorial.zh-cn.md 
b/thirdparty/rapidjson-1.1.0/doc/tutorial.zh-cn.md
new file mode 100644
index 0000000..61fb0b2
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/tutorial.zh-cn.md
@@ -0,0 +1,534 @@
+# 教程
+
+本教程简介文件对象模型(Document Object Model, DOM)API。
+
+如 [用法一览](../readme.zh-cn.md#用法一览) 
中所示,可以解析一个 JSON 至 
DOM,然后就可以轻松查询及修改 DOM,并最终转换回 JSON。
+
+[TOC]
+
+# Value 及 Document {#ValueDocument}
+
+每个 JSON 值都储存为 `Value` 类,而 `Document` 类则表示整个 
DOM,它存储了一个 DOM 树的根 `Value`。RapidJSON 的所有å…
¬å¼€ç±»åž‹åŠå‡½æ•°éƒ½åœ¨ `rapidjson` 命名空间中。
+
+# 查询 Value {#QueryValue}
+
+在本节中,我们会使用到 `example/tutorial/tutorial.cpp` 中的代ç 
ç‰‡æ®µã€‚
+
+假设我们用 C 语言的字符串储存一个 JSON(`const char* 
json`):
+~~~~~~~~~~js
+{
+    "hello": "world",
+    "t": true ,
+    "f": false,
+    "n": null,
+    "i": 123,
+    "pi": 3.1416,
+    "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+把它解析至一个 `Document`:
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+
+using namespace rapidjson;
+
+// ...
+Document document;
+document.Parse(json);
+~~~~~~~~~~
+
+那么现在该 JSON 就会被解析至 `document` 中,成为一棵 *DOM 树 
*:
+
+![教程中的 DOM](diagram/tutorial.png)
+
+自从 RFC 7159 作出更新,合法 JSON 文件的æ 
¹å¯ä»¥æ˜¯ä»»ä½•ç±»åž‹çš„ JSON 值。而在较早的 RFC 4627 中,根值只å…
è®¸æ˜¯ Object 或 Array。而在上述例子中,根是一个 Object。
+~~~~~~~~~~cpp
+assert(document.IsObject());
+~~~~~~~~~~
+
+让我们查询一下根 Object 中有没有 `"hello"` 成员。由于一个 
`Value` 可包
含不同类型的值,我们可能需要验证它的类型,并使用合适的
 API 去获取其值。在此例中,`"hello"` 成员关联到一个 JSON 
String。
+~~~~~~~~~~cpp
+assert(document.HasMember("hello"));
+assert(document["hello"].IsString());
+printf("hello = %s\n", document["hello"].GetString());
+~~~~~~~~~~
+
+~~~~~~~~~~
+world
+~~~~~~~~~~
+
+JSON True/False 值是以 `bool` 表示的。
+~~~~~~~~~~cpp
+assert(document["t"].IsBool());
+printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
+~~~~~~~~~~
+
+~~~~~~~~~~
+true
+~~~~~~~~~~
+
+JSON Null 值可用 `IsNull()` 查询。
+~~~~~~~~~~cpp
+printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
+~~~~~~~~~~
+
+~~~~~~~~~~
+null
+~~~~~~~~~~
+
+JSON Number 类型表示所有数值。然而,C++ 
需要使用更专门的类型。
+
+~~~~~~~~~~cpp
+assert(document["i"].IsNumber());
+
+// 在此情况下,IsUint()/IsInt64()/IsUInt64() 也会返回 true
+assert(document["i"].IsInt());          
+printf("i = %d\n", document["i"].GetInt());
+// 另一种用法: (int)document["i"]
+
+assert(document["pi"].IsNumber());
+assert(document["pi"].IsDouble());
+printf("pi = %g\n", document["pi"].GetDouble());
+~~~~~~~~~~
+
+~~~~~~~~~~
+i = 123
+pi = 3.1416
+~~~~~~~~~~
+
+JSON Array 包含一些元素。
+~~~~~~~~~~cpp
+// 使用引用来连续访问,方便之余还更高效。
+const Value& a = document["a"];
+assert(a.IsArray());
+for (SizeType i = 0; i < a.Size(); i++) // 使用 SizeType 而不是 size_t
+        printf("a[%d] = %d\n", i, a[i].GetInt());
+~~~~~~~~~~
+
+~~~~~~~~~~
+a[0] = 1
+a[1] = 2
+a[2] = 3
+a[3] = 4
+~~~~~~~~~~
+
+注意,RapidJSON 并不自动转换各种 JSON 类型。例如,对一个 
String 的 Value 调用 `GetInt()` 
是非法的。在调试模式下,它会被断言失败。在发布模式下,å
…¶è¡Œä¸ºæ˜¯æœªå®šä¹‰çš„。
+
+以下将会讨论有关查询各类型的细节。
+
+## 查询 Array {#QueryArray}
+
+缺省情况下,`SizeType` 是 `unsigned` 的 
typedef。在多数系统中,Array 最多能存储 2^32-1 个元素。
+
+你可以用整数字面量访问元素,如 `a[0]`、`a[1]`、`a[2]`。
+
+Array 与 `std::vector` 
相似,除了使用索引,也可使用迭代器来访问所有元素。
+~~~~~~~~~~cpp
+for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+    printf("%d ", itr->GetInt());
+~~~~~~~~~~
+
+还有一些熟悉的查询函数:
+* `SizeType Capacity() const`
+* `bool Empty() const`
+
+### 范围 for 循环 (v1.1.0 中的新功能)
+
+当使用 C++11 功能时,你可使用范围 for 循环去访问 Array 内
的所有元素。
+
+~~~~~~~~~~cpp
+for (auto& v : a.GetArray())
+    printf("%d ", v.GetInt());
+~~~~~~~~~~
+
+## 查询 Object {#QueryObject}
+
+和 Array 相似,我们可以用迭代器去访问所有 Object 成员:
+
+~~~~~~~~~~cpp
+static const char* kTypeNames[] = 
+    { "Null", "False", "True", "Object", "Array", "String", "Number" };
+
+for (Value::ConstMemberIterator itr = document.MemberBegin();
+    itr != document.MemberEnd(); ++itr)
+{
+    printf("Type of member %s is %s\n",
+        itr->name.GetString(), kTypeNames[itr->value.GetType()]);
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+Type of member hello is String
+Type of member t is True
+Type of member f is False
+Type of member n is Null
+Type of member i is Number
+Type of member pi is Number
+Type of member a is Array
+~~~~~~~~~~
+
+注意,当 `operator[](const char*)` 找不到成员,它会断言失败。
+
+若我们不确定一个成员是否存在,便需要在调用 
`operator[](const char*)` 前先调用 
`HasMember()`。然而,这会导致两次查找。更好的做法是调用 
`FindMember()`,它能同时检查成员是否存在并返回它的 Value:
+
+~~~~~~~~~~cpp
+Value::ConstMemberIterator itr = document.FindMember("hello");
+if (itr != document.MemberEnd())
+    printf("%s\n", itr->value.GetString());
+~~~~~~~~~~
+
+### 范围 for 循环 (v1.1.0 中的新功能)
+
+当使用 C++11 功能时,你可使用范围 for 循环去访问 Object 内
的所有成员。
+
+~~~~~~~~~~cpp
+for (auto& m : document.GetObject())
+    printf("Type of member %s is %s\n",
+        m.name.GetString(), kTypeNames[m.value.GetType()]);
+~~~~~~~~~~
+
+## 查询 Number {#QueryNumber}
+
+JSON 
只提供一种数值类型──Number。数字可以是整数或实数。RFC 
4627 规定数字的范围由解析器指定。
+
+由于 C++ 提供多种整数及浮点数类型,DOM 
尝试尽量提供最广的范围及良好性能。
+
+当解析一个 Number 时, 它会被存储在 DOM 之中,成为下列å…
¶ä¸­ä¸€ä¸ªç±»åž‹ï¼š
+
+类型       | 描述
+-----------|---------------------------------------
+`unsigned` | 32 位无号整数
+`int`      | 32 位有号整数
+`uint64_t` | 64 位无号整数
+`int64_t`  | 64 位有号整数
+`double`   | 64 位双精度浮点数
+
+当查询一个 Number 时, 你可以检查该数字是否能以目æ 
‡ç±»åž‹æ¥æå–:
+
+查检              | 提取
+------------------|---------------------
+`bool IsNumber()` | 不适用
+`bool IsUint()`   | `unsigned GetUint()`
+`bool IsInt()`    | `int GetInt()`
+`bool IsUint64()` | `uint64_t GetUint64()`
+`bool IsInt64()`  | `int64_t GetInt64()`
+`bool IsDouble()` | `double GetDouble()`
+
+注意,一个整数可能用几种类型来提取,而无
需转换。例如,一个名为 `x` 的 Value 包含 123,那么 `x.IsInt() 
== x.IsUint() == x.IsInt64() == x.IsUint64() == true`。但如果一个名为 
`y` 的 Value 包含 -3000000000,那么仅会令 `x.IsInt64() == true`。
+
+当要提取 Number 类型,`GetDouble()` 是会把内
部整数的表示转换成 `double`。注意 `int` 和 `unsigned` 可以安å…
¨åœ°è½¬æ¢è‡³ `double`,但 `int64_t` 及 `uint64_t` 
可能会丧失精度(因为 `double` 的尾数只有 52 位)。
+
+## 查询 String {#QueryString}
+
+除了 `GetString()`,`Value` 类也有一个 
`GetStringLength()`。这里会解释个中原因。
+
+根据 RFC 4627,JSON String 可包含 Unicode 字符 `U+0000`,在 JSON 
中会表示为 `"\u0000"`。问题是,C/C++ 
通常使用空字符结尾字符串(null-terminated 
string),这种字符串把 ``\0'` 作为结束符号。
+
+为了符合 RFC 4627,RapidJSON 支持包含 `U+0000` 的 String。若你
需要处理这些 String,便可使用 `GetStringLength()` 
去获得正确的字符串长度。
+
+例如,当解析以下的 JSON 至 `Document d` 之后:
+
+~~~~~~~~~~js
+{ "s" :  "a\u0000b" }
+~~~~~~~~~~
+`"a\u0000b"` 值的正确长度应该是 3。但 `strlen()` 会返回 1。
+
+`GetStringLength()` 也可以提高性能,因为用户可能需要调用 
`strlen()` 去分配缓冲。
+
+此外,`std::string` 也支持这个构造函数:
+
+~~~~~~~~~~cpp
+string(const char* s, size_t count);
+~~~~~~~~~~
+
+此构造
函数接受字符串长度作为参数。它支持在字符串中存储空字符,也应该会有更好的性能。
+
+## 比较两个 Value
+
+你可使用 `==` 及 `!=` 去比较两个 Value。当且仅当两个 Value 
的类型及内容相同,它们才当作相等。你也可以比较 Value 
和它的原生类型值。以下是一个例子。
+
+~~~~~~~~~~cpp
+if (document["hello"] == document["n"]) /*...*/;    // 比较两个值
+if (document["hello"] == "world") /*...*/;          // 
与字符串家面量作比较
+if (document["i"] != 123) /*...*/;                  // 与整数作比较
+if (document["pi"] != 3.14) /*...*/;                // 与 double 作比较
+~~~~~~~~~~
+
+Array/Object 顺序以它们的元素/成员作比较。当且仅
当它们的整个子树相等,它们才当作相等。
+
+注意,现时若一个 Object 含有重复命名的成员,它与任何 
Object 作比较都总会返回 `false`。
+
+# 创建/修改值 {#CreateModifyValues}
+
+有多种方法去创建值。 当一个 DOM æ 
‘被创建或修改后,可使用 `Writer` 再次存储为 JSON。
+
+## 改变 Value 类型 {#ChangeValueType}
+当使用默认构造函数创建一个 Value 或 
Document,它的类型便会是 Null。要改变其类型,需调用 
`SetXXX()` 或赋值操作,例如:
+
+~~~~~~~~~~cpp
+Document d; // Null
+d.SetObject();
+
+Value v;    // Null
+v.SetInt(10);
+v = 10;     // 简写,和上面的相同
+~~~~~~~~~~
+
+### 构造函数的各个重载
+几个类型也有重载构造函数:
+
+~~~~~~~~~~cpp
+Value b(true);    // 调用 Value(bool)
+Value i(-123);    // 调用 Value(int)
+Value u(123u);    // 调用 Value(unsigned)
+Value d(1.5);     // 调用 Value(double)
+~~~~~~~~~~
+
+要重建空 Object 或 Array,可在默认构造函数后使用 
`SetObject()`/`SetArray()`,或一次性使用 `Value(Type)`:
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+Value a(kArrayType);
+~~~~~~~~~~
+
+## 转移语意(Move Semantics) {#MoveSemantics}
+
+在设计 RapidJSON 时有一个非常特别的决定,就是 Value 
赋值并不是把来源 Value 复制至目的 Value,而是把把来源 Value 
转移(move)至目的 Value。例如:
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b(456);
+b = a;         // a 变成 Null,b 变成数字 123。
+~~~~~~~~~~
+
+![使用移动语意赋值。](diagram/move1.png)
+
+为什么?此语意有何优点?
+
+最简单的答案就是性能。对于固定大小的 JSON 
类型(Number、True、False、Null),复制它们是简单快捷。然而,对于可变大小的
 JSON 
类型(String、Array、Object),复制它们会产生大量开销,而且这些开销常常不被察觉。尤å
…¶æ˜¯å½“我们需要创建临时 
Object,把它复制至另一变量,然后再析构它。
+
+例如,若使用正常 * 复制 * 语意:
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+{
+    Value contacts(kArrayType);
+    // 把元素加进 contacts 数组。
+    // ...
+    o.AddMember("contacts", contacts, d.GetAllocator());  // 深度复制 
contacts (可能有大量内存分配)
+    // 析构 contacts。
+}
+~~~~~~~~~~
+
+![复制语意产生大量的复制操作。](diagram/move2.png)
+
+那个 `o` Object 需要分配一个和 contacts 
相同大小的缓冲区,对 conacts 做深度复制,并最终要析构 
contacts。这样会产生大量无必要的内存分配/释放,以及内
存复制。
+
+有一些方案可避å…
å®žè´¨åœ°å¤åˆ¶è¿™äº›æ•°æ®ï¼Œä¾‹å¦‚引用计数(reference 
counting)、垃圾回收(garbage collection, GC)。
+
+为了使 RapidJSON 简单及快速,我们选择了对赋值采用 * 转移 
* 语意。这方法与 `std::auto_ptr` 
相似,都是在赋值时转移拥有权。转移快得多简单得多,只需要析构原来的
 Value,把来源 `memcpy()` 至目标,最后把来源设置为 Null 
类型。
+
+因此,使用转移语意后,上面的例子变成:
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+{
+    Value contacts(kArrayType);
+    // adding elements to contacts array.
+    o.AddMember("contacts", contacts, d.GetAllocator());  // 只需 memcpy() 
contacts 本身至新成员的 Value(16 字节)
+    // contacts 在这里变成 Null。它的析构是平凡的。
+}
+~~~~~~~~~~
+
+![转移语意不需复制。](diagram/move3.png)
+
+在 C++11 中这称为转移赋值操作(move assignment 
operator)。由于 RapidJSON 支持 
C++03,它在赋值操作采用转移语意,其它修改形函数如 
`AddMember()`, `PushBack()` 也采用转移语意。
+
+### 转移语意及临时值 {#TemporaryValues}
+
+有时候,我们想直接构造一个 Value 并传
递给一个“转移”函数(如 
`PushBack()`、`AddMember()`)。由于临时对象是不能转换为正常的 
Value 引用,我们加入了一个方便的 `Move()` 函数:
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+// a.PushBack(Value(42), allocator);       // 不能通过编译
+a.PushBack(Value().SetInt(42), allocator); // fluent API
+a.PushBack(Value(42).Move(), allocator);   // 和上一行相同
+~~~~~~~~~~
+
+## 创建 String {#CreateString}
+RapidJSON 提供两个 String 的存储策略。
+
+1. copy-string: 分配缓冲区,然后把来源数据复制至它。
+2. const-string: 简单地储存字符串的指针。
+
+Copy-string 总是安全的,因为它拥有数据的克隆。Const-string 
可用于存储字符串字面量,以及用于在 DOM 
一节中将会提到的 in-situ 解析中。
+
+为了让用户自定义内存分配方式,当一个操作可能需要内
存分配时,RapidJSON 要求用户传递一个 allocator 实例作为 API 
参数。此设计避免了在每个 Value 存储 allocator(或 
document)的指针。
+
+因此,当我们把一个 copy-string 赋值时, 调用含有 allocator 的 
`SetString()` 重载函数:
+
+~~~~~~~~~~cpp
+Document document;
+Value author;
+char buffer[10];
+int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // 
动态创建的字符串。
+author.SetString(buffer, len, document.GetAllocator());
+memset(buffer, 0, sizeof(buffer));
+// 清空 buffer 后 author.GetString() 仍然包含 "Milo Yip"
+~~~~~~~~~~
+
+在此例子中,我们使用 `Document` 实例的 allocator。这是使用 
RapidJSON 时常用的惯用法。但你也可以用其他 allocator 实例。
+
+另外,上面的 `SetString()` 需要长度参数。这个 API 
能处理含有空字符的字符串。另一个 `SetString()` 
重载函数没有长度参数,它假设输å…
¥æ˜¯ç©ºå­—符结尾的,并会调用类似 `strlen()` 
的函数去获取长度。
+
+最后,对于字符串字面量或有安å…
¨ç”Ÿå‘½å‘¨æœŸçš„字符串,可以使用 const-string 版本的 
`SetString()`,它没有 allocator 
参数。对于字符串家面量(或字符数组常量),只需简单地ä¼
 é€’字面量,又安全又高效:
+
+~~~~~~~~~~cpp
+Value s;
+s.SetString("rapidjson");    // 可包含空字符,长度在编译萁推导
+s = "rapidjson";             // 上行的缩写
+~~~~~~~~~~
+
+对于字符指针,RapidJSON 需要作一个æ 
‡è®°ï¼Œä»£è¡¨å®ƒä¸å¤åˆ¶ä¹Ÿæ˜¯å®‰å…¨çš„。可以使用 `StringRef` 函数:
+
+~~~~~~~~~cpp
+const char * cstr = getenv("USER");
+size_t cstr_len = ...;                 // 如果有长度
+Value s;
+// s.SetString(cstr);                  // 这不能通过编译
+s.SetString(StringRef(cstr));          // 
可以,假设它的生命周期安全,并且是以空字符结尾的
+s = StringRef(cstr);                   // 上行的缩写
+s.SetString(StringRef(cstr, cstr_len));// 更快,可处理空字符
+s = StringRef(cstr, cstr_len);         // 上行的缩写
+
+~~~~~~~~~
+
+## 修改 Array {#ModifyArray}
+Array 类型的 Value 提供与 `std::vector` 相似的 API。
+
+* `Clear()`
+* `Reserve(SizeType, Allocator&)`
+* `Value& PushBack(Value&, Allocator&)`
+* `template <typename T> GenericValue& PushBack(T, Allocator&)`
+* `Value& PopBack()`
+* `ValueIterator Erase(ConstValueIterator pos)`
+* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
+
+注意,`Reserve(...)` 及 `PushBack(...)` 可能会为数组元素分配内
存,所以需要一个 allocator。
+
+以下是 `PushBack()` 的例子:
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+
+for (int i = 5; i <= 10; i++)
+    a.PushBack(i, allocator);   // 可能需要调用 realloc() 所以需要 
allocator
+
+// 流畅接口(Fluent interface)
+a.PushBack("Lua", allocator).PushBack("Mio", allocator);
+~~~~~~~~~~
+
+与 STL 不一样的是,`PushBack()`/`PopBack()` 返回 Array 
本身的引用。这称为流畅接口(_fluent interface_)。
+
+如果你想在 Array 中加å…
¥ä¸€ä¸ªéžå¸¸é‡å­—符串,或是一个没有足够生命周期的字符串(见
 [Create String](#CreateString)),你需要使用 copy-string API 
去创建一个 String。为了避免加å…
¥ä¸­é—´å˜é‡ï¼Œå¯ä»¥å°±åœ°ä½¿ç”¨ä¸€ä¸ª [临时值](#TemporaryValues):
+
+~~~~~~~~~~cpp
+// 就地 Value 参数
+contact.PushBack(Value("copy", document.GetAllocator()).Move(), // copy string
+                 document.GetAllocator());
+
+// 显式 Value 参数
+Value val("key", document.GetAllocator()); // copy string
+contact.PushBack(val, document.GetAllocator());
+~~~~~~~~~~
+
+## 修改 Object {#ModifyObject}
+Object 是键值对的集合。每个键必须为 String。要修改 
Object,方法是增加或移除成员。以下的 API 用来增加城员:
+
+* `Value& AddMember(Value&, Value&, Allocator& allocator)`
+* `Value& AddMember(StringRefType, Value&, Allocator&)`
+* `template <typename T> Value& AddMember(StringRefType, T value, Allocator&)`
+
+以下是一个例子。
+
+~~~~~~~~~~cpp
+Value contact(kObject);
+contact.AddMember("name", "Milo", document.GetAllocator());
+contact.AddMember("married", true, document.GetAllocator());
+~~~~~~~~~~
+
+使用 `StringRefType` 作为 name 参数的重载版本与字符串的 
`SetString` 的接口相似。 这些重载是为了避免复制 `name` 
字符串,因为 JSON object 中经常会使用常数键名。
+
+如果你
需要从非常数字符串或生命周期不足的字符串创建键名(见 
[创建 String](#CreateString)),你需要使用 copy-string 
API。为了避免中间变量,可以就地使用 
[临时值](#TemporaryValues):
+
+~~~~~~~~~~cpp
+// 就地 Value 参数
+contact.AddMember(Value("copy", document.GetAllocator()).Move(), // copy string
+                  Value().Move(),                                // null value
+                  document.GetAllocator());
+
+// 显式参数
+Value key("key", document.GetAllocator()); // copy string name
+Value val(42);                             // 某 Value
+contact.AddMember(key, val, document.GetAllocator());
+~~~~~~~~~~
+
+移除成员有几个选择:
+
+* `bool RemoveMember(const Ch* 
name)`:使用键名来移除成员(线性时间复杂度)。
+* `bool RemoveMember(const Value& name)`:除了 `name` 是一个 
Value,和上一行相同。
+* `MemberIterator 
RemoveMember(MemberIterator)`:使用迭代器移除成员(_ 常数 _ 
时间复杂度)。
+* `MemberIterator 
EraseMember(MemberIterator)`:和上行相似但维持成员次序(线性时间复杂度)。
+* `MemberIterator EraseMember(MemberIterator first, MemberIterator 
last)`:移除一个范围内
的成员,维持次序(线性时间复杂度)。
+
+`MemberIterator RemoveMember(MemberIterator)` 
使用了“转移最后”手法来达成常数时间复杂度。基本上就是析构迭代器位置的成员,然后把最后的成员转移至迭代器位置。å›
 æ­¤ï¼Œæˆå‘˜çš„次序会被改变。
+
+## 深复制 Value {#DeepCopyValue}
+若我们真的要复制一个 DOM 树,我们可使用两个 APIs 
作深复制:含 allocator 的构造函数及 `CopyFrom()`。
+
+~~~~~~~~~~cpp
+Document d;
+Document::AllocatorType& a = d.GetAllocator();
+Value v1("foo");
+// Value v2(v1); // 不容许
+
+Value v2(v1, a);                      // 制造一个克隆
+assert(v1.IsString());                // v1 不变
+d.SetArray().PushBack(v1, a).PushBack(v2, a);
+assert(v1.IsNull() && v2.IsNull());   // 两个都转移动 d
+
+v2.CopyFrom(d, a);                    // 把整个 document 复制至 v2
+assert(d.IsArray() && d.Size() == 2); // d 不变
+v1.SetObject().AddMember("array", v2, a);
+d.PushBack(v1, a);
+~~~~~~~~~~
+
+## 交换 Value {#SwapValues}
+
+RapidJSON 也提供 `Swap()`。
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b("Hello");
+a.Swap(b);
+assert(a.IsString());
+assert(b.IsInt());
+~~~~~~~~~~
+
+无论两棵 DOM 树有多复杂,交换是很快的(常数时间)。
+
+# 下一部分 {#WhatsNext}
+
+本教程展示了如何询查及修改 DOM 树。RapidJSON 
还有一个重要概念:
+
+1. [流](doc/stream.zh-cn.md) 是读写 JSON 的通道。流可以是内
存字符串、文件流等。用户也可以自定义流。
+2. [编码](doc/encoding.zh-cn.md) 定义在流或内存中使用的字符编ç 
ã€‚RapidJSON 也在内部提供 Unicode 转换及校验功能。
+3. [DOM](doc/dom.zh-cn.md) 
的基本功能已在本教程里介绍。还有更高级的功能,如原位(*in
 situ*)解析、其他解析选项及高级用法。
+4. [SAX](doc/sax.zh-cn.md) 是 RapidJSON 
解析/生成功能的基础。学习使用 `Reader`/`Writer` 
去实现更高性能的应用程序。也可以使用 `PrettyWriter` 去æ 
¼å¼åŒ– JSON。
+5. [性能](doc/performance.zh-cn.md) 
展示一些我们做的及第三方的性能测试。
+6. [技术内幕](doc/internals.md) 讲述一些 RapidJSON 内
部的设计及技术。
+
+你也可以参考 [常见问题](doc/faq.zh-cn.md)、API 
文档、例子及单元测试。

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/docker/debian/Dockerfile
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/docker/debian/Dockerfile 
b/thirdparty/rapidjson-1.1.0/docker/debian/Dockerfile
new file mode 100644
index 0000000..76f0235
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/docker/debian/Dockerfile
@@ -0,0 +1,8 @@
+# BUILD:  docker build -t rapidjson-debian .
+# RUN:    docker run -it -v "$PWD"/../..:/rapidjson rapidjson-debian
+
+FROM debian:jessie
+
+RUN apt-get update && apt-get install -y g++ cmake doxygen valgrind
+
+ENTRYPOINT ["/bin/bash"]

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/example/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/example/CMakeLists.txt 
b/thirdparty/rapidjson-1.1.0/example/CMakeLists.txt
new file mode 100644
index 0000000..4d448cc
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/example/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 2.8)
+
+if(POLICY CMP0054)
+  cmake_policy(SET CMP0054 NEW)
+endif()
+
+set(EXAMPLES
+    capitalize
+    condense
+    filterkey
+    filterkeydom
+    jsonx
+    messagereader
+    parsebyparts
+    pretty
+    prettyauto
+    schemavalidator
+    serialize
+    simpledom
+    simplereader
+    simplewriter
+    tutorial)
+    
+include_directories("../include/")
+
+add_definitions(-D__STDC_FORMAT_MACROS)
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -Werror -Wall -Wextra 
-Weffc++ -Wswitch-default")
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ 
-Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
+endif()
+
+foreach (example ${EXAMPLES})
+    add_executable(${example} ${example}/${example}.cpp)
+endforeach()
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+    target_link_libraries(parsebyparts pthread)
+endif()
+
+add_custom_target(examples ALL DEPENDS ${EXAMPLES})

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/example/capitalize/capitalize.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/example/capitalize/capitalize.cpp 
b/thirdparty/rapidjson-1.1.0/example/capitalize/capitalize.cpp
new file mode 100644
index 0000000..7da37e9
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/example/capitalize/capitalize.cpp
@@ -0,0 +1,67 @@
+// JSON condenser example
+
+// This example parses JSON from stdin with validation, 
+// and re-output the JSON content to stdout with all string capitalized, and 
without whitespace.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <vector>
+#include <cctype>
+
+using namespace rapidjson;
+
+template<typename OutputHandler>
+struct CapitalizeFilter {
+    CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {}
+
+    bool Null() { return out_.Null(); }
+    bool Bool(bool b) { return out_.Bool(b); }
+    bool Int(int i) { return out_.Int(i); }
+    bool Uint(unsigned u) { return out_.Uint(u); }
+    bool Int64(int64_t i) { return out_.Int64(i); }
+    bool Uint64(uint64_t u) { return out_.Uint64(u); }
+    bool Double(double d) { return out_.Double(d); }
+    bool RawNumber(const char* str, SizeType length, bool copy) { return 
out_.RawNumber(str, length, copy); }
+    bool String(const char* str, SizeType length, bool) {
+        buffer_.clear();
+        for (SizeType i = 0; i < length; i++)
+            buffer_.push_back(static_cast<char>(std::toupper(str[i])));
+        return out_.String(&buffer_.front(), length, true); // true = output 
handler need to copy the string
+    }
+    bool StartObject() { return out_.StartObject(); }
+    bool Key(const char* str, SizeType length, bool copy) { return String(str, 
length, copy); }
+    bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); 
}
+    bool StartArray() { return out_.StartArray(); }
+    bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); 
}
+
+    OutputHandler& out_;
+    std::vector<char> buffer_;
+
+private:
+    CapitalizeFilter(const CapitalizeFilter&);
+    CapitalizeFilter& operator=(const CapitalizeFilter&);
+};
+
+int main(int, char*[]) {
+    // Prepare JSON reader and input stream.
+    Reader reader;
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    // Prepare JSON writer and output stream.
+    char writeBuffer[65536];
+    FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+    Writer<FileWriteStream> writer(os);
+
+    // JSON reader parse from the input stream and let writer generate the 
output.
+    CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
+    if (!reader.Parse(is, filter)) {
+        fprintf(stderr, "\nError(%u): %s\n", 
static_cast<unsigned>(reader.GetErrorOffset()), 
GetParseError_En(reader.GetParseErrorCode()));
+        return 1;
+    }
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/example/condense/condense.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/example/condense/condense.cpp 
b/thirdparty/rapidjson-1.1.0/example/condense/condense.cpp
new file mode 100644
index 0000000..46dc350
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/example/condense/condense.cpp
@@ -0,0 +1,32 @@
+// JSON condenser example
+
+// This example parses JSON text from stdin with validation, 
+// and re-output the JSON content to stdout without whitespace.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+
+using namespace rapidjson;
+
+int main(int, char*[]) {
+    // Prepare JSON reader and input stream.
+    Reader reader;
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    // Prepare JSON writer and output stream.
+    char writeBuffer[65536];
+    FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+    Writer<FileWriteStream> writer(os);
+
+    // JSON reader parse from the input stream and let writer generate the 
output.
+    if (!reader.Parse(is, writer)) {
+        fprintf(stderr, "\nError(%u): %s\n", 
static_cast<unsigned>(reader.GetErrorOffset()), 
GetParseError_En(reader.GetParseErrorCode()));
+        return 1;
+    }
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/example/filterkey/filterkey.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/example/filterkey/filterkey.cpp 
b/thirdparty/rapidjson-1.1.0/example/filterkey/filterkey.cpp
new file mode 100644
index 0000000..c34a050
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/example/filterkey/filterkey.cpp
@@ -0,0 +1,135 @@
+// JSON filterkey example with SAX-style API.
+
+// This example parses JSON text from stdin with validation.
+// During parsing, specified key will be filtered using a SAX handler.
+// It re-output the JSON content to stdout without whitespace.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <stack>
+
+using namespace rapidjson;
+
+// This handler forwards event into an output handler, with filtering the 
descendent events of specified key.
+template <typename OutputHandler>
+class FilterKeyHandler {
+public:
+    typedef char Ch;
+
+    FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, 
SizeType keyLength) : 
+        outputHandler_(outputHandler), keyString_(keyString), 
keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_()
+    {}
+
+    bool Null()             { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Null()    && EndValue(); }
+    bool Bool(bool b)       { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Bool(b)   && EndValue(); }
+    bool Int(int i)         { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Int(i)    && EndValue(); }
+    bool Uint(unsigned u)   { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Uint(u)   && EndValue(); }
+    bool Int64(int64_t i)   { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Int64(i)  && EndValue(); }
+    bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Uint64(u) && EndValue(); }
+    bool Double(double d)   { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Double(d) && EndValue(); }
+    bool RawNumber(const Ch* str, SizeType len, bool copy) { return 
filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) 
&& EndValue(); }
+    bool String   (const Ch* str, SizeType len, bool copy) { return 
filterValueDepth_ > 0 ? EndValue() : outputHandler_.String   (str, len, copy) 
&& EndValue(); }
+    
+    bool StartObject() { 
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_++;
+            return true;
+        }
+        else {
+            filteredKeyCount_.push(0);
+            return outputHandler_.StartObject();
+        }
+    }
+    
+    bool Key(const Ch* str, SizeType len, bool copy) { 
+        if (filterValueDepth_ > 0) 
+            return true;
+        else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) {
+            filterValueDepth_ = 1;
+            return true;
+        }
+        else {
+            ++filteredKeyCount_.top();
+            return outputHandler_.Key(str, len, copy);
+        }
+    }
+
+    bool EndObject(SizeType) {
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_--;
+            return EndValue();
+        }
+        else {
+            // Use our own filtered memberCount
+            SizeType memberCount = filteredKeyCount_.top();
+            filteredKeyCount_.pop();
+            return outputHandler_.EndObject(memberCount) && EndValue();
+        }
+    }
+
+    bool StartArray() {
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_++;
+            return true;
+        }
+        else
+            return outputHandler_.StartArray();
+    }
+
+    bool EndArray(SizeType elementCount) {
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_--;
+            return EndValue();
+        }
+        else
+            return outputHandler_.EndArray(elementCount) && EndValue();
+    }
+
+private:
+    FilterKeyHandler(const FilterKeyHandler&);
+    FilterKeyHandler& operator=(const FilterKeyHandler&);
+
+    bool EndValue() {
+        if (filterValueDepth_ == 1) // Just at the end of value after filtered 
key
+            filterValueDepth_ = 0;
+        return true;
+    }
+    
+    OutputHandler& outputHandler_;
+    const char* keyString_;
+    const SizeType keyLength_;
+    unsigned filterValueDepth_;
+    std::stack<SizeType> filteredKeyCount_;
+};
+
+int main(int argc, char* argv[]) {
+    if (argc != 2) {
+        fprintf(stderr, "filterkey key < input.json > output.json\n");
+        return 1;
+    }
+
+    // Prepare JSON reader and input stream.
+    Reader reader;
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    // Prepare JSON writer and output stream.
+    char writeBuffer[65536];
+    FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+    Writer<FileWriteStream> writer(os);
+
+    // Prepare Filter
+    FilterKeyHandler<Writer<FileWriteStream> > filter(writer, argv[1], 
static_cast<SizeType>(strlen(argv[1])));
+
+    // JSON reader parse from the input stream, filter handler filters the 
events, and forward to writer.
+    // i.e. the events flow is: reader -> filter -> writer
+    if (!reader.Parse(is, filter)) {
+        fprintf(stderr, "\nError(%u): %s\n", 
static_cast<unsigned>(reader.GetErrorOffset()), 
GetParseError_En(reader.GetParseErrorCode()));
+        return 1;
+    }
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/example/filterkeydom/filterkeydom.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/example/filterkeydom/filterkeydom.cpp 
b/thirdparty/rapidjson-1.1.0/example/filterkeydom/filterkeydom.cpp
new file mode 100644
index 0000000..732cc81
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/example/filterkeydom/filterkeydom.cpp
@@ -0,0 +1,170 @@
+// JSON filterkey example which populates filtered SAX events into a Document.
+
+// This example parses JSON text from stdin with validation.
+// During parsing, specified key will be filtered using a SAX handler.
+// And finally the filtered events are used to populate a Document.
+// As an example, the document is written to standard output.
+
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <stack>
+
+using namespace rapidjson;
+
+// This handler forwards event into an output handler, with filtering the 
descendent events of specified key.
+template <typename OutputHandler>
+class FilterKeyHandler {
+public:
+    typedef char Ch;
+
+    FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, 
SizeType keyLength) : 
+        outputHandler_(outputHandler), keyString_(keyString), 
keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_()
+    {}
+
+    bool Null()             { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Null()    && EndValue(); }
+    bool Bool(bool b)       { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Bool(b)   && EndValue(); }
+    bool Int(int i)         { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Int(i)    && EndValue(); }
+    bool Uint(unsigned u)   { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Uint(u)   && EndValue(); }
+    bool Int64(int64_t i)   { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Int64(i)  && EndValue(); }
+    bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Uint64(u) && EndValue(); }
+    bool Double(double d)   { return filterValueDepth_ > 0 ? EndValue() : 
outputHandler_.Double(d) && EndValue(); }
+    bool RawNumber(const Ch* str, SizeType len, bool copy) { return 
filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) 
&& EndValue(); }
+    bool String   (const Ch* str, SizeType len, bool copy) { return 
filterValueDepth_ > 0 ? EndValue() : outputHandler_.String   (str, len, copy) 
&& EndValue(); }
+    
+    bool StartObject() { 
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_++;
+            return true;
+        }
+        else {
+            filteredKeyCount_.push(0);
+            return outputHandler_.StartObject();
+        }
+    }
+    
+    bool Key(const Ch* str, SizeType len, bool copy) { 
+        if (filterValueDepth_ > 0) 
+            return true;
+        else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) {
+            filterValueDepth_ = 1;
+            return true;
+        }
+        else {
+            ++filteredKeyCount_.top();
+            return outputHandler_.Key(str, len, copy);
+        }
+    }
+
+    bool EndObject(SizeType) {
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_--;
+            return EndValue();
+        }
+        else {
+            // Use our own filtered memberCount
+            SizeType memberCount = filteredKeyCount_.top();
+            filteredKeyCount_.pop();
+            return outputHandler_.EndObject(memberCount) && EndValue();
+        }
+    }
+
+    bool StartArray() {
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_++;
+            return true;
+        }
+        else
+            return outputHandler_.StartArray();
+    }
+
+    bool EndArray(SizeType elementCount) {
+        if (filterValueDepth_ > 0) {
+            filterValueDepth_--;
+            return EndValue();
+        }
+        else
+            return outputHandler_.EndArray(elementCount) && EndValue();
+    }
+
+private:
+    FilterKeyHandler(const FilterKeyHandler&);
+    FilterKeyHandler& operator=(const FilterKeyHandler&);
+
+    bool EndValue() {
+        if (filterValueDepth_ == 1) // Just at the end of value after filtered 
key
+            filterValueDepth_ = 0;
+        return true;
+    }
+
+    OutputHandler& outputHandler_;
+    const char* keyString_;
+    const SizeType keyLength_;
+    unsigned filterValueDepth_;
+    std::stack<SizeType> filteredKeyCount_;
+};
+
+// Implements a generator for Document::Populate()
+template <typename InputStream>
+class FilterKeyReader {
+public:
+    typedef char Ch;
+
+    FilterKeyReader(InputStream& is, const Ch* keyString, SizeType keyLength) 
: 
+        is_(is), keyString_(keyString), keyLength_(keyLength), parseResult_()
+    {}
+
+    // SAX event flow: reader -> filter -> handler
+    template <typename Handler>
+    bool operator()(Handler& handler) {
+        FilterKeyHandler<Handler> filter(handler, keyString_, keyLength_);
+        Reader reader;
+        parseResult_ = reader.Parse(is_, filter);
+        return parseResult_;
+    }
+
+    const ParseResult& GetParseResult() const { return parseResult_; }
+
+private:
+    FilterKeyReader(const FilterKeyReader&);
+    FilterKeyReader& operator=(const FilterKeyReader&);
+
+    InputStream& is_;
+    const char* keyString_;
+    const SizeType keyLength_;
+    ParseResult parseResult_;
+};
+
+int main(int argc, char* argv[]) {
+    if (argc != 2) {
+        fprintf(stderr, "filterkeydom key < input.json > output.json\n");
+        return 1;
+    }
+
+    // Prepare input stream.
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    // Prepare Filter
+    FilterKeyReader<FileReadStream> reader(is, argv[1], 
static_cast<SizeType>(strlen(argv[1])));
+
+    // Populates the filtered events from reader
+    Document document;
+    document.Populate(reader);
+    ParseResult pr = reader.GetParseResult();
+    if (!pr) {
+        fprintf(stderr, "\nError(%u): %s\n", 
static_cast<unsigned>(pr.Offset()), GetParseError_En(pr.Code()));
+        return 1;
+    }
+
+    // Prepare JSON writer and output stream.
+    char writeBuffer[65536];
+    FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+    Writer<FileWriteStream> writer(os);
+
+    // Write the document to standard output
+    document.Accept(writer);
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/example/jsonx/jsonx.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/example/jsonx/jsonx.cpp 
b/thirdparty/rapidjson-1.1.0/example/jsonx/jsonx.cpp
new file mode 100644
index 0000000..1346b57
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/example/jsonx/jsonx.cpp
@@ -0,0 +1,207 @@
+// JSON to JSONx conversion exmaple, using SAX API.
+// JSONx is an IBM standard format to represent JSON as XML.
+// 
https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html
+// This example parses JSON text from stdin with validation, 
+// and convert to JSONx format to stdout.
+// Need compile with -D__STDC_FORMAT_MACROS for defining PRId64 and PRIu64 
macros.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+// For simplicity, this example only read/write in UTF-8 encoding
+template <typename OutputStream>
+class JsonxWriter {
+public:
+    JsonxWriter(OutputStream& os) : os_(os), name_(), level_(0), 
hasName_(false) {
+    }
+
+    bool Null() {
+        return WriteStartElement("null", true);
+    }
+    
+    bool Bool(bool b) {
+        return 
+            WriteStartElement("boolean") &&
+            WriteString(b ? "true" : "false") &&
+            WriteEndElement("boolean");
+    }
+    
+    bool Int(int i) {
+        char buffer[12];
+        return WriteNumberElement(buffer, sprintf(buffer, "%d", i));
+    }
+    
+    bool Uint(unsigned i) {
+        char buffer[11];
+        return WriteNumberElement(buffer, sprintf(buffer, "%u", i));
+    }
+    
+    bool Int64(int64_t i) {
+        char buffer[21];
+        return WriteNumberElement(buffer, sprintf(buffer, "%" PRId64, i));
+    }
+    
+    bool Uint64(uint64_t i) {
+        char buffer[21];
+        return WriteNumberElement(buffer, sprintf(buffer, "%" PRIu64, i));
+    }
+    
+    bool Double(double d) {
+        char buffer[30];
+        return WriteNumberElement(buffer, sprintf(buffer, "%.17g", d));
+    }
+
+    bool RawNumber(const char* str, SizeType length, bool) {
+        return
+            WriteStartElement("number") &&
+            WriteEscapedText(str, length) &&
+            WriteEndElement("number");
+    }
+
+    bool String(const char* str, SizeType length, bool) {
+        return
+            WriteStartElement("string") &&
+            WriteEscapedText(str, length) &&
+            WriteEndElement("string");
+    }
+
+    bool StartObject() {
+        return WriteStartElement("object");
+    }
+
+    bool Key(const char* str, SizeType length, bool) {
+        // backup key to name_
+        name_.Clear();
+        for (SizeType i = 0; i < length; i++)
+            name_.Put(str[i]);
+        hasName_ = true;
+        return true;
+    }
+
+    bool EndObject(SizeType) {
+        return WriteEndElement("object");
+    }
+
+    bool StartArray() {
+        return WriteStartElement("array");
+    }
+
+    bool EndArray(SizeType) {
+        return WriteEndElement("array");
+    }
+
+private:
+    bool WriteString(const char* s) {
+        while (*s)
+            os_.Put(*s++);
+        return true;
+    }
+
+    bool WriteEscapedAttributeValue(const char* s, size_t length) {
+        for (size_t i = 0; i < length; i++) {
+            switch (s[i]) {
+                case '&': WriteString("&amp;"); break;
+                case '<': WriteString("&lt;"); break;
+                case '"': WriteString("&quot;"); break;
+                default: os_.Put(s[i]); break;
+            }
+        }
+        return true;
+    }
+
+    bool WriteEscapedText(const char* s, size_t length) {
+        for (size_t i = 0; i < length; i++) {
+            switch (s[i]) {
+                case '&': WriteString("&amp;"); break;
+                case '<': WriteString("&lt;"); break;
+                default: os_.Put(s[i]); break;
+            }
+        }
+        return true;
+    }
+
+    bool WriteStartElement(const char* type, bool emptyElement = false) {
+        if (level_ == 0)
+            if (!WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))
+                return false;
+
+        if (!WriteString("<json:") || !WriteString(type))
+            return false;
+
+        // For root element, need to add declarations
+        if (level_ == 0) {
+            if (!WriteString(
+                " xsi:schemaLocation=\"http://www.datapower.com/schemas/json 
jsonx.xsd\""
+                " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
+                " xmlns:json=\"http://www.ibm.com/xmlns/prod/2009/jsonx\"";))
+                return false;
+        }
+
+        if (hasName_) {
+            hasName_ = false;
+            if (!WriteString(" name=\"") ||
+                !WriteEscapedAttributeValue(name_.GetString(), 
name_.GetSize()) ||
+                !WriteString("\""))
+                return false;
+        }
+
+        if (emptyElement)
+            return WriteString("/>");
+        else {
+            level_++;
+            return WriteString(">");
+        }
+    }
+
+    bool WriteEndElement(const char* type) {
+        if (!WriteString("</json:") ||
+            !WriteString(type) ||
+            !WriteString(">"))
+            return false;
+
+        // For the last end tag, flush the output stream.
+        if (--level_ == 0)
+            os_.Flush();
+
+        return true;
+    }
+
+    bool WriteNumberElement(const char* buffer, int length) {
+        if (!WriteStartElement("number"))
+            return false;
+        for (int j = 0; j < length; j++)
+            os_.Put(buffer[j]);
+        return WriteEndElement("number");
+    }
+
+    OutputStream& os_;
+    StringBuffer name_;
+    unsigned level_;
+    bool hasName_;
+};
+
+int main(int, char*[]) {
+    // Prepare JSON reader and input stream.
+    Reader reader;
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    // Prepare JSON writer and output stream.
+    char writeBuffer[65536];
+    FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+    JsonxWriter<FileWriteStream> writer(os);
+
+    // JSON reader parse from the input stream and let writer generate the 
output.
+    if (!reader.Parse(is, writer)) {
+        fprintf(stderr, "\nError(%u): %s\n", 
static_cast<unsigned>(reader.GetErrorOffset()), 
GetParseError_En(reader.GetParseErrorCode()));
+        return 1;
+    }
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/example/messagereader/messagereader.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/example/messagereader/messagereader.cpp 
b/thirdparty/rapidjson-1.1.0/example/messagereader/messagereader.cpp
new file mode 100644
index 0000000..3399bc9
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/example/messagereader/messagereader.cpp
@@ -0,0 +1,105 @@
+// Reading a message JSON with Reader (SAX-style API).
+// The JSON should be an object with key-string pairs.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/error/en.h"
+#include <iostream>
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace rapidjson;
+
+typedef map<string, string> MessageMap;
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+struct MessageHandler
+    : public BaseReaderHandler<UTF8<>, MessageHandler> {
+    MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
+
+    bool StartObject() {
+        switch (state_) {
+        case kExpectObjectStart:
+            state_ = kExpectNameOrObjectEnd;
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool String(const char* str, SizeType length, bool) {
+        switch (state_) {
+        case kExpectNameOrObjectEnd:
+            name_ = string(str, length);
+            state_ = kExpectValue;
+            return true;
+        case kExpectValue:
+            messages_.insert(MessageMap::value_type(name_, string(str, 
length)));
+            state_ = kExpectNameOrObjectEnd;
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
+
+    bool Default() { return false; } // All other events are invalid.
+
+    MessageMap messages_;
+    enum State {
+        kExpectObjectStart,
+        kExpectNameOrObjectEnd,
+        kExpectValue
+    }state_;
+    std::string name_;
+};
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+static void ParseMessages(const char* json, MessageMap& messages) {
+    Reader reader;
+    MessageHandler handler;
+    StringStream ss(json);
+    if (reader.Parse(ss, handler))
+        messages.swap(handler.messages_);   // Only change it if success.
+    else {
+        ParseErrorCode e = reader.GetParseErrorCode();
+        size_t o = reader.GetErrorOffset();
+        cout << "Error: " << GetParseError_En(e) << endl;;
+        cout << " at offset " << o << " near '" << string(json).substr(o, 10) 
<< "...'" << endl;
+    }
+}
+
+int main() {
+    MessageMap messages;
+
+    const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : 
\"bye-bye!\" }";
+    cout << json1 << endl;
+    ParseMessages(json1, messages);
+
+    for (MessageMap::const_iterator itr = messages.begin(); itr != 
messages.end(); ++itr)
+        cout << itr->first << ": " << itr->second << endl;
+
+    cout << endl << "Parse a JSON with invalid schema." << endl;
+    const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : 
\"bye-bye!\", \"foo\" : {} }";
+    cout << json2 << endl;
+    ParseMessages(json2, messages);
+
+    return 0;
+}

Reply via email to