Thrift: Add a full-featured JSON protocol for C++.

Summary:
This change adds a new and exciting protocol to Thrift.  It uses
RFC-compliant JSON as the wire protocol and is fully human readable.
(once a little whitespace has been inserted.)  Unlike the existing
JSON protocol for Java, which is intended to allow Thrift data to be
transferred to scripting languages, this protocol is lossless and fully
read-write.  It was written by Chad Walters of Powerset and reviewed
by David Reiss.

Tested by running make check.


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665482 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift
index aa3ecef..bd13d44 100644
--- a/test/DebugProtoTest.thrift
+++ b/test/DebugProtoTest.thrift
@@ -1,5 +1,16 @@
 cpp_namespace thrift.test
 
+struct Doubles {
+ 1: double nan,
+ 2: double inf,
+ 3: double neginf,
+ 4: double repeating,
+ 5: double big,
+ 6: double small,
+ 7: double zero,
+ 8: double negzero,
+}
+
 struct OneOfEach {
   1: bool im_true,
   2: bool im_false,
@@ -11,6 +22,7 @@
   8: string some_characters,
   9: string zomg_unicode,
   10: bool what_who,
+  11: binary base64,
 }
 
 struct Bonk {
diff --git a/test/JSONProtoTest.cpp b/test/JSONProtoTest.cpp
new file mode 100644
index 0000000..077d2c4
--- /dev/null
+++ b/test/JSONProtoTest.cpp
@@ -0,0 +1,119 @@
+#include <iostream>
+#include <cmath>
+#include <transport/TTransportUtils.h>
+#include <protocol/TJSONProtocol.h>
+#include "gen-cpp/DebugProtoTest_types.h"
+
+int main() {
+  using std::cout;
+  using std::endl;
+  using namespace thrift::test;
+  using facebook::thrift::transport::TMemoryBuffer;
+  using facebook::thrift::protocol::TJSONProtocol;
+
+  OneOfEach ooe;
+  ooe.im_true   = true;
+  ooe.im_false  = false;
+  ooe.a_bite    = 0xd6;
+  ooe.integer16 = 27000;
+  ooe.integer32 = 1<<24;
+  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
+  ooe.double_precision = M_PI;
+  ooe.some_characters  = "JSON THIS! \"\1";
+  ooe.zomg_unicode     = "\xd7\n\a\t";
+  ooe.base64 = "\1\2\3\255";
+  cout << facebook::thrift::ThriftJSONString(ooe) << endl << endl;
+
+
+  Nesting n;
+  n.my_ooe = ooe;
+  n.my_ooe.integer16 = 16;
+  n.my_ooe.integer32 = 32;
+  n.my_ooe.integer64 = 64;
+  n.my_ooe.double_precision = (std::sqrt(5)+1)/2;
+  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
+  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
+                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
+                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
+  n.my_bonk.type    = 31337;
+  n.my_bonk.message = "I am a bonk... xor!";
+
+  cout << facebook::thrift::ThriftJSONString(n) << endl << endl;
+
+
+  HolyMoley hm;
+
+  hm.big.push_back(ooe);
+  hm.big.push_back(n.my_ooe);
+  hm.big[0].a_bite = 0x22;
+  hm.big[1].a_bite = 0x33;
+
+  std::vector<std::string> stage1;
+  stage1.push_back("and a one");
+  stage1.push_back("and a two");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  stage1.push_back("then a one, two");
+  stage1.push_back("three!");
+  stage1.push_back("FOUR!!");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  hm.contain.insert(stage1);
+
+  std::vector<Bonk> stage2;
+  hm.bonks["nothing"] = stage2;
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 1;
+  stage2.back().message = "Wait.";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 2;
+  stage2.back().message = "What?";
+  hm.bonks["something"] = stage2;
+  stage2.clear();
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 3;
+  stage2.back().message = "quoth";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 4;
+  stage2.back().message = "the raven";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 5;
+  stage2.back().message = "nevermore";
+  hm.bonks["poe"] = stage2;
+
+  cout << facebook::thrift::ThriftJSONString(hm) << endl << endl;
+
+  boost::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  boost::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+
+
+  cout << "Testing ooe" << endl;
+
+  ooe.write(proto.get());
+  OneOfEach ooe2;
+  ooe2.read(proto.get());
+
+  assert(ooe == ooe2);
+
+
+  cout << "Testing hm" << endl;
+
+  hm.write(proto.get());
+  HolyMoley hm2;
+  hm2.read(proto.get());
+
+  assert(hm == hm2);
+
+  Doubles dub;
+  dub.nan = HUGE_VAL/HUGE_VAL;
+  dub.inf = HUGE_VAL;
+  dub.neginf = -HUGE_VAL;
+  dub.repeating = 10.0/3.0;
+  dub.big = 1E+305;
+  dub.small = 1E-305;
+  dub.zero = 0.0;
+  dub.negzero = -0.0;
+  cout << facebook::thrift::ThriftJSONString(dub) << endl << endl;
+
+  return 0;
+}
diff --git a/test/Makefile.am b/test/Makefile.am
index 5fb3941..07c2e77 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,6 +2,7 @@
 
 check_PROGRAMS = \
 	DebugProtoTest \
+	JSONProtoTest \
 	OptionalRequiredTest \
 	ReflectionTest
 
@@ -21,6 +22,16 @@
 
 
 #
+# JSONProtoTest
+#
+JSONProtoTest_SOURCES = \
+	gen-cpp/DebugProtoTest_types.cpp \
+	JSONProtoTest.cpp
+
+JSONProtoTest_LDADD = \
+	$(top_srcdir)/lib/cpp/libthrift.la
+
+#
 # OptionalRequiredTest
 #
 OptionalRequiredTest_SOURCES = \