From d3a54e309c8c6335a5d6384d3e239bd7bc9390f6 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Mon, 17 Dec 2012 14:19:09 +0000 Subject: cleanup git-svn-id: http://svn.miranda-ng.org/main/trunk@2757 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/json/JSONNode.h | 1502 +++++++++++++++++------------------ src/modules/json/JSONNode_Mutex.cpp | 431 +++++----- src/modules/json/JSONOptions.h | 404 +++++----- src/modules/json/JSONWorker.cpp | 1398 ++++++++++++++++---------------- src/modules/json/JSONWorker.h | 92 +-- src/modules/json/JSONWriter.cpp | 346 ++++---- src/modules/json/NumberToString.h | 208 ++--- src/modules/json/libJSON.cpp | 1011 ++++++++++++----------- src/modules/json/libJSON.h | 423 +++++----- 9 files changed, 2857 insertions(+), 2958 deletions(-) (limited to 'src') diff --git a/src/modules/json/JSONNode.h b/src/modules/json/JSONNode.h index 051475e704..2d36c5232b 100644 --- a/src/modules/json/JSONNode.h +++ b/src/modules/json/JSONNode.h @@ -7,917 +7,847 @@ #include //for the ... parameter #ifdef JSON_BINARY - #include "JSON_Base64.h" + #include "JSON_Base64.h" #endif #ifndef JSON_REF_COUNT - #define makeUniqueInternal() (void)0 + #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 + #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 + #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) - + #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) - + #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) - + 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. + 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(*it[pos]); }; - inline const JSONNode& operator *(void) const { return const_cast(*(*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(*it[pos]); }; - inline const JSONNode& operator *(void) const { return const_cast(*(*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); + 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(*it[pos]); }; + inline const JSONNode& operator *(void) const { return const_cast(*(*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(*it[pos]); }; + inline const JSONNode& operator *(void) const { return const_cast(*(*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; + 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. + 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(); + 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(); + 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(); + orig.internal = 0; + incAllocCount(); } - inline JSONNode::~JSONNode(void){ - if (internal) decRef(); - decAllocCount(); + if (internal) decRef(); + decAllocCount(); } - inline json_index_t JSONNode::size(void) const { - JSON_CHECK_INTERNAL(); - return internal -> size(); + JSON_CHECK_INTERNAL(); + return internal -> size(); } - inline bool JSONNode::empty(void) const { - JSON_CHECK_INTERNAL(); - return internal -> empty(); + JSON_CHECK_INTERNAL(); + return internal -> empty(); } - inline void JSONNode::clear(void){ - JSON_CHECK_INTERNAL(); - if (!empty()) { - makeUniqueInternal(); - internal -> Children.clear(); - } + JSON_CHECK_INTERNAL(); + if (!empty()) { + makeUniqueInternal(); + internal -> Children.clear(); + } } - inline unsigned char JSONNode::type(void) const { - JSON_CHECK_INTERNAL(); - return internal -> type(); + JSON_CHECK_INTERNAL(); + return internal -> type(); } - inline json_string JSONNode::name(void) const { - JSON_CHECK_INTERNAL(); - return internal -> name(); + JSON_CHECK_INTERNAL(); + return internal -> name(); } - inline void JSONNode::set_name(const json_string & newname){ - JSON_CHECK_INTERNAL(); - makeUniqueInternal(); - internal -> setname(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(); - } + 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(); + JSON_CHECK_INTERNAL(); + return internal -> as_string(); } - inline long JSONNode::as_int(void) const { - JSON_CHECK_INTERNAL(); - return internal -> as_int(); + JSON_CHECK_INTERNAL(); + return internal -> as_int(); } - inline json_number JSONNode::as_float(void) const { - JSON_CHECK_INTERNAL(); - return internal -> as_float(); + JSON_CHECK_INTERNAL(); + return internal -> as_float(); } - inline bool JSONNode::as_bool(void) const { - JSON_CHECK_INTERNAL(); - return internal -> as_bool(); + 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()); - } + 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))); + 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))); + 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); + JSON_CHECK_INTERNAL(); + makeUniqueInternal(); + internal -> push_back(child); } - + inline void JSONNode::reserve(json_index_t size){ - makeUniqueInternal(); - internal -> reserve(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; + 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; - } + 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;\ - } +#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 + This section is the equality operators */ - #define NODE_CHECK_EQUALITY(type)\ - inline bool JSONNode::operator == (type val) const {\ - JSON_CHECK_INTERNAL();\ - return internal -> IsEqualToNum(val);\ - } - + inline bool JSONNode::operator == (type val) const {\ + JSON_CHECK_INTERNAL();\ + return internal -> IsEqualToNum(val);\ + } IMPLEMENT_FOR_ALL_NUMBERS(NODE_CHECK_EQUALITY) - inline bool JSONNode::operator == (const json_string & val) const { - JSON_CHECK_INTERNAL(); - return internal -> IsEqualTo(val); + 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); - } + 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); + JSON_CHECK_INTERNAL(); + return internal -> IsEqualTo(val); } inline bool JSONNode::operator == (const JSONNode & val) const { - JSON_CHECK_INTERNAL(); - return internal -> IsEqualTo(val.internal); + JSON_CHECK_INTERNAL(); + return internal -> IsEqualTo(val.internal); } - /* - This section is the inequality operators + This section is the inequality operators */ - #define NODE_CHECK_INEQUALITY(type)\ - inline bool JSONNode::operator != (type val) const {\ - JSON_CHECK_INTERNAL();\ - return !(*this == val);\ - } - + 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 * ) + NODE_CHECK_INEQUALITY(const json_char * ) #endif - + inline void JSONNode::nullify(void){ - JSON_CHECK_INTERNAL(); - makeUniqueInternal(); - internal -> Nullify(); + 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(); + 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 + 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 - } + 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)); - } + 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); - } - + 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(); - } + 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(); - } + 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 + #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(ptr); - #else - delete ptr; - #endif + #ifdef JSON_MEMORY_CALLBACKS + ptr -> ~JSONNode(); + libjson_free(ptr); + #else + delete ptr; + #endif } - inline JSONNode * _newJSONNode(const JSONNode & orig){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) JSONNode(orig); - #else - return new JSONNode(orig); - #endif + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(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(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(1)) JSONNode(internal_t); - #else - return new JSONNode(internal_t); - #endif + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(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(1)) JSONNode(true, const_cast(orig)); - #else - return new JSONNode(true, const_cast(orig)); - #endif + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) JSONNode(true, const_cast(orig)); + #else + return new JSONNode(true, const_cast(orig)); + #endif } #endif diff --git a/src/modules/json/JSONNode_Mutex.cpp b/src/modules/json/JSONNode_Mutex.cpp index 2adb694ca8..77a9e90697 100644 --- a/src/modules/json/JSONNode_Mutex.cpp +++ b/src/modules/json/JSONNode_Mutex.cpp @@ -1,216 +1,215 @@ -/* - -Miranda IM: the free IM client for Microsoft* Windows* - -Copyright 2000-2009 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\..\core\commonheaders.h" -#include - -#include "libJSON.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 -#ifdef JSON_MUTEX_MANAGE - json_mutex_callback_t json_destroy = 0; - std::map 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 > 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 >::iterator it = threadlocks.find(thread); - if (it == threadlocks.end()) { - std::map newthread; - newthread[thislock] = 1; - threadlocks.insert(std::pair >(thread, newthread)); - } else { //this thread already has some things locked, check if the current mutex is - std::map & newthread = it -> second; - std::map::iterator locker = newthread.find(thislock); - if (locker == newthread.end()) { //current mutex is not locked, set it to locked - newthread.insert(std::pair(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 >::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 & newthread = it -> second; - std::map::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::iterator it = mutex_manager.find(mutex); - if (it == mutex_manager.end()) { - mutex_manager.insert(std::pair(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::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::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 +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\..\core\commonheaders.h" +#include + +#include "libJSON.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 +#ifdef JSON_MUTEX_MANAGE + json_mutex_callback_t json_destroy = 0; + std::map 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 > 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 >::iterator it = threadlocks.find(thread); + if (it == threadlocks.end()) { + std::map newthread; + newthread[thislock] = 1; + threadlocks.insert(std::pair >(thread, newthread)); + } else { //this thread already has some things locked, check if the current mutex is + std::map & newthread = it -> second; + std::map::iterator locker = newthread.find(thislock); + if (locker == newthread.end()) { //current mutex is not locked, set it to locked + newthread.insert(std::pair(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 >::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 & newthread = it -> second; + std::map::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::iterator it = mutex_manager.find(mutex); + if (it == mutex_manager.end()) { + mutex_manager.insert(std::pair(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::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::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/src/modules/json/JSONOptions.h b/src/modules/json/JSONOptions.h index 3c5bb8168f..29d588113a 100644 --- a/src/modules/json/JSONOptions.h +++ b/src/modules/json/JSONOptions.h @@ -1,214 +1,190 @@ -#ifndef JSON_OPTIONS_H -#define JSON_OPTIONS_H - -#define snprintf _snprintf - -/** - * This file holds all of the compiling options for easy access and so - * that you don't have to remember them, or look them up all the time - */ - - -/* - * JSON_LIBRARY must be declared if libjson is compiled as a static or dynamic - * library. This exposes a C-style interface, but none of the inner workings of libjson - */ -#define JSON_LIBRARY - - -/* - * JSON_DEBUG is used to perform extra error checking. Because libjson usually - * does on the fly parsing, validation is impossible, so this option will allow - * you to register an error callback so that you can record what is going wrong - * before the library crashes. This option does not protect from these errors, - * it simply tells you about them, which is nice for debugging, but not preferable - * for release candidates - */ -//#define JSON_DEBUG - - -/* - * JSON_SAFE performs similarly to JSON_DEBUG, except this option does protect - * from the errors that it encounters. This option is recommended for those who - * feel it's possible for their program to encounter invalid json. - */ -#define JSON_SAFE - - -/* - * JSON_STDERROR routes error messages to cerr instead of a callback, this - * option hides the callback registering function. This will usually display - * messages in the console - */ -//#define JSON_STDERROR - - -/* - * JSON_PREPARSE causes all parsing to be done immediately. By default, libjson - * parses nodes on the fly as they are needed, this makes parsing much faster if - * your program gets a lot of information that it doesn't need. An example of - * this would be a client application communicating with a server if the server - * returns things like last modified date and other things that you don't use. - */ -//#define JSON_PREPARSE - - -/* - * JSON_LESS_MEMORY will force libjson to let go of memory as quickly as it can - * this is recommended for software that has to run on less than optimal machines. - * It will cut libjson's memory usage by about 20%, but also run slightly slower. - * It's recommended that you also compile using the -Os option, as this will also - * reduce the size of the library - */ -//#define JSON_LESS_MEMORY - - -/* - * JSON_UNICODE tells libjson to use wstrings instead of regular strings, this - * means that libjson supports the full array of unicode characters, but also takes - * much more memory and processing power. - */ -//#define JSON_UNICODE - - -/* - * JSON_REF_COUNT causes libjson to reference count JSONNodes, which makes copying - * and passing them around much faster. It is recommended that this stay on for - * most uses - */ -#define JSON_REF_COUNT - - -/* - * JSON_BINARY is used to support binary, which is base64 encoded and decoded by libjson, - * if this option is not turned on, no base64 support is included - */ -//#define JSON_BINARY - - -/* - * JSON_MEMORY_CALLBACKS exposes functions to register callbacks for allocating, resizing, - * and freeing memory. Because libjson is designed for costomizability, it is feasible - * that some users would like to further add speed by having the library utilize a memory - * pool. With this option turned on, the default behavior is still done internally unless - * a callback is registered. So you can have this option on and mot use it. - */ -#define JSON_MEMORY_CALLBACKS - -/* - * JSON_MEMORY_MANAGE is used to create functionality to automatically track and clean - * up memory that has been allocated by the user. This includes strings, binary data, and - * nodes. It also exposes bulk delete functions. - */ -//#define JSON_MEMORY_MANAGE - - -/* - * JSON_MUTEX_CALLBACKS exposes functions to register callbacks to lock and unlock - * mutexs and functions to lock and unlock JSONNodes and all of it's children. This - * does not prevent other threads from accessing the node, but will prevent them from - * locking it. It is much easier for the end programmer to allow libjson to manage - * your mutexs because of reference counting and manipulating trees, libjson automatically - * tracks mutex controls for you, so you only ever lock what you need to - */ -//#define JSON_MUTEX_CALLBACKS - - -/* - * JSON_MUTEX_MANAGE lets you set mutexes and forget them, libjson will not only keep - * track of the mutex, but also keep a count of how many nodes are using it, and delete - * it when there are no more references - */ -//#define JSON_MUTEX_MANAGE - - -/* - * JSON_ISO_STRICT turns off all code that uses non-standard C++. This removes all - * references to long long and long double as well as a few others - */ -//#define JSON_ISO_STRICT - -/* - * JSON_ITERATORS turns on all of libjson's iterating functionality. This would usually - * only be turned off while compiling for use with C - */ -//#define JSON_ITERATORS - - -/* - * JSON_WRITER turns on libjson's writing capabilties. Without this libjson can only - * read and parse json, this allows it to write back out - */ -#define JSON_WRITER - - -/* - * JSON_NEWLINE affects how libjson writes. If this option is turned on, libjson - * will use whatever it's defined as for the newline signifier, otherwise, it will use - * standard unix \n. - */ -//#define JSON_NEWLINE "\r\n" //\r\n is standard for most windows and dos programs - - -/* - * JSON_COMMENTS tells libjson to store and write comments. libjson always supports - * parsing json that has comments in it as it simply ignores them, but with this option - * it keeps the comments and allows you to insert further comments - */ -//#define JSON_COMMENTS - - -/* - * JSON_INDENT affects how libjson writes. If this option is turned on, libjson - * will use \t to indent formatted json, otherwise it will use the number of characters - * that you specify. If this is not turned on, then it will use the tab (\t) character - */ -//#define JSON_INDENT " " - - -/* - * JSON_WRITE_BASH_COMMENTS will cause libjson to write all comments in bash (#) style - * if this option is not turned on, then it will use C-style comments. Bash comments are - * all single line - */ -//#define JSON_WRITE_BASH_COMMENTS - - -/* - * JSON_WRITE_SINGLE_LINE_COMMENTS will cause libjson to write all comments in using // - * notation, or (#) if that option is on. Some parsers do not support multiline C comments - * although, this option is not needed for bash comments, as they are all single line anyway - */ -//#define JSON_WRITE_SINGLE_LINE_COMMENTS - - -/* - * JSON_VALIDATE turns on validation features of libjson. This option requires JSON_SAFE - */ -//#define JSON_VALIDATE - - -/* - * JSON_CASE_INSENSITIVE_FUNCTIONS turns on funtions for finding child nodes in a case- - * insenititve way - */ -//#define JSON_CASE_INSENSITIVE_FUNCTIONS - - -/* - * JSON_UNIT_TEST is used to maintain and debug the libjson. It makes all private - * members and functions public so that tests can do checks of the inner workings - * of libjson. This should not be turned on by end users. - */ -//#define JSON_UNIT_TEST - - -/* - * JSON_INDEX_TYPE allows you th change the size type for the children functions. If this - * option is not used then unsigned int is used. This option is useful for cutting down - * on memory, or using huge numbers of child nodes (over 4 billion) - */ -//#define JSON_INDEX_TYPE unsigned int - -#endif - +#ifndef JSON_OPTIONS_H +#define JSON_OPTIONS_H + +#define snprintf _snprintf + +/** + * This file holds all of the compiling options for easy access and so + * that you don't have to remember them, or look them up all the time + */ + +/* + * JSON_LIBRARY must be declared if libjson is compiled as a static or dynamic + * library. This exposes a C-style interface, but none of the inner workings of libjson + */ +#define JSON_LIBRARY + +/* + * JSON_DEBUG is used to perform extra error checking. Because libjson usually + * does on the fly parsing, validation is impossible, so this option will allow + * you to register an error callback so that you can record what is going wrong + * before the library crashes. This option does not protect from these errors, + * it simply tells you about them, which is nice for debugging, but not preferable + * for release candidates + */ +//#define JSON_DEBUG + +/* + * JSON_SAFE performs similarly to JSON_DEBUG, except this option does protect + * from the errors that it encounters. This option is recommended for those who + * feel it's possible for their program to encounter invalid json. + */ +#define JSON_SAFE + +/* + * JSON_STDERROR routes error messages to cerr instead of a callback, this + * option hides the callback registering function. This will usually display + * messages in the console + */ +//#define JSON_STDERROR + +/* + * JSON_PREPARSE causes all parsing to be done immediately. By default, libjson + * parses nodes on the fly as they are needed, this makes parsing much faster if + * your program gets a lot of information that it doesn't need. An example of + * this would be a client application communicating with a server if the server + * returns things like last modified date and other things that you don't use. + */ +//#define JSON_PREPARSE + +/* + * JSON_LESS_MEMORY will force libjson to let go of memory as quickly as it can + * this is recommended for software that has to run on less than optimal machines. + * It will cut libjson's memory usage by about 20%, but also run slightly slower. + * It's recommended that you also compile using the -Os option, as this will also + * reduce the size of the library + */ +//#define JSON_LESS_MEMORY + +/* + * JSON_UNICODE tells libjson to use wstrings instead of regular strings, this + * means that libjson supports the full array of unicode characters, but also takes + * much more memory and processing power. + */ +//#define JSON_UNICODE + +/* + * JSON_REF_COUNT causes libjson to reference count JSONNodes, which makes copying + * and passing them around much faster. It is recommended that this stay on for + * most uses + */ +#define JSON_REF_COUNT + +/* + * JSON_BINARY is used to support binary, which is base64 encoded and decoded by libjson, + * if this option is not turned on, no base64 support is included + */ +//#define JSON_BINARY + +/* + * JSON_MEMORY_CALLBACKS exposes functions to register callbacks for allocating, resizing, + * and freeing memory. Because libjson is designed for costomizability, it is feasible + * that some users would like to further add speed by having the library utilize a memory + * pool. With this option turned on, the default behavior is still done internally unless + * a callback is registered. So you can have this option on and mot use it. + */ +#define JSON_MEMORY_CALLBACKS + +/* + * JSON_MEMORY_MANAGE is used to create functionality to automatically track and clean + * up memory that has been allocated by the user. This includes strings, binary data, and + * nodes. It also exposes bulk delete functions. + */ +//#define JSON_MEMORY_MANAGE + +/* + * JSON_MUTEX_CALLBACKS exposes functions to register callbacks to lock and unlock + * mutexs and functions to lock and unlock JSONNodes and all of it's children. This + * does not prevent other threads from accessing the node, but will prevent them from + * locking it. It is much easier for the end programmer to allow libjson to manage + * your mutexs because of reference counting and manipulating trees, libjson automatically + * tracks mutex controls for you, so you only ever lock what you need to + */ +//#define JSON_MUTEX_CALLBACKS + +/* + * JSON_MUTEX_MANAGE lets you set mutexes and forget them, libjson will not only keep + * track of the mutex, but also keep a count of how many nodes are using it, and delete + * it when there are no more references + */ +//#define JSON_MUTEX_MANAGE + +/* + * JSON_ISO_STRICT turns off all code that uses non-standard C++. This removes all + * references to long long and long double as well as a few others + */ +//#define JSON_ISO_STRICT + +/* + * JSON_ITERATORS turns on all of libjson's iterating functionality. This would usually + * only be turned off while compiling for use with C + */ +//#define JSON_ITERATORS + +/* + * JSON_WRITER turns on libjson's writing capabilties. Without this libjson can only + * read and parse json, this allows it to write back out + */ +#define JSON_WRITER + +/* + * JSON_NEWLINE affects how libjson writes. If this option is turned on, libjson + * will use whatever it's defined as for the newline signifier, otherwise, it will use + * standard unix \n. + */ +//#define JSON_NEWLINE "\r\n" //\r\n is standard for most windows and dos programs + +/* + * JSON_COMMENTS tells libjson to store and write comments. libjson always supports + * parsing json that has comments in it as it simply ignores them, but with this option + * it keeps the comments and allows you to insert further comments + */ +//#define JSON_COMMENTS + +/* + * JSON_INDENT affects how libjson writes. If this option is turned on, libjson + * will use \t to indent formatted json, otherwise it will use the number of characters + * that you specify. If this is not turned on, then it will use the tab (\t) character + */ +//#define JSON_INDENT " " + +/* + * JSON_WRITE_BASH_COMMENTS will cause libjson to write all comments in bash (#) style + * if this option is not turned on, then it will use C-style comments. Bash comments are + * all single line + */ +//#define JSON_WRITE_BASH_COMMENTS + +/* + * JSON_WRITE_SINGLE_LINE_COMMENTS will cause libjson to write all comments in using // + * notation, or (#) if that option is on. Some parsers do not support multiline C comments + * although, this option is not needed for bash comments, as they are all single line anyway + */ +//#define JSON_WRITE_SINGLE_LINE_COMMENTS + +/* + * JSON_VALIDATE turns on validation features of libjson. This option requires JSON_SAFE + */ +//#define JSON_VALIDATE + +/* + * JSON_CASE_INSENSITIVE_FUNCTIONS turns on funtions for finding child nodes in a case- + * insenititve way + */ +//#define JSON_CASE_INSENSITIVE_FUNCTIONS + +/* + * JSON_UNIT_TEST is used to maintain and debug the libjson. It makes all private + * members and functions public so that tests can do checks of the inner workings + * of libjson. This should not be turned on by end users. + */ +//#define JSON_UNIT_TEST + +/* + * JSON_INDEX_TYPE allows you th change the size type for the children functions. If this + * option is not used then unsigned int is used. This option is useful for cutting down + * on memory, or using huge numbers of child nodes (over 4 billion) + */ +//#define JSON_INDEX_TYPE unsigned int + +#endif diff --git a/src/modules/json/JSONWorker.cpp b/src/modules/json/JSONWorker.cpp index 488089345f..83ab246ee1 100644 --- a/src/modules/json/JSONWorker.cpp +++ b/src/modules/json/JSONWorker.cpp @@ -1,701 +1,697 @@ -/* - -Miranda IM: the free IM client for Microsoft* Windows* - -Copyright 2000-2009 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\..\core\commonheaders.h" - -#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 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(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((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); - JSON_ASSERT_SAFE((json_uchar)*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((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); - JSON_ASSERT_SAFE((json_uchar)*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 json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo){ - JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); - JSON_ASSERT(sizeof(json_uchar) == 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; - json_uchar first = UTF8(pos); - if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')) { - pos += 2; - json_uchar 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 - -json_uchar JSONWorker::UTF8(const json_char * & pos){ - #ifdef JSON_UNICODE - ++pos; - json_uchar 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 json_char szU8Buffer[10]; - -json_char* JSONWorker::UTF8_2(const json_char * & pos){ - #ifdef JSON_UNICODE - ++pos; - json_uchar 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 - json_uchar 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 - json_uchar 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 json_uchar top = ((json_uchar)(*(str++) - 48)); - const json_uchar middle = (json_uchar)(*(str++) - 48); - const json_uchar bottom = (json_uchar)(*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(json_uchar 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(json_uchar) == 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(json_uchar p){ - #ifdef JSON_UNICODE - if (p > 0xFFFF) return toSurrogatePair(p); - #endif - json_string res(JSON_TEXT("\\u")); - #ifdef JSON_UNICODE - json_uchar hihi = ((p & 0xF000) >> 12) + 48; - if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those - json_uchar 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; - json_uchar hi = ((p & 0x00F0) >> 4) + 48; - #else - res += JSON_TEXT("00"); - json_uchar 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 - json_uchar 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 (((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126)) { - //res += toUTF8((json_uchar)(*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(parent) -> Children.push_back(child); //attach it to the parent node - #else - const_cast(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); -} +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\..\core\commonheaders.h" + +#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 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(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((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); + JSON_ASSERT_SAFE((json_uchar)*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((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); + JSON_ASSERT_SAFE((json_uchar)*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 json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo){ + JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); + JSON_ASSERT(sizeof(json_uchar) == 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; + json_uchar first = UTF8(pos); + if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')) { + pos += 2; + json_uchar 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 + +json_uchar JSONWorker::UTF8(const json_char * & pos){ + #ifdef JSON_UNICODE + ++pos; + json_uchar 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 json_char szU8Buffer[10]; + +json_char* JSONWorker::UTF8_2(const json_char * & pos){ + #ifdef JSON_UNICODE + ++pos; + json_uchar 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 + json_uchar 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 + json_uchar 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 json_uchar top = ((json_uchar)(*(str++) - 48)); + const json_uchar middle = (json_uchar)(*(str++) - 48); + const json_uchar bottom = (json_uchar)(*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(json_uchar 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(json_uchar) == 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(json_uchar p){ + #ifdef JSON_UNICODE + if (p > 0xFFFF) return toSurrogatePair(p); + #endif + json_string res(JSON_TEXT("\\u")); + #ifdef JSON_UNICODE + json_uchar hihi = ((p & 0xF000) >> 12) + 48; + if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those + json_uchar 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; + json_uchar hi = ((p & 0x00F0) >> 4) + 48; + #else + res += JSON_TEXT("00"); + json_uchar 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 + json_uchar 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 (((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126)) { + //res += toUTF8((json_uchar)(*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(parent) -> Children.push_back(child); //attach it to the parent node + #else + const_cast(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/src/modules/json/JSONWorker.h b/src/modules/json/JSONWorker.h index 91a4f6d8c4..f425e12e86 100644 --- a/src/modules/json/JSONWorker.h +++ b/src/modules/json/JSONWorker.h @@ -1,46 +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 json_uchar UTF8(const json_char * & pos); - static json_char* UTF8_2(const json_char * & pos); - static json_string toUTF8(json_uchar p); - #ifdef JSON_UNICODE - static json_string UTF(const json_char * & pos); - static json_string toSurrogatePair(json_uchar 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 +#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 json_uchar UTF8(const json_char * & pos); + static json_char* UTF8_2(const json_char * & pos); + static json_string toUTF8(json_uchar p); + #ifdef JSON_UNICODE + static json_string UTF(const json_char * & pos); + static json_string toSurrogatePair(json_uchar 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/src/modules/json/JSONWriter.cpp b/src/modules/json/JSONWriter.cpp index 550a03dadd..d141a00a01 100644 --- a/src/modules/json/JSONWriter.cpp +++ b/src/modules/json/JSONWriter.cpp @@ -1,173 +1,173 @@ -/* - -Miranda IM: the free IM client for Microsoft* Windows* - -Copyright 2000-2009 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\..\core\commonheaders.h" - -#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 +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\..\core\commonheaders.h" + +#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/src/modules/json/NumberToString.h b/src/modules/json/NumberToString.h index 35c6c98d0a..cf81f2ef22 100644 --- a/src/modules/json/NumberToString.h +++ b/src/modules/json/NumberToString.h @@ -1,104 +1,104 @@ -#ifndef NUMBERTOSTRING_H -#define NUMBERTOSTRING_H - -#include "JSONDebug.h" -#include "JSONMemory.h" -#include - -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 - static json_string _itoa(T val, unsigned int size){ - long value = (long)val; - const unsigned int digits = getlen(size); - json_auto 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 - 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 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 - 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 +#ifndef NUMBERTOSTRING_H +#define NUMBERTOSTRING_H + +#include "JSONDebug.h" +#include "JSONMemory.h" +#include + +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 + static json_string _itoa(T val, unsigned int size){ + long value = (long)val; + const unsigned int digits = getlen(size); + json_auto 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 + 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 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 + 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/src/modules/json/libJSON.cpp b/src/modules/json/libJSON.cpp index 0312898299..a40dde4773 100644 --- a/src/modules/json/libJSON.cpp +++ b/src/modules/json/libJSON.cpp @@ -1,506 +1,505 @@ -/* - -Miranda IM: the free IM client for Microsoft* Windows* - -Copyright 2000-2009 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\..\core\commonheaders.h" - -#include "libJSON.h" - -/* - 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 -*/ - -#ifdef JSON_LIBRARY - - #include "JSONNode.h" - #include "JSONWorker.h" - #include //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(len), str.c_str(), len)); - #else - return (json_char *)memcpy(json_malloc(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(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(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(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(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(1)) JSONNode(name, value != 0 )); - #else - return MANAGER_INSERT(new JSONNode(name, (bool)value)) != 0; - #endif - } - - JSONNODE * json_new(char type){ - #ifdef JSON_MEMORY_CALLBACKS - return MANAGER_INSERT(new(json_malloc(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(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) = value != 0; - } - - 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(len), result.data(), len)); - #else - return memcpy(json_malloc(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 +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\..\core\commonheaders.h" + +#include "libJSON.h" + +/* + 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 +*/ + +#ifdef JSON_LIBRARY + + #include "JSONNode.h" + #include "JSONWorker.h" + #include //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(len), str.c_str(), len)); + #else + return (json_char *)memcpy(json_malloc(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(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(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(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(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(1)) JSONNode(name, value != 0 )); + #else + return MANAGER_INSERT(new JSONNode(name, (bool)value)) != 0; + #endif + } + + JSONNODE * json_new(char type){ + #ifdef JSON_MEMORY_CALLBACKS + return MANAGER_INSERT(new(json_malloc(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(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) = value != 0; + } + + 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(len), result.data(), len)); + #else + return memcpy(json_malloc(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 diff --git a/src/modules/json/libJSON.h b/src/modules/json/libJSON.h index 3e60fd502a..d552e71720 100644 --- a/src/modules/json/libJSON.h +++ b/src/modules/json/libJSON.h @@ -1,212 +1,211 @@ -#ifndef LIBJSON_H -#define LIBJSON_H - -#include "JSONDefs.h" //for typedefs of functions, strings, and nodes - -#ifdef _STATIC -#define LIBJSON_DLL -#elif LIBJSON_EXPORTS -#define LIBJSON_DLL _declspec(dllexport) -#else -#define LIBJSON_DLL _declspec(dllimport) -#endif - -/* - This is the C interface to libJSON. - - This file also declares various things that are needed for - C++ programming -*/ - -#ifdef JSON_LIBRARY //compiling the library, hide the interface - #ifdef __cplusplus - #ifdef JSON_UNIT_TEST - #include "JSONNode.h" - #endif - extern "C" { - #endif - - /* - stuff that's in namespace libJSON - */ - LIBJSON_DLL void json_free(void * str); - LIBJSON_DLL void json_delete(JSONNODE * node); - #ifdef JSON_MEMORY_MANAGE - LIBJSON_DLL void json_free_all(void); - LIBJSON_DLL void json_delete_all(void); - #endif - LIBJSON_DLL JSONNODE * json_parse(const json_char * json); - LIBJSON_DLL json_char * json_strip_white_space(const json_char * json); - #ifdef JSON_VALIDATE - LIBJSON_DLL JSONNODE * json_validate(const json_char * json); - #endif - #if defined JSON_DEBUG && !defined JSON_STDERROR - //When libjson errors, a callback allows the user to know what went wrong - LIBJSON_DLL void json_register_debug_callback(json_error_callback_t callback); - #endif - #ifdef JSON_MUTEX_CALLBACKS - #ifdef JSON_MUTEX_MANAGE - LIBJSON_DLL void json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, json_mutex_callback_t destroy, void * manager_lock); - #else - LIBJSON_DLL void json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock); - #endif - LIBJSON_DLL void json_set_global_mutex(void * mutex); - LIBJSON_DLL void json_set_mutex(JSONNODE * node, void * mutex); - LIBJSON_DLL void json_lock(JSONNODE * node, int threadid); - LIBJSON_DLL void json_unlock(JSONNODE * node, int threadid); - #endif - #ifdef JSON_MEMORY_CALLBACKS - LIBJSON_DLL void json_register_memory_callbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre); - #endif - - - /* - stuff that's in class JSONNode - */ - //ctors - LIBJSON_DLL JSONNODE * json_new_a(const json_char * name, const json_char * value); - LIBJSON_DLL JSONNODE * json_new_i(const json_char * name, long value); - LIBJSON_DLL JSONNODE * json_new_f(const json_char * name, json_number value); - LIBJSON_DLL JSONNODE * json_new_b(const json_char * name, int value); //because C bools are ints and C++ will implicitly cast it - LIBJSON_DLL JSONNODE * json_new(char type); - LIBJSON_DLL JSONNODE * json_copy(const JSONNODE * orig); - LIBJSON_DLL JSONNODE * json_duplicate(const JSONNODE * orig); - - //assignment - LIBJSON_DLL void json_set_a(JSONNODE * node, const json_char * value); - LIBJSON_DLL void json_set_i(JSONNODE * node, long value); - LIBJSON_DLL void json_set_f(JSONNODE * node, json_number value); - LIBJSON_DLL void json_set_b(JSONNODE * node, int value); //because C bools are ints ane C++ will implicit - LIBJSON_DLL void json_set_n(JSONNODE * node, const JSONNODE * orig); - - //inspectors - LIBJSON_DLL char json_type(const JSONNODE * node); - LIBJSON_DLL json_index_t json_size(const JSONNODE * node); - LIBJSON_DLL int json_empty(const JSONNODE * node); - LIBJSON_DLL json_char * json_name(const JSONNODE * node); - #ifdef JSON_COMMENTS - LIBJSON_DLL json_char * json_get_comment(const JSONNODE * node); - #endif - LIBJSON_DLL json_char * json_as_string(const JSONNODE * node); - LIBJSON_DLL long json_as_int(const JSONNODE * node); - LIBJSON_DLL json_number json_as_float(const JSONNODE * node); - LIBJSON_DLL int json_as_bool(const JSONNODE * node); - LIBJSON_DLL JSONNODE * json_as_node(const JSONNODE * node); - LIBJSON_DLL JSONNODE * json_as_array(const JSONNODE * node); - #ifdef JSON_BINARY - LIBJSON_DLL void * json_as_binary(const JSONNODE * node, unsigned long * size); - #endif - #ifdef JSON_WRITER - LIBJSON_DLL json_char * json_write(const JSONNODE * node); - LIBJSON_DLL json_char * json_write_formatted(const JSONNODE * node); - #endif - - //modifiers - LIBJSON_DLL void json_set_name(JSONNODE * node, const json_char * name); - #ifdef JSON_COMMENTS - LIBJSON_DLL void json_set_comment(JSONNODE * node, const json_char * comment); - #endif - LIBJSON_DLL void json_clear(JSONNODE * node); - LIBJSON_DLL void json_nullify(JSONNODE * node); - LIBJSON_DLL void json_swap(JSONNODE * node, JSONNODE * node2); - LIBJSON_DLL void json_merge(JSONNODE * node, JSONNODE * node2); - #ifndef JSON_PREPARSE - LIBJSON_DLL void json_preparse(JSONNODE * node); - #endif - #ifdef JSON_BINARY - LIBJSON_DLL void json_set_binary(JSONNODE * node, const void * data, unsigned long length); - #endif - LIBJSON_DLL void json_cast(JSONNODE * node, char type); - - //children access - LIBJSON_DLL void json_reserve(JSONNODE * node, json_index_t siz); - LIBJSON_DLL JSONNODE * json_at(JSONNODE * node, json_index_t pos); - LIBJSON_DLL JSONNODE * json_get(JSONNODE * node, const json_char * name); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - LIBJSON_DLL JSONNODE * json_get_nocase(JSONNODE * node, const json_char * name); - LIBJSON_DLL JSONNODE * json_pop_back_nocase(JSONNODE * node, const json_char * name); - #endif - LIBJSON_DLL void json_push_back(JSONNODE * node, JSONNODE * node2); - LIBJSON_DLL JSONNODE * json_pop_back_at(JSONNODE * node, json_index_t pos); - LIBJSON_DLL JSONNODE * json_pop_back(JSONNODE * node, const json_char * name); - #ifdef JSON_ITERATORS - LIBJSON_DLL JSONNODE_ITERATOR json_find(JSONNODE * node, const json_char * name); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - LIBJSON_DLL JSONNODE_ITERATOR json_find_nocase(JSONNODE * node, const json_char * name); - #endif - LIBJSON_DLL JSONNODE_ITERATOR json_erase(JSONNODE * node, JSONNODE_ITERATOR it); - LIBJSON_DLL JSONNODE_ITERATOR json_erase_multi(JSONNODE * node, JSONNODE_ITERATOR start, JSONNODE_ITERATOR end); - LIBJSON_DLL JSONNODE_ITERATOR json_insert(JSONNODE * node, JSONNODE_ITERATOR it, JSONNODE * node2); - LIBJSON_DLL JSONNODE_ITERATOR json_insert_multi(JSONNODE * node, JSONNODE_ITERATOR it, JSONNODE_ITERATOR start, JSONNODE_ITERATOR end); - - //iterator functions - LIBJSON_DLL JSONNODE_ITERATOR json_begin(JSONNODE * node); - LIBJSON_DLL JSONNODE_ITERATOR json_end(JSONNODE * node); - #endif - - //comparison - LIBJSON_DLL int json_equal(JSONNODE * node, JSONNODE * node2); - - #ifdef __cplusplus - } - #endif -#else - #ifndef __cplusplus - #error Using the non-library requires C++ - #endif - #include "JSONNode.h" //not used in this file, but libJSON.h should be the only file required to use it embedded - #include "JSONWorker.h" - #include //some methods throw exceptions - - namespace libJSON { - //if json is invalid, it throws a std::invalid_argument exception - inline static JSONNode parse(const json_string & json){ - return JSONWorker::parse(json); - } - - //useful if you have json that you don't want to parse, just want to strip to cut down on space - inline static json_string strip_white_space(const json_string & json){ - return JSONWorker::RemoveWhiteSpaceAndComments(json); - } - - //if json is invalid, it throws a std::invalid_argument exception (differs from parse because this checks the entire tree) - #ifdef JSON_VALIDATE - inline static JSONNode validate(const json_string & json){ - return JSONWorker::validate(json); - } - #endif - - //When libjson errors, a callback allows the user to know what went wrong - #if defined JSON_DEBUG && !defined JSON_STDERROR - inline static void register_debug_callback(json_error_callback_t callback){ - JSONDebug::register_callback(callback); - } - #endif - - #ifdef JSON_MUTEX_CALLBACKS - #ifdef JSON_MUTEX_MANAGE - inline static void 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 - inline static void 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 - - inline static void set_global_mutex(void * mutex){ - JSONNode::set_global_mutex(mutex); - } - #endif - - #ifdef JSON_MEMORY_CALLBACKS - inline static void register_memory_callbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre){ - JSONMemory::registerMemoryCallbacks(mal, real, fre); - } - #endif - - } -#endif //JSON_LIBRARY - -#endif //LIBJSON_H +#ifndef LIBJSON_H +#define LIBJSON_H + +#include "JSONDefs.h" //for typedefs of functions, strings, and nodes + +#ifdef _STATIC +#define LIBJSON_DLL +#elif LIBJSON_EXPORTS +#define LIBJSON_DLL _declspec(dllexport) +#else +#define LIBJSON_DLL _declspec(dllimport) +#endif + +/* + This is the C interface to libJSON. + + This file also declares various things that are needed for + C++ programming +*/ + +#ifdef JSON_LIBRARY //compiling the library, hide the interface + #ifdef __cplusplus + #ifdef JSON_UNIT_TEST + #include "JSONNode.h" + #endif + extern "C" { + #endif + + /* + stuff that's in namespace libJSON + */ + LIBJSON_DLL void json_free(void * str); + LIBJSON_DLL void json_delete(JSONNODE * node); + #ifdef JSON_MEMORY_MANAGE + LIBJSON_DLL void json_free_all(void); + LIBJSON_DLL void json_delete_all(void); + #endif + LIBJSON_DLL JSONNODE * json_parse(const json_char * json); + LIBJSON_DLL json_char * json_strip_white_space(const json_char * json); + #ifdef JSON_VALIDATE + LIBJSON_DLL JSONNODE * json_validate(const json_char * json); + #endif + #if defined JSON_DEBUG && !defined JSON_STDERROR + //When libjson errors, a callback allows the user to know what went wrong + LIBJSON_DLL void json_register_debug_callback(json_error_callback_t callback); + #endif + #ifdef JSON_MUTEX_CALLBACKS + #ifdef JSON_MUTEX_MANAGE + LIBJSON_DLL void json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, json_mutex_callback_t destroy, void * manager_lock); + #else + LIBJSON_DLL void json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock); + #endif + LIBJSON_DLL void json_set_global_mutex(void * mutex); + LIBJSON_DLL void json_set_mutex(JSONNODE * node, void * mutex); + LIBJSON_DLL void json_lock(JSONNODE * node, int threadid); + LIBJSON_DLL void json_unlock(JSONNODE * node, int threadid); + #endif + #ifdef JSON_MEMORY_CALLBACKS + LIBJSON_DLL void json_register_memory_callbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre); + #endif + + /* + stuff that's in class JSONNode + */ + //ctors + LIBJSON_DLL JSONNODE * json_new_a(const json_char * name, const json_char * value); + LIBJSON_DLL JSONNODE * json_new_i(const json_char * name, long value); + LIBJSON_DLL JSONNODE * json_new_f(const json_char * name, json_number value); + LIBJSON_DLL JSONNODE * json_new_b(const json_char * name, int value); //because C bools are ints and C++ will implicitly cast it + LIBJSON_DLL JSONNODE * json_new(char type); + LIBJSON_DLL JSONNODE * json_copy(const JSONNODE * orig); + LIBJSON_DLL JSONNODE * json_duplicate(const JSONNODE * orig); + + //assignment + LIBJSON_DLL void json_set_a(JSONNODE * node, const json_char * value); + LIBJSON_DLL void json_set_i(JSONNODE * node, long value); + LIBJSON_DLL void json_set_f(JSONNODE * node, json_number value); + LIBJSON_DLL void json_set_b(JSONNODE * node, int value); //because C bools are ints ane C++ will implicit + LIBJSON_DLL void json_set_n(JSONNODE * node, const JSONNODE * orig); + + //inspectors + LIBJSON_DLL char json_type(const JSONNODE * node); + LIBJSON_DLL json_index_t json_size(const JSONNODE * node); + LIBJSON_DLL int json_empty(const JSONNODE * node); + LIBJSON_DLL json_char * json_name(const JSONNODE * node); + #ifdef JSON_COMMENTS + LIBJSON_DLL json_char * json_get_comment(const JSONNODE * node); + #endif + LIBJSON_DLL json_char * json_as_string(const JSONNODE * node); + LIBJSON_DLL long json_as_int(const JSONNODE * node); + LIBJSON_DLL json_number json_as_float(const JSONNODE * node); + LIBJSON_DLL int json_as_bool(const JSONNODE * node); + LIBJSON_DLL JSONNODE * json_as_node(const JSONNODE * node); + LIBJSON_DLL JSONNODE * json_as_array(const JSONNODE * node); + #ifdef JSON_BINARY + LIBJSON_DLL void * json_as_binary(const JSONNODE * node, unsigned long * size); + #endif + #ifdef JSON_WRITER + LIBJSON_DLL json_char * json_write(const JSONNODE * node); + LIBJSON_DLL json_char * json_write_formatted(const JSONNODE * node); + #endif + + //modifiers + LIBJSON_DLL void json_set_name(JSONNODE * node, const json_char * name); + #ifdef JSON_COMMENTS + LIBJSON_DLL void json_set_comment(JSONNODE * node, const json_char * comment); + #endif + LIBJSON_DLL void json_clear(JSONNODE * node); + LIBJSON_DLL void json_nullify(JSONNODE * node); + LIBJSON_DLL void json_swap(JSONNODE * node, JSONNODE * node2); + LIBJSON_DLL void json_merge(JSONNODE * node, JSONNODE * node2); + #ifndef JSON_PREPARSE + LIBJSON_DLL void json_preparse(JSONNODE * node); + #endif + #ifdef JSON_BINARY + LIBJSON_DLL void json_set_binary(JSONNODE * node, const void * data, unsigned long length); + #endif + LIBJSON_DLL void json_cast(JSONNODE * node, char type); + + //children access + LIBJSON_DLL void json_reserve(JSONNODE * node, json_index_t siz); + LIBJSON_DLL JSONNODE * json_at(JSONNODE * node, json_index_t pos); + LIBJSON_DLL JSONNODE * json_get(JSONNODE * node, const json_char * name); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + LIBJSON_DLL JSONNODE * json_get_nocase(JSONNODE * node, const json_char * name); + LIBJSON_DLL JSONNODE * json_pop_back_nocase(JSONNODE * node, const json_char * name); + #endif + LIBJSON_DLL void json_push_back(JSONNODE * node, JSONNODE * node2); + LIBJSON_DLL JSONNODE * json_pop_back_at(JSONNODE * node, json_index_t pos); + LIBJSON_DLL JSONNODE * json_pop_back(JSONNODE * node, const json_char * name); + #ifdef JSON_ITERATORS + LIBJSON_DLL JSONNODE_ITERATOR json_find(JSONNODE * node, const json_char * name); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + LIBJSON_DLL JSONNODE_ITERATOR json_find_nocase(JSONNODE * node, const json_char * name); + #endif + LIBJSON_DLL JSONNODE_ITERATOR json_erase(JSONNODE * node, JSONNODE_ITERATOR it); + LIBJSON_DLL JSONNODE_ITERATOR json_erase_multi(JSONNODE * node, JSONNODE_ITERATOR start, JSONNODE_ITERATOR end); + LIBJSON_DLL JSONNODE_ITERATOR json_insert(JSONNODE * node, JSONNODE_ITERATOR it, JSONNODE * node2); + LIBJSON_DLL JSONNODE_ITERATOR json_insert_multi(JSONNODE * node, JSONNODE_ITERATOR it, JSONNODE_ITERATOR start, JSONNODE_ITERATOR end); + + //iterator functions + LIBJSON_DLL JSONNODE_ITERATOR json_begin(JSONNODE * node); + LIBJSON_DLL JSONNODE_ITERATOR json_end(JSONNODE * node); + #endif + + //comparison + LIBJSON_DLL int json_equal(JSONNODE * node, JSONNODE * node2); + + #ifdef __cplusplus + } + #endif +#else + #ifndef __cplusplus + #error Using the non-library requires C++ + #endif + #include "JSONNode.h" //not used in this file, but libJSON.h should be the only file required to use it embedded + #include "JSONWorker.h" + #include //some methods throw exceptions + + namespace libJSON { + //if json is invalid, it throws a std::invalid_argument exception + inline static JSONNode parse(const json_string & json){ + return JSONWorker::parse(json); + } + + //useful if you have json that you don't want to parse, just want to strip to cut down on space + inline static json_string strip_white_space(const json_string & json){ + return JSONWorker::RemoveWhiteSpaceAndComments(json); + } + + //if json is invalid, it throws a std::invalid_argument exception (differs from parse because this checks the entire tree) + #ifdef JSON_VALIDATE + inline static JSONNode validate(const json_string & json){ + return JSONWorker::validate(json); + } + #endif + + //When libjson errors, a callback allows the user to know what went wrong + #if defined JSON_DEBUG && !defined JSON_STDERROR + inline static void register_debug_callback(json_error_callback_t callback){ + JSONDebug::register_callback(callback); + } + #endif + + #ifdef JSON_MUTEX_CALLBACKS + #ifdef JSON_MUTEX_MANAGE + inline static void 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 + inline static void register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock){ + SONNode::register_mutex_callbacks(lock, unlock, manager_lock); + } + #endif + + inline static void set_global_mutex(void * mutex){ + JSONNode::set_global_mutex(mutex); + } + #endif + + #ifdef JSON_MEMORY_CALLBACKS + inline static void register_memory_callbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre){ + JSONMemory::registerMemoryCallbacks(mal, real, fre); + } + #endif + + } +#endif //JSON_LIBRARY + +#endif //LIBJSON_H -- cgit v1.2.3