diff options
Diffstat (limited to 'include/json')
-rw-r--r-- | include/json/allocator.h | 98 | ||||
-rw-r--r-- | include/json/assertions.h | 41 | ||||
-rw-r--r-- | include/json/config.h | 135 | ||||
-rw-r--r-- | include/json/features.h | 6 | ||||
-rw-r--r-- | include/json/forwards.h | 8 | ||||
-rw-r--r-- | include/json/json.h | 2 | ||||
-rw-r--r-- | include/json/reader.h | 177 | ||||
-rw-r--r-- | include/json/value.h | 715 | ||||
-rw-r--r-- | include/json/version.h | 16 | ||||
-rw-r--r-- | include/json/writer.h | 202 |
10 files changed, 824 insertions, 576 deletions
diff --git a/include/json/allocator.h b/include/json/allocator.h new file mode 100644 index 0000000..9c7e573 --- /dev/null +++ b/include/json/allocator.h @@ -0,0 +1,98 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED +#define CPPTL_JSON_ALLOCATOR_H_INCLUDED + +#include <cstring> +#include <memory> + +#pragma pack(push, 8) + +namespace Json { +template<typename T> +class SecureAllocator { + public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) { + // allocate using "global operator new" + return static_cast<pointer>(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + * The pointer argument is tagged as "volatile" to prevent the + * compiler optimizing out this critical step. + */ + void deallocate(volatile pointer p, size_type n) { + std::memset(p, 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template<typename... Args> + void construct(pointer p, Args&&... args) { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...); + } + + size_type max_size() const { + return size_t(-1) / sizeof(T); + } + + pointer address( reference x ) const { + return std::addressof(x); + } + + const_pointer address( const_reference x ) const { + return std::addressof(x); + } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template<typename U> SecureAllocator(const SecureAllocator<U>&) {} + template<typename U> struct rebind { using other = SecureAllocator<U>; }; +}; + + +template<typename T, typename U> +bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) { + return true; +} + +template<typename T, typename U> +bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) { + return false; +} + +} //namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED diff --git a/include/json/assertions.h b/include/json/assertions.h index 5ef7e7b..1cca28d 100644 --- a/include/json/assertions.h +++ b/include/json/assertions.h @@ -1,4 +1,4 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -7,35 +7,48 @@ #define CPPTL_JSON_ASSERTIONS_H_INCLUDED #include <stdlib.h> +#include <sstream> #if !defined(JSON_IS_AMALGAMATION) #include "config.h" #endif // if !defined(JSON_IS_AMALGAMATION) +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ #if JSON_USE_EXCEPTION -#include <stdexcept> -#define JSON_ASSERT(condition) \ - assert(condition); // @todo <= change this into an exception throw -#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message); + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + #else // JSON_USE_EXCEPTION -#define JSON_ASSERT(condition) assert(condition); + +# define JSON_ASSERT(condition) assert(condition) // The call to assert() will show the failure message in debug builds. In -// release bugs we write to invalid memory in order to crash hard, so that a -// debugger or crash reporter gets the chance to take over. We still call exit() -// afterward in order to tell the compiler that this macro doesn't return. -#define JSON_FAIL_MESSAGE(message) \ +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ { \ - assert(false&& message); \ - strcpy(reinterpret_cast<char*>(666), message); \ - exit(123); \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ } + #endif #define JSON_ASSERT_MESSAGE(condition, message) \ if (!(condition)) { \ - JSON_FAIL_MESSAGE(message) \ + JSON_FAIL_MESSAGE(message); \ } #endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED diff --git a/include/json/config.h b/include/json/config.h index afd3a45..c83e78a 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -1,10 +1,13 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED +#include <stddef.h> +#include <string> //typedef String +#include <stdint.h> //typedef int64_t, uint64_t /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 @@ -15,17 +18,6 @@ /// std::map /// as Value container. //# define JSON_USE_CPPTL_SMALLMAP 1 -/// If defined, indicates that Json specific container should be used -/// (hash table & simple deque container with customizable allocator). -/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 -//# define JSON_VALUE_USE_INTERNAL_MAP 1 -/// Force usage of standard new/malloc based allocator instead of memory pool -/// based allocator. -/// The memory pools allocator used optimization (initializing Value and -/// ValueInternalLink -/// as if it was a POD) that may cause some validation tool to report errors. -/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. -//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 // If non-zero, the library uses exceptions to report bad input instead of C // assertion macros. The default is to use exceptions. @@ -48,12 +40,12 @@ #ifdef JSON_IN_CPPTL #define JSON_API CPPTL_API #elif defined(JSON_DLL_BUILD) -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #define JSON_API __declspec(dllexport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) #elif defined(JSON_DLL) -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #define JSON_API __declspec(dllimport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) @@ -67,26 +59,96 @@ // Storages, and 64 bits integer support is disabled. // #define JSON_NO_INT64 1 -#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 -// Microsoft Visual Studio 6 only support conversion from __int64 to double -// (no conversion from unsigned __int64). -#define JSON_USE_INT64_DOUBLE_CONVERSION 1 -// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' -// characters in the debug information) -// All projects I've ever seen with VS6 were using this globally (not bothering -// with pragma push/pop). -#pragma warning(disable : 4786) -#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 - -#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 -/// Indicates that the following function is deprecated. -#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#if defined(_MSC_VER) // MSVC +# if _MSC_VER <= 1200 // MSVC 6 + // Microsoft Visual Studio 6 only support conversion from __int64 to double + // (no conversion from unsigned __int64). +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicity define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT throw() +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#else +# define JSONCPP_OVERRIDE +# define JSONCPP_NOEXCEPT throw() +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 #endif +#ifdef __clang__ +# if __has_extension(attribute_deprecated_with_message) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + #if !defined(JSONCPP_DEPRECATED) #define JSONCPP_DEPRECATED(message) #endif // if !defined(JSONCPP_DEPRECATED) +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + namespace Json { typedef int Int; typedef unsigned int UInt; @@ -100,13 +162,26 @@ typedef unsigned int LargestUInt; typedef __int64 Int64; typedef unsigned __int64 UInt64; #else // if defined(_MSC_VER) // Other platforms, use long long -typedef long long int Int64; -typedef unsigned long long int UInt64; +typedef int64_t Int64; +typedef uint64_t UInt64; #endif // if defined(_MSC_VER) typedef Int64 LargestInt; typedef UInt64 LargestUInt; #define JSON_HAS_INT64 #endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY } // end namespace Json #endif // JSON_CONFIG_H_INCLUDED diff --git a/include/json/features.h b/include/json/features.h index 1bb7bb6..72eb6a8 100644 --- a/include/json/features.h +++ b/include/json/features.h @@ -1,4 +1,4 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -10,6 +10,8 @@ #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) +#pragma pack(push, 8) + namespace Json { /** \brief Configuration passed to reader and writer. @@ -54,4 +56,6 @@ public: } // namespace Json +#pragma pack(pop) + #endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/include/json/forwards.h b/include/json/forwards.h index 84a26cd..70bbe19 100644 --- a/include/json/forwards.h +++ b/include/json/forwards.h @@ -1,4 +1,4 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -31,12 +31,6 @@ class Value; class ValueIteratorBase; class ValueIterator; class ValueConstIterator; -#ifdef JSON_VALUE_USE_INTERNAL_MAP -class ValueMapAllocator; -class ValueInternalLink; -class ValueInternalArray; -class ValueInternalMap; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP } // namespace Json diff --git a/include/json/json.h b/include/json/json.h index 8f10ac2..3d2798a 100644 --- a/include/json/json.h +++ b/include/json/json.h @@ -1,4 +1,4 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE diff --git a/include/json/reader.h b/include/json/reader.h index 98814d5..82859fd 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -1,4 +1,4 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -14,6 +14,7 @@ #include <iosfwd> #include <stack> #include <string> +#include <istream> // Disable warning C4251: <data member>: <type> needs to have dll-interface to // be used by... @@ -22,13 +23,16 @@ #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + namespace Json { /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a *Value. * + * \deprecated Use CharReader and CharReaderBuilder. */ -class JSON_API Reader { +class JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") JSON_API Reader { public: typedef char Char; typedef const Char* Location; @@ -40,9 +44,9 @@ public: * */ struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; }; /** \brief Constructs a Reader allowing all features @@ -78,7 +82,7 @@ public: document to read. * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. - \ Must be >= beginDoc. + * Must be >= beginDoc. * \param root [out] Contains the root value of the document if it was * successfully parsed. * \param collectComments \c true to collect comment and allow writing them @@ -97,7 +101,7 @@ public: /// \brief Parse from input stream. /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse(std::istream& is, Value& root, bool collectComments = true); + bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); /** \brief Returns a user friendly string that list errors in the parsed * document. @@ -108,8 +112,8 @@ public: * during parsing. * \deprecated Use getFormattedErrorMessages() instead (typo fix). */ - JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") - std::string getFormatedErrorMessages() const; + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + JSONCPP_STRING getFormatedErrorMessages() const; /** \brief Returns a user friendly string that list errors in the parsed * document. @@ -119,7 +123,7 @@ public: * occurred * during parsing. */ - std::string getFormattedErrorMessages() const; + JSONCPP_STRING getFormattedErrorMessages() const; /** \brief Returns a vector of structured erros encounted while parsing. * \return A (possibly empty) vector of StructuredError objects. Currently @@ -136,7 +140,7 @@ public: * \return \c true if the error was successfully added, \c false if the * Value offset exceeds the document size. */ - bool pushError(const Value& value, const std::string& message); + bool pushError(const Value& value, const JSONCPP_STRING& message); /** \brief Add a semantic error message with extra context. * \param value JSON Value location associated with the error @@ -145,7 +149,7 @@ public: * \return \c true if the error was successfully added, \c false if either * Value offset exceeds the document size. */ - bool pushError(const Value& value, const std::string& message, const Value& extra); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); /** \brief Return whether there are any errors. * \return \c true if there are no errors to report \c false if @@ -181,13 +185,12 @@ private: class ErrorInfo { public: Token token_; - std::string message_; + JSONCPP_STRING message_; Location extra_; }; typedef std::deque<ErrorInfo> Errors; - bool expectToken(TokenType type, Token& token, const char* message); bool readToken(Token& token); void skipSpaces(); bool match(Location pattern, int patternLength); @@ -202,7 +205,7 @@ private: bool decodeNumber(Token& token); bool decodeNumber(Token& token, Value& decoded); bool decodeString(Token& token); - bool decodeString(Token& token, std::string& decoded); + bool decodeString(Token& token, JSONCPP_STRING& decoded); bool decodeDouble(Token& token); bool decodeDouble(Token& token, Value& decoded); bool decodeUnicodeCodePoint(Token& token, @@ -213,9 +216,9 @@ private: Location& current, Location end, unsigned int& unicode); - bool addError(const std::string& message, Token& token, Location extra = 0); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const std::string& message, + bool addErrorAndRecover(const JSONCPP_STRING& message, Token& token, TokenType skipUntilToken); void skipUntilSpace(); @@ -223,24 +226,154 @@ private: Char getNextChar(); void getLocationLineAndColumn(Location location, int& line, int& column) const; - std::string getLocationLineAndColumn(Location location) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; void addComment(Location begin, Location end, CommentPlacement placement); void skipCommentTokens(Token& token); + static bool containsNewLine(Location begin, Location end); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + typedef std::stack<Value*> Nodes; Nodes nodes_; Errors errors_; - std::string document_; + JSONCPP_STRING document_; Location begin_; Location end_; Location current_; Location lastValueEnd_; Value* lastValue_; - std::string commentsBefore_; + JSONCPP_STRING commentsBefore_; Features features_; bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> + document. + * The document must be a UTF-8 encoded string containing the document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_STRING errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); }; +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream( + CharReader::Factory const&, + JSONCPP_ISTREAM&, + Value* root, std::string* errs); + /** \brief Read from 'sin' into 'root'. Always keep comments from the input JSON. @@ -265,10 +398,12 @@ private: \throw std::exception on parse error. \see Json::operator<<() */ -JSON_API std::istream& operator>>(std::istream&, Value&); +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); } // namespace Json +#pragma pack(pop) + #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) diff --git a/include/json/value.h b/include/json/value.h index 197a856..ebca175 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -1,4 +1,4 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -11,6 +11,7 @@ #endif // if !defined(JSON_IS_AMALGAMATION) #include <string> #include <vector> +#include <exception> #ifndef JSON_USE_CPPTL_SMALLMAP #include <map> @@ -21,6 +22,19 @@ #include <cpptl/forwards.h> #endif +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + // Disable warning C4251: <data member>: <type> needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) @@ -28,10 +42,52 @@ #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + /** \brief JSON (JavaScript Object Notation). */ namespace Json { +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; +protected: + JSONCPP_STRING msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); + /** \brief Type of the value held by a Value object. */ enum ValueType { @@ -74,14 +130,14 @@ enum CommentPlacement { */ class JSON_API StaticString { public: - explicit StaticString(const char* czstring) : str_(czstring) {} + explicit StaticString(const char* czstring) : c_str_(czstring) {} - operator const char*() const { return str_; } + operator const char*() const { return c_str_; } - const char* c_str() const { return str_; } + const char* c_str() const { return c_str_; } private: - const char* str_; + const char* c_str_; }; /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. @@ -99,28 +155,29 @@ private: * The type of the held value is represented by a #ValueType and * can be obtained using type(). * - * values of an #objectValue or #arrayValue can be accessed using operator[]() - *methods. - * Non const methods will automatically create the a #nullValue element + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element * if it does not exist. - * The sequence of an #arrayValue will be automatically resize and initialized + * The sequence of an #arrayValue will be automatically resized and initialized * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. * - * The get() methods can be used to obtanis default value in the case the - *required element - * does not exist. + * The get() methods can be used to obtain default value in the case the + * required element does not exist. * * It is possible to iterate over the list of a #objectValue values using * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. */ class JSON_API Value { friend class ValueIteratorBase; -#ifdef JSON_VALUE_USE_INTERNAL_MAP - friend class ValueInternalLink; - friend class ValueInternalMap; -#endif public: - typedef std::vector<std::string> Members; + typedef std::vector<JSONCPP_STRING> Members; typedef ValueIterator iterator; typedef ValueConstIterator const_iterator; typedef Json::UInt UInt; @@ -133,7 +190,10 @@ public: typedef Json::LargestUInt LargestUInt; typedef Json::ArrayIndex ArrayIndex; - static const Value& null; + static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + /// Minimum signed integer value that can be stored in a Json::Value. static const LargestInt minLargestInt; /// Maximum signed integer value that can be stored in a Json::Value. @@ -159,7 +219,6 @@ public: private: #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION -#ifndef JSON_VALUE_USE_INTERNAL_MAP class CZString { public: enum DuplicationPolicy { @@ -168,20 +227,39 @@ private: duplicateOnCopy }; CZString(ArrayIndex index); - CZString(const char* cstr, DuplicationPolicy allocate); - CZString(const CZString& other); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif ~CZString(); - CZString& operator=(CZString other); - bool operator<(const CZString& other) const; - bool operator==(const CZString& other) const; + CZString& operator=(const CZString& other); + +#if JSON_HAS_RVALUE_REFERENCES + CZString& operator=(CZString&& other); +#endif + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; ArrayIndex index() const; - const char* c_str() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; bool isStaticString() const; private: void swap(CZString& other); - const char* cstr_; - ArrayIndex index_; + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; }; public: @@ -190,7 +268,6 @@ public: #else typedef CppTL::SmallMap<CZString, Value> ObjectValues; #endif // ifndef JSON_USE_CPPTL_SMALLMAP -#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION public: @@ -217,47 +294,72 @@ Json::Value obj_value(Json::objectValue); // {} Value(UInt64 value); #endif // if defined(JSON_HAS_INT64) Value(double value); - Value(const char* value); - Value(const char* beginValue, const char* endValue); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. /** \brief Constructs a value from a static string. * Like other value string constructor but do not duplicate the string for * internal storage. The given string must remain alive after the call to this * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * * Example of usage: * \code - * Json::Value aValue( StaticString("some text") ); + * static StaticString foo("some text"); + * Json::Value aValue(foo); * \endcode */ Value(const StaticString& value); - Value(const std::string& value); + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. #ifdef JSON_USE_CPPTL Value(const CppTL::ConstString& value); #endif Value(bool value); + /// Deep copy. Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif ~Value(); + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). Value& operator=(Value other); - /// Swap values. - /// \note Currently, comments are intentionally not swapped, for - /// both logic and efficiency. + + /// Swap everything. void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); ValueType type() const; + /// Compare payload only, not comments etc. bool operator<(const Value& other) const; bool operator<=(const Value& other) const; bool operator>=(const Value& other) const; bool operator>(const Value& other) const; - bool operator==(const Value& other) const; bool operator!=(const Value& other) const; - int compare(const Value& other) const; - const char* asCString() const; - std::string asString() const; + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; //Allows you to understand the length of the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; #ifdef JSON_USE_CPPTL CppTL::ConstString asConstString() const; #endif @@ -347,20 +449,28 @@ Json::Value obj_value(Json::objectValue); // {} /// Equivalent to jsonvalue[jsonvalue.size()] = value; Value& append(const Value& value); +#if JSON_HAS_RVALUE_REFERENCES + Value& append(Value&& value); +#endif + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. Value& operator[](const char* key); /// Access an object value by name, returns null if there is no member with /// that name. const Value& operator[](const char* key) const; /// Access an object value by name, create a null member if it does not exist. - Value& operator[](const std::string& key); + /// \param key may contain embedded nulls. + Value& operator[](const JSONCPP_STRING& key); /// Access an object value by name, returns null if there is no member with /// that name. - const Value& operator[](const std::string& key) const; + /// \param key may contain embedded nulls. + const Value& operator[](const JSONCPP_STRING& key) const; /** \brief Access an object value by name, create a null member if it does not exist. - * If the object as no entry for that name, then the member name used to store + * If the object has no entry for that name, then the member name used to store * the new entry is not duplicated. * Example of use: * \code @@ -378,27 +488,71 @@ Json::Value obj_value(Json::objectValue); // {} const Value& operator[](const CppTL::ConstString& key) const; #endif /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy Value get(const char* key, const Value& defaultValue) const; /// Return the member named key if it exist, defaultValue otherwise. - Value get(const std::string& key, const Value& defaultValue) const; + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; #ifdef JSON_USE_CPPTL /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy Value get(const CppTL::ConstString& key, const Value& defaultValue) const; #endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); /// \brief Remove and return the named member. /// /// Do nothing if it did not exist. /// \return the removed Value, or null. /// \pre type() is objectValue or nullValue /// \post type() is unchanged + /// \deprecated + JSONCPP_DEPRECATED("") Value removeMember(const char* key); /// Same as removeMember(const char*) - Value removeMember(const std::string& key); + /// \param key may contain embedded nulls. + /// \deprecated + JSONCPP_DEPRECATED("") + Value removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. bool isMember(const char* key) const; /// Return true if the object has a member named key. - bool isMember(const std::string& key) const; + /// \param key may contain embedded nulls. + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) const; #ifdef JSON_USE_CPPTL /// Return true if the object has a member named key. bool isMember(const CppTL::ConstString& key) const; @@ -416,15 +570,18 @@ Json::Value obj_value(Json::objectValue); // {} // EnumValues enumValues() const; //# endif - /// Comments must be //... or /* ... */ + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") void setComment(const char* comment, CommentPlacement placement); /// Comments must be //... or /* ... */ - void setComment(const std::string& comment, CommentPlacement placement); + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); bool hasComment(CommentPlacement placement) const; /// Include delimiters and embedded newlines. - std::string getComment(CommentPlacement placement) const; + JSONCPP_STRING getComment(CommentPlacement placement) const; - std::string toStyledString() const; + JSONCPP_STRING toStyledString() const; const_iterator begin() const; const_iterator end() const; @@ -434,34 +591,22 @@ Json::Value obj_value(Json::objectValue); // {} // Accessors for the [start, limit) range of bytes within the JSON text from // which this value was parsed, if any. - void setOffsetStart(size_t start); - void setOffsetLimit(size_t limit); - size_t getOffsetStart() const; - size_t getOffsetLimit() const; + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; private: void initBasic(ValueType type, bool allocated = false); - Value& resolveReference(const char* key, bool isStatic); - -#ifdef JSON_VALUE_USE_INTERNAL_MAP - inline bool isItemAvailable() const { return itemIsUsed_ == 0; } + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); - inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; } - - inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; } - - inline void setMemberNameIsStatic(bool isStatic) { - memberNameIsStatic_ = isStatic ? 1 : 0; - } -#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP - -private: struct CommentInfo { CommentInfo(); ~CommentInfo(); - void setComment(const char* text); + void setComment(const char* text, size_t len); char* comment_; }; @@ -480,26 +625,18 @@ private: LargestUInt uint_; double real_; bool bool_; - char* string_; -#ifdef JSON_VALUE_USE_INTERNAL_MAP - ValueInternalArray* array_; - ValueInternalMap* map_; -#else + char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ ObjectValues* map_; -#endif } value_; ValueType type_ : 8; - int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. -#ifdef JSON_VALUE_USE_INTERNAL_MAP - unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. - int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. -#endif + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. CommentInfo* comments_; // [start, limit) byte offsets in the source JSON text from which this Value // was extracted. - size_t start_; - size_t limit_; + ptrdiff_t start_; + ptrdiff_t limit_; }; /** \brief Experimental and untested: represents an element of the "path" to @@ -512,7 +649,7 @@ public: PathArgument(); PathArgument(ArrayIndex index); PathArgument(const char* key); - PathArgument(const std::string& key); + PathArgument(const JSONCPP_STRING& key); private: enum Kind { @@ -520,7 +657,7 @@ private: kindIndex, kindKey }; - std::string key_; + JSONCPP_STRING key_; ArrayIndex index_; Kind kind_; }; @@ -538,7 +675,7 @@ private: */ class JSON_API Path { public: - Path(const std::string& path, + Path(const JSONCPP_STRING& path, const PathArgument& a1 = PathArgument(), const PathArgument& a2 = PathArgument(), const PathArgument& a3 = PathArgument(), @@ -555,355 +692,16 @@ private: typedef std::vector<const PathArgument*> InArgs; typedef std::vector<PathArgument> Args; - void makePath(const std::string& path, const InArgs& in); - void addPathInArg(const std::string& path, + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, const InArgs& in, InArgs::const_iterator& itInArg, PathArgument::Kind kind); - void invalidPath(const std::string& path, int location); + void invalidPath(const JSONCPP_STRING& path, int location); Args args_; }; -#ifdef JSON_VALUE_USE_INTERNAL_MAP -/** \brief Allocator to customize Value internal map. - * Below is an example of a simple implementation (default implementation - actually - * use memory pool for speed). - * \code - class DefaultValueMapAllocator : public ValueMapAllocator - { - public: // overridden from ValueMapAllocator - virtual ValueInternalMap *newMap() - { - return new ValueInternalMap(); - } - - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) - { - return new ValueInternalMap( other ); - } - - virtual void destructMap( ValueInternalMap *map ) - { - delete map; - } - - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) - { - return new ValueInternalLink[size]; - } - - virtual void releaseMapBuckets( ValueInternalLink *links ) - { - delete [] links; - } - - virtual ValueInternalLink *allocateMapLink() - { - return new ValueInternalLink(); - } - - virtual void releaseMapLink( ValueInternalLink *link ) - { - delete link; - } - }; - * \endcode - */ -class JSON_API ValueMapAllocator { -public: - virtual ~ValueMapAllocator(); - virtual ValueInternalMap* newMap() = 0; - virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) = 0; - virtual void destructMap(ValueInternalMap* map) = 0; - virtual ValueInternalLink* allocateMapBuckets(unsigned int size) = 0; - virtual void releaseMapBuckets(ValueInternalLink* links) = 0; - virtual ValueInternalLink* allocateMapLink() = 0; - virtual void releaseMapLink(ValueInternalLink* link) = 0; -}; - -/** \brief ValueInternalMap hash-map bucket chain link (for internal use only). - * \internal previous_ & next_ allows for bidirectional traversal. - */ -class JSON_API ValueInternalLink { -public: - enum { - itemPerLink = 6 - }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. - enum InternalFlags { - flagAvailable = 0, - flagUsed = 1 - }; - - ValueInternalLink(); - - ~ValueInternalLink(); - - Value items_[itemPerLink]; - char* keys_[itemPerLink]; - ValueInternalLink* previous_; - ValueInternalLink* next_; -}; - -/** \brief A linked page based hash-table implementation used internally by - *Value. - * \internal ValueInternalMap is a tradional bucket based hash-table, with a - *linked - * list in each bucket to handle collision. There is an addional twist in that - * each node of the collision linked list is a page containing a fixed amount of - * value. This provides a better compromise between memory usage and speed. - * - * Each bucket is made up of a chained list of ValueInternalLink. The last - * link of a given bucket can be found in the 'previous_' field of the following - *bucket. - * The last link of the last bucket is stored in tailLink_ as it has no - *following bucket. - * Only the last link of a bucket may contains 'available' item. The last link - *always - * contains at least one element unless is it the bucket one very first link. - */ -class JSON_API ValueInternalMap { - friend class ValueIteratorBase; - friend class Value; - -public: - typedef unsigned int HashKey; - typedef unsigned int BucketIndex; - -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState { - IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {} - ValueInternalMap* map_; - ValueInternalLink* link_; - BucketIndex itemIndex_; - BucketIndex bucketIndex_; - }; -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalMap(); - ValueInternalMap(const ValueInternalMap& other); - ValueInternalMap& operator=(ValueInternalMap other); - ~ValueInternalMap(); - - void swap(ValueInternalMap& other); - - BucketIndex size() const; - - void clear(); - - bool reserveDelta(BucketIndex growth); - - bool reserve(BucketIndex newItemCount); - - const Value* find(const char* key) const; - - Value* find(const char* key); - - Value& resolveReference(const char* key, bool isStatic); - - void remove(const char* key); - - void doActualRemove(ValueInternalLink* link, - BucketIndex index, - BucketIndex bucketIndex); - - ValueInternalLink*& getLastLinkInBucket(BucketIndex bucketIndex); - - Value& setNewItem(const char* key, - bool isStatic, - ValueInternalLink* link, - BucketIndex index); - - Value& unsafeAdd(const char* key, bool isStatic, HashKey hashedKey); - - HashKey hash(const char* key) const; - - int compare(const ValueInternalMap& other) const; - -private: - void makeBeginIterator(IteratorState& it) const; - void makeEndIterator(IteratorState& it) const; - static bool equals(const IteratorState& x, const IteratorState& other); - static void increment(IteratorState& iterator); - static void incrementBucket(IteratorState& iterator); - static void decrement(IteratorState& iterator); - static const char* key(const IteratorState& iterator); - static const char* key(const IteratorState& iterator, bool& isStatic); - static Value& value(const IteratorState& iterator); - static int distance(const IteratorState& x, const IteratorState& y); - -private: - ValueInternalLink* buckets_; - ValueInternalLink* tailLink_; - BucketIndex bucketsSize_; - BucketIndex itemCount_; -}; - -/** \brief A simplified deque implementation used internally by Value. -* \internal -* It is based on a list of fixed "page", each page contains a fixed number of -*items. -* Instead of using a linked-list, a array of pointer is used for fast item -*look-up. -* Look-up for an element is as follow: -* - compute page index: pageIndex = itemIndex / itemsPerPage -* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] -* -* Insertion is amortized constant time (only the array containing the index of -*pointers -* need to be reallocated when items are appended). -*/ -class JSON_API ValueInternalArray { - friend class Value; - friend class ValueIteratorBase; - -public: - enum { - itemsPerPage = 8 - }; // should be a power of 2 for fast divide and modulo. - typedef Value::ArrayIndex ArrayIndex; - typedef unsigned int PageIndex; - -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState // Must be a POD - { - IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {} - ValueInternalArray* array_; - Value** currentPageIndex_; - unsigned int currentItemIndex_; - }; -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalArray(); - ValueInternalArray(const ValueInternalArray& other); - ValueInternalArray& operator=(ValueInternalArray other); - ~ValueInternalArray(); - void swap(ValueInternalArray& other); - - void clear(); - void resize(ArrayIndex newSize); - - Value& resolveReference(ArrayIndex index); - - Value* find(ArrayIndex index) const; - - ArrayIndex size() const; - - int compare(const ValueInternalArray& other) const; - -private: - static bool equals(const IteratorState& x, const IteratorState& other); - static void increment(IteratorState& iterator); - static void decrement(IteratorState& iterator); - static Value& dereference(const IteratorState& iterator); - static Value& unsafeDereference(const IteratorState& iterator); - static int distance(const IteratorState& x, const IteratorState& y); - static ArrayIndex indexOf(const IteratorState& iterator); - void makeBeginIterator(IteratorState& it) const; - void makeEndIterator(IteratorState& it) const; - void makeIterator(IteratorState& it, ArrayIndex index) const; - - void makeIndexValid(ArrayIndex index); - - Value** pages_; - ArrayIndex size_; - PageIndex pageCount_; -}; - -/** \brief Experimental: do not use. Allocator to customize Value internal -array. - * Below is an example of a simple implementation (actual implementation use - * memory pool). - \code -class DefaultValueArrayAllocator : public ValueArrayAllocator -{ -public: // overridden from ValueArrayAllocator -virtual ~DefaultValueArrayAllocator() -{ -} - -virtual ValueInternalArray *newArray() -{ - return new ValueInternalArray(); -} - -virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) -{ - return new ValueInternalArray( other ); -} - -virtual void destruct( ValueInternalArray *array ) -{ - delete array; -} - -virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex -&indexCount, - ValueInternalArray::PageIndex -minNewIndexCount ) -{ - ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; - if ( minNewIndexCount > newIndexCount ) - newIndexCount = minNewIndexCount; - void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); - if ( !newIndexes ) - throw std::bad_alloc(); - indexCount = newIndexCount; - indexes = static_cast<Value **>( newIndexes ); -} -virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) -{ - if ( indexes ) - free( indexes ); -} - -virtual Value *allocateArrayPage() -{ - return static_cast<Value *>( malloc( sizeof(Value) * -ValueInternalArray::itemsPerPage ) ); -} - -virtual void releaseArrayPage( Value *value ) -{ - if ( value ) - free( value ); -} -}; - \endcode - */ -class JSON_API ValueArrayAllocator { -public: - virtual ~ValueArrayAllocator(); - virtual ValueInternalArray* newArray() = 0; - virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) = 0; - virtual void destructArray(ValueInternalArray* array) = 0; - /** \brief Reallocate array page index. - * Reallocates an array of pointer on each page. - * \param indexes [input] pointer on the current index. May be \c NULL. - * [output] pointer on the new index of at least - * \a minNewIndexCount pages. - * \param indexCount [input] current number of pages in the index. - * [output] number of page the reallocated index can handle. - * \b MUST be >= \a minNewIndexCount. - * \param minNewIndexCount Minimum number of page the new index must be able - * to - * handle. - */ - virtual void - reallocateArrayPageIndex(Value**& indexes, - ValueInternalArray::PageIndex& indexCount, - ValueInternalArray::PageIndex minNewIndexCount) = 0; - virtual void - releaseArrayPageIndex(Value** indexes, - ValueInternalArray::PageIndex indexCount) = 0; - virtual Value* allocateArrayPage() = 0; - virtual void releaseArrayPage(Value* value) = 0; -}; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - /** \brief base class for Value iterators. * */ @@ -914,32 +712,35 @@ public: typedef int difference_type; typedef ValueIteratorBase SelfType; - ValueIteratorBase(); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); -#else - ValueIteratorBase(const ValueInternalArray::IteratorState& state); - ValueIteratorBase(const ValueInternalMap::IteratorState& state); -#endif - bool operator==(const SelfType& other) const { return isEqual(other); } bool operator!=(const SelfType& other) const { return !isEqual(other); } difference_type operator-(const SelfType& other) const { - return computeDistance(other); + return other.computeDistance(*this); } /// Return either the index or the member name of the referenced value as a /// Value. Value key() const; - /// Return the index of the referenced Value. -1 if it is not an arrayValue. + /// Return the index of the referenced Value, or -1 if it is not an arrayValue. UInt index() const; + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + JSONCPP_STRING name() const; + /// Return the member name of the referenced Value. "" if it is not an /// objectValue. - const char* memberName() const; + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; protected: Value& deref() const; @@ -955,17 +756,15 @@ protected: void copy(const SelfType& other); private: -#ifndef JSON_VALUE_USE_INTERNAL_MAP Value::ObjectValues::iterator current_; // Indicates that iterator is for a null value. bool isNull_; -#else - union { - ValueInternalArray::IteratorState array_; - ValueInternalMap::IteratorState map_; - } iterator_; - bool isArray_; -#endif + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); }; /** \brief const iterator for object and array value. @@ -976,23 +775,19 @@ class JSON_API ValueConstIterator : public ValueIteratorBase { public: typedef const Value value_type; - typedef unsigned int size_t; - typedef int difference_type; + //typedef unsigned int size_t; + //typedef int difference_type; typedef const Value& reference; typedef const Value* pointer; typedef ValueConstIterator SelfType; ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); private: /*! \internal Use by Value to create an iterator. */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueConstIterator(const Value::ObjectValues::iterator& current); -#else - ValueConstIterator(const ValueInternalArray::IteratorState& state); - ValueConstIterator(const ValueInternalMap::IteratorState& state); -#endif public: SelfType& operator=(const ValueIteratorBase& other); @@ -1037,18 +832,13 @@ public: typedef ValueIterator SelfType; ValueIterator(); - ValueIterator(const ValueConstIterator& other); + explicit ValueIterator(const ValueConstIterator& other); ValueIterator(const ValueIterator& other); private: /*! \internal Use by Value to create an iterator. */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueIterator(const Value::ObjectValues::iterator& current); -#else - ValueIterator(const ValueInternalArray::IteratorState& state); - ValueIterator(const ValueInternalMap::IteratorState& state); -#endif public: SelfType& operator=(const SelfType& other); @@ -1081,6 +871,15 @@ public: } // namespace Json + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + +#pragma pack(pop) + #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) diff --git a/include/json/version.h b/include/json/version.h index 6fe0682..d953961 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -1,14 +1,20 @@ -// DO NOT EDIT. This file is generated by CMake from "version" -// and "version.h.in" files. +// DO NOT EDIT. This file (and "version") is generated by CMake. // Run CMake configure step to update it. #ifndef JSON_VERSION_H_INCLUDED # define JSON_VERSION_H_INCLUDED -# define JSONCPP_VERSION_STRING "1.0.0" +# define JSONCPP_VERSION_STRING "1.8.2" # define JSONCPP_VERSION_MAJOR 1 -# define JSONCPP_VERSION_MINOR 0 -# define JSONCPP_VERSION_PATCH 0 +# define JSONCPP_VERSION_MINOR 8 +# define JSONCPP_VERSION_PATCH 2 # define JSONCPP_VERSION_QUALIFIER # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + #endif // JSON_VERSION_H_INCLUDED diff --git a/include/json/writer.h b/include/json/writer.h index dc9e46f..f258cbf 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -1,4 +1,4 @@ -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -11,6 +11,7 @@ #endif // if !defined(JSON_IS_AMALGAMATION) #include <vector> #include <string> +#include <ostream> // Disable warning C4251: <data member>: <type> needs to have dll-interface to // be used by... @@ -19,17 +20,131 @@ #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + namespace Json { class Value; +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr<StreamWriter> const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + JSONCPP_OSTREAM* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr<Json::StreamWriter> writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "<anything>" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + /** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) */ -class JSON_API Writer { +class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { public: virtual ~Writer(); - virtual std::string write(const Value& root) = 0; + virtual JSONCPP_STRING write(const Value& root) = 0; }; /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format @@ -39,11 +154,13 @@ public: *consumption, * but may be usefull to support feature such as RPC where bandwith is limited. * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. */ -class JSON_API FastWriter : public Writer { +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter : public Writer { + public: FastWriter(); - virtual ~FastWriter() {} + ~FastWriter() JSONCPP_OVERRIDE {} void enableYAMLCompatibility(); @@ -57,12 +174,12 @@ public: void omitEndingLineFeed(); public: // overridden from Writer - virtual std::string write(const Value& root); + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; private: void writeValue(const Value& value); - std::string document_; + JSONCPP_STRING document_; bool yamlCompatiblityEnabled_; bool dropNullPlaceholders_; bool omitEndingLineFeed_; @@ -90,40 +207,41 @@ private: *#CommentPlacement. * * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. */ -class JSON_API StyledWriter : public Writer { +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledWriter : public Writer { public: StyledWriter(); - virtual ~StyledWriter() {} + ~StyledWriter() JSONCPP_OVERRIDE {} public: // overridden from Writer /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. * \param root Value to serialize. * \return String containing the JSON document that represents the root value. */ - virtual std::string write(const Value& root); + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; private: void writeValue(const Value& value); void writeArrayValue(const Value& value); bool isMultineArray(const Value& value); - void pushValue(const std::string& value); + void pushValue(const JSONCPP_STRING& value); void writeIndent(); - void writeWithIndent(const std::string& value); + void writeWithIndent(const JSONCPP_STRING& value); void indent(); void unindent(); void writeCommentBeforeValue(const Value& root); void writeCommentAfterValueOnSameLine(const Value& root); bool hasCommentForValue(const Value& value); - static std::string normalizeEOL(const std::string& text); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); - typedef std::vector<std::string> ChildValues; + typedef std::vector<JSONCPP_STRING> ChildValues; ChildValues childValues_; - std::string document_; - std::string indentString_; - int rightMargin_; - int indentSize_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; bool addChildValues_; }; @@ -149,12 +267,15 @@ private: * If the Value have comments then they are outputed according to their #CommentPlacement. * - * \param indentation Each level will be indented by this amount extra. * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. */ -class JSON_API StyledStreamWriter { +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledStreamWriter { public: - StyledStreamWriter(std::string indentation = "\t"); +/** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(JSONCPP_STRING indentation = "\t"); ~StyledStreamWriter() {} public: @@ -164,48 +285,51 @@ public: * \note There is no point in deriving from Writer, since write() should not * return a value. */ - void write(std::ostream& out, const Value& root); + void write(JSONCPP_OSTREAM& out, const Value& root); private: void writeValue(const Value& value); void writeArrayValue(const Value& value); bool isMultineArray(const Value& value); - void pushValue(const std::string& value); + void pushValue(const JSONCPP_STRING& value); void writeIndent(); - void writeWithIndent(const std::string& value); + void writeWithIndent(const JSONCPP_STRING& value); void indent(); void unindent(); void writeCommentBeforeValue(const Value& root); void writeCommentAfterValueOnSameLine(const Value& root); bool hasCommentForValue(const Value& value); - static std::string normalizeEOL(const std::string& text); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); - typedef std::vector<std::string> ChildValues; + typedef std::vector<JSONCPP_STRING> ChildValues; ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - bool addChildValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; }; #if defined(JSON_HAS_INT64) -std::string JSON_API valueToString(Int value); -std::string JSON_API valueToString(UInt value); +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); #endif // if defined(JSON_HAS_INT64) -std::string JSON_API valueToString(LargestInt value); -std::string JSON_API valueToString(LargestUInt value); -std::string JSON_API valueToString(double value); -std::string JSON_API valueToString(bool value); -std::string JSON_API valueToQuotedString(const char* value); +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API valueToString(double value); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); /// \brief Output using the StyledStreamWriter. /// \see Json::operator>>() -JSON_API std::ostream& operator<<(std::ostream&, const Value& root); +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); } // namespace Json +#pragma pack(pop) + #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) |