diff options
Diffstat (limited to 'plugins/JSON/Source')
| -rw-r--r-- | plugins/JSON/Source/JSONChildren.cpp | 73 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONChildren.h | 234 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONDebug.cpp | 39 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONDebug.h | 68 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONDefs.h | 81 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONIterators.cpp | 214 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONMemory.cpp | 81 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONMemory.h | 134 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONNode.cpp | 287 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONNode.h | 923 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONNode_Mutex.cpp | 191 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONWorker.cpp | 676 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONWorker.h | 46 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSONWriter.cpp | 148 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSON_Base64.cpp | 111 | ||||
| -rw-r--r-- | plugins/JSON/Source/JSON_Base64.h | 14 | ||||
| -rw-r--r-- | plugins/JSON/Source/NumberToString.h | 104 | ||||
| -rw-r--r-- | plugins/JSON/Source/internalJSONNode.cpp | 545 | ||||
| -rw-r--r-- | plugins/JSON/Source/internalJSONNode.h | 453 | ||||
| -rw-r--r-- | plugins/JSON/Source/libJSON.cpp | 480 | 
20 files changed, 4902 insertions, 0 deletions
diff --git a/plugins/JSON/Source/JSONChildren.cpp b/plugins/JSON/Source/JSONChildren.cpp new file mode 100644 index 0000000000..9f9e53ee81 --- /dev/null +++ b/plugins/JSON/Source/JSONChildren.cpp @@ -0,0 +1,73 @@ +#include "JSONChildren.h" +#include "JSONNode.h" + +void jsonChildren::inc(void){ +    if (mysize == mycapacity){  //it's full +	   if (!mycapacity){  //the array hasn't been created yet +		  JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); +		  #ifdef JSON_LESS_MEMORY +			 array = json_malloc<JSONNode*>(1); +			 mycapacity = 1; +		  #else +			 array = json_malloc<JSONNode*>(8);  //8 seems average for JSON, and it's only 64 bytes +			 mycapacity = 8; +		  #endif +	   } else { +		  #ifdef JSON_LESS_MEMORY +			 mycapacity += 1;  //increment the size of the array +		  #else +			 mycapacity <<= 1;  //double the size of the array +		  #endif +		  array = json_realloc<JSONNode*>(array, mycapacity); +	   } +    }    +} + + +void jsonChildren::inc(json_index_t amount){ +    if (!amount) return; +    if (mysize + amount >= mycapacity){  //it's full +	   if (!mycapacity){  //the array hasn't been created yet +		  JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); +		  #ifdef JSON_LESS_MEMORY +			 array = json_malloc<JSONNode*>(amount); +			 mycapacity = amount; +		  #else +			 array = json_malloc<JSONNode*>(amount > 8 ? amount : 8);  //8 seems average for JSON, and it's only 64 bytes +			 mycapacity = amount > 8 ? amount : 8; +		  #endif +	   } else { +		  #ifdef JSON_LESS_MEMORY +			 mycapacity = mysize + amount;  //increment the size of the array +		  #else +			 while(mysize + amount > mycapacity){ +				mycapacity <<= 1;  //double the size of the array +			 } +		  #endif +		  array = json_realloc<JSONNode*>(array, mycapacity); +	   } +    }    +} + +//actually deletes everything within the vector, this is safe to do on an empty or even a null array +void jsonChildren::deleteAll(void){ +    json_foreach((*this), runner){ +        JSON_ASSERT(*runner, JSON_TEXT("a null pointer within the children")); +	   JSONNode::deleteJSONNode(*runner);  //this is why I can't do forward declaration +    } +} + +void jsonChildren::doerase(JSONNode ** position, json_index_t number){ +    JSON_ASSERT(array, JSON_TEXT("erasing something from a null array 2")); +    JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 2")); +    JSON_ASSERT(position + number <= array + mysize, JSON_TEXT("erasing out of bounds 2")); +    if (position + number >= array + mysize){ +	   mysize = (json_index_t)(position - array); +	   #ifndef JSON_ISO_STRICT +		  JSON_ASSERT((long long)position - (long long)array >= 0, JSON_TEXT("doing negative allocation")); +	   #endif +    } else { +	   memmove(position, position + number, (mysize - (position - array) - number) * sizeof(JSONNode *)); +	   mysize -= number; +    } +} diff --git a/plugins/JSON/Source/JSONChildren.h b/plugins/JSON/Source/JSONChildren.h new file mode 100644 index 0000000000..acc9a712a2 --- /dev/null +++ b/plugins/JSON/Source/JSONChildren.h @@ -0,0 +1,234 @@ +#ifndef JSONCHILDREN_H +#define JSONCHILDREN_H + +#include "JSONMemory.h" +#include "JSONDebug.h"  //for JSON_ASSERT macro + +#define json_foreach(children, iterator)\ +    JSONNode ** iterator = children.begin();\ +    for(JSONNode ** iterator##_end = children.end(); iterator != iterator##_end; ++iterator) + +/* + This class is essentially a vector that has been heavily optimized for the specific purpose + of holding JSONNode children.  It acts the same way as a vector, it has a automatically + expanding array.  On destruction, this container automatically destroys everything contained + in it as well, so that you libJSON doesn't have to do that. +  + T is JSONNode*, I can't define it that way directly because JSONNode uses this container, and because + the container deletes the children automatically, forward declaration can't be used + */ + +class JSONNode;  //forward declaration + +class jsonChildren { +public: +    //starts completely empty and the array is not allocated +    jsonChildren(void) : array(0), mysize(0), mycapacity(0) { } +     +    //deletes the array and everything that is contained within it (using delete) +    ~jsonChildren(void){ +	   if (array){  //the following function calls are safe, but take more time than a check here +		  deleteAll(); +		  libjson_free<JSONNode*>(array); +	   } +    } +     +    //increase the size of the array +    void inc(json_index_t amount); +    void inc(void); +     +    //Adds something to the vector, doubling the array if necessary +    void push_back(JSONNode * item){ +	   inc(); +	   array[mysize++] = item; +    } +     +    //Adds something to the front of the vector, doubling the array if necessary +    void push_front(JSONNode * item){ +	   inc(); +	   memmove(array + 1, array, mysize++ * sizeof(JSONNode *)); +	   array[0] = item; +    } +     +    //gets an item out of the vector by it's position +    inline JSONNode * operator[] (json_index_t position) const { +	   JSON_ASSERT(position < mysize, JSON_TEXT("Using [] out of bounds")); +	   JSON_ASSERT(position < mycapacity, JSON_TEXT("Using [] out of bounds")); +	   JSON_ASSERT(array, JSON_TEXT("Array is null")); +	   return array[position]; +    } +     +    //returns the allocated capacity, but keep in mind that some might not be valid +    inline json_index_t capacity() const { +	   return mycapacity; +    } +     +    //returns the number of valid objects within the vector +    inline json_index_t size() const { +	   return mysize; +    } +     +    //tests whether or not the vector is empty +    inline bool empty() const { +	   return mysize == 0; +    } +     +    //clears (and deletes) everything from the vector and sets it's size to 0 +    inline void clear(){ +	   if (array){  //don't bother clearing anything if there is nothing in it +		  JSON_ASSERT(mycapacity != 0, JSON_TEXT("mycapacity is not zero, but array is null")); +		  deleteAll(); +		  mysize = 0; +	   } +	   JSON_ASSERT(mysize == 0, JSON_TEXT("mysize is not zero after clear")); +    } +     +    //returns the beginning of the array +    inline JSONNode ** begin(void) const { +	   return array; +    } +     +    //returns the end of the array +    inline JSONNode ** end(void) const { +	   return array + mysize; +    } +     +    //makes sure that even after shirnking and expanding, the iterator is in same relative position +    struct iteratorKeeper { +    public: +	   #ifdef JSON_LIBRARY +		  iteratorKeeper(jsonChildren * pthis, JSONNode ** & position) :  +			 myRelativeOffset((json_index_t)(position - pthis -> array)), +	   #else +		  iteratorKeeper(jsonChildren * pthis, JSONNode ** & position, bool reverse = false) :  +			 myRelativeOffset(reverse ? (json_index_t)(pthis -> array + (size_t)pthis -> mysize - position) : (json_index_t)(position - pthis -> array)), +			 myReverse(reverse), +	   #endif +			 myChildren(pthis),  +			 myPos(position){} + +	   ~iteratorKeeper(void){ +		  #ifdef JSON_LIBRARY +			 myPos = myChildren -> array + myRelativeOffset; +		  #else +			 if (myReverse){ +				myPos = myChildren -> array + myChildren -> mysize - myRelativeOffset; +			 } else { +				myPos = myChildren -> array + myRelativeOffset; +			 } +		  #endif +	   } +    private: +	   iteratorKeeper(const iteratorKeeper &); +	   iteratorKeeper & operator = (const iteratorKeeper &); +	    +	   jsonChildren * myChildren; +	   JSONNode ** & myPos; +	   json_index_t myRelativeOffset; +	   #ifndef JSON_LIBRARY +		  bool myReverse BITS(1); +	   #endif +    }; +     +    //This function DOES NOT delete the item it points to +    inline void erase(JSONNode ** & position){ +	   JSON_ASSERT(array, JSON_TEXT("erasing something from a null array 1")); +	   JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 1")); +	   JSON_ASSERT(position <= array + mysize, JSON_TEXT("erasing out of bounds 1")); +	   memmove(position, position + 1, (mysize-- - (position - array) - 1) * sizeof(JSONNode *)); +	   iteratorKeeper ik(this, position); +	   shrink(); +    } +     +    //This function DOES NOT delete the item it points to +    inline void erase(JSONNode ** & position, json_index_t number){ +	   doerase(position, number); +	   iteratorKeeper ik(this, position); +	   shrink(); +    } +     +     +    //This function DOES NOT delete the item it points to +    inline void erase(JSONNode ** position, json_index_t number, JSONNode ** & starter){ +	   doerase(position, number); +	   iteratorKeeper ik(this, starter); +	   shrink(); +    } +     +    #ifdef JSON_LIBRARY +	   void insert(JSONNode ** & position, JSONNode * item){ +    #else +	   void insert(JSONNode ** & position, JSONNode * item, bool reverse = false){ +    #endif +	   //position isnt relative to array because of realloc +	   JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 1")); +	   JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 1")); +	   { +		  #ifdef JSON_LIBRARY +			 iteratorKeeper ik(this, position); +		  #else +			 iteratorKeeper ik(this, position, reverse); +		  #endif +		  inc(); +	   } +	   memmove(position + 1, position, (mysize++ - (position - array)) * sizeof(JSONNode *)); +	   *position = item; +    } + +    void insert(JSONNode ** & position, JSONNode ** items, json_index_t num){ +	   JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 2")); +	   JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 2")); +	   { +		  iteratorKeeper ik(this, position); +		  inc(num); +	   } +	   const size_t ptrs = ((JSONNode **)(array + mysize)) - position; +	   memmove(position + num, position, ptrs * sizeof(JSONNode *)); +	   memcpy(position, items, num * sizeof(JSONNode *)); +	   mysize += num; +    } +     +    inline void reserve(json_index_t amount){ +	   JSON_ASSERT(!array, JSON_TEXT("reserve is not meant to expand a preexisting array")); +	   JSON_ASSERT(!mycapacity, JSON_TEXT("reservec is not meant to expand a preexisting array")); +	   JSON_ASSERT(!mysize, JSON_TEXT("reserves is not meant to expand a preexisting array")); +	   array = json_malloc<JSONNode*>(mycapacity = amount); +    } + +    inline void reserve2(json_index_t amount){ +	   if (array){ +		  if (mycapacity < amount) inc(amount - mycapacity); +	   } else { +		  reserve(amount); +	   } +    } +		   +    //shrinks the array to only as large as it needs to be to hold everything within it +    inline void shrink(){ +	   if (mysize == 0){  //size is zero, we should completely free the array +		  libjson_free<JSONNode*>(array);  //free does checks for a null pointer, so don't bother checking +		  array = 0; +		  #ifdef JSON_LESS_MEMORY +			 } else {  //need to shrink it, using realloc +				JSON_ASSERT(array, JSON_TEXT("shrinking a null array that is not size 0")); +				array = json_realloc<JSONNode*>(array, mysize); +		  #endif   +	   } +	   mycapacity = mysize; +    } +JSON_PRIVATE +    //to make sure it's not copyable +    jsonChildren(const jsonChildren &); +    jsonChildren & operator = (const jsonChildren &); +     +    void deleteAll(void);  //implemented in JSONNode.cpp +    void doerase(JSONNode ** position, json_index_t number); +     +    JSONNode ** array;  //the expandable array + +    json_index_t mysize;	     //the number of valid items +    json_index_t mycapacity;   //the number of possible items +}; + + +#endif diff --git a/plugins/JSON/Source/JSONDebug.cpp b/plugins/JSON/Source/JSONDebug.cpp new file mode 100644 index 0000000000..3061fff616 --- /dev/null +++ b/plugins/JSON/Source/JSONDebug.cpp @@ -0,0 +1,39 @@ +#include "JSONDebug.h" +#ifdef JSON_DEBUG + +#ifdef JSON_STDERROR +    #include <iostream>  //need std::cerr +#else +    //otherwise, use a callback to tell the end user what happened +    json_error_callback_t ErrorCallback = 0; +    void JSONDebug::register_callback(json_error_callback_t callback){ +	   ErrorCallback = callback; +    } +#endif + +//Something went wrong or an assert failed +void JSONDebug::_JSON_FAIL(const json_string & msg){ +    #ifdef JSON_STDERROR  //no callback, just use stderror +	   #ifndef JSON_UNICODE +		  std::cerr << msg << std::endl; +	   #else +		  std::cerr << std::string(msg.begin(), msg.end()) << std::endl; +	   #endif +    #else +	   if (ErrorCallback){  //only do anything if the callback is registered +		  #ifdef JSON_LIBRARY +			 ErrorCallback(msg.c_str()); +		  #else +			 ErrorCallback(msg); +		  #endif +	   } +    #endif +} + +//asserts that condition is true, more useful than cassert because it lets you keep going +void JSONDebug::_JSON_ASSERT(bool condition, const json_string & msg){ +    if (!condition){ +	   _JSON_FAIL(msg); +    } +} +#endif diff --git a/plugins/JSON/Source/JSONDebug.h b/plugins/JSON/Source/JSONDebug.h new file mode 100644 index 0000000000..cace9b5c8e --- /dev/null +++ b/plugins/JSON/Source/JSONDebug.h @@ -0,0 +1,68 @@ +#ifndef JSON_DEBUG_H +#define JSON_DEBUG_H + +#include "JSONDefs.h" +#include "../JSONOptions.h" + +#ifdef JSON_UNIT_TEST +    #define JSON_PRIVATE +#else +    #define JSON_PRIVATE private: +#endif + +#ifdef JSON_DEBUG +    #ifdef JSON_SAFE +	   #define JSON_ASSERT_SAFE(condition, msg, code)\ +		  {\ +			 if (!(condition)){\ +				JSON_FAIL(msg);\ +				code\ +			 }\ +		  } +	   #define JSON_FAIL_SAFE(msg, code)\ +		  {\ +			 JSON_FAIL(msg);\ +			 code\ +		  } +    #else +	   #define JSON_ASSERT_SAFE(condition, msg, code) JSON_ASSERT(condition, msg) +	   #define JSON_FAIL_SAFE(msg, code) JSON_FAIL(msg) +    #endif + +    #define JSON_FAIL JSONDebug::_JSON_FAIL	 +    #define JSON_ASSERT JSONDebug::_JSON_ASSERT	 + +    class JSONDebug { +    public: +	   #ifndef JSON_STDERROR +		  static void register_callback(json_error_callback_t callback); +	   #endif +	   static void _JSON_FAIL(const json_string & msg); +	   static void _JSON_ASSERT(bool condition, const json_string & msg); +    }; +#else +    #ifdef JSON_SAFE +	   #define JSON_ASSERT_SAFE(condition, msg, code)\ +		  {\ +			 if (!(condition)){\ +				code\ +			 }\ +		  } +	   #define JSON_FAIL_SAFE(msg, code)\ +		  {\ +			 code\ +		  } +    #else +	   #define JSON_ASSERT_SAFE(condition, msg, code) +	   #define JSON_FAIL_SAFE(msg, code) +    #endif + +    #define JSON_ASSERT(condition, msg) +    #define JSON_FAIL(msg) +#endif + +static const json_string EMPTY_STRING; +static const std::string EMPTY_STRING2; + +#endif + diff --git a/plugins/JSON/Source/JSONDefs.h b/plugins/JSON/Source/JSONDefs.h new file mode 100644 index 0000000000..3cc6a3be35 --- /dev/null +++ b/plugins/JSON/Source/JSONDefs.h @@ -0,0 +1,81 @@ +#ifndef JSONDEFS_H +#define JSONDEFS_H + +/* +    Defines all of the types of functions and various other definitions +    that are used in C applications, this is very useful if dynamically loading +    the library instead of linking. +*/ + +#include "../JSONOptions.h" + +#define JSON_NULL '\0' +#define JSON_STRING '\1' +#define JSON_NUMBER '\2' +#define JSON_BOOL '\3' +#define JSON_ARRAY '\4' +#define JSON_NODE '\5' + +#ifdef __cplusplus +    #include <string> +#endif + +#ifdef JSON_UNICODE +    #ifdef JSON_ISO_STRICT +	   #error, You can not use unicode under ISO Strict C++ +    #endif +    #define json_char wchar_t +    #ifdef __cplusplus +	   #include <cwchar>  //need wide characters +	   typedef std::wstring json_string; +    #else +	   #include <wchar.h>  //need wide characters +    #endif +    #define JSON_TEXT(s) L ## s +    #define json_strlen wcslen +    #define json_strcmp wcscmp +#else +    #define json_char char +    #ifdef __cplusplus +	   typedef std::string json_string; +    #endif +    #define JSON_TEXT(s) s +    #define json_strlen strlen +    #define json_strcmp strcmp +#endif + +#ifdef JSON_LESS_MEMORY +    #define BITS(x) :x  //tells the compiler how many bits to use for a field +    typedef float json_number; +#else +    #define BITS(x) +    typedef double json_number; +#endif + +#if defined JSON_DEBUG || defined JSON_SAFE +    #ifdef JSON_LIBRARY +	   typedef void (*json_error_callback_t)(const json_char *); +    #else +	   typedef void (*json_error_callback_t)(const json_string &); +    #endif +#endif + +#ifdef JSON_INDEX_TYPE +    typedef JSON_INDEX_TYPE json_index_t; +#else +    typedef unsigned int json_index_t; +#endif + +typedef void (*json_mutex_callback_t)(void *); +typedef void (*json_free_t)(void *); +#ifndef JSON_LIBRARY +    typedef void * (*json_malloc_t)(size_t); +    typedef void * (*json_realloc_t)(void *, size_t); +#else +    #define JSONNODE void  //so that JSONNODE* is void* +    typedef JSONNODE** JSONNODE_ITERATOR; +    typedef void * (*json_malloc_t)(unsigned long); +    typedef void * (*json_realloc_t)(void *, unsigned long); +#endif + +#endif //JSONDEFS_H diff --git a/plugins/JSON/Source/JSONIterators.cpp b/plugins/JSON/Source/JSONIterators.cpp new file mode 100644 index 0000000000..5b140d9b17 --- /dev/null +++ b/plugins/JSON/Source/JSONIterators.cpp @@ -0,0 +1,214 @@ +#include "JSONNode.h" + +#ifdef JSON_ITERATORS +    #ifdef JSON_REF_COUNT +	   #define JSON_ASSERT_UNIQUE(x) JSON_ASSERT(internal -> refcount == 1, json_string(JSON_TEXT(x)) + JSON_TEXT(" in non single reference")) +    #else +	   #define JSON_ASSERT_UNIQUE(x) (void)0 +    #endif + +    #ifdef JSON_MUTEX_CALLBACKS +	   #define JSON_MUTEX_COPY2 ,internal -> mylock +    #else +	   #define JSON_MUTEX_COPY2 +    #endif + +JSONNode::json_iterator JSONNode::find(const json_string & name_t){ +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); +    makeUniqueInternal(); +    if (JSONNode ** res = internal -> at(name_t)){ +	   return ptr_to_json_iterator(res); +    } +    return end(); +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +    JSONNode::json_iterator JSONNode::find_nocase(const json_string & name_t){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); +	   makeUniqueInternal(); +	   if (JSONNode ** res = internal -> at_nocase(name_t)){ +		  return ptr_to_json_iterator(res); +	   } +	   return end(); +    } +#endif + +JSONNode::json_iterator JSONNode::erase(json_iterator pos){ +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +    JSON_ASSERT_UNIQUE("erase 1"); +    JSON_ASSERT_SAFE(pos < end(), JSON_TEXT("erase out of range"), return end();); +    JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("erase out of range"), return begin();); +    deleteJSONNode(*(json_iterator_ptr(pos))); +    internal -> Children.erase(json_iterator_ptr(pos)); +    return (empty()) ? end() : pos; +} + +JSONNode::json_iterator JSONNode::erase(json_iterator _start, const json_iterator & _end){ +    if (_start == _end) return _start; +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +    JSON_ASSERT_UNIQUE("erase 3"); +    JSON_ASSERT_SAFE(_start <= end(), JSON_TEXT("erase out of lo range"), return end();); +    JSON_ASSERT_SAFE(_end <= end(), JSON_TEXT("erase out of hi range"), return end();); +    JSON_ASSERT_SAFE(_start >= begin(), JSON_TEXT("erase out of lo range"), return begin();); +    JSON_ASSERT_SAFE(_end >= begin(), JSON_TEXT("erase out of hi range"), return begin();); +    for (JSONNode ** pos = json_iterator_ptr(_start); pos < json_iterator_ptr(_end); ++pos){ +	   deleteJSONNode(*pos); +    } +     +    internal -> Children.erase(json_iterator_ptr(_start), json_iterator_ptr(_end) - json_iterator_ptr(_start)); +    return (empty()) ? end() : _start; +} + +#ifdef JSON_LIBRARY +JSONNode::json_iterator JSONNode::insert(json_iterator pos, JSONNode * x){ +#else +JSONNode::json_iterator JSONNode::insert(json_iterator pos, const JSONNode & x){ +#endif +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +    JSON_ASSERT_UNIQUE("insert 1"); +    if (json_iterator_ptr(pos) >= internal -> Children.end()){ +	   internal -> push_back(x); +	   return end() - 1; +    } +    JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of lo range"), return begin();); +    #ifdef JSON_LIBRARY +	   internal -> Children.insert(json_iterator_ptr(pos), x); +    #else +	   internal -> Children.insert(json_iterator_ptr(pos), newJSONNode(x)); +    #endif +    return pos; +} +     +JSONNode::json_iterator JSONNode::insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +    JSON_ASSERT_UNIQUE("insertFFF"); +    JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of high range"), return end();); +    JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of low range"), return begin();); +    const size_t num = _end - _start; +    json_auto<JSONNode *> mem(num); +    JSONNode ** runner = mem.ptr; +    for (JSONNode ** po = _start; po < _end; ++po){ +	   *runner++ = newJSONNode(*(*po)  JSON_MUTEX_COPY2); +    } +    internal -> Children.insert(json_iterator_ptr(pos), mem.ptr, num); +    return pos;    +} + +#ifndef JSON_LIBRARY +    JSONNode::const_iterator JSONNode::find(const json_string & name_t) const { +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); +	   if (JSONNode ** res = internal -> at(name_t)){ +		  return JSONNode::const_iterator(res); +	   } +	   return JSONNode::const_iterator(internal -> end()); +    } +     +    #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +	   JSONNode::const_iterator JSONNode::find_nocase(const json_string & name_t) const { +		  JSON_CHECK_INTERNAL(); +		  JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); +		  if (JSONNode ** res = internal -> at_nocase(name_t)){ +			 return JSONNode::const_iterator(res); +		  } +		  return JSONNode::const_iterator(internal -> end()); +	   } +    #endif +     +    JSONNode::reverse_iterator JSONNode::erase(reverse_iterator pos){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +	   JSON_ASSERT_UNIQUE("erase 2"); +	   JSON_ASSERT_SAFE(pos < rend(), JSON_TEXT("erase out of range"), return rend();); +	   JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("erase out of range"), return rbegin();); +	   deleteJSONNode(*(pos.it)); +	   internal -> Children.erase(pos.it); +	   return (empty()) ? rend() : pos + 1; +    } +     +    JSONNode::reverse_iterator JSONNode::erase(reverse_iterator _start, const reverse_iterator & _end){ +	   if (_start == _end) return _start; +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +	   JSON_ASSERT_UNIQUE("erase 4"); +	   JSON_ASSERT_SAFE(_start <= rend(), JSON_TEXT("erase out of lo range"), return rend();); +	   JSON_ASSERT_SAFE(_end <= rend(), JSON_TEXT("erase out of hi range"), return rend();); +	   JSON_ASSERT_SAFE(_start >= rbegin(), JSON_TEXT("erase out of lo range"), return rbegin();); +	   JSON_ASSERT_SAFE(_end >= rbegin(), JSON_TEXT("erase out of hi range"), return rbegin();); +	   for (JSONNode ** pos = _start.it; pos > _end.it; --pos){ +		  deleteJSONNode(*pos); +	   } +	   const size_t num = _start.it - _end.it; +	   internal -> Children.erase(_end.it + 1, num, _start.it); +	   return (empty()) ? rend() : _start + num; +    } +     +    JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const JSONNode & x){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +	   JSON_ASSERT_UNIQUE("insert 1"); +	   if (pos.it < internal -> Children.begin()){ +		  internal -> push_front(x); +		  return rend() - 1; +	   } +	   JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); +	   internal -> Children.insert(++pos.it, newJSONNode(x), true); +	   return pos; +    } +     +    JSONNode::reverse_iterator JSONNode::insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +	   JSON_ASSERT_UNIQUE("insert RFF"); +	   JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); +	   JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); +	   const size_t num = _end - _start; +	   json_auto<JSONNode *> mem(num); +	   JSONNode ** runner = mem.ptr + num; +	   for (JSONNode ** po = _start; po < _end; ++po){  //fill it backwards +		  *(--runner) = newJSONNode(*(*po)    JSON_MUTEX_COPY2); +	   } +	   internal -> Children.insert(++pos.it, mem.ptr, num); +	   return pos - num + 1; +    } +     +    JSONNode::iterator JSONNode::insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +	   JSON_ASSERT_UNIQUE("insert FRR"); +	   JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of range"), return end();); +	   JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of range"), return begin();); +	   const size_t num = _start - _end; +	   json_auto<JSONNode *> mem(num); +	   JSONNode ** runner = mem.ptr; +	   for (JSONNode ** po = _start; po > _end; --po){ +		  *runner++ = newJSONNode(*(*po)    JSON_MUTEX_COPY2); +	   } +	   internal -> Children.insert(pos.it, mem.ptr, num); +	   return pos;  +    } +     +    JSONNode::reverse_iterator JSONNode::insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); +	   JSON_ASSERT_UNIQUE("insert RRR"); +	   JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); +	   JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); +	   const size_t num = _start - _end; +	   json_auto<JSONNode *> mem(num); +	   JSONNode ** runner = mem.ptr; +	   for (JSONNode ** po = _start; po > _end; --po){ +		  *runner++ = newJSONNode(*(*po)    JSON_MUTEX_COPY2); +	   } +	   internal -> Children.insert(++pos.it, mem.ptr, num); +	   return pos - num + 1;    +    } +#endif + +#endif diff --git a/plugins/JSON/Source/JSONMemory.cpp b/plugins/JSON/Source/JSONMemory.cpp new file mode 100644 index 0000000000..e0181e019a --- /dev/null +++ b/plugins/JSON/Source/JSONMemory.cpp @@ -0,0 +1,81 @@ +#include "JSONMemory.h" +#include "JSONNode.h" + +#ifdef JSON_MEMORY_MANAGE +    void auto_expand::purge(void){ +	   for(std::map<void *, void *>::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ +		  #if defined(JSON_DEBUG) || defined(JSON_SAFE) +			 void * temp = (void*)i -> first;  //because its pass by reference +			 libjson_free<void>(temp); +		  #else +			 libjson_free<void>((void*)i -> first); +		  #endif +	   } +    } + +    void auto_expand_node::purge(void){ +	   for(std::map<void *, JSONNode *>::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ +		  JSONNode::deleteJSONNode((JSONNode *)i -> second);  +	   } +    } +#endif + +#ifdef JSON_MEMORY_CALLBACKS + +json_malloc_t mymalloc = 0; +json_realloc_t myrealloc = 0; +json_free_t myfree = 0; + +void * JSONMemory::json_malloc(size_t siz){ +    if (mymalloc){ +	   #ifdef JSON_DEBUG  //in debug mode, see if the malloc was successful +		  void * result = mymalloc(siz); +		  JSON_ASSERT(result, JSON_TEXT("out of memory")); +		  return result; +	   #else +		  return mymalloc(siz); +	   #endif +    } +    #ifdef JSON_DEBUG  //in debug mode, see if the malloc was successful +	   void * result = malloc(siz); +	   JSON_ASSERT(result, JSON_TEXT("out of memory")); +	   return result; +    #else +	   return malloc(siz); +    #endif +} + +void * JSONMemory::json_realloc(void * ptr, size_t siz){ +    if (myrealloc){ +	   #ifdef JSON_DEBUG  //in debug mode, see if the malloc was successful +		  void * result = myrealloc(ptr, siz); +		  JSON_ASSERT(result, JSON_TEXT("out of memory")); +		  return result; +	   #else +		  return myrealloc(ptr, siz); +	   #endif +    } +    #ifdef JSON_DEBUG  //in debug mode, see if the malloc was successful +	   void * result = realloc(ptr, siz); +	   JSON_ASSERT(result, JSON_TEXT("out of memory")); +	   return result; +    #else +	   return realloc(ptr, siz); +    #endif   +} + +void JSONMemory::json_free(void * ptr){ +    if (myfree){ +	   myfree(ptr); +    } else { +	   free(ptr); +    } +} + +void JSONMemory::registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre){ +    mymalloc = mal; +    myrealloc = real; +    myfree = fre; +} + +#endif diff --git a/plugins/JSON/Source/JSONMemory.h b/plugins/JSON/Source/JSONMemory.h new file mode 100644 index 0000000000..4797bd619f --- /dev/null +++ b/plugins/JSON/Source/JSONMemory.h @@ -0,0 +1,134 @@ +#ifndef JSON_MEMORY_H +#define JSON_MEMORY_H + +#include <cstdlib> //for malloc, realloc, and free +#include <cstring> //for memmove +#include "../JSONOptions.h" +#include "JSONDebug.h" + +#if defined(JSON_DEBUG) || defined(JSON_SAFE) +    #define JSON_FREE_PASSTYPE & +#else +    #define JSON_FREE_PASSTYPE +#endif + +#ifdef JSON_MEMORY_CALLBACKS +    class JSONMemory { +    public: +	   static void * json_malloc(size_t siz); +	   static void * json_realloc(void * ptr, size_t siz); +	   static void json_free(void * ptr); +	   static void registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre); +    }; + +    template <typename T> static inline T * json_malloc(size_t count){ +	   return (T *)JSONMemory::json_malloc(sizeof(T) * count); +    } + +    template <typename T> static inline T * json_realloc(T * ptr, size_t count){ +	   return (T *)JSONMemory::json_realloc(ptr, sizeof(T) * count); +    } + +    template <typename T> static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr){ +	   JSONMemory::json_free(ptr); +	   #if defined(JSON_DEBUG) || defined(JSON_SAFE)  //in debug or safe mode, set the pointer to 0 so that it can't be used again +		  ptr = 0; +	   #endif +    } +#else +    template <typename T> +    static inline T * json_malloc(size_t count){ +	   #ifdef JSON_DEBUG  //in debug mode, see if the malloc was successful +		  void * result = malloc(count * sizeof(T)); +		  JSON_ASSERT(result, JSON_TEXT("out of memory")); +		  #ifdef JSON_NULL_MEMORY +			 memset(result, '\0', count  * sizeof(T)); +		  #endif +		  return (T *)result; +	   #else +		  return (T *)malloc(count * sizeof(T)); +	   #endif +    } + +    template <typename T> +    static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr){ +	   free(ptr); +	   #if defined(JSON_DEBUG) || defined(JSON_SAFE)  //in debug or safe mode, set the pointer to 0 so that it can't be used again +		  ptr = 0; +	   #endif +    } + +    template <typename T> +    static inline T * json_realloc(T * ptr, size_t count){ +	   #ifdef JSON_DEBUG  //in debug mode, check the results of realloc to be sure it was successful +		  void * result = realloc(ptr, count * sizeof(T)); +		  JSON_ASSERT(result, JSON_TEXT("out of memory")); +		  #ifdef JSON_NULL_MEMORY +			 memset(result, '\0', count  * sizeof(T)); +		  #endif +		  return (T *)result; +	   #else +		  return (T *)realloc(ptr, count * sizeof(T)); +	   #endif +    } +#endif + +#ifdef JSON_MEMORY_MANAGE +    #include <map> +    class JSONNode; +    struct auto_expand { +	   auto_expand(void) : mymap(){} +	   ~auto_expand(void){ purge(); } +	   void purge(void); +	   inline void clear(void){ purge(); mymap.clear(); } +	   inline void * insert(void * ptr){ mymap[ptr] = ptr; return ptr; } +	   inline void remove(void * ptr){  +		  std::map<void *, void *>::iterator i = mymap.find(ptr); +		  JSON_ASSERT(i != mymap.end(), JSON_TEXT("Removing a non-managed item")); +		  mymap.erase(i); +	   } +	   std::map<void *, void *> mymap; +    }; + +    struct auto_expand_node { +	   auto_expand_node(void) : mymap(){} +	   ~auto_expand_node(void){ purge(); } +	   void purge(void); +	   inline void clear(void){ purge(); mymap.clear(); } +	   inline JSONNode * insert(JSONNode * ptr){ mymap[ptr] = ptr; return ptr; } +	   inline void remove(void * ptr){  +		  std::map<void *, JSONNode *>::iterator i = mymap.find(ptr); +		  if(i != mymap.end()) mymap.erase(i); +	   } +	   std::map<void *, JSONNode *> mymap; +    }; +#endif + +//The C++ way, use an self-deleting pointer and let the optimizer decide when it gets destroyed +template <typename T> +class json_auto { +    public: +	   json_auto(void) : ptr(0){} +	   json_auto(size_t count) : ptr(json_malloc<T>(count)){} +	   ~json_auto(void){ +		  libjson_free<T>(ptr); +	   } +	   void set(T * p){ +		  ptr = p;  +	   } +	   T * ptr; +    private: +	   json_auto(const json_auto &); +	   json_auto & operator =(const json_auto &); +}; + +//Clears a string, if required, frees the memory +static inline void clearString(json_string & str){ +    #ifdef JSON_LESS_MEMORY +	   json_string().swap(str); +    #else +	   str.clear(); +    #endif +} + +#endif diff --git a/plugins/JSON/Source/JSONNode.cpp b/plugins/JSON/Source/JSONNode.cpp new file mode 100644 index 0000000000..f4ced9a478 --- /dev/null +++ b/plugins/JSON/Source/JSONNode.cpp @@ -0,0 +1,287 @@ +#include "JSONNode.h" + +#ifdef JSON_UNIT_TEST +    int allocCount = 0; +    int deallocCount = 0; +    int internalAllocCount = 0; +    int internalDeallocCount = 0; +    int JSONNode::getNodeAllocationCount(void){ return allocCount; } +    int JSONNode::getNodeDeallocationCount(void){ return deallocCount; } +    int JSONNode::getInternalAllocationCount(void){ return internalAllocCount; } +    int JSONNode::getInternalDeallocationCount(void){ return internalDeallocCount; } +    void JSONNode::incAllocCount(void){ ++allocCount; } +    void JSONNode::decAllocCount(void){ ++deallocCount; } +    void JSONNode::incinternalAllocCount(void){ ++internalAllocCount; } +    void JSONNode::decinternalAllocCount(void){ ++internalDeallocCount; } +#endif + +#define IMPLEMENT_CTOR(type)\ +    JSONNode::JSONNode(const json_string & name_t, type value_t) : internal(internalJSONNode::newInternal()){\ +	   internal -> Set(value_t);\ +	   internal -> setname(name_t);\ +	   incAllocCount();\ +    } +IMPLEMENT_FOR_ALL_TYPES(IMPLEMENT_CTOR) + +#ifndef JSON_LIBRARY +    JSONNode::JSONNode(const json_string & name_t, const json_char * value_t) : internal(internalJSONNode::newInternal()){ +	   internal -> Set(json_string(value_t)); +	   internal -> setname(name_t); +	   incAllocCount(); +    } +#endif + +JSONNode JSONNode::as_node(void) const { +    JSON_CHECK_INTERNAL(); +    if (type() == JSON_NODE){ +	   return *this; +    } else if (type() == JSON_ARRAY){ +	   JSONNode res = duplicate(); +	   res.internal -> _type = JSON_NODE; +	   return res; +    } +    #ifdef JSON_MUTEX_CALLBACKS +	   if (internal -> mylock){ +		  JSONNode res = JSONNode(JSON_NODE); +		  res.set_mutex(internal -> mylock); +		  return res; +	   } +    #endif +    return JSONNode(JSON_NODE); +} + +JSONNode JSONNode::as_array(void) const { +    JSON_CHECK_INTERNAL(); +    if (type() == JSON_ARRAY){ +	   return *this; +    } else if (type() == JSON_NODE){ +	   JSONNode res = duplicate(); +	   res.internal -> _type = JSON_ARRAY; +	   json_foreach(res.internal -> Children, runner){ +		  (*runner) -> set_name(JSON_TEXT("")); +	   } +	   return res; +    } +    #ifdef JSON_MUTEX_CALLBACKS +	   if (internal -> mylock){ +		  JSONNode res = JSONNode(JSON_ARRAY); +		  res.set_mutex(internal -> mylock); +		  return res; +	   } +    #endif +    return JSONNode(JSON_ARRAY); +} + +void JSONNode::cast(char newtype){ +    JSON_CHECK_INTERNAL(); +    if (newtype == type()) return; +     +    switch(newtype){ +	   case JSON_NULL: +		  nullify(); +		  return; +	   case JSON_STRING: +		  *this = as_string(); +		  return; +	   case JSON_NUMBER: +		  *this = as_float(); +		  return; +	   case JSON_BOOL: +		  *this = as_bool(); +		  return; +	   case JSON_ARRAY: +		  *this = as_array(); +		  return; +	   case JSON_NODE: +		  *this = as_node(); +		  return; +    } +    JSON_FAIL(JSON_TEXT("cast to unknown type")); +} + +//different just to supress the warning +#ifdef JSON_REF_COUNT +void JSONNode::merge(JSONNode & other){ +#else +void JSONNode::merge(JSONNode &){ +#endif +    JSON_CHECK_INTERNAL(); +    #ifdef JSON_REF_COUNT +	   if (internal == other.internal) return; +	   JSON_ASSERT(*this == other, JSON_TEXT("merging two nodes that aren't equal")); +	   if (internal -> refcount < other.internal -> refcount){ +		  *this = other; +	   } else { +		  other = *this; +	   } +    #endif +} + +#ifdef JSON_REF_COUNT +    void JSONNode::merge(JSONNode * other){ +	   JSON_CHECK_INTERNAL(); +	   if (internal == other -> internal) return; +	   *other = *this; +    } + +    //different just to supress the warning +    void JSONNode::merge(unsigned int num, ...){ +#else +    void JSONNode::merge(unsigned int, ...){ +#endif +    JSON_CHECK_INTERNAL(); +    #ifdef JSON_REF_COUNT +	   va_list args; +	   va_start(args, num); +	   for(unsigned int i = 0; i < num; ++i){ +		  merge(va_arg(args, JSONNode*)); +	   } +	   va_end(args); +    #endif +} + +JSONNode JSONNode::duplicate(void) const { +    JSON_CHECK_INTERNAL(); +    JSONNode mycopy(*this); +    #ifdef JSON_REF_COUNT +	   JSON_ASSERT(internal == mycopy.internal, JSON_TEXT("copy ctor failed to ref count correctly")); +	   mycopy.makeUniqueInternal(); +    #endif +    JSON_ASSERT(internal != mycopy.internal, JSON_TEXT("makeUniqueInternal failed")); +    return mycopy; +} + +JSONNode & JSONNode::at(json_index_t pos){ +    JSON_CHECK_INTERNAL(); +    if (pos >= internal -> size()){ +	   JSON_FAIL(JSON_TEXT("at() out of bounds")); +	   throw std::out_of_range(EMPTY_STRING2); +    } +    return (*this)[pos]; +} + +const JSONNode & JSONNode::at(json_index_t pos) const { +    JSON_CHECK_INTERNAL(); +    if (pos >= internal -> size()){ +	   JSON_FAIL(JSON_TEXT("at() const out of bounds")); +	   throw std::out_of_range(EMPTY_STRING2); +    } +    return (*this)[pos]; +} + +JSONNode & JSONNode::operator[](json_index_t pos){ +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] out of bounds")); +    makeUniqueInternal(); +    return *(internal -> at(pos)); +} + +const JSONNode & JSONNode::operator[](json_index_t pos) const { +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] const out of bounds")); +    return *(internal -> at(pos)); +} + +JSONNode & JSONNode::at(const json_string & name_t){ +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); +    makeUniqueInternal(); +    if (JSONNode ** res = internal -> at(name_t)){ +	   return *(*res); +    } +    JSON_FAIL(json_string(JSON_TEXT("at could not find child by name: ")) + name_t); +    throw std::out_of_range(EMPTY_STRING2); +} + +const JSONNode & JSONNode::at(const json_string & name_t) const { +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); +    if (JSONNode ** res = internal -> at(name_t)){ +	   return *(*res); +    } +    JSON_FAIL(json_string(JSON_TEXT("at const could not find child by name: ")) + name_t); +    throw std::out_of_range(EMPTY_STRING2); +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +    JSONNode & JSONNode::at_nocase(const json_string & name_t){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); +	   makeUniqueInternal(); +	   if (JSONNode ** res = internal -> at_nocase(name_t)){ +		  return *(*res); +	   } +	   JSON_FAIL(json_string(JSON_TEXT("at_nocase could not find child by name: ")) + name_t); +	   throw std::out_of_range(EMPTY_STRING2); +    } + +    const JSONNode & JSONNode::at_nocase(const json_string & name_t) const { +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); +	   if (JSONNode ** res = internal -> at_nocase(name_t)){ +		  return *(*res); +	   } +	   JSON_FAIL(json_string(JSON_TEXT("at_nocase const could not find child by name: ")) + name_t); +	   throw std::out_of_range(EMPTY_STRING2); +    } +#endif + +#ifndef JSON_LIBRARY +    struct auto_delete { +	   public: +		  auto_delete(JSONNode * node) : mynode(node){}; +		  ~auto_delete(void){ JSONNode::deleteJSONNode(mynode); }; +		  JSONNode * mynode; +	   private: +		  auto_delete(const auto_delete &); +		  auto_delete & operator = (const auto_delete &); +    }; +#endif + +JSONNode JSON_PTR_LIB JSONNode::pop_back(json_index_t pos){ +    JSON_CHECK_INTERNAL(); +    if (pos >= internal -> size()){ +	   JSON_FAIL(JSON_TEXT("pop_back out of bounds")); +	   throw std::out_of_range(EMPTY_STRING2); +    } +    makeUniqueInternal(); +    #ifdef JSON_LIBRARY +	   return internal -> pop_back(pos); +    #else +	   auto_delete temp(internal -> pop_back(pos)); +	   return *temp.mynode; +    #endif +} + +JSONNode JSON_PTR_LIB JSONNode::pop_back(const json_string & name_t){ +    JSON_CHECK_INTERNAL(); +    JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("popping a non-iteratable node")); +    #ifdef JSON_LIBRARY +	   return internal -> pop_back(name_t); +    #else +	   if (JSONNode * res = internal -> pop_back(name_t)){ +		  auto_delete temp(res); +		  return *(temp.mynode); +	   } +	   JSON_FAIL(json_string(JSON_TEXT("pop_back const could not find child by name: ")) + name_t); +	   throw std::out_of_range(EMPTY_STRING2);   +    #endif +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +    JSONNode JSON_PTR_LIB JSONNode::pop_back_nocase(const json_string & name_t){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("popping a non-iteratable node")); +	   #ifdef JSON_LIBRARY +		  return internal -> pop_back_nocase(name_t); +	   #else +		  if (JSONNode * res = internal -> pop_back_nocase(name_t)){ +			 auto_delete temp(res); +			 return *(temp.mynode); +		  } +		  JSON_FAIL(json_string(JSON_TEXT("pop_back_nocase could not find child by name: ")) + name_t); +		  throw std::out_of_range(EMPTY_STRING2);    +	   #endif +    } +#endif + diff --git a/plugins/JSON/Source/JSONNode.h b/plugins/JSON/Source/JSONNode.h new file mode 100644 index 0000000000..b4fad7573c --- /dev/null +++ b/plugins/JSON/Source/JSONNode.h @@ -0,0 +1,923 @@ +#ifndef JSONNODE_H +#define JSONNODE_H + +#include "JSONDefs.h"   //for string type +#include "internalJSONNode.h"  //internal structure for json value +#include <stdexcept> +#include <cstdarg>  //for the ... parameter + +#ifdef JSON_BINARY +    #include "JSON_Base64.h" +#endif + +#ifndef JSON_REF_COUNT +    #define makeUniqueInternal() (void)0 +#endif + +#define JSON_CHECK_INTERNAL() JSON_ASSERT(internal, JSON_TEXT("no internal")) + +#ifdef JSON_MUTEX_CALLBACKS +    #define JSON_MUTEX_COPY_DECL ,void * parentMutex +    #define JSON_MUTEX_COPY_DECL2 ,void * parentMutex = 0 +#else +    #define JSON_MUTEX_COPY_DECL +    #define JSON_MUTEX_COPY_DECL2 +#endif + +#ifdef JSON_LIBRARY +    #define JSON_PTR_LIB * +    #define JSON_NEW(x) JSONNode::newJSONNode_Shallow(x) +    #define DECLARE_FOR_ALL_TYPES(foo)\ +	   foo(long);\ +	   foo(json_number);\ +	   foo(bool);\ +	   foo(const json_string &); + +    #define DECLARE_FOR_ALL_TYPES_CONST(foo)\ +	   foo(long) const;\ +	   foo(json_number) const;\ +	   foo(bool) const;\ +	   foo(const json_string &) const;\ +	   foo(const JSONNode &) const; + +    #define IMPLEMENT_FOR_ALL_NUMBERS(foo)\ +	   foo(long)\ +	   foo(json_number) + + +#else +    #define JSON_PTR_LIB +    #define JSON_NEW(x) x +    #define DECLARE_FOR_ALL_TYPES(foo)\ +	   foo(char); foo(unsigned char);\ +	   foo(short); foo(unsigned short);\ +	   foo(int); foo(unsigned int);\ +	   foo(long); foo(unsigned long);\ +	   foo(float); foo(double);\ +	   foo(bool);\ +	   foo(const json_string &);\ +	   foo(const json_char *); + +    #define DECLARE_FOR_ALL_TYPES_CONST(foo)\ +	   foo(char) const; foo(unsigned char) const;\ +	   foo(short) const; foo(unsigned short) const;\ +	   foo(int) const; foo(unsigned int) const;\ +	   foo(long) const; foo(unsigned long) const;\ +	   foo(float) const; foo(double) const;\ +	   foo(bool) const;\ +	   foo(const json_string &) const;\ +	   foo(const JSONNode &) const;\ +	   foo(const json_char *) const; + +    #define IMPLEMENT_FOR_ALL_NUMBERS(foo)\ +	   foo(char) foo(unsigned char)\ +	   foo(short) foo(unsigned short)\ +	   foo(int) foo(unsigned int)\ +	   foo(long) foo(unsigned long)\ +	   foo(float) foo(double) + +#endif + +#define IMPLEMENT_FOR_ALL_TYPES(foo)\ +    IMPLEMENT_FOR_ALL_NUMBERS(foo)\ +    foo(const json_string &)\ +    foo(bool) + +/* +    This class is mostly just a wrapper class around internalJSONNode, this class keeps +    the reference count and handles copy on write and such.  This class is also responsible +    for argument checking and throwing exceptions if needed. +*/ + + +class JSONNode { +public:  +    explicit JSONNode(char mytype = JSON_NODE); +    #define DECLARE_CTOR(type) JSONNode(const json_string & name_t, type value_t) +    DECLARE_FOR_ALL_TYPES(DECLARE_CTOR) +     +    JSONNode(const JSONNode & orig);     +    ~JSONNode(void); +  +    json_index_t size(void) const; +    bool empty(void) const; +    void clear(void); +    unsigned char type(void) const; +     +    json_string name(void) const; +    void set_name(const json_string & newname); +    #ifdef JSON_COMMENTS +	   void set_comment(const json_string & comment); +	   json_string get_comment(void) const; +    #endif +    #ifndef JSON_PREPARSE +	   void preparse(void); +    #endif +    #ifdef JSON_VALIDATE +	   #ifndef JSON_SAFE +		  #error JSON_VALIDATE also requires JSON_SAFE +	   #endif +	   bool validate(void); +    #endif +     +    json_string as_string(void) const; +    long as_int(void) const; +    json_number as_float(void) const; +    bool as_bool(void) const; +    JSONNode as_node(void) const; +    JSONNode as_array(void) const; +     +    #ifdef JSON_BINARY +	   std::string as_binary(void) const; +	   void set_binary(const unsigned char * bin, json_index_t bytes); +    #endif +     +    JSONNode & at(json_index_t pos); +    const JSONNode & at(json_index_t pos) const; +    JSONNode & operator[](json_index_t pos); +    const JSONNode & operator[](json_index_t pos) const; +    +    JSONNode & at(const json_string & name_t); +    const JSONNode & at(const json_string & name_t) const; +    #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +	   JSONNode & at_nocase(const json_string & name_t); +	   const JSONNode & at_nocase(const json_string & name_t) const; +    #endif +    JSONNode & operator[](const json_string & name_t); +    const JSONNode & operator[](const json_string & name_t) const; + +    #ifdef JSON_LIBRARY +	   void push_back(JSONNode * node); +    #else +	   void push_back(const JSONNode & node); +    #endif +    void reserve(json_index_t size); +    JSONNode JSON_PTR_LIB pop_back(json_index_t pos); +    JSONNode JSON_PTR_LIB pop_back(const json_string & name_t); +    #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +	   JSONNode JSON_PTR_LIB pop_back_nocase(const json_string & name_t); +    #endif +     +    DECLARE_FOR_ALL_TYPES(JSONNode & operator =) +    JSONNode & operator = (const JSONNode &); + +    DECLARE_FOR_ALL_TYPES_CONST(bool operator ==) +    DECLARE_FOR_ALL_TYPES_CONST(bool operator !=) + + +    void nullify(void); +    void swap(JSONNode & other); +    void merge(JSONNode & other); +    void merge(unsigned int num, ...); +    JSONNode duplicate(void) const; +    void cast(char newtype); +     +     +    //iterator +    #ifdef JSON_ITERATORS +	   #ifndef JSON_LIBRARY +		  #define json_iterator_ptr(iter) iter.it +		  #define ptr_to_json_iterator(iter) json_iterator(iter) +		  struct iterator { +			 inline iterator& operator ++(void){ ++it; return *this; } +			 inline iterator& operator --(void){ --it; return *this; } +			 inline iterator& operator +=(long i){ it += i; return *this; } +			 inline iterator& operator -=(long i){ it -= i; return *this; } +			 inline iterator operator ++(int){ +				iterator result(*this); +				++it; +				return result; +			 } +			 inline iterator operator --(int){ +				iterator result(*this); +				--it; +				return result; +			 } +			 inline iterator operator +(long i) const { +				iterator result(*this); +				result.it += i; +				return result; +			 } +			 inline iterator operator -(long i) const { +				iterator result(*this); +				result.it -= i; +				return result; +			 } +			 inline JSONNode& operator [](size_t pos) const { return *it[pos]; }; +			 inline JSONNode& operator *(void) const { return *(*it); } +			 inline bool operator == (const iterator & other) const { return it == other.it; } +			 inline bool operator != (const iterator & other) const { return it != other.it; } +			 inline bool operator > (const iterator & other) const { return it > other.it; } +			 inline bool operator >= (const iterator & other) const { return it >= other.it; } +			 inline bool operator < (const iterator & other) const { return it < other.it; } +			 inline bool operator <= (const iterator & other) const { return it <= other.it; } +			 inline iterator & operator = (const iterator & orig){ it = orig.it; return *this; } +			 iterator (const iterator & orig) : it(orig.it) {} +		  private: +			 JSONNode ** it; +			 iterator(JSONNode ** starter) : it(starter) {} +			 friend class JSONNode; +		  }; +		  typedef iterator json_iterator; +     +		  struct const_iterator { +			 inline const_iterator& operator ++(void){ ++it; return *this; } +			 inline const_iterator& operator --(void){ --it; return *this; } +			 inline const_iterator& operator +=(long i){ it += i; return *this; } +			 inline const_iterator& operator -=(long i){ it -= i; return *this; } +			 inline const_iterator operator ++(int){ +				const_iterator result(*this); +				++it; +				return result; +			 } +			 inline const_iterator operator --(int){ +				const_iterator result(*this); +				--it; +				return result; +			 } +			 inline const_iterator operator +(long i) const { +				const_iterator result(*this); +				result.it += i; +				return result; +			 } +			 inline const_iterator operator -(long i) const { +				const_iterator result(*this); +				result.it -= i; +				return result; +			 } +			 inline const JSONNode& operator [](size_t pos) const { return const_cast<const JSONNode&>(*it[pos]); }; +			 inline const JSONNode& operator *(void) const { return const_cast<const JSONNode&>(*(*it)); } +			 inline bool operator == (const const_iterator & other) const { return it == other.it; } +			 inline bool operator != (const const_iterator & other) const { return it != other.it; } +			 inline bool operator > (const const_iterator & other) const { return it > other.it; } +			 inline bool operator >= (const const_iterator & other) const { return it >= other.it; } +			 inline bool operator < (const const_iterator & other) const { return it < other.it; } +			 inline bool operator <= (const const_iterator & other) const { return it <= other.it; } +			 inline const_iterator & operator =(const const_iterator & orig){ it = orig.it; return *this; } +			 const_iterator (const const_iterator & orig) : it(orig.it) {} +		  private: +			 JSONNode ** it; +			 const_iterator(JSONNode ** starter) : it(starter) {} +			 friend class JSONNode; +		  }; +		  const_iterator begin(void) const; +		  const_iterator end(void) const; +		   +		  struct reverse_iterator { +			 inline reverse_iterator& operator ++(void){ --it; return *this; } +			 inline reverse_iterator& operator --(void){ ++it; return *this; } +			 inline reverse_iterator& operator +=(long i){ it -= i; return *this; } +			 inline reverse_iterator& operator -=(long i){ it += i; return *this; } +			 inline reverse_iterator operator ++(int){ +				reverse_iterator result(*this); +				--it; +				return result; +			 } +			 inline reverse_iterator operator --(int){ +				reverse_iterator result(*this); +				++it; +				return result; +			 } +			 inline reverse_iterator operator +(long i) const { +				reverse_iterator result(*this); +				result.it -= i; +				return result; +			 } +			 inline reverse_iterator operator -(long i) const { +				reverse_iterator result(*this); +				result.it += i; +				return result; +			 } +			 inline JSONNode& operator [](size_t pos) const { return *it[pos]; }; +			 inline JSONNode& operator *(void) const { return *(*it); } +			 inline bool operator == (const reverse_iterator & other) const { return it == other.it; } +			 inline bool operator != (const reverse_iterator & other) const { return it != other.it; } +			 inline bool operator < (const reverse_iterator & other) const { return it > other.it; } +			 inline bool operator <= (const reverse_iterator & other) const { return it >= other.it; } +			 inline bool operator > (const reverse_iterator & other) const { return it < other.it; } +			 inline bool operator >= (const reverse_iterator & other) const { return it <= other.it; } +			 inline reverse_iterator & operator = (const reverse_iterator & orig){ it = orig.it; return *this; } +			 reverse_iterator (const reverse_iterator & orig) : it(orig.it) {} +		  private: +			 JSONNode ** it; +			 reverse_iterator(JSONNode ** starter) : it(starter) {} +			 friend class JSONNode; +		  }; +		  reverse_iterator rbegin(void); +		  reverse_iterator rend(void); +		   +		  struct reverse_const_iterator { +			 inline reverse_const_iterator& operator ++(void){ --it; return *this; } +			 inline reverse_const_iterator& operator --(void){ ++it; return *this; } +			 inline reverse_const_iterator& operator +=(long i){ it -= i; return *this; } +			 inline reverse_const_iterator& operator -=(long i){ it += i; return *this; } +			 inline reverse_const_iterator operator ++(int){ +				reverse_const_iterator result(*this); +				--it; +				return result; +			 } +			 inline reverse_const_iterator operator --(int){ +				reverse_const_iterator result(*this); +				++it; +				return result; +			 } +			 inline reverse_const_iterator operator +(long i) const { +				reverse_const_iterator result(*this); +				result.it -= i; +				return result; +			 } +			 inline reverse_const_iterator operator -(long i) const { +				reverse_const_iterator result(*this); +				result.it += i; +				return result; +			 } +			 inline const JSONNode& operator [](size_t pos) const { return const_cast<const JSONNode&>(*it[pos]); }; +			 inline const JSONNode& operator *(void) const { return const_cast<const JSONNode&>(*(*it)); } +			 inline bool operator == (const reverse_const_iterator & other) const { return it == other.it; } +			 inline bool operator != (const reverse_const_iterator & other) const { return it != other.it; } +			 inline bool operator < (const reverse_const_iterator & other) const { return it > other.it; } +			 inline bool operator <= (const reverse_const_iterator & other) const { return it >= other.it; } +			 inline bool operator > (const reverse_const_iterator & other) const { return it < other.it; } +			 inline bool operator >= (const reverse_const_iterator & other) const { return it <= other.it; } +			 inline reverse_const_iterator & operator = (const reverse_const_iterator & orig){ it = orig.it; return *this; } +			 reverse_const_iterator (const reverse_const_iterator & orig) : it(orig.it) {} +		  private: +			 JSONNode ** it; +			 reverse_const_iterator(JSONNode ** starter) : it(starter) {} +			 friend class JSONNode; +		  }; +		  reverse_const_iterator rbegin(void) const; +		  reverse_const_iterator rend(void) const; +		   +		  const_iterator find(const json_string & name_t) const; +		  #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +			 const_iterator find_nocase(const json_string & name_t) const; +		  #endif +     +		  reverse_iterator erase(reverse_iterator pos); +		  reverse_iterator erase(reverse_iterator start, const reverse_iterator & end); +	    +		  iterator insert(iterator pos, const JSONNode & x); +		  reverse_iterator insert(reverse_iterator pos, const JSONNode & x); +		  iterator insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end); +		  reverse_iterator insert(reverse_iterator pos, const iterator & _start, const iterator & _end); +		  reverse_iterator insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end); +     +		  json_iterator insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end); +		  reverse_iterator insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end); +		  json_iterator insert(json_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end); +		  reverse_iterator insert(reverse_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end); +	   #else +		  typedef JSONNode** json_iterator; +		  #define json_iterator_ptr(iter) iter +		  #define ptr_to_json_iterator(iter) iter +		  json_iterator insert(json_iterator pos, JSONNode * x); +	   #endif +     +	   json_iterator begin(void); +	   json_iterator end(void); +	    +	   json_iterator find(const json_string & name_t); +	   #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +		  json_iterator find_nocase(const json_string & name_t); +	   #endif +	   json_iterator erase(json_iterator pos); +	   json_iterator erase(json_iterator start, const json_iterator & end); +	   json_iterator insert(json_iterator pos, const json_iterator & _start, const json_iterator & _end); +    #endif +     +     +    #ifdef JSON_MUTEX_CALLBACKS +	   static void register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock); +	   #ifdef JSON_MUTEX_MANAGE +		  static void register_mutex_destructor(json_mutex_callback_t destroy); +	   #endif +	   static void set_global_mutex(void * mutex); +	   void set_mutex(void * mutex); +	   void lock(int thread); +	   void unlock(int thread); +	   struct auto_lock { +		  public: +			 auto_lock(JSONNode & node, int thread) : mynode(&node), mythread(thread){ +				mynode -> lock(mythread); +			 } +			 auto_lock(JSONNode * node, int thread) : mynode(node), mythread(thread){ +				mynode -> lock(mythread); +			 } +			 ~auto_lock(void){ +				mynode -> unlock(mythread); +			 } +		  private: +			 auto_lock & operator = (const auto_lock &); +			 auto_lock(const auto_lock &); +			 JSONNode * mynode; +			 int mythread; +	   }; +	   static void * getThisLock(JSONNode * pthis); +    #endif +     +    #ifdef JSON_UNIT_TEST +	   static int getNodeAllocationCount(void); +	   static int getNodeDeallocationCount(void); +	   static int getInternalAllocationCount(void); +	   static int getInternalDeallocationCount(void); +	   static void incAllocCount(void); +	   static void decAllocCount(void); +	   static void incinternalAllocCount(void); +	   static void decinternalAllocCount(void); +    #endif +     +    #ifdef JSON_WRITER +	   json_string write(void); +	   json_string write_formatted(void); +    #endif +     +    #ifdef JSON_DEBUG +	   #ifndef JSON_LIBRARY +		  JSONNode dump(void) const; +	   #endif +    #endif +    static void deleteJSONNode(JSONNode * ptr); +    static JSONNode * newJSONNode_Shallow(const JSONNode & orig); +JSON_PRIVATE +    static JSONNode * newJSONNode(const JSONNode & orig     JSON_MUTEX_COPY_DECL2); +    static JSONNode * newJSONNode(internalJSONNode * internal_t); +    //used by JSONWorker +    JSONNode(const json_string & unparsed) : internal(internalJSONNode::newInternal(unparsed)){ //root, specialized because it can only be array or node +	   incAllocCount(); +    } +    JSONNode(internalJSONNode * internal_t) : internal(internal_t){ //do not increment anything, this is only used in one case and it's already taken care of  +	   incAllocCount(); +    } +    JSONNode(bool, JSONNode & orig); +     +    void decRef(void);  //decrements internal's counter, deletes it if needed +    #ifdef JSON_REF_COUNT +	   void makeUniqueInternal(void); //makes internal it's own +	   void merge(JSONNode * other); +    #endif +     +    #ifdef JSON_DEBUG +	   #ifndef JSON_LIBRARY +		  JSONNode dump(size_t & totalmemory); +	   #endif +    #endif +     +    #ifdef JSON_ITERATORS +	   #ifndef JSON_LIBRARY +		  json_iterator insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end); +		  reverse_iterator insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end); +		  reverse_iterator insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end); +	   #endif +	   json_iterator insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end); +    #endif +     +    mutable internalJSONNode * internal; +    friend class JSONWorker; +    friend class internalJSONNode; +}; + + + +/* +    Implementations are here to keep the class declaration cleaner.  They can't be placed in a different +    file because they are inlined. +*/ + +inline JSONNode::JSONNode(char mytype) : internal(internalJSONNode::newInternal(mytype)){ +    JSON_ASSERT((mytype == JSON_NULL) || +			 (mytype == JSON_STRING) || +			 (mytype == JSON_NUMBER) || +			 (mytype == JSON_BOOL) || +			 (mytype == JSON_ARRAY) || +			 (mytype == JSON_NODE), JSON_TEXT("Not a proper JSON type")); +    incAllocCount(); +} + +inline JSONNode::JSONNode(const JSONNode & orig): internal(orig.internal -> incRef()){ +    incAllocCount(); +} + +//this allows a temp node to simply transfer its contents, even with ref counting off +inline JSONNode::JSONNode(bool, JSONNode & orig): internal(orig.internal){ +    orig.internal = 0; +    incAllocCount(); +} + +inline JSONNode::~JSONNode(void){ +    if (internal) decRef(); +    decAllocCount(); +} + +inline json_index_t JSONNode::size(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> size(); +} + +inline bool JSONNode::empty(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> empty(); +} + +inline void JSONNode::clear(void){ +    JSON_CHECK_INTERNAL(); +    if (!empty()){ +	   makeUniqueInternal(); +	   internal -> Children.clear(); +    } +} + +inline unsigned char JSONNode::type(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> type(); +} + +inline json_string JSONNode::name(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> name(); +} + +inline void JSONNode::set_name(const json_string & newname){ +    JSON_CHECK_INTERNAL(); +    makeUniqueInternal(); +    internal -> setname(newname); +} + +#ifdef JSON_COMMENTS +    inline void JSONNode::set_comment(const json_string & newname){ +	   JSON_CHECK_INTERNAL(); +	   makeUniqueInternal(); +	   internal -> setcomment(newname); +    } + +    inline json_string JSONNode::get_comment(void) const {  +	   JSON_CHECK_INTERNAL(); +	   return internal -> getcomment(); +    } +#endif + +inline json_string JSONNode::as_string(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> as_string(); +} + +inline long JSONNode::as_int(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> as_int(); +} + +inline json_number JSONNode::as_float(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> as_float();     +} + +inline bool JSONNode::as_bool(void) const { +    JSON_CHECK_INTERNAL(); +    return internal -> as_bool(); +} + +#ifdef JSON_BINARY +    inline void JSONNode::set_binary(const unsigned char * bin, json_index_t bytes){ +	   JSON_CHECK_INTERNAL(); +	   *this = JSONBase64::json_encode64(bin, bytes); +    } + +    inline std::string JSONNode::as_binary(void) const { +	   JSON_ASSERT_SAFE(type() == JSON_STRING, JSON_TEXT("using as_binary for a non-string type"), return EMPTY_STRING2;); +	   JSON_CHECK_INTERNAL(); +	   return JSONBase64::json_decode64(as_string()); +    } +#endif + +inline JSONNode & JSONNode::operator[](const json_string & name_t){ +    JSON_CHECK_INTERNAL(); +    makeUniqueInternal(); +    return *(*(internal -> at(name_t))); +} + +inline const JSONNode & JSONNode::operator[](const json_string & name_t) const { +    JSON_CHECK_INTERNAL(); +    return *(*(internal -> at(name_t))); +} + +#ifdef JSON_LIBRARY +inline void JSONNode::push_back(JSONNode * child){ +#else +inline void JSONNode::push_back(const JSONNode & child){ +#endif +    JSON_CHECK_INTERNAL(); +    makeUniqueInternal(); +    internal -> push_back(child); +} +     +inline void JSONNode::reserve(json_index_t size){ +    makeUniqueInternal(); +    internal -> reserve(size); +} + +inline JSONNode & JSONNode::operator = (const JSONNode & orig){ +    JSON_CHECK_INTERNAL(); +    #ifdef JSON_REF_COUNT +	   if (internal == orig.internal) return *this;  //don't want it accidentally deleting itself +    #endif +    decRef();  //dereference my current one +    internal = orig.internal -> incRef();  //increase reference of original +    return *this; +} + +#ifndef JSON_LIBRARY +    inline JSONNode & JSONNode::operator = (const json_char * val){ +	   JSON_CHECK_INTERNAL(); +	   *this = json_string(val); +	   return *this; +    } +#endif +     +#define NODE_SET_TYPED(type)\ +    inline JSONNode & JSONNode::operator = (type val){\ +	   JSON_CHECK_INTERNAL();\ +	   makeUniqueInternal();\ +	   internal -> Set(val);\ +	   return *this;\ +    } + +IMPLEMENT_FOR_ALL_TYPES(NODE_SET_TYPED) + + +/* +    This section is the equality operators +*/ + +#define NODE_CHECK_EQUALITY(type)\ +    inline bool JSONNode::operator == (type val) const {\ +	   JSON_CHECK_INTERNAL();\ +	   return internal -> IsEqualToNum<type>(val);\ +    } + +IMPLEMENT_FOR_ALL_NUMBERS(NODE_CHECK_EQUALITY) + +inline bool JSONNode::operator == (const json_string & val) const { +    JSON_CHECK_INTERNAL(); +    return internal -> IsEqualTo(val); +} + +#ifndef JSON_LIBRARY +    inline bool JSONNode::operator == (const json_char * val) const { +	   JSON_CHECK_INTERNAL(); +	   return *this == json_string(val); +    } +#endif + +inline bool JSONNode::operator == (bool val) const { +    JSON_CHECK_INTERNAL(); +    return internal -> IsEqualTo(val); +} +inline bool JSONNode::operator == (const JSONNode & val) const { +    JSON_CHECK_INTERNAL(); +    return internal -> IsEqualTo(val.internal); +} + + +/* +    This section is the inequality operators +*/ + + +#define NODE_CHECK_INEQUALITY(type)\ +    inline bool JSONNode::operator != (type val) const {\ +	   JSON_CHECK_INTERNAL();\ +	   return !(*this == val);\ +    } + +IMPLEMENT_FOR_ALL_TYPES(NODE_CHECK_INEQUALITY) +NODE_CHECK_INEQUALITY(const JSONNode &) +#ifndef JSON_LIBRARY +    NODE_CHECK_INEQUALITY(const json_char * ) +#endif +     +inline void JSONNode::nullify(void){ +    JSON_CHECK_INTERNAL(); +    makeUniqueInternal(); +    internal -> Nullify(); +} + +inline void JSONNode::swap(JSONNode & other){ +    JSON_CHECK_INTERNAL(); +    internalJSONNode * temp = other.internal; +    other.internal = internal; +    internal = temp; +    JSON_CHECK_INTERNAL(); +} + +inline void JSONNode::decRef(void){ //decrements internal's counter, deletes it if needed +    JSON_CHECK_INTERNAL(); +    #ifdef JSON_REF_COUNT +	   internal -> decRef(); +	   if (internal -> hasNoReferences()){ +		  internalJSONNode::deleteInternal(internal); +	   } +    #else +	   internalJSONNode::deleteInternal(internal); +    #endif +} + +#ifdef JSON_REF_COUNT +    inline void JSONNode::makeUniqueInternal(){ //makes internal it's own +	   JSON_CHECK_INTERNAL(); +	   internal = internal -> makeUnique();  //might return itself or a new one that's exactly the same +    } +#endif + +#ifdef JSON_ITERATORS +    inline JSONNode::json_iterator JSONNode::begin(void){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +	   makeUniqueInternal(); +	   return json_iterator(internal -> begin()); +    } + +    inline JSONNode::json_iterator JSONNode::end(void){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +	   makeUniqueInternal(); +	   return json_iterator(internal -> end()); +    } +     +    #ifndef JSON_LIBRARY +	   inline JSONNode::const_iterator JSONNode::begin(void) const { +		  JSON_CHECK_INTERNAL(); +		  JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +		  return JSONNode::const_iterator(internal -> begin()); +	   } + +	   inline JSONNode::const_iterator JSONNode::end(void) const { +		  JSON_CHECK_INTERNAL(); +		  JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +		  return JSONNode::const_iterator(internal -> end()); +	   } + +	   inline JSONNode::reverse_iterator JSONNode::rbegin(void){ +		  JSON_CHECK_INTERNAL(); +		  JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +		  makeUniqueInternal(); +		  return JSONNode::reverse_iterator(internal -> end() - 1); +	   } + +	   inline JSONNode::reverse_iterator JSONNode::rend(void){ +		  JSON_CHECK_INTERNAL(); +		  JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +		  makeUniqueInternal(); +		  return JSONNode::reverse_iterator(internal -> begin() - 1); +	   } + +	   inline JSONNode::reverse_const_iterator JSONNode::rbegin(void) const { +		  JSON_CHECK_INTERNAL(); +		  JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +		  return JSONNode::reverse_const_iterator(internal -> end() - 1); +	   } + +	   inline JSONNode::reverse_const_iterator JSONNode::rend(void) const { +		  JSON_CHECK_INTERNAL(); +		  JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); +		  return JSONNode::reverse_const_iterator(internal -> begin() - 1); +	   } +     +	   inline JSONNode::iterator JSONNode::insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end){ +		  return insertFFF(pos, _start.it, _end.it); +	   } +     +	   inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end){ +		  return insertRFF(pos, _start.it, _end.it); +	   } +	    +	   inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const iterator & _start, const iterator & _end){ +		  return insertRFF(pos, _start.it, _end.it); +	   } +	    +	   inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end){ +		  return insertRRR(pos, _start.it, _end.it); +	   } +	    +	   inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end){ +		  return insertRRR(pos, _start.it, _end.it); +	   } +     +	   inline JSONNode::iterator JSONNode::insert(json_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end){ +		  return insertFRR(pos, _start.it, _end.it);  +	   } +	    +	   inline JSONNode::iterator JSONNode::insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end){ +		  return insertFRR(pos, _start.it, _end.it);  +	   } +    #endif +     +    inline JSONNode::json_iterator JSONNode::insert(json_iterator pos, const json_iterator & _start, const json_iterator & _end){ +	   return insertFFF(pos, json_iterator_ptr(_start), json_iterator_ptr(_end)); +    }   +#endif + +#ifdef JSON_WRITER +    inline json_string JSONNode::write(void){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return JSON_TEXT("");); +	   return internal -> Write(0xFFFFFFFF, true); +    } + +    inline json_string JSONNode::write_formatted(void){ +	   JSON_CHECK_INTERNAL(); +	   JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return JSON_TEXT("");); +	   return internal -> Write(0, true); +    } + +#endif + +#ifndef JSON_PREPARSE +    inline void JSONNode::preparse(void){ +	   JSON_CHECK_INTERNAL(); +	   internal -> preparse(); +    } +#endif + +#ifdef JSON_VALIDATE +    inline bool JSONNode::validate(void){ +	   JSON_CHECK_INTERNAL(); +	   if (type() == JSON_NULL) return false; +	   JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Validating non root node"), return false;); +	   #ifndef JSON_PREPARSE +		  internal -> Fetch();  //will nullify it if it's bad +	   #endif +	   if (type() == JSON_NULL) return false; +	   return internal -> validate(); +    } +#endif + +#ifdef JSON_DEBUG +    #ifndef JSON_LIBRARY +	   inline JSONNode JSONNode::dump(void) const { +		  JSON_CHECK_INTERNAL(); +		  JSONNode dumpage(JSON_NODE); +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); +		  size_t total = 0; +		  JSONNode node = internal -> Dump(total); +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("total bytes used"), total))); +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), sizeof(JSONNode)))); +		  dumpage.push_back(JSON_NEW(node)); +		  return dumpage; +	   } + +	   inline JSONNode JSONNode::dump(size_t & totalmemory){ +		  JSON_CHECK_INTERNAL(); +		  JSONNode dumpage(JSON_NODE); +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), sizeof(JSONNode)))); +		  dumpage.push_back(JSON_NEW(internal -> Dump(totalmemory))); +		  return dumpage; +	   } +    #endif +#endif + + +inline void JSONNode::deleteJSONNode(JSONNode * ptr){ +    #ifdef JSON_MEMORY_CALLBACKS +	   ptr -> ~JSONNode(); +	   libjson_free<JSONNode>(ptr); +    #else +	   delete ptr; +    #endif      +} + +inline JSONNode * _newJSONNode(const JSONNode & orig){ +    #ifdef JSON_MEMORY_CALLBACKS +	   return new(json_malloc<JSONNode>(1)) JSONNode(orig); +    #else +	   return new JSONNode(orig); +    #endif     +} + +inline JSONNode * JSONNode::newJSONNode(const JSONNode & orig    JSON_MUTEX_COPY_DECL){ +    #ifdef JSON_MUTEX_CALLBACKS +	   if (parentMutex){ +		  JSONNode * temp = _newJSONNode(orig); +		  temp -> set_mutex(parentMutex); +		  return temp; +	   } +    #endif +    return _newJSONNode(orig); +} + +inline JSONNode * JSONNode::newJSONNode(internalJSONNode * internal_t){ +    #ifdef JSON_MEMORY_CALLBACKS +	   return new(json_malloc<JSONNode>(1)) JSONNode(internal_t); +    #else +	   return new JSONNode(internal_t); +    #endif  +} +     +inline JSONNode * JSONNode::newJSONNode_Shallow(const JSONNode & orig){ +    #ifdef JSON_MEMORY_CALLBACKS +	   return new(json_malloc<JSONNode>(1)) JSONNode(true, const_cast<JSONNode &>(orig)); +    #else +	   return new JSONNode(true, const_cast<JSONNode &>(orig)); +    #endif    +} +#endif diff --git a/plugins/JSON/Source/JSONNode_Mutex.cpp b/plugins/JSON/Source/JSONNode_Mutex.cpp new file mode 100644 index 0000000000..0f0dbe5d7b --- /dev/null +++ b/plugins/JSON/Source/JSONNode_Mutex.cpp @@ -0,0 +1,191 @@ +#include "JSONNode.h" +#include "../JSONOptions.h" + +#ifdef JSON_MUTEX_CALLBACKS + +json_mutex_callback_t json_lock_callback = 0; +json_mutex_callback_t json_unlock_callback = 0; +void * global_mutex = 0; +void * manager_mutex = 0; + +struct AutoLock { +    AutoLock(void){ +	   json_lock_callback(manager_mutex); +    } +    ~AutoLock(void){ +	   json_unlock_callback(manager_mutex); +    } +}; + +#include <map> +#ifdef JSON_MUTEX_MANAGE +    json_mutex_callback_t json_destroy = 0;  +    std::map<void *, unsigned int> mutex_manager; + +    //make sure that the global mutex is taken care of too +    struct auto_global { +	   auto_global(void){} +	   ~auto_global(void){ +		  if (global_mutex){ +			 JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("No json_destroy in mutex managed mode"), return;); +			 json_destroy(global_mutex);  +		  } +	   } +    }; +    auto_global cleanupGlobal; +#endif + +void JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock){ +    json_lock_callback = lock; +    json_unlock_callback = unlock; +    manager_mutex = manager_lock; +} + +void JSONNode::set_global_mutex(void * mutex){ +    global_mutex = mutex; +} + +void JSONNode::set_mutex(void * mutex){ +    makeUniqueInternal(); +    internal -> _set_mutex(mutex); +} + +std::map<int, std::map<void *, unsigned int> > threadlocks; + +void * JSONNode::getThisLock(JSONNode * pthis){ +    if (pthis -> internal -> mylock){ +	   return pthis -> internal -> mylock; +    } +    JSON_ASSERT_SAFE(global_mutex, JSON_TEXT("No global_mutex"), return 0;); +    return global_mutex; +} + +void JSONNode::lock(int thread){ +    JSON_ASSERT_SAFE(json_lock_callback, JSON_TEXT("No locking callback"), return;); +     +    AutoLock lockControl; +     +    //first, figure out what needs to be locked +    void * thislock = getThisLock(this); +    #ifdef JSON_SAFE +	   if (!thislock) return; +    #endif +     +    //make sure that the same thread isn't locking it more than once (possible due to complex ref counting) +    std::map<int, std::map<void *, unsigned int> >::iterator it = threadlocks.find(thread); +    if (it == threadlocks.end()){ +	   std::map<void *, unsigned int> newthread; +	   newthread[thislock] = 1; +	   threadlocks.insert(std::pair<int, std::map<void *, unsigned int> >(thread, newthread)); +    } else {  //this thread already has some things locked, check if the current mutex is +	   std::map<void *, unsigned int> & newthread = it -> second; +	   std::map<void *, unsigned int>::iterator locker = newthread.find(thislock); +	   if (locker == newthread.end()){  //current mutex is not locked, set it to locked +		  newthread.insert(std::pair<void *, unsigned int>(thislock, 1)); +	   } else {  //it's already locked, don't relock it +		  ++(locker -> second); +		  return;  //don't try to relock, it will deadlock the program +	   } +    } +     +    //if I need to, lock it +    json_lock_callback(thislock); +} + +void JSONNode::unlock(int thread){ +    JSON_ASSERT_SAFE(json_unlock_callback, JSON_TEXT("No unlocking callback"), return;); +     +    AutoLock lockControl; +  +    //first, figure out what needs to be locked +    void * thislock = getThisLock(this); +    #ifdef JSON_SAFE +	   if (!thislock) return; +    #endif +     +    //get it out of the map +    std::map<int, std::map<void *, unsigned int> >::iterator it = threadlocks.find(thread); +    JSON_ASSERT_SAFE(it != threadlocks.end(), JSON_TEXT("thread unlocking something it didn't lock"), return;); +     +    //get the mutex out of the thread +    std::map<void *, unsigned int> & newthread = it -> second; +    std::map<void *, unsigned int>::iterator locker = newthread.find(thislock); +    JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;); +     +    //unlock it +    if (--(locker -> second)) return;  //other nodes is this same thread still have a lock on it +     +    //if I need to, unlock it +    newthread.erase(locker); +    json_unlock_callback(thislock); +} + +#ifdef JSON_MUTEX_MANAGE +    void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy){ +	   json_destroy = destroy; +    } +#endif + + +void internalJSONNode::_set_mutex(void * mutex, bool unset){ +    if (unset) _unset_mutex();  //for reference counting +    mylock = mutex; +    if (mutex){ +	   #ifdef JSON_MUTEX_MANAGE +		  std::map<void *, unsigned int>::iterator it = mutex_manager.find(mutex); +		  if (it == mutex_manager.end()){ +			 mutex_manager.insert(std::pair<void *, unsigned int>(mutex, 1)); +		  } else { +			 ++it -> second; +		  } +	   #endif +	   json_foreach(Children, myrunner){ +		  (*myrunner) -> set_mutex(mutex); +	   } +    } +} + +void internalJSONNode::_unset_mutex(void){ +    #ifdef JSON_MUTEX_MANAGE +	   if (mylock){ +		  std::map<void *, unsigned int>::iterator it = mutex_manager.find(mylock); +		  JSON_ASSERT_SAFE(it != mutex_manager.end(), JSON_TEXT("Mutex not managed"), return;); +		  --it -> second; +		  if (it -> second == 0){ +			 JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("You didn't register a destructor for mutexes"), return;); +			 mutex_manager.erase(it); +		  } +	   } +    #endif +} + +#ifdef JSON_DEBUG +    #ifndef JSON_LIBRARY +	   JSONNode internalJSONNode::DumpMutex(void) const { +		  JSONNode mut(JSON_NODE); +		  mut.set_name(JSON_TEXT("mylock")); +		  #ifdef JSON_MUTEX_MANAGE +			 if (mylock){ +				mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock))); +				std::map<void *, unsigned int>::iterator it = mutex_manager.find(mylock); +				if (it == mutex_manager.end()){ +				    mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), JSON_TEXT("error")))); +				} else { +				    mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), it -> second))); +				} +			 } else { +				mut = (long)mylock; +			 } +		  #else +			 mut = (long)mylock; +		  #endif +		  return mut; +	   } +    #endif +#endif + +#else +    #ifdef JSON_MUTEX_MANAGE +	   #error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS +    #endif +#endif diff --git a/plugins/JSON/Source/JSONWorker.cpp b/plugins/JSON/Source/JSONWorker.cpp new file mode 100644 index 0000000000..093d9a75b2 --- /dev/null +++ b/plugins/JSON/Source/JSONWorker.cpp @@ -0,0 +1,676 @@ +#include "JSONWorker.h" + +#ifdef JSON_VALIDATE +JSONNode JSONWorker::validate(const json_string & json){ +    JSONNode res = parse(json); +    if (!res.validate()){ +	   throw std::invalid_argument(EMPTY_STRING2);		   +    } +    return JSONNode(true, res);  //forces it to simply return the original interal, even with ref counting off +} +#endif + +JSONNode JSONWorker::parse(const json_string & json){ +    json_auto<json_char> s; +    #if defined JSON_DEBUG || defined JSON_SAFE +	   json_char lastchar; +	   s.set(RemoveWhiteSpace(json, lastchar)); +    #else +	   s.set(RemoveWhiteSpace(json)); +    #endif +     +    #ifdef JSON_COMMENTS +	   json_char firstchar = s.ptr[0]; +	   json_string _comment; +	   json_char * runner = s.ptr; +	   if (firstchar == '\5'){  //multiple comments will be consolidated into one +		  newcomment: +		  while(*(++runner) != '\5'){ +			 JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed")); +			 _comment += *runner; +		  }  +		  firstchar = *(++runner); //step past the trailing tag +		  if (firstchar == '\5'){ +			 _comment += '\n'; +			 goto newcomment; +		  } +	   } +    #else +	   const json_char firstchar = s.ptr[0]; +    #endif +     +    switch (firstchar){ +        case '{': +        case '[': +		  #if defined JSON_DEBUG || defined JSON_SAFE +			 if (firstchar == '['){ +				if (lastchar != ']'){ +				    JSON_FAIL(JSON_TEXT("Missing final ]")); +				    break; +				} +			 } else { +				if (lastchar != '}'){ +				    JSON_FAIL(JSON_TEXT("Missing final }")); +				    break; +				} +			 } +		  #endif +		  #ifdef JSON_COMMENTS +			 JSONNode foo(runner); +			 foo.set_comment(_comment); +			 return JSONNode(true, foo);  //forces it to simply return the original interal, even with ref counting off +		  #else +			 return JSONNode(s.ptr); +		  #endif +    } + +    JSON_FAIL(JSON_TEXT("Not JSON!")); +    throw std::invalid_argument(EMPTY_STRING2); +} + +#define QUOTECASE()\ +    case JSON_TEXT('\"'):\ +	   while (*(++p) != JSON_TEXT('\"')){\ +		  JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), return json_string::npos;);\ +	   }\ +	   break; + +#ifdef JSON_DEBUG +    #define NULLCASE(error)\ +	   case JSON_TEXT('\0'):\ +		  JSON_FAIL_SAFE(error, return json_string::npos;);\ +		  break; +#else +    #define NULLCASE(error) +#endif + +#define BRACKET(left, right)\ +    case left: {\ +	   size_t brac = 1;\ +	   while (brac){\ +		  switch (*(++p)){\ +			 case right:\ +				--brac;\ +				break;\ +			 case left:\ +				++brac;\ +				break;\ +			 QUOTECASE()\ +			 NULLCASE(JSON_TEXT("Null terminator inside of a bracket"))\ +		  }\ +	   }\ +	   break;}\ +    case right:\ +	   return json_string::npos; + +size_t JSONWorker::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos){ +    const json_char * start = value_t.c_str(); +    const json_char * p = start + pos; //start at the correct offset +    do { +	   if (*p == ch) return p - start; +	   switch (*p){ +			 BRACKET(JSON_TEXT('['), JSON_TEXT(']')) +			 BRACKET(JSON_TEXT('{'), JSON_TEXT('}')) +			 QUOTECASE() +	   } +    } while(*(++p)); +    return json_string::npos; +} + +#ifdef JSON_COMMENTS +    #define COMMENT_DELIMITER() *runner++ = '\5' +    #define AND_RUNNER ,runner +    inline void SingleLineComment(const json_char * & p, json_char * & runner){ +	   COMMENT_DELIMITER(); +	   while((*(++p)) && (*p != JSON_TEXT('\n'))){ +		  *runner++ = *p; +	   } +	   COMMENT_DELIMITER(); +    } +#else +    #define COMMENT_DELIMITER() (void)0 +    #define AND_RUNNER +#endif + +inline void SingleLineComment(const json_char * & p){ +    while((*(++p)) && (*p != JSON_TEXT('\n'))); +} + + +#if defined JSON_DEBUG || defined JSON_SAFE +    json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t, json_char & last){ +#else +    json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t){ +#endif +	   json_char * result; +	   json_char * runner = result = json_malloc<json_char>(value_t.length() + 1);  //dealing with raw memory is faster than adding to a json_string +	   JSON_ASSERT(result, JSON_TEXT("Out of memory")); +	   const json_char * p = value_t.c_str(); +	   while(*p){ +		  switch(*p){ +			 case JSON_TEXT(' '):   //defined as white space +			 case JSON_TEXT('\t'):  //defined as white space +			 case JSON_TEXT('\n'):  //defined as white space +			 case JSON_TEXT('\r'):  //defined as white space +				break; +			 case JSON_TEXT('/'):  //a C comment +				if (*(++p) == JSON_TEXT('*')){  //a multiline comment +				    COMMENT_DELIMITER(); +				    while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))){ +					   JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), COMMENT_DELIMITER(); goto endofloop;); +					   *runner++ = *p; +				    } +				    ++p; +				    COMMENT_DELIMITER(); +				    break; +				} +				//Should be a single line C comment, so let it fall through to use the bash comment stripper +				JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;); +			 case JSON_TEXT('#'):  //a bash comment +				SingleLineComment(p AND_RUNNER); +				break; +			 case JSON_TEXT('\"'):  //a quote +				*runner++ = JSON_TEXT('\"'); +				while(*(++p) != JSON_TEXT('\"')){  //find the end of the quotation, as white space is preserved within it +				    JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), goto endofloop;); +				    switch(*p){ +					   case JSON_TEXT('\\'): +						  *runner++ = JSON_TEXT('\\'); +						  *runner++ = (*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p;  //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on +						  break; +					   default: +						  *runner++ = *p; +						  break; +				    } +				} +				//no break, let it fall through so that the trailing quote gets added +			 default: +				JSON_ASSERT_SAFE((unsigned json_char)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); +				JSON_ASSERT_SAFE((unsigned json_char)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;); +				*runner++ = *p; +				break; +		  } +		  ++p; +	   } +	   #ifdef JSON_SAFE +		  endofloop: +	   #endif +	   #if defined JSON_DEBUG || defined JSON_SAFE +		  last = *(runner - 1); +	   #endif +	   *runner = JSON_TEXT('\0'); +	   return result; +    } +	    +json_string JSONWorker::RemoveWhiteSpaceAndComments(const json_string & value_t){ +    json_string result; +    result.reserve(value_t.length()); +    const json_char * p = value_t.c_str(); +    while(*p){ +	   switch(*p){ +		  case JSON_TEXT(' '):   //defined as white space +		  case JSON_TEXT('\t'):  //defined as white space +		  case JSON_TEXT('\n'):  //defined as white space +		  case JSON_TEXT('\r'):  //defined as white space +			 break; +		  case JSON_TEXT('/'):  //a C comment +			 if (*(++p) == JSON_TEXT('*')){  //a multiline comment +				while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))){ +				    JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), goto endofloop;); +				} +				++p; +				break; +			 } +			 //Should be a single line C comment, so let it fall through to use the bash comment stripper +			 JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;); +		  case JSON_TEXT('#'):  //a bash comment +			 SingleLineComment(p); +			 break; +		  case JSON_TEXT('\"'):  //a quote +			 result += JSON_TEXT('\"'); +			 while(*(++p) != JSON_TEXT('\"')){  //find the end of the quotation, as white space is preserved within it +				JSON_ASSERT(*p, JSON_TEXT("Null terminator inside of a quotation")); +				switch(*p){ +				    case JSON_TEXT('\\'): +					   result += JSON_TEXT('\\'); +					   result += (*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p;  //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on +					   break; +				    default: +					   result += *p; +					   break; +				} +			 } +			 //no break, let it fall through so that the trailing quote gets added +		  default: +			 JSON_ASSERT_SAFE((unsigned json_char)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); +			 JSON_ASSERT_SAFE((unsigned json_char)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;); +			 result += *p; +			 break; +	   } +	   ++p; +    } +    #ifdef JSON_SAFE +	   endofloop: +    #endif +    return result; +} +	    +/* + These three functions analyze json_string literals and convert them into std::strings + This includes dealing with special characters and utf characters + */ +#ifdef JSON_UNICODE +    inline unsigned json_char SurrogatePair(const unsigned json_char hi, const unsigned json_char lo){ +	   JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); +	   JSON_ASSERT(sizeof(unsigned json_char) == 4, JSON_TEXT("size of json_char is not 32-bit")); +	   return (((hi << 10) & 0x1FFC00) + 0x10000) | lo & 0x3FF; +    } + +    json_string JSONWorker::UTF(const json_char * & pos){ +	   json_string result; +	   unsigned json_char first = UTF8(pos); +	   if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')){ +		  pos += 2; +		  unsigned json_char second = UTF8(pos); +		  //surrogate pair, not two characters +		  if ((first > 0xD800) && (first < 0xDBFF) && (second > 0xDC00) && (second < 0xDFFF)){ +			 result += SurrogatePair(first, second); +		  } else { +			 result += first; +			 result += second; +		  } +	   } else { +		  result += first; +	   } +	   JSON_ASSERT(!result.empty(), JSON_TEXT("missing case, somehow UTF returned empty")); +	   return result; +    } +#endif + +unsigned json_char JSONWorker::UTF8(const json_char * & pos){ +    #ifdef JSON_UNICODE +	   ++pos; +	   unsigned json_char temp = Hex(pos) << 8; +	   ++pos; +	   return temp | Hex(pos); +    #else +	   JSON_ASSERT(*(pos + 1) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hihi)")); +	   JSON_ASSERT(*(pos + 2) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hilo)")); +	   pos += 3; +	   return Hex(pos); +    #endif +} + +static char szU8Buffer[10]; + +json_char* JSONWorker::UTF8_2(const json_char * & pos){ +    #ifdef JSON_UNICODE +	   ++pos; +	   unsigned json_char temp = Hex(pos) << 8; +	   ++pos; +	   *szU8Buffer= temp | Hex(pos); +	   szU8Buffer[1]=0; +	   return szU8Buffer; +    #else +	   union { +	      unsigned short uChar; +		  unsigned char uByte[2]; +	   }; +	   pos++; +	   strncpy(szU8Buffer+5,pos,4); +	   szU8Buffer[9]=0; +	   uChar=strtoul(szU8Buffer+5,NULL,16); +	   if (uChar<0x80) { +		  szU8Buffer[0]=uChar; +		  szU8Buffer[1]=0; +	   } else if (uChar<0x7ff) { +		  szU8Buffer[0]=0xc0+(uByte[1]<<2)+(uByte[0]>>6); +		  szU8Buffer[1]=0x80+(uByte[0]&0x3f); +		  szU8Buffer[2]=0; +	   } else { +	      szU8Buffer[0]=0xe0+(uByte[1]>>4); +		  szU8Buffer[1]=0x80+((uByte[1]&0x0f)<<2)+(uByte[0]>>6); +		  szU8Buffer[2]=0x80+(uByte[0]&0x3f); +		  szU8Buffer[3]=0; +	   }
 + +	   pos += 3; +	   return szU8Buffer; +    #endif +} + +	    +json_char JSONWorker::Hex(const json_char * & pos){ +    /* +	takes the numeric value of the next two characters and convert them +	\u0058 becomes 0x58 +	 +	In case of \u, it's SpecialChar's responsibility to move past the first two chars +	as this method is also used for \x +	*/ +    //First character +    unsigned json_char hi = *pos++ - 48; +    if (hi > 48){  //A-F don't immediately follow 0-9, so have to pull them down a little +	   hi -= 39; +    } else if (hi > 9){  //neither do a-f +	   hi -= 7; +    } +    //second character +    unsigned json_char lo = *pos - 48; +    if (lo > 48){  //A-F don't immediately follow 0-9, so have to pull them down a little +	   lo -= 39; +    } else if (lo > 9){  //neither do a-f +	   lo -= 7; +    } +    //combine them +    return (json_char)((hi << 4) | lo); +} + +inline json_char FromOctal(const json_char * & str){ +    JSON_ASSERT(json_strlen(str) > 3, JSON_TEXT("Octal will go out of bounds")); +    const unsigned json_char top = ((unsigned json_char)(*(str++) - 48)); +    const unsigned json_char middle = (unsigned json_char)(*(str++) - 48); +    const unsigned json_char bottom = (unsigned json_char)(*str - 48); +    return (json_char)((top << 6) | (middle << 3) | bottom); +} + +void JSONWorker::SpecialChar(const json_char * & pos, json_string & res){ +    /* +	Since JSON uses forward slash escaping for special characters within strings, I have to +	convert these escaped characters into C characters +	*/ +    switch(*pos){ +	   case JSON_TEXT('\1'):  //quote character (altered by RemoveWhiteSpace) +		  res += JSON_TEXT('\"'); +		  break; +	   case JSON_TEXT('t'):	//tab character +		  res += JSON_TEXT('\t'); +		  break; +	   case JSON_TEXT('n'):	//newline character +		  res += JSON_TEXT('\n'); +		  break; +	   case JSON_TEXT('r'):	//return character +		  res += JSON_TEXT('\r'); +		  break; +	   case JSON_TEXT('\\'):	//backslash +		  res += JSON_TEXT('\\'); +		  break; +	   case JSON_TEXT('/'):	//forward slash +		  res += JSON_TEXT('/'); +		  break; +	   case JSON_TEXT('b'):	//backspace +		  res += JSON_TEXT('\b'); +		  break; +	   case JSON_TEXT('f'):	//formfeed +		  res += JSON_TEXT('\f'); +		  break; +	   case JSON_TEXT('v'):	//vertical tab +		  res += JSON_TEXT('\v'); +		  break; +	   case JSON_TEXT('\''):	//apostrophe +		  res += JSON_TEXT('\''); +		  break; +	   case JSON_TEXT('x'):   //hexidecimal ascii code +		  res += Hex(++pos); +		  break; +	   case JSON_TEXT('u'):	//utf character +		  #ifdef JSON_UNICODE +			 res += UTF(pos); +		  #else +			 //res += UTF8(pos); +		     res.append(UTF8_2(pos)); +		  #endif +		  break; +		   +		  //octal encoding +	   case JSON_TEXT('1'): +	   case JSON_TEXT('2'): +	   case JSON_TEXT('3'): +	   case JSON_TEXT('4'): +	   case JSON_TEXT('5'): +	   case JSON_TEXT('6'): +	   case JSON_TEXT('7'): +	   case JSON_TEXT('0'): +		  res += FromOctal(pos); +		  break; +		   +	   #ifdef JSON_DEBUG +		  default: +			 JSON_FAIL(JSON_TEXT("Unsupported escaped character")); +	   #endif +    } +} + +#ifdef JSON_LESS_MEMORY +	   inline void doflag(const internalJSONNode * flag, bool which, bool x){ +		  if (which){ +			 flag -> _name_encoded = x; +		  } else { +			 flag -> _string_encoded = x; +		  } +	   } +	    +	   json_string JSONWorker::FixString(const json_string & value_t, const internalJSONNode * flag, bool which){ +	   #define setflag(x) doflag(flag, which, x) +#else +	   json_string JSONWorker::FixString(const json_string & value_t, bool & flag){ +    #define setflag(x) flag = x +#endif +    /* +	Do things like unescaping +	*/ +    setflag(false); +    json_string res; +    res.reserve(value_t.length());	 //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating +    const json_char * p = value_t.c_str(); +    while(*p){ +	   switch (*p){ +		  case JSON_TEXT('\\'): +			 setflag(true); +			 SpecialChar(++p, res); +			 break; +		  default: +			 res += *p; +			 break; +	   } +	   ++p; +    } +    return res; +} + +#ifdef JSON_UNICODE +    json_string JSONWorker::toSurrogatePair(unsigned json_char C){ +	   JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); +	   JSON_ASSERT(sizeof(unsigned short) == 2, JSON_TEXT("size of unsigned short is not 16-bit")); +	   JSON_ASSERT(sizeof(unsigned json_char) == 4, JSON_TEXT("json_char is not 32-bit")); +	   //Compute the high surrogate +	   const unsigned int U = (C >> 16) & 31; +	   unsigned short HiSurrogate = 0xD800 | (((unsigned short)U - 1) << 6) | ((unsigned short)C) >> 10; +	    +	   //compute the low surrogate +	   unsigned short LoSurrogate = (unsigned short) (0xDC00 | ((unsigned short)C) & 1023); +	    +	   json_string res; +	   res += toUTF8(HiSurrogate); +	   res += toUTF8(LoSurrogate); +	   return res; +    } +#endif + +json_string JSONWorker::toUTF8(unsigned json_char p){ +    #ifdef JSON_UNICODE +	   if (p > 0xFFFF) return toSurrogatePair(p); +    #endif +    json_string res(JSON_TEXT("\\u")); +    #ifdef JSON_UNICODE +	   unsigned json_char hihi = ((p & 0xF000) >> 12) + 48; +	   if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those +	   unsigned json_char hilo = ((p & 0x0F00) >> 8) + 48; +	   if (hilo > 57) hilo += 7; //A-F don't immediately follow 0-9, so have to further adjust those +	   res += hihi; +	   res += hilo; +	   unsigned json_char hi = ((p & 0x00F0) >> 4) + 48; +    #else +	   res += JSON_TEXT("00"); +	   unsigned json_char hi = (p >> 4) + 48; +    #endif +    //convert the character to be escaped into two digits between 0 and 15 +    if (hi > 57) hi += 7; //A-F don't immediately follow 0-9, so have to further adjust those +    unsigned json_char lo = (p & 0x000F) + 48; +    if (lo > 57) lo += 7; //A-F don't immediately follow 0-9, so have to further adjust those +    res += hi; +    res += lo; +    return res; +} + +json_string JSONWorker::UnfixString(const json_string & value_t, bool flag){ +    if (!flag) return value_t; +    /* +	Re-escapes a json_string so that it can be written out into a JSON file +	*/ +    json_string res; +    res.reserve(value_t.length());  //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating +    const json_char * p = value_t.c_str(); +    while(*p){ +	   switch(*p){ +		  case JSON_TEXT('\"'):  //quote character +			 res += JSON_TEXT("\\\""); +			 break; +		  case JSON_TEXT('\t'):	//tab character +			 res += JSON_TEXT("\\t"); +			 break; +		  case JSON_TEXT('\n'):	//newline character +			 res += JSON_TEXT("\\n"); +			 break; +		  case JSON_TEXT('\r'):	//return character +			 res += JSON_TEXT("\\r"); +			 break; +		  case JSON_TEXT('\\'):	//backslash +			 res += JSON_TEXT("\\\\"); +			 break; +		  case JSON_TEXT('/'):	//forward slash +			 res += JSON_TEXT("\\/"); +			 break; +		  case JSON_TEXT('\b'):	//backspace +			 res += JSON_TEXT("\\b"); +			 break; +		  case JSON_TEXT('\f'):	//formfeed +			 res += JSON_TEXT("\\f"); +			 break; +		  case JSON_TEXT('\v'):	//vertical tab +			 res += JSON_TEXT("\\v"); +			 break; +		  case JSON_TEXT('\''):	//apostrophe +			 res += JSON_TEXT("\\\'"); +			 break; +		  default: +			 /*if (((unsigned json_char)(*p) < 32) || ((unsigned json_char)(*p) > 126)){ +				//res += toUTF8((unsigned json_char)(*p)); +			 } else*/ { +				res += *p; +			 } +			 break; +	   } +	   ++p; +    } +    return res; +} + + +//Create a childnode +#ifdef JSON_COMMENTS +    #define ARRAY_PARAM bool array  //Just to supress warnings +#else +    #define ARRAY_PARAM bool +#endif +inline void JSONWorker::NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, ARRAY_PARAM){ +    #ifdef JSON_COMMENTS +    const json_char * runner = (array) ? value.c_str() : name.c_str(); +	   json_string _comment; +	   if (*runner == '\5'){  //multiple comments will be consolidated into one +		  newcomment: +		  while(*(++runner) != '\5'){ +			 JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed")); +			 _comment += *runner; +		  }  +		  if (*(++runner) == '\5'){ //step past the trailing tag +			 _comment += '\n'; +			 goto newcomment; +		  } +	   } +	   internalJSONNode * myinternal; +	   if (array){ +		  myinternal = internalJSONNode::newInternal(name, runner); +	   } else { +		  myinternal = internalJSONNode::newInternal(++runner, value); +	   } +	   JSONNode * child = JSONNode::newJSONNode(myinternal); +	   child -> set_comment(_comment); +	   const_cast<internalJSONNode*>(parent) -> Children.push_back(child);   //attach it to the parent node +    #else +	   const_cast<internalJSONNode*>(parent) -> Children.push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(name.c_str() + 1, value)));	    //attach it to the parent node +    #endif +} + +//Create a subarray +void JSONWorker::DoArray(const internalJSONNode * parent, const json_string & value_t){ +    /* +	This takes an array and creates nodes out of them +	*/ +    JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoArray is empty")); +    JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('['), JSON_TEXT("DoArray is not an array"), parent -> Nullify(); return;); +    const size_t len = value_t.length(); +    if (len <= 2) return;  // just a [] (blank array) +     +    //Not sure what's in the array, so we have to use commas +    size_t starting = 1;  //ignore the [ +    size_t ending = FindNextRelevant(JSON_TEXT(','), value_t, 1); +    while (ending != json_string::npos){ +	   #ifdef JSON_SAFE +		  json_string newValue = value_t.substr(starting, ending - starting); +		  JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;); +		  NewNode(parent, JSON_TEXT(""), newValue, true); +	   #else +		  NewNode(parent, JSON_TEXT(""), value_t.substr(starting, ending - starting), true); +	   #endif +		  starting = ending + 1; +		  ending = FindNextRelevant(JSON_TEXT(','), value_t, starting); +	   } +	   //since the last one will not find the comma, we have to add it here, but ignore the final ] +	    +    #ifdef JSON_SAFE +	   json_string newValue = value_t.substr(starting, len - starting - 1); +	   JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;); +	   NewNode(parent, JSON_TEXT(""), newValue, true); +    #else +	   NewNode(parent, JSON_TEXT(""), value_t.substr(starting, len - starting - 1), true); +    #endif +} + + +//Create all child nodes +void JSONWorker::DoNode(const internalJSONNode * parent, const json_string & value_t){ +    /* +	This take a node and creates its members and such +	*/ +    JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoNode is empty")); +    JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('{'), JSON_TEXT("DoNode is not an node"), parent -> Nullify(); return;); +    const size_t len = value_t.length(); +    if (len <= 2) return;  // just a {} (blank node) +     +    size_t name_starting = 1;  //ignore the { +    size_t name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, 1);  //find where the name ends +    JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;); +    json_string name = value_t.substr(name_starting, name_ending - 2);	  //pull the name out +    size_t value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending);  //find the end of the value +    while (value_ending != json_string::npos){ +	   NewNode(parent, name, value_t.substr(name_ending + 1, value_ending - name_ending - 1), false); +	   name_starting = value_ending + 1; +	   name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, name_starting); +	   JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;); +	   name = value_t.substr(name_starting, name_ending - name_starting - 1); +	   value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending); +    } +    //since the last one will not find the comma, we have to add it here +    NewNode(parent, name, value_t.substr(name_ending + 1, len - name_ending - 2), false); +} diff --git a/plugins/JSON/Source/JSONWorker.h b/plugins/JSON/Source/JSONWorker.h new file mode 100644 index 0000000000..373660743c --- /dev/null +++ b/plugins/JSON/Source/JSONWorker.h @@ -0,0 +1,46 @@ +#ifndef JSON_WORKER_H +#define JSON_WORKER_H + +#include "JSONNode.h" + +class JSONWorker { +public: +    static JSONNode parse(const json_string & json); +    #ifdef JSON_VALIDATE +	   static JSONNode validate(const json_string & json); +    #endif +    #if defined JSON_DEBUG || defined JSON_SAFE +	   static json_char * RemoveWhiteSpace(const json_string & value_t, json_char & last); +    #else +	   static json_char * RemoveWhiteSpace(const json_string & value_t); +    #endif +    static json_string RemoveWhiteSpaceAndComments(const json_string & value_t); +     +    static void DoArray(const internalJSONNode * parent, const json_string & value_t); +    static void DoNode(const internalJSONNode * parent, const json_string & value_t); + +    #ifdef JSON_LESS_MEMORY +	   #define NAME_ENCODED this, true +	   #define STRING_ENCODED this, false +	   static json_string FixString(const json_string & value_t, const internalJSONNode * flag, bool which); +    #else +	   #define NAME_ENCODED _name_encoded +	   #define STRING_ENCODED _string_encoded +	   static json_string FixString(const json_string & value_t, bool & flag); +    #endif +    static json_string UnfixString(const json_string & value_t, bool flag); +JSON_PRIVATE +    static json_char Hex(const json_char * & pos); +    static unsigned json_char UTF8(const json_char * & pos); +    static json_char* UTF8_2(const json_char * & pos); +    static json_string toUTF8(unsigned json_char p); +    #ifdef JSON_UNICODE +	   static json_string UTF(const json_char * & pos); +	   static json_string toSurrogatePair(unsigned json_char pos); +    #endif +    static void SpecialChar(const json_char * & pos, json_string & res); +    static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos); +    static void NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, bool array); +}; + +#endif diff --git a/plugins/JSON/Source/JSONWriter.cpp b/plugins/JSON/Source/JSONWriter.cpp new file mode 100644 index 0000000000..9b53689002 --- /dev/null +++ b/plugins/JSON/Source/JSONWriter.cpp @@ -0,0 +1,148 @@ +#include "JSONNode.h" +#ifdef JSON_WRITER +#include "JSONWorker.h" + +const static json_string WRITER_EMPTY; +#ifndef JSON_NEWLINE +    const static json_string NEW_LINE(JSON_TEXT("\n")); +#else +    const static json_string NEW_LINE(JSON_TEXT(JSON_NEWLINE)); +#endif + +#ifdef JSON_INDENT +    const static json_string INDENT(JSON_TEXT(JSON_INDENT)); + +    inline json_string makeIndent(unsigned int amount){ +	   if (amount == 0xFFFFFFFF) return WRITER_EMPTY; +	   json_string result; +	   result.reserve(amount); +	   for(unsigned int i = 0; i < amount; ++i){ +		  result += INDENT; +	   } +	   return result; +    } +#else +    inline json_string makeIndent(unsigned int amount){ +	   if (amount == 0xFFFFFFFF) return WRITER_EMPTY; +	   return json_string(amount, JSON_TEXT('\t')); +    } +#endif + +json_string internalJSONNode::WriteName(bool formatted, bool arrayChild) const { +    if (arrayChild){ +	   return WRITER_EMPTY ; +    } else { +	   return JSON_TEXT("\"") + JSONWorker::UnfixString(_name, _name_encoded) + ((formatted) ? JSON_TEXT("\" : ") : JSON_TEXT("\":")); +    } +} + +json_string internalJSONNode::WriteChildren(unsigned int indent){ +    //Iterate through the children and write them +    if (Children.empty()) return WRITER_EMPTY; +     +    json_string indent_plus_one; +    json_string indent_this; +    json_string res; +    //handle whether or not it's formatted JSON +    if (indent != 0xFFFFFFFF){  //it's formatted, make the indentation strings +	   indent_this = NEW_LINE + makeIndent(indent); +	   indent_plus_one = NEW_LINE + makeIndent(++indent); +    } +    //else it's not formatted, leave the indentation strings empty +    const size_t size_minus_one = Children.size() - 1; +    size_t i = 0; +    json_foreach(Children, it){ +	   res += indent_plus_one + (*it) -> internal -> Write(indent, type() == JSON_ARRAY); +	   if (i < size_minus_one) res += JSON_TEXT(",");  //the last one does not get a comma, but all of the others do +	   ++i; +    } +    return res + indent_this; +} + +#ifdef JSON_COMMENTS +    #ifdef JSON_WRITE_BASH_COMMENTS +	   const static json_string SINGLELINE(JSON_TEXT("#")); +    #else +	   const static json_string SINGLELINE(JSON_TEXT("//")); +    #endif + +    json_string internalJSONNode::WriteComment(unsigned int indent) const { +	   if (indent == 0xFFFFFFFF) return WRITER_EMPTY; +	   if (_comment.empty()) return WRITER_EMPTY; +	   size_t pos = _comment.find(JSON_TEXT('\n')); +	   if (pos == json_string::npos){  //Single line comment +		  return NEW_LINE + makeIndent(indent) + SINGLELINE + _comment + NEW_LINE + makeIndent(indent); +	   } +	    +	   /* +	    Multiline comments +	    */ +	   #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) +		  json_string result(NEW_LINE + makeIndent(indent)); +	   #else +		  json_string result(NEW_LINE + makeIndent(indent) + JSON_TEXT("/*") + NEW_LINE + makeIndent(indent + 1)); +	   #endif +	   size_t old = 0; +	   while(pos != json_string::npos){ +		  if (pos && _comment[pos - 1] == JSON_TEXT('\r')) --pos; +		  #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) +			 result += SINGLELINE; +		  #endif +		  result += _comment.substr(old, pos - old) + NEW_LINE; +		  #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) +			 result += makeIndent(indent); +		  #else +			 result += makeIndent(indent + 1); +		  #endif +		  old = (_comment[pos] == JSON_TEXT('\r')) ? pos + 2 : pos + 1; +		  pos = _comment.find(JSON_TEXT('\n'), old); +	   } +	   #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) +		  result += SINGLELINE; +	   #endif +	   result += _comment.substr(old, pos - old) + NEW_LINE + makeIndent(indent); +	   #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) +		  return result; +	   #else +		  return result + JSON_TEXT("*/") + NEW_LINE + makeIndent(indent); +	   #endif +    } +#else +    json_string internalJSONNode::WriteComment(unsigned int) const { +	   return WRITER_EMPTY; +    } +#endif + +json_string internalJSONNode::Write(unsigned int indent, bool arrayChild){ +    const bool formatted = indent != 0xFFFFFFFF; +     +    #ifndef JSON_PREPARSE +	   if (!(formatted || fetched)){  //It's not formatted or fetched, just do a raw dump +		  return WriteComment(indent) + WriteName(false, arrayChild) + _string; +	   } +    #endif +     +    //It's either formatted or fetched +    switch (type()){ +	   case JSON_NODE:   //got members, write the members +		  Fetch(); +            return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("{") + WriteChildren(indent) + JSON_TEXT("}"); +	   case JSON_ARRAY:	   //write out the child nodes int he array +		  Fetch(); +            return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("[") + WriteChildren(indent) + JSON_TEXT("]"); +	   case JSON_NUMBER:   //write out a literal, without quotes +	   case JSON_NULL: +	   case JSON_BOOL: +            return WriteComment(indent) + WriteName(formatted, arrayChild) + _string; +    } +     +    JSON_ASSERT_SAFE(type() == JSON_STRING, JSON_TEXT("Writing an unknown JSON node type"), return JSON_TEXT("");); +    //If it go here, then it's a json_string +    #ifndef JSON_PREPARSE +	   if (fetched) return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("\"") + JSONWorker::UnfixString(_string, _string_encoded) + JSON_TEXT("\"");  //It's already been fetched, meaning that it's unescaped +	   return WriteComment(indent) + WriteName(formatted, arrayChild) + _string;  //it hasn't yet been fetched, so it's already unescaped, just do a dump +    #else +	   return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("\"") + JSONWorker::UnfixString(_string, _string_encoded) + JSON_TEXT("\""); +    #endif +} +#endif diff --git a/plugins/JSON/Source/JSON_Base64.cpp b/plugins/JSON/Source/JSON_Base64.cpp new file mode 100644 index 0000000000..fcde330b1a --- /dev/null +++ b/plugins/JSON/Source/JSON_Base64.cpp @@ -0,0 +1,111 @@ +#include "JSON_Base64.h" +#include "JSONDefs.h" + +#ifdef JSON_BINARY  //if this is not needed, don't waste space compiling it + +static const json_char * chars64 = JSON_TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); +#ifdef JSON_UNICODE +    static std::string BASE64_EMPTY_STRING; +#else +    #define BASE64_EMPTY_STRING EMPTY_STRING +#endif + +json_string JSONBase64::json_encode64(const unsigned char * binary, size_t bytes){ +    size_t misaligned = bytes % 3; +    size_t aligned = (bytes - misaligned) / 3;  //divide by three once and inc is faster than add 3 each time +    json_string result; +    result.reserve((size_t)(((float)bytes) * 1.37f) + 4); +     +    //do all of the ones that are 3 byte aligned +    for (size_t i = 0; i < aligned; ++i){ +	   result += chars64[(binary[0] & 0xFC) >> 2]; +	   result += chars64[((binary[0] & 0x03) << 4) + ((binary[1] & 0xF0) >> 4)]; +	   result += chars64[((binary[1] & 0x0F) << 2) + ((binary[2] & 0xC0) >> 6)]; +	   result += chars64[binary[2] & 0x3F]; +	   binary += 3; +    } +     +    if (misaligned){ +	   //copy the rest into a temporary buffer +	   unsigned char temp[3]; +	   for (unsigned int i = 0; i < misaligned; ++i){ +		  temp[i] = *binary++; +	   } +	   for (unsigned int i = (unsigned int)misaligned; i < 3; ++i){ +		  temp[i] = '\0'; +	   } +	    +	   //now do the final three bytes +	   result += chars64[(temp[0] & 0xFC) >> 2]; +	   result += chars64[((temp[0] & 0x03) << 4) + ((temp[1] & 0xF0) >> 4)]; +	   if (misaligned == 2){ +		  result += chars64[((temp[1] & 0x0F) << 2) + ((temp[2] & 0xC0) >> 6)]; +		  result += JSON_TEXT('='); +	   } else { +		  result += JSON_TEXT("=="); +	   } +    } +    JSON_ASSERT((size_t)(((float)bytes) * 1.37f) + 4 >= result.length(), JSON_TEXT("Didn't reserve enough space for a one-time go")); +    return result; +} + +inline json_char toBinary(json_char c){ +    if (c == JSON_TEXT('+')){ +	   return JSON_TEXT('>'); +    } else if (c == JSON_TEXT('/')){ +	   return JSON_TEXT('?'); +    } else if (c < JSON_TEXT(':')){ +	   return c + JSON_TEXT('\x04'); +    } else if (c < JSON_TEXT('[')){ +	   return c - JSON_TEXT('\x41'); +    } +    return c - 71; +} + +/* + Must be a std::string because it's binary, and chars must be 1 byte + */ +std::string JSONBase64::json_decode64(const json_string & encoded){ +    const size_t length = encoded.length(); +    #if defined JSON_DEBUG || defined JSON_SAFE +	   size_t pos = encoded.find_first_not_of(chars64); +	   if (pos != json_string::npos){ +		  JSON_ASSERT_SAFE(encoded[pos] == JSON_TEXT('='), JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); +		  if (pos != length - 1){ +			 JSON_ASSERT_SAFE(pos == length - 2, JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); +			 JSON_ASSERT_SAFE(encoded[pos + 1] == JSON_TEXT('='), JSON_TEXT("Not Base64"), return BASE64_EMPTY_STRING;); +		  } +	   } +    #endif +    const json_char * runner = encoded.c_str(); +    size_t aligned = length / 4; //don't do the last ones as they might be = padding +    std::string result; +    if (aligned){ +	   --aligned; +	   result.reserve((size_t)((float)length / 1.37) + 1); +	    +	   //first do the ones that can not have any padding +	   for (unsigned int i = 0; i < aligned; ++i){ +		  const json_char second = toBinary(runner[1]); +		  const json_char third = toBinary(runner[2]); +		  result += (toBinary(runner[0]) << 2) + ((second & 0x30) >> 4); +		  result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); +		  result += ((third & 0x3) << 6) + toBinary(runner[3]); +		  runner += 4; +	   } +	    +	   //now do the ones that might have padding, the first two characters can not be padding, so do them quickly +	   const char second = toBinary(runner[1]); +	   result += (toBinary(runner[0]) << 2) + ((second & 0x30) >> 4); +	   if (runner[2] != '='){  //not two = pads +		  const char third = toBinary(runner[2]); +		  result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2); +		  if (runner[3] != '='){  //no padding +			 result += ((third & 0x3) << 6) + toBinary(runner[3]); +		  } +	   } +    } +    return result; +} + +#endif diff --git a/plugins/JSON/Source/JSON_Base64.h b/plugins/JSON/Source/JSON_Base64.h new file mode 100644 index 0000000000..1e2d76baa8 --- /dev/null +++ b/plugins/JSON/Source/JSON_Base64.h @@ -0,0 +1,14 @@ +#ifndef JSON_BASE64_H +#define JSON_BASE64_H + +#include "JSONDebug.h" +#ifdef JSON_BINARY  //if this is not needed, don't waste space compiling it + +class JSONBase64 { +public: +    static json_string json_encode64(const unsigned char * binary, size_t bytes); +    static std::string json_decode64(const json_string & encoded); +}; + +#endif +#endif diff --git a/plugins/JSON/Source/NumberToString.h b/plugins/JSON/Source/NumberToString.h new file mode 100644 index 0000000000..a1ea2d4d3c --- /dev/null +++ b/plugins/JSON/Source/NumberToString.h @@ -0,0 +1,104 @@ +#ifndef NUMBERTOSTRING_H +#define NUMBERTOSTRING_H + +#include "JSONDebug.h" +#include "JSONMemory.h" +#include <cstdio> + +static unsigned int getlen(unsigned int size){ +    switch (size){ +	   case 1: +		  return 5;   //3 digits for the number, plus null terminator and negation +	   case 2: +		  return 7;   //5 digits for the number, plus null terminator and negation +	   case 4: +		  return 12;  //10 digits for the number, plus null terminator and negation +	   case 8: +		  return 22;  //20 digits for the number, plus null terminator and negation +    } +    JSON_ASSERT(size == 16, JSON_TEXT("template is not recognized 2^x in size")); +    return 41;  //39 digits for the number, plus null terminator and negation +} + +class NumberToString { +public: +    template<typename T> +    static json_string _itoa(T val, unsigned int size){ +	   long value = (long)val; +	   const unsigned int digits = getlen(size); +	   json_auto<json_char> result(digits); +	   result.ptr[digits - 1] = JSON_TEXT('\0'); //null terminator +	   json_char * runner = &result.ptr[digits - 2]; +	   bool negative; +	    +	   //first thing, check if it's negative, if so, make it positive +	   if (value < 0){ +		  value = -value; +		  negative = true; +	   } else { +		  negative = false; +	   } +	    +	   //create the string +	   do { +		  *runner-- = (json_char)(value % 10) + JSON_TEXT('0'); +	   } while(value /= 10); +	    +	   //if it's negative, add the negation +	   json_string res; +	   if (negative){ +		  *runner = JSON_TEXT('-'); +		  res = runner; +	   } else { +		  res = runner + 1; +	   } +	   return res;    +    } +     +    #ifndef JSON_LIBRARY +	   template<typename T> +	   static json_string _uitoa(T val, unsigned int size){ +		  unsigned long value = val; +		  const unsigned int digits = getlen(size) - 1;  //minus one because no '-' char +		  json_auto<json_char> result(digits); +		  result.ptr[digits - 1] = JSON_TEXT('\0'); //null terminator +		  json_char * runner = &result.ptr[digits - 2]; +		   +		  //create the string +		  do { +			 *runner-- = (json_char)(value % 10) + JSON_TEXT('0'); +		  } while(value /= 10); +		   +		  json_string res = runner + 1; +		  return res;    +	   } +    #endif +     +    template<typename T> +    static json_string _ftoa(T value){ +	   json_char result[64]; +	   #ifdef JSON_UNICODE +		  swprintf(result, 63, L"%f", value);  +	   #else +		  snprintf(result, 63, "%f", value);  +	   #endif +	   //strip the trailing zeros +	   for(json_char * pos = &result[0]; *pos; ++pos){ +		  if (*pos == '.'){  //only care about after the decimal +			 for(json_char * runner = pos + 1; *runner; ++runner){ +				if (*runner != JSON_TEXT('0')) pos = runner + 1; +			 } +			 *pos = JSON_TEXT('\0'); +			 break; +		  } +	   } +	   return result;     +    } +     +    static inline bool areEqual(const json_number & one, const json_number & two){ +	   const json_number temp = one - two; +	   return (temp > 0.0) ? temp < 0.00001 : temp > -0.00001;    +    } +}; + +#endif diff --git a/plugins/JSON/Source/internalJSONNode.cpp b/plugins/JSON/Source/internalJSONNode.cpp new file mode 100644 index 0000000000..2651394a8a --- /dev/null +++ b/plugins/JSON/Source/internalJSONNode.cpp @@ -0,0 +1,545 @@ +#include "internalJSONNode.h" +#include "NumberToString.h"  //So that I can convert numbers into strings +#include "JSONNode.h"  //To fill in the foreward declaration +#include "JSONWorker.h"  //For fetching and parsing and such + +/* +    The point of these constants is for faster assigning, if I +    were to constantly assign to a string literal, there would be  +    lots of copies, but since strings are copy on write, this assignment +    is much faster +*/ +static const json_string CONST_TRUE(JSON_TEXT("true")); +static const json_string CONST_FALSE(JSON_TEXT("false")); +static const json_string CONST_NULL(JSON_TEXT("null")); + +#ifdef JSON_UNIT_TEST +    void internalJSONNode::incinternalAllocCount(void){ JSONNode::incinternalAllocCount(); } +    void internalJSONNode::decinternalAllocCount(void){ JSONNode::decinternalAllocCount(); } +#endif + +internalJSONNode::internalJSONNode(const internalJSONNode & orig) : +    _type(orig._type), _name(orig._name), _name_encoded(orig._name_encoded), Children(), +    _string(orig._string), _string_encoded(orig._string_encoded), _value(orig._value) +    initializeRefCount(1) +    initializeFetch(orig.fetched) +    initializeMutex(0) +    initializeComment(orig._comment) +    initializeValid(orig.isValid){ +	    +	    +    incinternalAllocCount(); +    #ifdef JSON_MUTEX_CALLBACKS +	   _set_mutex(orig.mylock, false);   +    #endif +    if (!orig.Children.empty()){ +	   Children.reserve(orig.Children.size()); +	   json_foreach(orig.Children, myrunner){ +		  Children.push_back(JSONNode::newJSONNode((*myrunner) -> duplicate())); +	   } +    } +} + +#ifdef JSON_PREPARSE +    #define SetFetchedFalseOrDo(code) code +#else +    #define SetFetchedFalseOrDo(code) SetFetched(false) +#endif + +#ifdef JSON_VALIDATE +    #define NOTVALID false +#else +    #define NOTVALID +#endif + +//this one is specialized because the root can only be array or node +internalJSONNode::internalJSONNode(const json_string & unparsed) : _type(), _name(),_name_encoded(false), _string(unparsed), _string_encoded(), _value(), Children() +    initializeMutex(0) +    initializeRefCount(1) +    initializeFetch(false) +    initializeComment(0) +    initializeValid(0){ +	    +    incinternalAllocCount(); +    switch (unparsed[0]){ +	   case JSON_TEXT('{'):  //node +		  _type = JSON_NODE; +		  #ifdef JSON_PREPARSE +			 FetchNode(); +		  #endif +		  break; +	   case JSON_TEXT('['):  //array +		  _type = JSON_ARRAY; +		  #ifdef JSON_PREPARSE +			 FetchArray(); +		  #endif +		  break; +	   default: +		  JSON_FAIL_SAFE(JSON_TEXT("root not starting with either { or ["), Nullify(NOTVALID);); +		  break; +    } +} + +internalJSONNode::internalJSONNode(const json_string & name_t, const json_string & value_t) : _type(), _name_encoded(), _name(JSONWorker::FixString(name_t, NAME_ENCODED)), _string(), _string_encoded(), _value(), Children() +    initializeMutex(0) +    initializeRefCount(1) +    initializeFetch(0) +    initializeComment(0) +    initializeValid(0){ +	    +    incinternalAllocCount(); +	    +    if (value_t.empty()){ +        _type = JSON_NULL; +	   #ifdef JSON_VALIDATE +		  isValid = true; +	   #endif +	   SetFetched(true); +        return; +    } +     +    _string = value_t; +    const json_char firstchar = value_t[0]; +    #if defined JSON_DEBUG || defined JSON_SAFE +	   const json_char lastchar = value_t[value_t.length() - 1]; +    #endif +     +    switch (firstchar){ +        case JSON_TEXT('\"'):  //a json_string literal, still escaped and with leading and trailing quotes +            JSON_ASSERT_SAFE(lastchar == JSON_TEXT('\"'), JSON_TEXT("Unterminated quote"), Nullify(NOTVALID); return;); +            _type = JSON_STRING; +		  SetFetchedFalseOrDo(FetchString()); +            break; +        case JSON_TEXT('{'):  //a child node, or set of children +            JSON_ASSERT_SAFE(lastchar == JSON_TEXT('}'), JSON_TEXT("Missing }"), Nullify(NOTVALID); return;); +            _type = JSON_NODE; +		  SetFetchedFalseOrDo(FetchNode()); +            break; +        case JSON_TEXT('['):  //an array +            JSON_ASSERT_SAFE(lastchar == JSON_TEXT(']'), JSON_TEXT("Missing ]"), Nullify(NOTVALID); return;); +            _type = JSON_ARRAY; +		  SetFetchedFalseOrDo(FetchArray()); +            break; +        case JSON_TEXT('t'): +            JSON_ASSERT_SAFE(value_t == JSON_TEXT("true"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); +            _value._bool = true; +            _type = JSON_BOOL; +		  SetFetched(true); +            break; +        case JSON_TEXT('f'): +            JSON_ASSERT_SAFE(value_t == JSON_TEXT("false"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); +            _value._bool = false; +            _type = JSON_BOOL; +		  SetFetched(true); +            break; +        case JSON_TEXT('n'): +            JSON_ASSERT_SAFE(value_t == JSON_TEXT("null"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); +            _type = JSON_NULL; +		  SetFetched(true); +		  #ifdef JSON_VALIDATE +			 isValid = true; +		  #endif +            break; +        default: +            JSON_ASSERT_SAFE(value_t.find_first_not_of(JSON_TEXT("0123456789.e+-")) == json_string::npos, json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); +            _type = JSON_NUMBER; +		  SetFetchedFalseOrDo(FetchNumber()); +            break; +    } +} + +internalJSONNode::~internalJSONNode(void){ +    decinternalAllocCount(); +    #ifdef JSON_MUTEX_CALLBACKS +	   _unset_mutex();   +    #endif +    //DO NOT delete the children!  It automatically gets removed +} + +void internalJSONNode::FetchString(void) const { +    JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON json_string type is empty?"), Nullify(NOTVALID); return;); +    JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't start with a quotation?"), Nullify(NOTVALID); return;); +    JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't end with a quotation?"), Nullify(NOTVALID); return;); +    _string = JSONWorker::FixString(_string.substr(1, _string.length() - 2), STRING_ENCODED); +} + +void internalJSONNode::FetchNode(void) const { +    JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); +    JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('{'), JSON_TEXT("JSON node type doesn't start with a bracket?"), Nullify(NOTVALID); return;); +    JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('}'), JSON_TEXT("JSON node type doesn't end with a bracket?"), Nullify(NOTVALID); return;); +    JSONWorker::DoNode(this, _string); +    clearString(_string); +} + +void internalJSONNode::FetchArray(void) const { +    JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); +    JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('['), JSON_TEXT("JSON node type doesn't start with a square bracket?"), Nullify(NOTVALID); return;); +    JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT(']'), JSON_TEXT("JSON node type doesn't end with a square bracket?"), Nullify(NOTVALID); return;); +    JSONWorker::DoArray(this, _string); +    clearString(_string); +} + +void internalJSONNode::FetchNumber(void) const { +    #ifdef JSON_UNICODE +	   { +		  const size_t len = _string.length(); +		  json_auto<char> temp(len + 1); +		  wcstombs(temp.ptr, _string.c_str(), len); +		  temp.ptr[len] = '\0'; +		  _value._number = (json_number)atof(temp.ptr); +	   } +    #else +	   _value._number = (json_number)atof(_string.c_str()); +    #endif +} + +#ifndef JSON_PREPARSE +    void internalJSONNode::Fetch(void) const { +	   if (fetched) return; +	   switch (type()){ +		  case JSON_STRING: +			 FetchString(); +			 break; +		  case JSON_NODE: +			 FetchNode(); +			 break; +		  case JSON_ARRAY: +			 FetchArray(); +			 break; +		  case JSON_NUMBER: +			 FetchNumber(); +			 break; +		  #if defined JSON_DEBUG || defined JSON_SAFE +			 default: +				JSON_FAIL(JSON_TEXT("Fetching an unknown type")); +				Nullify(NOTVALID); +		  #endif +	   } +	   fetched = true;   +    } +#endif + +void internalJSONNode::Set(const json_string & val){ +    _type = JSON_STRING; +    _string = val; +    _string_encoded = true; +    SetFetched(true); +} + + +#ifdef JSON_LIBRARY +    void internalJSONNode::Set(long val){ +	   _type = JSON_NUMBER; +	   _value._number = (json_number)val; +	   _string = NumberToString::_itoa<long>(val, sizeof(long)); +	   SetFetched(true); +    } + +    void internalJSONNode::Set(json_number val){ +	   _type = JSON_NUMBER; +	   _value._number = val; +	   _string = NumberToString::_ftoa<json_number>(val); +	   SetFetched(true); +    } +#else +    #define SET(converter, type)\ +	   void internalJSONNode::Set(type val){\ +		  _type = JSON_NUMBER;\ +		  _value._number = (json_number)val;\ +		  _string = NumberToString::converter<type>(val, sizeof(type));\ +		  SetFetched(true);\ +	   } +    #define SET_INTEGER(type) SET(_itoa, type) SET(_uitoa, unsigned type) +    #define SET_FLOAT(type) \ +	   void internalJSONNode::Set(type val){\ +		  _type = JSON_NUMBER;\ +		  _value._number = (json_number)val;\ +		  _string = NumberToString::_ftoa<type>(val);\ +		  SetFetched(true);\ +	   } + +    SET_INTEGER(char) +    SET_INTEGER(short) +    SET_INTEGER(int) +    SET_INTEGER(long) +    #ifndef JSON_ISO_STRICT +	   SET_INTEGER(long long) +    #endif + +    SET_FLOAT(float) +    SET_FLOAT(double) +#endif + +void internalJSONNode::Set(bool val){ +    _type = JSON_BOOL; +    _value._bool = val; +    _string = val ? CONST_TRUE : CONST_FALSE; +    SetFetched(true); +} + +bool internalJSONNode::IsEqualTo(const internalJSONNode * val) const { +    #ifdef JSON_REF_COUNT +	   if (this == val) return true;  //reference counting the same internal object, so they must be equal +    #endif +    if (type() != val -> type()) return false;	 //aren't even same type +    if (_name != val -> _name) return false;  //names aren't the same +    if (type() == JSON_NULL) return true;  //both null, can't be different +    #ifndef JSON_PREPARSE +	   Fetch(); +	   val -> Fetch(); +    #endif +    switch (type()){ +	   case JSON_STRING: +		  return val -> _string == _string; +	   case JSON_NUMBER: +		  return NumberToString::areEqual(val -> _value._number, _value._number); +	   case JSON_BOOL: +		  return val -> _value._bool == _value._bool; +    }; +     +    JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Checking for equality, not sure what type")); +    if (Children.size() != val -> Children.size()) return false;  //if they arne't he same size then they certainly aren't equal +     +    //make sure each children is the same +    JSONNode ** valrunner = val -> Children.begin(); +    json_foreach(Children, myrunner){ +        JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); +	   JSON_ASSERT(*valrunner, JSON_TEXT("a null pointer within the children")); +	   JSON_ASSERT(valrunner != val -> Children.end(), JSON_TEXT("at the end of other one's children, but they're the same size?")); +        if (**myrunner != **valrunner) return false; +	   ++valrunner; +    } +    return true; +} + +#ifdef JSON_VALIDATE +void internalJSONNode::Nullify(bool validation) const { +    isValid = validation; +#else +void internalJSONNode::Nullify(void) const { +#endif +    _type = JSON_NULL; +    _string = CONST_NULL; +    SetFetched(true); +} +     +#ifdef JSON_MUTEX_CALLBACKS +    #define JSON_MUTEX_COPY ,mylock +#else +    #define JSON_MUTEX_COPY +#endif + +#ifdef JSON_LIBRARY +void internalJSONNode::push_back(JSONNode * node){ +#else +void internalJSONNode::push_back(const JSONNode & node){ +#endif +    JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing back to something that is not an array or object")); +    #ifdef JSON_LIBRARY +	   #ifdef JSON_MUTEX_CALLBACKS +		  if (mylock) node -> set_mutex(mylock); +	   #endif +	   Children.push_back(node); +    #else +	   Children.push_back(JSONNode::newJSONNode(node   JSON_MUTEX_COPY)); +    #endif +} +     +void internalJSONNode::push_front(const JSONNode & node){ +    JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing front to something that is not an array or object")); +    Children.push_front(JSONNode::newJSONNode(node   JSON_MUTEX_COPY)); +} + +JSONNode * internalJSONNode::pop_back(json_index_t pos){ +    JSONNode * result = Children[pos]; +    JSONNode ** temp = Children.begin() + pos; +    Children.erase(temp); +    return result; +} + +JSONNode * internalJSONNode::pop_back(const json_string & name_t){ +    if (JSONNode ** res = at(name_t)){ +	   JSONNode * result = *res; +	   Children.erase(res); +	   return result; +    } +    return 0; +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +    JSONNode * internalJSONNode::pop_back_nocase(const json_string & name_t){ +	   if (JSONNode ** res = at_nocase(name_t)){ +		  JSONNode * result = *res; +		  Children.erase(res); +		  return result; +	   } +	   return 0; +    } +#endif + +JSONNode ** internalJSONNode::at(const json_string & name_t){ +    Fetch(); +    json_foreach(Children, myrunner){ +	   JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); +	   if ((*myrunner) -> name() == name_t) return myrunner; +    } +    return 0; +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +    bool internalJSONNode::AreEqualNoCase(const json_char * ch_one, const json_char * ch_two){ +	   while (*ch_one){  //only need to check one, if the other one terminates early, the check will cause it to fail +		  const json_char c_one = *ch_one; +		  const json_char c_two = *ch_two; +		  if (c_one != c_two){ +			 if ((c_two > 64) && (c_two < 91)){  //A - Z +				if (c_one != (json_char)(c_two + 32)) return false; +			 } else if ((c_two > 96) && (c_two < 123)){  //a - z +				if (c_one != (json_char)(c_two - 32)) return false; +			 } else { //not a letter, so return false +				return false; +			 } +		  } +		  ++ch_one; +		  ++ch_two; +		   +	   } +	   return *ch_two == '\0';  //this one has to be null terminated too, or else json_string two is longer, hence, not equal +    } + +    JSONNode ** internalJSONNode::at_nocase(const json_string & name_t){ +	   Fetch(); +	   json_foreach(Children, myrunner){ +		  JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); +		  if (AreEqualNoCase((*myrunner) -> name().c_str(), name_t.c_str())) return myrunner; +	   } +	   return 0; +    } +#endif + +#ifndef JSON_PREPARSE +    void internalJSONNode::preparse(void){ +	   Fetch(); +	   json_foreach(Children, myrunner){ +		  (*myrunner) -> preparse(); +	   } +    } +#endif +     +#ifdef JSON_VALIDATE +    bool internalJSONNode::validate(void){ +	   json_foreach(Children, myrunner){ +		  if ((*myrunner) -> type() != JSON_NULL){ +			 #ifndef JSON_PREPARSE +				(*myrunner) -> internal -> Fetch(); +			 #endif +			 if ((*myrunner) -> type() == JSON_NULL) return false; +		  } else if (!((*myrunner) -> internal -> isValid)){ +			 JSON_FAIL(_name + JSON_TEXT(" is null and not valid")); +			 return false; +		  } +	   } +	   json_foreach(Children, runner){ +		  if (!((*runner) -> internal -> validate())) return false; +	   } +	   return true; +    } +#endif + +#ifdef JSON_DEBUG +    #ifndef JSON_LIBRARY +	   JSONNode internalJSONNode::Dump(size_t & totalbytes) const { +		  JSONNode dumpage(JSON_NODE); +		  dumpage.set_name(JSON_TEXT("internalJSONNode")); +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); +		   +		  size_t memory = sizeof(internalJSONNode); +		  memory += _name.capacity() * sizeof(json_char); +		  memory += _string.capacity() * sizeof(json_char); +		  memory += Children.capacity() * sizeof(JSONNode*); +		  #ifdef JSON_COMMENTS +			 memory += _comment.capacity() * sizeof(json_char); +		  #endif +		  totalbytes += memory; +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), memory))); +		   +		   +		  #ifdef JSON_REF_COUNT +			 dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("refcount"), refcount))); +		  #endif +		  #ifdef JSON_MUTEX_CALLBACKS +			 dumpage.push_back(JSON_NEW(DumpMutex())); +		  #endif + + +		  #define DUMPCASE(ty)\ +			 case ty:\ +				dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT(#ty))));\ +				break; +		   +		  switch(type()){ +			 DUMPCASE(JSON_NULL) +			 DUMPCASE(JSON_STRING) +			 DUMPCASE(JSON_NUMBER) +			 DUMPCASE(JSON_BOOL) +			 DUMPCASE(JSON_ARRAY) +			 DUMPCASE(JSON_NODE) +			 default: +				dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT("Unknown")))); +		  } +		   +		  JSONNode str(JSON_NODE); +		  str.set_name(JSON_TEXT("_name")); +		  str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _name))); +		  str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _name.length()))); +		  str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _name.capacity()))); +		   +		  #ifdef JSON_LESS_MEMORY +			 dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _type & 0x10))); +		  #else +			 dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _name_encoded))); +		  #endif +		  dumpage.push_back(JSON_NEW(str)); +		  dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_string_encoded"), _string_encoded))); +		  str.clear(); +		  str.set_name(JSON_TEXT("_string")); +		  str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _string))); +		  str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _string.length()))); +		  str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _string.capacity()))); +		  dumpage.push_back(JSON_NEW(str)); +		   +		  JSONNode unio(JSON_NODE); +		  unio.set_name(JSON_TEXT("_value")); +		  unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_bool"), _value._bool))); +		  unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_number"), _value._number))); +		  dumpage.push_back(JSON_NEW(unio)); +		   +		  #ifndef JSON_PREPARSE +			 dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("fetched"), fetched))); +		  #endif +		   +		  #ifdef JSON_COMMENTS +			 str.clear(); +			 str.set_name(JSON_TEXT("_comment")); +			 str.push_back(JSON_NEW(JSONNode(JSON_TEXT("value"), _comment))); +			 str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _comment.length()))); +			 str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _comment.capacity()))); +			 dumpage.push_back(JSON_NEW(str)); +		  #endif +		   +		  JSONNode arra(JSON_NODE); +		  arra.set_name(JSON_TEXT("Children")); +		  arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("size"), Children.size()))); +		  arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("capacity"), Children.capacity()))); +		  JSONNode chil(JSON_ARRAY); +		  chil.set_name(JSON_TEXT("array")); +		  json_foreach(Children, it){ +			 chil.push_back(JSON_NEW((*it) -> dump(totalbytes))); +		  } +		  arra.push_back(JSON_NEW(chil)); +		  dumpage.push_back(JSON_NEW(arra)); +		   +		  return dumpage; +	   } +    #endif +#endif diff --git a/plugins/JSON/Source/internalJSONNode.h b/plugins/JSON/Source/internalJSONNode.h new file mode 100644 index 0000000000..8667e3fbbb --- /dev/null +++ b/plugins/JSON/Source/internalJSONNode.h @@ -0,0 +1,453 @@ +#ifndef INTERNAL_JSONNODE_H +#define INTERNAL_JSONNODE_H + +#include "JSONDebug.h" +#include "JSONChildren.h" +#include "JSONMemory.h" +#ifdef JSON_DEBUG +    #include <climits>  //to check int value +#endif + +/* +    This class is the work horse of libJSON, it handles all of the +    functinality of JSONNode.  This object is reference counted for +    speed and memory reasons. +  +    If JSON_REF_COUNT is not on, this internal structure still has an important +    purpose, as it can be passed around by JSONNoders that are flagged as temporary +*/ + +class JSONNode;  //forward declaration + +#ifndef JSON_LIBRARY +    #define DECL_SET_INTEGER(type) void Set(type); void Set(unsigned type); +#endif + +#ifdef JSON_MUTEX_CALLBACKS +    #define initializeMutex(x) ,mylock(x) +#else +    #define initializeMutex(x) +#endif + +#ifdef JSON_PREPARSE +    #define SetFetched(b) (void)0 +    #define Fetch() (void)0 +    #define initializeFetch(x) +#else +    #define initializeFetch(x) ,fetched(x) +#endif + +#ifdef JSON_REF_COUNT +    #define initializeRefCount(x) ,refcount(x) +#else +    #define initializeRefCount(x) +#endif + +#ifdef JSON_COMMENTS +    #define initializeComment(x) ,_comment(x) +#else +    #define initializeComment(x) +#endif + +#ifndef JSON_UNIT_TEST +    #define incAllocCount() (void)0 +    #define decAllocCount() (void)0 +    #define incinternalAllocCount() (void)0 +    #define decinternalAllocCount() (void)0 +#endif + +#ifdef JSON_VALIDATE +    #define initializeValid(x) ,isValid(x) +#else +    #define initializeValid(x) +#endif + +class internalJSONNode { +public: +    internalJSONNode(char mytype = JSON_NULL); +    internalJSONNode(const json_string & unparsed); +    internalJSONNode(const json_string & name_t, const json_string & value_t); +    internalJSONNode(const internalJSONNode & orig);   +    internalJSONNode & operator = (const internalJSONNode &); +    ~internalJSONNode(void); +     +    static internalJSONNode * newInternal(char mytype = JSON_NULL); +    static internalJSONNode * newInternal(const json_string & unparsed); +    static internalJSONNode * newInternal(const json_string & name_t, const json_string & value_t); +    static internalJSONNode * newInternal(const internalJSONNode & orig);  //not copyable, only by this class +    static void deleteInternal(internalJSONNode * ptr); + +    json_index_t size(void) const; +    bool empty(void) const; +    unsigned char type(void) const; +     +    json_string name(void) const; +    void setname(const json_string & newname); +    #ifdef JSON_COMMENTS +	   void setcomment(const json_string & comment); +	   json_string getcomment(void) const; +    #endif +    json_string as_string(void) const; +    long as_int(void) const; +    json_number as_float(void) const; +    bool as_bool(void) const; +  +    #ifndef JSON_PREPARSE +	   void preparse(void); +    #endif +     +    #ifdef JSON_LIBRARY +	   void push_back(JSONNode * node); +    #else +	   void push_back(const JSONNode & node); +    #endif +    void reserve(json_index_t size); +    void push_front(const JSONNode & node); +    JSONNode * pop_back(json_index_t pos); +    JSONNode * pop_back(const json_string & name_t); +    #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +	   JSONNode * pop_back_nocase(const json_string & name_t); +    #endif +     +    JSONNode * at(json_index_t pos); +    //These return ** because pop_back needs them +    JSONNode ** at(const json_string & name_t); +    #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +	   JSONNode ** at_nocase(const json_string & name_t); +    #endif +     +    void Set(const json_string & val); +    #ifdef JSON_LIBRARY +	   void Set(json_number val); +	   void Set(long val); +    #else +	   DECL_SET_INTEGER(char) +	   DECL_SET_INTEGER(short) +	   DECL_SET_INTEGER(int) +	   DECL_SET_INTEGER(long) +	   #ifndef JSON_ISO_STRICT +		  DECL_SET_INTEGER(long long) +	   #endif +	    +	   void Set(float val); +	   void Set(double val); +    #endif +    void Set(bool val); +   +    bool IsEqualTo(const json_string & val)const ; +    bool IsEqualTo(bool val) const; +    bool IsEqualTo(const internalJSONNode * val) const;   +     +    template<typename T> +    bool IsEqualToNum(T val) const; + +    internalJSONNode * incRef(void); +    #ifdef JSON_REF_COUNT +	   void decRef(void); +	   bool hasNoReferences(void); +    #endif +    internalJSONNode * makeUnique(void); +     +    JSONNode ** begin(void) const; +    JSONNode ** end(void) const; +    #ifdef JSON_REF_COUNT +	   size_t refcount BITS(20); +    #endif +    bool Fetched(void) const; +    #ifdef JSON_MUTEX_CALLBACKS +	   void * mylock; +	   void _set_mutex(void * mutex, bool unset = true); +	   void _unset_mutex(void); +    #endif +    #ifdef JSON_UNIT_TEST +	   static void incinternalAllocCount(void); +	   static void decinternalAllocCount(void); +    #endif +     +    #ifdef JSON_WRITER +	   json_string WriteName(bool formatted, bool arrayChild) const; +	   json_string WriteChildren(unsigned int indent); +	   json_string WriteComment(unsigned int indent) const; +	   json_string Write(unsigned int indent, bool arrayChild); +    #endif +    #ifdef JSON_DEBUG +	   #ifndef JSON_LIBRARY +		  JSONNode Dump(size_t & totalmemory) const; +		  JSONNode DumpMutex(void) const; +	   #endif +    #endif +     +    //json parts +    mutable unsigned char _type BITS(3); +    mutable bool _name_encoded BITS(1);  //must be above name due to initialization list order +    json_string _name;	 +     +    mutable json_string _string;   //these are both mutable because the string can change when it's fetched +    mutable bool _string_encoded BITS(1); +     +    //the value of the json +    union value_union_t { +	   bool _bool; +	   json_number _number; +    }; +    mutable value_union_t _value; //internal structure changes depending on type +     +    jsonChildren Children;  //container that holds all of my children +     +    #ifdef JSON_VALIDATE +	   mutable bool isValid BITS(1);  //this does not need to be initialized, it's only used if it's null +	   void Nullify(bool validation = true) const; +	   bool validate(void); +    #else +	   void Nullify(void) const; +    #endif +     +    //Fetching and such +    #ifndef JSON_PREPARSE +	   mutable bool fetched BITS(1); +	   void SetFetched(bool val) const; +	   void Fetch(void) const;  //it's const because it doesn't change the VALUE of the function +    #endif +     +    #ifdef JSON_COMMENTS +	   json_string _comment; +    #endif +	    +    void FetchString(void) const; +    void FetchNode(void) const; +    void FetchArray(void) const; +    void FetchNumber(void) const; +    #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +	   static bool AreEqualNoCase(const json_char * ch_one, const json_char * ch_two); +    #endif +}; + +inline internalJSONNode::internalJSONNode(char mytype) : _type(mytype), Children(), _name(), _name_encoded(), _string(), _string_encoded(), _value() +    initializeMutex(0)   +    initializeRefCount(1) +    initializeFetch(true) +    initializeComment(0) +    initializeValid(true){ +	    +    incinternalAllocCount(); +} + +inline internalJSONNode * internalJSONNode::incRef(void){ +    #ifdef JSON_REF_COUNT +	   ++refcount; +	   return this; +    #else +	   return makeUnique(); +    #endif +} + +inline json_index_t internalJSONNode::size(void) const { +    Fetch(); +    return Children.size(); +} + +inline bool internalJSONNode::empty(void) const { +    if (type() != JSON_NODE && type() != JSON_ARRAY) return true; +    Fetch(); +    return Children.empty(); +} + +inline unsigned char internalJSONNode::type(void) const { +    #ifdef JSON_LESS_MEMORY +	   return _type & 0xF; +    #else +	   return _type; +    #endif +} + +inline json_string internalJSONNode::name(void) const { +    return _name; +} + +inline void internalJSONNode::setname(const json_string & newname){ +    _name = newname; +    #ifdef JSON_LESS_MEMORY +	   _type |= 0x10; +    #else +	   _name_encoded = true;  +    #endif +} + +#ifdef JSON_COMMENTS +    inline void internalJSONNode::setcomment(const json_string & comment){ +	   _comment = comment; +    } + +    inline json_string internalJSONNode::getcomment(void) const { +	   return _comment; +    } +#endif + +inline json_string internalJSONNode::as_string(void) const { +    Fetch(); +    return _string; +} + +inline long internalJSONNode::as_int(void) const { +    Fetch(); +    switch(type()){ +	   case JSON_NULL: +		  return 0; +	   case JSON_BOOL: +		  return _value._bool ? 1 : 0; +    } +    JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_int returning undefined results")); +    JSON_ASSERT(_value._number > LONG_MIN, _string + JSON_TEXT(" is outside the lower range of long")); +    JSON_ASSERT(_value._number < LONG_MAX, _string + JSON_TEXT(" is outside the upper range of long")); +    JSON_ASSERT(_value._number == (json_number)((int)_value._number), json_string(JSON_TEXT("as_int will truncate ")) + _string); +    return (int)_value._number; +} + +inline json_number internalJSONNode::as_float(void) const { +    Fetch(); +    switch(type()){ +	   case JSON_NULL: +		  return (json_number)0.0; +	   case JSON_BOOL: +		  return (json_number)(_value._bool ? 1.0 : 0.0); +    } +    JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_float returning undefined results")); +    return _value._number;    +} + +inline bool internalJSONNode::as_bool(void) const { +    Fetch(); +    switch(type()){ +	   case JSON_NUMBER: +		  return _value._number != 0.0f; +	   case JSON_NULL: +		  return false; +    } +    JSON_ASSERT(type() == JSON_BOOL, JSON_TEXT("as_bool returning undefined results")); +    return _value._bool; +} + +inline bool internalJSONNode::IsEqualTo(const json_string & val) const { +    if (type() != JSON_STRING) return false; +    Fetch();  +    return val == _string; +} + +inline bool internalJSONNode::IsEqualTo(bool val) const { +    if (type() != JSON_BOOL) return false; +    Fetch();  +    return val == _value._bool; +} + +template<typename T> +inline bool internalJSONNode::IsEqualToNum(T val) const { +    if (type() != JSON_NUMBER) return false; +    Fetch();  +    return (json_number)val == _value._number; +} + +#ifdef JSON_REF_COUNT +    inline void internalJSONNode::decRef(void){ +	   JSON_ASSERT(refcount != 0, JSON_TEXT("decRef on a 0 refcount internal")); +	   --refcount; +    } + +    inline bool internalJSONNode::hasNoReferences(void){ +	   return refcount == 0; +    } +#endif + +inline internalJSONNode * internalJSONNode::makeUnique(void){ +    #ifdef JSON_REF_COUNT +	   if (refcount > 1){ +		  decRef(); +		  return newInternal(*this); +	   } +	   JSON_ASSERT(refcount == 1, JSON_TEXT("makeUnique on a 0 refcount internal")); +	   return this; +    #else +	   return newInternal(*this); +    #endif +} + +#ifndef JSON_PREPARSE +    inline void internalJSONNode::SetFetched(bool val) const { +	   fetched = val; +    } +#endif + +inline bool internalJSONNode::Fetched(void) const { +    #ifndef JSON_PREPARSE +	   return fetched; +    #else +	   return true; +    #endif +} + +inline JSONNode ** internalJSONNode::begin(void) const { +    Fetch(); +    return Children.begin(); +} + +inline JSONNode ** internalJSONNode::end(void) const { +    Fetch(); +    return Children.end(); +} + +inline JSONNode * internalJSONNode::at(json_index_t pos){ +    Fetch(); +    return Children[pos]; +} + +inline void internalJSONNode::reserve(json_index_t size){ +    Fetch(); +    Children.reserve2(size); +} + +/* +    These functions are to allow allocation to be completely controlled by the callbacks +*/ + +inline void internalJSONNode::deleteInternal(internalJSONNode * ptr){ +    #ifdef JSON_MEMORY_CALLBACKS +	   ptr -> ~internalJSONNode(); +	   libjson_free<internalJSONNode>(ptr); +    #else +	   delete ptr; +    #endif      +} + +inline internalJSONNode * internalJSONNode::newInternal(char mytype){ +    #ifdef JSON_MEMORY_CALLBACKS +	   return new(json_malloc<internalJSONNode>(1)) internalJSONNode(mytype); +    #else +	   return new internalJSONNode(mytype); +    #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(const json_string & unparsed){ +    #ifdef JSON_MEMORY_CALLBACKS +	   return new(json_malloc<internalJSONNode>(1)) internalJSONNode(unparsed); +    #else +	   return new internalJSONNode(unparsed); +    #endif    +} + +inline internalJSONNode * internalJSONNode::newInternal(const json_string & name_t, const json_string & value_t){ +    #ifdef JSON_MEMORY_CALLBACKS +	   return new(json_malloc<internalJSONNode>(1)) internalJSONNode(name_t, value_t); +    #else +	   return new internalJSONNode(name_t, value_t); +    #endif    +} + +inline internalJSONNode * internalJSONNode::newInternal(const internalJSONNode & orig){ +    #ifdef JSON_MEMORY_CALLBACKS +	   return new(json_malloc<internalJSONNode>(1)) internalJSONNode(orig); +    #else +	   return new internalJSONNode(orig); +    #endif     +} + + +#endif diff --git a/plugins/JSON/Source/libJSON.cpp b/plugins/JSON/Source/libJSON.cpp new file mode 100644 index 0000000000..5671f9c0ec --- /dev/null +++ b/plugins/JSON/Source/libJSON.cpp @@ -0,0 +1,480 @@ +/* +    This is the implementation of the C interface to libJSON +    This file may be included in any C++ application, but it will  +    be completely ignored if JSON_LIBRARY isn't defined.  The  +    only reason JSON_LIBRARY should be defined is when compiling libJSON +    as a library +*/ +#include "../libJSON.h" +#ifdef JSON_LIBRARY + +    #include "JSONNode.h" +    #include "JSONWorker.h" +    #include <stdexcept>  //some methods throw exceptions +    #ifdef JSON_MEMORY_MANAGE +	   auto_expand StringHandler;  +	   auto_expand_node NodeHandler; +	   #define MANAGER_INSERT(x) NodeHandler.insert(x) +    #else +	   #define MANAGER_INSERT(x) x +    #endif + +    #ifdef JSON_SAFE +	   static const json_char * EMPTY_CSTRING = JSON_TEXT(""); +    #endif + +    inline json_char * toCString(const json_string & str){ +	   const size_t len((str.length() + 1) * sizeof(json_char)); +	   #ifdef JSON_MEMORY_MANAGE +		  return (json_char *)StringHandler.insert(memcpy(json_malloc<json_char>(len), str.c_str(), len)); +	   #else +		  return (json_char *)memcpy(json_malloc<json_char>(len), str.c_str(), len); +	   #endif +    } +     +    /* +	   stuff that's in namespace libJSON +    */ +    void json_free(void * str){ +	   JSON_ASSERT_SAFE(str, JSON_TEXT("freeing null ptr"), return;); +	   #ifdef JSON_MEMORY_MANAGE +		  StringHandler.remove(str); +	   #endif +	   libjson_free<void>(str); +    } +     +    void json_delete(JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("deleting null ptr"), return;); +	   #ifdef JSON_MEMORY_MANAGE +		  NodeHandler.remove(node); +	   #endif +	   JSONNode::deleteJSONNode((JSONNode *)node);  +    } + +    #ifdef JSON_MEMORY_MANAGE +	   void json_free_all(void){ +		  StringHandler.clear(); +	   } +	    +	   void json_delete_all(void){ +		  NodeHandler.clear(); +	   } +    #endif +     +    JSONNODE * json_parse(const json_char * json){ +	   JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_parse"), return 0;); +	   try { +		  //use this constructor to simply copy reference instead of copying the temp +		  return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::parse(json))); +	   } catch (std::invalid_argument){} +	   return 0; +    } + +    json_char * json_strip_white_space(const json_char * json){ +	   JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_strip_white_space"), return 0;); +	   return toCString(JSONWorker::RemoveWhiteSpaceAndComments(json)); +    } + +    #ifdef JSON_VALIDATE +	   JSONNODE * json_validate(const json_char * json){ +		  JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_validate"), return 0;); +		  try { +			 //use this constructor to simply copy reference instead of copying the temp +			 return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::validate(json))); +		  } catch (std::invalid_argument){} +		  return 0; +	   } +    #endif + +    #if defined JSON_DEBUG && !defined JSON_STDERROR +	   //When libjson errors, a callback allows the user to know what went wrong +	   void json_register_debug_callback(json_error_callback_t callback){ +		  JSONDebug::register_callback(callback); +	   } +    #endif + +    #ifdef JSON_MUTEX_CALLBACKS +	   #ifdef JSON_MUTEX_MANAGE +		  void json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, json_mutex_callback_t destroy, void * manager_lock){ +			 JSONNode::register_mutex_callbacks(lock, unlock, manager_lock); +			 JSONNode::register_mutex_destructor(destroy); +		  } + +	   #else +		  void json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock){ +			 JSONNode::register_mutex_callbacks(lock, unlock, manager_lock); +		  } +	   #endif + +	   void json_set_global_mutex(void * mutex){ +		  JSONNode::set_global_mutex(mutex); +	   } + +	   void json_set_mutex(JSONNODE * node, void * mutex){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_mutex"), return;); +		  ((JSONNode*)node) -> set_mutex(mutex); +	   } + +	   void json_lock(JSONNODE * node, int threadid){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_lock"), return;); +		  ((JSONNode*)node) -> lock(threadid);    +	   } + +	   void json_unlock(JSONNODE * node, int threadid){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_unlock"), return;); +		  ((JSONNode*)node) -> unlock(threadid);    +	   } +    #endif + +    #ifdef JSON_MEMORY_CALLBACKS +	   void json_register_memory_callbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre){ +		  JSONMemory::registerMemoryCallbacks(mal, real, fre); +	   } +    #endif + + +    /* +	stuff that's in class JSONNode +	*/ +    //ctors +    JSONNODE * json_new_a(const json_char * name, const json_char * value){ +	   JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_a"), name = EMPTY_CSTRING;); +	   JSON_ASSERT_SAFE(value, JSON_TEXT("null value to json_new_a"), value = EMPTY_CSTRING;); +	   #ifdef JSON_MEMORY_CALLBACKS +		  return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(name, json_string(value))); +	   #else +		  return MANAGER_INSERT(new JSONNode(name, json_string(value))); +	   #endif  +    } + +    JSONNODE * json_new_i(const json_char * name, long value){ +	   JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_i"), name = EMPTY_CSTRING;); +	   #ifdef JSON_MEMORY_CALLBACKS +		  return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(name, value)); +	   #else +		  return MANAGER_INSERT(new JSONNode(name, value)); +	   #endif  +    } + +    JSONNODE * json_new_f(const json_char * name, json_number value){ +	   JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_f"), name = EMPTY_CSTRING;); +	   #ifdef JSON_MEMORY_CALLBACKS +		  return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(name, value)); +	   #else +		  return MANAGER_INSERT(new JSONNode(name, value)); +	   #endif  +    } + +    JSONNODE * json_new_b(const json_char * name, int value){ +	   JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_b"), name = EMPTY_CSTRING;); +	   #ifdef JSON_MEMORY_CALLBACKS +		  return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(name, (bool)value)); +	   #else +		  return MANAGER_INSERT(new JSONNode(name, (bool)value)); +	   #endif  +    } + +    JSONNODE * json_new(char type){ +	   #ifdef JSON_MEMORY_CALLBACKS +		  return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(type)); +	   #else +		  return MANAGER_INSERT(new JSONNode(type)); +	   #endif  +    } + +    JSONNODE * json_copy(const JSONNODE * orig){ +	   JSON_ASSERT_SAFE(orig, JSON_TEXT("null orig to json_copy"), return 0;); +	   #ifdef JSON_MEMORY_CALLBACKS +		  return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(*((JSONNode*)orig))); +	   #else +		  return MANAGER_INSERT(new JSONNode(*((JSONNode*)orig))); +	   #endif  +    } + +    JSONNODE * json_duplicate(const JSONNODE * orig){ +	   JSON_ASSERT_SAFE(orig, JSON_TEXT("null orig to json_duplicate"), return 0;); +	   return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)orig) -> duplicate())); +    } + +    //assignment +    void json_set_a(JSONNODE * node, const json_char * value){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_a"), return;); +	   JSON_ASSERT_SAFE(value, JSON_TEXT("null value to json_set_a"), value = EMPTY_CSTRING;); +	   *((JSONNode*)node) = json_string(value); +    } + +    void json_set_i(JSONNODE * node, long value){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_i"), return;); +	   *((JSONNode*)node) = value; +    } + +    void json_set_f(JSONNODE * node, json_number value){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_f"), return;); +	   *((JSONNode*)node) = value; +    } + +    void json_set_b(JSONNODE * node, int value){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_b"), return;); +	   *((JSONNode*)node) = (bool)value; +    } + +    void json_set_n(JSONNODE * node, const JSONNODE * orig){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_n"), return;); +	   JSON_ASSERT_SAFE(orig, JSON_TEXT("null node to json_set_n"), return;); +	   *((JSONNode*)node) = *((JSONNode*)orig); +    } + + +    //inspectors +    char json_type(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_type"), return JSON_NULL;); +	   return ((JSONNode*)node) -> type(); +    } + +    json_index_t json_size(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_size"), return 0;); +	   return ((JSONNode*)node) -> size(); +    } + +    int json_empty(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_empty"), return true;); +	   return (int)(((JSONNode*)node) -> empty()); +    } + +    json_char * json_name(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_name"), return toCString(EMPTY_CSTRING);); +	   return toCString(((JSONNode*)node) -> name()); +    } + +    #ifdef JSON_COMMENTS +	   json_char * json_get_comment(const JSONNODE * node){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_get_comment"), return toCString(EMPTY_CSTRING);); +		  return toCString(((JSONNode*)node) -> get_comment()); +	   } +    #endif + +    json_char * json_as_string(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_string"), return toCString(EMPTY_CSTRING);); +	   return toCString(((JSONNode*)node) -> as_string()); +    } + +    long json_as_int(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_int"), return 0;); +	   return ((JSONNode*)node) -> as_int(); +    } + +    json_number json_as_float(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_float"), return 0.0;); +	   return ((JSONNode*)node) -> as_float(); +    } + +    int json_as_bool(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_bool"), return false;); +	   return (int)(((JSONNode*)node) -> as_bool()); +    } + +    JSONNODE * json_as_node(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_node"), return 0;); +	   return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)node) -> as_node())); +    } + +    JSONNODE * json_as_array(const JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_array"), return 0;); +	   return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)node) -> as_array())); +    } + +    #ifdef JSON_BINARY +	   void * json_as_binary(const JSONNODE * node, unsigned long * size){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_binary"), if (size){*size = 0;} return 0;); +		  const std::string result = ((JSONNode*)node) -> as_binary(); +		  const size_t len = result.length(); +		  if (size) *size = len; +		  #ifdef JSON_SAFE +			 if (result.empty()) return 0; +		  #endif +		  #ifdef JSON_MEMORY_MANAGE +			 return StringHandler.insert(memcpy(json_malloc<char>(len), result.data(), len)); +		  #else +			 return memcpy(json_malloc<char>(len), result.data(), len); +		  #endif +	   } +    #endif + +    #ifdef JSON_WRITER +	   json_char * json_write(const JSONNODE * node){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_write"), return toCString(EMPTY_CSTRING);); +		  return toCString(((JSONNode*)node) -> write()); +	   } + +	   json_char * json_write_formatted(const JSONNODE * node){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_write_formatted"), return toCString(EMPTY_CSTRING);); +		  return toCString(((JSONNode*)node) -> write_formatted()); +	   } +    #endif + +    //modifiers +    void json_set_name(JSONNODE * node, const json_char * name){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_name"), return;); +	   JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_set_name"), name = EMPTY_CSTRING;); +	   ((JSONNode*)node) -> set_name(name); +    } + +    #ifdef JSON_COMMENTS +	   void json_set_comment(JSONNODE * node, const json_char * comment){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_comment"), return;); +		  JSON_ASSERT_SAFE(comment, JSON_TEXT("null name to json_set_comment"), comment = EMPTY_CSTRING;); +		  ((JSONNode*)node) -> set_comment(comment); +	   } +    #endif + +    void json_clear(JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_clear"), return;); +	   ((JSONNode*)node) -> clear(); +    } + +    void json_nullify(JSONNODE * node){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_nullify"), return;); +	   ((JSONNode*)node) -> nullify(); +    } + +    void json_swap(JSONNODE * node, JSONNODE * node2){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_swap"), return;); +	   JSON_ASSERT_SAFE(node2, JSON_TEXT("null node to json_swap"), return;); +	   ((JSONNode*)node) -> swap(*(JSONNode*)node2); +    } + +    void json_merge(JSONNODE * node, JSONNODE * node2){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_merge"), return;); +	   JSON_ASSERT_SAFE(node2, JSON_TEXT("null node to json_merge"), return;); +	   ((JSONNode*)node) -> merge(*(JSONNode*)node2); +    } + +    #ifndef JSON_PREPARSE +	   void json_preparse(JSONNODE * node){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_preparse"), return;); +		  ((JSONNode*)node) -> preparse(); +	   } +    #endif + +    #ifdef JSON_BINARY +	   void json_set_binary(JSONNODE * node, const void * data, unsigned long length){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_swap"), return;); +		  JSON_ASSERT_SAFE(data, JSON_TEXT("null data to json_set_binary"), *((JSONNode*)node) = EMPTY_CSTRING; return;); +		  ((JSONNode*)node) -> set_binary((unsigned char *)data, length); +	   } +    #endif + +    void json_cast(JSONNODE * node, char type){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_cast"), return;); +	   ((JSONNode*)node) -> cast(type); +    } + +    //children access +    void json_reserve(JSONNODE * node, json_index_t siz){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_reserve"), return;); +	   ((JSONNode*)node) -> reserve(siz); +    } + +    JSONNODE * json_at(JSONNODE * node, unsigned int pos){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_at"), return 0;); +	   try { +		  return &((JSONNode*)node) -> at(pos); +	   } catch (std::out_of_range){} +	   return 0; +    } + +    JSONNODE * json_get(JSONNODE * node, const json_char * name){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_get"), return 0;); +	   JSON_ASSERT_SAFE(name, JSON_TEXT("null node to json_get.  Did you mean to use json_at?"), return 0;); +	   try { +		  return &((JSONNode*)node) -> at(name); +	   } catch (std::out_of_range){} +	   return 0; +    } + + +	#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +	   JSONNODE * json_get_nocase(JSONNODE * node, const json_char * name){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_at_nocase"), return 0;); +		  JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_at_nocase"), return 0;); +		  try { +			 return &((JSONNode*)node) -> at_nocase(name); +		  } catch (std::out_of_range){} +		  return 0; +	   } + +	   JSONNODE * json_pop_back_nocase(JSONNODE * node, const json_char * name){ +		  JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back_nocase"), return 0;); +		  JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_pop_back_nocase"), return 0;); +		  return MANAGER_INSERT(((JSONNode*)node) -> pop_back_nocase(name)); +	   } +    #endif + +    void json_push_back(JSONNODE * node, JSONNODE * node2){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_push_back"), return;); +	   JSON_ASSERT_SAFE(node2, JSON_TEXT("null node2 to json_push_back"), return;); +	   #ifdef JSON_MEMORY_MANAGE +		  NodeHandler.remove(node2); +	   #endif +	   ((JSONNode*)node) -> push_back((JSONNode*)node2); +    } + +    JSONNODE * json_pop_back_at(JSONNODE * node, unsigned int pos){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back_i"), return 0;); +	   return MANAGER_INSERT(((JSONNode*)node) -> pop_back(pos)); +    } + +    JSONNODE * json_pop_back(JSONNODE * node, const json_char * name){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back"), return 0;); +	   JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_pop_back.  Did you mean to use json_pop_back_at?"), return 0;); +	   return MANAGER_INSERT(((JSONNode*)node) -> pop_back(name)); +    } +     +    #ifdef JSON_ITERATORS +	   JSONNODE_ITERATOR json_find(JSONNODE * node, const json_char * name){ +		  return (JSONNODE_ITERATOR)(((JSONNode*)node) -> find(name)); +	   } + +	   #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS +		  JSONNODE_ITERATOR json_find_nocase(JSONNODE * node, const json_char * name){ +			 return (JSONNODE_ITERATOR)(((JSONNode*)node) -> find_nocase(name)); +		  } +	   #endif + +	   JSONNODE_ITERATOR json_erase(JSONNODE * node, JSONNODE_ITERATOR it){ +		  return (JSONNODE_ITERATOR)(((JSONNode*)node) -> erase((JSONNode**)it)); +	   } + +	   JSONNODE_ITERATOR json_erase_multi(JSONNODE * node, JSONNODE_ITERATOR start, JSONNODE_ITERATOR end){ +		  return (JSONNODE_ITERATOR)(((JSONNode*)node) -> erase((JSONNode**)start, (JSONNode**)end)); +	   } + +	   JSONNODE_ITERATOR json_insert(JSONNODE * node, JSONNODE_ITERATOR it, JSONNODE * node2){ +		  #ifdef JSON_MEMORY_MANAGE +			 NodeHandler.remove(node2); +		  #endif +		  return (JSONNODE_ITERATOR)(((JSONNode*)node) -> insert((JSONNode**)it, (JSONNode*)node2)); +	   } + +	   JSONNODE_ITERATOR json_insert_multi(JSONNODE * node, JSONNODE_ITERATOR it, JSONNODE_ITERATOR start, JSONNODE_ITERATOR end){ +		  return (JSONNODE_ITERATOR)(((JSONNode*)node) -> insert((JSONNode**)it, (JSONNode**)start, (JSONNode**)end)); +	   } + +	   //iterator functions +	   JSONNODE_ITERATOR json_begin(JSONNODE * node){ +		  return (JSONNODE_ITERATOR)(((JSONNode*)node) -> begin()); +	   } +	    +	   JSONNODE_ITERATOR json_end(JSONNODE * node){ +		  return (JSONNODE_ITERATOR)(((JSONNode*)node) -> end()); +	   } +    #endif + +    //comparison +    int json_equal(JSONNODE * node, JSONNODE * node2){ +	   JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_equal"), return false;); +	   JSON_ASSERT_SAFE(node2, JSON_TEXT("null node2 to json_equal"), return false;); +	   return (int)(*((JSONNode*)node) == *((JSONNode*)node2)); +    } + +#endif //JSON_LIBRARY  | 
