]> granicus.if.org Git - icinga2/commitdiff
Replace cJSON with YAJL
authorGunnar Beutner <gunnar@beutner.name>
Sun, 26 Oct 2014 18:59:49 +0000 (19:59 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Sun, 26 Oct 2014 19:00:35 +0000 (20:00 +0100)
fixes #7452

66 files changed:
lib/base/CMakeLists.txt
lib/base/array.cpp
lib/base/array.hpp
lib/base/dictionary.cpp
lib/base/dictionary.hpp
lib/base/dynamicobject.cpp
lib/base/dynamicobject.hpp
lib/base/json.cpp [new file with mode: 0644]
lib/base/json.hpp [new file with mode: 0644]
lib/base/scriptutils.cpp
lib/base/scriptvariable.cpp
lib/base/serializer.cpp
lib/base/serializer.hpp
lib/base/type.hpp
lib/base/value.cpp
lib/base/value.hpp
lib/cli/agentutility.cpp
lib/cli/objectlistcommand.cpp
lib/cli/repositoryutility.cpp
lib/cli/variablegetcommand.cpp
lib/cli/variablelistcommand.cpp
lib/config/configitem.cpp
lib/config/expression.cpp
lib/icinga/apievents.cpp
lib/icinga/host.cpp
lib/icinga/icingastatuswriter.cpp
lib/livestatus/livestatusquery.cpp
lib/remote/apilistener.cpp
lib/remote/jsonrpc.cpp
test/CMakeLists.txt
test/base-array.cpp
test/base-dictionary.cpp
test/base-json.cpp [new file with mode: 0644]
third-party/CMakeLists.txt
third-party/cJSON/CMakeLists.txt [deleted file]
third-party/cJSON/cJSON.c [deleted file]
third-party/cJSON/cJSON.h [deleted file]
third-party/yajl/.gitignore [new file with mode: 0644]
third-party/yajl/BUILDING [new file with mode: 0644]
third-party/yajl/BUILDING.win32 [new file with mode: 0644]
third-party/yajl/CMakeLists.txt [new file with mode: 0644]
third-party/yajl/COPYING [new file with mode: 0644]
third-party/yajl/ChangeLog [new file with mode: 0644]
third-party/yajl/README [new file with mode: 0644]
third-party/yajl/TODO [new file with mode: 0644]
third-party/yajl/src/CMakeLists.txt [new file with mode: 0644]
third-party/yajl/src/api/yajl_common.h [new file with mode: 0644]
third-party/yajl/src/api/yajl_gen.h [new file with mode: 0644]
third-party/yajl/src/api/yajl_parse.h [new file with mode: 0644]
third-party/yajl/src/api/yajl_tree.h [new file with mode: 0644]
third-party/yajl/src/api/yajl_version.h.cmake [new file with mode: 0644]
third-party/yajl/src/yajl.c [new file with mode: 0644]
third-party/yajl/src/yajl_alloc.c [new file with mode: 0644]
third-party/yajl/src/yajl_alloc.h [new file with mode: 0644]
third-party/yajl/src/yajl_buf.c [new file with mode: 0644]
third-party/yajl/src/yajl_buf.h [new file with mode: 0644]
third-party/yajl/src/yajl_bytestack.h [new file with mode: 0644]
third-party/yajl/src/yajl_encode.c [new file with mode: 0644]
third-party/yajl/src/yajl_encode.h [new file with mode: 0644]
third-party/yajl/src/yajl_gen.c [new file with mode: 0644]
third-party/yajl/src/yajl_lex.c [new file with mode: 0644]
third-party/yajl/src/yajl_lex.h [new file with mode: 0644]
third-party/yajl/src/yajl_parser.c [new file with mode: 0644]
third-party/yajl/src/yajl_parser.h [new file with mode: 0644]
third-party/yajl/src/yajl_tree.c [new file with mode: 0644]
third-party/yajl/src/yajl_version.c [new file with mode: 0644]

index 1c831ba24ae31e40d03f4e27311b45d430180643..8d2606cf2d8f30d2e572a6df519fa27bc6529041 100644 (file)
@@ -25,7 +25,7 @@ mkclass_target(sysloglogger.ti sysloglogger.thpp)
 set(base_SOURCES
   application.cpp application.thpp array.cpp configerror.cpp console.cpp context.cpp
   convert.cpp debuginfo.cpp dictionary.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp
-  exception.cpp fifo.cpp filelogger.cpp filelogger.thpp logger.cpp logger.thpp
+  exception.cpp fifo.cpp filelogger.cpp filelogger.thpp json.cpp logger.cpp logger.thpp
   netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp
   ringbuffer.cpp scriptfunction.cpp scriptfunctionwrapper.cpp
   scriptutils.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp
@@ -41,7 +41,7 @@ endif()
 
 add_library(base SHARED ${base_SOURCES})
 
-target_link_libraries(base ${CMAKE_DL_LIBS} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} cJSON mmatch)
+target_link_libraries(base ${CMAKE_DL_LIBS} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} mmatch yajl)
 
 if(HAVE_LIBEXECINFO)
     target_link_libraries(base execinfo)
@@ -56,6 +56,9 @@ link_directories(${icinga2_BINARY_DIR}/third-party/execvpe)
 include_directories(${icinga2_SOURCE_DIR}/third-party/mmatch)
 link_directories(${icinga2_BINARY_DIR}/third-party/mmatch)
 
+include_directories(${icinga2_BINARY_DIR}/third-party/yajl/yajl/include)
+link_directories(${icinga2_BINARY_DIR}/third-party/yajl)
+
 if(UNIX OR CYGWIN)
   target_link_libraries(base execvpe)
 endif()
index 924eaf27906f4b30ac90b339ccbc079c1f7265f2..b352e6ec44b66215cf1b0e42b1462867c15ea21f 100644 (file)
@@ -20,7 +20,6 @@
 #include "base/array.hpp"
 #include "base/objectlock.hpp"
 #include "base/debug.hpp"
-#include <cJSON.h>
 #include <boost/foreach.hpp>
 
 using namespace icinga;
@@ -198,46 +197,3 @@ Array::Ptr Array::ShallowClone(void) const
        CopyTo(clone);
        return clone;
 }
-
-/**
- * Converts a JSON object to an array.
- *
- * @param json The JSON object.
- * @returns An array that is equivalent to the JSON object.
- */
-Array::Ptr Array::FromJson(cJSON *json)
-{
-       Array::Ptr array = make_shared<Array>();
-
-       ASSERT(json->type == cJSON_Array);
-
-       for (cJSON *i = json->child; i != NULL; i = i->next) {
-               array->Add(Value::FromJson(i));
-       }
-
-       return array;
-}
-
-/**
- * Converts this array to a JSON object.
- *
- * @returns A JSON object that is equivalent to the array. Values that
- *         cannot be represented in JSON are omitted.
- */
-cJSON *Array::ToJson(void) const
-{
-       cJSON *json = cJSON_CreateArray();
-
-       try {
-               ObjectLock olock(this);
-
-               BOOST_FOREACH(const Value& value, m_Data) {
-                       cJSON_AddItemToArray(json, value.ToJson());
-               }
-       } catch (...) {
-               cJSON_Delete(json);
-               throw;
-       }
-
-       return json;
-}
index 5e0602106db5517b0366e9d36a8f1ade4c59008c..bfbea258847a9075c110c4d3b732ebc3b1012bd9 100644 (file)
@@ -65,9 +65,6 @@ public:
        void CopyTo(const Array::Ptr& dest) const;
        Array::Ptr ShallowClone(void) const;
 
-       static Array::Ptr FromJson(cJSON *json);
-       cJSON *ToJson(void) const;
-
 private:
        std::vector<Value> m_Data; /**< The data for the array. */
 };
index 4362a13d7661b6b869d1d66f727bb6e41593dc0f..cec0961a1c20bd1ea9860a853757f3e0cea3b6f0 100644 (file)
@@ -20,7 +20,6 @@
 #include "base/dictionary.hpp"
 #include "base/objectlock.hpp"
 #include "base/debug.hpp"
-#include <cJSON.h>
 #include <boost/foreach.hpp>
 
 using namespace icinga;
@@ -213,46 +212,3 @@ Dictionary::Ptr Dictionary::ShallowClone(void) const
        CopyTo(clone);
        return clone;
 }
-
-/**
- * Converts a JSON object to a dictionary.
- *
- * @param json The JSON object.
- * @returns A dictionary that is equivalent to the JSON object.
- */
-Dictionary::Ptr Dictionary::FromJson(cJSON *json)
-{
-       Dictionary::Ptr dictionary = make_shared<Dictionary>();
-
-       ASSERT(json->type == cJSON_Object);
-
-       for (cJSON *i = json->child; i != NULL; i = i->next) {
-               dictionary->Set(i->string, Value::FromJson(i));
-       }
-
-       return dictionary;
-}
-
-/**
- * Converts this dictionary to a JSON object.
- *
- * @returns A JSON object that is equivalent to the dictionary. Values that
- *         cannot be represented in JSON are omitted.
- */
-cJSON *Dictionary::ToJson(void) const
-{
-       cJSON *json = cJSON_CreateObject();
-
-       try {
-               ObjectLock olock(this);
-
-               BOOST_FOREACH(const Dictionary::Pair& kv, m_Data) {
-                       cJSON_AddItemToObject(json, kv.first.CStr(), kv.second.ToJson());
-               }
-       } catch (...) {
-               cJSON_Delete(json);
-               throw;
-       }
-
-       return json;
-}
index ccce691b6c113dcc4c2051a674483f8ee7152bdd..754182b1c4fce0be02b8480653abc06c06e294f7 100644 (file)
@@ -64,9 +64,6 @@ public:
        void CopyTo(const Dictionary::Ptr& dest) const;
        Dictionary::Ptr ShallowClone(void) const;
 
-       static Dictionary::Ptr FromJson(cJSON *json);
-       cJSON *ToJson(void) const;
-
 private:
        std::map<String, Value> m_Data; /**< The data for the dictionary. */
 };
index 919ee059980e945aa56d8272ef8235ac2d89beeb..0d5d0d8b60c0fe680d52362f05032c70c88d7d67 100644 (file)
@@ -21,6 +21,7 @@
 #include "base/dynamictype.hpp"
 #include "base/serializer.hpp"
 #include "base/netstring.hpp"
+#include "base/json.hpp"
 #include "base/stdiostream.hpp"
 #include "base/debug.hpp"
 #include "base/objectlock.hpp"
@@ -266,7 +267,7 @@ void DynamicObject::DumpObjects(const String& filename, int attributeTypes)
 
                        persistentObject->Set("update", update);
 
-                       String json = JsonSerialize(persistentObject);
+                       String json = JsonEncode(persistentObject);
 
                        NetString::WriteStringToStream(sfp, json);
                }
@@ -290,7 +291,7 @@ void DynamicObject::DumpObjects(const String& filename, int attributeTypes)
 
 void DynamicObject::RestoreObject(const String& message, int attributeTypes)
 {
-       Dictionary::Ptr persistentObject = JsonDeserialize(message);
+       Dictionary::Ptr persistentObject = JsonDecode(message);
 
        String type = persistentObject->Get("type");
 
index 1b64b0d2caca5d6bc55e600fa493985e096904f8..68611f89ab726bbe16f67924020687b709b83e11 100644 (file)
@@ -23,7 +23,7 @@
 #include "base/i2-base.hpp"
 #include "base/dynamicobject.thpp"
 #include "base/object.hpp"
-#include "base/serializer.hpp"
+#include "base/type.hpp"
 #include "base/dictionary.hpp"
 #include "base/debuginfo.hpp"
 #include <boost/signals2.hpp>
diff --git a/lib/base/json.cpp b/lib/base/json.cpp
new file mode 100644 (file)
index 0000000..cd5d30d
--- /dev/null
@@ -0,0 +1,338 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#include "base/json.hpp"
+#include "base/debug.hpp"
+#include "base/dictionary.hpp"
+#include "base/array.hpp"
+#include "base/objectlock.hpp"
+#include "base/convert.hpp"
+#include <boost/foreach.hpp>
+#include <boost/exception_ptr.hpp>
+#include <yajl/yajl_gen.h>
+#include <yajl/yajl_parse.h>
+#include <stack>
+
+using namespace icinga;
+
+static void Encode(yajl_gen handle, const Value& value);
+
+static void EncodeDictionary(yajl_gen handle, const Dictionary::Ptr& dict)
+{
+       yajl_gen_map_open(handle);
+
+       ObjectLock olock(dict);
+       BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
+               yajl_gen_string(handle, reinterpret_cast<const unsigned char *>(kv.first.CStr()), kv.first.GetLength());
+               Encode(handle, kv.second);
+       }
+
+       yajl_gen_map_close(handle);
+}
+
+static void EncodeArray(yajl_gen handle, const Array::Ptr& arr)
+{
+       yajl_gen_array_open(handle);
+
+       ObjectLock olock(arr);
+       BOOST_FOREACH(const Value& value, arr) {
+               Encode(handle, value);
+       }
+
+       yajl_gen_array_close(handle);
+}
+
+static void Encode(yajl_gen handle, const Value& value)
+{
+       String str;
+
+       switch (value.GetType()) {
+               case ValueNumber:
+                       if (yajl_gen_double(handle, static_cast<double>(value)) == yajl_gen_invalid_number)
+                               yajl_gen_double(handle, 0);
+
+                       break;
+               case ValueString:
+                       str = value;
+                       yajl_gen_string(handle, reinterpret_cast<const unsigned char *>(str.CStr()), str.GetLength());
+
+                       break;
+               case ValueObject:
+                       if (value.IsObjectType<Dictionary>())
+                               EncodeDictionary(handle, value);
+                       else if (value.IsObjectType<Array>())
+                               EncodeArray(handle, value);
+                       else
+                               yajl_gen_null(handle);
+
+                       break;
+               case ValueEmpty:
+                       yajl_gen_null(handle);
+
+                       break;
+               default:
+                       VERIFY(!"Invalid variant type.");
+       }
+}
+
+String icinga::JsonEncode(const Value& value)
+{
+       yajl_gen handle = yajl_gen_alloc(NULL);
+       Encode(handle, value);
+
+       const unsigned char *buf;
+       size_t len;
+       yajl_gen_get_buf(handle, &buf, &len);
+
+       String result = String(buf, buf + len);
+
+       yajl_gen_free(handle);
+
+       return result;
+}
+
+struct JsonElement
+{
+       String Key;
+       bool KeySet;
+       Value Value;
+
+       JsonElement(void)
+               : KeySet(false)
+       { }
+};
+
+struct JsonContext
+{
+public:
+       void Push(const Value& value)
+       {
+               JsonElement element;
+               element.Value = value;
+
+               m_Stack.push(element);
+       }
+
+       JsonElement Pop(void)
+       {
+               JsonElement value = m_Stack.top();
+               m_Stack.pop();
+               return value;
+       }
+
+       void AddValue(const Value& value)
+       {
+               if (m_Stack.empty()) {
+                       JsonElement element;
+                       element.Value = value;
+                       m_Stack.push(element);
+                       return;
+               }
+
+               JsonElement& element = m_Stack.top();
+
+               if (element.Value.IsObjectType<Dictionary>()) {
+                       if (!element.KeySet) {
+                               element.Key = value;
+                               element.KeySet = true;
+                       } else {
+                               Dictionary::Ptr dict = element.Value;
+                               dict->Set(element.Key, value);
+                               element.KeySet = false;
+                       }
+               } else if (element.Value.IsObjectType<Array>()) {
+                       Array::Ptr arr = element.Value;
+                       arr->Add(value);
+               } else {
+                       BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot add value to JSON element."));
+               }
+       }
+
+       Value GetValue(void) const
+       {
+               ASSERT(m_Stack.size() == 1);
+               return m_Stack.top().Value;
+       }
+
+       void SaveException(void)
+       {
+               m_Exception = boost::current_exception();
+       }
+
+       void ThrowException(void) const
+       {
+               boost::rethrow_exception(m_Exception);
+       }
+
+private:
+       std::stack<JsonElement> m_Stack;
+       Value m_Key;
+       boost::exception_ptr m_Exception;
+};
+
+static int DecodeNull(void *ctx)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+
+       try {
+               context->AddValue(Empty);
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+static int DecodeBoolean(void *ctx, int value)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+
+       try {
+               context->AddValue(value);
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+static int DecodeNumber(void *ctx, const char *str, size_t len)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+
+       try {
+               String jstr = String(str, str + len);
+               context->AddValue(Convert::ToDouble(jstr));
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+static int DecodeString(void *ctx, const unsigned char *str, size_t len)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+
+       try {
+               context->AddValue(String(reinterpret_cast<const char *>(str), reinterpret_cast<const char *>(str) + len));
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+static int DecodeStartMap(void *ctx)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+
+       try {
+               context->Push(make_shared<Dictionary>());
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+static int DecodeEndMap(void *ctx)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+
+       try {
+               context->AddValue(context->Pop().Value);
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+static int DecodeStartArray(void *ctx)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+       
+       try {
+               context->Push(make_shared<Array>());
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+static int DecodeEndArray(void *ctx)
+{
+       JsonContext *context = static_cast<JsonContext *>(ctx);
+
+       try {
+               context->AddValue(context->Pop().Value);
+       } catch (...) {
+               context->SaveException();
+               return 0;
+       }
+
+       return 1;
+}
+
+Value icinga::JsonDecode(const String& data)
+{
+       static const yajl_callbacks callbacks = {
+               DecodeNull,
+               DecodeBoolean,
+               NULL,
+               NULL,
+               DecodeNumber,
+               DecodeString,
+               DecodeStartMap,
+               DecodeString,
+               DecodeEndMap,
+               DecodeStartArray,
+               DecodeEndArray
+       };
+
+       yajl_handle handle;
+       JsonContext context;
+
+       handle = yajl_alloc(&callbacks, NULL, &context);
+
+       yajl_parse(handle, reinterpret_cast<const unsigned char *>(data.CStr()), data.GetLength());
+
+       if (yajl_complete_parse(handle) != yajl_status_ok) {
+               unsigned char *internal_err_str = yajl_get_error(handle, 1, reinterpret_cast<const unsigned char *>(data.CStr()), data.GetLength());
+               String msg = reinterpret_cast<char *>(internal_err_str);
+               yajl_free_error(handle, internal_err_str);
+
+               yajl_free(handle);
+
+               BOOST_THROW_EXCEPTION(std::invalid_argument(msg));
+       }
+
+       yajl_free(handle);
+
+       return context.GetValue();
+}
diff --git a/lib/base/json.hpp b/lib/base/json.hpp
new file mode 100644 (file)
index 0000000..62f37aa
--- /dev/null
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#ifndef JSON_H
+#define JSON_H
+
+#include "base/i2-base.hpp"
+#include "base/value.hpp"
+
+namespace icinga
+{
+
+I2_BASE_API String JsonEncode(const Value& value);
+I2_BASE_API Value JsonDecode(const String& data);
+
+}
+
+#endif /* JSON_H */
index c24e3ba7538ce2c432c0319e66b8756a38108b43..a4573ff661242567168144137c435da264071eb9 100644 (file)
@@ -23,7 +23,7 @@
 #include "base/convert.hpp"
 #include "base/array.hpp"
 #include "base/dictionary.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/logger.hpp"
 #include <boost/foreach.hpp>
 #include <boost/regex.hpp>
@@ -135,7 +135,7 @@ void ScriptUtils::Log(const std::vector<Value>& arguments)
        if (message.IsString())
                ::Log(severity, facility, message);
        else
-               ::Log(severity, facility, JsonSerialize(message));
+               ::Log(severity, facility, JsonEncode(message));
 }
 
 Array::Ptr ScriptUtils::Range(const std::vector<Value>& arguments)
index ef131fb50c2565f268391dbe2350ca84e5678847..f730c1f93e667125e09297b248a0757e85950a2e 100644 (file)
@@ -22,6 +22,7 @@
 #include "base/logger.hpp"
 #include "base/stdiostream.hpp"
 #include "base/netstring.hpp"
+#include "base/json.hpp"
 #include "base/convert.hpp"
 #include <boost/foreach.hpp>
 #include <fstream>
@@ -124,7 +125,7 @@ void ScriptVariable::WriteVariablesFile(const String& filename)
 
                persistentVariable->Set("value", value);
 
-               String json = JsonSerialize(persistentVariable);
+               String json = JsonEncode(persistentVariable);
 
                NetString::WriteStringToStream(sfp, json);
        }
index aee604350d26d6f75aa09f30a9cb3f6e1f6d577b..196adc77b06713174b1f2e4a08dcd085e17b67fe 100644 (file)
 #include "base/application.hpp"
 #include "base/objectlock.hpp"
 #include <boost/foreach.hpp>
-#include <cJSON.h>
 
 using namespace icinga;
 
-/**
- * Serializes a Value into a JSON string.
- *
- * @returns A string representing the Value.
- */
-String icinga::JsonSerialize(const Value& value)
-{
-       cJSON *json = value.ToJson();
-
-       char *jsonString;
-
-#ifdef _DEBUG
-       jsonString = cJSON_Print(json);
-#else /* _DEBUG */
-       jsonString = cJSON_PrintUnformatted(json);
-#endif /* _DEBUG */
-
-       cJSON_Delete(json);
-
-       String result = jsonString;
-
-       free(jsonString);
-
-       return result;
-}
-
-/**
- * Deserializes the string representation of a Value.
- *
- * @param data A JSON string obtained from JsonSerialize
- * @returns The newly deserialized Value.
- */
-Value icinga::JsonDeserialize(const String& data)
-{
-       cJSON *json = cJSON_Parse(data.CStr());
-
-       if (!json)
-               BOOST_THROW_EXCEPTION(std::runtime_error("Invalid JSON String: " + data));
-
-       Value value = Value::FromJson(json);
-       cJSON_Delete(json);
-
-       return value;
-}
-
 static Array::Ptr SerializeArray(const Array::Ptr& input, int attributeTypes)
 {
        Array::Ptr result = make_shared<Array>();
index ce0f8cae23ff52c924b69d33b812c5c4beb1b178..ed9cc8616f182bfed5ea42bae57030ae5d61417f 100644 (file)
 #define SERIALIZER_H
 
 #include "base/i2-base.hpp"
+#include "base/type.hpp"
 #include "base/value.hpp"
 
 namespace icinga
 {
 
-enum FieldAttribute
-{
-       FAConfig = 1,
-       FAState = 2
-};
-
-I2_BASE_API String JsonSerialize(const Value& value);
-I2_BASE_API Value JsonDeserialize(const String& data);
-
 I2_BASE_API Value Serialize(const Value& value, int attributeTypes = FAState);
 I2_BASE_API Value Deserialize(const Value& value, bool safe_mode = false, int attributeTypes = FAState);
 I2_BASE_API Value Deserialize(const Object::Ptr& object, const Value& value, bool safe_mode = false, int attributeTypes = FAState);
index da9baac64ec95e6e00da16537917241c07bdc044..f26b3fcee60d1bb9023fefaf9fe45b64baac2ed9 100644 (file)
 namespace icinga
 {
 
+enum FieldAttribute
+{
+       FAConfig = 1,
+       FAState = 2
+}; 
+       
 struct Field
 {
        int ID;
index b4d1984a66ffef7aefcebc1eabdb38db40af2501..9dff7cee23ec76ee4896427469c8cdd30bbca52f 100644 (file)
@@ -21,7 +21,6 @@
 #include "base/array.hpp"
 #include "base/dictionary.hpp"
 #include "base/type.hpp"
-#include <cJSON.h>
 
 using namespace icinga;
 
@@ -137,65 +136,6 @@ bool Value::ToBool(void) const
        }
 }
 
-
-/**
- * Converts a JSON object into a variant.
- *
- * @param json The JSON object.
- */
-Value Value::FromJson(cJSON *json)
-{
-       if (json->type == cJSON_Number)
-               return json->valuedouble;
-       else if (json->type == cJSON_String)
-               return String(json->valuestring);
-       else if (json->type == cJSON_True)
-               return 1;
-       else if (json->type == cJSON_False)
-               return 0;
-       else if (json->type == cJSON_Object)
-               return Dictionary::FromJson(json);
-       else if (json->type == cJSON_Array)
-               return Array::FromJson(json);
-       else if (json->type == cJSON_NULL)
-               return Value();
-       else
-               BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported JSON type."));
-}
-
-/**
- * Serializes the variant.
- *
- * @returns A JSON object representing this variant.
- */
-cJSON *Value::ToJson(void) const
-{
-       switch (GetType()) {
-               case ValueNumber:
-                       return cJSON_CreateNumber(boost::get<double>(m_Value));
-
-               case ValueString:
-                       return cJSON_CreateString(boost::get<String>(m_Value).CStr());
-
-               case ValueObject:
-                       if (IsObjectType<Dictionary>()) {
-                               Dictionary::Ptr dictionary = *this;
-                               return dictionary->ToJson();
-                       } else if (IsObjectType<Array>()) {
-                               Array::Ptr array = *this;
-                               return array->ToJson();
-                       } else {
-                               return cJSON_CreateNull();
-                       }
-
-               case ValueEmpty:
-                       return cJSON_CreateNull();
-
-               default:
-                       BOOST_THROW_EXCEPTION(std::runtime_error("Invalid variant type."));
-       }
-}
-
 /**
  * Returns the type of the value.
  *
index 375e7b2da2c4a7bb1005582a9f4c63eaba0c7ea8..e2ce64e59d8001281aae379147a073662bf3c706 100644 (file)
@@ -126,9 +126,6 @@ public:
                return (dynamic_pointer_cast<T>(boost::get<Object::Ptr>(m_Value)) != NULL);
        }
 
-       static Value FromJson(cJSON *json);
-       cJSON *ToJson(void) const;
-
        ValueType GetType(void) const;
        String GetTypeName(void) const;
 
index f2647a3932beb8d9e19ec0e955d5ea5ba5f8926c..94ac0d17d51709863783c9576e47b9a3b7c1b860 100644 (file)
@@ -23,7 +23,7 @@
 #include "base/application.hpp"
 #include "base/tlsutility.hpp"
 #include "base/convert.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/netstring.hpp"
 #include "base/stdiostream.hpp"
 #include "base/debug.hpp"
@@ -112,7 +112,7 @@ void AgentUtility::PrintAgentsJson(std::ostream& fp)
                result->Set(agent->Get("endpoint"), agent);
        }
 
-       fp << JsonSerialize(result);
+       fp << JsonEncode(result);
 }
 
 bool AgentUtility::AddAgent(const String& name)
@@ -206,7 +206,7 @@ bool AgentUtility::WriteAgentToRepository(const String& filename, const Dictiona
        String tempFilename = filename + ".tmp";
 
        std::ofstream fp(tempFilename.CStr(), std::ofstream::out | std::ostream::trunc);
-       fp << JsonSerialize(item);
+       fp << JsonEncode(item);
        fp.close();
 
 #ifdef _WIN32
@@ -235,7 +235,7 @@ Dictionary::Ptr AgentUtility::GetAgentFromRepository(const String& filename)
 
        fp.close();
 
-       return JsonDeserialize(content);
+       return JsonDecode(content);
 }
 
 std::vector<Dictionary::Ptr> AgentUtility::GetAgents(void)
index 63e1e7b53fb4e021f7ab1f8c186033eb1c20cf10..28c4a4652347db22c3341e11537f497e58d6ed54 100644 (file)
@@ -23,7 +23,7 @@
 #include "base/convert.hpp"
 #include "base/dynamicobject.hpp"
 #include "base/dynamictype.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/netstring.hpp"
 #include "base/stdiostream.hpp"
 #include "base/debug.hpp"
@@ -116,7 +116,7 @@ int ObjectListCommand::Run(const boost::program_options::variables_map& vm, cons
 
 void ObjectListCommand::PrintObject(std::ostream& fp, bool& first, const String& message, std::map<String, int>& type_count, const String& name_filter, const String& type_filter)
 {
-       Dictionary::Ptr object = JsonDeserialize(message);
+       Dictionary::Ptr object = JsonDecode(message);
 
        Dictionary::Ptr properties = object->Get("properties");
 
index fef05aa8a403c2be7efe53f30b3e77ec3c2c4ee2..3b9558c46db94d8a5aeac61e0086a960d131668d 100644 (file)
@@ -22,7 +22,7 @@
 #include "base/logger.hpp"
 #include "base/application.hpp"
 #include "base/convert.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/netstring.hpp"
 #include "base/stdiostream.hpp"
 #include "base/debug.hpp"
@@ -101,7 +101,7 @@ void RepositoryUtility::PrintObjects(std::ostream& fp, const String& type)
 
                if (obj) {
                        fp << "Object Name: " << object << "\n";
-                       fp << JsonSerialize(obj);
+                       fp << JsonEncode(obj);
                }
        }
 }
@@ -157,7 +157,7 @@ void RepositoryUtility::PrintChangeLog(std::ostream& fp)
        std::cout << "Changes to be committed:\n";
 
        BOOST_FOREACH(const Value& entry, changelog) {
-               std::cout << JsonSerialize(entry) << "\n"; //TODO better formatting
+               std::cout << JsonEncode(entry) << "\n"; //TODO better formatting
        }
 }
 
@@ -267,7 +267,7 @@ bool RepositoryUtility::WriteObjectToRepositoryChangeLog(const String& path, con
        String tempPath = path + ".tmp";
 
         std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc);
-        fp << JsonSerialize(item);
+        fp << JsonEncode(item);
         fp.close();
 
 #ifdef _WIN32
@@ -296,7 +296,7 @@ Dictionary::Ptr RepositoryUtility::GetObjectFromRepositoryChangeLog(const String
 
        fp.close();
 
-       return JsonDeserialize(content);
+       return JsonDecode(content);
 }
 
 /*
index 82d43af2fd1eaa3e5f3a1ff52efe1dc79b64e45f..d204f550ff7322db0c4afdf05afb8dcc3df87f52 100644 (file)
@@ -23,7 +23,7 @@
 #include "base/convert.hpp"
 #include "base/dynamicobject.hpp"
 #include "base/dynamictype.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/netstring.hpp"
 #include "base/stdiostream.hpp"
 #include "base/debug.hpp"
@@ -92,7 +92,7 @@ int VariableGetCommand::Run(const boost::program_options::variables_map& vm, con
        String message;
 
        while (NetString::ReadStringFromStream(sfp, &message))  {
-               Dictionary::Ptr variable = JsonDeserialize(message);
+               Dictionary::Ptr variable = JsonDecode(message);
 
                if (variable->Get("name") == ap[0]) {
                        std::cout << variable->Get("value") << "\n";
index 3deb62fc142c2900c5d1f91a1f3e15ccd331d14f..e3c0bbfe1b192327a7a82ba77ea881551276d1a2 100644 (file)
@@ -23,7 +23,7 @@
 #include "base/convert.hpp"
 #include "base/dynamicobject.hpp"
 #include "base/dynamictype.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/netstring.hpp"
 #include "base/stdiostream.hpp"
 #include "base/debug.hpp"
@@ -90,7 +90,7 @@ int VariableListCommand::Run(const boost::program_options::variables_map& vm, co
 
 void VariableListCommand::PrintVariable(std::ostream& fp, const String& message)
 {
-       Dictionary::Ptr variable = JsonDeserialize(message);
+       Dictionary::Ptr variable = JsonDecode(message);
 
        std::cout << variable->Get("name") << " = " << variable->Get("value") << "\n";
 }
index 7dd1a78160602455fdfd20ac5fd5074e8b77c62d..67b288ba87256fe7de29065194dec0c9b3815f15 100644 (file)
@@ -32,6 +32,7 @@
 #include "base/exception.hpp"
 #include "base/stdiostream.hpp"
 #include "base/netstring.hpp"
+#include "base/json.hpp"
 #include "base/configerror.hpp"
 #include <sstream>
 #include <fstream>
@@ -310,7 +311,7 @@ void ConfigItem::WriteObjectsFile(const String& filename)
                }
                persistentItem->Set("debug_hints", item->GetDebugHints());
 
-               String json = JsonSerialize(persistentItem);
+               String json = JsonEncode(persistentItem);
 
                NetString::WriteStringToStream(sfp, json);
        }
index 3e0b1957215df6d9f3815ea86d004666c1d6508e..a8d4513c90cf7341f3b7e3e91b65a7ed24a21f60 100644 (file)
@@ -23,7 +23,7 @@
 #include "config/applyrule.hpp"
 #include "config/objectrule.hpp"
 #include "base/array.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/scriptfunction.hpp"
 #include "base/scriptvariable.hpp"
 #include "base/utility.hpp"
@@ -84,7 +84,7 @@ void Expression::DumpOperand(std::ostream& stream, const Value& operand, int ind
                Expression::Ptr left = operand;
                left->Dump(stream, indent);
        } else {
-               stream << String(indent, ' ') << JsonSerialize(operand) << "\n";
+               stream << String(indent, ' ') << JsonEncode(operand) << "\n";
        }
 }
 
@@ -215,7 +215,7 @@ Value Expression::OpIn(const Expression *expr, const Dictionary::Ptr& locals, De
        if (right.IsEmpty())
                return false;
        else if (!right.IsObjectType<Array>())
-               BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
+               BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonEncode(right)));
 
        Value left = expr->EvaluateOperand1(locals);
                
index c9aa173f331d1f9aa31c08b96869666f384b5b23..c4fe5098338dddaa9e84642976fcc1f376dba3ff 100644 (file)
@@ -29,6 +29,8 @@
 #include "base/utility.hpp"
 #include "base/exception.hpp"
 #include "base/initialize.hpp"
+#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include <fstream>
 
 using namespace icinga;
@@ -1540,7 +1542,7 @@ Value ApiEvents::UpdateRepositoryAPIHandler(const MessageOrigin& origin, const D
        String repositoryTempFile = repositoryFile + ".tmp";
 
        std::ofstream fp(repositoryTempFile.CStr(), std::ofstream::out | std::ostream::trunc);
-       fp << JsonSerialize(params);
+       fp << JsonEncode(params);
        fp.close();
 
 #ifdef _WIN32
index 52cdd76587681bd822a605edb573a56b60906ee6..b21cc3f4df017f490677bdfd9c92b0263520f6de 100644 (file)
@@ -25,7 +25,7 @@
 #include "base/convert.hpp"
 #include "base/utility.hpp"
 #include "base/debug.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include <boost/foreach.hpp>
 
 using namespace icinga;
@@ -123,7 +123,7 @@ Service::Ptr Host::GetServiceByShortName(const Value& name)
 
                return Service::GetByNamePair(dict->Get("host"), dict->Get("service"));
        } else {
-               BOOST_THROW_EXCEPTION(std::invalid_argument("Host/Service name pair is invalid: " + JsonSerialize(name)));
+               BOOST_THROW_EXCEPTION(std::invalid_argument("Host/Service name pair is invalid: " + JsonEncode(name)));
        }
 }
 
index ac49481312f44490c8246bd48c9914265fea40a3..9f10b7d792a06a82696b73515d49f9f5d0016a98 100644 (file)
@@ -24,6 +24,7 @@
 #include "base/exception.hpp"
 #include "base/application.hpp"
 #include "base/statsfunction.hpp"
+#include "base/json.hpp"
 #include <boost/foreach.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <fstream>
@@ -151,7 +152,7 @@ void IcingaStatusWriter::StatusTimerHandler(void)
 
        statusfp << std::fixed;
 
-       statusfp << JsonSerialize(GetStatusData());
+       statusfp << JsonEncode(GetStatusData());
 
        statusfp.close();
 
index 44a522cfddbca43f720bcd321ee98a2930f30c22..0b3e5dec1b6c2190018e641c67a421ee5581ee47 100644 (file)
@@ -37,7 +37,7 @@
 #include "base/logger.hpp"
 #include "base/exception.hpp"
 #include "base/utility.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/foreach.hpp>
 #include <boost/algorithm/string/replace.hpp>
@@ -382,7 +382,7 @@ void LivestatusQuery::PrintResultSet(std::ostream& fp, const Array::Ptr& rs) con
                        fp << m_Separators[0];
                }
        } else if (m_OutputFormat == "json") {
-               fp << JsonSerialize(rs);
+               fp << JsonEncode(rs);
        } else if (m_OutputFormat == "python") {
                PrintPythonArray(fp, rs);
        }
index 5dc67dc7fd53a53fb4669f44689a5b89cdf3908e..da204dd96ce003e17cc74f38dc2f6ae7f1400089 100644 (file)
@@ -22,6 +22,7 @@
 #include "remote/endpoint.hpp"
 #include "base/convert.hpp"
 #include "base/netstring.hpp"
+#include "base/json.hpp"
 #include "base/dynamictype.hpp"
 #include "base/logger.hpp"
 #include "base/objectlock.hpp"
@@ -461,7 +462,7 @@ void ApiListener::PersistMessage(const Dictionary::Ptr& message, const DynamicOb
        Dictionary::Ptr pmessage = make_shared<Dictionary>();
        pmessage->Set("timestamp", ts);
 
-       pmessage->Set("message", JsonSerialize(message));
+       pmessage->Set("message", JsonEncode(message));
        
        Dictionary::Ptr secname = make_shared<Dictionary>();
        secname->Set("type", secobj->GetType()->GetName());
@@ -470,7 +471,7 @@ void ApiListener::PersistMessage(const Dictionary::Ptr& message, const DynamicOb
 
        boost::mutex::scoped_lock lock(m_LogLock);
        if (m_LogFile) {
-               NetString::WriteStringToStream(m_LogFile, JsonSerialize(pmessage));
+               NetString::WriteStringToStream(m_LogFile, JsonEncode(pmessage));
                m_LogMessageCount++;
                SetLogMessageTimestamp(ts);
 
@@ -683,7 +684,7 @@ void ApiListener::ReplayLog(const ApiClient::Ptr& client)
                                        if (!NetString::ReadStringFromStream(logStream, &message))
                                                break;
 
-                                       pmessage = JsonDeserialize(message);
+                                       pmessage = JsonDecode(message);
                                } catch (const std::exception&) {
                                        Log(LogWarning, "ApiListener")
                                            << "Unexpected end-of-file for cluster log: " << path;
index 1ee32d703f6de4af62fe977b67397ffc2d8baaf8..bee339e1e02cd17e1cbfb38ee55bc4fb2ec33594 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "remote/jsonrpc.hpp"
 #include "base/netstring.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 //#include <iostream>
 
 using namespace icinga;
@@ -31,7 +31,7 @@ using namespace icinga;
  */
 void JsonRpc::SendMessage(const Stream::Ptr& stream, const Dictionary::Ptr& message)
 {
-       String json = JsonSerialize(message);
+       String json = JsonEncode(message);
        //std::cerr << ">> " << json << std::endl;
        NetString::WriteStringToStream(stream, json);
 }
@@ -43,7 +43,7 @@ Dictionary::Ptr JsonRpc::ReadMessage(const Stream::Ptr& stream)
                return Dictionary::Ptr();
 
        //std::cerr << "<< " << jsonString << std::endl;
-       Value value = JsonDeserialize(jsonString);
+       Value value = JsonDecode(jsonString);
 
        if (!value.IsObjectType<Dictionary>()) {
                BOOST_THROW_EXCEPTION(std::invalid_argument("JSON-RPC"
index fc331fcac18978b94a8153d12fd470d7fe71b082..d2e158b5218eede872444d37b88b6089be868375 100644 (file)
@@ -19,10 +19,10 @@ include(BoostTestTargets)
 
 set(base_test_SOURCES
   base-array.cpp base-convert.cpp base-dictionary.cpp base-fifo.cpp
-  base-match.cpp base-netstring.cpp base-object.cpp base-serialize.cpp
-  base-shellescape.cpp base-stacktrace.cpp base-stream.cpp
-  base-string.cpp base-timer.cpp base-type.cpp base-value.cpp
-  icinga-perfdata.cpp test.cpp
+  base-json.cpp base-match.cpp base-netstring.cpp base-object.cpp
+  base-serialize.cpp base-shellescape.cpp base-stacktrace.cpp
+  base-stream.cpp base-string.cpp base-timer.cpp base-type.cpp
+  base-value.cpp icinga-perfdata.cpp test.cpp
 )
 
 set_property(SOURCE test.cpp PROPERTY EXCLUDE_UNITY_BUILD TRUE)
@@ -54,6 +54,7 @@ add_boost_test(base
         base_dictionary/json
         base_fifo/construct
         base_fifo/io
+        base_json/invalid1
         base_match/tolong
         base_netstring/netstring
         base_object/construct
index da84eebdd5e073f3f17df1ba98ba91ce7b79aa6a..e58cc9e2136a1f97f3bf06b52473da30d0a246c2 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "base/array.hpp"
 #include "base/objectlock.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
 
@@ -133,10 +133,10 @@ BOOST_AUTO_TEST_CASE(json)
        array->Add(2);
        array->Add(5);
 
-       String json = JsonSerialize(array);
+       String json = JsonEncode(array);
        BOOST_CHECK(json.GetLength() > 0);
 
-       Array::Ptr deserialized = JsonDeserialize(json);
+       Array::Ptr deserialized = JsonDecode(json);
        BOOST_CHECK(deserialized);
        BOOST_CHECK(deserialized->GetLength() == 3);
        BOOST_CHECK(deserialized->Get(0) == 7);
index eed1229c6c993ab38b59b7b63e652e4c8ada1bfc..f140d5a2a22f2625e37b1d5d7f4103964b299459 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "base/dictionary.hpp"
 #include "base/objectlock.hpp"
-#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
 #include <boost/tuple/tuple.hpp>
@@ -172,9 +172,9 @@ BOOST_AUTO_TEST_CASE(json)
        dictionary->Set("test1", 7);
        dictionary->Set("test2", "hello world");
 
-       String json = JsonSerialize(dictionary);
+       String json = JsonEncode(dictionary);
        BOOST_CHECK(json.GetLength() > 0);
-       Dictionary::Ptr deserialized = JsonDeserialize(json);
+       Dictionary::Ptr deserialized = JsonDecode(json);
        BOOST_CHECK(deserialized->GetLength() == 2);
        BOOST_CHECK(deserialized->Get("test1") == 7);
        BOOST_CHECK(deserialized->Get("test2") == "hello world");
diff --git a/test/base-json.cpp b/test/base-json.cpp
new file mode 100644 (file)
index 0000000..acc1a6d
--- /dev/null
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#include "icinga/perfdatavalue.hpp"
+#include "base/dictionary.hpp"
+#include "base/objectlock.hpp"
+#include "base/json.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <boost/tuple/tuple.hpp>
+
+using namespace icinga;
+
+BOOST_AUTO_TEST_SUITE(base_json)
+
+BOOST_AUTO_TEST_CASE(invalid1)
+{
+       BOOST_CHECK_THROW(JsonDecode("\"1.7"), std::exception);
+       BOOST_CHECK_THROW(JsonDecode("{8: \"test\"}"), std::exception);
+       BOOST_CHECK_THROW(JsonDecode("{\"test\": \"test\""), std::exception);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
index a10b48191e268f4efd5cd4df91773db92b269211..41fc705c54d2a6af7d0eeddcce5d3d21dead7394 100644 (file)
@@ -15,8 +15,8 @@
 # along with this program; if not, write to the Free Software Foundation
 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
-add_subdirectory(cJSON)
 add_subdirectory(mmatch)
+add_subdirectory(yajl)
 
 if(UNIX OR CYGWIN)
   add_subdirectory(execvpe)
diff --git a/third-party/cJSON/CMakeLists.txt b/third-party/cJSON/CMakeLists.txt
deleted file mode 100644 (file)
index 617a9e1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# Icinga 2
-# Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-add_library(cJSON SHARED cJSON.c cJSON.h)
-
-set_target_properties (
-  cJSON PROPERTIES
-  DEFINE_SYMBOL I2_CJSON_BUILD
-  FOLDER Lib
-)
-
-if(UNIX AND NOT HAIKU)
-    target_link_libraries(cJSON m)
-endif()
-
-install(
-  TARGETS cJSON
-  RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
-  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
-)
diff --git a/third-party/cJSON/cJSON.c b/third-party/cJSON/cJSON.c
deleted file mode 100644 (file)
index f1bef65..0000000
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
-  Copyright (c) 2009 Dave Gamble
-
-  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.
-*/
-
-/* cJSON */
-/* JSON parser in C. */
-
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-#include <float.h>
-#include <limits.h>
-#include <ctype.h>
-#include "cJSON.h"
-
-static const char *ep;
-
-const char *cJSON_GetErrorPtr() {return ep;}
-
-static int cJSON_strcasecmp(const char *s1,const char *s2)
-{
-       if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
-       for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0)    return 0;
-       return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
-}
-
-static void *(*cJSON_malloc)(size_t sz) = malloc;
-static void (*cJSON_free)(void *ptr) = free;
-
-static char* cJSON_strdup(const char* str)
-{
-      size_t len;
-      char* copy;
-
-      len = strlen(str) + 1;
-      if (!(copy = (char*)cJSON_malloc(len))) return 0;
-      memcpy(copy,str,len);
-      return copy;
-}
-
-void cJSON_InitHooks(cJSON_Hooks* hooks)
-{
-    if (!hooks) { /* Reset hooks */
-        cJSON_malloc = malloc;
-        cJSON_free = free;
-        return;
-    }
-
-       cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
-       cJSON_free       = (hooks->free_fn)?hooks->free_fn:free;
-}
-
-/* Internal constructor. */
-static cJSON *cJSON_New_Item()
-{
-       cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
-       if (node) memset(node,0,sizeof(cJSON));
-       return node;
-}
-
-/* Delete a cJSON structure. */
-void cJSON_Delete(cJSON *c)
-{
-       cJSON *next;
-       while (c)
-       {
-               next=c->next;
-               if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
-               if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
-               if (c->string) cJSON_free(c->string);
-               cJSON_free(c);
-               c=next;
-       }
-}
-
-/* Parse the input text to generate a number, and populate the result into item. */
-static const char *parse_number(cJSON *item,const char *num)
-{
-       double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
-
-       /* Could use sscanf for this? */
-       if (*num=='-') sign=-1,num++;   /* Has sign? */
-       if (*num=='0') num++;                   /* is zero */
-       if (*num>='1' && *num<='9')     do      n=(n*10.0)+(*num++ -'0');       while (*num>='0' && *num<='9'); /* Number? */
-       if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;            do      n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}      /* Fractional part? */
-       if (*num=='e' || *num=='E')             /* Exponent? */
-       {       num++;if (*num=='+') num++;     else if (*num=='-') signsubscale=-1,num++;              /* With sign? */
-               while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');   /* Number? */
-       }
-
-       n=sign*n*pow(10.0,(scale+subscale*signsubscale));       /* number = +/- number.fraction * 10^+/- exponent */
-       
-       item->valuedouble=n;
-       item->valueint=(int)n;
-       item->type=cJSON_Number;
-       return num;
-}
-
-/* Render the number nicely from the given item into a string. */
-static char *print_number(cJSON *item)
-{
-       char *str;
-       double d=item->valuedouble;
-       if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
-       {
-               str=(char*)cJSON_malloc(21);    /* 2^64+1 can be represented in 21 chars. */
-               if (str) sprintf(str,"%d",item->valueint);
-       }
-       else
-       {
-               if (d != d)
-               {
-                       str=(char*)cJSON_malloc(2);
-                       if (str)
-                               strcpy(str, "0");
-               }
-               else
-               {
-                       str = (char*)cJSON_malloc(64 + (int)log10(fabs(d)));    /* This is a nice tradeoff. */
-                       if (str)
-                       {
-                               if (fabs(floor(d) - d) <= DBL_EPSILON)                  sprintf(str, "%.0f", d);
-                               else                                                    sprintf(str, "%.*e", (int)log10(d) + 6, d);
-                       }
-               }
-       }
-       return str;
-}
-
-/* Parse the input text into an unescaped cstring, and populate item. */
-static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-static const char *parse_string(cJSON *item,const char *str)
-{
-       const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
-       if (*str!='\"') {ep=str;return 0;}      /* not a string! */
-       
-       while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;  /* Skip escaped quotes. */
-       
-       out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
-       if (!out) return 0;
-       
-       ptr=str+1;ptr2=out;
-       while (*ptr!='\"' && *ptr)
-       {
-               if (*ptr!='\\') *ptr2++=*ptr++;
-               else
-               {
-                       ptr++;
-                       switch (*ptr)
-                       {
-                               case 'b': *ptr2++='\b'; break;
-                               case 'f': *ptr2++='\f'; break;
-                               case 'n': *ptr2++='\n'; break;
-                               case 'r': *ptr2++='\r'; break;
-                               case 't': *ptr2++='\t'; break;
-                               case 'u':        /* transcode utf16 to utf8. */
-                                       sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */
-
-                                       if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)        break;  // check for invalid.
-
-                                       if (uc>=0xD800 && uc<=0xDBFF)   // UTF16 surrogate pairs.
-                                       {
-                                               if (ptr[1]!='\\' || ptr[2]!='u')        break;  // missing second-half of surrogate.
-                                               sscanf(ptr+3,"%4x",&uc2);ptr+=6;
-                                               if (uc2<0xDC00 || uc2>0xDFFF)           break;  // invalid second-half of surrogate.
-                                               uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);
-                                       }
-
-                                       len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
-                                       
-                                       switch (len) {
-                                               case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
-                                               case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
-                                               case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
-                                               case 1: *--ptr2 =(uc | firstByteMark[len]);
-                                       }
-                                       ptr2+=len;
-                                       break;
-                               default:  *ptr2++=*ptr; break;
-                       }
-                       ptr++;
-               }
-       }
-       *ptr2=0;
-       if (*ptr=='\"') ptr++;
-       item->valuestring=out;
-       item->type=cJSON_String;
-       return ptr;
-}
-
-/* Render the cstring provided to an escaped version that can be printed. */
-static char *print_string_ptr(const char *str)
-{
-       const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
-       
-       if (!str) return cJSON_strdup("");
-       ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
-       
-       out=(char*)cJSON_malloc(len+3);
-       if (!out) return 0;
-
-       ptr2=out;ptr=str;
-       *ptr2++='\"';
-       while (*ptr)
-       {
-               if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
-               else
-               {
-                       *ptr2++='\\';
-                       switch (token=*ptr++)
-                       {
-                               case '\\':      *ptr2++='\\';   break;
-                               case '\"':      *ptr2++='\"';   break;
-                               case '\b':      *ptr2++='b';    break;
-                               case '\f':      *ptr2++='f';    break;
-                               case '\n':      *ptr2++='n';    break;
-                               case '\r':      *ptr2++='r';    break;
-                               case '\t':      *ptr2++='t';    break;
-                               default: sprintf(ptr2,"u%04x",token);ptr2+=5;   break;  /* escape and print */
-                       }
-               }
-       }
-       *ptr2++='\"';*ptr2++=0;
-       return out;
-}
-/* Invote print_string_ptr (which is useful) on an item. */
-static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
-
-/* Predeclare these prototypes. */
-static const char *parse_value(cJSON *item,const char *value);
-static char *print_value(cJSON *item,int depth,int fmt);
-static const char *parse_array(cJSON *item,const char *value);
-static char *print_array(cJSON *item,int depth,int fmt);
-static const char *parse_object(cJSON *item,const char *value);
-static char *print_object(cJSON *item,int depth,int fmt);
-
-/* Utility to jump whitespace and cr/lf */
-static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
-
-/* Parse an object - create a new root, and populate. */
-cJSON *cJSON_Parse(const char *value)
-{
-       cJSON *c=cJSON_New_Item();
-       ep=0;
-       if (!c) return 0;       /* memory fail */
-
-       if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;}
-       return c;
-}
-
-/* Render a cJSON item/entity/structure to text. */
-char *cJSON_Print(cJSON *item)                         {return print_value(item,0,1);}
-char *cJSON_PrintUnformatted(cJSON *item)      {return print_value(item,0,0);}
-
-/* Parser core - when encountering text, process appropriately. */
-static const char *parse_value(cJSON *item,const char *value)
-{
-       if (!value)                                             return 0;       /* Fail on null. */
-       if (!strncmp(value,"null",4))   { item->type=cJSON_NULL;  return value+4; }
-       if (!strncmp(value,"false",5))  { item->type=cJSON_False; return value+5; }
-       if (!strncmp(value,"true",4))   { item->type=cJSON_True; item->valueint=1;      return value+4; }
-       if (*value=='\"')                               { return parse_string(item,value); }
-       if (*value=='-' || (*value>='0' && *value<='9'))        { return parse_number(item,value); }
-       if (*value=='[')                                { return parse_array(item,value); }
-       if (*value=='{')                                { return parse_object(item,value); }
-
-       ep=value;return 0;      /* failure. */
-}
-
-/* Render a value to text. */
-static char *print_value(cJSON *item,int depth,int fmt)
-{
-       char *out=0;
-       if (!item) return 0;
-       switch ((item->type)&255)
-       {
-               case cJSON_NULL:        out=cJSON_strdup("null");       break;
-               case cJSON_False:       out=cJSON_strdup("false");break;
-               case cJSON_True:        out=cJSON_strdup("true"); break;
-               case cJSON_Number:      out=print_number(item);break;
-               case cJSON_String:      out=print_string(item);break;
-               case cJSON_Array:       out=print_array(item,depth,fmt);break;
-               case cJSON_Object:      out=print_object(item,depth,fmt);break;
-       }
-       return out;
-}
-
-/* Build an array from input text. */
-static const char *parse_array(cJSON *item,const char *value)
-{
-       cJSON *child;
-       if (*value!='[')        {ep=value;return 0;}    /* not an array! */
-
-       item->type=cJSON_Array;
-       value=skip(value+1);
-       if (*value==']') return value+1;        /* empty array. */
-
-       item->child=child=cJSON_New_Item();
-       if (!item->child) return 0;              /* memory fail */
-       value=skip(parse_value(child,skip(value)));     /* skip any spacing, get the value. */
-       if (!value) return 0;
-
-       while (*value==',')
-       {
-               cJSON *new_item;
-               if (!(new_item=cJSON_New_Item())) return 0;     /* memory fail */
-               child->next=new_item;new_item->prev=child;child=new_item;
-               value=skip(parse_value(child,skip(value+1)));
-               if (!value) return 0;   /* memory fail */
-       }
-
-       if (*value==']') return value+1;        /* end of array */
-       ep=value;return 0;      /* malformed. */
-}
-
-/* Render an array to text */
-static char *print_array(cJSON *item,int depth,int fmt)
-{
-       char **entries;
-       char *out=0,*ptr,*ret;int len=5;
-       cJSON *child=item->child;
-       int numentries=0,i=0,fail=0;
-       
-       /* How many entries in the array? */
-       while (child) numentries++,child=child->next;
-       /* Allocate an array to hold the values for each */
-       entries=(char**)cJSON_malloc(numentries*sizeof(char*));
-       if (!entries) return 0;
-       memset(entries,0,numentries*sizeof(char*));
-       /* Retrieve all the results: */
-       child=item->child;
-       while (child && !fail)
-       {
-               ret=print_value(child,depth+1,fmt);
-               entries[i++]=ret;
-               if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
-               child=child->next;
-       }
-       
-       /* If we didn't fail, try to malloc the output string */
-       if (!fail) out=(char*)cJSON_malloc(len);
-       /* If that fails, we fail. */
-       if (!out) fail=1;
-
-       /* Handle failure. */
-       if (fail)
-       {
-               for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
-               cJSON_free(entries);
-               return 0;
-       }
-       
-       /* Compose the output array. */
-       *out='[';
-       ptr=out+1;*ptr=0;
-       for (i=0;i<numentries;i++)
-       {
-               strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
-               if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
-               cJSON_free(entries[i]);
-       }
-       cJSON_free(entries);
-       *ptr++=']';*ptr++=0;
-       return out;     
-}
-
-/* Build an object from the text. */
-static const char *parse_object(cJSON *item,const char *value)
-{
-       cJSON *child;
-       if (*value!='{')        {ep=value;return 0;}    /* not an object! */
-       
-       item->type=cJSON_Object;
-       value=skip(value+1);
-       if (*value=='}') return value+1;        /* empty array. */
-       
-       item->child=child=cJSON_New_Item();
-       if (!item->child) return 0;
-       value=skip(parse_string(child,skip(value)));
-       if (!value) return 0;
-       child->string=child->valuestring;child->valuestring=0;
-       if (*value!=':') {ep=value;return 0;}   /* fail! */
-       value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
-       if (!value) return 0;
-       
-       while (*value==',')
-       {
-               cJSON *new_item;
-               if (!(new_item=cJSON_New_Item()))       return 0; /* memory fail */
-               child->next=new_item;new_item->prev=child;child=new_item;
-               value=skip(parse_string(child,skip(value+1)));
-               if (!value) return 0;
-               child->string=child->valuestring;child->valuestring=0;
-               if (*value!=':') {ep=value;return 0;}   /* fail! */
-               value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
-               if (!value) return 0;
-       }
-       
-       if (*value=='}') return value+1;        /* end of array */
-       ep=value;return 0;      /* malformed. */
-}
-
-/* Render an object to text. */
-static char *print_object(cJSON *item,int depth,int fmt)
-{
-       char **entries=0,**names=0;
-       char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
-       cJSON *child=item->child;
-       int numentries=0,fail=0;
-       /* Count the number of entries. */
-       while (child) numentries++,child=child->next;
-       /* Allocate space for the names and the objects */
-       entries=(char**)cJSON_malloc(numentries*sizeof(char*));
-       if (!entries) return 0;
-       names=(char**)cJSON_malloc(numentries*sizeof(char*));
-       if (!names) {cJSON_free(entries);return 0;}
-       memset(entries,0,sizeof(char*)*numentries);
-       memset(names,0,sizeof(char*)*numentries);
-
-       /* Collect all the results into our arrays: */
-       child=item->child;depth++;if (fmt) len+=depth;
-       while (child)
-       {
-               names[i]=str=print_string_ptr(child->string);
-               entries[i++]=ret=print_value(child,depth,fmt);
-               if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
-               child=child->next;
-       }
-       
-       /* Try to allocate the output string */
-       if (!fail) out=(char*)cJSON_malloc(len);
-       if (!out) fail=1;
-
-       /* Handle failure */
-       if (fail)
-       {
-               for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
-               cJSON_free(names);cJSON_free(entries);
-               return 0;
-       }
-       
-       /* Compose the output: */
-       *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
-       for (i=0;i<numentries;i++)
-       {
-               if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
-               strcpy(ptr,names[i]);ptr+=strlen(names[i]);
-               *ptr++=':';if (fmt) *ptr++='\t';
-               strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
-               if (i!=numentries-1) *ptr++=',';
-               if (fmt) *ptr++='\n';*ptr=0;
-               cJSON_free(names[i]);cJSON_free(entries[i]);
-       }
-       
-       cJSON_free(names);cJSON_free(entries);
-       if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
-       *ptr++='}';*ptr++=0;
-       return out;     
-}
-
-/* Get Array size/item / object item. */
-int    cJSON_GetArraySize(cJSON *array)                                                        {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
-cJSON *cJSON_GetArrayItem(cJSON *array,int item)                               {cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
-cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)   {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
-
-/* Utility for array list handling. */
-static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
-/* Utility for handling references. */
-static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
-
-/* Add item to array/object. */
-void   cJSON_AddItemToArray(cJSON *array, cJSON *item)                                         {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
-void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)     {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
-void   cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)                                                {cJSON_AddItemToArray(array,create_reference(item));}
-void   cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)    {cJSON_AddItemToObject(object,string,create_reference(item));}
-
-cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)                       {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
-       if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
-void   cJSON_DeleteItemFromArray(cJSON *array,int which)                       {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
-cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
-void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
-
-/* Replace array/object items with new ones. */
-void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)         {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
-       newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
-       if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
-void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
-
-/* Create basic types: */
-cJSON *cJSON_CreateNull()                                              {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
-cJSON *cJSON_CreateTrue()                                              {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
-cJSON *cJSON_CreateFalse()                                             {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
-cJSON *cJSON_CreateBool(int b)                                 {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
-cJSON *cJSON_CreateNumber(double num)                  {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
-cJSON *cJSON_CreateString(const char *string)  {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
-cJSON *cJSON_CreateArray()                                             {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
-cJSON *cJSON_CreateObject()                                            {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
-
-/* Create Arrays: */
-cJSON *cJSON_CreateIntArray(int *numbers,int count)                            {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
-cJSON *cJSON_CreateFloatArray(float *numbers,int count)                        {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
-cJSON *cJSON_CreateDoubleArray(double *numbers,int count)              {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
-cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
diff --git a/third-party/cJSON/cJSON.h b/third-party/cJSON/cJSON.h
deleted file mode 100644 (file)
index 5d0555a..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-  Copyright (c) 2009 Dave Gamble
-  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.
-*/
-
-#ifndef cJSON__h
-#define cJSON__h
-
-#include "base/visibility.hpp"
-
-#ifdef I2_CJSON_BUILD
-#      define I2_CJSON_API I2_EXPORT
-#else
-#      define I2_CJSON_API I2_IMPORT
-#endif /* I2_CJSON_BUILD */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/* cJSON Types: */
-#define cJSON_False 0
-#define cJSON_True 1
-#define cJSON_NULL 2
-#define cJSON_Number 3
-#define cJSON_String 4
-#define cJSON_Array 5
-#define cJSON_Object 6
-       
-#define cJSON_IsReference 256
-
-/* The cJSON structure: */
-typedef struct cJSON {
-       struct cJSON *next,*prev;       /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
-       struct cJSON *child;            /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
-
-       int type;                                       /* The type of the item, as above. */
-
-       char *valuestring;                      /* The item's string, if type==cJSON_String */
-       int valueint;                           /* The item's number, if type==cJSON_Number */
-       double valuedouble;                     /* The item's number, if type==cJSON_Number */
-
-       char *string;                           /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
-} cJSON;
-
-typedef struct cJSON_Hooks {
-      void *(*malloc_fn)(size_t sz);
-      void (*free_fn)(void *ptr);
-} cJSON_Hooks;
-
-/* Supply malloc, realloc and free functions to cJSON */
-extern I2_CJSON_API void cJSON_InitHooks(cJSON_Hooks* hooks);
-
-
-/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
-extern I2_CJSON_API cJSON *cJSON_Parse(const char *value);
-/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
-extern I2_CJSON_API char  *cJSON_Print(cJSON *item);
-/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
-extern I2_CJSON_API char  *cJSON_PrintUnformatted(cJSON *item);
-/* Delete a cJSON entity and all subentities. */
-extern I2_CJSON_API void   cJSON_Delete(cJSON *c);
-
-/* Returns the number of items in an array (or object). */
-extern I2_CJSON_API int          cJSON_GetArraySize(cJSON *array);
-/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
-extern I2_CJSON_API cJSON *cJSON_GetArrayItem(cJSON *array,int item);
-/* Get item "string" from object. Case insensitive. */
-extern I2_CJSON_API cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
-
-/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
-extern I2_CJSON_API const char *cJSON_GetErrorPtr();
-       
-/* These calls create a cJSON item of the appropriate type. */
-extern I2_CJSON_API cJSON *cJSON_CreateNull();
-extern I2_CJSON_API cJSON *cJSON_CreateTrue();
-extern I2_CJSON_API cJSON *cJSON_CreateFalse();
-extern I2_CJSON_API cJSON *cJSON_CreateBool(int b);
-extern I2_CJSON_API cJSON *cJSON_CreateNumber(double num);
-extern I2_CJSON_API cJSON *cJSON_CreateString(const char *string);
-extern I2_CJSON_API cJSON *cJSON_CreateArray();
-extern I2_CJSON_API cJSON *cJSON_CreateObject();
-
-/* These utilities create an Array of count items. */
-extern I2_CJSON_API cJSON *cJSON_CreateIntArray(int *numbers,int count);
-extern I2_CJSON_API cJSON *cJSON_CreateFloatArray(float *numbers,int count);
-extern I2_CJSON_API cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
-extern I2_CJSON_API cJSON *cJSON_CreateStringArray(const char **strings,int count);
-
-/* Append item to the specified array/object. */
-extern I2_CJSON_API void cJSON_AddItemToArray(cJSON *array, cJSON *item);
-extern I2_CJSON_API void       cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
-/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
-extern I2_CJSON_API void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
-extern I2_CJSON_API void       cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
-
-/* Remove/Detatch items from Arrays/Objects. */
-extern I2_CJSON_API cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
-extern I2_CJSON_API void   cJSON_DeleteItemFromArray(cJSON *array,int which);
-extern I2_CJSON_API cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
-extern I2_CJSON_API void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
-       
-/* Update array items. */
-extern I2_CJSON_API void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
-extern I2_CJSON_API void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
-
-#define cJSON_AddNullToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateNull())
-#define cJSON_AddTrueToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
-#define cJSON_AddFalseToObject(object,name)            cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
-#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
-#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/third-party/yajl/.gitignore b/third-party/yajl/.gitignore
new file mode 100644 (file)
index 0000000..b0aff9a
--- /dev/null
@@ -0,0 +1,3 @@
+.DS_Store
+Makefile
+/build/
diff --git a/third-party/yajl/BUILDING b/third-party/yajl/BUILDING
new file mode 100644 (file)
index 0000000..8460ed4
--- /dev/null
@@ -0,0 +1,23 @@
+Short story (If you already have ruby and cmake):
+
+./configure && make install
+
+When things go wrong:
+
+attain CMake (http://www.cmake.org) and ruby (http://ruby-lang.org) and
+try again.
+
+OR, attain CMake and build by hand:
+
+1. mkdir build
+2. cd build
+3. cmake ..
+4. make 
+5. build output left in yajl-X.Y.Z
+
+NOTE: for 64-bit systems where lib64 is used you can pass the cmake
+      variable LIB_SUFFIX to cause installation into the system's 'lib64'
+      directory.
+
+best,
+lloyd
diff --git a/third-party/yajl/BUILDING.win32 b/third-party/yajl/BUILDING.win32
new file mode 100644 (file)
index 0000000..6b35aa4
--- /dev/null
@@ -0,0 +1,27 @@
+YAJL has been successfully built using Visual Studio 8.  CMake, a
+build file generator, is used to build the software.  CMake supports
+several different build environments, so you may either build YAJL
+using the IDE via the following steps:
+
+1. acquire cmake (http://www.cmake.org)
+2. mkdir build
+3. cd build
+4. cmake ..
+5. devenv YetAnotherJSONParser.sln /project ALL_BUILD /build Release
+6. build output is left in build/yajl-X.Y.Z
+
+Or you can build from the command line using nmake:
+
+1. Click Start > Programs > Microsoft Visual Studio > Visual Studio
+Tools > Visual Studio Command Prompt -- for your version of Visual
+Studio, which will open a command prompt.  You may verify that the
+compiler is in your path by typing "cl /?" at the prompt.
+2. cd C:\path\to\yajl\source\
+3. mkdir build
+4. cd build
+5. cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ..
+6. nmake
+7. nmake install
+
+Earlier versions of visual studio and other build generators haven't
+been thoroughly tested, but should work without any major issues.
diff --git a/third-party/yajl/CMakeLists.txt b/third-party/yajl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7440dab
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+#
+# 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.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+PROJECT(YetAnotherJSONParser C)
+
+SET (YAJL_MAJOR 2)
+SET (YAJL_MINOR 1)
+SET (YAJL_MICRO 0)
+
+IF (WIN32)
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
+  ADD_DEFINITIONS(-DWIN32)
+
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996 /wd4255 /wd4130 /wd4100 /wd4711")
+  SET(CMAKE_C_FLAGS_DEBUG "/D DEBUG /Od /Z7")
+  SET(CMAKE_C_FLAGS_RELEASE "/D NDEBUG /O2")
+ELSE (WIN32)
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+  IF(CMAKE_COMPILER_IS_GNUCC)
+    INCLUDE(CheckCCompilerFlag)
+    CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_GCC_VISIBILITY)
+    IF(HAVE_GCC_VISIBILITY)
+      SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
+    ENDIF(HAVE_GCC_VISIBILITY)
+  ENDIF(CMAKE_COMPILER_IS_GNUCC)
+  SET(CMAKE_C_FLAGS
+      "${CMAKE_C_FLAGS} -std=c99 -pedantic -Wpointer-arith -Wno-format-y2k -Wstrict-prototypes -Wmissing-declarations -Wnested-externs -Wextra -Wundef -Wwrite-strings -Wold-style-definition -Wredundant-decls -Wno-unused-parameter -Wno-sign-compare -Wmissing-prototypes")
+
+  SET(CMAKE_C_FLAGS_DEBUG "-DDEBUG")
+  SET(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -Wuninitialized")
+ENDIF (WIN32)
+
+ADD_SUBDIRECTORY(src)
diff --git a/third-party/yajl/COPYING b/third-party/yajl/COPYING
new file mode 100644 (file)
index 0000000..30be349
--- /dev/null
@@ -0,0 +1,13 @@
+Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+
+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.
diff --git a/third-party/yajl/ChangeLog b/third-party/yajl/ChangeLog
new file mode 100644 (file)
index 0000000..343f894
--- /dev/null
@@ -0,0 +1,189 @@
+2.1.0
+     * @nonodename, @patperry - fixed some compiler warnings
+     * @yep, @emaste - documentation improvements
+     * @sgravrock - build fix for NetBSD (and whenever sh != bash)
+     * @rotty, @brimstone3, @lloyd - allow client to reset generator
+     * @sgravrock - remove bash dependencies
+     * @lloyd - add api tests
+     * @rflynn - remove ruby dependency
+     * @cloderic - nmake install works on windows
+     * @shahbag - build fix for qnx
+     * @breese - debugging improvements
+     * @lloyd - json_verify supports -s flag for stream processing
+     * @lloyd - json_reformat supports -s flag for stream processing
+
+2.0.4
+     * @jcekstrom - additional checking in integer parsing
+     * @jcekstrom - fix a bug in yajl_tree that would cause valid json integersto fail to parse
+     * @plaguemorin - fix a memory leak in yajl_tree (error strings were being leaked)
+     * @7AC - reset errno
+     * @ConradIrwin - include flags to reformatter to allow toggling of escape solidus option
+
+2.0.3
+     * John Stamp generation of a pkgconfig file at build time.
+     * @robzuber bugfix in yajl_tree_get()
+     * @lloyd - fix for compilation on 64 bit windows
+
+2.0.2
+     * lth fix typos in yajl_tree.h macros YAJL_IS_INTEGER and YAJL_IS_DOUBLE,
+       contributed by Artem S Vybornov.
+     * lth add #ifdef __cplusplus wrappers to yajl_tree to allow proper
+       usage from many populer C++ compilers.
+
+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
diff --git a/third-party/yajl/README b/third-party/yajl/README
new file mode 100644 (file)
index 0000000..ad61759
--- /dev/null
@@ -0,0 +1,74 @@
+**********************************************************************
+        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 were 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 
diff --git a/third-party/yajl/TODO b/third-party/yajl/TODO
new file mode 100644 (file)
index 0000000..56c3dc0
--- /dev/null
@@ -0,0 +1,9 @@
+* 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
diff --git a/third-party/yajl/src/CMakeLists.txt b/third-party/yajl/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..63a8ee9
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+#
+# 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 (incDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include/yajl)
+
+ADD_LIBRARY(yajl SHARED ${SRCS} ${HDRS} ${PUB_HDRS})
+
+#### setup shared library version number
+SET_TARGET_PROPERTIES(yajl PROPERTIES
+                      INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
+                      DEFINE_SYMBOL YAJL_SHARED
+                      SOVERSION ${YAJL_MAJOR}
+                      VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO}
+                                         FOLDER Lib)
+
+#### build up an sdk as a post build step
+
+# create some directories
+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}\")
+ENDFOREACH (header ${PUB_HDRS})
+
+INCLUDE_DIRECTORIES(${incDir}/..)
+
+INSTALL(TARGETS yajl
+  RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2)
diff --git a/third-party/yajl/src/api/yajl_common.h b/third-party/yajl/src/api/yajl_common.h
new file mode 100644 (file)
index 0000000..9596ef9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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(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
diff --git a/third-party/yajl/src/api/yajl_gen.h b/third-party/yajl/src/api/yajl_gen.h
new file mode 100644 (file)
index 0000000..ddd1527
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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);
+
+    /** Reset the generator state.  Allows a client to generate multiple
+     *  json entities in a stream. The "sep" string will be inserted to
+     *  separate the previously generated entity from the current,
+     *  NULL means *no separation* of entites (clients beware, generating
+     *  multiple JSON numbers, for instance, will result in inscrutable
+     *  output) */
+    YAJL_API void yajl_gen_reset(yajl_gen hand, const char * sep);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third-party/yajl/src/api/yajl_parse.h b/third-party/yajl/src/api/yajl_parse.h
new file mode 100644 (file)
index 0000000..1c25a60
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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
diff --git a/third-party/yajl/src/api/yajl_tree.h b/third-party/yajl/src/api/yajl_tree.h
new file mode 100644 (file)
index 0000000..1c1e06a
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** 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_*" macros 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. */
+            char   *r;   /*< unparsed number in string form. */
+            /** Signals whether the \em i and \em d members are
+             * valid. See \c YAJL_NUMBER_INT_VALID and
+             * \c YAJL_NUMBER_DOUBLE_VALID. */
+            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.number.flags & YAJL_NUMBER_INT_VALID))
+#define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.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)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* YAJL_TREE_H */
diff --git a/third-party/yajl/src/api/yajl_version.h.cmake b/third-party/yajl/src/api/yajl_version.h.cmake
new file mode 100644 (file)
index 0000000..4262ff7
--- /dev/null
@@ -0,0 +1,23 @@
+#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_ */
+
diff --git a/third-party/yajl/src/yajl.c b/third-party/yajl/src/yajl.c
new file mode 100644 (file)
index 0000000..d477893
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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 */
diff --git a/third-party/yajl/src/yajl_alloc.c b/third-party/yajl/src/yajl_alloc.c
new file mode 100644 (file)
index 0000000..96ad1d3
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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)
+{
+    (void)ctx;
+    return malloc(sz);
+}
+
+static void * yajl_internal_realloc(void *ctx, void * previous,
+                                    size_t sz)
+{
+    (void)ctx;
+    return realloc(previous, sz);
+}
+
+static void yajl_internal_free(void *ctx, void * ptr)
+{
+    (void)ctx;
+    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;
+}
+
diff --git a/third-party/yajl/src/yajl_alloc.h b/third-party/yajl/src/yajl_alloc.h
new file mode 100644 (file)
index 0000000..203c2f9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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
diff --git a/third-party/yajl/src/yajl_buf.c b/third-party/yajl/src/yajl_buf.c
new file mode 100644 (file)
index 0000000..1aeafde
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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;
+}
diff --git a/third-party/yajl/src/yajl_buf.h b/third-party/yajl/src/yajl_buf.h
new file mode 100644 (file)
index 0000000..a358246
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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
diff --git a/third-party/yajl/src/yajl_bytestack.h b/third-party/yajl/src/yajl_bytestack.h
new file mode 100644 (file)
index 0000000..9ea7d15
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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
diff --git a/third-party/yajl/src/yajl_encode.c b/third-party/yajl/src/yajl_encode.c
new file mode 100644 (file)
index 0000000..fd08258
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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;
+}
diff --git a/third-party/yajl/src/yajl_encode.h b/third-party/yajl/src/yajl_encode.h
new file mode 100644 (file)
index 0000000..853a1a7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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
diff --git a/third-party/yajl/src/yajl_gen.c b/third-party/yajl/src/yajl_gen.c
new file mode 100644 (file)
index 0000000..0f5c68e
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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:
+        case yajl_gen_escape_solidus:
+            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_reset(yajl_gen g, const char * sep)
+{
+    g->depth = 0;
+    memset((void *) &(g->state), 0, sizeof(g->state));
+    if (sep != NULL) g->print(g->ctx, sep, strlen(sep));
+}
+
+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_generation_complete;
+
+#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;
+}
+
+#if defined(_WIN32) || defined(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);
+    if (strspn(i, "0123456789-") == strlen(i)) {
+        strcat(i, ".0");
+    }
+    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);
+}
diff --git a/third-party/yajl/src/yajl_lex.c b/third-party/yajl/src/yajl_lex.c
new file mode 100644 (file)
index 0000000..0b6f7cc
--- /dev/null
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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;
+}
diff --git a/third-party/yajl/src/yajl_lex.h b/third-party/yajl/src/yajl_lex.h
new file mode 100644 (file)
index 0000000..fd17c00
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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
+ * 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
diff --git a/third-party/yajl/src/yajl_parser.c b/third-party/yajl/src/yajl_parser.c
new file mode 100644 (file)
index 0000000..1a528a6
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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;
+        }
+        if (*pos < '0' || *pos > '9') {
+            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;
+                            errno = 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);
+                            errno = 0;
+                            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;
+}
+
diff --git a/third-party/yajl/src/yajl_parser.h b/third-party/yajl/src/yajl_parser.h
new file mode 100644 (file)
index 0000000..c79299a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
+ *
+ * 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
diff --git a/third-party/yajl/src/yajl_tree.c b/third-party/yajl/src/yajl_tree.c
new file mode 100644 (file)
index 0000000..3d357a3
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * 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"
+
+#if defined(_WIN32) || defined(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;
+
+    errno = 0;
+    v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r,
+                                       strlen(v->u.number.r));
+    if (errno == 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;
+    char * internal_err_str;
+       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) {
+               internal_err_str = (char *) yajl_get_error(handle, 1,
+                     (const unsigned char *) input,
+                     strlen(input));
+             snprintf(error_buffer, error_buffer_size, "%s", internal_err_str);
+             YA_FREE(&(handle->alloc), internal_err_str);
+        }
+        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) {
+        size_t i;
+        size_t len;
+
+        if (n->type != yajl_t_object) return NULL;
+        len = n->u.object.len;
+        for (i = 0; i < len; i++) {
+            if (!strcmp(*path, n->u.object.keys[i])) {
+                n = n->u.object.values[i];
+                break;
+            }
+        }
+        if (i == 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);
+    }
+}
diff --git a/third-party/yajl/src/yajl_version.c b/third-party/yajl/src/yajl_version.c
new file mode 100644 (file)
index 0000000..0671da7
--- /dev/null
@@ -0,0 +1,7 @@
+#include <yajl/yajl_version.h>
+
+int yajl_version(void)
+{
+       return YAJL_VERSION;
+}
+