-libjson added but not used. Initial code added in Worker

This commit is contained in:
Harry van Haaren 2013-08-22 03:47:06 +01:00
parent 2ffe57a0f5
commit f3596341ee
210 changed files with 43426 additions and 2 deletions

361
src/libjson/JSONOptions.h Normal file
View file

@ -0,0 +1,361 @@
#ifndef JSON_OPTIONS_H
#define JSON_OPTIONS_H
/**
* 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
#define NDEBUG
/*
* JSON_STRICT removes all of libjson's extensions. Meaning no comments, no special numbers
*/
//#define JSON_STRICT
/*
* 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_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_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 off, no base64 support is included
*/
#define JSON_BINARY
/*
* JSON_EXPOSE_BASE64 is used to turn on the functionality of libjson's base64 encoding
* and decoding. This may be useful if you want to obfuscate your json, or send binary data over
* a network
*/
#define JSON_EXPOSE_BASE64
/*
* 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_STREAM turns on libjson's streaming functionality. This allows you to give parts of
* your json into a stream, which will automatically hit a callback when full nodes are
* completed
*/
#define JSON_STREAM
/*
* JSON_MEMORY_CALLBACKS exposes functions to register callbacks for allocating, resizing,
* and freeing memory. Because libjson is designed for customizability, 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 not 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_MEMORY_POOL Turns on libjson's iteraction with mempool++. It is more efficient that simply
* connecting mempool++ to the callbacks because it integrates things internally and uses a number
* of memory pools. This value tells libjson how large of a memory pool to start out with. 500KB
* should suffice for most cases. libjson will distribute that within the pool for the best
* performance depending on other settings.
*/
//#define JSON_MEMORY_POOL 524288
/*
* 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_NO_C_CONSTS removes consts from the C interface. It still acts the same way, but
* this may be useful for using the header with languages or variants that don't have const
*/
//#define JSON_NO_C_CONSTS
/*
* JSON_OCTAL allows libjson to use octal values in numbers.
*/
//#define JSON_OCTAL
/*
* JSON_WRITE_PRIORITY turns on libjson's writing capabilties. Without this libjson can only
* read and parse json, this allows it to write back out. Changing the value of the writer
* changes how libjson compiles, and how fast it will go when writing
*/
#define JSON_WRITE_PRIORITY MED
/*
* JSON_READ_PRIORITY turns on libjson's reading capabilties. Changing the value of the reader
* changes how libjson compiles, and how fast it will go when writing
*/
#define JSON_READ_PRIORITY HIGH
/*
* 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_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_ESCAPE_WRITES tells the libjson engine to escape special characters when it writes
* out. If this option is turned off, the json it outputs may not adhere to JSON standards
*/
#define JSON_ESCAPE_WRITES
/*
* 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_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_ARRAY_SIZE_ON_ON_LINE allows you to put small arrays of primitives all on one line
* in a write_formatted. This is common for tuples, like coordinates. If must be defined
* as an integer
*/
//#define JSON_ARRAY_SIZE_ON_ONE_LINE 2
/*
* JSON_VALIDATE turns on validation features of libjson.
*/
#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_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
/*
* JSON_BOOL_TYPE lets you change the bool type for the C interface. Because before C99 there
* was no bool, and even then it's just a typedef, you may want to use something else. If this
* is not defined, it will revert to int
*/
//#define JSON_BOOL_TYPE char
/*
* JSON_INT_TYPE lets you change the int type for as_int. If you ommit this option, the default
* long will be used
*/
//#define JSON_INT_TYPE long
/*
* JSON_NUMBER_TYPE lets you change the number type for as_float as well as the internal storage for the
* number. If you omit this option, the default double will be used for most cases and float for JSON_LESS_MEMORY
*/
//#define JSON_NUMBER_TYPE double
/*
* JSON_STRING_HEADER allows you to change the type of string that libjson uses both for the
* interface and internally. It must implement most of the STL string interface, but not all
* of it. Things like wxString or QString should wourk without much trouble
*/
//#define JSON_STRING_HEADER "../TestSuite/StringTest.h"
/*
* 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_NO_EXCEPTIONS turns off any exception throwing by the library. It may still use exceptions
* internally, but the interface will never throw anything.
*/
//#define JSON_NO_EXCEPTIONS
/*
* JSON_DEPRECATED_FUNCTIONS turns on functions that have been deprecated, this is for backwards
* compatibility between major releases. It is highly recommended that you move your functions
* over to the new equivalents
*/
#define JSON_DEPRECATED_FUNCTIONS
/*
* JSON_CASTABLE allows you to call as_bool on a number and have it do the 0 or not 0 check,
* it also allows you to ask for a string from a number, or boolean, and have it return the right thing.
* Without this option, those types of requests are undefined. It also exposes the as_array, as_node, and cast
* functions
*/
#define JSON_CASTABLE
/*
* JSON_SECURITY_MAX_NEST_LEVEL is a security measure added to make prevent against DoS attacks
* This only affects validation, as if you are worried about security attacks, then you are
* most certainly validating json before sending it to be parsed. This option allows you to limitl how many
* levels deep a JSON Node can go. 128 is a good depth to start with
*/
#define JSON_SECURITY_MAX_NEST_LEVEL 128
/*
* JSON_SECURITY_MAX_STRING_LENGTH is another security measure, preventing DoS attacks with very long
* strings of JSON. 32MB is the default value for this, this allows large images to be embedded
*/
#define JSON_SECURITY_MAX_STRING_LENGTH 33554432
/*
* JSON_SECURITY_MAX_STREAM_OBJECTS is a security measure for streams. It prevents DoS attacks with
* large number of objects hitting the stream all at once. 128 is a lot of objects, but not out of
* the question for high speed systems.
*/
#define JSON_SECURITY_MAX_STREAM_OBJECTS 128
#endif

13
src/libjson/License.txt Normal file
View file

@ -0,0 +1,13 @@
This license is also available in Documentation.pdf
Copyright 2010 Jonathan Wallace. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY JONATHAN WALLACE ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JONATHAN WALLACE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Jonathan Wallace.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,270 @@
#ifndef LIBBASE64_CPP_H
#define LIBBASE64_CPP_H
#include <string>
//#define LIBBASE64_THROW_STD_INVALID_ARGUMENT
//version info
#define __LIBBASE64_MAJOR__ 1
#define __LIBBASE64_MINOR__ 1
#define __LIBBASE64_PATCH__ 0
#define __LIBBASE64_VERSION__ (__LIBBASE64_MAJOR__ * 10000 + __LIBBASE64_MINOR__ * 100 + __LIBBASE64_PATCH__)
//code coverage and asserts
#ifdef NDEBUG
#define LIBBASE64_ASSERT(cond, msg) (void)0
#define CREATEBOUNDCHECKER(type, name, ubound, lbound) (void)0
#define GETITEM_BOUNDCHECK(loc, name) (*(loc))
#else
#include <iostream>
#define LIBBASE64_ASSERT(cond, msg) if (!(cond)){ std::cerr << msg << std::endl; throw false; }
template<typename T>
class libbase64_boundChecker {
public:
libbase64_boundChecker(const T * lbound, const T * ubound) : upperbound(ubound), lowerbound(lbound){};
T getLocation(const T * loc){
LIBBASE64_ASSERT(loc < upperbound, "Array index above bounds");
LIBBASE64_ASSERT(loc >= lowerbound, "Array index below bounds");
return *loc;
}
private:
const T * lowerbound;
const T * upperbound;
};
#define CREATEBOUNDCHECKER(type, name, ubound, lbound) libbase64_boundChecker<type> name(ubound, lbound)
#define GETITEM_BOUNDCHECK(loc, name) name.getLocation(loc)
#ifdef LIBBASE64CODECOVERAGE
#define LIBBASE64CODECOVERAGEBRANCH { static bool f_codeCoverage_ = false; if (f_codeCoverage_ == false){ libbase64::getCoverageHits<STRINGTYPE, CHARTYPE, UCHARTYPE, SAFETY>(true); f_codeCoverage_ = true; } }
#endif
#endif
#ifndef LIBBASE64CODECOVERAGE
#define LIBBASE64CODECOVERAGEBRANCH (void)0
#endif
//predictive branching optimizations
#ifdef __GNUC__
#define LIBBASE64_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
#if (LIBBASE64_GCC_VERSION >= 29600)
#define libbase64_likely(x) __builtin_expect((long)((bool)(x)),1)
#define libbase64_unlikely(x) __builtin_expect((long)((bool)(x)),0)
#endif
#endif
#ifndef libbase64_likely
#define libbase64_likely(x) x
#define libbase64_unlikely(x) x
#endif
namespace libbase64 {
#ifdef LIBBASE64CODECOVERAGE //Gets the number of branches that has been made
template<class STRINGTYPE, typename CHARTYPE, typename UCHARTYPE, bool SAFETY>
static size_t getCoverageHits(bool inc){
static size_t hits = 0;
if (inc) ++hits;
return hits;
}
#endif
//characters used in convertions
namespace libbase64_characters {
template<typename T>
inline static const T * getChar64(void){
static const T char64s[64] = {
(T)'A', (T)'B', (T)'C', (T)'D', (T)'E', (T)'F', (T)'G', (T)'H', (T)'I', (T)'J', (T)'K', (T)'L', (T)'M',
(T)'N', (T)'O', (T)'P', (T)'Q', (T)'R', (T)'S', (T)'T', (T)'U', (T)'V', (T)'W', (T)'X', (T)'Y', (T)'Z',
(T)'a', (T)'b', (T)'c', (T)'d', (T)'e', (T)'f', (T)'g', (T)'h', (T)'i', (T)'j', (T)'k', (T)'l', (T)'m',
(T)'n', (T)'o', (T)'p', (T)'q', (T)'r', (T)'s', (T)'t', (T)'u', (T)'v', (T)'w', (T)'x', (T)'y', (T)'z',
(T)'0', (T)'1', (T)'2', (T)'3', (T)'4', (T)'5', (T)'6', (T)'7', (T)'8', (T)'9', (T)'+', (T)'/'
};
return char64s;
}
template<typename T>
inline static T getChar(unsigned char bin){
CREATEBOUNDCHECKER(T, char64bounds, getChar64<T>(), getChar64<T>() + 64);
return GETITEM_BOUNDCHECK(getChar64<T>() + bin, char64bounds);
}
template<typename T>
inline static T toBinary(T c) {
static T binaryConvert[80] = {62,48,49,50,63,52,53,54,55,56,57,58,59,60,61,249,250,251,252,253,254,255,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
CREATEBOUNDCHECKER(T, binaryConvertsbounds, binaryConvert, binaryConvert + 80);
return GETITEM_BOUNDCHECK(binaryConvert + c - 43, binaryConvertsbounds);
}
template<typename T>
static inline T & emptyString(void){
static T t;
return t;
}
}
namespace libbase64_Calculator {
inline static size_t getEncodingSize(size_t bytes){
return (bytes + 2 - ((bytes + 2) % 3)) / 3 * 4;
}
inline static size_t getDecodingSize(size_t res){
return res * 3 / 4;
}
}
/**
* Encodes data into a base64 string of STRINGTYPE
*/
template<class STRINGTYPE, typename CHARTYPE, typename UCHARTYPE, bool SAFETY>
static STRINGTYPE encode(const unsigned char * binary, size_t bytes){
CREATEBOUNDCHECKER(unsigned char, binarybounds, binary, binary + bytes);
//make sure that there is actually something to encode
if (SAFETY){
if (libbase64_unlikely(bytes == 0)){
LIBBASE64CODECOVERAGEBRANCH;
return libbase64_characters::emptyString<STRINGTYPE>();
}
}
//calculate length and how misaligned it is
size_t misaligned = bytes % 3;
STRINGTYPE result;
result.reserve(libbase64_Calculator::getEncodingSize(bytes));
//do all of the ones that are 3 byte aligned
for (size_t i = 0, aligned((bytes - misaligned) / 3); i < aligned; ++i){
LIBBASE64CODECOVERAGEBRANCH;
result += libbase64_characters::getChar<CHARTYPE>((GETITEM_BOUNDCHECK(binary, binarybounds) & 0xFC) >> 2);
result += libbase64_characters::getChar<CHARTYPE>(((GETITEM_BOUNDCHECK(binary, binarybounds) & 0x03) << 4) + ((GETITEM_BOUNDCHECK(binary + 1, binarybounds) & 0xF0) >> 4));
result += libbase64_characters::getChar<CHARTYPE>(((GETITEM_BOUNDCHECK(binary + 1, binarybounds) & 0x0F) << 2) + ((GETITEM_BOUNDCHECK(binary + 2, binarybounds) & 0xC0) >> 6));
result += libbase64_characters::getChar<CHARTYPE>(GETITEM_BOUNDCHECK(binary + 2, binarybounds) & 0x3F);
binary += 3;
}
//handle any additional characters at the end of it
if (libbase64_likely(misaligned != 0)){
LIBBASE64CODECOVERAGEBRANCH;
//copy the rest into a temporary buffer, need it for the null terminators
unsigned char temp[3] = { '\0', '\0', '\0' };
for (unsigned char i = 0; i < (unsigned char)misaligned; ++i){
LIBBASE64CODECOVERAGEBRANCH;
temp[i] = GETITEM_BOUNDCHECK(binary++, binarybounds);
}
//now do the final three bytes
result += libbase64_characters::getChar<CHARTYPE>((temp[0] & 0xFC) >> 2);
result += libbase64_characters::getChar<CHARTYPE>(((temp[0] & 0x03) << 4) + ((temp[1] & 0xF0) >> 4));
if (misaligned == 2){
LIBBASE64CODECOVERAGEBRANCH;
result += libbase64_characters::getChar<CHARTYPE>(((temp[1] & 0x0F) << 2) + ((temp[2] & 0xC0) >> 6));
} else {
LIBBASE64CODECOVERAGEBRANCH;
result += (CHARTYPE)'=';
}
result += (CHARTYPE)'=';
} else {
LIBBASE64CODECOVERAGEBRANCH;
}
LIBBASE64_ASSERT(libbase64_Calculator::getEncodingSize(bytes) == result.length(), "Reserve wasn't the correct guess");
return result;
}
template<class STRINGTYPE, typename CHARTYPE, typename UCHARTYPE, bool SAFETY>
static std::string decode(const STRINGTYPE & encoded){
//check length to be sure its acceptable for base64
const size_t length = encoded.length();
if (SAFETY){
if (libbase64_unlikely((length % 4) != 0)){
LIBBASE64CODECOVERAGEBRANCH;
return libbase64_characters::emptyString<std::string>();
}
if (libbase64_unlikely(length == 0)){
LIBBASE64CODECOVERAGEBRANCH;
return libbase64_characters::emptyString<std::string>();
}
//check to be sure there aren't odd characters or characters in the wrong places
size_t pos = encoded.find_first_not_of(libbase64_characters::getChar64<CHARTYPE>());
if (libbase64_unlikely(pos != STRINGTYPE::npos)){
LIBBASE64CODECOVERAGEBRANCH;
if (libbase64_unlikely(encoded[pos] != (CHARTYPE)'=')){
LIBBASE64CODECOVERAGEBRANCH; //INVALID_CHAR
#ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT
throw std::invalid_argument("invalid character in base64");
#else
return libbase64_characters::emptyString<std::string>();
#endif
}
if (pos != length - 1){
LIBBASE64CODECOVERAGEBRANCH;
if (libbase64_unlikely(pos != length - 2)){
LIBBASE64CODECOVERAGEBRANCH; //EQUAL_WRONG_PLACE
#ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT
throw std::invalid_argument("equal sign in wrong place in base64");
#else
return libbase64_characters::emptyString<std::string>();
#endif
}
if (libbase64_unlikely(encoded[pos + 1] != (CHARTYPE)'=')){
LIBBASE64CODECOVERAGEBRANCH; //EQUAL_NOT_LAST
#ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT
throw std::invalid_argument("invalid character in base64");
#else
return libbase64_characters::emptyString<std::string>();
#endif
}
LIBBASE64CODECOVERAGEBRANCH;
} else {
LIBBASE64CODECOVERAGEBRANCH;
}
} else {
LIBBASE64CODECOVERAGEBRANCH;
}
}
const CHARTYPE * runner = encoded.data();
const CHARTYPE * end = runner + encoded.length();
CREATEBOUNDCHECKER(CHARTYPE, encodedbounds, runner, end);
size_t aligned = length / 4; //don't do the last ones as they might be = padding
std::string result;
--aligned;
result.reserve(libbase64_Calculator::getDecodingSize(length));
//first do the ones that can not have any padding
for (unsigned int i = 0; i < aligned; ++i){
const CHARTYPE second = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 1, encodedbounds));
const CHARTYPE third = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 2, encodedbounds));
result += (libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner, encodedbounds)) << 2) + ((second & 0x30) >> 4);
result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2);
result += ((third & 0x3) << 6) + libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 3, encodedbounds));
runner += 4;
}
//now do the ones that might have padding, the first two characters can not be padding, so do them quickly
const CHARTYPE second = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 1, encodedbounds));
result += (libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 0, encodedbounds)) << 2) + ((second & 0x30) >> 4);
runner += 2;
if ((runner != end) && (*runner != (CHARTYPE)'=')){ //not two = pads
LIBBASE64CODECOVERAGEBRANCH;
const CHARTYPE third = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner, encodedbounds));
result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2);
++runner;
if ((runner != end) && (*runner != (CHARTYPE)'=')){ //no padding
LIBBASE64CODECOVERAGEBRANCH;
result += ((third & 0x3) << 6) + libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner, encodedbounds));
} else {
LIBBASE64CODECOVERAGEBRANCH;
}
} else {
LIBBASE64CODECOVERAGEBRANCH;
}
LIBBASE64_ASSERT(libbase64_Calculator::getDecodingSize(length) >= result.length(), "Reserve wasn't the correct guess, too small");
LIBBASE64_ASSERT((result.length() <= 3) || (libbase64_Calculator::getDecodingSize(length) > result.length() - 3), "Reserve wasn't the correct guess, too big");
return result;
}
}
#endif

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,13 @@
#include "JSONAllocator.h"
#if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL)
#include "JSONMemory.h"
void * JSONAllocatorRelayer::alloc(size_t bytes) json_nothrow {
return JSONMemory::json_malloc(bytes);
}
void JSONAllocatorRelayer::dealloc(void * ptr) json_nothrow {
JSONMemory::json_free(ptr);
}
#endif

View file

@ -0,0 +1,82 @@
#ifndef JSON_ALLOCATOR_H
#define JSON_ALLOCATOR_H
#include "JSONStats.h"
#if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL)
#include <cstddef>
//need these for the json_nothrow
#include "JSONDefs/Visual_C.h"
#include "JSONDefs/GNU_C.h"
#include "JSONDefs/Unknown_C.h"
class JSONAllocatorRelayer {
public:
static void * alloc(size_t bytes) json_nothrow json_hot;
static void dealloc(void * ptr) json_nothrow json_hot;
};
template <class T> class json_allocator;
// specialize for void:
template <> class json_allocator<void> {
public:
typedef void* pointer;
typedef const void* const_pointer;
// reference to void members are impossible.
typedef void value_type;
template <class U> struct rebind { typedef json_allocator<U> other; };
};
template <class T> class json_allocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef json_allocator<U> other; };
//LIBJSON_OBJECT(json_allocator);
inline json_allocator() json_nothrow {
//LIBJSON_CTOR;
}
inline json_allocator(const json_allocator&) json_nothrow {
//LIBJSON_COPY_CTOR;
}
template <class U> inline json_allocator(const json_allocator<U>&) json_nothrow {
//LIBJSON_COPY_CTOR;
}
inline ~json_allocator() json_nothrow {
//LIBJSON_DTOR;
}
inline pointer address(reference x) const { return &x; }
inline const_pointer address(const_reference x) const { return &x; }
inline pointer allocate(size_type n, json_allocator<void>::const_pointer = 0) json_hot {
return (pointer)JSONAllocatorRelayer::alloc(n * sizeof(T));
}
inline void deallocate(pointer p, size_type) json_hot {
JSONAllocatorRelayer::dealloc(p);
}
inline size_type max_size() const json_nothrow { return 0xEFFFFFFF; }
inline void construct(pointer p, const T& val){
new(p)T(val);
};
inline void destroy(pointer p){
((T*)p) -> ~T();
}
};
template <class T1, class T2> inline bool operator==(const json_allocator<T1>&, const json_allocator<T2>&) json_nothrow { return true; }
template <class T1, class T2> inline bool operator!=(const json_allocator<T1>&, const json_allocator<T2>&) json_nothrow { return false; }
#endif
#endif

View file

@ -0,0 +1,94 @@
#include "JSONChildren.h"
#include "JSONNode.h"
/*
* reserves a certain number of bytes, in memory saving mode it creates a special
* type of child container that will not autoshrink
*/
void jsonChildren::reserve2(jsonChildren *& mine, json_index_t amount) json_nothrow {
if (mine -> array != 0){
if (mine -> mycapacity < amount){
mine -> inc(amount - mine -> mycapacity);
#ifdef JSON_LESS_MEMORY
mine = jsonChildren_Reserved::newChildren_Reserved(mine, amount);
#endif
}
} else {
mine -> reserve(amount);
}
}
void jsonChildren::inc(void) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null inc"));
if (json_unlikely(mysize == mycapacity)){ //it's full
if (json_unlikely(mycapacity == 0)){ //the array hasn't been created yet
JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null"));
#ifdef JSON_LESS_MEMORY
array = json_malloc<JSONNode*>(1);
mycapacity = 1;
#else
array = json_malloc<JSONNode*>(8); //8 seems average for JSON, and it's only 64 bytes
mycapacity = 8;
#endif
} else {
#ifdef JSON_LESS_MEMORY
mycapacity += 1; //increment the size of the array
#else
mycapacity <<= 1; //double the size of the array
#endif
array = json_realloc<JSONNode*>(array, mycapacity);
}
}
}
void jsonChildren::inc(json_index_t amount) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null inc(amount)"));
if (json_unlikely(amount == 0)) return;
if (json_likely(mysize + amount >= mycapacity)){ //it's full
if (json_unlikely(mycapacity == 0)){ //the array hasn't been created yet
JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null"));
#ifdef JSON_LESS_MEMORY
array = json_malloc<JSONNode*>(amount);
mycapacity = amount;
#else
array = json_malloc<JSONNode*>(amount > 8 ? amount : 8); //8 seems average for JSON, and it's only 64 bytes
mycapacity = amount > 8 ? amount : 8;
#endif
} else {
#ifdef JSON_LESS_MEMORY
mycapacity = mysize + amount; //increment the size of the array
#else
while(mysize + amount > mycapacity){
mycapacity <<= 1; //double the size of the array
}
#endif
array = json_realloc<JSONNode*>(array, mycapacity);
}
}
}
//actually deletes everything within the vector, this is safe to do on an empty or even a null array
void jsonChildren::deleteAll(void) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null deleteAll"));
json_foreach(this, runner){
JSON_ASSERT(*runner != JSON_TEXT('\0'), JSON_TEXT("a null pointer within the children"));
JSONNode::deleteJSONNode(*runner); //this is why I can't do forward declaration
}
}
void jsonChildren::doerase(JSONNode ** position, json_index_t number) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null doerase"));
JSON_ASSERT(array != 0, JSON_TEXT("erasing something from a null array 2"));
JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 2"));
JSON_ASSERT(position + number <= array + mysize, JSON_TEXT("erasing out of bounds 2"));
if (position + number >= array + mysize){
mysize = (json_index_t)(position - array);
#ifndef JSON_ISO_STRICT
JSON_ASSERT((long long)position - (long long)array >= 0, JSON_TEXT("doing negative allocation"));
#endif
} else {
std::memmove(position, position + number, (mysize - (position - array) - number) * sizeof(JSONNode *));
mysize -= number;
}
}

View file

@ -0,0 +1,329 @@
#ifndef JSONCHILDREN_H
#define JSONCHILDREN_H
#include "JSONMemory.h"
#include "JSONDebug.h" //for JSON_ASSERT macro
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(push, 1)
#elif _MSC_VER
#pragma pack(push, jsonChildren, 1)
#endif
#endif
#define json_foreach(chldrn, itrtr)\
JSONNode ** itrtr = chldrn -> begin();\
for(JSONNode ** itrtr##_end = chldrn -> end(); itrtr != itrtr##_end; ++itrtr)
/*
This class is essentially a vector that has been heavily optimized for the specific purpose
of holding JSONNode children. It acts the same way as a vector, it has a automatically
expanding array. On destruction, this container automatically destroys everything contained
in it as well, so that you libjson doesn't have to do that.
T is JSONNode*, I can't define it that way directly because JSONNode uses this container, and because
the container deletes the children automatically, forward declaration can't be used
*/
class JSONNode; //forward declaration
#ifdef JSON_LESS_MEMORY
#define childrenVirtual virtual
#else
#define childrenVirtual
#endif
class jsonChildren {
public:
LIBJSON_OBJECT(jsonChildren);
//starts completely empty and the array is not allocated
jsonChildren(void) json_nothrow : array(0), mysize(0), mycapacity(0) {
LIBJSON_CTOR;
}
#ifdef JSON_LESS_MEMORY
jsonChildren(JSONNode** ar, json_index_t si, json_index_t ca) json_nothrow : array(ar), mysize(si), mycapacity(ca) {
LIBJSON_CTOR;
}
#endif
//deletes the array and everything that is contained within it (using delete)
childrenVirtual ~jsonChildren(void) json_nothrow {
if (json_unlikely(array != 0)){ //the following function calls are safe, but take more time than a check here
deleteAll();
libjson_free<JSONNode*>(array);
}
LIBJSON_DTOR;
}
//increase the size of the array
void inc(json_index_t amount) json_nothrow;
void inc(void) json_nothrow;
//Adds something to the vector, doubling the array if necessary
void push_back(JSONNode * item) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_back"));
inc();
array[mysize++] = item;
}
//Adds something to the front of the vector, doubling the array if necessary
void push_front(JSONNode * item) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_front"));
inc();
std::memmove(array + 1, array, mysize++ * sizeof(JSONNode *));
array[0] = item;
}
//gets an item out of the vector by it's position
inline JSONNode * operator[] (json_index_t position) const json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null []"));
JSON_ASSERT(position < mysize, JSON_TEXT("Using [] out of bounds"));
JSON_ASSERT(position < mycapacity, JSON_TEXT("Using [] out of bounds"));
JSON_ASSERT(array != 0, JSON_TEXT("Array is null"));
return array[position];
}
//returns the allocated capacity, but keep in mind that some might not be valid
inline json_index_t capacity() const json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null capacity"));
return mycapacity;
}
//returns the number of valid objects within the vector
inline json_index_t size() const json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null size"));
return mysize;
}
//tests whether or not the vector is empty
inline bool empty() const json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null empty"));
return mysize == 0;
}
//clears (and deletes) everything from the vector and sets it's size to 0
inline void clear() json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null clear"));
if (json_likely(array != 0)){ //don't bother clearing anything if there is nothing in it
JSON_ASSERT(mycapacity != 0, JSON_TEXT("mycapacity is not zero, but array is null"));
deleteAll();
mysize = 0;
}
JSON_ASSERT(mysize == 0, JSON_TEXT("mysize is not zero after clear"));
}
//returns the beginning of the array
inline JSONNode ** begin(void) const json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null begin"));
return array;
}
//returns the end of the array
inline JSONNode ** end(void) const json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null end"));
return array + mysize;
}
//makes sure that even after shirnking and expanding, the iterator is in same relative position
template <bool reverse>
struct iteratorKeeper {
public:
LIBJSON_OBJECT(jsonChildren::iteratorKeeper);
iteratorKeeper(jsonChildren * pthis, JSONNode ** & position) json_nothrow :
myRelativeOffset(reverse ? (json_index_t)(pthis -> array + (size_t)pthis -> mysize - position) : (json_index_t)(position - pthis -> array)),
myChildren(pthis),
myPos(position){
LIBJSON_CTOR;
}
~iteratorKeeper(void) json_nothrow {
LIBJSON_DTOR;
if (reverse){
myPos = myChildren -> array + myChildren -> mysize - myRelativeOffset;
} else {
myPos = myChildren -> array + myRelativeOffset;
}
}
private:
iteratorKeeper(const iteratorKeeper &);
iteratorKeeper & operator = (const iteratorKeeper &);
json_index_t myRelativeOffset;
jsonChildren * myChildren;
JSONNode ** & myPos;
};
//This function DOES NOT delete the item it points to
inline void erase(JSONNode ** & position) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase"));
JSON_ASSERT(array != 0, JSON_TEXT("erasing something from a null array 1"));
JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 1"));
JSON_ASSERT(position <= array + mysize, JSON_TEXT("erasing out of bounds 1"));
std::memmove(position, position + 1, (mysize-- - (position - array) - 1) * sizeof(JSONNode *));
iteratorKeeper<false> ik(this, position);
shrink();
}
//This function DOES NOT delete the item it points to
inline void erase(JSONNode ** & position, json_index_t number) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 2"));
doerase(position, number);
iteratorKeeper<false> ik(this, position);
shrink();
}
//This function DOES NOT delete the item it points to
inline void erase(JSONNode ** position, json_index_t number, JSONNode ** & starter) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 3"));
doerase(position, number);
iteratorKeeper<false> ik(this, starter);
shrink();
}
#ifdef JSON_LIBRARY
void insert(JSONNode ** & position, JSONNode * item) json_nothrow{
#else
void insert(JSONNode ** & position, JSONNode * item, bool reverse = false) json_nothrow {
#endif
JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert"));
//position isnt relative to array because of realloc
JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 1"));
JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 1"));
#ifndef JSON_LIBRARY
if (reverse){
iteratorKeeper<true> ik(this, position);
inc();
} else
#endif
{
iteratorKeeper<false> ik(this, position);
inc();
}
std::memmove(position + 1, position, (mysize++ - (position - array)) * sizeof(JSONNode *));
*position = item;
}
void insert(JSONNode ** & position, JSONNode ** items, json_index_t num) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert 2"));
JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 2"));
JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 2"));
{
iteratorKeeper<false> ik(this, position);
inc(num);
}
const size_t ptrs = ((JSONNode **)(array + mysize)) - position;
std::memmove(position + num, position, ptrs * sizeof(JSONNode *));
std::memcpy(position, items, num * sizeof(JSONNode *));
mysize += num;
}
inline void reserve(json_index_t amount) json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null reserve"));
JSON_ASSERT(array == 0, JSON_TEXT("reserve is not meant to expand a preexisting array"));
JSON_ASSERT(mycapacity == 0, JSON_TEXT("reservec is not meant to expand a preexisting array"));
JSON_ASSERT(mysize == 0, JSON_TEXT("reserves is not meant to expand a preexisting array"));
array = json_malloc<JSONNode*>(mycapacity = amount);
}
//it is static because mine might change pointers entirely
static void reserve2(jsonChildren *& mine, json_index_t amount) json_nothrow;
//shrinks the array to only as large as it needs to be to hold everything within it
inline childrenVirtual void shrink() json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink"));
if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array
libjson_free<JSONNode*>(array); //free does checks for a null pointer, so don't bother checking
array = 0;
#ifdef JSON_LESS_MEMORY
} else { //need to shrink it, using realloc
JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0"));
array = json_realloc<JSONNode*>(array, mysize);
#endif
}
mycapacity = mysize;
}
inline static void deleteChildren(jsonChildren * ptr) json_nothrow {
#ifdef JSON_MEMORY_CALLBACKS
ptr -> ~jsonChildren();
libjson_free<jsonChildren>(ptr);
#else
delete ptr;
#endif
}
inline static jsonChildren * newChildren(void) {
#ifdef JSON_MEMORY_CALLBACKS
return new(json_malloc<jsonChildren>(1)) jsonChildren();
#else
return new jsonChildren();
#endif
}
JSONNode ** array; //the expandable array
json_index_t mysize; //the number of valid items
json_index_t mycapacity; //the number of possible items
JSON_PROTECTED
//to make sure it's not copyable
jsonChildren(const jsonChildren &);
jsonChildren & operator = (const jsonChildren &);
void deleteAll(void) json_nothrow json_hot; //implemented in JSONNode.cpp
void doerase(JSONNode ** position, json_index_t number) json_nothrow;
};
#ifdef JSON_LESS_MEMORY
class jsonChildren_Reserved : public jsonChildren {
public:
LIBJSON_OBJECT(jsonChildren_Reserved);
jsonChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow : jsonChildren(orig -> array, orig -> mysize, orig -> mycapacity), myreserved(siz) {
orig -> array = 0;
deleteChildren(orig);
LIBJSON_CTOR;
}
jsonChildren_Reserved(const jsonChildren_Reserved & orig) json_nothrow : jsonChildren(orig.array, orig.mysize, orig.mycapacity), myreserved(orig.myreserved){
LIBJSON_COPY_CTOR;
}
inline virtual ~jsonChildren_Reserved() json_nothrow {
LIBJSON_DTOR;
};
inline virtual void shrink() json_nothrow {
JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink reserved"));
if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array
libjson_free<JSONNode*>(array); //free does checks for a null pointer, so don't bother checking
array = 0;
} else if (mysize > myreserved){
JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0"));
array = json_realloc<JSONNode*>(array, mysize);
}
}
#ifdef JSON_LESS_MEMORY
inline static jsonChildren * newChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow {
#ifdef JSON_MEMORY_CALLBACKS
return new(json_malloc<jsonChildren_Reserved>(1)) jsonChildren_Reserved(orig, siz);
#else
return new jsonChildren_Reserved(orig, siz);
#endif
}
#endif
JSON_PRIVATE
jsonChildren_Reserved & operator = (const jsonChildren_Reserved &);
json_index_t myreserved;
};
#endif
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(pop)
#elif _MSC_VER
#pragma pack(pop, jsonChildren)
#endif
#endif
#endif

View file

@ -0,0 +1,42 @@
#include "JSONDebug.h"
#ifdef JSON_DEBUG
#ifdef JSON_STDERROR
#include <iostream> //need std::cerr
#else
#include "JSONSingleton.h"
//otherwise, use a callback to tell the end user what happened
json_error_callback_t JSONDebug::register_callback(json_error_callback_t callback) json_nothrow {
json_error_callback_t res = JSONSingleton<json_error_callback_t>::get();
JSONSingleton<json_error_callback_t>::set(callback);
return res;
}
#endif
//Something went wrong or an assert failed
void JSONDebug::_JSON_FAIL(const json_string & msg) json_nothrow {
#ifdef JSON_STDERROR //no callback, just use stderror
#ifndef JSON_UNICODE
std::cerr << msg << std::endl;
#else
std::cerr << std::string(msg.begin(), msg.end()) << std::endl;
#endif
#else
if (json_error_callback_t ErrorCallback = JSONSingleton<json_error_callback_t>::get()){ //only do anything if the callback is registered
#ifdef JSON_LIBRARY
ErrorCallback(msg.c_str());
#else
ErrorCallback(msg);
#endif
}
#endif
}
//asserts that condition is true, more useful than cassert because it lets you keep going
void JSONDebug::_JSON_ASSERT(bool condition, const json_string & msg) json_nothrow {
if (json_unlikely(!condition)){
_JSON_FAIL(msg);
}
}
#endif

View file

@ -0,0 +1,59 @@
#ifndef LIBJSON_GUARD_DEBUG_H
#define LIBJSON_GUARD_DEBUG_H
#include "JSONDefs.h"
#include "JSONStats.h"
#ifdef JSON_DEBUG
#ifdef JSON_SAFE
#define JSON_ASSERT_SAFE(condition, msg, code)\
{\
if (json_unlikely(!(condition))){\
JSON_FAIL(msg);\
code\
}\
}
#define JSON_FAIL_SAFE(msg, code)\
{\
JSON_FAIL(msg);\
code\
}
#else
#define JSON_ASSERT_SAFE(condition, msg, code) JSON_ASSERT(condition, msg)
#define JSON_FAIL_SAFE(msg, code) JSON_FAIL(msg)
#endif
#define JSON_FAIL(msg) JSONDebug::_JSON_FAIL(msg)
#define JSON_ASSERT(bo, msg) JSONDebug::_JSON_ASSERT(bo, msg)
class JSONDebug {
public:
#ifndef JSON_STDERROR
static json_error_callback_t register_callback(json_error_callback_t callback) json_nothrow json_cold;
#endif
static void _JSON_FAIL(const json_string & msg) json_nothrow json_cold;
static void _JSON_ASSERT(bool condition, const json_string & msg) json_nothrow json_cold;
};
#else
#ifdef JSON_SAFE
#define JSON_ASSERT_SAFE(condition, msg, code)\
{\
if (json_unlikely(!(condition))){\
code\
}\
}
#define JSON_FAIL_SAFE(msg, code)\
{\
code\
}
#else
#define JSON_ASSERT_SAFE(condition, msg, code)
#define JSON_FAIL_SAFE(msg, code)
#endif
#define JSON_ASSERT(condition, msg)
#define JSON_FAIL(msg)
#endif
#endif

View file

@ -0,0 +1,184 @@
#ifndef JSONDEFS_H
#define JSONDEFS_H
/*
Defines all of the types of functions and various other definitions
that are used in C applications, this is very useful if dynamically loading
the library instead of linking.
*/
#include "../../JSONOptions.h"
#include "JSONDefs/Unknown_C.h"
#include "JSONDefs/GNU_C.h"
#include "JSONDefs/Visual_C.h"
#include "JSONDefs/Strings_Defs.h"
#define __LIBJSON_MAJOR__ 7
#define __LIBJSON_MINOR__ 6
#define __LIBJSON_PATCH__ 1
#define __LIBJSON_VERSION__ (__LIBJSON_MAJOR__ * 10000 + __LIBJSON_MINOR__ * 100 + __LIBJSON_PATCH__)
#define JSON_NULL '\0'
#define JSON_STRING '\1'
#define JSON_NUMBER '\2'
#define JSON_BOOL '\3'
#define JSON_ARRAY '\4'
#define JSON_NODE '\5'
#ifdef __cplusplus
#if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL)
#include "JSONAllocator.h"
#else
#define json_allocator std::allocator
#endif
#ifdef JSON_STRING_HEADER
#include JSON_STRING_HEADER
#else
typedef std::basic_string<json_char, std::char_traits<json_char>, json_allocator<json_char> > json_string;
#endif
#endif
#define JSON_MAP(x, y) std::map<x, y, std::less<x>, json_allocator<std::pair<const x, y> > >
#ifdef JSON_NO_EXCEPTIONS
#define json_throw(x)
#define json_try
#define json_catch(exception, code)
#else
#define json_throw(x) throw(x)
#define json_try try
#define json_catch(exception, code) catch(exception){ code }
#endif
#ifdef JSON_STRICT
#ifndef JSON_UNICODE
#error, JSON_UNICODE is required for JSON_STRICT
#endif
#ifdef JSON_COMMENTS
#error, JSON_COMMENTS is required to be off for JSON_STRICT
#endif
#endif
#ifdef JSON_ISO_STRICT
#ifdef JSON_UNICODE
#error, You can not use unicode under ANSI Strict C++
#endif
#else
#ifdef __GNUC__
#ifdef __STRICT_ANSI__
#warning, Using -ansi GCC option, but JSON_ISO_STRICT not on, turning it on for you
#define JSON_ISO_STRICT
#endif
#endif
#endif
#ifdef JSON_NUMBER_TYPE
typedef JSON_NUMBER_TYPE json_number;
#define JSON_FLOAT_THRESHHOLD 0.00001
#else
#ifdef JSON_LESS_MEMORY
typedef float json_number;
#define JSON_FLOAT_THRESHHOLD 0.00001f
#else
typedef double json_number;
#define JSON_FLOAT_THRESHHOLD 0.00001
#endif
#endif
#ifdef JSON_LESS_MEMORY
/* PACKED and BITS stored in compiler specific headers */
#define START_MEM_SCOPE {
#define END_MEM_SCOPE }
#else
#define PACKED(x)
#define BITS(x)
#define START_MEM_SCOPE
#define END_MEM_SCOPE
#endif
#if defined JSON_DEBUG || defined JSON_SAFE
#ifdef JSON_LIBRARY
typedef void (*json_error_callback_t)(const json_char *);
#else
typedef void (*json_error_callback_t)(const json_string &);
#endif
#endif
#ifdef JSON_INDEX_TYPE
typedef JSON_INDEX_TYPE json_index_t;
#else
typedef unsigned int json_index_t;
#endif
#ifdef JSON_BOOL_TYPE
typedef JSON_BOOL_TYPE json_bool_t;
#else
typedef int json_bool_t;
#endif
#ifdef JSON_INT_TYPE
typedef JSON_INT_TYPE json_int_t;
#else
typedef long json_int_t;
#endif
#define JSONSTREAM_SELF (void*)-1
typedef void (*json_stream_e_callback_t)(void * identifier);
typedef void (*json_mutex_callback_t)(void *);
typedef void (*json_free_t)(void *);
#ifndef JSON_LIBRARY
typedef void * (*json_malloc_t)(size_t);
typedef void * (*json_realloc_t)(void *, size_t);
#else
#define JSONNODE void /* so that JSONNODE* is void* */
typedef JSONNODE** JSONNODE_ITERATOR;
#ifdef JSON_STREAM
#define JSONSTREAM void
typedef void (*json_stream_callback_t)(JSONNODE *, void * identifier);
#endif
typedef void * (*json_malloc_t)(unsigned long);
typedef void * (*json_realloc_t)(void *, unsigned long);
#endif
#ifdef JSON_DEBUG
#ifdef NDEBUG
#ifdef __GNUC__
#warning, Have JSON_DEBUG on in a release build
#else
#error, Have JSON_DEBUG on in a release build
#endif
#endif
#else
#ifndef NDEBUG
#ifdef __GNUC__
#warning, Release build of libjson, but NDEBUG is not on
#else
#error, Release build of libjson, but NDEBUG is not on
#endif
#endif
#endif
#ifdef JSON_UNIT_TEST
#define JSON_PRIVATE public:
#define JSON_PROTECTED public:
#else
#define JSON_PRIVATE private:
#define JSON_PROTECTED protected:
#endif
#ifdef JSON_STREAM
#ifndef JSON_READ_PRIORITY
#error, JSON_STREAM also requires JSON_READ_PRIORITY
#endif
#endif
#ifdef JSON_VALIDATE
#ifndef JSON_READ_PRIORITY
#error, JSON_VALIDATE also requires JSON_READ_PRIORITY
#endif
#endif
#define JSON_TEMP_COMMENT_IDENTIFIER JSON_TEXT('#')
#endif

View file

@ -0,0 +1,184 @@
#ifndef JSONDEFS_H
#define JSONDEFS_H
/*
Defines all of the types of functions and various other definitions
that are used in C applications, this is very useful if dynamically loading
the library instead of linking.
*/
#include "../../JSONOptions.h"
#include "JSONDefs/Unknown_C.h"
#include "JSONDefs/GNU_C.h"
#include "JSONDefs/Visual_C.h"
#include "JSONDefs/Strings_Defs.h"
#define __LIBJSON_MAJOR__ 7
#define __LIBJSON_MINOR__ 6
#define __LIBJSON_PATCH__ 0
#define __LIBJSON_VERSION__ (__LIBJSON_MAJOR__ * 10000 + __LIBJSON_MINOR__ * 100 + __LIBJSON_PATCH__)
#define JSON_NULL '\0'
#define JSON_STRING '\1'
#define JSON_NUMBER '\2'
#define JSON_BOOL '\3'
#define JSON_ARRAY '\4'
#define JSON_NODE '\5'
#ifdef __cplusplus
#if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL)
#include "JSONAllocator.h"
#else
#define json_allocator std::allocator
#endif
#ifdef JSON_STRING_HEADER
#include JSON_STRING_HEADER
#else
typedef std::basic_string<json_char, std::char_traits<json_char>, json_allocator<json_char> > json_string;
#endif
#endif
#define JSON_MAP(x, y) std::map<x, y, std::less<x>, json_allocator<std::pair<const x, y> > >
#ifdef JSON_NO_EXCEPTIONS
#define json_throw(x)
#define json_try
#define json_catch(exception, code)
#else
#define json_throw(x) throw(x)
#define json_try try
#define json_catch(exception, code) catch(exception){ code }
#endif
#ifdef JSON_STRICT
#ifndef JSON_UNICODE
#error, JSON_UNICODE is required for JSON_STRICT
#endif
#ifdef JSON_COMMENTS
#error, JSON_COMMENTS is required to be off for JSON_STRICT
#endif
#endif
#ifdef JSON_ISO_STRICT
#ifdef JSON_UNICODE
#error, You can not use unicode under ANSI Strict C++
#endif
#else
#ifdef __GNUC__
#ifdef __STRICT_ANSI__
#warning, Using -ansi GCC option, but JSON_ISO_STRICT not on, turning it on for you
#define JSON_ISO_STRICT
#endif
#endif
#endif
#ifdef JSON_NUMBER_TYPE
typedef JSON_NUMBER_TYPE json_number;
#define JSON_FLOAT_THRESHHOLD 0.00001
#else
#ifdef JSON_LESS_MEMORY
typedef float json_number;
#define JSON_FLOAT_THRESHHOLD 0.00001f
#else
typedef double json_number;
#define JSON_FLOAT_THRESHHOLD 0.00001
#endif
#endif
#ifdef JSON_LESS_MEMORY
/* PACKED and BITS stored in compiler specific headers */
#define START_MEM_SCOPE {
#define END_MEM_SCOPE }
#else
#define PACKED(x)
#define BITS(x)
#define START_MEM_SCOPE
#define END_MEM_SCOPE
#endif
#if defined JSON_DEBUG || defined JSON_SAFE
#ifdef JSON_LIBRARY
typedef void (*json_error_callback_t)(const json_char *);
#else
typedef void (*json_error_callback_t)(const json_string &);
#endif
#endif
#ifdef JSON_INDEX_TYPE
typedef JSON_INDEX_TYPE json_index_t;
#else
typedef unsigned int json_index_t;
#endif
#ifdef JSON_BOOL_TYPE
typedef JSON_BOOL_TYPE json_bool_t;
#else
typedef int json_bool_t;
#endif
#ifdef JSON_INT_TYPE
typedef JSON_INT_TYPE json_int_t;
#else
typedef long json_int_t;
#endif
#define JSONSTREAM_SELF (void*)-1
typedef void (*json_stream_e_callback_t)(void * identifier);
typedef void (*json_mutex_callback_t)(void *);
typedef void (*json_free_t)(void *);
#ifndef JSON_LIBRARY
typedef void * (*json_malloc_t)(size_t);
typedef void * (*json_realloc_t)(void *, size_t);
#else
#define JSONNODE void /* so that JSONNODE* is void* */
typedef JSONNODE** JSONNODE_ITERATOR;
#ifdef JSON_STREAM
#define JSONSTREAM void
typedef void (*json_stream_callback_t)(JSONNODE *, void * identifier);
#endif
typedef void * (*json_malloc_t)(unsigned long);
typedef void * (*json_realloc_t)(void *, unsigned long);
#endif
#ifdef JSON_DEBUG
#ifdef NDEBUG
#ifdef __GNUC__
#warning, Have JSON_DEBUG on in a release build
#else
#error, Have JSON_DEBUG on in a release build
#endif
#endif
#else
#ifndef NDEBUG
#ifdef __GNUC__
#warning, Release build of libjson, but NDEBUG is not on
#else
#error, Release build of libjson, but NDEBUG is not on
#endif
#endif
#endif
#ifdef JSON_UNIT_TEST
#define JSON_PRIVATE public:
#define JSON_PROTECTED public:
#else
#define JSON_PRIVATE private:
#define JSON_PROTECTED protected:
#endif
#ifdef JSON_STREAM
#ifndef JSON_READ_PRIORITY
#error, JSON_STREAM also requires JSON_READ_PRIORITY
#endif
#endif
#ifdef JSON_VALIDATE
#ifndef JSON_READ_PRIORITY
#error, JSON_VALIDATE also requires JSON_READ_PRIORITY
#endif
#endif
#define JSON_TEMP_COMMENT_IDENTIFIER JSON_TEXT('#')
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,67 @@
#ifndef JSON_GNU_C_HEADER
#define JSON_GUN_C_HEADER
#ifdef __GNUC__
#define json_deprecated(method, warning) method __attribute__((deprecated))
#if (__GNUC__ >= 3)
#define JSON_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
#define JSON_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
#endif
#if (JSON_GCC_VERSION >= 40300)
#define json_hot __attribute__ ((hot))
#define json_cold __attribute__ ((cold))
#define json_pure json_nothrow __attribute__ ((pure, hot))
#define json_malloc_attr json_nothrow __attribute__ ((malloc, hot))
/* Can do priorities */
#if (JSON_WRITE_PRIORITY == HIGH)
#define json_write_priority __attribute__ ((hot))
#elif (JSON_WRITE_PRIORITY == LOW)
#define json_write_priority __attribute__ ((cold))
#else
#define json_write_priority
#endif
#if (JSON_READ_PRIORITY == HIGH)
#define json_read_priority __attribute__ ((hot))
#elif (JSON_READ_PRIORITY == LOW)
#define json_read_priority __attribute__ ((cold))
#else
#define json_read_priority
#endif
#define json_likely(x) __builtin_expect((long)((bool)(x)),1)
#define json_unlikely(x) __builtin_expect((long)((bool)(x)),0)
#else
#if (JSON_GCC_VERSION >= 29600)
#define json_pure json_nothrow __attribute__ ((pure))
#define json_likely(x) __builtin_expect((long)((bool)(x)),1)
#define json_unlikely(x) __builtin_expect((long)((bool)(x)),0)
#else
#define json_pure json_nothrow
#define json_likely(x) x
#define json_unlikely(x) x
#endif
#define json_malloc_attr json_nothrow __attribute__ ((malloc))
#define json_write_priority
#define json_read_priority
#define json_hot
#define json_cold
#endif
#define json_nothrow throw()
#define json_throws(x) throw(x)
#ifdef JSON_LESS_MEMORY
#define PACKED(x) :x __attribute__ ((packed))
#define BITS(x) :x
#endif
#endif
#endif

View file

@ -0,0 +1,36 @@
#ifndef STRINGS_DEFS_HEADER
#define STRINGS_DEFS_HEADER
#include "../../../JSONOptions.h"
#ifdef JSON_UNICODE
#define json_char wchar_t
#define json_uchar wchar_t
#ifdef __cplusplus
#include <cwchar> /* need wide characters */
#ifndef JSON_STRING_HEADER
#include <string>
#endif
#else
#include <wchar.h> /* need wide characters */
#endif
#define JSON_TEXT(s) L ## s
#define json_strlen wcslen
#define json_strcmp wcscmp
#else
#define json_char char
#define json_uchar unsigned char
#ifdef __cplusplus
#ifndef JSON_STRING_HEADER
#include <string>
#endif
#else
#include <string.h> /* still need it for strlen and such */
#endif
#define JSON_TEXT(s) s
#define json_strlen strlen
#define json_strcmp strcmp
#endif
#endif

View file

@ -0,0 +1,26 @@
#ifndef JSON_UNKNOWN_C_HEADER
#define JSON_UNKNOWN_C_HEADER
#if !defined(__GNUC__) && !defined(_MSC_VER)
#define json_deprecated(method, warning) method
#define json_nothrow
#define json_throws(x)
#define json_pure json_nothrow
#define json_read_priority
#define json_write_priority
#define json_malloc_attr json_nothrow
#define json_hot
#define json_cold
#define json_likely(x) x
#define json_unlikely(x) x
#ifdef JSON_LESS_MEMORY
#define PACKED(x) :x
#define BITS(x) :x
#endif
#endif
#endif

View file

@ -0,0 +1,26 @@
#ifndef JSON_VISUAL_C_HEADER
#define JSON_VISUAL_C_HEADER
#ifdef _MSC_VER
#define json_deprecated(method, warning) __declspec(deprecated(warning)) method
#define json_nothrow
#define json_throws(x)
#define json_pure json_nothrow
#define json_read_priority
#define json_write_priority
#define json_malloc_attr json_nothrow
#define json_hot
#define json_cold
#define json_likely(x) x
#define json_unlikely(x) x
#ifdef JSON_LESS_MEMORY
#define PACKED(x) :x
#define BITS(x) :x
#endif
#endif
#endif

View file

@ -0,0 +1,95 @@
#ifndef JSON_GLOBALS_H
#define JSON_GLOBALS_H
#include "JSONDefs.h"
/*
* The use of singletons for globals makes globals not
* actually be initialized until it is first needed, this
* makes the library faster to load, and have a smaller
* memory footprint
*/
#define json_global_decl(TYPE, NAME, VALUE) \
class jsonSingleton ## NAME { \
public: \
inline static TYPE & getValue() json_nothrow { \
static jsonSingleton ## NAME single; \
return single.val; \
} \
protected: \
inline jsonSingleton ## NAME() json_nothrow : val(VALUE) {} \
TYPE val; \
}
#define json_global_decl_strconfig(TYPE, NAME, VALUE) \
class jsonSingleton ## NAME { \
public: \
inline static TYPE & getValue() json_nothrow { \
static jsonSingleton ## NAME single; \
return single.val; \
} \
protected: \
inline jsonSingleton ## NAME() json_nothrow { \
const std::string tmp = std::string(VALUE); \
val = json_string(tmp.begin(), tmp.end()); \
} \
TYPE val; \
}
#define json_global(NAME) jsonSingleton ## NAME::getValue()
#include <string>
json_global_decl(json_string, EMPTY_JSON_STRING, );
json_global_decl(std::string, EMPTY_STD_STRING, );
json_global_decl(json_string, CONST_TRUE, JSON_TEXT("true"));
json_global_decl(json_string, CONST_FALSE, JSON_TEXT("false"));
json_global_decl(json_string, CONST_NULL, JSON_TEXT("null"));
#ifndef JSON_NEWLINE
json_global_decl(json_string, NEW_LINE, JSON_TEXT("\n"));
#else
json_global_decl_strconfig(json_string, NEW_LINE, JSON_NEWLINE);
#endif
#ifdef JSON_WRITE_BASH_COMMENTS
json_global_decl(json_string, SINGLELINE_COMMENT, JSON_TEXT("#"));
#else
json_global_decl(json_string, SINGLELINE_COMMENT, JSON_TEXT("//"));
#endif
#ifdef JSON_INDENT
json_global_decl_strconfig(json_string, INDENT, JSON_INDENT);
#endif
#ifdef JSON_MUTEX_CALLBACKS
#include <map>
json_global_decl(JSON_MAP(void *, unsigned int), MUTEX_MANAGER, );
json_global_decl(JSON_MAP(int, JSON_MAP(void *, unsigned int) ), THREAD_LOCKS, );
#endif
#ifdef JSON_LIBRARY
#ifdef JSON_MEMORY_MANAGE
#include "JSONMemory.h"
json_global_decl(auto_expand, STRING_HANDLER, );
json_global_decl(auto_expand_node, NODE_HANDLER, );
#ifdef JSON_STREAM
json_global_decl(auto_expand_stream, STREAM_HANDLER, );
#endif
#endif
#endif
//These are common error responses
json_global_decl(json_string, ERROR_TOO_LONG, JSON_TEXT("Exceeding JSON_SECURITY_MAX_STRING_LENGTH"));
json_global_decl(json_string, ERROR_UNKNOWN_LITERAL, JSON_TEXT("Unknown JSON literal: "));
json_global_decl(json_string, ERROR_NON_CONTAINER, JSON_TEXT("Calling container method on non-container: "));
json_global_decl(json_string, ERROR_NON_ITERATABLE, JSON_TEXT("Calling iterator method on non-iteratable: "));
json_global_decl(json_string, ERROR_NULL_IN_CHILDREN, JSON_TEXT("a null pointer within the children"));
json_global_decl(json_string, ERROR_UNDEFINED, JSON_TEXT("Undefined results: "));
json_global_decl(json_string, ERROR_LOWER_RANGE, JSON_TEXT(" is outside the lower range of "));
json_global_decl(json_string, ERROR_UPPER_RANGE, JSON_TEXT(" is outside the upper range of "));
json_global_decl(json_string, ERROR_NOT_BASE64, JSON_TEXT("Not base64"));
json_global_decl(json_string, ERROR_OUT_OF_MEMORY, JSON_TEXT("Out of memory"));
#endif

View file

@ -0,0 +1,214 @@
#include "JSONNode.h"
#ifdef JSON_ITERATORS
#ifdef JSON_REF_COUNT
#define JSON_ASSERT_UNIQUE(x) JSON_ASSERT(internal -> refcount == 1, json_string(JSON_TEXT(x)) + JSON_TEXT(" in non single reference"))
#else
#define JSON_ASSERT_UNIQUE(x) (void)0
#endif
#ifdef JSON_MUTEX_CALLBACKS
#define JSON_MUTEX_COPY2 ,internal -> mylock
#else
#define JSON_MUTEX_COPY2
#endif
JSONNode::json_iterator JSONNode::find(const json_string & name_t) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find"));
makeUniqueInternal();
if (JSONNode ** res = internal -> at(name_t)){
return ptr_to_json_iterator(res);
}
return end();
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode::json_iterator JSONNode::find_nocase(const json_string & name_t) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find_nocase"));
makeUniqueInternal();
if (JSONNode ** res = internal -> at_nocase(name_t)){
return ptr_to_json_iterator(res);
}
return end();
}
#endif
JSONNode::json_iterator JSONNode::erase(json_iterator pos) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase"));
JSON_ASSERT_UNIQUE("erase 1");
JSON_ASSERT_SAFE(pos < end(), JSON_TEXT("erase out of range"), return end(););
JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("erase out of range"), return begin(););
deleteJSONNode(*(json_iterator_ptr(pos)));
internal -> CHILDREN -> erase(json_iterator_ptr(pos));
return (empty()) ? end() : pos;
}
JSONNode::json_iterator JSONNode::erase(json_iterator _start, const json_iterator & _end) json_nothrow {
if (_start == _end) return _start;
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase"));
JSON_ASSERT_UNIQUE("erase 3");
JSON_ASSERT_SAFE(_start <= end(), JSON_TEXT("erase out of lo range"), return end(););
JSON_ASSERT_SAFE(_end <= end(), JSON_TEXT("erase out of hi range"), return end(););
JSON_ASSERT_SAFE(_start >= begin(), JSON_TEXT("erase out of lo range"), return begin(););
JSON_ASSERT_SAFE(_end >= begin(), JSON_TEXT("erase out of hi range"), return begin(););
for (JSONNode ** pos = json_iterator_ptr(_start); pos < json_iterator_ptr(_end); ++pos){
deleteJSONNode(*pos);
}
internal -> CHILDREN -> erase(json_iterator_ptr(_start), (json_index_t)(json_iterator_ptr(_end) - json_iterator_ptr(_start)));
return (empty()) ? end() : _start;
}
#ifdef JSON_LIBRARY
JSONNode::json_iterator JSONNode::insert(json_iterator pos, JSONNode * x) json_nothrow {
#else
JSONNode::json_iterator JSONNode::insert(json_iterator pos, const JSONNode & x) json_nothrow {
#endif
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insert"));
JSON_ASSERT_UNIQUE("insert 1");
if (json_iterator_ptr(pos) >= internal -> CHILDREN -> end()){
internal -> push_back(x);
return end() - 1;
}
JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of lo range"), return begin(););
#ifdef JSON_LIBRARY
internal -> CHILDREN -> insert(json_iterator_ptr(pos), x);
#else
internal -> CHILDREN -> insert(json_iterator_ptr(pos), newJSONNode(x));
#endif
return pos;
}
JSONNode::json_iterator JSONNode::insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertFFF"));
JSON_ASSERT_UNIQUE("insertFFF");
JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of high range"), return end(););
JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of low range"), return begin(););
const json_index_t num = (json_index_t)(_end - _start);
json_auto<JSONNode *> mem(num);
JSONNode ** runner = mem.ptr;
for (JSONNode ** po = _start; po < _end; ++po){
*runner++ = newJSONNode(*(*po) JSON_MUTEX_COPY2);
}
internal -> CHILDREN -> insert(json_iterator_ptr(pos), mem.ptr, num);
return pos;
}
#ifndef JSON_LIBRARY
JSONNode::const_iterator JSONNode::find(const json_string & name_t) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find"));
if (JSONNode ** res = internal -> at(name_t)){
return JSONNode::const_iterator(res);
}
return JSONNode::const_iterator(internal -> end());
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode::const_iterator JSONNode::find_nocase(const json_string & name_t) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("find_nocase"));
if (JSONNode ** res = internal -> at_nocase(name_t)){
return JSONNode::const_iterator(res);
}
return JSONNode::const_iterator(internal -> end());
}
#endif
JSONNode::reverse_iterator JSONNode::erase(reverse_iterator pos) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase"));
JSON_ASSERT_UNIQUE("erase 2");
JSON_ASSERT_SAFE(pos < rend(), JSON_TEXT("erase out of range"), return rend(););
JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("erase out of range"), return rbegin(););
deleteJSONNode(*(pos.it));
internal -> CHILDREN -> erase(pos.it);
return (empty()) ? rend() : pos + 1;
}
JSONNode::reverse_iterator JSONNode::erase(reverse_iterator _start, const reverse_iterator & _end) json_nothrow {
if (_start == _end) return _start;
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("erase"));
JSON_ASSERT_UNIQUE("erase 4");
JSON_ASSERT_SAFE(_start <= rend(), JSON_TEXT("erase out of lo range"), return rend(););
JSON_ASSERT_SAFE(_end <= rend(), JSON_TEXT("erase out of hi range"), return rend(););
JSON_ASSERT_SAFE(_start >= rbegin(), JSON_TEXT("erase out of lo range"), return rbegin(););
JSON_ASSERT_SAFE(_end >= rbegin(), JSON_TEXT("erase out of hi range"), return rbegin(););
for (JSONNode ** pos = _start.it; pos > _end.it; --pos){
deleteJSONNode(*pos);
}
const json_index_t num = (json_index_t)(_start.it - _end.it);
internal -> CHILDREN -> erase(_end.it + 1, num, _start.it);
return (empty()) ? rend() : _start + num;
}
JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const JSONNode & x) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insert"));
JSON_ASSERT_UNIQUE("insert 1");
if (pos.it < internal -> CHILDREN -> begin()){
internal -> push_front(x);
return rend() - 1;
}
JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin(););
internal -> CHILDREN -> insert(++pos.it, newJSONNode(x), true);
return pos;
}
JSONNode::reverse_iterator JSONNode::insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertRFF"));
JSON_ASSERT_UNIQUE("insert RFF");
JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend(););
JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin(););
const json_index_t num = (json_index_t)(_end - _start);
json_auto<JSONNode *> mem(num);
JSONNode ** runner = mem.ptr + num;
for (JSONNode ** po = _start; po < _end; ++po){ //fill it backwards
*(--runner) = newJSONNode(*(*po) JSON_MUTEX_COPY2);
}
internal -> CHILDREN -> insert(++pos.it, mem.ptr, num);
return pos - num + 1;
}
JSONNode::iterator JSONNode::insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertFRR"));
JSON_ASSERT_UNIQUE("insert FRR");
JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of range"), return end(););
JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of range"), return begin(););
const json_index_t num = (json_index_t)(_start - _end);
json_auto<JSONNode *> mem(num);
JSONNode ** runner = mem.ptr;
for (JSONNode ** po = _start; po > _end; --po){
*runner++ = newJSONNode(*(*po) JSON_MUTEX_COPY2);
}
internal -> CHILDREN -> insert(pos.it, mem.ptr, num);
return pos;
}
JSONNode::reverse_iterator JSONNode::insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("insertRRR"));
JSON_ASSERT_UNIQUE("insert RRR");
JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend(););
JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin(););
const json_index_t num = (json_index_t)(_start - _end);
json_auto<JSONNode *> mem(num);
JSONNode ** runner = mem.ptr;
for (JSONNode ** po = _start; po > _end; --po){
*runner++ = newJSONNode(*(*po) JSON_MUTEX_COPY2);
}
internal -> CHILDREN -> insert(++pos.it, mem.ptr, num);
return pos - num + 1;
}
#endif
#endif

View file

@ -0,0 +1,149 @@
#include "JSONMemory.h"
#ifdef JSON_MEMORY_MANAGE
#include "JSONNode.h"
void auto_expand::purge(void) json_nothrow {
for(JSON_MAP(void *, void *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){
#if defined(JSON_DEBUG) || defined(JSON_SAFE)
void * temp = (void*)i -> first; //because its pass by reference
libjson_free<void>(temp);
#else
libjson_free<void>((void*)i -> first);
#endif
}
}
void auto_expand_node::purge(void) json_nothrow {
for(JSON_MAP(void *, JSONNode *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){
JSONNode::deleteJSONNode((JSONNode *)i -> second);
}
}
#ifdef JSON_STREAM
#include "JSONStream.h"
void auto_expand_stream::purge(void) json_nothrow {
for(JSON_MAP(void *, JSONStream *)::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){
JSONStream::deleteJSONStream((JSONStream *)i -> second);
}
}
#endif
#endif
#if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL)
#ifdef JSON_MEMORY_POOL
#include "JSONMemoryPool.h"
static bucket_pool_8<MEMPOOL_1, MEMPOOL_2, MEMPOOL_3, MEMPOOL_4, MEMPOOL_5, MEMPOOL_6, MEMPOOL_7, MEMPOOL_8> json_generic_mempool;
//This class is only meant to initiate the mempool to start out using std::malloc/realloc/free
class mempool_callback_setter {
public:
LIBJSON_OBJECT(mempool_callback_setter);
inline mempool_callback_setter(void) json_nothrow {
` LIBJSON_CTOR;
mempool_callbacks::set(std::malloc, std::realloc, std::free);
}
private:
inline mempool_callback_setter(const mempool_callback_setter & o);
inline mempool_callback_setter & operator = (const mempool_callback_setter & o);
};
static mempool_callback_setter __mempoolcallbacksetter;
#endif
#include "JSONSingleton.h"
void * JSONMemory::json_malloc(size_t siz) json_nothrow {
#ifdef JSON_MEMORY_POOL
return json_generic_mempool.allocate(siz);
#else
if (json_malloc_t callback = JSONSingleton<json_malloc_t>::get()){
#if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful
void * result = callback(siz);
JSON_ASSERT(result, JSON_TEXT("Out of memory"));
return result;
#else
return callback(siz);
#endif
}
#if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful
void * result = std::malloc(siz);
JSON_ASSERT(result, JSON_TEXT("Out of memory"));
return result;
#else
return std::malloc(siz);
#endif
#endif
}
void JSONMemory::json_free(void * ptr) json_nothrow {
#ifdef JSON_MEMORY_POOL
json_generic_mempool.deallocate(ptr);
#else
if (json_free_t callback = JSONSingleton<json_free_t>::get()){
callback(ptr);
} else {
std::free(ptr);
}
#endif
}
void * JSONMemory::json_realloc(void * ptr, size_t siz) json_nothrow {
#ifdef JSON_MEMORY_POOL
return json_generic_mempool.reallocate(ptr, siz);
#else
if (json_realloc_t callback = JSONSingleton<json_realloc_t>::get()){
#if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful
void * result = callback(ptr, siz);
JSON_ASSERT(result, JSON_TEXT("Out of memory"));
return result;
#else
return callback(ptr, siz);
#endif
}
#if(defined(JSON_DEBUG) && (!defined(JSON_MEMORY_CALLBACKS))) //in debug mode without mem callback, see if the malloc was successful
void * result = std::realloc(ptr, siz);
JSON_ASSERT(result, JSON_TEXT("Out of memory"));
return result;
#else
return std::realloc(ptr, siz);
#endif
#endif
}
#ifdef JSON_MEMORY_POOL
//it is okay to pass null to these callbacks, no make sure they function exists
static void * malloc_proxy(size_t siz) json_nothrow {
if (json_malloc_t callback = JSONSingleton<json_malloc_t>::get()){
return callback(siz);
}
return std::malloc(siz);
}
static void * realloc_proxy(void * ptr, size_t siz) json_nothrow {
if (json_realloc_t callback = JSONSingleton<json_realloc_t>::get()){
return callback(ptr, siz);
}
return std::realloc(ptr, siz);
}
static void free_proxy(void * ptr){
if (json_free_t callback = JSONSingleton<json_free_t>::get()){
callback(ptr);
} else {
std::free(ptr);
}
}
#endif
void JSONMemory::registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre) json_nothrow {
JSONSingleton<json_malloc_t>::set(mal);
JSONSingleton<json_realloc_t>::set(real);
JSONSingleton<json_free_t>::set(fre);
#ifdef JSON_MEMORY_POOL
mempool_callbacks::set(malloc_proxy, realloc_proxy, free_proxy);
#endif
}
#endif

View file

@ -0,0 +1,175 @@
#ifndef JSON_MEMORY_H
#define JSON_MEMORY_H
#include <cstdlib> //for malloc, realloc, and free
#include <cstring> //for memmove
#include "JSONDebug.h"
#if defined(JSON_DEBUG) || defined(JSON_SAFE)
#define JSON_FREE_PASSTYPE &
#else
#define JSON_FREE_PASSTYPE
#endif
#if defined(JSON_MEMORY_CALLBACKS) || defined(JSON_MEMORY_POOL)
class JSONMemory {
public:
static void * json_malloc(size_t siz) json_malloc_attr;
static void * json_realloc(void * ptr, size_t siz) json_malloc_attr;
static void json_free(void * ptr) json_nothrow;
static void registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre) json_nothrow json_cold;
private:
JSONMemory(void);
};
template <typename T> static inline T * json_malloc(size_t count) json_malloc_attr;
template <typename T> static inline T * json_malloc(size_t count) json_nothrow {
return (T *)JSONMemory::json_malloc(sizeof(T) * count);
}
template <typename T> static inline T * json_realloc(T * ptr, size_t count) json_malloc_attr;
template <typename T> static inline T * json_realloc(T * ptr, size_t count) json_nothrow {
return (T *)JSONMemory::json_realloc(ptr, sizeof(T) * count);
}
template <typename T> static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr) json_nothrow {
JSONMemory::json_free(ptr);
#if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again
ptr = 0;
#endif
}
#else
template <typename T> static inline T * json_malloc(size_t count) json_malloc_attr;
template <typename T> static inline T * json_malloc(size_t count) json_nothrow {
#ifdef JSON_DEBUG //in debug mode, see if the malloc was successful
void * result = std::malloc(count * sizeof(T));
JSON_ASSERT(result != 0, JSON_TEXT("Out of memory"));
#ifdef JSON_NULL_MEMORY
std::memset(result, '\0', count * sizeof(T));
#endif
return (T *)result;
#else
return (T *)std::malloc(count * sizeof(T));
#endif
}
template <typename T> static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr) json_nothrow {
std::free(ptr);
#if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again
ptr = 0;
#endif
}
template <typename T> static inline T * json_realloc(T * ptr, size_t count) json_malloc_attr;
template <typename T> static inline T * json_realloc(T * ptr, size_t count) json_nothrow {
#ifdef JSON_DEBUG //in debug mode, check the results of realloc to be sure it was successful
void * result = std::realloc(ptr, count * sizeof(T));
JSON_ASSERT(result != 0, JSON_TEXT("Out of memory"));
return (T *)result;
#else
return (T *)std::realloc(ptr, count * sizeof(T));
#endif
}
#endif
#ifdef JSON_MEMORY_MANAGE
#include <map>
class JSONNode;
struct auto_expand {
public:
LIBJSON_OBJECT(auto_expand);
auto_expand(void) json_nothrow : mymap(){ LIBJSON_CTOR;}
~auto_expand(void) json_nothrow { purge(); LIBJSON_DTOR; }
void purge(void) json_nothrow;
inline void clear(void) json_nothrow { purge(); mymap.clear(); }
inline void * insert(void * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; }
inline void remove(void * ptr) json_nothrow {
JSON_MAP(void *, void *)::iterator i = mymap.find(ptr);
JSON_ASSERT(i != mymap.end(), JSON_TEXT("Removing a non-managed item"));
mymap.erase(i);
}
JSON_MAP(void *, void *) mymap;
private:
auto_expand(const auto_expand &);
auto_expand & operator = (const auto_expand &);
};
struct auto_expand_node {
public:
LIBJSON_OBJECT(auto_expand_node);
auto_expand_node(void) json_nothrow : mymap(){ LIBJSON_CTOR; }
~auto_expand_node(void) json_nothrow { purge(); LIBJSON_DTOR; }
void purge(void) json_nothrow ;
inline void clear(void) json_nothrow { purge(); mymap.clear(); }
inline JSONNode * insert(JSONNode * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; }
inline void remove(void * ptr) json_nothrow {
JSON_MAP(void *, JSONNode *)::iterator i = mymap.find(ptr);
if(json_likely(i != mymap.end())) mymap.erase(i);
}
JSON_MAP(void *, JSONNode *) mymap;
private:
auto_expand_node(const auto_expand_node &);
auto_expand_node & operator = (const auto_expand_node &);
};
#ifdef JSON_STREAM
class JSONStream;
struct auto_expand_stream {
public:
LIBJSON_OBJECT(auto_expand_stream);
auto_expand_stream(void) json_nothrow : mymap(){ LIBJSON_CTOR; }
~auto_expand_stream(void) json_nothrow { purge(); LIBJSON_DTOR; }
void purge(void) json_nothrow ;
inline void clear(void) json_nothrow { purge(); mymap.clear(); }
inline JSONStream * insert(JSONStream * ptr) json_nothrow { mymap[ptr] = ptr; return ptr; }
inline void remove(void * ptr) json_nothrow {
JSON_MAP(void *, JSONStream *)::iterator i = mymap.find(ptr);
if(json_likely(i != mymap.end())) mymap.erase(i);
}
JSON_MAP(void *, JSONStream *) mymap;
private:
auto_expand_stream(const auto_expand_stream &);
auto_expand_stream & operator = (const auto_expand_stream &);
};
#endif
#endif
//The C++ way, use an self-deleting pointer and let the optimizer decide when it gets destroyed
template <typename T>
class json_auto {
public:
LIBJSON_OBJECT(json_auto);
json_auto(void) json_nothrow : ptr(0){ LIBJSON_CTOR; }
json_auto(size_t count) json_nothrow : ptr(json_malloc<T>(count)){ LIBJSON_CTOR; }
json_auto(T * arg) json_nothrow : ptr(arg){ LIBJSON_CTOR; }
~json_auto(void) json_nothrow {
libjson_free<T>(ptr);
LIBJSON_DTOR;
}
inline void set(T * p) json_nothrow{
ptr = p;
}
T * ptr;
private:
json_auto(const json_auto &);
json_auto & operator =(const json_auto &);
};
//Clears a string, if required, frees the memory
static inline void clearString(json_string & str) json_nothrow {
#ifdef JSON_LESS_MEMORY
json_string().swap(str);
#else
str.clear();
#endif
}
//Shrinks a string
static inline void shrinkString(json_string & str) json_nothrow {
#ifdef JSON_LESS_MEMORY
if (str.capacity() != str.length()) str = json_string(str.begin(), str.end());
#endif
}
#endif

View file

@ -0,0 +1,38 @@
#ifndef LIBJSON_GUARD_MEMORY_POOL_H
#define LIBJSON_GUARD_MEMORY_POOL_H
#ifdef JSON_MEMORY_POOL
#include "../Dependencies/mempool++/mempool.h"
//this macro expands to the number of bytes a pool gets based on block size and number of 32s of the total pool it gets
#define jsonPoolPart(bytes_per_block, thirty_seconds_of_mem) bytes_per_block, ((thirty_seconds_of_mem * JSON_MEMORY_POOL / 32) / bytes_per_block)
#ifdef JSON_PREPARSE
#define NODEPOOL jsonPoolPart(sizeof(JSONNode), 1)
#define INTERNALNODEPOOL jsonPoolPart(sizeof(internalJSONNode), 3)
#define MEMPOOL_1 jsonPoolPart(8, 2)
#define MEMPOOL_2 jsonPoolPart(16, 2)
#define MEMPOOL_3 jsonPoolPart(32, 2)
#define MEMPOOL_4 jsonPoolPart(64, 2)
#define MEMPOOL_5 jsonPoolPart(128, 3)
#define MEMPOOL_6 jsonPoolPart(256, 4)
#define MEMPOOL_7 jsonPoolPart(512, 5)
#define MEMPOOL_8 jsonPoolPart(4096, 8)
#else
#define NODEPOOL jsonPoolPart(sizeof(JSONNode), 2)
#define INTERNALNODEPOOL jsonPoolPart(sizeof(internalJSONNode), 7)
#define MEMPOOL_1 jsonPoolPart(8, 1)
#define MEMPOOL_2 jsonPoolPart(16, 1)
#define MEMPOOL_3 jsonPoolPart(32, 1)
#define MEMPOOL_4 jsonPoolPart(64, 1)
#define MEMPOOL_5 jsonPoolPart(128, 3)
#define MEMPOOL_6 jsonPoolPart(256, 3)
#define MEMPOOL_7 jsonPoolPart(512, 5)
#define MEMPOOL_8 jsonPoolPart(4096, 8)
#endif
#endif
#endif

View file

@ -0,0 +1,356 @@
#include "JSONNode.h"
#define IMPLEMENT_CTOR(type)\
JSONNode::JSONNode(const json_string & name_t, type value_t) json_nothrow : internal(internalJSONNode::newInternal()){\
internal -> Set(value_t);\
internal -> setname(name_t);\
LIBJSON_CTOR;\
}
IMPLEMENT_FOR_ALL_TYPES(IMPLEMENT_CTOR)
#ifndef JSON_LIBRARY
JSONNode::JSONNode(const json_string & name_t, const json_char * value_t) json_nothrow : internal(internalJSONNode::newInternal()){
internal -> Set(json_string(value_t));
internal -> setname(name_t);
LIBJSON_CTOR;
}
#endif
#if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY))
#include "JSONWorker.h"
JSONNode JSONNode::stringType(const json_string & str){
JSONNode res;
res.set_name(json_global(EMPTY_JSON_STRING));
#ifdef JSON_LESS_MEMORY
res = JSONWorker::FixString(str, res.internal, false);
#else
res = JSONWorker::FixString(str, res.internal -> _string_encoded);
#endif
return res;
}
void JSONNode::set_name_(const json_string & newname) json_nothrow {
#ifdef JSON_LESS_MEMORY
json_string _newname = JSONWorker::FixString(newname, internal, true);
#else
json_string _newname = JSONWorker::FixString(newname, internal -> _name_encoded);
#endif
set_name(_newname);
}
#endif
#ifdef JSON_CASTABLE
JSONNode JSONNode::as_node(void) const json_nothrow {
JSON_CHECK_INTERNAL();
if (type() == JSON_NODE){
return *this;
} else if (type() == JSON_ARRAY){
JSONNode res(duplicate());
res.internal -> _type = JSON_NODE;
return res;
}
#ifdef JSON_MUTEX_CALLBACKS
if (internal -> mylock != 0){
JSONNode res(JSON_NODE);
res.set_mutex(internal -> mylock);
return res;
}
#endif
return JSONNode(JSON_NODE);
}
JSONNode JSONNode::as_array(void) const json_nothrow {
JSON_CHECK_INTERNAL();
if (type() == JSON_ARRAY){
return *this;
} else if (type() == JSON_NODE){
JSONNode res(duplicate());
res.internal -> _type = JSON_ARRAY;
json_foreach(res.internal -> CHILDREN, runner){
(*runner) -> clear_name();
}
return res;
}
#ifdef JSON_MUTEX_CALLBACKS
if (internal -> mylock != 0){
JSONNode res(JSON_ARRAY);
res.set_mutex(internal -> mylock);
return res;
}
#endif
return JSONNode(JSON_ARRAY);
}
void JSONNode::cast(char newtype) json_nothrow {
JSON_CHECK_INTERNAL();
if (newtype == type()) return;
switch(newtype){
case JSON_NULL:
nullify();
return;
case JSON_STRING:
*this = as_string();
return;
case JSON_NUMBER:
*this = as_float();
return;
case JSON_BOOL:
*this = as_bool();
return;
case JSON_ARRAY:
*this = as_array();
return;
case JSON_NODE:
*this = as_node();
return;
}
JSON_FAIL(JSON_TEXT("cast to unknown type"));
}
#endif
//different just to supress the warning
#ifdef JSON_REF_COUNT
void JSONNode::merge(JSONNode & other) json_nothrow {
#else
void JSONNode::merge(JSONNode &) json_nothrow {
#endif
JSON_CHECK_INTERNAL();
#ifdef JSON_REF_COUNT
if (internal == other.internal) return;
JSON_ASSERT(*this == other, JSON_TEXT("merging two nodes that aren't equal"));
if (internal -> refcount < other.internal -> refcount){
*this = other;
} else {
other = *this;
}
#endif
}
#ifdef JSON_REF_COUNT
void JSONNode::merge(JSONNode * other) json_nothrow {
JSON_CHECK_INTERNAL();
if (internal == other -> internal) return;
*other = *this;
}
//different just to supress the warning
void JSONNode::merge(unsigned int num, ...) json_nothrow {
#else
void JSONNode::merge(unsigned int, ...) json_nothrow {
#endif
JSON_CHECK_INTERNAL();
#ifdef JSON_REF_COUNT
va_list args;
va_start(args, num);
for(unsigned int i = 0; i < num; ++i){
merge(va_arg(args, JSONNode*));
}
va_end(args);
#endif
}
JSONNode JSONNode::duplicate(void) const json_nothrow {
JSON_CHECK_INTERNAL();
JSONNode mycopy(*this);
#ifdef JSON_REF_COUNT
JSON_ASSERT(internal == mycopy.internal, JSON_TEXT("copy ctor failed to ref count correctly"));
mycopy.makeUniqueInternal();
#endif
JSON_ASSERT(internal != mycopy.internal, JSON_TEXT("makeUniqueInternal failed"));
return mycopy;
}
JSONNode & JSONNode::at(json_index_t pos) json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
if (json_unlikely(pos >= internal -> size())){
JSON_FAIL(JSON_TEXT("at() out of bounds"));
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
}
return (*this)[pos];
}
const JSONNode & JSONNode::at(json_index_t pos) const json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
if (json_unlikely(pos >= internal -> size())){
JSON_FAIL(JSON_TEXT("at() const out of bounds"));
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
}
return (*this)[pos];
}
JSONNode & JSONNode::operator[](json_index_t pos) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] out of bounds"));
makeUniqueInternal();
return *(internal -> at(pos));
}
const JSONNode & JSONNode::operator[](json_index_t pos) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] const out of bounds"));
return *(internal -> at(pos));
}
JSONNode & JSONNode::at(const json_string & name_t) json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at"));
makeUniqueInternal();
if (JSONNode ** res = internal -> at(name_t)){
return *(*res);
}
JSON_FAIL(json_string(JSON_TEXT("at could not find child by name: ")) + name_t);
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
}
const JSONNode & JSONNode::at(const json_string & name_t) const json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at"));
if (JSONNode ** res = internal -> at(name_t)){
return *(*res);
}
JSON_FAIL(json_string(JSON_TEXT("at const could not find child by name: ")) + name_t);
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode & JSONNode::at_nocase(const json_string & name_t) json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at_nocase"));
makeUniqueInternal();
if (JSONNode ** res = internal -> at_nocase(name_t)){
return *(*res);
}
JSON_FAIL(json_string(JSON_TEXT("at_nocase could not find child by name: ")) + name_t);
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
}
const JSONNode & JSONNode::at_nocase(const json_string & name_t) const json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("at_nocase"));
if (JSONNode ** res = internal -> at_nocase(name_t)){
return *(*res);
}
JSON_FAIL(json_string(JSON_TEXT("at_nocase const could not find child by name: ")) + name_t);
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
}
#endif
#ifndef JSON_LIBRARY
struct auto_delete {
public:
auto_delete(JSONNode * node) json_nothrow : mynode(node){};
~auto_delete(void) json_nothrow { JSONNode::deleteJSONNode(mynode); };
JSONNode * mynode;
private:
auto_delete(const auto_delete &);
auto_delete & operator = (const auto_delete &);
};
#endif
JSONNode JSON_PTR_LIB JSONNode::pop_back(json_index_t pos) json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
if (json_unlikely(pos >= internal -> size())){
JSON_FAIL(JSON_TEXT("pop_back out of bounds"));
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
}
makeUniqueInternal();
#ifdef JSON_LIBRARY
return internal -> pop_back(pos);
#else
auto_delete temp(internal -> pop_back(pos));
return *temp.mynode;
#endif
}
JSONNode JSON_PTR_LIB JSONNode::pop_back(const json_string & name_t) json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("pop_back"));
#ifdef JSON_LIBRARY
return internal -> pop_back(name_t);
#else
if (JSONNode * res = internal -> pop_back(name_t)){
auto_delete temp(res);
return *(temp.mynode);
}
JSON_FAIL(json_string(JSON_TEXT("pop_back const could not find child by name: ")) + name_t);
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
#endif
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode JSON_PTR_LIB JSONNode::pop_back_nocase(const json_string & name_t) json_throws(std::out_of_range) {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("pop_back_no_case"));
#ifdef JSON_LIBRARY
return internal -> pop_back_nocase(name_t);
#else
if (JSONNode * res = internal -> pop_back_nocase(name_t)){
auto_delete temp(res);
return *(temp.mynode);
}
JSON_FAIL(json_string(JSON_TEXT("pop_back_nocase could not find child by name: ")) + name_t);
json_throw(std::out_of_range(json_global(EMPTY_STD_STRING)));
#endif
}
#endif
#ifdef JSON_MEMORY_POOL
#include "JSONMemoryPool.h"
memory_pool<NODEPOOL> json_node_mempool;
#endif
void JSONNode::deleteJSONNode(JSONNode * ptr) json_nothrow {
#ifdef JSON_MEMORY_POOL
ptr -> ~JSONNode();
json_node_mempool.deallocate((void*)ptr);
#elif defined(JSON_MEMORY_CALLBACKS)
ptr -> ~JSONNode();
libjson_free<JSONNode>(ptr);
#else
delete ptr;
#endif
}
inline JSONNode * _newJSONNode(const JSONNode & orig) {
#ifdef JSON_MEMORY_POOL
return new((JSONNode*)json_node_mempool.allocate()) JSONNode(orig);
#elif defined(JSON_MEMORY_CALLBACKS)
return new(json_malloc<JSONNode>(1)) JSONNode(orig);
#else
return new JSONNode(orig);
#endif
}
JSONNode * JSONNode::newJSONNode(const JSONNode & orig JSON_MUTEX_COPY_DECL) {
#ifdef JSON_MUTEX_CALLBACKS
if (parentMutex != 0){
JSONNode * temp = _newJSONNode(orig);
temp -> set_mutex(parentMutex);
return temp;
}
#endif
return _newJSONNode(orig);
}
JSONNode * JSONNode::newJSONNode(internalJSONNode * internal_t) {
#ifdef JSON_MEMORY_POOL
return new((JSONNode*)json_node_mempool.allocate()) JSONNode(internal_t);
#elif defined(JSON_MEMORY_CALLBACKS)
return new(json_malloc<JSONNode>(1)) JSONNode(internal_t);
#else
return new JSONNode(internal_t);
#endif
}
JSONNode * JSONNode::newJSONNode_Shallow(const JSONNode & orig) {
#ifdef JSON_MEMORY_POOL
return new((JSONNode*)json_node_mempool.allocate()) JSONNode(true, const_cast<JSONNode &>(orig));
#elif defined(JSON_MEMORY_CALLBACKS)
return new(json_malloc<JSONNode>(1)) JSONNode(true, const_cast<JSONNode &>(orig));
#else
return new JSONNode(true, const_cast<JSONNode &>(orig));
#endif
}

View file

@ -0,0 +1,985 @@
#ifndef JSONNODE_H
#define JSONNODE_H
#include "JSONDebug.h" //for string type
#include "internalJSONNode.h" //internal structure for json value
#include <stdexcept>
#include <cstdarg> //for the ... parameter
#ifdef JSON_BINARY
#include "JSON_Base64.h"
#endif
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(push, 1)
#elif _MSC_VER
#pragma pack(push, JSONNode_pack, 1)
#endif
#endif
#ifndef JSON_REF_COUNT
#define makeUniqueInternal() (void)0
#endif
#define JSON_CHECK_INTERNAL() JSON_ASSERT(internal != 0, JSON_TEXT("no internal"))
#ifdef JSON_MUTEX_CALLBACKS
#define JSON_MUTEX_COPY_DECL ,void * parentMutex
#define JSON_MUTEX_COPY_DECL2 ,void * parentMutex = 0
#else
#define JSON_MUTEX_COPY_DECL
#define JSON_MUTEX_COPY_DECL2
#endif
#ifdef JSON_LIBRARY
#define JSON_PTR_LIB *
#define JSON_NEW(x) JSONNode::newJSONNode_Shallow(x)
#define DECLARE_FOR_ALL_TYPES(foo)\
foo(json_int_t)json_nothrow;\
foo(json_number) json_nothrow;\
foo(bool) json_nothrow;\
foo(const json_string &) json_nothrow;
#define DECLARE_FOR_ALL_CAST_TYPES_CONST(foo)\
foo(json_int_t) const json_nothrow;\
foo(json_number) const json_nothrow;\
foo(bool) const json_nothrow;\
foo(const json_string &) const json_nothrow;\
#define DECLARE_FOR_ALL_TYPES_CONST(foo)\
DECLARE_FOR_ALL_CAST_TYPES_CONST(foo)\
foo(const JSONNode &) const json_nothrow;
#define IMPLEMENT_FOR_ALL_NUMBERS(foo)\
foo(json_int_t)\
foo(json_number)
#else
#define JSON_PTR_LIB
#define JSON_NEW(x) x
#ifdef JSON_ISO_STRICT
#define DECLARE_FOR_LONG_LONG(foo)
#define DECLARE_FOR_LONG_LONG_CONST(foo)
#define IMPLEMENT_FOR_LONG_LONG(foo)
#define DECLARE_FOR_LONG_DOUBLE(foo)
#define DECLARE_FOR_LONG_DOUBLE_CONST(foo)
#define IMPLEMENT_FOR_LONG_DOUBLE(foo)
#else
#define DECLARE_FOR_LONG_LONG(foo) foo(long long) json_nothrow; foo(unsigned long long) json_nothrow;
#define DECLARE_FOR_LONG_LONG_CONST(foo) foo(long long) const json_nothrow; foo(unsigned long long) const json_nothrow;
#define IMPLEMENT_FOR_LONG_LONG(foo) foo(long long) foo(unsigned long long)
#define DECLARE_FOR_LONG_DOUBLE(foo) foo(long double) json_nothrow;
#define DECLARE_FOR_LONG_DOUBLE_CONST(foo) foo(long double) const json_nothrow;
#define IMPLEMENT_FOR_LONG_DOUBLE(foo) foo(long double)
#endif
#define DECLARE_FOR_ALL_TYPES(foo)\
foo(char) json_nothrow; foo(unsigned char) json_nothrow;\
foo(short) json_nothrow; foo(unsigned short) json_nothrow;\
foo(int) json_nothrow; foo(unsigned int) json_nothrow;\
foo(long) json_nothrow; foo(unsigned long) json_nothrow;\
foo(float) json_nothrow; foo(double) json_nothrow;\
foo(bool) json_nothrow;\
foo(const json_string &) json_nothrow;\
foo(const json_char *) json_nothrow;\
DECLARE_FOR_LONG_LONG(foo)\
DECLARE_FOR_LONG_DOUBLE(foo)
#define DECLARE_FOR_ALL_CAST_TYPES_CONST(foo)\
foo(char) const json_nothrow; foo(unsigned char) const json_nothrow;\
foo(short) const json_nothrow; foo(unsigned short) const json_nothrow;\
foo(int) const json_nothrow; foo(unsigned int) const json_nothrow;\
foo(long) const json_nothrow; foo(unsigned long) const json_nothrow;\
foo(float) const json_nothrow; foo(double) const json_nothrow;\
foo(bool) const json_nothrow;\
foo(const json_string &) const json_nothrow;\
DECLARE_FOR_LONG_LONG_CONST(foo)\
DECLARE_FOR_LONG_DOUBLE_CONST(foo)
#define DECLARE_FOR_ALL_TYPES_CONST(foo)\
DECLARE_FOR_ALL_CAST_TYPES_CONST(foo)\
foo(const JSONNode &) const json_nothrow;\
foo(const json_char *) const json_nothrow;
#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)\
IMPLEMENT_FOR_LONG_LONG(foo)\
IMPLEMENT_FOR_LONG_DOUBLE(foo)
#endif
#define IMPLEMENT_FOR_ALL_TYPES(foo)\
IMPLEMENT_FOR_ALL_NUMBERS(foo)\
foo(const json_string &)\
foo(bool)
/*
This class is mostly just a wrapper class around internalJSONNode, this class keeps
the reference count and handles copy on write and such. This class is also responsible
for argument checking and throwing exceptions if needed.
*/
class JSONNode {
public:
LIBJSON_OBJECT(JSONNode);
explicit JSONNode(char mytype = JSON_NODE) json_nothrow json_hot;
#define DECLARE_CTOR(type) explicit JSONNode(const json_string & name_t, type value_t)
DECLARE_FOR_ALL_TYPES(DECLARE_CTOR)
JSONNode(const JSONNode & orig) json_nothrow json_hot;
~JSONNode(void) json_nothrow json_hot;
#if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY))
static JSONNode stringType(const json_string & str);
void set_name_(const json_string & newname) json_nothrow json_write_priority;
#endif
json_index_t size(void) const json_nothrow json_read_priority;
bool empty(void) const json_nothrow json_read_priority;
void clear(void) json_nothrow json_cold;
unsigned char type(void) const json_nothrow json_read_priority;
json_string name(void) const json_nothrow json_read_priority;
void set_name(const json_string & newname) json_nothrow json_write_priority;
#ifdef JSON_COMMENTS
void set_comment(const json_string & comment) json_nothrow;
json_string get_comment(void) const json_nothrow;
#endif
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
void preparse(void) json_nothrow json_read_priority;
#endif
json_string as_string(void) const json_nothrow json_read_priority;
json_int_t as_int(void) const json_nothrow json_read_priority;
json_number as_float(void) const json_nothrow json_read_priority;
bool as_bool(void) const json_nothrow json_read_priority;
#ifdef JSON_CASTABLE
JSONNode as_node(void) const json_nothrow json_read_priority;
JSONNode as_array(void) const json_nothrow json_read_priority;
void cast(char newtype) json_nothrow;
#endif
#ifdef JSON_BINARY
std::string as_binary(void) const json_nothrow json_cold;
void set_binary(const unsigned char * bin, size_t bytes) json_nothrow json_cold;
#endif
JSONNode & at(json_index_t pos) json_throws(std::out_of_range);
const JSONNode & at(json_index_t pos) const json_throws(std::out_of_range);
JSONNode & operator[](json_index_t pos) json_nothrow;
const JSONNode & operator[](json_index_t pos) const json_nothrow;
JSONNode & at(const json_string & name_t) json_throws(std::out_of_range);
const JSONNode & at(const json_string & name_t) const json_throws(std::out_of_range);
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode & at_nocase(const json_string & name_t) json_throws(std::out_of_range);
const JSONNode & at_nocase(const json_string & name_t) const json_throws(std::out_of_range);
#endif
JSONNode & operator[](const json_string & name_t) json_nothrow;
const JSONNode & operator[](const json_string & name_t) const json_nothrow;
#ifdef JSON_LIBRARY
void push_back(JSONNode * node) json_nothrow;
#else
void push_back(const JSONNode & node) json_nothrow;
#endif
void reserve(json_index_t siz) json_nothrow;
JSONNode JSON_PTR_LIB pop_back(json_index_t pos) json_throws(std::out_of_range);
JSONNode JSON_PTR_LIB pop_back(const json_string & name_t) json_throws(std::out_of_range);
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode JSON_PTR_LIB pop_back_nocase(const json_string & name_t) json_throws(std::out_of_range);
#endif
DECLARE_FOR_ALL_TYPES(JSONNode & operator =)
JSONNode & operator = (const JSONNode &) json_nothrow;
DECLARE_FOR_ALL_TYPES_CONST(bool operator ==)
DECLARE_FOR_ALL_TYPES_CONST(bool operator !=)
void nullify(void) json_nothrow;
void swap(JSONNode & other) json_nothrow;
void merge(JSONNode & other) json_nothrow json_cold;
void merge(unsigned int num, ...) json_nothrow json_cold;
JSONNode duplicate(void) const json_nothrow;
//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;
struct const_iterator {
inline const_iterator& operator ++(void) json_nothrow { ++it; return *this; }
inline const_iterator& operator --(void) json_nothrow { --it; return *this; }
inline const_iterator& operator +=(long i) json_nothrow { it += i; return *this; }
inline const_iterator& operator -=(long i) json_nothrow { it -= i; return *this; }
inline const_iterator operator ++(int) json_nothrow {
const_iterator result(*this);
++it;
return result;
}
inline const_iterator operator --(int) json_nothrow {
const_iterator result(*this);
--it;
return result;
}
inline const_iterator operator +(long i) const json_nothrow {
const_iterator result(*this);
result.it += i;
return result;
}
inline const_iterator operator -(long i) const json_nothrow {
const_iterator result(*this);
result.it -= i;
return result;
}
inline const JSONNode& operator [](size_t pos) const json_nothrow { return const_cast<const JSONNode&>(*it[pos]); };
inline const JSONNode& operator *(void) const json_nothrow { return const_cast<const JSONNode&>(*(*it)); }
inline const JSONNode* operator ->(void) const json_nothrow { return const_cast<const JSONNode*>(*it); }
inline bool operator == (const const_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const const_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const const_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const const_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const const_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const const_iterator & other) const json_nothrow { return it <= other.it; }
inline bool operator == (const iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const iterator & other) const json_nothrow { return it <= other.it; }
inline const_iterator & operator =(const const_iterator & orig) json_nothrow { it = orig.it; return *this; }
const_iterator (const const_iterator & orig) json_nothrow : it(orig.it) {}
private:
JSONNode ** it;
const_iterator(JSONNode ** starter) : it(starter) {}
friend class JSONNode;
friend struct iterator;
};
const_iterator begin(void) const json_nothrow;
const_iterator end(void) const json_nothrow;
struct iterator {
inline iterator& operator ++(void) json_nothrow { ++it; return *this; }
inline iterator& operator --(void) json_nothrow { --it; return *this; }
inline iterator& operator +=(long i) json_nothrow { it += i; return *this; }
inline iterator& operator -=(long i) json_nothrow { it -= i; return *this; }
inline iterator operator ++(int) json_nothrow {
iterator result(*this);
++it;
return result;
}
inline iterator operator --(int) json_nothrow {
iterator result(*this);
--it;
return result;
}
inline iterator operator +(long i) const json_nothrow {
iterator result(*this);
result.it += i;
return result;
}
inline iterator operator -(long i) const json_nothrow {
iterator result(*this);
result.it -= i;
return result;
}
inline JSONNode& operator [](size_t pos) const json_nothrow { return *it[pos]; };
inline JSONNode& operator *(void) const json_nothrow { return *(*it); }
inline JSONNode* operator ->(void) const json_nothrow { return *it; }
inline bool operator == (const iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const iterator & other) const json_nothrow { return it <= other.it; }
inline iterator & operator = (const iterator & orig) json_nothrow { it = orig.it; return *this; }
inline bool operator == (const const_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const const_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const const_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const const_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const const_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const const_iterator & other) const json_nothrow { return it <= other.it; }
inline iterator & operator = (const const_iterator & orig) json_nothrow { it = orig.it; return *this; }
iterator (const iterator & orig) json_nothrow : it(orig.it) {}
inline operator const_iterator() const json_nothrow { return const_iterator(it); }
private:
JSONNode ** it;
iterator(JSONNode ** starter) json_nothrow : it(starter) {}
friend class JSONNode;
friend struct const_iterator;
};
typedef iterator json_iterator;
struct reverse_iterator;
struct reverse_const_iterator {
inline reverse_const_iterator& operator ++(void) json_nothrow{ --it; return *this; }
inline reverse_const_iterator& operator --(void) json_nothrow{ ++it; return *this; }
inline reverse_const_iterator& operator +=(long i) json_nothrow{ it -= i; return *this; }
inline reverse_const_iterator& operator -=(long i) json_nothrow{ it += i; return *this; }
inline reverse_const_iterator operator ++(int) json_nothrow{
reverse_const_iterator result(*this);
--it;
return result;
}
inline reverse_const_iterator operator --(int) json_nothrow{
reverse_const_iterator result(*this);
++it;
return result;
}
inline reverse_const_iterator operator +(long i) const json_nothrow {
reverse_const_iterator result(*this);
result.it -= i;
return result;
}
inline reverse_const_iterator operator -(long i) const json_nothrow {
reverse_const_iterator result(*this);
result.it += i;
return result;
}
inline const JSONNode& operator [](size_t pos) const json_nothrow { return const_cast<const JSONNode&>(*it[pos]); };
inline const JSONNode& operator *(void) const json_nothrow { return const_cast<const JSONNode&>(*(*it)); }
inline const JSONNode* operator ->(void) const json_nothrow { return const_cast<const JSONNode*>(*it); }
inline bool operator == (const reverse_const_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const reverse_const_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator < (const reverse_const_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator <= (const reverse_const_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator > (const reverse_const_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator >= (const reverse_const_iterator & other) const json_nothrow { return it <= other.it; }
inline bool operator == (const reverse_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const reverse_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator < (const reverse_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator <= (const reverse_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator > (const reverse_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator >= (const reverse_iterator & other) const json_nothrow { return it <= other.it; }
inline reverse_const_iterator & operator = (const reverse_const_iterator & orig) json_nothrow { it = orig.it; return *this; }
reverse_const_iterator (const reverse_const_iterator & orig) json_nothrow : it(orig.it) {}
private:
JSONNode ** it;
reverse_const_iterator(JSONNode ** starter) json_nothrow : it(starter) {}
friend class JSONNode;
friend struct reverse_iterator;
};
reverse_const_iterator rbegin(void) const json_nothrow;
reverse_const_iterator rend(void) const json_nothrow;
struct reverse_iterator {
inline reverse_iterator& operator ++(void) json_nothrow { --it; return *this; }
inline reverse_iterator& operator --(void) json_nothrow { ++it; return *this; }
inline reverse_iterator& operator +=(long i) json_nothrow { it -= i; return *this; }
inline reverse_iterator& operator -=(long i) json_nothrow { it += i; return *this; }
inline reverse_iterator operator ++(int) json_nothrow {
reverse_iterator result(*this);
--it;
return result;
}
inline reverse_iterator operator --(int) json_nothrow {
reverse_iterator result(*this);
++it;
return result;
}
inline reverse_iterator operator +(long i) const json_nothrow {
reverse_iterator result(*this);
result.it -= i;
return result;
}
inline reverse_iterator operator -(long i) const json_nothrow {
reverse_iterator result(*this);
result.it += i;
return result;
}
inline JSONNode& operator [](size_t pos) const json_nothrow { return *it[pos]; };
inline JSONNode& operator *(void) const json_nothrow { return *(*it); }
inline JSONNode* operator ->(void) const json_nothrow { return *it; }
inline bool operator == (const reverse_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const reverse_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator < (const reverse_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator <= (const reverse_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator > (const reverse_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator >= (const reverse_iterator & other) const json_nothrow { return it <= other.it; }
inline bool operator == (const reverse_const_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const reverse_const_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator < (const reverse_const_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator <= (const reverse_const_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator > (const reverse_const_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator >= (const reverse_const_iterator & other) const json_nothrow { return it <= other.it; }
inline reverse_iterator & operator = (const reverse_iterator & orig) json_nothrow { it = orig.it; return *this; }
reverse_iterator (const reverse_iterator & orig) json_nothrow : it(orig.it) {}
inline operator reverse_const_iterator() const json_nothrow { return reverse_const_iterator(it); }
private:
JSONNode ** it;
reverse_iterator(JSONNode ** starter) json_nothrow : it(starter) {}
friend class JSONNode;
friend struct reverse_const_iterator;
};
reverse_iterator rbegin(void) json_nothrow;
reverse_iterator rend(void) json_nothrow;
const_iterator find(const json_string & name_t) const json_nothrow;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
const_iterator find_nocase(const json_string & name_t) const json_nothrow;
#endif
reverse_iterator erase(reverse_iterator pos) json_nothrow;
reverse_iterator erase(reverse_iterator start, const reverse_iterator & end) json_nothrow;
iterator insert(iterator pos, const JSONNode & x) json_nothrow;
reverse_iterator insert(reverse_iterator pos, const JSONNode & x) json_nothrow;
iterator insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end) json_nothrow;
reverse_iterator insert(reverse_iterator pos, const iterator & _start, const iterator & _end) json_nothrow;
reverse_iterator insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end) json_nothrow;
json_iterator insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end) json_nothrow;
reverse_iterator insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end) json_nothrow;
json_iterator insert(json_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end) json_nothrow;
reverse_iterator insert(reverse_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end) json_nothrow;
#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) json_nothrow;
#endif
json_iterator begin(void) json_nothrow;
json_iterator end(void) json_nothrow;
json_iterator find(const json_string & name_t) json_nothrow;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
json_iterator find_nocase(const json_string & name_t) json_nothrow;
#endif
json_iterator erase(json_iterator pos) json_nothrow;
json_iterator erase(json_iterator start, const json_iterator & end) json_nothrow;
json_iterator insert(json_iterator pos, const json_iterator & _start, const json_iterator & _end) json_nothrow;
#endif
#ifdef JSON_MUTEX_CALLBACKS
static void register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock) json_nothrow json_cold;
#ifdef JSON_MUTEX_MANAGE
static void register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow json_cold;
#endif
static void set_global_mutex(void * mutex) json_nothrow json_cold;
void set_mutex(void * mutex) json_nothrow json_cold;
void lock(int thread) json_nothrow json_cold;
void unlock(int thread) json_nothrow json_cold;
struct auto_lock {
public:
auto_lock(JSONNode & node, int thread) json_nothrow: mynode(&node), mythread(thread){
mynode -> lock(mythread);
}
auto_lock(JSONNode * node, int thread) json_nothrow: mynode(node), mythread(thread){
mynode -> lock(mythread);
}
~auto_lock(void) json_nothrow{
mynode -> unlock(mythread);
}
private:
auto_lock & operator = (const auto_lock &);
auto_lock(const auto_lock &);
JSONNode * mynode;
int mythread;
};
static void * getThisLock(JSONNode * pthis) json_nothrow json_cold;
#endif
#ifdef JSON_WRITE_PRIORITY
#ifdef JSON_LESS_MEMORY
#define DEFAULT_APPROX_SIZE 8
#define DEFAULT_APPROX_SIZE_FORMATTED 16
#else
#define DEFAULT_APPROX_SIZE 1024
#define DEFAULT_APPROX_SIZE_FORMATTED 2048
#endif
json_string write(size_t approxsize = DEFAULT_APPROX_SIZE) const json_nothrow json_write_priority;
json_string write_formatted(size_t approxsize = DEFAULT_APPROX_SIZE_FORMATTED) const json_nothrow json_write_priority;
#endif
#ifdef JSON_DEBUG
#ifndef JSON_LIBRARY
JSONNode dump(void) const json_nothrow;
#endif
#endif
static void deleteJSONNode(JSONNode * ptr) json_nothrow json_hot;
static JSONNode * newJSONNode_Shallow(const JSONNode & orig) json_hot;
#define DECLARE_CAST_OP(type) operator type()
//DECLARE_FOR_ALL_CAST_TYPES_CONST(DECLARE_CAST_OP)
JSON_PRIVATE
static JSONNode * newJSONNode(const JSONNode & orig JSON_MUTEX_COPY_DECL2) json_hot;
static JSONNode * newJSONNode(internalJSONNode * internal_t) json_hot;
#ifdef JSON_READ_PRIORITY
//used by JSONWorker
JSONNode(const json_string & unparsed) json_nothrow : internal(internalJSONNode::newInternal(unparsed)){ //root, specialized because it can only be array or node
LIBJSON_CTOR;
}
#endif
JSONNode(internalJSONNode * internal_t) json_nothrow : internal(internal_t){ //do not increment anything, this is only used in one case and it's already taken care of
LIBJSON_CTOR;
}
JSONNode(bool, JSONNode & orig) json_nothrow json_hot;
void decRef(void) json_nothrow json_hot; //decrements internal's counter, deletes it if needed
#ifdef JSON_REF_COUNT
void makeUniqueInternal(void) json_nothrow; //makes internal it's own
void merge(JSONNode * other) json_nothrow json_cold;
#endif
#ifdef JSON_DEBUG
#ifndef JSON_LIBRARY
JSONNode dump(size_t & totalmemory) json_nothrow;
#endif
#endif
#ifdef JSON_ITERATORS
#ifndef JSON_LIBRARY
json_iterator insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow;
reverse_iterator insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow;
reverse_iterator insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow;
#endif
json_iterator insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end) json_nothrow;
#endif
inline void clear_name(void) json_nothrow {
JSON_CHECK_INTERNAL();
makeUniqueInternal();
internal -> clearname();
}
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.
*/
#define CAST_OP(type)\
inline JSONNode::operator type() const json_nothrow {\
return static_cast<type>(*internal);\
}
//IMPLEMENT_FOR_ALL_TYPES(CAST_OP)
inline JSONNode::JSONNode(char mytype) json_nothrow : 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"));
LIBJSON_CTOR;
}
inline JSONNode::JSONNode(const JSONNode & orig) json_nothrow : internal(orig.internal -> incRef()){
LIBJSON_COPY_CTOR;
}
//this allows a temp node to simply transfer its contents, even with ref counting off
inline JSONNode::JSONNode(bool, JSONNode & orig) json_nothrow : internal(orig.internal){
orig.internal = 0;
LIBJSON_CTOR;
}
inline JSONNode::~JSONNode(void) json_nothrow{
if (internal != 0) decRef();
LIBJSON_DTOR;
}
inline json_index_t JSONNode::size(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> size();
}
inline bool JSONNode::empty(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> empty();
}
inline void JSONNode::clear(void) json_nothrow {
JSON_CHECK_INTERNAL();
if (!empty()){
makeUniqueInternal();
internal -> CHILDREN -> clear();
}
}
inline unsigned char JSONNode::type(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> type();
}
inline json_string JSONNode::name(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> name();
}
inline void JSONNode::set_name(const json_string & newname) json_nothrow{
JSON_CHECK_INTERNAL();
makeUniqueInternal();
internal -> setname(newname);
}
#ifdef JSON_COMMENTS
inline void JSONNode::set_comment(const json_string & newname) json_nothrow{
JSON_CHECK_INTERNAL();
makeUniqueInternal();
internal -> setcomment(newname);
}
inline json_string JSONNode::get_comment(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> getcomment();
}
#endif
//#ifdef JSON_DEPRECATED_FUNCTIONS
inline json_string JSONNode::as_string(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return static_cast<json_string>(*internal);
}
inline json_int_t JSONNode::as_int(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return static_cast<json_int_t>(*internal);
}
inline json_number JSONNode::as_float(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return static_cast<json_number>(*internal);
}
inline bool JSONNode::as_bool(void) const json_nothrow {
JSON_CHECK_INTERNAL();
return static_cast<bool>(*internal);
}
//#endif
#ifdef JSON_BINARY
inline void JSONNode::set_binary(const unsigned char * bin, size_t bytes) json_nothrow{
JSON_CHECK_INTERNAL();
*this = JSONBase64::json_encode64(bin, bytes);
}
inline std::string JSONNode::as_binary(void) const json_nothrow {
JSON_ASSERT_SAFE(type() == JSON_STRING, JSON_TEXT("using as_binary for a non-string type"), return json_global(EMPTY_STD_STRING););
JSON_CHECK_INTERNAL();
return JSONBase64::json_decode64(as_string());
}
#endif
inline JSONNode & JSONNode::operator[](const json_string & name_t) json_nothrow {
JSON_CHECK_INTERNAL();
makeUniqueInternal();
return *(*(internal -> at(name_t)));
}
inline const JSONNode & JSONNode::operator[](const json_string & name_t) const json_nothrow {
JSON_CHECK_INTERNAL();
return *(*(internal -> at(name_t)));
}
#ifdef JSON_LIBRARY
inline void JSONNode::push_back(JSONNode * child) json_nothrow{
#else
inline void JSONNode::push_back(const JSONNode & child) json_nothrow{
#endif
JSON_CHECK_INTERNAL();
makeUniqueInternal();
internal -> push_back(child);
}
inline void JSONNode::reserve(json_index_t siz) json_nothrow{
makeUniqueInternal();
internal -> reserve(siz);
}
inline JSONNode & JSONNode::operator = (const JSONNode & orig) json_nothrow {
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_nothrow {
JSON_CHECK_INTERNAL();
*this = json_string(val);
return *this;
}
#endif
#define NODE_SET_TYPED(type)\
inline JSONNode & JSONNode::operator = (type val) json_nothrow {\
LIBJSON_ASSIGNMENT;\
JSON_CHECK_INTERNAL();\
makeUniqueInternal();\
internal -> Set(val);\
return *this;\
}
IMPLEMENT_FOR_ALL_TYPES(NODE_SET_TYPED)
/*
This section is the equality operators
*/
#define NODE_CHECK_EQUALITY(type)\
inline bool JSONNode::operator == (type val) const json_nothrow {\
JSON_CHECK_INTERNAL();\
return internal -> IsEqualToNum<type>(val);\
}
IMPLEMENT_FOR_ALL_NUMBERS(NODE_CHECK_EQUALITY)
inline bool JSONNode::operator == (const json_string & val) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> IsEqualTo(val);
}
#ifndef JSON_LIBRARY
inline bool JSONNode::operator == (const json_char * val) const json_nothrow {
JSON_CHECK_INTERNAL();
return *this == json_string(val);
}
#endif
inline bool JSONNode::operator == (bool val) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> IsEqualTo(val);
}
inline bool JSONNode::operator == (const JSONNode & val) const json_nothrow {
JSON_CHECK_INTERNAL();
return internal -> IsEqualTo(val.internal);
}
/*
This section is the inequality operators
*/
#define NODE_CHECK_INEQUALITY(type)\
inline bool JSONNode::operator != (type val) const json_nothrow {\
JSON_CHECK_INTERNAL();\
return !(*this == val);\
}
IMPLEMENT_FOR_ALL_TYPES(NODE_CHECK_INEQUALITY)
NODE_CHECK_INEQUALITY(const JSONNode &)
#ifndef JSON_LIBRARY
NODE_CHECK_INEQUALITY(const json_char * )
#endif
inline void JSONNode::nullify(void) json_nothrow {
JSON_CHECK_INTERNAL();
makeUniqueInternal();
internal -> Nullify();
}
inline void JSONNode::swap(JSONNode & other) json_nothrow {
JSON_CHECK_INTERNAL();
internalJSONNode * temp = other.internal;
other.internal = internal;
internal = temp;
JSON_CHECK_INTERNAL();
}
inline void JSONNode::decRef(void) json_nothrow { //decrements internal's counter, deletes it if needed
JSON_CHECK_INTERNAL();
#ifdef JSON_REF_COUNT
internal -> decRef();
if (internal -> hasNoReferences()){
internalJSONNode::deleteInternal(internal);
}
#else
internalJSONNode::deleteInternal(internal);
#endif
}
#ifdef JSON_REF_COUNT
inline void JSONNode::makeUniqueInternal() json_nothrow { //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_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("begin"));
makeUniqueInternal();
return json_iterator(internal -> begin());
}
inline JSONNode::json_iterator JSONNode::end(void) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("end"));
makeUniqueInternal();
return json_iterator(internal -> end());
}
#ifndef JSON_LIBRARY
inline JSONNode::const_iterator JSONNode::begin(void) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("begin"));
return JSONNode::const_iterator(internal -> begin());
}
inline JSONNode::const_iterator JSONNode::end(void) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("end"));
return JSONNode::const_iterator(internal -> end());
}
inline JSONNode::reverse_iterator JSONNode::rbegin(void) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("rbegin"));
makeUniqueInternal();
return JSONNode::reverse_iterator(internal -> end() - 1);
}
inline JSONNode::reverse_iterator JSONNode::rend(void) json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("rend"));
makeUniqueInternal();
return JSONNode::reverse_iterator(internal -> begin() - 1);
}
inline JSONNode::reverse_const_iterator JSONNode::rbegin(void) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("rbegin"));
return JSONNode::reverse_const_iterator(internal -> end() - 1);
}
inline JSONNode::reverse_const_iterator JSONNode::rend(void) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, json_global(ERROR_NON_ITERATABLE) + JSON_TEXT("rend"));
return JSONNode::reverse_const_iterator(internal -> begin() - 1);
}
inline JSONNode::iterator JSONNode::insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end) json_nothrow {
return insertFFF(pos, _start.it, _end.it);
}
inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end) json_nothrow {
return insertRFF(pos, _start.it, _end.it);
}
inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const iterator & _start, const iterator & _end) json_nothrow {
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) json_nothrow {
return insertRRR(pos, _start.it, _end.it);
}
inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end) json_nothrow {
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) json_nothrow {
return insertFRR(pos, _start.it, _end.it);
}
inline JSONNode::iterator JSONNode::insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end) json_nothrow {
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) json_nothrow {
return insertFFF(pos, json_iterator_ptr(_start), json_iterator_ptr(_end));
}
#endif
#ifdef JSON_WRITE_PRIORITY
inline json_string JSONNode::write(size_t approxsize) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return json_global(EMPTY_JSON_STRING););
json_string result;
result.reserve(approxsize);
internal -> Write(0xFFFFFFFF, true, result);
return result;
}
inline json_string JSONNode::write_formatted(size_t approxsize) const json_nothrow {
JSON_CHECK_INTERNAL();
JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return json_global(EMPTY_JSON_STRING););
json_string result;
result.reserve(approxsize);
internal -> Write(0, true, result);
return result;
}
#endif
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
inline void JSONNode::preparse(void) json_nothrow {
JSON_CHECK_INTERNAL();
internal -> preparse();
}
#endif
#ifdef JSON_DEBUG
#ifndef JSON_LIBRARY
inline JSONNode JSONNode::dump(void) const json_nothrow {
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_nothrow {
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
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(pop)
#elif _MSC_VER
#pragma pack(pop, JSONNode_pack)
#endif
#endif
#endif

View file

@ -0,0 +1,203 @@
#include "JSONNode.h"
#include "JSONGlobals.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 {
public:
LIBJSON_OBJECT(AutoLock);
AutoLock(void) json_nothrow {
LIBJSON_CTOR;
json_lock_callback(manager_mutex);
}
~AutoLock(void) json_nothrow {
LIBJSON_DTOR;
json_unlock_callback(manager_mutex);
}
private:
AutoLock(const AutoLock &);
AutoLock & operator = (const AutoLock &);
};
#ifdef JSON_MUTEX_MANAGE
json_mutex_callback_t json_destroy = 0;
//make sure that the global mutex is taken care of too
struct auto_global {
public:
LIBJSON_OBJECT(auto_global;)
auto_global(void) json_nothrow { LIBJSON_CTOR; }
~auto_global(void) json_nothrow {
LIBJSON_DTOR;
if (global_mutex){
JSON_ASSERT_SAFE(json_destroy != 0, JSON_TEXT("No json_destroy in mutex managed mode"), return;);
json_destroy(global_mutex);
}
}
private:
auto_global(const auto_global &);
auto_global & operator = (const auto_global &);
};
auto_global cleanupGlobal;
#endif
void JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock) json_nothrow {
json_lock_callback = lock;
json_unlock_callback = unlock;
manager_mutex = manager_lock;
}
void JSONNode::set_global_mutex(void * mutex) json_nothrow {
global_mutex = mutex;
}
void JSONNode::set_mutex(void * mutex) json_nothrow {
makeUniqueInternal();
internal -> _set_mutex(mutex);
}
void * JSONNode::getThisLock(JSONNode * pthis) json_nothrow {
if (pthis -> internal -> mylock != 0){
return pthis -> internal -> mylock;
}
JSON_ASSERT(global_mutex != 0, JSON_TEXT("No global_mutex")); //this is safe, because it's just goingi to return 0 anyway
return global_mutex;
}
void JSONNode::lock(int thread) json_nothrow {
JSON_ASSERT_SAFE(json_lock_callback != 0, JSON_TEXT("No locking callback"), return;);
AutoLock lockControl;
//first, figure out what needs to be locked
void * thislock = getThisLock(this);
#ifdef JSON_SAFE
if (json_unlikely(thislock == 0)) return;
#endif
//make sure that the same thread isn't locking it more than once (possible due to complex ref counting)
JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread);
if (it == json_global(THREAD_LOCKS).end()){
JSON_MAP(void *, unsigned int) newthread;
newthread[thislock] = 1;
json_global(THREAD_LOCKS).insert(std::pair<int, JSON_MAP(void *, unsigned int) >(thread, newthread));
} else { //this thread already has some things locked, check if the current mutex is
JSON_MAP(void *, unsigned int) & newthread = it -> second;
JSON_MAP(void *, unsigned int)::iterator locker(newthread.find(thislock));
if (locker == newthread.end()){ //current mutex is not locked, set it to locked
newthread.insert(std::pair<void *, unsigned int>(thislock, 1));
} else { //it's already locked, don't relock it
++(locker -> second);
return; //don't try to relock, it will deadlock the program
}
}
//if I need to, lock it
json_lock_callback(thislock);
}
void JSONNode::unlock(int thread) json_nothrow{
JSON_ASSERT_SAFE(json_unlock_callback != 0, 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 == 0) return;
#endif
//get it out of the map
JSON_MAP(int, JSON_MAP(void *, unsigned int) )::iterator it = json_global(THREAD_LOCKS).find(thread);
JSON_ASSERT_SAFE(it != json_global(THREAD_LOCKS).end(), JSON_TEXT("thread unlocking something it didn't lock"), return;);
//get the mutex out of the thread
JSON_MAP(void *, unsigned int) & newthread = it -> second;
JSON_MAP(void *, unsigned int)::iterator locker = newthread.find(thislock);
JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;);
//unlock it
if (--(locker -> second)) return; //other nodes is this same thread still have a lock on it
//if I need to, unlock it
newthread.erase(locker);
json_unlock_callback(thislock);
}
#ifdef JSON_MUTEX_MANAGE
void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy) json_nothrow {
json_destroy = destroy;
}
#endif
void internalJSONNode::_set_mutex(void * mutex, bool unset) json_nothrow {
if (unset) _unset_mutex(); //for reference counting
mylock = mutex;
if (mutex != 0){
#ifdef JSON_MUTEX_MANAGE
JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mutex);
if (it == json_global(MUTEX_MANAGER).end()){
json_global(MUTEX_MANAGER).insert(std::pair<void *, unsigned int>(mutex, 1));
} else {
++it -> second;
}
#endif
if (isContainer()){
json_foreach(CHILDREN, myrunner){
(*myrunner) -> set_mutex(mutex);
}
}
}
}
void internalJSONNode::_unset_mutex(void) json_nothrow {
#ifdef JSON_MUTEX_MANAGE
if (mylock != 0){
JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock);
JSON_ASSERT_SAFE(it != json_global(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;);
json_global(MUTEX_MANAGER).erase(it);
}
}
#endif
}
#ifdef JSON_DEBUG
#ifndef JSON_LIBRARY
JSONNode internalJSONNode::DumpMutex(void) const json_nothrow {
JSONNode mut(JSON_NODE);
mut.set_name(JSON_TEXT("mylock"));
#ifdef JSON_MUTEX_MANAGE
if (mylock != 0){
mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock)));
JSON_MAP(void *, unsigned int)::iterator it = json_global(MUTEX_MANAGER).find(mylock);
if (it == json_global(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

View file

@ -0,0 +1,499 @@
/*
* JSONPreparse.cpp
* TestSuite
*
* Created by Wallace on 4/13/11.
* Copyright 2011 Streamwide. All rights reserved.
*
*/
#include "JSONPreparse.h"
#if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY))
#ifdef JSON_COMMENTS
json_string extractComment(json_string::const_iterator & ptr, json_string::const_iterator & end);
json_string extractComment(json_string::const_iterator & ptr, json_string::const_iterator & end){
json_string::const_iterator start;
json_string result;
looplabel:
if (json_unlikely(((ptr != end) && (*ptr == JSON_TEMP_COMMENT_IDENTIFIER)))){
start = ++ptr;
for(; (ptr != end) && (*(ptr) != JSON_TEMP_COMMENT_IDENTIFIER); ++ptr){}
result += json_string(start, ptr);
if (json_unlikely(ptr == end)) return result;
++ptr;
if (json_unlikely(((ptr != end) && (*ptr == JSON_TEMP_COMMENT_IDENTIFIER)))){
result += JSON_TEXT('\n');
goto looplabel;
}
}
return result;
}
#define GET_COMMENT(x, y, name) json_string name = extractComment(x, y)
#define RETURN_NODE(node, name){\
JSONNode res = node;\
res.set_comment(name);\
return res;\
}
#define RETURN_NODE_NOCOPY(node, name){\
node.set_comment(name);\
return node;\
}
#define SET_COMMENT(node, name) node.set_comment(name)
#define COMMENT_ARG(name) ,name
#else
#define GET_COMMENT(x, y, name) (void)0
#define RETURN_NODE(node, name) return node
#define RETURN_NODE_NOCOPY(node, name) return node
#define SET_COMMENT(node, name) (void)0
#define COMMENT_ARG(name)
#endif
inline bool isHex(json_char c) json_pure;
inline bool isHex(json_char c) json_nothrow {
return (((c >= JSON_TEXT('0')) && (c <= JSON_TEXT('9'))) ||
((c >= JSON_TEXT('A')) && (c <= JSON_TEXT('F'))) ||
((c >= JSON_TEXT('a')) && (c <= JSON_TEXT('f'))));
}
#ifdef JSON_STRICT
#include "NumberToString.h"
#endif
json_number FetchNumber(const json_string & _string) json_nothrow;
json_number FetchNumber(const json_string & _string) json_nothrow {
#ifdef JSON_STRICT
return NumberToString::_atof(_string.c_str());
#else
#ifdef JSON_UNICODE
const size_t len = _string.length();
#if defined(_MSC_VER) && defined(JSON_SAFE)
const size_t bytes = (len * (sizeof(json_char) / sizeof(char))) + 1;
json_auto<char> temp(bytes);
size_t res;
errno_t err = std::wcstombs_s(&res, temp.ptr, bytes, _string.c_str(), len);
if (err != 0){
return (json_number)0.0;
}
#elif defined(JSON_SAFE)
const size_t bytes = (len * (sizeof(json_char) / sizeof(char))) + 1;
json_auto<char> temp(bytes);
size_t res = std::wcstombs(temp.ptr, _string.c_str(), len);
if (res == (size_t)-1){ //-1 is error code for this function
return (json_number)0.0;
}
#else
json_auto<char> temp(len + 1);
size_t res = std::wcstombs(temp.ptr, _string.c_str(), len);
#endif
temp.ptr[res] = JSON_TEXT('\0');
return (json_number)std::atof(temp.ptr);
#else
return (json_number)std::atof(_string.c_str());
#endif
#endif
}
JSONNode JSONPreparse::isValidNumber(json_string::const_iterator & ptr, json_string::const_iterator & end){
//ptr points at the first character in the number
//ptr will end up past the last character
json_string::const_iterator start = ptr;
bool decimal = false;
bool scientific = false;
//first letter is weird
switch(*ptr){
#ifndef JSON_STRICT
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('+'):
#endif
case JSON_TEXT('-'):
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('8'):
case JSON_TEXT('9'):
break;
case JSON_TEXT('0'):
++ptr;
switch(*ptr){
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
scientific = true;
++ptr;
if (ptr == end) throw false;
switch(*ptr){
case JSON_TEXT('-'):
case JSON_TEXT('+'):
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
break;
default:
throw false;
}
break;
#ifndef JSON_STRICT
case JSON_TEXT('x'):
while(isHex(*++ptr)){};
return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, end - 1)));
#ifdef JSON_OCTAL
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('7'): //octal
#else
case JSON_TEXT('0'):
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'):
#endif
while((*++ptr >= JSON_TEXT('0')) && (*ptr <= JSON_TEXT('7'))){};
if ((*ptr != JSON_TEXT('8')) && (*ptr != JSON_TEXT('9'))){
return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, ptr - 1)));
}
throw false;
case JSON_TEXT('8'):
case JSON_TEXT('9'):
break;
#else
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
#endif
#else
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
#endif
default: //just a 0
return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, ptr - 1)));;
}
break;
default:
throw false;
}
++ptr;
//next digits
while (true){
switch(*ptr){
case JSON_TEXT('.'):
if (json_unlikely(decimal)) throw false; //multiple decimals
if (json_unlikely(scientific)) throw false;
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
if (json_likely(scientific)) throw false;
scientific = true;
++ptr;
switch(*ptr){
case JSON_TEXT('-'):
case JSON_TEXT('+'):
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
default:
throw false;
}
break;
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
default:
return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, ptr)));;
}
++ptr;
}
throw false;
}
#ifndef JSON_STRICT
#define LETTERCASE(x, y)\
case JSON_TEXT(x):\
case JSON_TEXT(y)
#define LETTERCHECK(x, y)\
if (json_unlikely((*++ptr != JSON_TEXT(x)) && (*ptr != JSON_TEXT(y)))) throw false
#else
#define LETTERCASE(x, y)\
case JSON_TEXT(x)
#define LETTERCHECK(x, y)\
if (json_unlikely(*++ptr != JSON_TEXT(x))) throw false
#endif
JSONNode JSONPreparse::isValidMember(json_string::const_iterator & ptr, json_string::const_iterator & end){
//ptr is on the first character of the member
//ptr will end up immediately after the last character in the member
if (ptr == end) throw false;
switch(*ptr){
case JSON_TEXT('\"'):{
return JSONNode::stringType(isValidString(++ptr, end));
}
case JSON_TEXT('{'):
return isValidObject(++ptr, end);
case JSON_TEXT('['):
return isValidArray(++ptr, end);
LETTERCASE('t', 'T'):
LETTERCHECK('r', 'R');
LETTERCHECK('u', 'U');
LETTERCHECK('e', 'E');
++ptr;
return JSONNode(json_global(EMPTY_JSON_STRING), true);
LETTERCASE('f', 'F'):
LETTERCHECK('a', 'A');
LETTERCHECK('l', 'L');
LETTERCHECK('s', 'S');
LETTERCHECK('e', 'E');
++ptr;
return JSONNode(json_global(EMPTY_JSON_STRING), false);
LETTERCASE('n', 'N'):
LETTERCHECK('u', 'U');
LETTERCHECK('l', 'L');
LETTERCHECK('l', 'L');
++ptr;
return JSONNode(JSON_NULL);
#ifndef JSON_STRICT
case JSON_TEXT('}'): //null in libjson
case JSON_TEXT(']'): //null in libjson
case JSON_TEXT(','): //null in libjson
return JSONNode(JSON_NULL);
#endif
}
//a number
return isValidNumber(ptr, end);
}
json_string JSONPreparse::isValidString(json_string::const_iterator & ptr, json_string::const_iterator & end){
//ptr is pointing to the first character after the quote
//ptr will end up behind the closing "
json_string::const_iterator start = ptr;
while(ptr != end){
switch(*ptr){
case JSON_TEXT('\\'):
switch(*(++ptr)){
case JSON_TEXT('\"'):
case JSON_TEXT('\\'):
case JSON_TEXT('/'):
case JSON_TEXT('b'):
case JSON_TEXT('f'):
case JSON_TEXT('n'):
case JSON_TEXT('r'):
case JSON_TEXT('t'):
break;
case JSON_TEXT('u'):
if (json_unlikely(!isHex(*++ptr))) throw false;
if (json_unlikely(!isHex(*++ptr))) throw false;
//fallthrough to \x
#ifndef JSON_STRICT
case JSON_TEXT('x'): //hex
#endif
if (json_unlikely(!isHex(*++ptr))) throw false;
if (json_unlikely(!isHex(*++ptr))) throw false;
break;
#ifndef JSON_OCTAL
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('7'): //octal
#else
case JSON_TEXT('0'):
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'):
#endif
if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) throw false;
if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) throw false;
break;
#endif
default:
throw false;
}
break;
case JSON_TEXT('\"'):
return json_string(start, ptr++);
}
++ptr;
}
throw false;
}
void JSONPreparse::isValidNamedObject(json_string::const_iterator & ptr, json_string::const_iterator & end, JSONNode & parent COMMENT_PARAM(comment)) {
//ptr should be right before the string name
{
json_string _name = isValidString(++ptr, end);
if (json_unlikely(*ptr++ != JSON_TEXT(':'))) throw false;
JSONNode res = isValidMember(ptr, end);
res.set_name_(_name);
SET_COMMENT(res, comment);
#ifdef JSON_LIBRARY
parent.push_back(&res);
#else
parent.push_back(res);
#endif
}
if (ptr == end) throw false;
switch(*ptr){
case JSON_TEXT(','):
++ptr;
{
GET_COMMENT(ptr, end, nextcomment);
isValidNamedObject(ptr, end, parent COMMENT_ARG(nextcomment)); //will handle all of them
}
return;
case JSON_TEXT('}'):
++ptr;
return;
default:
throw false;
}
}
JSONNode JSONPreparse::isValidObject(json_string::const_iterator & ptr, json_string::const_iterator & end) {
//ptr should currently be pointing past the {, so this must be the start of a name, or the closing }
//ptr will end up past the last }
JSONNode res(JSON_NODE);
GET_COMMENT(ptr, end, comment);
switch(*ptr){
case JSON_TEXT('\"'):
isValidNamedObject(ptr, end, res COMMENT_ARG(comment));
return res;
case JSON_TEXT('}'):
++ptr;
return res;
default:
throw false;
}
}
void pushArrayMember(JSONNode & res, json_string::const_iterator & ptr, json_string::const_iterator & end);
void pushArrayMember(JSONNode & res, json_string::const_iterator & ptr, json_string::const_iterator & end){
GET_COMMENT(ptr, end, comment);
JSONNode temp = JSONPreparse::isValidMember(ptr, end);
SET_COMMENT(temp, comment);
#ifdef JSON_LIBRARY
res.push_back(&temp);
#else
res.push_back(temp);
#endif
}
JSONNode JSONPreparse::isValidArray(json_string::const_iterator & ptr, json_string::const_iterator & end) {
//ptr should currently be pointing past the [, so this must be the start of a member, or the closing ]
//ptr will end up past the last ]
JSONNode res(JSON_ARRAY);
do{
switch(*ptr){
case JSON_TEXT(']'):
++ptr;
return res;
default:
pushArrayMember(res, ptr, end);
switch(*ptr){
case JSON_TEXT(','):
break;
case JSON_TEXT(']'):
++ptr;
return res;
default:
throw false;
}
break;
}
} while (++ptr != end);
throw false;
}
JSONNode JSONPreparse::isValidRoot(const json_string & json) json_throws(std::invalid_argument) {
json_string::const_iterator it = json.begin();
json_string::const_iterator end = json.end();
try {
GET_COMMENT(it, end, comment);
switch(*it){
case JSON_TEXT('{'):
RETURN_NODE(isValidObject(++it, end), comment);
case JSON_TEXT('['):
RETURN_NODE(isValidArray(++it, end), comment);
}
} catch (...){}
#ifndef JSON_NO_EXCEPTIONS
throw std::invalid_argument(json_global(EMPTY_STD_STRING));
#else
return JSONNode(JSON_NULL);
#endif
}
#endif

View file

@ -0,0 +1,28 @@
#ifndef LIBJSON_GUARD_PREPARSE_H
#define LIBJSON_GUARD_PREPARSE_H
#include "JSONDebug.h"
#include "JSONNode.h"
#if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY))
#ifdef JSON_COMMENTS
#define COMMENT_PARAM(name) ,const json_string & name
#else
#define COMMENT_PARAM(name)
#endif
class JSONPreparse {
public:
static JSONNode isValidNumber(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority;
static JSONNode isValidMember(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority;
static json_string isValidString(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority;
static void isValidNamedObject(json_string::const_iterator & ptr, json_string::const_iterator & end, JSONNode & parent COMMENT_PARAM(comment)) json_read_priority;
static JSONNode isValidObject(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority;
static JSONNode isValidArray(json_string::const_iterator & ptr, json_string::const_iterator & end) json_read_priority;
static JSONNode isValidRoot(const json_string & json) json_throws(std::invalid_argument) json_read_priority;
};
#endif
#endif

View file

@ -0,0 +1,308 @@
#ifndef JSON_SHARED_STRING_H
#define JSON_SHARED_STRING_H
/*
* This class allows json objects to share string
* Since libjson is a parser, it does a lot of substrings, but since
* a string with all of the information already exists, those substrings
* can be infered by an offset and length and a pointer to the master
* string
*
* EXPERIMENTAL, Not used yet
*/
#include "JSONDebug.h"
#include "JSONGlobals.h"
#include "JSONMemory.h"
/*
mallocs: 3351
frees: 3351
reallocs: 3
bytes: 298751 (291 KB)
max bytes at once: 3624 (3 KB)
avg bytes at once: 970 (0 KB)
*/
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(push, 1)
#elif _MSC_VER
#pragma pack(push, json_shared_string_pack, 1)
#endif
#endif
class json_shared_string {
public:
struct iterator;
struct const_iterator {
const_iterator(const json_char * p, const json_shared_string * pa) : parent(pa), it(p){}
inline const_iterator& operator ++(void) json_nothrow { ++it; return *this; }
inline const_iterator& operator --(void) json_nothrow { --it; return *this; }
inline const_iterator& operator +=(long i) json_nothrow { it += i; return *this; }
inline const_iterator& operator -=(long i) json_nothrow { it -= i; return *this; }
inline const_iterator operator ++(int) json_nothrow {
const_iterator result(*this);
++it;
return result;
}
inline const_iterator operator --(int) json_nothrow {
const_iterator result(*this);
--it;
return result;
}
inline const_iterator operator +(long i) const json_nothrow {
const_iterator result(*this);
result.it += i;
return result;
}
inline const_iterator operator -(long i) const json_nothrow {
const_iterator result(*this);
result.it -= i;
return result;
}
inline const json_char & operator [](size_t pos) const json_nothrow { return it[pos]; };
inline const json_char & operator *(void) const json_nothrow { return *it; }
inline const json_char * operator ->(void) const json_nothrow { return it; }
inline bool operator == (const const_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const const_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const const_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const const_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const const_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const const_iterator & other) const json_nothrow { return it <= other.it; }
inline bool operator == (const iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const iterator & other) const json_nothrow { return it <= other.it; }
inline const_iterator & operator =(const const_iterator & orig) json_nothrow { it = orig.it; return *this; }
const_iterator (const const_iterator & orig) json_nothrow : it(orig.it) {}
private:
const json_shared_string * parent;
const json_char * it;
friend class json_shared_string;
friend struct iterator;
};
struct iterator {
iterator(const json_char * p, const json_shared_string * pa) : parent(pa), it(p){}
inline iterator& operator ++(void) json_nothrow { ++it; return *this; }
inline iterator& operator --(void) json_nothrow { --it; return *this; }
inline iterator& operator +=(long i) json_nothrow { it += i; return *this; }
inline iterator& operator -=(long i) json_nothrow { it -= i; return *this; }
inline iterator operator ++(int) json_nothrow {
iterator result(*this);
++it;
return result;
}
inline iterator operator --(int) json_nothrow {
iterator result(*this);
--it;
return result;
}
inline iterator operator +(long i) const json_nothrow {
iterator result(*this);
result.it += i;
return result;
}
inline iterator operator -(long i) const json_nothrow {
iterator result(*this);
result.it -= i;
return result;
}
inline const json_char & operator [](size_t pos) const json_nothrow { return it[pos]; };
inline const json_char & operator *(void) const json_nothrow { return *it; }
inline const json_char * operator ->(void) const json_nothrow { return it; }
inline bool operator == (const const_iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const const_iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const const_iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const const_iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const const_iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const const_iterator & other) const json_nothrow { return it <= other.it; }
inline bool operator == (const iterator & other) const json_nothrow { return it == other.it; }
inline bool operator != (const iterator & other) const json_nothrow { return it != other.it; }
inline bool operator > (const iterator & other) const json_nothrow { return it > other.it; }
inline bool operator >= (const iterator & other) const json_nothrow { return it >= other.it; }
inline bool operator < (const iterator & other) const json_nothrow { return it < other.it; }
inline bool operator <= (const iterator & other) const json_nothrow { return it <= other.it; }
inline iterator & operator =(const iterator & orig) json_nothrow { it = orig.it; return *this; }
iterator (const iterator & orig) json_nothrow : it(orig.it) {}
private:
const json_shared_string * parent;
const json_char * it;
friend class json_shared_string;
friend struct const_iterator;
};
inline json_shared_string::iterator begin(void){
iterator res = iterator(data(), this);
return res;
}
inline json_shared_string::iterator end(void){
iterator res = iterator(data() + len, this);
return res;
}
inline json_shared_string::const_iterator begin(void) const {
const_iterator res = const_iterator(data(), this);
return res;
}
inline json_shared_string::const_iterator end(void) const {
const_iterator res = const_iterator(data() + len, this);
return res;
}
inline json_string::iterator std_begin(void){
return _str -> mystring.begin() + offset;
}
inline json_string::iterator std_end(void){
return std_begin() + len;
}
inline json_string::const_iterator std_begin(void) const{
return _str -> mystring.begin() + offset;
}
inline json_string::const_iterator std_end(void) const{
return std_begin() + len;
}
inline json_shared_string(void) : offset(0), len(0), _str(new(json_malloc<json_shared_string_internal>(1)) json_shared_string_internal(json_global(EMPTY_JSON_STRING))) {}
inline json_shared_string(const json_string & str) : offset(0), len(str.length()), _str(new(json_malloc<json_shared_string_internal>(1)) json_shared_string_internal(str)) {}
inline json_shared_string(const json_shared_string & str, size_t _offset, size_t _len) : _str(str._str), offset(str.offset + _offset), len(_len) {
++_str -> refCount;
}
inline json_shared_string(const json_shared_string & str, size_t _offset) : _str(str._str), offset(str.offset + _offset), len(str.len - _offset) {
++_str -> refCount;
}
inline json_shared_string(const iterator & s, const iterator & e) : _str(s.parent -> _str), offset(s.it - s.parent -> _str -> mystring.data()), len(e.it - s.it){
++_str -> refCount;
}
inline ~json_shared_string(void){
deref();
}
inline bool empty(void) const { return len == 0; }
size_t find(json_char ch, size_t pos = 0) const {
if (_str -> refCount == 1) return _str -> mystring.find(ch, pos);
json_string::const_iterator e = std_end();
for(json_string::const_iterator b = std_begin() + pos; b != e; ++b){
if (*b == ch) return b - std_begin();
}
return json_string::npos;
}
inline json_char & operator[] (size_t loc){
return _str -> mystring[loc + offset];
}
inline json_char operator[] (size_t loc) const {
return _str -> mystring[loc + offset];
}
inline void clear(){ len = 0; }
inline size_t length() const { return len; }
inline const json_char * c_str() const { return toString().c_str(); }
inline const json_char * data() const { return _str -> mystring.data() + offset; }
inline bool operator != (const json_shared_string & other) const {
if ((other._str == _str) && (other.len == len) && (other.offset == offset)) return false;
return other.toString() != toString();
}
inline bool operator == (const json_shared_string & other) const {
if ((other._str == _str) && (other.len == len) && (other.offset == offset)) return true;
return other.toString() == toString();
}
inline bool operator == (const json_string & other) const {
return other == toString();
}
json_string & toString(void) const {
//gonna have to do a real substring now anyway, so do it completely
if (_str -> refCount == 1){
if (offset || len != _str -> mystring.length()){
_str -> mystring = json_string(std_begin(), std_end());
}
} else if (offset || len != _str -> mystring.length()){
--_str -> refCount; //dont use deref because I know its not going to be deleted
_str = new(json_malloc<json_shared_string_internal>(1)) json_shared_string_internal(json_string(std_begin(), std_end()));
}
offset = 0;
return _str -> mystring;
}
inline void assign(const json_shared_string & other, size_t _offset, size_t _len){
if (other._str != _str){
deref();
_str = other._str;
}
++_str -> refCount;
offset = other.offset + _offset;
len = _len;
}
json_shared_string(const json_shared_string & other) : _str(other._str), offset(other.offset), len(other.len){
++_str -> refCount;
}
json_shared_string & operator =(const json_shared_string & other){
if (other._str != _str){
deref();
_str = other._str;
++_str -> refCount;
}
offset = other.offset;
len = other.len;
return *this;
}
json_shared_string & operator += (const json_char c){
toString() += c;
++len;
return *this;
}
//when doing a plus equal of another string, see if it shares the string and starts where this one left off, in which case just increase len
JSON_PRIVATE
struct json_shared_string_internal {
inline json_shared_string_internal(const json_string & _mystring) : mystring(_mystring), refCount(1) {}
json_string mystring;
size_t refCount PACKED(20);
};
inline void deref(void){
if (--_str -> refCount == 0){
_str -> ~json_shared_string_internal();
libjson_free<json_shared_string_internal>(_str);
}
}
mutable json_shared_string_internal * _str;
mutable size_t offset PACKED(20);
mutable size_t len PACKED(20);
};
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(pop)
#elif _MSC_VER
#pragma pack(pop, json_shared_string_pack,)
#endif
#endif
#endif

View file

@ -0,0 +1,23 @@
#ifndef JSONSINGLETON_H
#define JSONSINGLETON_H
template <typename T> class JSONSingleton {
public:
static inline T get(void){
return get_singleton() -> ptr;
}
static inline void set(T p){
get_singleton() -> ptr = p;
}
private:
inline JSONSingleton() : ptr(NULL) { }
JSONSingleton(const JSONSingleton<T> &);
JSONSingleton<T> operator = (const JSONSingleton<T> &);
static inline JSONSingleton<T> * get_singleton(void){
static JSONSingleton<T> instance;
return &instance;
}
T ptr;
};
#endif

View file

@ -0,0 +1,83 @@
#ifndef TestSuite_JSONStats_h
#define TestSuite_JSONStats_h
#include "../../JSONOptions.h"
#if defined(JSON_UNIT_TEST) || defined(JSON_DEBUG)
#define LIBJSON_OBJECT(name)\
static size_t & getCtorCounter(void){\
static size_t count = 0;\
static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\
return count;\
}\
static size_t & getCopyCtorCounter(void){\
static size_t count = 0;\
static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\
return count;\
}\
static size_t & getAssignmentCounter(void){\
static size_t count = 0;\
static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\
return count;\
}\
static size_t & getDtorCounter(void){\
static size_t count = 0;\
static int i = JSONStats::setCallbacks(getCtorCounter, getCopyCtorCounter, getAssignmentCounter, getDtorCounter, #name);\
return count;\
}
#define LIBJSON_CTOR getCtorCounter() += 1
#define LIBJSON_COPY_CTOR getCopyCtorCounter() += 1
#define LIBJSON_ASSIGNMENT getAssignmentCounter() += 1
#define LIBJSON_DTOR getDtorCounter() += 1
#include <map>
#include <sstream>
#include <iostream>
#include <string>
class JSONStats {
public:
~JSONStats(void){
std::map<getCounter_m, objectStructure*> & mymap = getMapper();
std::map<getCounter_m, objectStructure*>::iterator b = mymap.begin();
std::map<getCounter_m, objectStructure*>::iterator e = mymap.end();
std::cout << "Counters for libjson:" << std::endl;
for(; b != e; ++b){
std::cout << " " << b -> second -> _name << std::endl;
std::cout << " Constructor: " << b -> second -> _cTor() << std::endl;
std::cout << " Copy Constructor: " << b -> second -> _ccTor() << std::endl;
std::cout << " Assignment: " << b -> second -> _assign() << std::endl;
std::cout << " Destructor: " << b -> second -> _dTor() << std::endl;
delete b -> second;
}
}
typedef size_t & (*getCounter_m)(void);
struct objectStructure {
objectStructure(getCounter_m cTor, getCounter_m ccTor, getCounter_m assign, getCounter_m dTor, const std::string & name):
_cTor(cTor), _ccTor(ccTor), _assign(assign), _dTor(dTor), _name(name){}
std::string _name;
getCounter_m _cTor;
getCounter_m _ccTor;
getCounter_m _assign;
getCounter_m _dTor;
};
static int setCallbacks(getCounter_m cTor, getCounter_m ccTor, getCounter_m assign, getCounter_m dtor, const std::string & name){
getMapper()[cTor] = new objectStructure (cTor, ccTor, assign, dtor, name);
return 0;
}
static std::map<getCounter_m, objectStructure*> & getMapper(void) {
static std::map<getCounter_m, objectStructure*> mymap;
return mymap;
}
};
#else
#define LIBJSON_OBJECT(name)
#define LIBJSON_CTOR (void)0
#define LIBJSON_DTOR (void)0
#define LIBJSON_COPY_CTOR (void)0
#define LIBJSON_ASSIGNMENT (void)0
typedef int JSONStats;
#endif
#endif

View file

@ -0,0 +1,143 @@
#include "JSONStream.h"
#ifdef JSON_STREAM
#include "JSONWorker.h"
#include "JSONValidator.h"
JSONStream::JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow : state(true), call(call_p), err_call(call_e), buffer(), callback_identifier(callbackIdentifier) {
LIBJSON_CTOR;
}
JSONStream::JSONStream(const JSONStream & orig) json_nothrow : state(orig.state), call(orig.call), err_call(orig.err_call), buffer(orig.buffer), callback_identifier(orig.callback_identifier){
LIBJSON_COPY_CTOR;
}
JSONStream & JSONStream::operator =(const JSONStream & orig) json_nothrow {
LIBJSON_ASSIGNMENT;
err_call = orig.err_call;
call = orig.call;
state = orig.state;
buffer = orig.buffer;
callback_identifier = orig.callback_identifier;
return *this;
}
#ifdef JSON_LIBRARY
JSONStream & JSONStream::operator << (const json_char * str) json_nothrow {
#else
JSONStream & JSONStream::operator << (const json_string & str) json_nothrow {
#endif
if (state){
buffer += str;
parse();
}
return *this;
}
#define QUOTECASE_STREAM()\
case JSON_TEXT('\"'):\
while (*(++p) != JSON_TEXT('\"')){\
if (json_unlikely(*p == JSON_TEXT('\0'))) return json_string::npos;\
}\
break;
#define NULLCASE_STREAM()\
case JSON_TEXT('\0'):\
return json_string::npos;\
#define BRACKET_STREAM(left, right)\
case left: {\
size_t brac = 1;\
while (brac){\
switch (*(++p)){\
case right:\
--brac;\
break;\
case left:\
++brac;\
break;\
QUOTECASE_STREAM()\
NULLCASE_STREAM()\
}\
}\
break;}\
case right:\
return json_string::npos;
#if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY)))
#define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant<ch>(vt, po)
template<json_char ch>
size_t JSONStream::FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow {
#else
#define STREAM_FIND_NEXT_RELEVANT(ch, vt, po) FindNextRelevant(ch, vt, po)
size_t JSONStream::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow {
#endif
const json_char * start = value_t.c_str();
for (const json_char * p = start + pos; *p; ++p){
if (json_unlikely(*p == ch)) return p - start;
switch (*p){
BRACKET_STREAM(JSON_TEXT('['), JSON_TEXT(']'))
BRACKET_STREAM(JSON_TEXT('{'), JSON_TEXT('}'))
QUOTECASE_STREAM()
}
};
return json_string::npos;
}
void JSONStream::parse(void) json_nothrow {
#ifdef JSON_SECURITY_MAX_STREAM_OBJECTS
size_t objects = 0;
#endif
for(;;){
size_t pos = buffer.find_first_of(JSON_TEXT("{["));
if (json_likely(pos != json_string::npos)){
size_t end = (buffer[pos] == JSON_TEXT('[')) ? STREAM_FIND_NEXT_RELEVANT(JSON_TEXT(']'), buffer, pos + 1) : STREAM_FIND_NEXT_RELEVANT(JSON_TEXT('}'), buffer, pos + 1);
if (end != json_string::npos){
#ifdef JSON_SECURITY_MAX_STREAM_OBJECTS
if (++objects > JSON_SECURITY_MAX_STREAM_OBJECTS){
JSON_FAIL(JSON_TEXT("Maximum number of json objects for a stream at once has been reached"));
if (err_call) err_call(getIdentifier());
state = false;
return;
}
#endif
START_MEM_SCOPE
JSONNode temp(JSONWorker::parse(buffer.substr(pos, end - pos + 1)));
#ifndef JSON_LIBRARY
call(temp, getIdentifier());
#else
call(&temp, getIdentifier());
#endif
END_MEM_SCOPE
json_string::iterator beginning = buffer.begin();
buffer.erase(beginning, beginning + end);
continue; //parse(); //parse the next object too
}
#ifdef JSON_SAFE
else {
//verify that what's in there is at least valid so far
#ifndef JSON_VALIDATE
#error In order to use safe mode and streams, JSON_VALIDATE needs to be defined
#endif
json_auto<json_char> s;
size_t len;
s.set(JSONWorker::RemoveWhiteSpace(json_string(buffer.c_str() + pos), len, false));
if (!JSONValidator::isValidPartialRoot(s.ptr)){
if (err_call) err_call(getIdentifier());
state = false;
}
}
#endif
}
break;
}
}
#endif

View file

@ -0,0 +1,93 @@
#ifndef LIBJSON_GUARD_STREAM_H
#define LIBJSON_GUARD_STREAM_H
#include "JSONDebug.h"
#ifdef JSON_STREAM
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(push, 1)
#elif _MSC_VER
#pragma pack(push, JSONStream_pack, 1)
#endif
#endif
#ifdef JSON_MEMORY_CALLBACKS
#include "JSONMemory.h"
#endif
#ifndef JSON_LIBRARY
class JSONNode; //foreward declaration
typedef void (*json_stream_callback_t)(JSONNode &, void *);
#endif
class JSONStream {
public:
LIBJSON_OBJECT(JSONStream);
JSONStream(json_stream_callback_t call_p, json_stream_e_callback_t call_e = NULL, void * callbackIdentifier = JSONSTREAM_SELF) json_nothrow;
JSONStream(const JSONStream & orig) json_nothrow;
JSONStream & operator =(const JSONStream & orig) json_nothrow;
~JSONStream(void) json_nothrow { LIBJSON_DTOR; }
#ifdef JSON_LIBRARY
JSONStream & operator << (const json_char * str) json_nothrow;
#else
JSONStream & operator << (const json_string & str) json_nothrow;
#endif
static void deleteJSONStream(JSONStream * stream) json_nothrow {
#ifdef JSON_MEMORY_CALLBACKS
stream -> ~JSONStream();
libjson_free<JSONStream>(stream);
#else
delete stream;
#endif
}
static JSONStream * newJSONStream(json_stream_callback_t callback, json_stream_e_callback_t call_e, void * callbackIdentifier) json_nothrow {
#ifdef JSON_MEMORY_CALLBACKS
return new(json_malloc<JSONStream>(1)) JSONStream(callback, call_e, callbackIdentifier);
#else
return new JSONStream(callback, call_e, callbackIdentifier);
#endif
}
inline void reset() json_nothrow {
state = true;
buffer.clear();
}
JSON_PRIVATE
inline void * getIdentifier(void) json_nothrow {
if (callback_identifier == JSONSTREAM_SELF){
return (void*)this;
}
return callback_identifier;
}
#if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY)))
template<json_char ch>
static size_t FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow json_read_priority;
#else
static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow json_read_priority;
#endif
void parse(void) json_nothrow;
json_string buffer;
json_stream_callback_t call;
json_stream_e_callback_t err_call;
void * callback_identifier;
bool state BITS(1);
};
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(pop)
#elif _MSC_VER
#pragma pack(pop, JSONStream_pack)
#endif
#endif
#endif
#endif

View file

@ -0,0 +1,404 @@
#include "JSONValidator.h"
#ifdef JSON_VALIDATE
inline bool isHex(json_char c) json_pure;
inline bool isHex(json_char c) json_nothrow {
return (((c >= JSON_TEXT('0')) && (c <= JSON_TEXT('9'))) ||
((c >= JSON_TEXT('A')) && (c <= JSON_TEXT('F'))) ||
((c >= JSON_TEXT('a')) && (c <= JSON_TEXT('f'))));
}
bool JSONValidator::isValidNumber(const json_char * & ptr) json_nothrow {
//ptr points at the first character in the number
//ptr will end up past the last character
bool decimal = false;
bool scientific = false;
//first letter is weird
switch(*ptr){
#ifndef JSON_STRICT
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('+'):
#endif
case JSON_TEXT('-'):
#ifdef JSON_STRICT
switch(*(ptr + 1)){
case '.':
case 'e':
case 'E':
case '\0':
return false;
}
break;
#endif
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('8'):
case JSON_TEXT('9'):
break;
case JSON_TEXT('0'):
++ptr;
switch(*ptr){
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
scientific = true;
++ptr;
switch(*ptr){
case JSON_TEXT('\0'):
return false;
case JSON_TEXT('-'):
case JSON_TEXT('+'):
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
break;
default:
return false;
}
break;
#ifndef JSON_STRICT
case JSON_TEXT('x'):
while(isHex(*++ptr)){};
return true;
#ifdef JSON_OCTAL
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('7'): //octal
#else
case JSON_TEXT('0'):
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'):
#endif
while((*++ptr >= JSON_TEXT('0')) && (*ptr <= JSON_TEXT('7'))){};
return ((*ptr != JSON_TEXT('8')) && (*ptr != JSON_TEXT('9')));
case JSON_TEXT('8'):
case JSON_TEXT('9'):
break;
#else
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
#endif
#else
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
#endif
default: //just a 0
return true;
}
break;
default:
return false;
}
++ptr;
//next digits
while (true){
switch(*ptr){
case JSON_TEXT('.'):
if (json_unlikely(decimal)) return false; //multiple decimals
if (json_unlikely(scientific)) return false;
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
if (json_likely(scientific)) return false;
scientific = true;
++ptr;
switch(*ptr){
case JSON_TEXT('-'):
case JSON_TEXT('+'):
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
default:
return false;
}
break;
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('9'):
#else
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
#endif
break;
default:
return true;
}
++ptr;
}
return false;
}
#ifndef JSON_STRICT
#define LETTERCASE(x, y)\
case JSON_TEXT(x):\
case JSON_TEXT(y)
#define LETTERCHECK(x, y)\
if (json_unlikely((*++ptr != JSON_TEXT(x)) && (*ptr != JSON_TEXT(y)))) return false
#else
#define LETTERCASE(x, y)\
case JSON_TEXT(x)
#define LETTERCHECK(x, y)\
if (json_unlikely(*++ptr != JSON_TEXT(x))) return false
#endif
bool JSONValidator::isValidMember(const json_char * & ptr DEPTH_PARAM) json_nothrow {
//ptr is on the first character of the member
//ptr will end up immediately after the last character in the member
switch(*ptr){
case JSON_TEXT('\"'):
return isValidString(++ptr);
case JSON_TEXT('{'):
INC_DEPTH();
return isValidObject(++ptr DEPTH_ARG(depth_param));
case JSON_TEXT('['):
INC_DEPTH();
return isValidArray(++ptr DEPTH_ARG(depth_param));
LETTERCASE('t', 'T'):
LETTERCHECK('r', 'R');
LETTERCHECK('u', 'U');
LETTERCHECK('e', 'E');
++ptr;
return true;
LETTERCASE('f', 'F'):
LETTERCHECK('a', 'A');
LETTERCHECK('l', 'L');
LETTERCHECK('s', 'S');
LETTERCHECK('e', 'E');
++ptr;
return true;
LETTERCASE('n', 'N'):
LETTERCHECK('u', 'U');
LETTERCHECK('l', 'L');
LETTERCHECK('l', 'L');
++ptr;
return true;
#ifndef JSON_STRICT
case JSON_TEXT('}'): //null in libjson
case JSON_TEXT(']'): //null in libjson
case JSON_TEXT(','): //null in libjson
return true;
#endif
case JSON_TEXT('\0'):
return false;
}
//a number
return isValidNumber(ptr);
}
bool JSONValidator::isValidString(const json_char * & ptr) json_nothrow {
//ptr is pointing to the first character after the quote
//ptr will end up behind the closing "
while(true){
switch(*ptr){
case JSON_TEXT('\\'):
switch(*(++ptr)){
case JSON_TEXT('\"'):
case JSON_TEXT('\\'):
case JSON_TEXT('/'):
case JSON_TEXT('b'):
case JSON_TEXT('f'):
case JSON_TEXT('n'):
case JSON_TEXT('r'):
case JSON_TEXT('t'):
break;
case JSON_TEXT('u'):
if (json_unlikely(!isHex(*++ptr))) return false;
if (json_unlikely(!isHex(*++ptr))) return false;
//fallthrough to \x
#ifndef JSON_STRICT
case JSON_TEXT('x'): //hex
#endif
if (json_unlikely(!isHex(*++ptr))) return false;
if (json_unlikely(!isHex(*++ptr))) return false;
break;
#ifdef JSON_OCTAL
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('7'): //octal
#else
case JSON_TEXT('0'):
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'):
#endif
if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) return false;
if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) return false;
break;
#endif
default:
return false;
}
break;
case JSON_TEXT('\"'):
++ptr;
return true;
case JSON_TEXT('\0'):
return false;
}
++ptr;
}
return false;
}
bool JSONValidator::isValidNamedObject(const json_char * &ptr DEPTH_PARAM) json_nothrow {
if (json_unlikely(!isValidString(++ptr))) return false;
if (json_unlikely(*ptr++ != JSON_TEXT(':'))) return false;
if (json_unlikely(!isValidMember(ptr DEPTH_ARG(depth_param)))) return false;
switch(*ptr){
case JSON_TEXT(','):
return isValidNamedObject(++ptr DEPTH_ARG(depth_param));
case JSON_TEXT('}'):
++ptr;
return true;
default:
return false;
}
}
bool JSONValidator::isValidObject(const json_char * & ptr DEPTH_PARAM) json_nothrow {
//ptr should currently be pointing past the {, so this must be the start of a name, or the closing }
//ptr will end up past the last }
do{
switch(*ptr){
case JSON_TEXT('\"'):
return isValidNamedObject(ptr DEPTH_ARG(depth_param));
case JSON_TEXT('}'):
++ptr;
return true;
default:
return false;
}
} while (*++ptr);
return false;
}
bool JSONValidator::isValidArray(const json_char * & ptr DEPTH_PARAM) json_nothrow {
//ptr should currently be pointing past the [, so this must be the start of a member, or the closing ]
//ptr will end up past the last ]
do{
switch(*ptr){
case JSON_TEXT(']'):
++ptr;
return true;
default:
if (json_unlikely(!isValidMember(ptr DEPTH_ARG(depth_param)))) return false;
switch(*ptr){
case JSON_TEXT(','):
break;
case JSON_TEXT(']'):
++ptr;
return true;
default:
return false;
}
break;
}
} while (*++ptr);
return false;
}
bool JSONValidator::isValidRoot(const json_char * json) json_nothrow {
const json_char * ptr = json;
switch(*ptr){
case JSON_TEXT('{'):
if (json_likely(isValidObject(++ptr DEPTH_ARG(1)))){
return *ptr == JSON_TEXT('\0');
}
return false;
case JSON_TEXT('['):
if (json_likely(isValidArray(++ptr DEPTH_ARG(1)))){
return *ptr == JSON_TEXT('\0');
}
return false;
}
return false;
}
#ifdef JSON_STREAM
//It has already been checked for a complete structure, so we know it's not complete
bool JSONValidator::isValidPartialRoot(const json_char * json) json_nothrow {
const json_char * ptr = json;
switch(*ptr){
case JSON_TEXT('{'):
JSON_ASSERT_SAFE(!isValidObject(++ptr DEPTH_ARG(1)), JSON_TEXT("Partial Object seems to be valid"), );
return *ptr == JSON_TEXT('\0');
case JSON_TEXT('['):
JSON_ASSERT_SAFE(!isValidArray(++ptr DEPTH_ARG(1)), JSON_TEXT("Partial Object seems to be valid"), );
return *ptr == JSON_TEXT('\0');
}
return false;
}
#endif
#endif

View file

@ -0,0 +1,40 @@
#ifndef JSON_VALIDATOR_H
#define JSON_VALIDATOR_H
#include "JSONDebug.h"
#ifdef JSON_VALIDATE
#ifdef JSON_SECURITY_MAX_NEST_LEVEL
#define DEPTH_PARAM ,size_t depth_param
#define DEPTH_ARG(arg) ,arg
#define INC_DEPTH()\
if (++depth_param > JSON_SECURITY_MAX_NEST_LEVEL){\
JSON_FAIL(JSON_TEXT("Exceeded JSON_SECURITY_MAX_NEST_LEVEL"));\
return false;\
}
#else
#define DEPTH_PARAM
#define DEPTH_ARG(arg)
#define INC_DEPTH() (void)0
#endif
class JSONValidator {
public:
static bool isValidNumber(const json_char * & ptr) json_nothrow json_read_priority;
static bool isValidMember(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority;
static bool isValidString(const json_char * & ptr) json_nothrow json_read_priority;
static bool isValidNamedObject(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority;
static bool isValidObject(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority;
static bool isValidArray(const json_char * & ptr DEPTH_PARAM) json_nothrow json_read_priority;
static bool isValidRoot(const json_char * json) json_nothrow json_read_priority;
#ifdef JSON_STREAM
static bool isValidPartialRoot(const json_char * json) json_nothrow json_read_priority;
#endif
private:
JSONValidator(void);
};
#endif
#endif

View file

@ -0,0 +1,674 @@
#include "JSONWorker.h"
bool used_ascii_one = false; //used to know whether or not to check for intermediates when writing, once flipped, can't be unflipped
inline json_char ascii_one(void) json_nothrow {
used_ascii_one = true;
return JSON_TEXT('\1');
}
#ifdef JSON_READ_PRIORITY
JSONNode JSONWorker::parse(const json_string & json) json_throws(std::invalid_argument) {
json_auto<json_char> s;
size_t len;
s.set(RemoveWhiteSpace(json, len, true));
return _parse_unformatted(s.ptr, s.ptr + len);
}
JSONNode JSONWorker::parse_unformatted(const json_string & json) json_throws(std::invalid_argument) {
#if defined JSON_DEBUG || defined JSON_SAFE
#ifndef JSON_NO_EXCEPTIONS
JSON_ASSERT_SAFE((json[0] == JSON_TEXT('{')) || (json[0] == JSON_TEXT('[')), JSON_TEXT("Not JSON!"), throw std::invalid_argument(json_global(EMPTY_STD_STRING)););
#else
JSON_ASSERT_SAFE((json[0] == JSON_TEXT('{')) || (json[0] == JSON_TEXT('[')), JSON_TEXT("Not JSON!"), return JSONNode(JSON_NULL););
#endif
#endif
return _parse_unformatted(json.data(), json.data() + json.length());
}
JSONNode JSONWorker::_parse_unformatted(const json_char * json, const json_char * const end) json_throws(std::invalid_argument) {
#ifdef JSON_COMMENTS
json_char firstchar = *json;
json_string _comment;
json_char * runner = (json_char*)json;
if (json_unlikely(firstchar == JSON_TEMP_COMMENT_IDENTIFIER)){ //multiple comments will be consolidated into one
newcomment:
while(*(++runner) != JSON_TEMP_COMMENT_IDENTIFIER){
JSON_ASSERT(runner != end, JSON_TEXT("Removing white space failed"));
_comment += *runner;
}
firstchar = *(++runner); //step past the trailing tag
if (json_unlikely(firstchar == JSON_TEMP_COMMENT_IDENTIFIER)){
_comment += JSON_TEXT('\n');
goto newcomment;
}
}
#else
const json_char firstchar = *json;
#endif
switch (firstchar){
case JSON_TEXT('{'):
case JSON_TEXT('['):
#if defined JSON_DEBUG || defined JSON_SAFE
if (firstchar == JSON_TEXT('[')){
if (json_unlikely(*(end - 1) != JSON_TEXT(']'))){
JSON_FAIL(JSON_TEXT("Missing final ]"));
break;
}
} else {
if (json_unlikely(*(end - 1) != JSON_TEXT('}'))){
JSON_FAIL(JSON_TEXT("Missing final }"));
break;
}
}
#endif
#ifdef JSON_COMMENTS
JSONNode foo(json_string(runner, end - 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(json_string(json, end - json));
#endif
}
JSON_FAIL(JSON_TEXT("Not JSON!"));
#ifndef JSON_NO_EXCEPTIONS
throw std::invalid_argument(json_global(EMPTY_STD_STRING));
#else
return JSONNode(JSON_NULL);
#endif
}
#endif
#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;
#if defined(JSON_DEBUG) || defined(JSON_SAFE)
#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;
#if defined(JSON_READ_PRIORITY) || defined(JSON_STREAM)
#if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY)))
#define FIND_NEXT_RELEVANT(ch, vt, po) JSONWorker::FindNextRelevant<ch>(vt, po)
template<json_char ch>
size_t JSONWorker::FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow {
#else
#define FIND_NEXT_RELEVANT(ch, vt, po) JSONWorker::FindNextRelevant(ch, vt, po)
size_t JSONWorker::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow {
#endif
json_string::const_iterator start = value_t.begin();
json_string::const_iterator e = value_t.end();
for (json_string::const_iterator p = value_t.begin() + pos; p != e; ++p){
if (json_unlikely(*p == ch)) return p - start;
switch (*p){
BRACKET(JSON_TEXT('['), JSON_TEXT(']'))
BRACKET(JSON_TEXT('{'), JSON_TEXT('}'))
QUOTECASE()
}
};
return json_string::npos;
}
#endif
#ifdef JSON_COMMENTS
#define COMMENT_DELIMITER() *runner++ = JSON_TEMP_COMMENT_IDENTIFIER
#define AND_RUNNER ,runner
inline void SingleLineComment(const json_char * & p, const json_char * const end, json_char * & runner) json_nothrow {
//It is okay to add two '\5' characters here because at minimun the # and '\n' are replaced, so it's at most the same size
COMMENT_DELIMITER();
while((++p != end) && (*p != JSON_TEXT('\n'))){
*runner++ = *p;
}
COMMENT_DELIMITER();
}
#else
#define COMMENT_DELIMITER() (void)0
#define AND_RUNNER
#endif
#ifndef JSON_STRICT
inline void SingleLineComment(const json_char * & p, const json_char * const end) json_nothrow {
while((++p != end) && (*p != JSON_TEXT('\n')));
}
#endif
#if defined(JSON_LESS_MEMORY) && defined(JSON_READ_PRIORITY)
#define PRIVATE_REMOVEWHITESPACE(T, value_t, escapeQuotes, len) private_RemoveWhiteSpace(T, value_t, escapeQuotes, len)
json_char * private_RemoveWhiteSpace(bool T, const json_string & value_t, bool escapeQuotes, size_t & len) json_nothrow {
#else
#define PRIVATE_REMOVEWHITESPACE(T, value_t, escapeQuotes, len) private_RemoveWhiteSpace<T>(value_t, escapeQuotes, len)
template<bool T>
json_char * private_RemoveWhiteSpace(const json_string & value_t, bool escapeQuotes, size_t & len) json_nothrow {
#endif
json_char * result;
json_char * runner = result = json_malloc<json_char>(value_t.length() + 1); //dealing with raw memory is faster than adding to a json_string
JSON_ASSERT(result != 0, json_global(ERROR_OUT_OF_MEMORY));
const json_char * const end = value_t.data() + value_t.length();
for(const json_char * p = value_t.data(); p != end; ++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;
#ifndef JSON_STRICT
case JSON_TEXT('/'): //a C comment
if (*(++p) == JSON_TEXT('*')){ //a multiline comment
if (T) COMMENT_DELIMITER();
while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))){
if(p == end){
COMMENT_DELIMITER();
goto endofrunner;
}
if (T) *runner++ = *p;
}
++p;
if (T) 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 endofrunner;);
case JSON_TEXT('#'): //a bash comment
if (T){
SingleLineComment(p, end AND_RUNNER);
} else {
SingleLineComment(p, end);
}
break;
#endif
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
if(p == end) goto endofrunner;
switch(*p){
case JSON_TEXT('\\'):
*runner++ = JSON_TEXT('\\');
if (escapeQuotes){
*runner++ = (*++p == JSON_TEXT('\"')) ? ascii_one() : *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
} else {
*runner++ = *++p;
}
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 endofrunner;);
JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofrunner;);
*runner++ = *p;
break;
}
}
endofrunner:
len = runner - result;
return result;
}
#ifdef JSON_READ_PRIORITY
json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t, size_t & len, bool escapeQuotes) json_nothrow {
json_char * result = PRIVATE_REMOVEWHITESPACE(true, value_t, escapeQuotes, len);
result[len] = JSON_TEXT('\0');
return result;
}
#endif
json_char * JSONWorker::RemoveWhiteSpaceAndCommentsC(const json_string & value_t, bool escapeQuotes) json_nothrow {
size_t len;
json_char * result = PRIVATE_REMOVEWHITESPACE(false, value_t, escapeQuotes, len);
result[len] = JSON_TEXT('\0');
return result;
}
json_string JSONWorker::RemoveWhiteSpaceAndComments(const json_string & value_t, bool escapeQuotes) json_nothrow {
json_auto<json_char> s;
size_t len;
s.set(PRIVATE_REMOVEWHITESPACE(false, value_t, escapeQuotes, len));
return json_string(s.ptr, len);
}
#ifdef JSON_READ_PRIORITY
/*
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_pure;
inline json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo) json_nothrow {
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;
}
void JSONWorker::UTF(const json_char * & pos, json_string & result, const json_char * const end) json_nothrow {
JSON_ASSERT_SAFE(((long)end - (long)pos) > 4, JSON_TEXT("UTF will go out of bounds"), return;);
json_uchar first = UTF8(pos, end);
if (json_unlikely((first > 0xD800) && (first < 0xDBFF) &&
(*(pos + 1) == '\\') && (*(pos + 2) == 'u'))){
const json_char * original_pos = pos; //if the 2nd character is not correct I need to roll back the iterator
pos += 2;
json_uchar second = UTF8(pos, end);
//surrogate pair, not two characters
if (json_unlikely((second > 0xDC00) && (second < 0xDFFF))){
result += SurrogatePair(first, second);
} else {
pos = original_pos;
}
} else {
result += first;
}
}
#endif
json_uchar JSONWorker::UTF8(const json_char * & pos, const json_char * const end) json_nothrow {
JSON_ASSERT_SAFE(((long)end - (long)pos) > 4, JSON_TEXT("UTF will go out of bounds"), return JSON_TEXT('\0'););
#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
}
json_char JSONWorker::Hex(const json_char * & pos) json_nothrow {
/*
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);
}
#ifndef JSON_STRICT
inline json_char FromOctal(const json_char * & str, const json_char * const end) json_nothrow {
JSON_ASSERT_SAFE(((long)end - (long)str) > 3, JSON_TEXT("Octal will go out of bounds"), return JSON_TEXT('\0'););
str += 2;
return (json_char)(((((json_uchar)(*(str - 2) - 48))) << 6) | (((json_uchar)(*(str - 1) - 48)) << 3) | ((json_uchar)(*str - 48)));
}
#endif
void JSONWorker::SpecialChar(const json_char * & pos, const json_char * const end, json_string & res) json_nothrow {
JSON_ASSERT_SAFE(pos != end, JSON_TEXT("Special char termantion"), return;);
/*
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('u'): //utf character
#ifdef JSON_UNICODE
UTF(pos, res, end);
#else
res += UTF8(pos, end);
#endif
break;
#ifndef JSON_STRICT
case JSON_TEXT('x'): //hexidecimal ascii code
JSON_ASSERT_SAFE(((long)end - (long)pos) > 3, JSON_TEXT("Hex will go out of bounds"), res += JSON_TEXT('\0'); return;);
res += Hex(++pos);
break;
#ifdef __GNUC__
case JSON_TEXT('0') ... JSON_TEXT('7'):
#else
//octal encoding
case JSON_TEXT('0'):
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'):
#endif
res += FromOctal(pos, end);
break;
default:
res += *pos;
break;
#elif defined(JSON_DEBUG)
default:
JSON_FAIL(JSON_TEXT("Unsupported escaped character"));
break;
#endif
}
}
#ifdef JSON_LESS_MEMORY
inline void doflag(const internalJSONNode * flag, bool which, bool x) json_nothrow {
if (json_likely(which)){
flag -> _name_encoded = x;
} else {
flag -> _string_encoded = x;
}
}
json_string JSONWorker::FixString(const json_string & value_t, const internalJSONNode * flag, bool which) json_nothrow {
#define setflag(x) doflag(flag, which, x)
#else
json_string JSONWorker::FixString(const json_string & value_t, bool & flag) json_nothrow {
#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 * const end = value_t.data() + value_t.length();
for(const json_char * p = value_t.data(); p != end; ++p){
switch (*p){
case JSON_TEXT('\\'):
setflag(true);
SpecialChar(++p, end, res);
break;
default:
res += *p;
break;
}
}
shrinkString(res); //because this is actually setting something to be stored, shrink it it need be
return res;
}
#endif
#ifdef JSON_UNICODE
#ifdef JSON_ESCAPE_WRITES
json_string JSONWorker::toSurrogatePair(json_uchar C) json_nothrow {
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
unsigned short HiSurrogate = 0xD800 | (((unsigned short)((unsigned int)((C >> 16) & 31)) - 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
#endif
#ifdef JSON_ESCAPE_WRITES
json_string JSONWorker::toUTF8(json_uchar p) json_nothrow {
#ifdef JSON_UNICODE
if (json_unlikely(p > 0xFFFF)) return toSurrogatePair(p);
#endif
json_string res(JSON_TEXT("\\u"));
#ifdef JSON_UNICODE
START_MEM_SCOPE
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;
END_MEM_SCOPE
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;
}
#endif
void JSONWorker::UnfixString(const json_string & value_t, bool flag, json_string & res) json_nothrow {
if (!flag){
res += value_t;
return;
}
//Re-escapes a json_string so that it can be written out into a JSON file
const json_char * const end = value_t.data() + value_t.length();
for(const json_char * p = value_t.data(); p != end; ++p){
switch(*p){
case JSON_TEXT('\"'): //quote character
res += JSON_TEXT("\\\"");
break;
case JSON_TEXT('\\'): //backslash
res += JSON_TEXT("\\\\");
break;
#ifdef JSON_ESCAPE_WRITES
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('/'): //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;
default:
{
if (json_unlikely(((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126))){
res += toUTF8((json_uchar)(*p));
} else {
res += *p;
}
}
break;
#else
default:
res += *p;
break;
#endif
}
}
}
#ifdef JSON_READ_PRIORITY
//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) json_nothrow {
#ifdef JSON_COMMENTS
JSONNode * child;
START_MEM_SCOPE
json_string _comment;
START_MEM_SCOPE
const json_char * runner = ((array) ? value.data() : name.data());
#ifdef JSON_DEBUG
const json_char * const end = runner + value.length();
#endif
if (json_unlikely(*runner == JSON_TEMP_COMMENT_IDENTIFIER)){ //multiple comments will be consolidated into one
size_t count;
const json_char * start;
newcomment:
count = 0;
start = runner + 1;
while(*(++runner) != JSON_TEMP_COMMENT_IDENTIFIER){
JSON_ASSERT(runner != end, JSON_TEXT("Removing white space failed"));
++count;
}
if (count) _comment += json_string(start, count);
if (json_unlikely(*(++runner) == JSON_TEMP_COMMENT_IDENTIFIER)){ //step past the trailing tag
_comment += JSON_TEXT('\n');
goto newcomment;
}
}
internalJSONNode * myinternal;
if (array){
myinternal = internalJSONNode::newInternal(name, runner);
} else {
myinternal = internalJSONNode::newInternal(++runner, value);
}
child = JSONNode::newJSONNode(myinternal);
END_MEM_SCOPE
child -> set_comment(_comment);
END_MEM_SCOPE
const_cast<internalJSONNode*>(parent) -> CHILDREN -> push_back(child); //attach it to the parent node
#else
if (name.empty()){
const_cast<internalJSONNode*>(parent) -> CHILDREN -> push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(name, value))); //attach it to the parent node
} else {
const_cast<internalJSONNode*>(parent) -> CHILDREN -> push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(json_string(name.begin() + 1, name.end()), value))); //attach it to the parent node
}
#endif
}
//Create a subarray
void JSONWorker::DoArray(const internalJSONNode * parent, const json_string & value_t) json_nothrow {
//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;);
if (json_unlikely(value_t.length() <= 2)) return; // just a [] (blank array)
#ifdef JSON_SAFE
json_string newValue; //share this so it has a reserved buffer
#endif
size_t starting = 1; //ignore the [
//Not sure what's in the array, so we have to use commas
for(size_t ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, 1);
ending != json_string::npos;
ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, starting)){
#ifdef JSON_SAFE
newValue.assign(value_t.begin() + starting, value_t.begin() + ending);
JSON_ASSERT_SAFE(FIND_NEXT_RELEVANT(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
NewNode(parent, json_global(EMPTY_JSON_STRING), newValue, true);
#else
NewNode(parent, json_global(EMPTY_JSON_STRING), json_string(value_t.begin() + starting, value_t.begin() + ending), true);
#endif
starting = ending + 1;
}
//since the last one will not find the comma, we have to add it here, but ignore the final ]
#ifdef JSON_SAFE
newValue.assign(value_t.begin() + starting, value_t.end() - 1);
JSON_ASSERT_SAFE(FIND_NEXT_RELEVANT(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;);
NewNode(parent, json_global(EMPTY_JSON_STRING), newValue, true);
#else
NewNode(parent, json_global(EMPTY_JSON_STRING), json_string(value_t.begin() + starting, value_t.end() - 1), true);
#endif
}
//Create all child nodes
void JSONWorker::DoNode(const internalJSONNode * parent, const json_string & value_t) json_nothrow {
//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;);
if (json_unlikely(value_t.length() <= 2)) return; // just a {} (blank node)
size_t name_ending = FIND_NEXT_RELEVANT(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.begin() + 1, value_t.begin() + name_ending - 1); //pull the name out
for (size_t value_ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, name_ending), //find the end of the value
name_starting = 1; //ignore the {
value_ending != json_string::npos;
value_ending = FIND_NEXT_RELEVANT(JSON_TEXT(','), value_t, name_ending)){
NewNode(parent, name, json_string(value_t.begin() + name_ending + 1, value_t.begin() + value_ending), false);
name_starting = value_ending + 1;
name_ending = FIND_NEXT_RELEVANT(JSON_TEXT(':'), value_t, name_starting);
JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;);
name.assign(value_t.begin() + name_starting, value_t.begin() + name_ending - 1);
}
//since the last one will not find the comma, we have to add it here
NewNode(parent, name, json_string(value_t.begin() + name_ending + 1, value_t.end() - 1), false);
}
#endif

View file

@ -0,0 +1,65 @@
#ifndef JSON_WORKER_H
#define JSON_WORKER_H
#include "JSONNode.h"
#include "JSONSharedString.h"
class JSONWorker {
public:
static json_string RemoveWhiteSpaceAndComments(const json_string & value_t, bool escapeQuotes) json_nothrow json_read_priority;
static json_char * RemoveWhiteSpaceAndCommentsC(const json_string & value_t, bool escapeQuotes) json_nothrow json_read_priority;
#ifdef JSON_READ_PRIORITY
static JSONNode parse(const json_string & json) json_throws(std::invalid_argument) json_read_priority;
static JSONNode parse_unformatted(const json_string & json) json_throws(std::invalid_argument) json_read_priority;
static JSONNode _parse_unformatted(const json_char * json, const json_char * const end) json_throws(std::invalid_argument) json_read_priority;
static json_char * RemoveWhiteSpace(const json_string & value_t, size_t & len, bool escapeQuotes) json_nothrow json_read_priority;
static void DoArray(const internalJSONNode * parent, const json_string & value_t) json_nothrow json_read_priority;
static void DoNode(const internalJSONNode * parent, const json_string & value_t) json_nothrow json_read_priority;
#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) json_nothrow json_read_priority;
#else
#define NAME_ENCODED _name_encoded
#define STRING_ENCODED _string_encoded
static json_string FixString(const json_string & value_t, bool & flag) json_nothrow json_read_priority;
#endif
#endif
#if defined(JSON_READ_PRIORITY) || defined(JSON_STREAM)
#if (JSON_READ_PRIORITY == HIGH) && (!(defined(JSON_LESS_MEMORY)))
template<json_char ch>
static size_t FindNextRelevant(const json_string & value_t, const size_t pos) json_nothrow json_read_priority;
#else
static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos) json_nothrow json_read_priority;
#endif
#endif
static void UnfixString(const json_string & value_t, bool flag, json_string & res) json_nothrow;
JSON_PRIVATE
#ifdef JSON_READ_PRIORITY
static json_char Hex(const json_char * & pos) json_nothrow;
static json_uchar UTF8(const json_char * & pos, const json_char * const end) json_nothrow;
#endif
#ifdef JSON_ESCAPE_WRITES
static json_string toUTF8(json_uchar p) json_nothrow;
#endif
#ifdef JSON_UNICODE
static void UTF(const json_char * & pos, json_string & result, const json_char * const end) json_nothrow;
#ifdef JSON_ESCAPE_WRITES
static json_string toSurrogatePair(json_uchar pos) json_nothrow;
#endif
#endif
#ifdef JSON_READ_PRIORITY
static void SpecialChar(const json_char * & pos, const json_char * const end, json_string & res) json_nothrow;
static void NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, bool array) json_nothrow;
#endif
private:
JSONWorker(void);
};
#endif

View file

@ -0,0 +1,252 @@
#include "JSONNode.h"
#ifdef JSON_WRITE_PRIORITY
#include "JSONWorker.h"
#include "JSONGlobals.h"
extern bool used_ascii_one;
#ifdef JSON_INDENT
inline json_string makeIndent(unsigned int amount) json_nothrow json_write_priority;
inline json_string makeIndent(unsigned int amount) json_nothrow {
if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING);
json_string result;
result.reserve(amount * json_global(INDENT).length());
for(unsigned int i = 0; i < amount; ++i){
result += json_global(INDENT);
}
JSON_ASSERT(result.capacity() == amount * json_global(INDENT).length(), JSON_TEXT("makeIndent made a string too big"));
return result;
}
#else
inline json_string makeIndent(unsigned int amount) json_nothrow {
if (amount == 0xFFFFFFFF) return json_global(EMPTY_JSON_STRING);
if (json_likely(amount < 8)){
static const json_string cache[] = {
json_string(),
json_string(JSON_TEXT("\t")),
json_string(JSON_TEXT("\t\t")),
json_string(JSON_TEXT("\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t"))
};
return cache[amount];
}
#ifndef JSON_LESS_MEMORY
if (json_likely(amount < 16)){
static const json_string cache[] = {
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"))
};
return cache[amount - 8];
}
#if JSON_WRITE_PRIORITY == HIGH
if (json_likely(amount < 24)){
static const json_string cache[] = {
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")),
json_string(JSON_TEXT("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"))
};
return cache[amount - 16];
}
#endif
#endif
return json_string(amount, JSON_TEXT('\t'));
}
#endif
void internalJSONNode::WriteName(bool formatted, bool arrayChild, json_string & output) const json_nothrow {
if (!arrayChild){
output += JSON_TEXT("\"");
JSONWorker::UnfixString(_name, _name_encoded, output);
output += ((formatted) ? JSON_TEXT("\" : ") : JSON_TEXT("\":"));
}
}
void internalJSONNode::WriteChildren(unsigned int indent, json_string & output) const json_nothrow {
//Iterate through the children and write them
if (json_likely(CHILDREN -> empty())) return;
json_string indent_plus_one;
//handle whether or not it's formatted JSON
if (indent != 0xFFFFFFFF){ //it's formatted, make the indentation strings
indent_plus_one = json_global(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;
JSONNode ** it = CHILDREN -> begin();
for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){
output += indent_plus_one;
(*it) -> internal -> Write(indent, type() == JSON_ARRAY, output);
if (json_likely(i < size_minus_one)) output += JSON_TEXT(','); //the last one does not get a comma, but all of the others do
}
if (indent != 0xFFFFFFFF){
output += json_global(NEW_LINE);
output += makeIndent(indent - 1);
}
}
#ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
void internalJSONNode::WriteChildrenOneLine(unsigned int indent, json_string & output) const json_nothrow {
//Iterate through the children and write them
if (json_likely(CHILDREN -> empty())) return;
if ((*CHILDREN -> begin()) -> internal -> isContainer()) return WriteChildren(indent, output);
json_string comma(JSON_TEXT(","));
if (indent != 0xFFFFFFFF){
comma += JSON_TEXT(' ');
}
//else it's not formatted, leave the indentation strings empty
const size_t size_minus_one = CHILDREN -> size() - 1;
size_t i = 0;
JSONNode ** it = CHILDREN -> begin();
for(JSONNode ** it_end = CHILDREN -> end(); it != it_end; ++it, ++i){
(*it) -> internal -> Write(indent, type() == JSON_ARRAY, output);
if (json_likely(i < size_minus_one)) output += comma; //the last one does not get a comma, but all of the others do
}
}
#endif
#ifdef JSON_COMMENTS
void internalJSONNode::WriteComment(unsigned int indent, json_string & output) const json_nothrow {
if (indent == 0xFFFFFFFF) return;
if (json_likely(_comment.empty())) return;
size_t pos = _comment.find(JSON_TEXT('\n'));
const json_string current_indent(json_global(NEW_LINE) + makeIndent(indent));
if (json_likely(pos == json_string::npos)){ //Single line comment
output += current_indent;
output += json_global(SINGLELINE_COMMENT);
output.append(_comment.begin(), _comment.end());
output += current_indent;
return;
}
/*
Multiline comments
*/
output += current_indent;
#if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS))
const json_string current_indent_plus_one(json_global(NEW_LINE) + makeIndent(indent + 1));
output += JSON_TEXT("/*");
output += current_indent_plus_one;
#endif
size_t old = 0;
while(pos != json_string::npos){
if (json_unlikely(pos && _comment[pos - 1] == JSON_TEXT('\r'))) --pos;
#if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
output += json_global(SINGLELINE_COMMENT);
#endif
output.append(_comment.begin() + old, _comment.begin() + pos);
#if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS)
output += current_indent;
#else
output += current_indent_plus_one;
#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)
output += json_global(SINGLELINE_COMMENT);
#endif
output.append(_comment.begin() + old, _comment.end());
output += current_indent;
#if !(defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS))
output += JSON_TEXT("*/");
output += current_indent;
#endif
}
#else
inline void internalJSONNode::WriteComment(unsigned int, json_string &) const json_nothrow {}
#endif
void internalJSONNode::DumpRawString(json_string & output) const json_nothrow {
//first remove the \1 characters
if (used_ascii_one){ //if it hasn't been used yet, don't bother checking
json_string result(_string.begin(), _string.end());
for(json_string::iterator beg = result.begin(), en = result.end(); beg != en; ++beg){
if (*beg == JSON_TEXT('\1')) *beg = JSON_TEXT('\"');
}
output += result;
return;
} else {
output.append(_string.begin(), _string.end());
}
}
void internalJSONNode::Write(unsigned int indent, bool arrayChild, json_string & output) const json_nothrow {
const bool formatted = indent != 0xFFFFFFFF;
WriteComment(indent, output);
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
if (!(formatted || fetched)){ //It's not formatted or fetched, just do a raw dump
WriteName(false, arrayChild, output);
//first remove the \1 characters
DumpRawString(output);
return;
}
#endif
WriteName(formatted, arrayChild, output);
//It's either formatted or fetched
switch (_type){
case JSON_NODE: //got members, write the members
Fetch();
output += JSON_TEXT("{");
WriteChildren(indent, output);
output += JSON_TEXT("}");
return;
case JSON_ARRAY: //write out the child nodes int he array
Fetch();
output += JSON_TEXT("[");
#ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
if (size() <= JSON_ARRAY_SIZE_ON_ONE_LINE){
WriteChildrenOneLine(indent, output);
} else {
#endif
WriteChildren(indent, output);
#ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
}
#endif
output += JSON_TEXT("]");
return;
case JSON_NUMBER: //write out a literal, without quotes
case JSON_NULL:
case JSON_BOOL:
output.append(_string.begin(), _string.end());
return;
}
JSON_ASSERT(_type == JSON_STRING, JSON_TEXT("Unknown json node type"));
//If it go here, then it's a json_string
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
if (json_likely(fetched)){
#endif
output += JSON_TEXT("\"");
JSONWorker::UnfixString(_string, _string_encoded, output); //It's already been fetched, meaning that it's unescaped
output += JSON_TEXT("\"");
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
} else {
DumpRawString(output); //it hasn't yet been fetched, so it's already unescaped, just do a dump
}
#endif
}
#endif

View file

@ -0,0 +1,35 @@
#ifndef LIBJSON_GUARD_BASE64_H
#define LIBJSON_GUARD_BASE64_H
#include "JSONDebug.h"
#if defined(JSON_BINARY) || defined(JSON_EXPOSE_BASE64) //if this is not needed, don't waste space compiling it
#include "../Dependencies/libbase64++/libbase64++.h"
class JSONBase64 {
public:
inline static json_string json_encode64(const unsigned char * binary, size_t bytes) json_nothrow json_cold;
inline static std::string json_decode64(const json_string & encoded) json_nothrow json_cold;
private:
JSONBase64(void);
};
json_string JSONBase64::json_encode64(const unsigned char * binary, size_t bytes) json_nothrow {
#if defined JSON_DEBUG || defined JSON_SAFE
return libbase64::encode<json_string, json_char, json_uchar, true>(binary, bytes);
#else
return libbase64::encode<json_string, json_char, json_uchar, false>(binary, bytes);
#endif
}
std::string JSONBase64::json_decode64(const json_string & encoded) json_nothrow {
#if defined JSON_DEBUG || defined JSON_SAFE
return libbase64::decode<json_string, json_char, json_uchar, true>(encoded);
#else
return libbase64::decode<json_string, json_char, json_uchar, false>(encoded);
#endif
}
#endif
#endif

View file

@ -0,0 +1,450 @@
#ifndef NUMBERTOSTRING_H
#define NUMBERTOSTRING_H
#include <limits>
#include "JSONDebug.h"
#ifdef JSON_LESS_MEMORY
#include "JSONMemory.h"
#endif
#include "JSONSharedString.h"
#include <cstdio>
#ifdef JSON_STRICT
#include <cmath>
#endif
template <unsigned int GETLENSIZE>
struct getLenSize{
char tmp[GETLENSIZE == 16]; // compile time assertion
enum {GETLEN = 41};
};
template<>
struct getLenSize<1>{
enum {GETLEN = 5};
};
template <>
struct getLenSize<2>{
enum {GETLEN = 7};
};
template <>
struct getLenSize<4>{
enum {GETLEN = 12};
};
template <>
struct getLenSize<8>{
enum {GETLEN = 22};
};
static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_pure;
static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_nothrow {
return (one > two) ? (one - two) < JSON_FLOAT_THRESHHOLD : (one - two) > -JSON_FLOAT_THRESHHOLD;
}
#ifdef JSON_LESS_MEMORY
#define num_str_result s.ptr
#endif
class NumberToString {
public:
template<typename T>
static json_string _itoa(T val) json_nothrow {
#ifdef JSON_LESS_MEMORY
json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN);
#else
json_char num_str_result[getLenSize<sizeof(T)>::GETLEN];
#endif
num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator
json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2];
bool negative;
START_MEM_SCOPE
long value = (long)val;
//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);
END_MEM_SCOPE
//if it's negative, add the negation
if (negative){
*runner = JSON_TEXT('-');
return json_string(runner);
}
return json_string(runner + 1);
}
#ifndef JSON_LIBRARY
template<typename T>
static json_string _uitoa(T val) json_nothrow {
#ifdef JSON_LESS_MEMORY
json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN);
#else
json_char num_str_result[getLenSize<sizeof(T)>::GETLEN];
#endif
num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator
json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2];
//create the string
START_MEM_SCOPE
unsigned long value = (unsigned long)val;
do {
*runner-- = (json_char)(value % 10) + JSON_TEXT('0');
} while(value /= 10);
END_MEM_SCOPE
return json_string(runner + 1);
}
#endif
#ifdef JSON_ISO_STRICT
#define EXTRA_LONG
#define FLOAT_STRING "%f"
#define LFLOAT_STRING L"%f"
#else
#define EXTRA_LONG long
#define FLOAT_STRING "%Lf"
#define LFLOAT_STRING L"%Lf"
#endif
static json_string _ftoa(json_number value) json_nothrow {
#ifndef JSON_LIBRARY
//ScopeCoverage(_ftoa_coverage, 6);
if (json_unlikely(value >= 0.0 && _floatsAreEqual(value, (json_number)((unsigned EXTRA_LONG long)value)))){
return _uitoa<unsigned EXTRA_LONG long>((unsigned EXTRA_LONG long)value);
} else
#else
//ScopeCoverage(_ftoa_coverage, 5);
#endif
if (json_unlikely(_floatsAreEqual(value, (json_number)((long EXTRA_LONG)value)))){
return _itoa<long EXTRA_LONG>((long EXTRA_LONG)value);
}
#ifdef JSON_LESS_MEMORY
json_auto<json_char> s(64);
#else
json_char num_str_result[64];
#endif
#ifdef JSON_UNICODE
std::swprintf(num_str_result, 63, LFLOAT_STRING, (EXTRA_LONG double)value);
#else
//Thanks to Salvor Hardin for this Visual C++ fix
#ifdef _MSC_VER
_snprintf_s(num_str_result, 63, 63, FLOAT_STRING, (EXTRA_LONG double)value); //yes, 63 appears twice using _snprintf_s()
#else
snprintf(num_str_result, 63, FLOAT_STRING, (EXTRA_LONG double)value);
#endif
#endif
//strip the trailing zeros
for(json_char * pos = &num_str_result[0]; *pos; ++pos){
if (json_unlikely(*pos == '.')){ //only care about after the decimal
for(json_char * runner = pos + 1; *runner; ++runner){
if (json_likely(*runner != JSON_TEXT('0'))){
pos = runner + 1; //have to go to the end 1.0001
}
}
*pos = JSON_TEXT('\0');
break;
}
}
return json_string(num_str_result);
}
#if defined(JSON_SAFE) || defined(JSON_DEBUG)
static bool isNumeric(const json_string & str) json_nothrow {
const json_char * p = str.c_str();
bool decimal = false;
bool scientific = false;
#ifdef JSON_STRICT
bool leadingzero = false;
#endif
//first letter is weird
switch(*p){
case JSON_TEXT('\0'):
return false;
#ifndef JSON_STRICT
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('+'):
#endif
case JSON_TEXT('-'):
switch (*(p + 1)){
case JSON_TEXT('.'):
case JSON_TEXT('e'):
case JSON_TEXT('E'):
case JSON_TEXT('\0'):
return false;
case JSON_TEXT('0'):
#ifdef JSON_STRICT
switch(*(p + 2)){
case JSON_TEXT('.'):
case JSON_TEXT('e'):
case JSON_TEXT('E'):
leadingzero = false;
break;
case JSON_TEXT('\0'):
return true;
default:
leadingzero = true;
break;
}
#endif
++p;
break;
default:
break;
}
break;
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('8'):
case JSON_TEXT('9'):
break;
case JSON_TEXT('0'):
++p;
#ifdef JSON_STRICT
leadingzero = true;
#endif
switch(*p){
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
#ifdef JSON_STRICT
leadingzero = false; //not leading, just a zero
#endif
scientific = true;
++p;
switch(*p){
case JSON_TEXT('\0'):
return false;
case JSON_TEXT('-'):
case JSON_TEXT('+'):
#ifndef JSON_STRICT
case JSON_TEXT('0'): //cant have a leading zero in scrict
#endif
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('8'):
case JSON_TEXT('9'):
break;
default:
return false;
}
break;
#ifndef JSON_STRICT
case JSON_TEXT('x'):
return (str.find_first_not_of(JSON_TEXT("0123456789ABCDEFabcdef"), 2) == json_string::npos);
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'):
return (str.find_first_not_of(JSON_TEXT("01234567"), 1) == json_string::npos);
#endif
case JSON_TEXT('\0'): //just 0
return true;
default:
return false;
}
break;
default:
return false;
}
++p;
//next digits
while (*p){
switch(*p){
case JSON_TEXT('.'):
if (json_unlikely(decimal)){
return false; //multiple decimals
}
if (json_unlikely(scientific)){
return false;
}
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
if (json_unlikely(scientific)){
return false;
}
scientific = true;
++p;
switch(*p){
case JSON_TEXT('\0'):
return false;
case JSON_TEXT('-'):
case JSON_TEXT('+'):
if (!isdigit(*(p + 1))){
return false;
}
#ifdef JSON_STRICT
if (*(p + 1) == JSON_TEXT('0')){ //no leading zeros on scientific notations
return false;
}
#endif
break;
#ifndef JSON_STRICT
case JSON_TEXT('0'): //cant have a leading zero in scrict
#endif
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('8'):
case JSON_TEXT('9'):
break;
default:
return false;
}
break;
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
break;
default:
return false;
}
++p;
}
#ifdef JSON_STRICT
if (leadingzero && !decimal){
return false;
}
#endif
return true;
}
#endif
#ifdef JSON_STRICT
//much faster because no octal or hex support
static json_number _atof (const json_char * num){
json_number sign = (json_number)1.0;
//sign
if (*num==JSON_TEXT('-')){
sign = -1.0;
++num;
} else {
}
//skip leading zero if one
#if defined(JSON_SAFE) || defined(JSON_DEBUG)
bool _leadingzeros = *num == JSON_TEXT('0');
bool _leadingdigits = false;
#endif
if (*num == JSON_TEXT('0')){
++num;
}
#ifdef JSON_STRICT
else if (json_likely(*num < JSON_TEXT('1') || *num > JSON_TEXT('9'))){
return std::numeric_limits<json_number>::signaling_NaN();
}
#endif
JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("multiple leading zeros"), return std::numeric_limits<json_number>::signaling_NaN(); );
// Number
json_number n = (json_number)0.0;
if (json_likely(*num >= JSON_TEXT('1') && *num <= JSON_TEXT('9'))){
#if defined(JSON_SAFE) || defined(JSON_DEBUG)
_leadingdigits = true;
#endif
do {
n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
} while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9'));
} else {
JSON_ASSERT_SAFE(
(*num) == JSON_TEXT('.') || //.xxx
(*num) == JSON_TEXT('e') || //0Exxx
(*num) == JSON_TEXT('E') || //0exxx
(*num) == JSON_TEXT('\0') //end of the number, just zero
, JSON_TEXT("first digit not a number, e, period, or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
}
// Fractional part
json_number scale = (json_number)0.0;
if (*num == JSON_TEXT('.')) {
JSON_ASSERT_SAFE(_leadingzeros || _leadingdigits, JSON_TEXT("period without leading anything"), return std::numeric_limits<json_number>::signaling_NaN(); );
++num;
for(; *num >= JSON_TEXT('0') && *num <= JSON_TEXT('9');){
n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
--scale;
};
} else {
JSON_ASSERT_SAFE(!_leadingzeros || n == 0, JSON_TEXT("leading zero on an int"), return std::numeric_limits<json_number>::signaling_NaN(); );
JSON_ASSERT_SAFE(
(*num) == JSON_TEXT('e') || //0Exxx
(*num) == JSON_TEXT('E') || //0exxx
(*num) == JSON_TEXT('\0') //end of the number, just zero
, JSON_TEXT("next char not an e or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
}
// Exponent
int subscale = 0, signsubscale = 1;
if (json_unlikely(*num == JSON_TEXT('e') || *num == JSON_TEXT('E'))){
++num;
switch(*num){
case JSON_TEXT('+'):
++num;
break;
case JSON_TEXT('-'):
signsubscale = -1;
++num;
JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("negative cant be followed by leading zero even after E"), return std::numeric_limits<json_number>::signaling_NaN(); );
break;
default:
break;
}
JSON_ASSERT_SAFE(*num != JSON_TEXT('\0'), JSON_TEXT("no exponent for scientific notation"), return std::numeric_limits<json_number>::signaling_NaN(); );
while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9')){
subscale=(subscale * 10) + (*num++ - JSON_TEXT('0'));
}
}
JSON_ASSERT_SAFE(*num == JSON_TEXT('\0'), JSON_TEXT("done with number, not at terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
return sign * n * pow((json_number)10.0, scale + subscale * signsubscale); // number = +/- number.fraction * 10^+/- exponent
}
#endif
};
#endif

View file

@ -0,0 +1,450 @@
#ifndef NUMBERTOSTRING_H
#define NUMBERTOSTRING_H
#include <limits>
#include "JSONDebug.h"
#ifdef JSON_LESS_MEMORY
#include "JSONMemory.h"
#endif
#include "JSONSharedString.h"
#include <cstdio>
#ifdef JSON_STRICT
#include <cmath>
#endif
template <unsigned int GETLENSIZE>
struct getLenSize{
char tmp[GETLENSIZE == 16]; // compile time assertion
enum {GETLEN = 41};
};
template<>
struct getLenSize<1>{
enum {GETLEN = 5};
};
template <>
struct getLenSize<2>{
enum {GETLEN = 7};
};
template <>
struct getLenSize<4>{
enum {GETLEN = 12};
};
template <>
struct getLenSize<8>{
enum {GETLEN = 22};
};
static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_pure;
static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_nothrow {
return (one > two) ? (one - two) < JSON_FLOAT_THRESHHOLD : (one - two) > -JSON_FLOAT_THRESHHOLD;
}
#ifdef JSON_LESS_MEMORY
#define num_str_result s.ptr
#endif
class NumberToString {
public:
template<typename T>
static json_string _itoa(T val) json_nothrow {
#ifdef JSON_LESS_MEMORY
json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN);
#else
json_char num_str_result[getLenSize<sizeof(T)>::GETLEN];
#endif
num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator
json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2];
bool negative;
START_MEM_SCOPE
long value = (long)val;
//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);
END_MEM_SCOPE
//if it's negative, add the negation
if (negative){
*runner = JSON_TEXT('-');
return json_string(runner);
}
return json_string(runner + 1);
}
#ifndef JSON_LIBRARY
template<typename T>
static json_string _uitoa(T val) json_nothrow {
#ifdef JSON_LESS_MEMORY
json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN);
#else
json_char num_str_result[getLenSize<sizeof(T)>::GETLEN];
#endif
num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator
json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2];
//create the string
START_MEM_SCOPE
unsigned long value = (unsigned long)val;
do {
*runner-- = (json_char)(value % 10) + JSON_TEXT('0');
} while(value /= 10);
END_MEM_SCOPE
return json_string(runner + 1);
}
#endif
#ifdef JSON_ISO_STRICT
#define EXTRA_LONG
#define FLOAT_STRING "%f"
#define LFLOAT_STRING L"%f"
#else
#define EXTRA_LONG long
#define FLOAT_STRING "%Lf"
#define LFLOAT_STRING L"%Lf"
#endif
static json_string _ftoa(json_number value) json_nothrow {
#ifndef JSON_LIBRARY
//ScopeCoverage(_ftoa_coverage, 6);
if (json_unlikely(value >= 0.0 && _floatsAreEqual(value, (json_number)((unsigned EXTRA_LONG long)value)))){
return _uitoa<unsigned EXTRA_LONG long>((unsigned EXTRA_LONG long)value);
} else
#else
//ScopeCoverage(_ftoa_coverage, 5);
#endif
if (json_unlikely(_floatsAreEqual(value, (json_number)((long EXTRA_LONG)value)))){
return _itoa<long EXTRA_LONG>((long EXTRA_LONG)value);
}
#ifdef JSON_LESS_MEMORY
json_auto<json_char> s(64);
#else
json_char num_str_result[64];
#endif
#ifdef JSON_UNICODE
std::swprintf(num_str_result, 63, LFLOAT_STRING, (EXTRA_LONG double)value);
#else
//Thanks to Salvor Hardin for this Visual C++ fix
#ifdef _MSC_VER
_snprintf_s(num_str_result, 63, 63, FLOAT_STRING, (EXTRA_LONG double)value); //yes, 63 appears twice using _snprintf_s()
#else
std::snprintf(num_str_result, 63, FLOAT_STRING, (EXTRA_LONG double)value);
#endif
#endif
//strip the trailing zeros
for(json_char * pos = &num_str_result[0]; *pos; ++pos){
if (json_unlikely(*pos == '.')){ //only care about after the decimal
for(json_char * runner = pos + 1; *runner; ++runner){
if (json_likely(*runner != JSON_TEXT('0'))){
pos = runner + 1; //have to go to the end 1.0001
}
}
*pos = JSON_TEXT('\0');
break;
}
}
return json_string(num_str_result);
}
#if defined(JSON_SAFE) || defined(JSON_DEBUG)
static bool isNumeric(const json_string & str) json_nothrow {
const json_char * p = str.c_str();
bool decimal = false;
bool scientific = false;
#ifdef JSON_STRICT
bool leadingzero = false;
#endif
//first letter is weird
switch(*p){
case JSON_TEXT('\0'):
return false;
#ifndef JSON_STRICT
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('+'):
#endif
case JSON_TEXT('-'):
switch (*(p + 1)){
case JSON_TEXT('.'):
case JSON_TEXT('e'):
case JSON_TEXT('E'):
case JSON_TEXT('\0'):
return false;
case JSON_TEXT('0'):
#ifdef JSON_STRICT
switch(*(p + 2)){
case JSON_TEXT('.'):
case JSON_TEXT('e'):
case JSON_TEXT('E'):
leadingzero = false;
break;
case JSON_TEXT('\0'):
return true;
default:
leadingzero = true;
break;
}
#endif
++p;
break;
default:
break;
}
break;
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('8'):
case JSON_TEXT('9'):
break;
case JSON_TEXT('0'):
++p;
#ifdef JSON_STRICT
leadingzero = true;
#endif
switch(*p){
case JSON_TEXT('.'):
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
#ifdef JSON_STRICT
leadingzero = false; //not leading, just a zero
#endif
scientific = true;
++p;
switch(*p){
case JSON_TEXT('\0'):
return false;
case JSON_TEXT('-'):
case JSON_TEXT('+'):
#ifndef JSON_STRICT
case JSON_TEXT('0'): //cant have a leading zero in scrict
#endif
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('8'):
case JSON_TEXT('9'):
break;
default:
return false;
}
break;
#ifndef JSON_STRICT
case JSON_TEXT('x'):
return (str.find_first_not_of(JSON_TEXT("0123456789ABCDEFabcdef"), 2) == json_string::npos);
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'):
return (str.find_first_not_of(JSON_TEXT("01234567"), 1) == json_string::npos);
#endif
case JSON_TEXT('\0'): //just 0
return true;
default:
return false;
}
break;
default:
return false;
}
++p;
//next digits
while (*p){
switch(*p){
case JSON_TEXT('.'):
if (json_unlikely(decimal)){
return false; //multiple decimals
}
if (json_unlikely(scientific)){
return false;
}
decimal = true;
break;
case JSON_TEXT('e'):
case JSON_TEXT('E'):
if (json_unlikely(scientific)){
return false;
}
scientific = true;
++p;
switch(*p){
case JSON_TEXT('\0'):
return false;
case JSON_TEXT('-'):
case JSON_TEXT('+'):
if (!isdigit(*(p + 1))){
return false;
}
#ifdef JSON_STRICT
if (*(p + 1) == JSON_TEXT('0')){ //no leading zeros on scientific notations
return false;
}
#endif
break;
#ifndef JSON_STRICT
case JSON_TEXT('0'): //cant have a leading zero in scrict
#endif
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('8'):
case JSON_TEXT('9'):
break;
default:
return false;
}
break;
case JSON_TEXT('0'):
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('8'):
case JSON_TEXT('9'):
break;
default:
return false;
}
++p;
}
#ifdef JSON_STRICT
if (leadingzero && !decimal){
return false;
}
#endif
return true;
}
#endif
#ifdef JSON_STRICT
//much faster because no octal or hex support
static json_number _atof (const json_char * num){
json_number sign = (json_number)1.0;
//sign
if (*num==JSON_TEXT('-')){
sign = -1.0;
++num;
} else {
}
//skip leading zero if one
#if defined(JSON_SAFE) || defined(JSON_DEBUG)
bool _leadingzeros = *num == JSON_TEXT('0');
bool _leadingdigits = false;
#endif
if (*num == JSON_TEXT('0')){
++num;
}
#ifdef JSON_STRICT
else if (json_likely(*num < JSON_TEXT('1') || *num > JSON_TEXT('9'))){
return std::numeric_limits<json_number>::signaling_NaN();
}
#endif
JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("multiple leading zeros"), return std::numeric_limits<json_number>::signaling_NaN(); );
// Number
json_number n = (json_number)0.0;
if (json_likely(*num >= JSON_TEXT('1') && *num <= JSON_TEXT('9'))){
#if defined(JSON_SAFE) || defined(JSON_DEBUG)
_leadingdigits = true;
#endif
do {
n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
} while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9'));
} else {
JSON_ASSERT_SAFE(
(*num) == JSON_TEXT('.') || //.xxx
(*num) == JSON_TEXT('e') || //0Exxx
(*num) == JSON_TEXT('E') || //0exxx
(*num) == JSON_TEXT('\0') //end of the number, just zero
, JSON_TEXT("first digit not a number, e, period, or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
}
// Fractional part
json_number scale = (json_number)0.0;
if (*num == JSON_TEXT('.')) {
JSON_ASSERT_SAFE(_leadingzeros || _leadingdigits, JSON_TEXT("period without leading anything"), return std::numeric_limits<json_number>::signaling_NaN(); );
++num;
for(; *num >= JSON_TEXT('0') && *num <= JSON_TEXT('9');){
n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
--scale;
};
} else {
JSON_ASSERT_SAFE(!_leadingzeros || n == 0, JSON_TEXT("leading zero on an int"), return std::numeric_limits<json_number>::signaling_NaN(); );
JSON_ASSERT_SAFE(
(*num) == JSON_TEXT('e') || //0Exxx
(*num) == JSON_TEXT('E') || //0exxx
(*num) == JSON_TEXT('\0') //end of the number, just zero
, JSON_TEXT("next char not an e or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
}
// Exponent
int subscale = 0, signsubscale = 1;
if (json_unlikely(*num == JSON_TEXT('e') || *num == JSON_TEXT('E'))){
++num;
switch(*num){
case JSON_TEXT('+'):
++num;
break;
case JSON_TEXT('-'):
signsubscale = -1;
++num;
JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("negative cant be followed by leading zero even after E"), return std::numeric_limits<json_number>::signaling_NaN(); );
break;
default:
break;
}
JSON_ASSERT_SAFE(*num != JSON_TEXT('\0'), JSON_TEXT("no exponent for scientific notation"), return std::numeric_limits<json_number>::signaling_NaN(); );
while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9')){
subscale=(subscale * 10) + (*num++ - JSON_TEXT('0'));
}
}
JSON_ASSERT_SAFE(*num == JSON_TEXT('\0'), JSON_TEXT("done with number, not at terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
return sign * n * pow((json_number)10.0, scale + subscale * signsubscale); // number = +/- number.fraction * 10^+/- exponent
}
#endif
};
#endif

View file

@ -0,0 +1,828 @@
#include "internalJSONNode.h"
#include "NumberToString.h" //So that I can convert numbers into strings
#include "JSONNode.h" //To fill in the foreward declaration
#include "JSONWorker.h" //For fetching and parsing and such
#include "JSONGlobals.h"
internalJSONNode::internalJSONNode(const internalJSONNode & orig) json_nothrow :
_type(orig._type), _name(orig._name), _name_encoded(orig._name_encoded),
_string(orig._string), _string_encoded(orig._string_encoded), _value(orig._value)
initializeMutex(0)
initializeRefCount(1)
initializeFetch(orig.fetched)
initializeComment(orig._comment)
initializeChildren(0){
LIBJSON_COPY_CTOR;
if (isContainer()){
CHILDREN = jsonChildren::newChildren();
if (json_likely(!orig.CHILDREN -> empty())){
CHILDREN -> reserve(orig.CHILDREN -> size());
json_foreach(orig.CHILDREN, myrunner){
CHILDREN -> push_back(JSONNode::newJSONNode((*myrunner) -> duplicate()));
}
}
}
#ifdef JSON_MUTEX_CALLBACKS /*-> JSON_MUTEX_CALLBACKS */
_set_mutex(orig.mylock, false);
#endif /*<- */
}
#ifdef JSON_PREPARSE /*-> JSON_PREPARSE */
#define SetFetchedFalseOrDo(code) code
#else /*<- else */
#define SetFetchedFalseOrDo(code) SetFetched(false)
#endif /*<- */
//this one is specialized because the root can only be array or node
#ifdef JSON_READ_PRIORITY /*-> JSON_READ_PRIORITY */
internalJSONNode::internalJSONNode(const json_string & unparsed) json_nothrow : _type(), _name(),_name_encoded(false), _string(unparsed), _string_encoded(), _value()
initializeMutex(0)
initializeRefCount(1)
initializeFetch(false)
initializeComment(json_global(EMPTY_JSON_STRING))
initializeChildren(0){
LIBJSON_CTOR;
switch (unparsed[0]){
case JSON_TEXT('{'): //node
_type = JSON_NODE;
CHILDREN = jsonChildren::newChildren();
#ifdef JSON_PREPARSE
FetchNode();
#endif
break;
case JSON_TEXT('['): //array
_type = JSON_ARRAY;
CHILDREN = jsonChildren::newChildren();
#ifdef JSON_PREPARSE
FetchArray();
#endif
break;
default:
JSON_FAIL_SAFE(JSON_TEXT("root not starting with either { or ["), Nullify(););
break;
}
}
#ifndef JSON_STRICT
#define LETTERCASE(x, y)\
case JSON_TEXT(x):\
case JSON_TEXT(y)
#else
#define LETTERCASE(x, y)\
case JSON_TEXT(x)
#endif
internalJSONNode::internalJSONNode(const json_string & name_t, const json_string & value_t) json_nothrow : _type(), _name_encoded(), _name(JSONWorker::FixString(name_t, NAME_ENCODED)), _string(), _string_encoded(), _value()
initializeMutex(0)
initializeRefCount(1)
initializeFetch(false)
initializeComment(json_global(EMPTY_JSON_STRING))
initializeChildren(0){
LIBJSON_CTOR;
#ifdef JSON_STRICT
JSON_ASSERT_SAFE(!value_t.empty(), JSON_TEXT("empty node"), Nullify(); return;);
#else
if (json_unlikely(value_t.empty())){
_type = JSON_NULL;
SetFetched(true);
return;
}
#endif
_string = value_t;
const json_char firstchar = value_t[0];
#if defined JSON_DEBUG || defined JSON_SAFE
const json_char lastchar = value_t[value_t.length() - 1];
#endif
switch (firstchar){
case JSON_TEXT('\"'): //a json_string literal, still escaped and with leading and trailing quotes
JSON_ASSERT_SAFE(lastchar == JSON_TEXT('\"'), JSON_TEXT("Unterminated quote"), Nullify(); return;);
_type = JSON_STRING;
SetFetchedFalseOrDo(FetchString());
break;
case JSON_TEXT('{'): //a child node, or set of children
JSON_ASSERT_SAFE(lastchar == JSON_TEXT('}'), JSON_TEXT("Missing }"), Nullify(); return;);
_type = JSON_NODE;
CHILDREN = jsonChildren::newChildren();
SetFetchedFalseOrDo(FetchNode());
break;
case JSON_TEXT('['): //an array
JSON_ASSERT_SAFE(lastchar == JSON_TEXT(']'), JSON_TEXT("Missing ]"), Nullify(); return;);
_type = JSON_ARRAY;
CHILDREN = jsonChildren::newChildren();
SetFetchedFalseOrDo(FetchArray());
break;
LETTERCASE('t', 'T'):
JSON_ASSERT_SAFE(value_t == json_global(CONST_TRUE), json_string(json_global(ERROR_UNKNOWN_LITERAL) + value_t).c_str(), Nullify(); return;);
_value._bool = true;
_type = JSON_BOOL;
SetFetched(true);
break;
LETTERCASE('f', 'F'):
JSON_ASSERT_SAFE(value_t == json_global(CONST_FALSE), json_string(json_global(ERROR_UNKNOWN_LITERAL) + value_t).c_str(), Nullify(); return;);
_value._bool = false;
_type = JSON_BOOL;
SetFetched(true);
break;
LETTERCASE('n', 'N'):
JSON_ASSERT_SAFE(value_t == json_global(CONST_NULL), json_string(json_global(ERROR_UNKNOWN_LITERAL) + value_t).c_str(), Nullify(); return;);
_type = JSON_NULL;
SetFetched(true);
break;
default:
JSON_ASSERT_SAFE(NumberToString::isNumeric(value_t), json_string(json_global(ERROR_UNKNOWN_LITERAL) + value_t).c_str(), Nullify(); return;);
_type = JSON_NUMBER;
SetFetchedFalseOrDo(FetchNumber());
break;
}
}
#endif /*<- */
internalJSONNode::~internalJSONNode(void) json_nothrow {
LIBJSON_DTOR;
#ifdef JSON_MUTEX_CALLBACKS
_unset_mutex();
#endif /*<- */
DELETE_CHILDREN();
}
#ifdef JSON_READ_PRIORITY
void internalJSONNode::FetchString(void) const json_nothrow {
JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON json_string type is empty?"), Nullify(); return;);
JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't start with a quotation?"), Nullify(); return;);
JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't end with a quotation?"), Nullify(); return;);
_string = JSONWorker::FixString(json_string(_string.begin() + 1, _string.end() - 1), STRING_ENCODED);
#ifdef JSON_LESS_MEMORY
JSON_ASSERT(_string.capacity() == _string.length(), JSON_TEXT("_string object too large 2"));
#endif
}
void internalJSONNode::FetchNode(void) const json_nothrow {
JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(); return;);
JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('{'), JSON_TEXT("JSON node type doesn't start with a bracket?"), Nullify(); return;);
JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('}'), JSON_TEXT("JSON node type doesn't end with a bracket?"), Nullify(); return;);
JSONWorker::DoNode(this, _string);
clearString(_string);
}
void internalJSONNode::FetchArray(void) const json_nothrow {
JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(); return;);
JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('['), JSON_TEXT("JSON node type doesn't start with a square bracket?"), Nullify(); return;);
JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT(']'), JSON_TEXT("JSON node type doesn't end with a square bracket?"), Nullify(); return;);
JSONWorker::DoArray(this, _string);
clearString(_string);
}
#endif
//This one is used by as_int and as_float, so even non-readers need it
void internalJSONNode::FetchNumber(void) const json_nothrow {
#ifdef JSON_STRICT
_value._number = NumberToString::_atof(_string.c_str());
#else
#ifdef JSON_UNICODE
const size_t len = _string.length();
#if defined(_MSC_VER) && defined(JSON_SAFE)
const size_t bytes = (len * (sizeof(json_char) / sizeof(char))) + 1;
json_auto<char> temp(bytes);
size_t res;
errno_t err = wcstombs_s(&res, temp.ptr, bytes, _string.c_str(), len);
if (err != 0){
_value._number = (json_number)0.0;
return;
}
#elif defined(JSON_SAFE)
const size_t bytes = (len * (sizeof(json_char) / sizeof(char))) + 1;
json_auto<char> temp(bytes);
size_t res = std::wcstombs(temp.ptr, _string.c_str(), len);
if (res == (size_t)-1){
_value._number = (json_number)0.0;
return;
}
#else
json_auto<char> temp(len + 1);
size_t res = std::wcstombs(temp.ptr, _string.c_str(), len);
#endif
temp.ptr[res] = '\0';
_value._number = (json_number)std::atof(temp.ptr);
#else
_value._number = (json_number)std::atof(_string.c_str());
#endif
#endif
#if((!defined(JSON_CASTABLE) && defined(JSON_LESS_MEMORY)) && !defined(JSON_WRITE_PRIORITY))
clearString(_string);
#endif
}
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
void internalJSONNode::Fetch(void) const json_nothrow {
if (fetched) return;
switch (type()){
case JSON_STRING:
FetchString();
break;
case JSON_NODE:
FetchNode();
break;
case JSON_ARRAY:
FetchArray();
break;
case JSON_NUMBER:
FetchNumber();
break;
#if defined JSON_DEBUG || defined JSON_SAFE
default:
JSON_FAIL(JSON_TEXT("Fetching an unknown type"));
Nullify();
#endif
}
fetched = true;
}
#endif
void internalJSONNode::Set(const json_string & val) json_nothrow {
makeNotContainer();
_type = JSON_STRING;
_string = val;
shrinkString(_string);
_string_encoded = true;
SetFetched(true);
}
#ifdef JSON_LIBRARY
void internalJSONNode::Set(json_int_t val) json_nothrow {
makeNotContainer();
_type = JSON_NUMBER;
_value._number = (json_number)val;
#if(defined(JSON_CASTABLE) || !defined(JSON_LESS_MEMORY) || defined(JSON_WRITE_PRIORITY))
_string = NumberToString::_itoa<json_int_t>(val);
#else
clearString(_string);
#endif
SetFetched(true);
}
void internalJSONNode::Set(json_number val) json_nothrow {
makeNotContainer();
_type = JSON_NUMBER;
_value._number = val;
#if(defined(JSON_CASTABLE) || !defined(JSON_LESS_MEMORY) || defined(JSON_WRITE_PRIORITY))
_string = NumberToString::_ftoa(val);
#else
clearString(_string);
#endif
SetFetched(true);
}
#else
#if(defined(JSON_CASTABLE) || !defined(JSON_LESS_MEMORY) || defined(JSON_WRITE_PRIORITY))
#define SET(converter, type)\
void internalJSONNode::Set(type val) json_nothrow {\
makeNotContainer();\
_type = JSON_NUMBER;\
_value._number = (json_number)val;\
_string = NumberToString::converter<type>(val);\
SetFetched(true);\
}
#define SET_FLOAT(type) \
void internalJSONNode::Set(type val) json_nothrow {\
makeNotContainer();\
_type = JSON_NUMBER;\
_value._number = (json_number)val;\
_string = NumberToString::_ftoa(_value._number);\
SetFetched(true);\
}
#else /*<- else */
#define SET(converter, type)\
void internalJSONNode::Set(type val) json_nothrow {\
makeNotContainer();\
_type = JSON_NUMBER;\
_value._number = (json_number)val;\
clearString(_string);\
SetFetched(true);\
}
#define SET_FLOAT(type) \
void internalJSONNode::Set(type val) json_nothrow {\
makeNotContainer();\
_type = JSON_NUMBER;\
_value._number = (json_number)val;\
clearString(_string);\
SetFetched(true);\
}
#endif
#define SET_INTEGER(type) SET(_itoa, type) SET(_uitoa, unsigned type)
SET_INTEGER(char)
SET_INTEGER(short)
SET_INTEGER(int)
SET_INTEGER(long)
#ifndef JSON_ISO_STRICT
SET_INTEGER(long long)
SET_FLOAT(long double)
#endif
SET_FLOAT(float)
SET_FLOAT(double)
#endif
void internalJSONNode::Set(bool val) json_nothrow {
makeNotContainer();
_type = JSON_BOOL;
_value._bool = val;
#if(defined(JSON_CASTABLE) || !defined(JSON_LESS_MEMORY) || defined(JSON_WRITE_PRIORITY))
_string = val ? json_global(CONST_TRUE) : json_global(CONST_FALSE);
#endif
SetFetched(true);
}
bool internalJSONNode::IsEqualTo(const internalJSONNode * val) const json_nothrow {
if (this == val) return true; //same internal object, so they must be equal (not only for ref counting)
if (type() != val -> type()) return false; //aren't even same type
if (_name != val -> _name) return false; //names aren't the same
if (type() == JSON_NULL) return true; //both null, can't be different
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
Fetch();
val -> Fetch();
#endif
switch (type()){
case JSON_STRING:
return val -> _string == _string;
case JSON_NUMBER:
return _floatsAreEqual(val -> _value._number, _value._number);
case JSON_BOOL:
return val -> _value._bool == _value._bool;
};
JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Checking for equality, not sure what type"));
if (CHILDREN -> size() != val -> CHILDREN -> size()) return false; //if they arne't he same size then they certainly aren't equal
//make sure each children is the same
JSONNode ** valrunner = val -> CHILDREN -> begin();
json_foreach(CHILDREN, myrunner){
JSON_ASSERT(*myrunner != NULL, json_global(ERROR_NULL_IN_CHILDREN));
JSON_ASSERT(*valrunner != NULL, json_global(ERROR_NULL_IN_CHILDREN));
JSON_ASSERT(valrunner != val -> CHILDREN -> end(), JSON_TEXT("at the end of other one's children, but they're the same size?"));
if (**myrunner != **valrunner) return false;
++valrunner;
}
return true;
}
void internalJSONNode::Nullify(void) const json_nothrow {
_type = JSON_NULL;
#if(defined(JSON_CASTABLE) || !defined(JSON_LESS_MEMORY) || defined(JSON_WRITE_PRIORITY)) /*-> JSON_CASTABLE || !JSON_LESS_MEMORY || JSON_WRITE_PRIORITY */
_string = json_global(CONST_NULL);
#else /*<- else */
clearString(_string);
#endif /*<- */
SetFetched(true);
}
#ifdef JSON_MUTEX_CALLBACKS /*-> JSON_MUTEX_CALLBACKS */
#define JSON_MUTEX_COPY ,mylock
#else /*<- else */
#define JSON_MUTEX_COPY
#endif /*<- */
#ifdef JSON_LIBRARY /*-> JSON_LIBRARY */
void internalJSONNode::push_back(JSONNode * node) json_nothrow {
#else /*<- else */
void internalJSONNode::push_back(const JSONNode & node) json_nothrow {
#endif /*<- */
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("push_back"), return;);
#ifdef JSON_LIBRARY /*-> JSON_LIBRARY */
#ifdef JSON_MUTEX_CALLBACKS /*-> JSON_MUTEX_CALLBACKS */
if (mylock != 0) node -> set_mutex(mylock);
#endif /*<- */
CHILDREN -> push_back(node);
#else /*<- else */
CHILDREN -> push_back(JSONNode::newJSONNode(node JSON_MUTEX_COPY));
#endif /*<- */
}
void internalJSONNode::push_front(const JSONNode & node) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("push_front"), return;);
CHILDREN -> push_front(JSONNode::newJSONNode(node JSON_MUTEX_COPY));
}
JSONNode * internalJSONNode::pop_back(json_index_t pos) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("pop_back"), return 0;);
JSONNode * result = (*CHILDREN)[pos];
JSONNode ** temp = CHILDREN -> begin() + pos;
CHILDREN -> erase(temp);
return result;
}
JSONNode * internalJSONNode::pop_back(const json_string & name_t) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("pop_back(str)"), return 0;);
if (JSONNode ** res = at(name_t)){
JSONNode * result = *res;
CHILDREN -> erase(res);
return result;
}
return 0;
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS /*-> JSON_CASE_INSENSITIVE_FUNCTIONS */
JSONNode * internalJSONNode::pop_back_nocase(const json_string & name_t) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("pop_back_nocase"), return 0;);
if (JSONNode ** res = at_nocase(name_t)){
JSONNode * result = *res;
CHILDREN -> erase(res);
return result;
}
return 0;
}
#endif /*<- */
JSONNode ** internalJSONNode::at(const json_string & name_t) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("at"), return 0;);
Fetch();
json_foreach(CHILDREN, myrunner){
JSON_ASSERT(*myrunner != NULL, json_global(ERROR_NULL_IN_CHILDREN));
if (json_unlikely((*myrunner) -> name() == name_t)) return myrunner;
}
return 0;
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS /*-> JSON_CASE_INSENSITIVE_FUNCTIONS */
bool internalJSONNode::AreEqualNoCase(const json_char * ch_one, const json_char * ch_two) json_nothrow {
while (*ch_one){ //only need to check one, if the other one terminates early, the check will cause it to fail
const json_char c_one = *ch_one;
const json_char c_two = *ch_two;
if (c_one != c_two){
if ((c_two > 64) && (c_two < 91)){ //A - Z
if (c_one != (json_char)(c_two + 32)) return false;
} else if ((c_two > 96) && (c_two < 123)){ //a - z
if (c_one != (json_char)(c_two - 32)) return false;
} else { //not a letter, so return false
return false;
}
}
++ch_one;
++ch_two;
}
return *ch_two == '\0'; //this one has to be null terminated too, or else json_string two is longer, hence, not equal
}
JSONNode ** internalJSONNode::at_nocase(const json_string & name_t) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("at_nocase"), return 0;);
Fetch();
json_foreach(CHILDREN, myrunner){
JSON_ASSERT(*myrunner, json_global(ERROR_NULL_IN_CHILDREN));
if (json_unlikely(AreEqualNoCase((*myrunner) -> name().c_str(), name_t.c_str()))) return myrunner;
}
return 0;
}
#endif /*<- */
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY) /*-> JSON_PREPARSE && JSON_READ_PRIORITY */
void internalJSONNode::preparse(void) json_nothrow {
Fetch();
if (isContainer()){
json_foreach(CHILDREN, myrunner){
(*myrunner) -> preparse();
}
}
}
#endif /*<- */
internalJSONNode::operator bool() const json_nothrow {
Fetch();
#ifdef JSON_CASTABLE /*-> JSON_CASTABLE */
switch(type()){
case JSON_NUMBER:
return !_floatsAreEqual(_value._number, (json_number)0.0);
case JSON_NULL:
return false;
}
#endif /*<- */
JSON_ASSERT(type() == JSON_BOOL, json_global(ERROR_UNDEFINED) + JSON_TEXT("(bool)"));
return _value._bool;
}
#ifdef JSON_LIBRARY /*-> JSON_LIBRARY */
internalJSONNode::operator json_number() const json_nothrow {
Fetch();
#ifdef JSON_CASTABLE /*-> JSON_CASTABLE */
switch(type()){
case JSON_NULL:
return (json_number)0.0;
case JSON_BOOL:
return (json_number)(_value._bool ? 1.0 : 0.0);
case JSON_STRING:
FetchNumber();
}
#endif /*<- */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("as_float"));
return (json_number)_value._number;
}
internalJSONNode::operator json_int_t() const json_nothrow {
Fetch();
#ifdef JSON_CASTABLE /*-> JSON_CASTABLE */
switch(type()){
case JSON_NULL:
return 0;
case JSON_BOOL:
return _value._bool ? 1 : 0;
case JSON_STRING:
FetchNumber();
}
#endif /*<- */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("as_int"));
JSON_ASSERT(_value._number == (json_number)((json_int_t)_value._number), json_string(JSON_TEXT("as_int will truncate ")) + _string);
return (json_int_t)_value._number;
}
#else /*<- else */
#ifndef JSON_ISO_STRICT /*-> !JSON_ISO_STRICT */
internalJSONNode::operator long double() const json_nothrow {
Fetch();
#ifdef JSON_CASTABLE /*-> JSON_CASTABLE */
switch(type()){
case JSON_NULL:
return (long double)0.0;
case JSON_BOOL:
return (long double)(_value._bool ? 1.0 : 0.0);
case JSON_STRING:
FetchNumber();
}
#endif /*<- */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("(long double)"));
return (long double)_value._number;
}
#else /*<- else */
internalJSONNode::operator double() const json_nothrow {
Fetch();
#ifdef JSON_CASTABLE /*-> JSON_CASTABLE */
switch(type()){
case JSON_NULL:
return (double)0.0;
case JSON_BOOL:
return (double)(_value._bool ? 1.0 : 0.0);
case JSON_STRING:
FetchNumber();
}
#endif /*<- */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("(double)"));
return (double)_value._number;
}
#endif /*<- */
//do whichever one is longer, because it's easy to cast down
#ifdef JSON_ISO_STRICT /*-> JSON_ISO_STRICT */
internalJSONNode::operator long() const json_nothrow
#else /*<- else */
internalJSONNode::operator long long() const json_nothrow
#endif /*<- */
{
Fetch();
#ifdef JSON_CASTABLE /*-> JSON_CASTABLE */
switch(type()){
case JSON_NULL:
return 0;
case JSON_BOOL:
return _value._bool ? 1 : 0;
case JSON_STRING:
FetchNumber();
}
#endif /*<- */
#ifdef JSON_ISO_STRICT /*-> JSON_ISO_STRICT */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("(long)"));
JSON_ASSERT(_value._number > LONG_MIN, _string + json_global(ERROR_LOWER_RANGE) + JSON_TEXT("long"));
JSON_ASSERT(_value._number < LONG_MAX, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT("long"));
JSON_ASSERT(_value._number == (json_number)((long)_value._number), json_string(JSON_TEXT("(long) will truncate ")) + _string);
return (long)_value._number;
#else /*<- else */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("(long long)"));
#ifdef LONG_LONG_MAX
JSON_ASSERT(_value._number < LONG_LONG_MAX, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT("long long"));
#elif defined(LLONG_MAX)
JSON_ASSERT(_value._number < LLONG_MAX, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT("long long"));
#endif
#ifdef LONG_LONG_MIN
JSON_ASSERT(_value._number > LONG_LONG_MIN, _string + json_global(ERROR_LOWER_RANGE) + JSON_TEXT("long long"));
#elif defined(LLONG_MAX)
JSON_ASSERT(_value._number > LLONG_MIN, _string + json_global(ERROR_LOWER_RANGE) + JSON_TEXT("long long"));
#endif
JSON_ASSERT(_value._number == (json_number)((long long)_value._number), json_string(JSON_TEXT("(long long) will truncate ")) + _string);
return (long long)_value._number;
#endif /*<- */
}
#ifdef JSON_ISO_STRICT /*-> JSON_ISO_STRICT */
internalJSONNode::operator unsigned long() const json_nothrow
#else /*<- else */
internalJSONNode::operator unsigned long long() const json_nothrow
#endif /*<- */
{
Fetch();
#ifdef JSON_CASTABLE /*-> JSON_CASTABLE */
switch(type()){
case JSON_NULL:
return 0;
case JSON_BOOL:
return _value._bool ? 1 : 0;
case JSON_STRING:
FetchNumber();
}
#endif /*<- */
#ifdef JSON_ISO_STRICT /*-> JSON_ISO_STRICT */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("(unsigned long)"));
JSON_ASSERT(_value._number > 0, _string + json_global(ERROR_LOWER_RANGE) + JSON_TEXT("unsigned long"));
JSON_ASSERT(_value._number < ULONG_MAX, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT("unsigned long"));
JSON_ASSERT(_value._number == (json_number)((unsigned long)_value._number), json_string(JSON_TEXT("(unsigend long) will truncate ")) + _string);
return (unsigned long)_value._number;
#else /*<- else */
JSON_ASSERT(type() == JSON_NUMBER, json_global(ERROR_UNDEFINED) + JSON_TEXT("(unsigned long long)"));
JSON_ASSERT(_value._number > 0, _string + json_global(ERROR_LOWER_RANGE) + JSON_TEXT("unsigned long long"));
#ifdef ULONG_LONG_MAX
JSON_ASSERT(_value._number < ULONG_LONG_MAX, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT("unsigned long long"));
#elif defined(ULLONG_MAX)
JSON_ASSERT(_value._number < ULLONG_MAX, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT("unsigned long long"));
#endif
JSON_ASSERT(_value._number == (json_number)((unsigned long long)_value._number), json_string(JSON_TEXT("(unsigned long long) will truncate ")) + _string);
return (unsigned long long)_value._number;
#endif /*<- */
}
#endif /*<- */
/*
These functions are to allow allocation to be completely controlled by the callbacks
*/
#ifdef JSON_MEMORY_POOL /*-> JSON_MEMORY_POOL */
#include "JSONMemoryPool.h"
static memory_pool<INTERNALNODEPOOL> json_internal_mempool;
#endif /*<- */
void internalJSONNode::deleteInternal(internalJSONNode * ptr) json_nothrow {
#ifdef JSON_MEMORY_POOL /*-> JSON_MEMORY_POOL */
ptr -> ~internalJSONNode();
json_internal_mempool.deallocate((void*)ptr);
#elif defined(JSON_MEMORY_CALLBACKS) /*<- else JSON_MEMORY_CALLBACKS */
ptr -> ~internalJSONNode();
libjson_free<internalJSONNode>(ptr);
#else /*<- else */
delete ptr;
#endif /*<- */
}
internalJSONNode * internalJSONNode::newInternal(char mytype) {
#ifdef JSON_MEMORY_POOL /*-> JSON_MEMORY_POOL */
return new((internalJSONNode*)json_internal_mempool.allocate()) internalJSONNode(mytype);
#elif defined(JSON_MEMORY_CALLBACKS) /*<- else JSON_MEMORY_CALLBACKS */
return new(json_malloc<internalJSONNode>(1)) internalJSONNode(mytype);
#else /*<- else */
return new internalJSONNode(mytype);
#endif /*<- */
}
#ifdef JSON_READ_PRIORITY /*-> JSON_READ_PRIORITY */
internalJSONNode * internalJSONNode::newInternal(const json_string & unparsed) {
#ifdef JSON_MEMORY_POOL /*-> JSON_MEMORY_POOL */
return new((internalJSONNode*)json_internal_mempool.allocate()) internalJSONNode(unparsed);
#elif defined(JSON_MEMORY_CALLBACKS) /*<- else JSON_MEMORY_CALLBACKS */
return new(json_malloc<internalJSONNode>(1)) internalJSONNode(unparsed);
#else /*<- else */
return new internalJSONNode(unparsed);
#endif /*<- */
}
internalJSONNode * internalJSONNode::newInternal(const json_string & name_t, const json_string & value_t) {
#ifdef JSON_MEMORY_POOL /*-> JSON_MEMORY_POOL */
return new((internalJSONNode*)json_internal_mempool.allocate()) internalJSONNode(name_t, value_t);
#elif defined(JSON_MEMORY_CALLBACKS) /*<- else JSON_MEMORY_CALLBACKS */
return new(json_malloc<internalJSONNode>(1)) internalJSONNode(name_t, value_t);
#else /*<- else */
return new internalJSONNode(name_t, value_t);
#endif /*<- */
}
#endif /*<- */
internalJSONNode * internalJSONNode::newInternal(const internalJSONNode & orig) {
#ifdef JSON_MEMORY_POOL /*-> JSON_MEMORY_POOL */
return new((internalJSONNode*)json_internal_mempool.allocate()) internalJSONNode(orig);
#elif defined(JSON_MEMORY_CALLBACKS) /*<- else JSON_MEMORY_CALLBACKS */
return new(json_malloc<internalJSONNode>(1)) internalJSONNode(orig);
#else /*<- else */
return new internalJSONNode(orig);
#endif /*<- */
}
#ifdef JSON_DEBUG /*-> JSON_MEMORY_POOL */
#ifndef JSON_LIBRARY /*-> JSON_MEMORY_POOL */
JSONNode internalJSONNode::Dump(size_t & totalbytes) const json_nothrow {
JSONNode dumpage(JSON_NODE);
dumpage.set_name(JSON_TEXT("internalJSONNode"));
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this)));
START_MEM_SCOPE
size_t memory = sizeof(internalJSONNode);
memory += _name.capacity() * sizeof(json_char);
memory += _string.capacity() * sizeof(json_char);
if (isContainer()){
memory += sizeof(jsonChildren);
memory += CHILDREN -> capacity() * sizeof(JSONNode*);
}
#ifdef JSON_COMMENTS /*-> JSON_COMMENTS */
memory += _comment.capacity() * sizeof(json_char);
#endif /*<- */
totalbytes += memory;
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), memory)));
END_MEM_SCOPE
#ifdef JSON_REF_COUNT /*-> JSON_REF_COUNT */
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("refcount"), refcount)));
#endif /*<- */
#ifdef JSON_MUTEX_CALLBACKS /*-> JSON_MUTEX_CALLBACKS */
dumpage.push_back(JSON_NEW(DumpMutex()));
#endif /*<- */
#define DUMPCASE(ty)\
case ty:\
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT(#ty))));\
break;
switch(type()){
DUMPCASE(JSON_NULL)
DUMPCASE(JSON_STRING)
DUMPCASE(JSON_NUMBER)
DUMPCASE(JSON_BOOL)
DUMPCASE(JSON_ARRAY)
DUMPCASE(JSON_NODE)
default:
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT("Unknown"))));
}
JSONNode str(JSON_NODE);
str.set_name(JSON_TEXT("_name"));
str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _name)));
str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _name.length())));
str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _name.capacity())));
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _name_encoded)));
dumpage.push_back(JSON_NEW(str));
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_string_encoded"), _string_encoded)));
str.clear();
str.set_name(JSON_TEXT("_string"));
str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _string)));
str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _string.length())));
str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _string.capacity())));
dumpage.push_back(JSON_NEW(str));
if ((type() == JSON_BOOL) || (type() == JSON_NUMBER)){
JSONNode unio(JSON_NODE);
unio.set_name(JSON_TEXT("_value"));
if (type() == JSON_BOOL){
unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_bool"), _value._bool)));
} else if (type() == JSON_NUMBER){
unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_number"), _value._number)));
}
dumpage.push_back(JSON_NEW(unio));
}
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY) /*-> !JSON_PREPARSE && JSON_READ_PRIORITY */
dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("fetched"), fetched)));
#endif /*<- */
#ifdef JSON_COMMENTS /*-> JSON_COMMENTS */
str.clear();
str.set_name(JSON_TEXT("_comment"));
str.push_back(JSON_NEW(JSONNode(JSON_TEXT("value"), _comment)));
str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _comment.length())));
str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _comment.capacity())));
dumpage.push_back(JSON_NEW(str));
#endif /*<- */
if (isContainer()){
JSONNode arra(JSON_NODE);
arra.set_name(JSON_TEXT("Children"));
arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("size"), CHILDREN -> size())));
arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("capacity"), CHILDREN -> capacity())));
JSONNode chil(JSON_ARRAY);
chil.set_name(JSON_TEXT("array"));
json_foreach(CHILDREN, it){
chil.push_back(JSON_NEW((*it) -> dump(totalbytes)));
}
arra.push_back(JSON_NEW(chil));
dumpage.push_back(JSON_NEW(arra));
}
return dumpage;
}
#endif /*<- */
#endif /*<- */

View file

@ -0,0 +1,504 @@
#ifndef INTERNAL_JSONNODE_H
#define INTERNAL_JSONNODE_H
#include "JSONDebug.h"
#include "JSONChildren.h"
#include "JSONMemory.h"
#include "JSONGlobals.h"
#ifdef JSON_DEBUG
#include <climits> //to check int value
#endif
#include "JSONSharedString.h"
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(push, 1)
#elif _MSC_VER
#pragma pack(push, internalJSONNode_pack, 1)
#endif
#endif
/*
This class is the work horse of libjson, it handles all of the
functinality of JSONNode. This object is reference counted for
speed and memory reasons.
If JSON_REF_COUNT is not on, this internal structure still has an important
purpose, as it can be passed around by JSONNoders that are flagged as temporary
*/
class JSONNode; //forward declaration
#ifndef JSON_LIBRARY
#define DECL_SET_INTEGER(type) void Set(type) json_nothrow json_write_priority; void Set(unsigned type) json_nothrow json_write_priority;
#define DECL_CAST_OP(type) operator type() const json_nothrow; operator unsigned type() const json_nothrow;
#endif
#ifdef JSON_MUTEX_CALLBACKS
#define initializeMutex(x) ,mylock(x)
#else
#define initializeMutex(x)
#endif
#if defined(JSON_PREPARSE) || !defined(JSON_READ_PRIORITY)
#define SetFetched(b) (void)0
#define Fetch() (void)0
#define initializeFetch(x)
#else
#define initializeFetch(x) ,fetched(x)
#endif
#ifdef JSON_REF_COUNT
#define initializeRefCount(x) ,refcount(x)
#else
#define initializeRefCount(x)
#endif
#ifdef JSON_COMMENTS
#define initializeComment(x) ,_comment(x)
#else
#define initializeComment(x)
#endif
#ifdef JSON_LESS_MEMORY
#define CHILDREN _value.Children
#define DELETE_CHILDREN()\
if (isContainer()){\
jsonChildren::deleteChildren(CHILDREN);\
}
#define CHILDREN_TO_NULL() (void)0
#define initializeChildren(x)
#else
#define CHILDREN Children
#define DELETE_CHILDREN()\
if (CHILDREN != 0) jsonChildren::deleteChildren(CHILDREN);
#define CHILDREN_TO_NULL() CHILDREN = 0
#define makeNotContainer() (void)0
#define makeContainer() if (!CHILDREN) CHILDREN = jsonChildren::newChildren()
#define initializeChildren(x) ,CHILDREN(x)
#endif
class internalJSONNode {
public:
LIBJSON_OBJECT(internalJSONNode);
internalJSONNode(char mytype = JSON_NULL) json_nothrow json_hot;
#ifdef JSON_READ_PRIORITY
internalJSONNode(const json_string & unparsed) json_nothrow json_hot;
internalJSONNode(const json_string & name_t, const json_string & value_t) json_nothrow json_read_priority;
#endif
internalJSONNode(const internalJSONNode & orig) json_nothrow json_hot;
internalJSONNode & operator = (const internalJSONNode &) json_nothrow json_hot;
~internalJSONNode(void) json_nothrow json_hot;
static internalJSONNode * newInternal(char mytype = JSON_NULL) json_hot;
#ifdef JSON_READ_PRIORITY
static internalJSONNode * newInternal(const json_string & unparsed) json_hot;
static internalJSONNode * newInternal(const json_string & name_t, const json_string & value_t) json_hot;
#endif
static internalJSONNode * newInternal(const internalJSONNode & orig) json_hot; //not copyable, only by this class
static void deleteInternal(internalJSONNode * ptr) json_nothrow json_hot;
json_index_t size(void) const json_nothrow json_read_priority;
bool empty(void) const json_nothrow;
unsigned char type(void) const json_nothrow json_read_priority;
json_string name(void) const json_nothrow json_read_priority;
void setname(const json_string & newname) json_nothrow json_write_priority;
#ifdef JSON_COMMENTS
void setcomment(const json_string & comment) json_nothrow;
json_string getcomment(void) const json_nothrow;
#endif
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
void preparse(void) json_nothrow;
#endif
#ifdef JSON_LIBRARY
void push_back(JSONNode * node) json_nothrow;
#else
void push_back(const JSONNode & node) json_nothrow;
#endif
void reserve(json_index_t siz) json_nothrow;
void push_front(const JSONNode & node) json_nothrow;
JSONNode * pop_back(json_index_t pos) json_nothrow;
JSONNode * pop_back(const json_string & name_t) json_nothrow;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode * pop_back_nocase(const json_string & name_t) json_nothrow;
#endif
JSONNode * at(json_index_t pos) json_nothrow;
//These return ** because pop_back needs them
JSONNode ** at(const json_string & name_t) json_nothrow;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode ** at_nocase(const json_string & name_t) json_nothrow;
#endif
void Set(const json_string & val) json_nothrow json_write_priority;
#ifdef JSON_LIBRARY
void Set(json_number val) json_nothrow json_write_priority;
void Set(json_int_t val) json_nothrow json_write_priority;
operator json_int_t() const json_nothrow;
operator json_number() const json_nothrow;
#else
DECL_SET_INTEGER(char)
DECL_SET_INTEGER(short)
DECL_SET_INTEGER(int)
DECL_SET_INTEGER(long)
#ifndef JSON_ISO_STRICT
DECL_SET_INTEGER(long long)
void Set(long double val) json_nothrow json_write_priority;
#endif
void Set(float val) json_nothrow json_write_priority;
void Set(double val) json_nothrow json_write_priority;
DECL_CAST_OP(char)
DECL_CAST_OP(short)
DECL_CAST_OP(int)
DECL_CAST_OP(long)
#ifndef JSON_ISO_STRICT
DECL_CAST_OP(long long)
operator long double() const json_nothrow;
#endif
operator float() const json_nothrow;
operator double() const json_nothrow;
#endif
operator json_string()const json_nothrow;
operator bool() const json_nothrow;
void Set(bool val) json_nothrow;
bool IsEqualTo(const json_string & val) const json_nothrow;
bool IsEqualTo(bool val) const json_nothrow;
bool IsEqualTo(const internalJSONNode * val) const json_nothrow;
template<typename T>
bool IsEqualToNum(T val) const json_nothrow;
internalJSONNode * incRef(void) json_nothrow;
#ifdef JSON_REF_COUNT
void decRef(void) json_nothrow json_hot;
bool hasNoReferences(void) json_nothrow json_hot;
#endif
internalJSONNode * makeUnique(void) json_nothrow json_hot;
JSONNode ** begin(void) const json_nothrow;
JSONNode ** end(void) const json_nothrow;
bool Fetched(void) const json_nothrow json_hot;
#ifdef JSON_MUTEX_CALLBACKS
void _set_mutex(void * mutex, bool unset = true) json_nothrow json_cold;
void _unset_mutex(void) json_nothrow json_cold;
#endif
#ifdef JSON_WRITE_PRIORITY
void DumpRawString(json_string & output) const json_nothrow json_write_priority;
void WriteName(bool formatted, bool arrayChild, json_string & output) const json_nothrow json_write_priority;
#ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
void WriteChildrenOneLine(unsigned int indent, json_string & output) const json_nothrow json_write_priority;
#endif
void WriteChildren(unsigned int indent, json_string & output) const json_nothrow json_write_priority;
void WriteComment(unsigned int indent, json_string & output) const json_nothrow json_write_priority;
void Write(unsigned int indent, bool arrayChild, json_string & output) const json_nothrow json_write_priority;
#endif
inline bool isContainer(void) const json_nothrow {
return (_type == JSON_NODE || _type == JSON_ARRAY);
}
inline bool isNotContainer(void) const json_nothrow {
return (_type != JSON_NODE && _type != JSON_ARRAY);
}
#ifdef JSON_LESS_MEMORY
inline void makeNotContainer(void){
if (isContainer()){
jsonChildren::deleteChildren(CHILDREN);
}
}
inline void makeContainer(void){
if (isNotContainer()){
CHILDREN = jsonChildren::newChildren();
}
}
#endif
void Nullify(void) const json_nothrow;
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
void SetFetched(bool val) const json_nothrow json_hot;
void Fetch(void) const json_nothrow json_hot; //it's const because it doesn't change the VALUE of the function
#endif
#ifdef JSON_READ_PRIORITY
void FetchString(void) const json_nothrow json_read_priority;
void FetchNode(void) const json_nothrow json_read_priority;
void FetchArray(void) const json_nothrow json_read_priority;
#endif
void FetchNumber(void) const json_nothrow json_read_priority;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
static bool AreEqualNoCase(const json_char * ch_one, const json_char * ch_two) json_nothrow json_read_priority;
#endif
inline void clearname(void) json_nothrow {
clearString(_name);
}
#ifdef JSON_DEBUG
#ifndef JSON_LIBRARY
JSONNode Dump(size_t & totalmemory) const json_nothrow;
JSONNode DumpMutex(void) const json_nothrow;
#endif
#endif
mutable unsigned char _type BITS(3);
json_string _name;
mutable bool _name_encoded BITS(1); //must be above name due to initialization list order
mutable json_string _string; //these are both mutable because the string can change when it's fetched
mutable bool _string_encoded BITS(1);
//the value of the json
union value_union_t {
bool _bool BITS(1);
json_number _number;
#ifdef JSON_LESS_MEMORY
jsonChildren * Children;
#endif
};
mutable value_union_t _value; //internal structure changes depending on type
#ifdef JSON_MUTEX_CALLBACKS
void * mylock;
#endif
#ifdef JSON_REF_COUNT
size_t refcount PACKED(20);
#endif
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
mutable bool fetched BITS(1);
#endif
#ifdef JSON_COMMENTS
json_string _comment;
#endif
#ifndef JSON_LESS_MEMORY
jsonChildren * CHILDREN;
#endif
};
inline internalJSONNode::internalJSONNode(char mytype) json_nothrow : _type(mytype), _name(), _name_encoded(), _string(), _string_encoded(), _value()
initializeMutex(0)
initializeRefCount(1)
initializeFetch(true)
initializeComment(json_global(EMPTY_JSON_STRING))
initializeChildren((_type == JSON_NODE || _type == JSON_ARRAY) ? jsonChildren::newChildren() : 0){
LIBJSON_CTOR;
#ifdef JSON_LESS_MEMORY
//if not less memory, its in the initialization list
if (isContainer()){
CHILDREN = jsonChildren::newChildren();
}
#endif
}
inline internalJSONNode * internalJSONNode::incRef(void) json_nothrow {
#ifdef JSON_REF_COUNT
++refcount;
return this;
#else
return makeUnique();
#endif
}
inline json_index_t internalJSONNode::size(void) const json_nothrow {
if (isNotContainer()) return 0;
Fetch();
return CHILDREN -> size();
}
inline bool internalJSONNode::empty(void) const json_nothrow {
if (isNotContainer()) return true;
Fetch();
return CHILDREN -> empty();
}
inline unsigned char internalJSONNode::type(void) const json_nothrow {
return _type;
}
inline json_string internalJSONNode::name(void) const json_nothrow {
return _name;
}
inline void internalJSONNode::setname(const json_string & newname) json_nothrow {
#ifdef JSON_LESS_MEMORY
JSON_ASSERT(newname.capacity() == newname.length(), JSON_TEXT("name object too large"));
#endif
_name = newname;
_name_encoded = true;
}
#ifdef JSON_COMMENTS
inline void internalJSONNode::setcomment(const json_string & comment) json_nothrow {
_comment = comment;
}
inline json_string internalJSONNode::getcomment(void) const json_nothrow {
return _comment;
}
#endif
inline bool internalJSONNode::IsEqualTo(const json_string & val) const json_nothrow {
if (type() != JSON_STRING) return false;
Fetch();
return _string == val;
}
inline bool internalJSONNode::IsEqualTo(bool val) const json_nothrow {
if (type() != JSON_BOOL) return false;
Fetch();
return val == _value._bool;
}
template<typename T>
inline bool internalJSONNode::IsEqualToNum(T val) const json_nothrow {
if (type() != JSON_NUMBER) return false;
Fetch();
return (json_number)val == _value._number;
}
#ifdef JSON_REF_COUNT
inline void internalJSONNode::decRef(void) json_nothrow {
JSON_ASSERT(refcount != 0, JSON_TEXT("decRef on a 0 refcount internal"));
--refcount;
}
inline bool internalJSONNode::hasNoReferences(void) json_nothrow {
return refcount == 0;
}
#endif
inline internalJSONNode * internalJSONNode::makeUnique(void) json_nothrow {
#ifdef JSON_REF_COUNT
if (refcount > 1){
decRef();
return newInternal(*this);
}
JSON_ASSERT(refcount == 1, JSON_TEXT("makeUnique on a 0 refcount internal"));
return this;
#else
return newInternal(*this);
#endif
}
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
inline void internalJSONNode::SetFetched(bool val) const json_nothrow {
fetched = val;
}
#endif
inline bool internalJSONNode::Fetched(void) const json_nothrow {
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
return fetched;
#else
return true;
#endif
}
inline JSONNode ** internalJSONNode::begin(void) const json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("begin"), return 0;);
Fetch();
return CHILDREN -> begin();
}
inline JSONNode ** internalJSONNode::end(void) const json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("end"), return 0;);
Fetch();
return CHILDREN -> end();
}
inline JSONNode * internalJSONNode::at(json_index_t pos) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), JSON_TEXT("calling at on non-container type"), return 0;);
Fetch();
return (*CHILDREN)[pos];
}
#if defined(JSON_LESS_MEMORY) && defined(__GNUC__)
inline void internalJSONNode::reserve(json_index_t __attribute__((unused)) siz) json_nothrow
#else
inline void internalJSONNode::reserve(json_index_t siz) json_nothrow
#endif
{
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("reserve"), return;);
Fetch();
jsonChildren::reserve2(CHILDREN, siz);
}
/*
cast operators
*/
#ifndef JSON_LIBRARY
#ifdef JSON_ISO_STRICT
#define BASE_CONVERT_TYPE long
#else
#define BASE_CONVERT_TYPE long long
#endif
#define IMP_SMALLER_INT_CAST_OP(_type, type_max, type_min)\
inline internalJSONNode::operator _type() const json_nothrow {\
JSON_ASSERT(_value._number > type_min, _string + json_global(ERROR_LOWER_RANGE) + JSON_TEXT(#_type));\
JSON_ASSERT(_value._number < type_max, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT(#_type));\
JSON_ASSERT(_value._number == (json_number)((_type)(_value._number)), json_string(JSON_TEXT("(")) + json_string(JSON_TEXT(#_type)) + json_string(JSON_TEXT(") will truncate ")) + _string);\
return (_type)static_cast<BASE_CONVERT_TYPE>(*this);\
}
IMP_SMALLER_INT_CAST_OP(char, CHAR_MAX, CHAR_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned char, UCHAR_MAX, 0)
IMP_SMALLER_INT_CAST_OP(short, SHRT_MAX, SHRT_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned short, USHRT_MAX, 0)
IMP_SMALLER_INT_CAST_OP(int, INT_MAX, INT_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned int, UINT_MAX, 0)
#ifndef JSON_ISO_STRICT
IMP_SMALLER_INT_CAST_OP(long, LONG_MAX, LONG_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned long, ULONG_MAX, 0)
#endif
#endif
inline internalJSONNode::operator json_string() const json_nothrow {
Fetch();
return _string;
}
#ifndef JSON_LIBRARY
#ifndef JSON_ISO_STRICT
inline internalJSONNode::operator float() const json_nothrow {
return static_cast<float>(static_cast<long double>(*this));
}
inline internalJSONNode::operator double() const json_nothrow {
return static_cast<double>(static_cast<long double>(*this));
}
#else
inline internalJSONNode::operator float() const json_nothrow {
return static_cast<float>(static_cast<double>(*this));
}
#endif
#endif
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(pop)
#elif _MSC_VER
#pragma pack(pop, internalJSONNode_pack,)
#endif
#endif
#endif

View file

@ -0,0 +1,605 @@
/*
This is the implementation of the C interface to libjson
This file may be included in any C++ application, but it will
be completely ignored if JSON_LIBRARY isn't defined. The
only reason JSON_LIBRARY should be defined is when compiling libjson
as a library
*/
#include "../../libjson.h"
#ifdef JSON_LIBRARY
#include "JSONNode.h"
#include "JSONWorker.h"
#include "JSONValidator.h"
#include "JSONStream.h"
#include "JSONGlobals.h"
#include <stdexcept> //some methods throw exceptions
#ifdef JSON_MEMORY_MANAGE
#define MANAGER_INSERT(x) json_global(NODE_HANDLER).insert(x)
#define MANAGER_STREAM_INSERT(x) json_global(STREAM_HANDLER).insert(x)
#else
#define MANAGER_INSERT(x) x
#define MANAGER_STREAM_INSERT(x) x
#endif
static const json_char * EMPTY_CSTRING(JSON_TEXT(""));
#ifdef JSON_MEMORY_POOL
#include "JSONMemoryPool.h"
extern memory_pool<NODEPOOL> json_node_mempool;
#endif
inline json_char * toCString(const json_string & str) json_nothrow {
const size_t len = (str.length() + 1) * sizeof(json_char);
#ifdef JSON_MEMORY_MANAGE
return (json_char *)json_global(STRING_HANDLER).insert(std::memcpy(json_malloc<json_char>(len), str.c_str(), len));
#else
return (json_char *)std::memcpy(json_malloc<json_char>(len), str.c_str(), len);
#endif
}
inline json_char * alreadyCString(json_char * str) json_nothrow {
#ifdef JSON_MEMORY_MANAGE
return (json_char *)json_global(STRING_HANDLER).insert(str);
#else
return str;
#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
json_global(STRING_HANDLER).remove(str);
#endif
libjson_free<void>(str);
}
void json_delete(JSONNODE * node){
JSON_ASSERT_SAFE(node, JSON_TEXT("deleting null ptr"), return;);
#ifdef JSON_MEMORY_MANAGE
json_global(NODE_HANDLER).remove(node);
#endif
JSONNode::deleteJSONNode((JSONNode *)node);
}
#ifdef JSON_MEMORY_MANAGE
void json_free_all(void){
json_global(STRING_HANDLER).clear();
}
void json_delete_all(void){
json_global(NODE_HANDLER).clear();
}
#endif
#ifdef JSON_READ_PRIORITY
JSONNODE * json_parse(json_const json_char * json){
JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_parse"), return 0;);
json_try {
//use this constructor to simply copy reference instead of copying the temp
return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::parse(TOCONST_CSTR(json))));
} json_catch (std::invalid_argument, (void)0; )
#ifndef JSON_NO_EXCEPTIONS
return 0;
#endif
}
JSONNODE * json_parse_unformatted(json_const json_char * json){
JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_parse"), return 0;);
json_try {
//use this constructor to simply copy reference instead of copying the temp
return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::parse_unformatted(TOCONST_CSTR(json))));
} json_catch(std::invalid_argument, (void)0; )
#ifndef JSON_NO_EXCEPTIONS
return 0;
#endif
}
#endif
json_char * json_strip_white_space(json_const json_char * json){
JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_strip_white_space"), return 0;);
return alreadyCString(JSONWorker::RemoveWhiteSpaceAndCommentsC(TOCONST_CSTR(json), false));
}
#ifdef JSON_VALIDATE
#ifdef JSON_DEPRECATED_FUNCTIONS
JSONNODE * json_validate(json_const json_char * json){
JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_validate"), return 0;);
if (json_is_valid(json)){
return json_parse(json);
}
return 0;
}
#endif
json_bool_t json_is_valid(json_const json_char * json){
JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_is_valid"), return (json_bool_t)false;);
#ifdef JSON_SECURITY_MAX_STRING_LENGTH
if (json_unlikely(json_strlen(json) > JSON_SECURITY_MAX_STRING_LENGTH)){
JSON_FAIL(JSON_TEXT("Exceeding JSON_SECURITY_MAX_STRING_LENGTH"));
return false;
}
#endif
json_auto<json_char> s;
s.set(JSONWorker::RemoveWhiteSpaceAndCommentsC(json, false));
return (json_bool_t)JSONValidator::isValidRoot(s.ptr);
}
json_bool_t json_is_valid_unformatted(json_const json_char * json){
JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_is_valid_unformatted"), return (json_bool_t)true;);
#ifdef JSON_SECURITY_MAX_STRING_LENGTH
if (json_unlikely(json_strlen(json) > JSON_SECURITY_MAX_STRING_LENGTH)){
JSON_FAIL(JSON_TEXT("Exceeding JSON_SECURITY_MAX_STRING_LENGTH"));
return false;
}
#endif
return (json_bool_t)JSONValidator::isValidRoot(json);
}
#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
#ifdef JSON_STREAM
void json_stream_push(JSONSTREAM * stream, json_const json_char * addendum){
(*((JSONStream*)stream)) << addendum;
}
void json_delete_stream(JSONSTREAM * stream){
JSON_ASSERT_SAFE(stream, JSON_TEXT("deleting null ptr"), return;);
#ifdef JSON_MEMORY_MANAGE
json_global(STREAM_HANDLER).remove(stream);
#endif
JSONStream::deleteJSONStream((JSONStream *)stream);
}
JSONSTREAM * json_new_stream(json_stream_callback_t callback, json_stream_e_callback_t e_callback, void * identifier){
return MANAGER_STREAM_INSERT(JSONStream::newJSONStream(callback, e_callback, identifier));
}
void json_stream_reset(JSONSTREAM * stream){
JSON_ASSERT_SAFE(stream, JSON_TEXT("resetting null ptr"), return;);
((JSONStream*)stream) -> reset();
}
#endif
/*
stuff that's in class JSONNode
*/
//ctors
JSONNODE * json_new_a(json_const json_char * name, json_const json_char * value){
if (!name) name = EMPTY_CSTRING;
JSON_ASSERT_SAFE(value, JSON_TEXT("null value to json_new_a"), value = EMPTY_CSTRING;);
#ifdef JSON_MEMORY_POOL
return MANAGER_INSERT(new((JSONNode*)json_node_mempool.allocate()) JSONNode(TOCONST_CSTR(name), json_string(TOCONST_CSTR(value))));
#elif defined(JSON_MEMORY_CALLBACKS)
return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(TOCONST_CSTR(name), json_string(TOCONST_CSTR(value))));
#else
return MANAGER_INSERT(new JSONNode(TOCONST_CSTR(name), json_string(TOCONST_CSTR(value))));
#endif
}
JSONNODE * json_new_i(json_const json_char * name, json_int_t value){
if (!name) name = EMPTY_CSTRING;
#ifdef JSON_MEMORY_POOL
return MANAGER_INSERT(new((JSONNode*)json_node_mempool.allocate()) JSONNode(TOCONST_CSTR(name), value));
#elif defined(JSON_MEMORY_CALLBACKS)
return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(TOCONST_CSTR(name), value));
#else
return MANAGER_INSERT(new JSONNode(TOCONST_CSTR(name), value));
#endif
}
JSONNODE * json_new_f(json_const json_char * name, json_number value){
if (!name) name = EMPTY_CSTRING;
#ifdef JSON_MEMORY_POOL
return MANAGER_INSERT(new((JSONNode*)json_node_mempool.allocate()) JSONNode(TOCONST_CSTR(name), value));
#elif defined(JSON_MEMORY_CALLBACKS)
return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(TOCONST_CSTR(name), value));
#else
return MANAGER_INSERT(new JSONNode(TOCONST_CSTR(name), value));
#endif
}
JSONNODE * json_new_b(json_const json_char * name, json_bool_t value){
if (!name) name = EMPTY_CSTRING;
#ifdef JSON_MEMORY_POOL
return MANAGER_INSERT(new((JSONNode*)json_node_mempool.allocate()) JSONNode(TOCONST_CSTR(name), static_cast<bool>(value)));
#elif defined(JSON_MEMORY_CALLBACKS)
return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(TOCONST_CSTR(name), static_cast<bool>(value)));
#else
return MANAGER_INSERT(new JSONNode(TOCONST_CSTR(name), static_cast<bool>(value)));
#endif
}
JSONNODE * json_new(char type){
#ifdef JSON_MEMORY_POOL
return MANAGER_INSERT(new((JSONNode*)json_node_mempool.allocate()) JSONNode(type));
#elif defined(JSON_MEMORY_CALLBACKS)
return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(type));
#else
return MANAGER_INSERT(new JSONNode(type));
#endif
}
JSONNODE * json_copy(json_const JSONNODE * orig){
JSON_ASSERT_SAFE(orig, JSON_TEXT("null orig to json_copy"), return 0;);
#ifdef JSON_MEMORY_POOL
return MANAGER_INSERT(new((JSONNode*)json_node_mempool.allocate()) JSONNode(*((JSONNode*)orig)));
#elif defined(JSON_MEMORY_CALLBACKS)
return MANAGER_INSERT(new(json_malloc<JSONNode>(1)) JSONNode(*((JSONNode*)orig)));
#else
return MANAGER_INSERT(new JSONNode(*((JSONNode*)orig)));
#endif
}
JSONNODE * json_duplicate(json_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, json_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(TOCONST_CSTR(value));
}
void json_set_i(JSONNODE * node, json_int_t 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, json_bool_t value){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_b"), return;);
*((JSONNode*)node) = static_cast<bool>(value);
}
void json_set_n(JSONNODE * node, json_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(json_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(json_const JSONNODE * node){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_size"), return 0;);
return ((JSONNode*)node) -> size();
}
json_bool_t json_empty(json_const JSONNODE * node){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_empty"), return true;);
return (json_bool_t)(((JSONNode*)node) -> empty());
}
json_char * json_name(json_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(json_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(json_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());
//return toCString(static_cast<json_string>(*((JSONNode*)node)));
}
json_int_t json_as_int(json_const JSONNODE * node){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_int"), return 0;);
return ((JSONNode*)node) -> as_int();
//return static_cast<json_int_t>(*((JSONNode*)node));
}
json_number json_as_float(json_const JSONNODE * node){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_float"), return 0.0f;);
return ((JSONNode*)node) -> as_float();
//return static_cast<json_number>(*((JSONNode*)node));
}
json_bool_t json_as_bool(json_const JSONNODE * node){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_bool"), return false;);
return ((JSONNode*)node) -> as_bool();
//return (json_bool_t)static_cast<bool>(*((JSONNode*)node));
}
#ifdef JSON_CASTABLE
JSONNODE * json_as_node(json_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(json_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()));
}
#endif
#if defined(JSON_BINARY) || defined(JSON_EXPOSE_BASE64)
static void * returnDecode64(const std::string & result, unsigned long * size) json_nothrow json_cold;
static void * returnDecode64(const std::string & result, unsigned long * size) json_nothrow {
const size_t len = result.length();
if (json_likely(size)) *size = (json_index_t)len;
#ifdef JSON_SAFE
if (json_unlikely(result.empty())) return 0;
#endif
#ifdef JSON_MEMORY_MANAGE
return json_global(STRING_HANDLER).insert(std::memcpy(json_malloc<char>(len), result.data(), len));
#else
return std::memcpy(json_malloc<char>(len), result.data(), len);
#endif
}
#endif
#ifdef JSON_BINARY
void * json_as_binary(json_const JSONNODE * node, unsigned long * size){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_binary"), if (size){*size = 0;} return 0;);
return returnDecode64(((JSONNode*)node) -> as_binary(), size);
}
#endif
#ifdef JSON_EXPOSE_BASE64
#include "JSON_Base64.h"
json_char * json_encode64(json_const void * binary, json_index_t bytes){
const json_string result(JSONBase64::json_encode64((const unsigned char *)binary, (size_t)bytes));
#ifdef JSON_MEMORY_MANAGE
return (json_char*)json_global(STRING_HANDLER).insert((json_char*)std::memcpy(json_malloc<json_char>(result.length() + 1), result.c_str(), (result.length() + 1) * sizeof(json_char)));
#else
return (json_char*)std::memcpy(json_malloc<json_char>(result.length() + 1), result.c_str(), (result.length() + 1) * sizeof(json_char));
#endif
}
void * json_decode64(const json_char * text, unsigned long * size){
return returnDecode64(JSONBase64::json_decode64(text), size);
}
#endif
#ifdef JSON_WRITE_PRIORITY
json_char * json_write(json_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(json_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, json_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(TOCONST_CSTR(name));
}
#ifdef JSON_COMMENTS
void json_set_comment(JSONNODE * node, json_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(TOCONST_CSTR(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);
}
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
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, json_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, (size_t)length);
}
#endif
#ifdef JSON_CASTABLE
void json_cast(JSONNODE * node, char type){
JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_cast"), return;);
((JSONNode*)node) -> cast(type);
}
#endif
//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;);
json_try {
return &((JSONNode*)node) -> at(pos);
} json_catch (std::out_of_range, (void)0; )
#ifndef JSON_NO_EXCEPTIONS
return 0;
#endif
}
JSONNODE * json_get(JSONNODE * node, json_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;);
json_try {
return &((JSONNode*)node) -> at(TOCONST_CSTR(name));
} json_catch (std::out_of_range, (void)0; )
#ifndef JSON_NO_EXCEPTIONS
return 0;
#endif
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNODE * json_get_nocase(JSONNODE * node, json_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;);
json_try {
return &((JSONNode*)node) -> at_nocase(TOCONST_CSTR(name));
} json_catch (std::out_of_range, (void)0; )
#ifndef JSON_NO_EXCEPTIONS
return 0;
#endif
}
JSONNODE * json_pop_back_nocase(JSONNODE * node, json_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(TOCONST_CSTR(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
json_global(NODE_HANDLER).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, json_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(TOCONST_CSTR(name)));
}
#ifdef JSON_ITERATORS
JSONNODE_ITERATOR json_find(JSONNODE * node, json_const json_char * name){
return (JSONNODE_ITERATOR)(((JSONNode*)node) -> find(TOCONST_CSTR(name)));
}
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNODE_ITERATOR json_find_nocase(JSONNODE * node, json_const json_char * name){
return (JSONNODE_ITERATOR)(((JSONNode*)node) -> find_nocase(TOCONST_CSTR(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
json_global(NODE_HANDLER).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
json_bool_t 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 (json_bool_t)(*((JSONNode*)node) == *((JSONNode*)node2));
}
#endif //JSON_LIBRARY

View file

@ -0,0 +1,371 @@
#unittesting
#library
#unicode
#standard set
STREAM, UNICODE, LIBRARY, SAFE, REF_COUNT, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS, STRICT
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting
STREAM, UNICODE, LIBRARY, SAFE, BINARY, WRITER, COMMENTS, VALIDATE
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
VALIDATE, STREAM, UNICODE, LIBRARY, REF_COUNT, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, VALIDATE, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, VALIDATE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, UNICODE, STRINGU_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, STRINGU_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, STRINGU_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, STRINGU_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, STREAM, UNICODE, STRINGU_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, UNICODE, LIBRARY, SAFE, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, UNICODE, LIBRARY, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, LIBRARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#no unicode
#standard set
STREAM, LIBRARY, SAFE, REF_COUNT, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, CASTABLE, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting
STREAM, LIBRARY, SAFE, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNIT_TEST, LIBRARY, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
STREAM, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, STREAM, UNIT_TEST, LIBRARY, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
VALIDATE, STREAM, LIBRARY, REF_COUNT, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, STREAM, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, VALIDATE, STREAM, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, VALIDATE, UNIT_TEST, LIBRARY, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, STRING_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STRING_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, STRING_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, STRING_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, STRING_HEADER, UNIT_TEST, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, LIBRARY, SAFE, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNIT_TEST, LIBRARY, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, LIBRARY, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNIT_TEST, LIBRARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#embedded
#unicode
#standard set
STREAM, UNICODE, SAFE, REF_COUNT, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting
STREAM, UNICODE, SAFE, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
VALIDATE, STREAM, UNICODE, REF_COUNT, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNICODE, ESCAPE_WRITES, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNICODE, ESCAPE_WRITES, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, VALIDATE, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, VALIDATE, UNICODE, ESCAPE_WRITES, UNIT_TEST, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, UNICODE, STRINGU_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, STRINGU_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, STRINGU_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, STRINGU_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, STREAM, UNICODE, STRINGU_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, UNICODE, SAFE, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, UNICODE, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNICODE, ESCAPE_WRITES, UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, ESCAPE_WRITES, UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNICODE, ESCAPE_WRITES, UNIT_TEST, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#no unicode
#standard set
STREAM, SAFE, REF_COUNT, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting
STREAM, SAFE, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNIT_TEST, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
STREAM, UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNIT_TEST, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, CASTABLE, STREAM, UNIT_TEST, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
VALIDATE, STREAM, REF_COUNT, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, STREAM, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
VALIDATE, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, VALIDATE, STREAM, UNIT_TEST, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, VALIDATE, UNIT_TEST, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, STRING_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STRING_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, STRING_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STRING_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, STREAM, STRING_HEADER, UNIT_TEST, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, SAFE, BINARY, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNIT_TEST, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, BINARY, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNIT_TEST, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
CASTABLE, UNIT_TEST, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#no unittesting
#library
#unicode
#standard set
STREAM, UNICODE, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting
STREAM, UNICODE, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
STREAM, UNICODE, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
STREAM, UNICODE, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
UNICODE, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, LIBRARY, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, UNICODE, STRINGU_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, STRINGU_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, STRINGU_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, STRINGU_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, STRINGU_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, UNICODE, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, UNICODE, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
UNICODE, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, LIBRARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#no unicode
#standard set
STREAM, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting
STREAM, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, LIBRARY, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
STREAM, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, LIBRARY, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
STREAM, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, LIBRARY, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, STRING_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STRING_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, STRING_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STRING_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, STRING_HEADER, LIBRARY, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, LIBRARY, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, LIBRARY, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, LIBRARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#embedded
#unicode
#standard set
STREAM, UNICODE, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting
STREAM, UNICODE, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
STREAM, UNICODE, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
STREAM, UNICODE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
UNICODE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, UNICODE, STRINGU_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, STRINGU_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, STRINGU_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, STRINGU_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, UNICODE, STRINGU_HEADER, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, UNICODE, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
UNICODE, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, UNICODE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
UNICODE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, UNICODE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, UNICODE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#no unicode
#standard set
STREAM, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref countingv
STREAM, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, SAFE, PREPARSE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, SAFE, PREPARSE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no preparse
STREAM, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, SAFE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, SAFE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no safe
STREAM, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
#string header
STREAM, STRING_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STRING_HEADER, STRING_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, STRING_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STRING_HEADER, SAFE, PREPARSE, REF_COUNT, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, STRING_HEADER, SAFE, PREPARSE, REF_COUNT, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing
STREAM, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
STREAM, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, SAFE, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, STREAM, SAFE, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, VALIDATE, CASE_INSENSITIVE_FUNCTIONS
#no ref counting or preparsing or safety
STREAM, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, CASE_INSENSITIVE_FUNCTIONS
BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
MEMORY_POOL, BINARY, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS
STREAM, MEMORY_CALLBACKS, MEMORY_MANAGE, MUTEX_CALLBACKS, MUTEX_MANAGE, ITERATORS, WRITER, COMMENTS, CASE_INSENSITIVE_FUNCTIONS

View file

@ -0,0 +1,246 @@
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <sys/stat.h>
#include "../UnitTest.h"
using namespace std;
map<string, string> options;
vector<string> lines;
vector<unsigned int> line_numbers;
size_t counter = 0;
string make;
string ArchivedOptions;
string makeStyle;
string makeOptions[] = {
"single",
"debug",
"small"
};
void makeMap(void){
options["LIBRARY"] = "#define JSON_LIBRARY";
options["DEBUG"] = "#define JSON_DEBUG";
options["STREAM"] = "#define JSON_STREAM";
options["SAFE"] = "#define JSON_SAFE";
options["STDERROR"] = "#define JSON_STDERROR";
options["PREPARSE"] = "#define JSON_PREPARSE";
options["LESS_MEMORY"] = "#define JSON_LESS_MEMORY";
options["UNICODE"] = "#define JSON_UNICODE";
options["REF_COUNT"] = "#define JSON_REF_COUNT";
options["BINARY"] = "#define JSON_BINARY";
options["MEMORY_CALLBACKS"] = "#define JSON_MEMORY_CALLBACKS";
options["MEMORY_MANAGE"] = "#define JSON_MEMORY_MANAGE";
options["MUTEX_CALLBACKS"] = "#define JSON_MUTEX_CALLBACKS";
options["MUTEX_MANAGE"] = "#define JSON_MUTEX_MANAGE";
options["ITERATORS"] = "#define JSON_ITERATORS";
options["WRITER"] = "#define JSON_WRITE_PRIORITY MID";
options["READER"] = "#define JSON_READ_PRIORITY HIGH";
options["NEWLINE"] = "#define JSON_NEWLINE \"\\r\\n\"";
options["COMMENTS"] = "#define JSON_COMMENTS";
options["INDENT"] = "#define JSON_INDENT \" \"";
options["WRITE_BASH_COMMENTS"] = "#define JSON_WRITE_BASH_COMMENTS";
options["WRITE_SINGLE_LINE_COMMENTS"] = "#define JSON_WRITE_SINGLE_LINE_COMMENTS";
options["VALIDATE"] = "#define JSON_VALIDATE";
options["UNIT_TEST"] = "#define JSON_UNIT_TEST";
options["INDEX_TYPE"] = "#define JSON_INDEX_TYPE unsigned int";
options["CASE_INSENSITIVE_FUNCTIONS"] = "#define JSON_CASE_INSENSITIVE_FUNCTIONS";
options["ESCAPE_WRITES"] = "#define JSON_ESCAPE_WRITES";
options["STRINGU_HEADER"] = "#define JSON_STRING_HEADER \"../TestSuite/UStringTest.h\"";
options["STRING_HEADER"] = "#define JSON_STRING_HEADER \"../TestSuite/StringTest.h\"";
options["CASTABLE"] = "#define JSON_CASTABLE";
options["STRICT"] = "#define JSON_STRICT";
options["MEMORY_POOL"] = "#define JSON_MEMORY_POOL 524288";
}
void testRules(unsigned int i){
remove("./testapp");
int q = system(make.c_str());
bool Archive = false;
if (FILE * fp = fopen("./testapp", "r")){
fclose(fp);
remove("./out.html");
q = system("./testapp");
if (FILE * fp = fopen("./out.html", "r")){
char buffer[255];
size_t qq = fread(&buffer[0], 255, 1, fp);
buffer[254] = '\0';
fclose(fp);
string buf(&buffer[0]);
size_t pos = buf.find("Failed Tests: <c style=\"color:#CC0000\">");
if (pos == string::npos){
FAIL("Something Wrong");
} else {
if(buf[pos + 39] == '0'){
PASS("GOOD");
} else {
size_t pp = buf.find('<', pos + 39);
FAIL(string("Didn't pass ") + buf.substr(pos + 39, pp - pos - 39) + " tests");
ArchivedOptions = std::string("Fail_") + ArchivedOptions;
Archive = true;
}
}
} else {
FAIL("Running crashed");
ArchivedOptions = std::string("Crashed_") + ArchivedOptions;
Archive = true;
}
} else {
FAIL(string("Compilation failed - ") + lines[i]);
ArchivedOptions = std::string("Compile_") + ArchivedOptions;
Archive = true;
}
//If something broke, make a copy of the options used to make the failure, so it can be easily retested
if (Archive){
if (FILE * fp = fopen("../JSONOptions.h", "r")){
ArchivedOptions = std::string("../") + ArchivedOptions;
if (FILE * ofp = fopen(ArchivedOptions.c_str(), "w")){
char buffer[2048] = {'\0'};
size_t qq = fread(&buffer[0], 2048, 1, fp);
fwrite(&buffer[0], strlen(&buffer[0]), 1, ofp);
fclose(ofp);
}
fclose(fp);
}
}
}
bool makeTempOptions(unsigned int i){
string & line = lines[i];
if (FILE * fp = fopen("../JSONOptions.h", "w")){
string res("#ifndef JSON_OPTIONS_H\n#define JSON_OPTIONS_H\n");
for (
map<string, string>::iterator runner = options.begin(), end = options.end();
runner != end;
++runner){
if (line.find(runner -> first) != string::npos){
res += runner -> second + "\n";
}
}
res += "#endif\n";
fwrite(res.c_str(), res.length(), 1, fp);
fclose(fp);
return true;
}
return false;
}
bool hideGoodOptions(void){
struct stat stFileInfo;
if (stat("../__JSONOptions.h", &stFileInfo)){
remove("../JSONOptions.h");
return true;
}
return (rename("../JSONOptions.h", "../__JSONOptions.h") == 0);
}
bool loadTests(){
ifstream infile("All/Options.txt");
if (!infile){
return false;
}
string line;
unsigned int iii = 0;
while (getline(infile, line)){
++iii;
size_t pos = line.find_first_not_of(' ');
if (pos != string::npos){
line = line.substr(pos);
pos = line.find_first_not_of("\r\n\t ");
if ((line.length() > 5) && (line[0] != '#')){
const string temp(line.substr(pos));
lines.push_back(string("READER, ") + temp);
line_numbers.push_back(iii);
if ((temp.find("VALIDATE") == string::npos) && (temp.find("STREAM") == string::npos)){
lines.push_back(temp);
line_numbers.push_back(iii);
}
}
}
}
infile.close();
return true;
}
void RunTest(const std::string & version, unsigned int i){
if(makeTempOptions(i)){
stringstream mystream;
mystream << version << " Line " << line_numbers[i];
cout << "Compiling " << ++counter << " of " << line_numbers.size() * 3 << " - " << mystream.str() << endl;
cout << " " << lines[i] << endl;
UnitTest::SetPrefix(mystream.str());
stringstream options_;
options_ << version << "_Line_" << line_numbers[i] << "_JSONOptions.h";
ArchivedOptions = options_.str();
testRules(i);
remove("../JSONOptions.h");
UnitTest::SaveTo("progress.html");
}
}
void Go(const std::string & version, unsigned int test){
echo(make);
if (makeStyle.empty() || (makeStyle == version)){
makeStyle.clear();
for (unsigned int i = test; i < lines.size(); ++i){
RunTest(version, i);
}
} else {
echo("skipping");
}
}
void RunTests(unsigned int test){
if (hideGoodOptions()){
if(loadTests()){
makeMap();
for(unsigned int i = 0; i < sizeof(makeOptions); ++i){
make = "make -j4 " + makeOptions[i];
Go(makeOptions[i], test);
}
} else {
FAIL("couldn't open options");
}
rename("../__JSONOptions.h", "../JSONOptions.h");
} else {
FAIL("Couldn't protect JSONOptions");
}
}
int main (int argc, char * const argv[]) {
UnitTest::StartTime();
unsigned int test = 0;
if (argc == 3){
test = atoi(argv[2]) - 1;
counter = test;
echo("starting on test " << test);
makeStyle = argv[1];
echo("starting with make " << makeStyle);
} else if (argc == 2){
test = 0;
counter = test;
echo("starting on test " << test);
makeStyle = argv[1];
echo("starting with make " << makeStyle);
}
RunTests(test);
UnitTest::SaveTo("out.html");
return 0;
}

View file

@ -0,0 +1,311 @@
/**
*
* This test suite should get run before releasing a new version of libjson, once all
* unit tests have passed. This asserts that the Options are in the default configuration,
* this prevents me from accidentally releasing libjson using options that I had been testing
* with. It also performs a speed benchmark, so I can keep track of how libjson is performing
*
*/
#include <iostream>
#include <string>
#include <ctime>
#include "../../libjson.h"
using namespace std;
#ifndef JSON_LIBRARY
#error, JSON_LIBRARY not on
#endif
#ifdef JSON_STRICT
#error, JSON_STRICT on
#endif
#ifdef JSON_DEBUG
#error, JSON_DEBUG on
#endif
#ifdef JSON_ISO_STRICT
#error, JSON_ISO_STRICT on
#endif
#ifndef JSON_SAFE
#error, JSON_SAFE not on
#endif
#ifndef JSON_CASTABLE
#error, JSON_CASTABLE not on
#endif
#ifdef JSON_STDERROR
#error, JSON_STDERROR on
#endif
#ifdef JSON_PREPARSE
#error, JSON_PREPARSE on
#endif
#ifdef JSON_LESS_MEMORY
#error, JSON_LESS_MEMORY on
#endif
#ifdef JSON_UNICODE
#error, JSON_UNICODE on
#endif
#ifndef JSON_REF_COUNT
#error, JSON_REF_COUNT not on
#endif
#ifndef JSON_BINARY
#error, JSON_BINARY not on
#endif
#ifndef JSON_EXPOSE_BASE64
#error, JSON_EXPOSE_BASE64 not on
#endif
#ifndef JSON_ITERATORS
#error, JSON_ITERATORS not on
#endif
#ifndef JSON_STREAM
#error, JSON_STREAM not on
#endif
#ifdef JSON_MEMORY_CALLBACKS
#error, JSON_MEMORY_CALLBACKS on
#endif
#ifdef JSON_MEMORY_MANAGE
#error, JSON_MEMORY_MANAGE on
#endif
#ifdef JSON_MUTEX_CALLBACKS
#error, JSON_MUTEX_CALLBACKS on
#endif
#ifdef JSON_MUTEX_MANAGE
#error, JSON_MUTEX_MANAGE on
#endif
#ifdef JSON_NO_C_CONSTS
#error, JSON_NO_C_CONSTS on
#endif
#ifdef JSON_OCTAL
#error, JSON_OCTAL on
#endif
#if (JSON_READ_PRIORITY != HIGH)
#error JSON_READ_PRIORITY not high
#endif
#if (JSON_WRITE_PRIORITY != MED)
#error JSON_WRITE_PRIORITY not med
#endif
#ifdef JSON_NEWLINE
#error, JSON_NEWLINE on
#endif
#ifdef JSON_INDENT
#error, JSON_INDENT on
#endif
#ifndef JSON_ESCAPE_WRITES
#error, JSON_ESCAPE_WRITES not on
#endif
#ifndef JSON_COMMENTS
#error, JSON_COMMENTS not on
#endif
#ifdef JSON_WRITE_BASH_COMMENTS
#error, JSON_WRITE_BASH_COMMENTS on
#endif
#ifdef JSON_WRITE_SINGLE_LINE_COMMENTS
#error, JSON_WRITE_SINGLE_LINE_COMMENTS on
#endif
#ifdef JSON_ARRAY_ON_ONE_LINE
#error, JSON_ARRAY_ON_ONE_LINE on
#endif
#ifndef JSON_VALIDATE
#error, JSON_VALIDATE not on
#endif
#ifndef JSON_CASE_INSENSITIVE_FUNCTIONS
#error, JSON_CASE_INSENSITIVE_FUNCTIONS not on
#endif
#ifdef JSON_INDEX_TYPE
#error, JSON_INDEX_TYPE on
#endif
#ifdef JSON_BOOL_TYPE
#error, JSON_BOOL_TYPE on
#endif
#ifdef JSON_INT_TYPE
#error, JSON_INT_TYPE on
#endif
#ifdef JSON_STRING_HEADER
#error, JSON_STRING_HEADER on
#endif
#ifdef JSON_NO_EXCEPTIONS
#error, JSON_NO_EXCEPTIONS on
#endif
#ifndef JSON_DEPRECATED_FUNCTIONS
#error, JSON_DEPRECATED_FUNCTIONS not on
#endif
#if (JSON_SECURITY_MAX_NEST_LEVEL != 128)
#error JSON_SECURITY_MAX_NEST_LEVEL not 128
#endif
#if (JSON_SECURITY_MAX_STRING_LENGTH != 33554432)
#error JSON_SECURITY_MAX_STRING_LENGTH not 33554432
#endif
#if (JSON_SECURITY_MAX_STREAM_OBJECTS != 128)
#error JSON_SECURITY_MAX_STREAM_OBJECTS not 128
#endif
#ifdef JSON_MEMORY_POOL
#error JSON_MEMORY_POOL is on
#endif
#ifdef JSON_UNIT_TEST
#error, JSON_UNIT_TEST on
#endif
#define IT_COUNT 50000
static string makeBigFormatted(){
string json = "{\n";
for(unsigned int i = 0; i < IT_COUNT; ++i){
json += "\t//This is an object\r\n\t{\n\t\t\"name\" : 14.783,\n\t\t/* This is a multilen commenet */\n\t\t\"another\" : \"I am a stirng\"\n\t},";
json += "\n\n\t//This is an array\r\n\t[4, 16, true, false, 78.98],\n";
}
json += "\t\"number\" : null\n}";
return json;
}
static string makeBig(){
string json = "{";
for(unsigned int i = 0; i < IT_COUNT; ++i){
json += "{\"name\":14.783,\"another\":\"I am a stirng\"},";
json += "[4, 16, true, false, 78.98],";
}
json += "\"number\":null}";
return json;
}
int main (int argc, char * const argv[]) {
JSONNODE * node;
string mystr = makeBigFormatted();
clock_t start = clock();
for(unsigned int i = 0; i < 100; ++i){
node = json_parse(mystr.c_str());
for (unsigned int j = 0; j < IT_COUNT; ++j){
JSONNODE * meh = json_at(node, j * 2);
json_as_float(json_get(meh, "name"));
char * str = json_as_string(json_get(meh, "another"));
json_free(str);
meh = json_at(node, j * 2 + 1);
json_as_int(json_at(meh, 0));
json_as_int(json_at(meh, 1));
json_as_bool(json_at(meh, 2));
json_as_bool(json_at(meh, 3));
json_as_int(json_at(meh, 4));
}
json_delete(node);
}
cout << "Reading: " << clock() - start << endl;
mystr = makeBig();
start = clock();
for(unsigned int i = 0; i < 100; ++i){
node = json_parse(mystr.c_str());
for (unsigned int j = 0; j < IT_COUNT; ++j){
JSONNODE * meh = json_at(node, j * 2);
json_as_float(json_get(meh, "name"));
char * str = json_as_string(json_get(meh, "another"));
json_free(str);
meh = json_at(node, j * 2 + 1);
json_as_int(json_at(meh, 0));
json_as_int(json_at(meh, 1));
json_as_bool(json_at(meh, 2));
json_as_bool(json_at(meh, 3));
json_as_int(json_at(meh, 4));
}
json_delete(node);
}
cout << "Reading Unformatted: " << clock() - start << endl;
start = clock();
for(unsigned int i = 0; i < 100; ++i){
node = json_new(JSON_NODE);
for (unsigned int j = 0; j < IT_COUNT; ++j){
JSONNODE * meh = json_new(JSON_NODE);
json_push_back(meh, json_new_f("name", 14.783));
json_push_back(meh, json_new_a("another", "I am a string"));
json_push_back(node, meh);
meh = json_new(JSON_ARRAY);
json_push_back(meh, json_new_i(NULL, 14));
json_push_back(meh, json_new_i("", 1));
json_push_back(meh, json_new_b(NULL, true));
json_push_back(meh, json_new_b("", false));
json_push_back(meh, json_new_f(NULL, 14.3243));
json_push_back(node, meh);
}
json_delete(node);
}
cout << "Building: " << clock() - start << endl;
node = json_new(JSON_NODE);
for (unsigned int j = 0; j < IT_COUNT; ++j){
JSONNODE * meh = json_new(JSON_NODE);
json_push_back(meh, json_new_f("name", 14.783));
json_push_back(meh, json_new_a("another", "I am a string"));
json_push_back(node, meh);
meh = json_new(JSON_ARRAY);
json_push_back(meh, json_new_i(NULL, 14));
json_push_back(meh, json_new_i("", 1));
json_push_back(meh, json_new_b(NULL, true));
json_push_back(meh, json_new_b("", false));
json_push_back(meh, json_new_f(NULL, 14.3243));
json_push_back(node, meh);
}
start = clock();
for(unsigned int i = 0; i < 100; ++i){
char * str = json_write_formatted(node);
json_free(str);
}
cout << "Writing: " << clock() - start << endl;
start = clock();
for(unsigned int i = 0; i < 100; ++i){
char * str = json_write(node);
json_free(str);
}
cout << "Writing Unformatted: " << clock() - start << endl;
json_delete(node);
return 0;
}

View file

@ -0,0 +1,42 @@
OS=$(shell uname)
ifeq ($(OS), Darwin)
fastflag = -fast
else
fastflag = -O3
endif
single:
g++ main.cpp \
../../Source/internalJSONNode.cpp \
../../Source/JSONChildren.cpp ../../Source/JSONDebug.cpp \
../../Source/JSONIterators.cpp ../../Source/JSONMemory.cpp \
../../Source/JSONNode_Mutex.cpp ../../Source/JSONNode.cpp \
../../Source/JSONWorker.cpp ../../Source/JSONWriter.cpp \
../../Source/libjson.cpp ../../Source/JSONValidator.cpp \
../../Source/JSONStream.cpp ../../Source/JSONAllocator.cpp \
../../Source/JSONPreparse.cpp \
-Wfatal-errors -DNDEBUG $(fastflag) -ffast-math -fexpensive-optimizations -o testapp
debug:
g++ main.cpp \
../../Source/internalJSONNode.cpp \
../../Source/JSONChildren.cpp ../../Source/JSONDebug.cpp \
../../Source/JSONIterators.cpp ../../Source/JSONMemory.cpp \
../../Source/JSONNode_Mutex.cpp ../../Source/JSONNode.cpp \
../../Source/JSONWorker.cpp ../../Source/JSONWriter.cpp \
../../Source/libjson.cpp ../../Source/JSONValidator.cpp \
../../Source/JSONStream.cpp ../../Source/JSONAllocator.cpp \
../../Source/JSONPreparse.cpp \
-Wfatal-errors -DJSON_DEBUG -o testapp
small:
g++ main.cpp \
../../Source/internalJSONNode.cpp \
../../Source/JSONChildren.cpp ../../Source/JSONDebug.cpp \
../../Source/JSONIterators.cpp ../../Source/JSONMemory.cpp \
../../Source/JSONNode_Mutex.cpp ../../Source/JSONNode.cpp \
../../Source/JSONWorker.cpp ../../Source/JSONWriter.cpp \
../../Source/libjson.cpp ../../Source/JSONValidator.cpp \
../../Source/JSONStream.cpp ../../Source/JSONAllocator.cpp \
../../Source/JSONPreparse.cpp \
-Wfatal-errors -DNDEBUG -Os -ffast-math -DJSON_LESS_MEMORY -o testapp

Some files were not shown because too many files have changed in this diff Show more