diff --git a/configure.ac b/configure.ac index 78ff83be8..1346482b2 100644 --- a/configure.ac +++ b/configure.ac @@ -282,6 +282,13 @@ if test "$enable_testing" = "yes"; then AC_DEFINE(ENABLE_TESTING,1,[include devel code parts for neutrino tests - not recommended for general users!]) fi +AC_ARG_ENABLE([fribidi], + AS_HELP_STRING([--enable-fribidi], [enable fribidi support]) +) +AM_CONDITIONAL(ENABLE_FRIBIDI, test "$enable_fribidi" = "yes") +AS_IF([test "$enable_fribidi" = "yes"], + AC_DEFINE(ENABLE_FRIBIDI, 1, [enable fribidi support]) +) if test "$BOXTYPE" = "coolstream"; then if test -e ${srcdir}/lib/hardware/coolstream/hd1/libcoolstream/nevis_ir.h; then diff --git a/lib/jsoncpp/include/json/json-forwards.h b/lib/jsoncpp/json/json-forwards.h similarity index 67% rename from lib/jsoncpp/include/json/json-forwards.h rename to lib/jsoncpp/json/json-forwards.h index ccbdb2b13..342438995 100644 --- a/lib/jsoncpp/include/json/json-forwards.h +++ b/lib/jsoncpp/json/json-forwards.h @@ -90,6 +90,9 @@ license you like. #ifndef JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED +#include +#include //typedef String +#include //typedef int64_t, uint64_t /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 @@ -122,12 +125,12 @@ license you like. #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) @@ -141,34 +144,93 @@ license you like. // 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) // 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 defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 -/// Indicates that the following function is deprecated. -#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#elif defined(__clang__) && defined(__has_feature) -#if __has_feature(attribute_deprecated_with_message) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# 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 -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) -#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) + +#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__ +#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; @@ -182,13 +244,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, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#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/lib/jsoncpp/include/json/json.h b/lib/jsoncpp/json/json.h similarity index 81% rename from lib/jsoncpp/include/json/json.h rename to lib/jsoncpp/json/json.h index f9a7948cf..02a31f4a0 100644 --- a/lib/jsoncpp/include/json/json.h +++ b/lib/jsoncpp/json/json.h @@ -68,11 +68,7 @@ license you like. // End of content of file: LICENSE // ////////////////////////////////////////////////////////////////////// -/* own assert() which does not abort... */ -#define assert(x) do { \ - if (x) \ - fprintf(stderr, "JSONCPP:%s:%d assert(%s) failed\n", __func__, __LINE__, #x); \ -} while (0) + @@ -91,13 +87,20 @@ license you like. #ifndef JSON_VERSION_H_INCLUDED # define JSON_VERSION_H_INCLUDED -# define JSONCPP_VERSION_STRING "0.10.5" -# define JSONCPP_VERSION_MAJOR 0 -# define JSONCPP_VERSION_MINOR 10 -# define JSONCPP_VERSION_PATCH 5 +# define JSONCPP_VERSION_STRING "1.8.0" +# define JSONCPP_VERSION_MAJOR 1 +# define JSONCPP_VERSION_MINOR 8 +# define JSONCPP_VERSION_PATCH 0 # 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 // ////////////////////////////////////////////////////////////////////// @@ -120,6 +123,9 @@ license you like. #ifndef JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED +#include +#include //typedef String +#include //typedef int64_t, uint64_t /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 @@ -152,12 +158,12 @@ license you like. #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) @@ -171,34 +177,93 @@ license you like. // 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) // 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 defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 -/// Indicates that the following function is deprecated. -#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#elif defined(__clang__) && defined(__has_feature) -#if __has_feature(attribute_deprecated_with_message) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# 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 -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) -#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) + +#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__ +#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; @@ -212,13 +277,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, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#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 @@ -299,6 +377,8 @@ class ValueConstIterator; #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) +#pragma pack(push, 8) + namespace Json { /** \brief Configuration passed to reader and writer. @@ -333,10 +413,18 @@ public: /// \c true if root must be either an array or an object value. Default: \c /// false. bool strictRoot_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; }; } // namespace Json +#pragma pack(pop) + #endif // CPPTL_JSON_FEATURES_H_INCLUDED // ////////////////////////////////////////////////////////////////////// @@ -376,6 +464,19 @@ public: #include #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: : needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) @@ -383,6 +484,8 @@ public: #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + /** \brief JSON (JavaScript Object Notation). */ namespace Json { @@ -393,11 +496,11 @@ namespace Json { */ class JSON_API Exception : public std::exception { public: - Exception(std::string const& msg); - virtual ~Exception() throw(); - virtual char const* what() const throw(); + Exception(JSONCPP_STRING const& msg); + ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; protected: - std::string const msg_; + JSONCPP_STRING msg_; }; /** Exceptions which the user cannot easily avoid. @@ -408,7 +511,7 @@ protected: */ class JSON_API RuntimeError : public Exception { public: - RuntimeError(std::string const& msg); + RuntimeError(JSONCPP_STRING const& msg); }; /** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. @@ -419,13 +522,13 @@ public: */ class JSON_API LogicError : public Exception { public: - LogicError(std::string const& msg); + LogicError(JSONCPP_STRING const& msg); }; /// used internally -void throwRuntimeError(std::string const& msg); +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); /// used internally -void throwLogicError(std::string const& msg); +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); /** \brief Type of the value held by a Value object. */ @@ -516,7 +619,7 @@ private: class JSON_API Value { friend class ValueIteratorBase; public: - typedef std::vector Members; + typedef std::vector Members; typedef ValueIterator iterator; typedef ValueConstIterator const_iterator; typedef Json::UInt UInt; @@ -529,11 +632,10 @@ public: typedef Json::LargestUInt LargestUInt; typedef Json::ArrayIndex ArrayIndex; - static const Value& nullRef; -#if !defined(__ARMEL__) - /// \deprecated This exists for binary compatibility only. Use nullRef. - static const Value null; -#endif + 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. @@ -569,6 +671,9 @@ private: CZString(ArrayIndex index); 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<(CZString const& other) const; @@ -644,18 +749,22 @@ Json::Value obj_value(Json::objectValue); // {} * \endcode */ Value(const StaticString& value); - Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too. + 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=(const Value &other); + Value& operator=(Value other); /// Swap everything. void swap(Value& other); /// Swap values but leave comments and source offsets in place. @@ -673,7 +782,10 @@ Json::Value obj_value(Json::objectValue); // {} int compare(const Value& other) const; const char* asCString() const; ///< Embedded zeroes could cause you trouble! - std::string asString() const; ///< Embedded zeroes are possible. +#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.) */ @@ -777,11 +889,11 @@ Json::Value obj_value(Json::objectValue); // {} const Value& operator[](const char* key) const; /// Access an object value by name, create a null member if it does not exist. /// \param key may contain embedded nulls. - Value& operator[](const std::string& key); + Value& operator[](const JSONCPP_STRING& key); /// Access an object value by name, returns null if there is no member with /// that name. /// \param key may contain embedded nulls. - const Value& operator[](const std::string& key) const; + const Value& operator[](const JSONCPP_STRING& key) const; /** \brief Access an object value by name, create a null member if it does not exist. @@ -812,7 +924,7 @@ Json::Value obj_value(Json::objectValue); // {} /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy /// \param key may contain embedded nulls. - Value get(const std::string& key, const Value& defaultValue) const; + 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 @@ -837,7 +949,7 @@ Json::Value obj_value(Json::objectValue); // {} /// Same as removeMember(const char*) /// \param key may contain embedded nulls. /// \deprecated - Value removeMember(const std::string& key); + 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); @@ -847,8 +959,8 @@ Json::Value obj_value(Json::objectValue); // {} \param key may contain embedded nulls. \return true iff removed (no exceptions) */ - bool removeMember(std::string const& key, Value* removed); - /// Same as removeMember(std::string const& key, Value* removed) + 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. @@ -863,8 +975,8 @@ Json::Value obj_value(Json::objectValue); // {} bool isMember(const char* key) const; /// Return true if the object has a member named key. /// \param key may contain embedded nulls. - bool isMember(const std::string& key) const; - /// Same as isMember(std::string const& key)const + 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. @@ -884,17 +996,17 @@ Json::Value obj_value(Json::objectValue); // {} //# endif /// \deprecated Always pass len. - JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.") + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") void setComment(const char* comment, CommentPlacement placement); /// Comments must be //... or /* ... */ void setComment(const char* comment, size_t len, CommentPlacement placement); /// Comments must be //... or /* ... */ - void setComment(const std::string& comment, CommentPlacement placement); + 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; @@ -902,6 +1014,13 @@ Json::Value obj_value(Json::objectValue); // {} iterator begin(); iterator end(); + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + 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); @@ -938,6 +1057,11 @@ private: 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. + ptrdiff_t start_; + ptrdiff_t limit_; }; /** \brief Experimental and untested: represents an element of the "path" to @@ -950,7 +1074,7 @@ public: PathArgument(); PathArgument(ArrayIndex index); PathArgument(const char* key); - PathArgument(const std::string& key); + PathArgument(const JSONCPP_STRING& key); private: enum Kind { @@ -958,7 +1082,7 @@ private: kindIndex, kindKey }; - std::string key_; + JSONCPP_STRING key_; ArrayIndex index_; Kind kind_; }; @@ -976,7 +1100,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(), @@ -993,12 +1117,12 @@ private: typedef std::vector InArgs; typedef std::vector 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_; }; @@ -1031,7 +1155,7 @@ public: /// 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. - std::string name() const; + JSONCPP_STRING name() const; /// Return the member name of the referenced Value. "" if it is not an /// objectValue. @@ -1083,6 +1207,7 @@ public: typedef ValueConstIterator SelfType; ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); private: /*! \internal Use by Value to create an iterator. @@ -1132,7 +1257,7 @@ public: typedef ValueIterator SelfType; ValueIterator(); - ValueIterator(const ValueConstIterator& other); + explicit ValueIterator(const ValueConstIterator& other); ValueIterator(const ValueIterator& other); private: @@ -1178,6 +1303,7 @@ 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) @@ -1223,6 +1349,8 @@ inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + namespace Json { /** \brief Unserialize a JSON document into a @@ -1235,6 +1363,18 @@ public: typedef char Char; typedef const Char* Location; + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + /** \brief Constructs a Reader allowing all features * for parsing. */ @@ -1287,7 +1427,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. @@ -1299,7 +1439,7 @@ public: * \deprecated Use getFormattedErrorMessages() instead (typo fix). */ JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") - std::string getFormatedErrorMessages() const; + JSONCPP_STRING getFormatedErrorMessages() const; /** \brief Returns a user friendly string that list errors in the parsed * document. @@ -1309,7 +1449,39 @@ 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 + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \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 JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \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 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 + * errors have occurred. + */ + bool good() const; private: enum TokenType { @@ -1339,7 +1511,7 @@ private: class ErrorInfo { public: Token token_; - std::string message_; + JSONCPP_STRING message_; Location extra_; }; @@ -1359,7 +1531,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, @@ -1370,9 +1542,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(); @@ -1380,20 +1552,20 @@ 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); typedef std::stack 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 @@ -1422,9 +1594,9 @@ public: */ virtual bool parse( char const* beginDoc, char const* endDoc, - Value* root, std::string* errs) = 0; + Value* root, JSONCPP_STRING* errs) = 0; - class Factory { + class JSON_API Factory { public: virtual ~Factory() {} /** \brief Allocate a CharReader via operator new(). @@ -1442,7 +1614,7 @@ Usage: CharReaderBuilder builder; builder["collectComments"] = false; Value value; - std::string errs; + JSONCPP_STRING errs; bool ok = parseFromStream(builder, std::cin, &value, &errs); \endcode */ @@ -1477,6 +1649,9 @@ public: 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 @@ -1486,9 +1661,9 @@ public: Json::Value settings_; CharReaderBuilder(); - virtual ~CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; - virtual CharReader* newCharReader() const; + CharReader* newCharReader() const JSONCPP_OVERRIDE; /** \return true if 'settings' are legal and consistent; * otherwise, indicate bad settings via 'invalid'. @@ -1497,7 +1672,7 @@ public: /** A simple way to update a specific setting. */ - Value& operator[](std::string key); + Value& operator[](JSONCPP_STRING key); /** Called by ctor, but you can use this to reset settings_. * \pre 'settings' != NULL (but Json::null is fine) @@ -1519,7 +1694,7 @@ public: */ bool JSON_API parseFromStream( CharReader::Factory const&, - std::istream&, + JSONCPP_ISTREAM&, Value* root, std::string* errs); /** \brief Read from 'sin' into 'root'. @@ -1546,10 +1721,12 @@ bool JSON_API parseFromStream( \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) @@ -1591,6 +1768,8 @@ JSON_API std::istream& operator>>(std::istream&, Value&); #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + namespace Json { class Value; @@ -1610,7 +1789,7 @@ Usage: */ class JSON_API StreamWriter { protected: - std::ostream* sout_; // not owned; will not delete + JSONCPP_OSTREAM* sout_; // not owned; will not delete public: StreamWriter(); virtual ~StreamWriter(); @@ -1620,7 +1799,7 @@ public: \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, std::ostream* sout) = 0; + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; /** \brief A simple abstract factory. */ @@ -1637,7 +1816,7 @@ public: /** \brief Write into stringstream, then return string, for convenience. * A StreamWriter will be created from the factory, used, and then deleted. */ -std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); /** \brief Build a StreamWriter implementation. @@ -1670,6 +1849,10 @@ public: 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 @@ -1679,12 +1862,12 @@ public: Json::Value settings_; StreamWriterBuilder(); - virtual ~StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; /** * \throw std::exception if something goes wrong (e.g. invalid settings) */ - virtual StreamWriter* newStreamWriter() const; + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; /** \return true if 'settings' are legal and consistent; * otherwise, indicate bad settings via 'invalid'. @@ -1692,7 +1875,7 @@ public: bool validate(Json::Value* invalid) const; /** A simple way to update a specific setting. */ - Value& operator[](std::string key); + Value& operator[](JSONCPP_STRING key); /** Called by ctor, but you can use this to reset settings_. * \pre 'settings' != NULL (but Json::null is fine) @@ -1709,7 +1892,7 @@ class 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 JSON format @@ -1725,18 +1908,29 @@ class JSON_API FastWriter : public Writer { public: FastWriter(); - virtual ~FastWriter() {} + ~FastWriter() JSONCPP_OVERRIDE {} void enableYAMLCompatibility(); + /** \brief 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. + */ + void dropNullPlaceholders(); + + 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_; }; /** \brief Writes a Value in JSON format in a @@ -1766,36 +1960,36 @@ private: class JSON_API StyledWriter : public Writer { public: StyledWriter(); - virtual ~StyledWriter() {} + ~StyledWriter() JSONCPP_OVERRIDE {} public: // overridden from Writer /** \brief Serialize a Value in JSON 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 ChildValues; + typedef std::vector 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_; }; @@ -1827,7 +2021,7 @@ private: */ class JSON_API StyledStreamWriter { public: - StyledStreamWriter(std::string indentation = "\t"); + StyledStreamWriter(JSONCPP_STRING indentation = "\t"); ~StyledStreamWriter() {} public: @@ -1837,49 +2031,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 ChildValues; + typedef std::vector ChildValues; ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; + 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) @@ -1926,7 +2122,7 @@ JSON_API std::ostream& operator<<(std::ostream&, const Value& root); # define JSON_FAIL_MESSAGE(message) \ { \ - std::ostringstream oss; oss << message; \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ Json::throwLogicError(oss.str()); \ abort(); \ } @@ -1939,7 +2135,7 @@ JSON_API std::ostream& operator<<(std::ostream&, const Value& root); // release builds we abort, for a core-dump or debugger. # define JSON_FAIL_MESSAGE(message) \ { \ - std::ostringstream oss; oss << message; \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ assert(false && oss.str().c_str()); \ abort(); \ } diff --git a/lib/jsoncpp/jsoncpp.cpp b/lib/jsoncpp/jsoncpp.cpp index 5c2825a2e..7634ed4f3 100644 --- a/lib/jsoncpp/jsoncpp.cpp +++ b/lib/jsoncpp/jsoncpp.cpp @@ -92,6 +92,16 @@ license you like. #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include +#endif + /* This header provides common string manipulation support, such as UTF-8, * portable conversion from/to string... * @@ -99,10 +109,18 @@ license you like. */ namespace Json { +static char getDecimalPoint() { +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} /// Converts a unicode code-point to UTF-8. -static inline std::string codePointToUTF8(unsigned int cp) { - std::string result; +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; // based on description from http://en.wikipedia.org/wiki/UTF-8 @@ -149,7 +167,7 @@ typedef char UIntToStringBuffer[uintToStringBufferSize]; static inline void uintToString(LargestUInt value, char*& current) { *--current = 0; do { - *--current = static_cast(value % 10U + static_cast('0')); + *--current = static_cast(value % 10U + static_cast('0')); value /= 10; } while (value != 0); } @@ -168,6 +186,18 @@ static inline void fixNumericLocale(char* begin, char* end) { } } +static inline void fixNumericLocaleInput(char* begin, char* end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint != '\0' && decimalPoint != '.') { + while (begin < end) { + if (*begin == '.') { + *begin = decimalPoint; + } + ++begin; + } + } +} + } // namespace Json { #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED @@ -186,6 +216,7 @@ static inline void fixNumericLocale(char* begin, char* end) { // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2011 Baptiste Lepilleur +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. // 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 @@ -198,28 +229,49 @@ static inline void fixNumericLocale(char* begin, char* end) { #endif // if !defined(JSON_IS_AMALGAMATION) #include #include -//#include +#include #include #include #include #include #include +#include -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else #define snprintf _snprintf #endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif -static int const stackLimit_g = 1000; -static int stackDepth_g = 0; // see readValue() +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit +#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) +#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#endif + +static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() namespace Json { -#if __cplusplus >= 201103L +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef std::unique_ptr CharReaderPtr; #else typedef std::auto_ptr CharReaderPtr; @@ -229,14 +281,17 @@ typedef std::auto_ptr CharReaderPtr; // //////////////////////////////// Features::Features() - : allowComments_(true), strictRoot_(false) -{} + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + Features Features::all() { return Features(); } Features Features::strictMode() { Features features; features.allowComments_ = false; features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; return features; } @@ -265,7 +320,8 @@ Reader::Reader(const Features& features) bool Reader::parse(const std::string& document, Value& root, bool collectComments) { - document_ = document; + JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity()); + std::swap(documentCopy, document_); const char* begin = document_.c_str(); const char* end = begin + document_.length(); return parse(begin, end, root, collectComments); @@ -277,11 +333,11 @@ bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { // Those would allow streamed input from a file, if parse() were a // template function. - // Since std::string is reference-counted, this at least does not + // Since JSONCPP_STRING is reference-counted, this at least does not // create an extra copy. - std::string doc; + JSONCPP_STRING doc; std::getline(sin, doc, (char)EOF); - return parse(doc, root, collectComments); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); } bool Reader::parse(const char* beginDoc, @@ -304,7 +360,6 @@ bool Reader::parse(const char* beginDoc, nodes_.pop(); nodes_.push(&root); - stackDepth_g = 0; // Yes, this is bad coding, but options are limited. bool successful = readValue(); Token token; skipCommentTokens(token); @@ -327,12 +382,10 @@ bool Reader::parse(const char* beginDoc, } bool Reader::readValue() { - // This is a non-reentrant way to support a stackLimit. Terrible! - // But this deprecated class has a security problem: Bad input can - // cause a seg-fault. This seems like a fair, binary-compatible way - // to prevent the problem. - if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_g; + // readValue() may call itself only if it calls readObject() or ReadArray(). + // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). + // parse() executes one nodes_.push(), so > instead of >=. + if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); @@ -346,9 +399,11 @@ bool Reader::readValue() { switch (token.type_) { case tokenObjectBegin: successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); break; case tokenArrayBegin: successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); break; case tokenNumber: successful = decodeNumber(token); @@ -360,22 +415,42 @@ bool Reader::readValue() { { Value v(true); currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenFalse: { Value v(false); currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenNull: { Value v; currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); } break; - // Else, fall through... + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return addError("Syntax error: value, object or array expected.", token); } @@ -384,7 +459,6 @@ bool Reader::readValue() { lastValue_ = ¤tValue(); } - --stackDepth_g; return successful; } @@ -513,9 +587,9 @@ bool Reader::readComment() { return true; } -static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { - std::string normalized; - normalized.reserve(end - begin); +static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); Reader::Location current = begin; while (current != end) { char c = *current++; @@ -535,7 +609,7 @@ static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { void Reader::addComment(Location begin, Location end, CommentPlacement placement) { assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { assert(lastValue_ != 0); lastValue_->setComment(normalized, placement); @@ -545,7 +619,7 @@ Reader::addComment(Location begin, Location end, CommentPlacement placement) { } bool Reader::readCStyleComment() { - while (current_ != end_) { + while ((current_ + 1) < end_) { Char c = getNextChar(); if (c == '*' && *current_ == '/') break; @@ -574,25 +648,25 @@ void Reader::readNumber() { char c = '0'; // stopgap for already consumed character // integral part while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; // fractional part if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } // exponential part if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } } bool Reader::readString() { - Char c = 0; + Char c = '\0'; while (current_ != end_) { c = getNextChar(); if (c == '\\') @@ -603,11 +677,12 @@ bool Reader::readString() { return c == '"'; } -bool Reader::readObject(Token& /*tokenStart*/) { +bool Reader::readObject(Token& tokenStart) { Token tokenName; - std::string name; + JSONCPP_STRING name; Value init(objectValue); currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); while (readToken(tokenName)) { bool initialTokenOk = true; while (tokenName.type_ == tokenComment && initialTokenOk) @@ -620,6 +695,11 @@ bool Reader::readObject(Token& /*tokenStart*/) { if (tokenName.type_ == tokenString) { if (!decodeString(tokenName, name)) return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = JSONCPP_STRING(numberName.asCString()); } else { break; } @@ -653,11 +733,12 @@ bool Reader::readObject(Token& /*tokenStart*/) { "Missing '}' or object member name", tokenName, tokenObjectEnd); } -bool Reader::readArray(Token& /*tokenStart*/) { +bool Reader::readArray(Token& tokenStart) { Value init(arrayValue); currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); skipSpaces(); - if (*current_ == ']') // empty array + if (current_ != end_ && *current_ == ']') // empty array { Token endArray; readToken(endArray); @@ -695,6 +776,8 @@ bool Reader::decodeNumber(Token& token) { if (!decodeNumber(token, decoded)) return false; currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -708,7 +791,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { ++current; // TODO: Help the compiler do the div and mod at compile time or get rid of them. Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(-Value::minLargestInt) + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 : Value::maxLargestUInt; Value::LargestUInt threshold = maxIntegerValue / 10; Value::LargestUInt value = 0; @@ -716,7 +799,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { Char c = *current++; if (c < '0' || c > '9') return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); + Value::UInt digit(static_cast(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, b) this is the last digit, and @@ -729,7 +812,9 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { } value = value * 10 + digit; } - if (isNegative) + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) decoded = -Value::LargestInt(value); else if (value <= Value::LargestUInt(Value::maxInt)) decoded = Value::LargestInt(value); @@ -743,15 +828,17 @@ bool Reader::decodeDouble(Token& token) { if (!decodeDouble(token, decoded)) return false; currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return true; } bool Reader::decodeDouble(Token& token, Value& decoded) { double value = 0; - std::string buffer(token.start_, token.end_); - std::istringstream is(buffer); + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); if (!(is >> value)) - return addError("'" + std::string(token.start_, token.end_) + + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + "' is not a number.", token); decoded = value; @@ -759,16 +846,18 @@ bool Reader::decodeDouble(Token& token, Value& decoded) { } bool Reader::decodeString(Token& token) { - std::string decoded_string; + JSONCPP_STRING decoded_string; if (!decodeString(token, decoded_string)) return false; Value decoded(decoded_string); currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return true; } -bool Reader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while (current != end) { @@ -852,13 +941,13 @@ bool Reader::decodeUnicodeCodePoint(Token& token, bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, - unsigned int& unicode) { + unsigned int& ret_unicode) { if (end - current < 4) return addError( "Bad unicode escape sequence in string: four digits expected.", token, current); - unicode = 0; + int unicode = 0; for (int index = 0; index < 4; ++index) { Char c = *current++; unicode *= 16; @@ -874,11 +963,12 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token, token, current); } + ret_unicode = static_cast(unicode); return true; } bool -Reader::addError(const std::string& message, Token& token, Location extra) { +Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -888,7 +978,7 @@ Reader::addError(const std::string& message, Token& token, Location extra) { } bool Reader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); + size_t const errorCount = errors_.size(); Token skip; for (;;) { if (!readToken(skip)) @@ -900,7 +990,7 @@ bool Reader::recoverFromError(TokenType skipUntilToken) { return false; } -bool Reader::addErrorAndRecover(const std::string& message, +bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, Token& token, TokenType skipUntilToken) { addError(message, token); @@ -938,29 +1028,21 @@ void Reader::getLocationLineAndColumn(Location location, ++line; } -std::string Reader::getLocationLineAndColumn(Location location) const { +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); char buffer[18 + 16 + 16 + 1]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) -#if defined(WINCE) - _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#else - sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif -#else snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif return buffer; } // Deprecated. Preserved for backward compatibility -std::string Reader::getFormatedErrorMessages() const { +JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFormattedErrorMessages(); } -std::string Reader::getFormattedErrorMessages() const { - std::string formattedMessage; +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { @@ -975,14 +1057,64 @@ std::string Reader::getFormattedErrorMessages() const { return formattedMessage; } -// Reader -///////////////////////// +std::vector Reader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { + return !errors_.size(); +} // exact copy of Features class OurFeatures { public: static OurFeatures all(); - OurFeatures(); bool allowComments_; bool strictRoot_; bool allowDroppedNullPlaceholders_; @@ -990,20 +1122,13 @@ public: bool allowSingleQuotes_; bool failIfExtra_; bool rejectDupKeys_; + bool allowSpecialFloats_; int stackLimit_; }; // OurFeatures // exact copy of Implementation of class Features // //////////////////////////////// -OurFeatures::OurFeatures() - : allowComments_(true), strictRoot_(false) - , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) - , allowSingleQuotes_(false) - , failIfExtra_(false) -{ -} - OurFeatures OurFeatures::all() { return OurFeatures(); } // Implementation of class Reader @@ -1015,9 +1140,9 @@ public: typedef char Char; typedef const Char* Location; struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; }; OurReader(OurFeatures const& features); @@ -1025,7 +1150,11 @@ public: const char* endDoc, Value& root, bool collectComments = true); - std::string getFormattedErrorMessages() const; + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + bool good() const; private: OurReader(OurReader const&); // no impl @@ -1042,6 +1171,9 @@ private: tokenTrue, tokenFalse, tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, tokenArraySeparator, tokenMemberSeparator, tokenComment, @@ -1058,7 +1190,7 @@ private: class ErrorInfo { public: Token token_; - std::string message_; + JSONCPP_STRING message_; Location extra_; }; @@ -1072,14 +1204,14 @@ private: bool readCppStyleComment(); bool readString(); bool readStringSingleQuote(); - void readNumber(); + bool readNumber(bool checkInf); bool readValue(); bool readObject(Token& token); bool readArray(Token& token); 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, @@ -1090,9 +1222,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(); @@ -1100,21 +1232,20 @@ 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); typedef std::stack Nodes; Nodes nodes_; Errors errors_; - std::string document_; + JSONCPP_STRING document_; Location begin_; Location end_; Location current_; Location lastValueEnd_; Value* lastValue_; - std::string commentsBefore_; - int stackDepth_; + JSONCPP_STRING commentsBefore_; OurFeatures const features_; bool collectComments_; @@ -1124,7 +1255,8 @@ private: OurReader::OurReader(OurFeatures const& features) : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { + lastValue_(), commentsBefore_(), + features_(features), collectComments_() { } bool OurReader::parse(const char* beginDoc, @@ -1147,12 +1279,11 @@ bool OurReader::parse(const char* beginDoc, nodes_.pop(); nodes_.push(&root); - stackDepth_ = 0; bool successful = readValue(); Token token; skipCommentTokens(token); if (features_.failIfExtra_) { - if (token.type_ != tokenError && token.type_ != tokenEndOfStream) { + if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) { addError("Extra non-whitespace after JSON value.", token); return false; } @@ -1176,8 +1307,8 @@ bool OurReader::parse(const char* beginDoc, } bool OurReader::readValue() { - if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_; + // To preserve the old behaviour we cast size_t to int. + if (static_cast(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); bool successful = true; @@ -1190,9 +1321,11 @@ bool OurReader::readValue() { switch (token.type_) { case tokenObjectBegin: successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); break; case tokenArrayBegin: successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); break; case tokenNumber: successful = decodeNumber(token); @@ -1204,18 +1337,48 @@ bool OurReader::readValue() { { Value v(true); currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenFalse: { Value v(false); currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenNull: { Value v; currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenArraySeparator: @@ -1227,9 +1390,13 @@ bool OurReader::readValue() { current_--; Value v; currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); break; } // else, fall through ... default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return addError("Syntax error: value, object or array expected.", token); } @@ -1238,7 +1405,6 @@ bool OurReader::readValue() { lastValue_ = ¤tValue(); } - --stackDepth_; return successful; } @@ -1294,9 +1460,16 @@ bool OurReader::readToken(Token& token) { case '7': case '8': case '9': - case '-': token.type_ = tokenNumber; - readNumber(); + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } break; case 't': token.type_ = tokenTrue; @@ -1310,6 +1483,22 @@ bool OurReader::readToken(Token& token) { token.type_ = tokenNull; ok = match("ull", 3); break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; case ',': token.type_ = tokenArraySeparator; break; @@ -1376,7 +1565,7 @@ bool OurReader::readComment() { void OurReader::addComment(Location begin, Location end, CommentPlacement placement) { assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { assert(lastValue_ != 0); lastValue_->setComment(normalized, placement); @@ -1386,7 +1575,7 @@ OurReader::addComment(Location begin, Location end, CommentPlacement placement) } bool OurReader::readCStyleComment() { - while (current_ != end_) { + while ((current_ + 1) < end_) { Char c = getNextChar(); if (c == '*' && *current_ == '/') break; @@ -1410,26 +1599,31 @@ bool OurReader::readCppStyleComment() { return true; } -void OurReader::readNumber() { +bool OurReader::readNumber(bool checkInf) { const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } char c = '0'; // stopgap for already consumed character // integral part while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; // fractional part if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } // exponential part if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } + return true; } bool OurReader::readString() { Char c = 0; @@ -1456,11 +1650,12 @@ bool OurReader::readStringSingleQuote() { return c == '\''; } -bool OurReader::readObject(Token& /*tokenStart*/) { +bool OurReader::readObject(Token& tokenStart) { Token tokenName; - std::string name; + JSONCPP_STRING name; Value init(objectValue); currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); while (readToken(tokenName)) { bool initialTokenOk = true; while (tokenName.type_ == tokenComment && initialTokenOk) @@ -1489,7 +1684,7 @@ bool OurReader::readObject(Token& /*tokenStart*/) { } if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - std::string msg = "Duplicate key: '" + name + "'"; + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; return addErrorAndRecover( msg, tokenName, tokenObjectEnd); } @@ -1517,11 +1712,12 @@ bool OurReader::readObject(Token& /*tokenStart*/) { "Missing '}' or object member name", tokenName, tokenObjectEnd); } -bool OurReader::readArray(Token& /*tokenStart*/) { +bool OurReader::readArray(Token& tokenStart) { Value init(arrayValue); currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); skipSpaces(); - if (*current_ == ']') // empty array + if (current_ != end_ && *current_ == ']') // empty array { Token endArray; readToken(endArray); @@ -1559,6 +1755,8 @@ bool OurReader::decodeNumber(Token& token) { if (!decodeNumber(token, decoded)) return false; currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -1580,7 +1778,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { Char c = *current++; if (c < '0' || c > '9') return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); + Value::UInt digit(static_cast(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, b) this is the last digit, and @@ -1607,6 +1805,8 @@ bool OurReader::decodeDouble(Token& token) { if (!decodeDouble(token, decoded)) return false; currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -1614,12 +1814,13 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { double value = 0; const int bufferSize = 32; int count; - int length = int(token.end_ - token.start_); + ptrdiff_t const length = token.end_ - token.start_; // Sanity check to avoid buffer overflow exploits. if (length < 0) { return addError("Unable to parse token length", token); } + size_t const ulength = static_cast(length); // Avoid using a string constant for the format control string given to // sscanf, as this can cause hard to debug crashes on OS X. See here for more @@ -1630,16 +1831,17 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { if (length <= bufferSize) { Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, length); + memcpy(buffer, token.start_, ulength); buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); count = sscanf(buffer, format, &value); } else { - std::string buffer(token.start_, token.end_); + JSONCPP_STRING buffer(token.start_, token.end_); count = sscanf(buffer.c_str(), format, &value); } if (count != 1) - return addError("'" + std::string(token.start_, token.end_) + + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + "' is not a number.", token); decoded = value; @@ -1647,16 +1849,18 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { } bool OurReader::decodeString(Token& token) { - std::string decoded_string; + JSONCPP_STRING decoded_string; if (!decodeString(token, decoded_string)) return false; Value decoded(decoded_string); currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); return true; } -bool OurReader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while (current != end) { @@ -1740,13 +1944,13 @@ bool OurReader::decodeUnicodeCodePoint(Token& token, bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, - unsigned int& unicode) { + unsigned int& ret_unicode) { if (end - current < 4) return addError( "Bad unicode escape sequence in string: four digits expected.", token, current); - unicode = 0; + int unicode = 0; for (int index = 0; index < 4; ++index) { Char c = *current++; unicode *= 16; @@ -1762,11 +1966,12 @@ bool OurReader::decodeUnicodeEscapeSequence(Token& token, token, current); } + ret_unicode = static_cast(unicode); return true; } bool -OurReader::addError(const std::string& message, Token& token, Location extra) { +OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -1776,7 +1981,7 @@ OurReader::addError(const std::string& message, Token& token, Location extra) { } bool OurReader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); + size_t errorCount = errors_.size(); Token skip; for (;;) { if (!readToken(skip)) @@ -1788,7 +1993,7 @@ bool OurReader::recoverFromError(TokenType skipUntilToken) { return false; } -bool OurReader::addErrorAndRecover(const std::string& message, +bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, Token& token, TokenType skipUntilToken) { addError(message, token); @@ -1826,24 +2031,16 @@ void OurReader::getLocationLineAndColumn(Location location, ++line; } -std::string OurReader::getLocationLineAndColumn(Location location) const { +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); char buffer[18 + 16 + 16 + 1]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) -#if defined(WINCE) - _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#else - sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif -#else snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif return buffer; } -std::string OurReader::getFormattedErrorMessages() const { - std::string formattedMessage; +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { @@ -1858,6 +2055,60 @@ std::string OurReader::getFormattedErrorMessages() const { return formattedMessage; } +std::vector OurReader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { + return !errors_.size(); +} + class OurCharReader : public CharReader { bool const collectComments_; @@ -1869,9 +2120,9 @@ public: : collectComments_(collectComments) , reader_(features) {} - virtual bool parse( + bool parse( char const* beginDoc, char const* endDoc, - Value* root, std::string* errs) { + Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); if (errs) { *errs = reader_.getFormattedErrorMessages(); @@ -1898,9 +2149,10 @@ CharReader* CharReaderBuilder::newCharReader() const features.stackLimit_ = settings_["stackLimit"].asInt(); features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); return new OurCharReader(collectComments, features); } -static void getValidReaderKeys(std::set* valid_keys) +static void getValidReaderKeys(std::set* valid_keys) { valid_keys->clear(); valid_keys->insert("collectComments"); @@ -1912,25 +2164,26 @@ static void getValidReaderKeys(std::set* valid_keys) valid_keys->insert("stackLimit"); valid_keys->insert("failIfExtra"); valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); } bool CharReaderBuilder::validate(Json::Value* invalid) const { Json::Value my_invalid; if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL Json::Value& inv = *invalid; - std::set valid_keys; + std::set valid_keys; getValidReaderKeys(&valid_keys); Value::Members keys = settings_.getMemberNames(); size_t n = keys.size(); for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; + JSONCPP_STRING const& key = keys[i]; if (valid_keys.find(key) == valid_keys.end()) { inv[key] = settings_[key]; } } return 0u == inv.size(); } -Value& CharReaderBuilder::operator[](std::string key) +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; } @@ -1943,8 +2196,10 @@ void CharReaderBuilder::strictMode(Json::Value* settings) (*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowNumericKeys"] = false; (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; //! [CharReaderBuilderStrictMode] } // static @@ -1960,6 +2215,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) (*settings)["stackLimit"] = 1000; (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; //! [CharReaderBuilderDefaults] } @@ -1967,12 +2223,12 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) // global functions bool parseFromStream( - CharReader::Factory const& fact, std::istream& sin, - Value* root, std::string* errs) + CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, + Value* root, JSONCPP_STRING* errs) { - std::ostringstream ssin; + JSONCPP_OSTRINGSTREAM ssin; ssin << sin.rdbuf(); - std::string doc = ssin.str(); + JSONCPP_STRING doc = ssin.str(); char const* begin = doc.data(); char const* end = begin + doc.size(); // Note that we do not actually need a null-terminator. @@ -1980,16 +2236,16 @@ bool parseFromStream( return reader->parse(begin, end, root, errs); } -std::istream& operator>>(std::istream& sin, Value& root) { +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { CharReaderBuilder b; - std::string errs; + JSONCPP_STRING errs; bool ok = parseFromStream(b, sin, &root, &errs); if (!ok) { fprintf(stderr, "Error from reader: %s", errs.c_str()); - throwRuntimeError("reader error"); + throwRuntimeError(errs); } return sin; } @@ -2103,12 +2359,12 @@ UInt ValueIteratorBase::index() const { return Value::UInt(-1); } -std::string ValueIteratorBase::name() const { +JSONCPP_STRING ValueIteratorBase::name() const { char const* keey; char const* end; keey = memberName(&end); - if (!keey) return std::string(); - return std::string(keey, end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); } char const* ValueIteratorBase::memberName() const { @@ -2140,6 +2396,9 @@ ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator& current) : ValueIteratorBase(current) {} +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + ValueConstIterator& ValueConstIterator:: operator=(const ValueIteratorBase& other) { copy(other); @@ -2160,7 +2419,9 @@ ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) : ValueIteratorBase(current) {} ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) {} + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} ValueIterator::ValueIterator(const ValueIterator& other) : ValueIteratorBase(other) {} @@ -2199,7 +2460,7 @@ ValueIterator& ValueIterator::operator=(const SelfType& other) { #include #include #include -//#include +#include #ifdef JSON_USE_CPPTL #include #endif @@ -2216,13 +2477,24 @@ namespace Json { #if defined(__ARMEL__) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #else -// This exists for binary compatibility only. Use nullRef. -const Value Value::null; #define ALIGNAS(byte_alignment) #endif -static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; -const unsigned char& kNullRef = kNull[0]; -const Value& Value::nullRef = reinterpret_cast(kNullRef); +//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +//const unsigned char& kNullRef = kNull[0]; +//const Value& Value::null = reinterpret_cast(kNullRef); +//const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() +{ + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but DO NOT +// use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); @@ -2243,11 +2515,14 @@ const LargestUInt Value::maxLargestUInt = LargestUInt(-1); #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + //return d >= static_cast(min) && d <= static_cast(max); return d >= min && d <= max; } #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); + return static_cast(Int64(value / 2)) * 2.0 + static_cast(Int64(value & 1)); } template static inline double integerToDouble(T value) { @@ -2268,10 +2543,11 @@ static inline bool InRange(double d, T min, U max) { * @return Pointer on the duplicate instance of string. */ static inline char* duplicateStringValue(const char* value, - size_t length) { + size_t length) +{ // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. - if (length >= (size_t)Value::maxInt) + if (length >= static_cast(Value::maxInt)) length = Value::maxInt - 1; char* newString = static_cast(malloc(length + 1)); @@ -2293,7 +2569,7 @@ static inline char* duplicateAndPrefixStringValue( { // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. - JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U, + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - sizeof(unsigned) - 1U, "in Json::Value::duplicateAndPrefixStringValue(): " "length too big for prefixing"); unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; @@ -2322,7 +2598,29 @@ inline static void decodePrefixedString( } /** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). */ -static inline void releaseStringValue(char* value) { free(value); } +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length==0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + free(value); +} +static inline void releaseStringValue(char* value, unsigned) { + free(value); +} +#endif // JSONCPP_USING_SECURE_MEMORY } // namespace Json @@ -2340,26 +2638,26 @@ static inline void releaseStringValue(char* value) { free(value); } namespace Json { -Exception::Exception(std::string const& msg) +Exception::Exception(JSONCPP_STRING const& msg) : msg_(msg) {} -Exception::~Exception() throw() +Exception::~Exception() JSONCPP_NOEXCEPT {} -char const* Exception::what() const throw() +char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } -RuntimeError::RuntimeError(std::string const& msg) +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) : Exception(msg) {} -LogicError::LogicError(std::string const& msg) +LogicError::LogicError(JSONCPP_STRING const& msg) : Exception(msg) {} -void throwRuntimeError(std::string const& msg) +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { throw RuntimeError(msg); } -void throwLogicError(std::string const& msg) +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { throw LogicError(msg); } @@ -2372,16 +2670,17 @@ void throwLogicError(std::string const& msg) // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -Value::CommentInfo::CommentInfo() : comment_(0) {} +Value::CommentInfo::CommentInfo() : comment_(0) +{} Value::CommentInfo::~CommentInfo() { if (comment_) - releaseStringValue(comment_); + releaseStringValue(comment_, 0u); } void Value::CommentInfo::setComment(const char* text, size_t len) { if (comment_) { - releaseStringValue(comment_); + releaseStringValue(comment_, 0u); comment_ = 0; } JSON_ASSERT(text != 0); @@ -2406,28 +2705,34 @@ void Value::CommentInfo::setComment(const char* text, size_t len) { Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) - : cstr_(str) -{ + : cstr_(str) { // allocate != duplicate storage_.policy_ = allocate & 0x3; storage_.length_ = ulength & 0x3FFFFFFF; } -Value::CZString::CZString(const CZString& other) - : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_) -{ - storage_.policy_ = (other.cstr_ +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = static_cast(other.cstr_ ? (static_cast(other.storage_.policy_) == noDuplication ? noDuplication : duplicate) - : static_cast(other.storage_.policy_)); + : static_cast(other.storage_.policy_)) & 3U; storage_.length_ = other.storage_.length_; } +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) - releaseStringValue(const_cast(cstr_)); + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + } } void Value::CZString::swap(CZString& other) { @@ -2446,7 +2751,8 @@ bool Value::CZString::operator<(const CZString& other) const { // Assume both are strings. unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; - unsigned min_len = std::min(this_len, other_len); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); int comp = memcmp(this->cstr_, other.cstr_, min_len); if (comp < 0) return true; if (comp > 0) return false; @@ -2460,6 +2766,7 @@ bool Value::CZString::operator==(const CZString& other) const { unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; if (this_len != other_len) return false; + JSON_ASSERT(this->cstr_ && other.cstr_); int comp = memcmp(this->cstr_, other.cstr_, this_len); return comp == 0; } @@ -2484,6 +2791,7 @@ bool Value::CZString::isStaticString() const { return storage_.policy_ == noDupl * This optimization is used in ValueInternalMap fast allocator. */ Value::Value(ValueType vtype) { + static char const emptyString[] = ""; initBasic(vtype); switch (vtype) { case nullValue: @@ -2496,7 +2804,8 @@ Value::Value(ValueType vtype) { value_.real_ = 0.0; break; case stringValue: - value_.string_ = 0; + // allocated_ == false, so this is safe. + value_.string_ = const_cast(static_cast(emptyString)); break; case arrayValue: case objectValue: @@ -2537,6 +2846,7 @@ Value::Value(double value) { Value::Value(const char* value) { initBasic(stringValue, true); + JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); } @@ -2546,7 +2856,7 @@ Value::Value(const char* beginValue, const char* endValue) { duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); } -Value::Value(const std::string& value) { +Value::Value(const JSONCPP_STRING& value) { initBasic(stringValue, true); value_.string_ = duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); @@ -2572,7 +2882,7 @@ Value::Value(bool value) { Value::Value(Value const& other) : type_(other.type_), allocated_(false) , - comments_(0) + comments_(0), start_(other.start_), limit_(other.limit_) { switch (type_) { case nullValue: @@ -2613,6 +2923,14 @@ Value::Value(Value const& other) } } +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + Value::~Value() { switch (type_) { case nullValue: @@ -2623,7 +2941,7 @@ Value::~Value() { break; case stringValue: if (allocated_) - releaseStringValue(value_.string_); + releasePrefixedStringValue(value_.string_); break; case arrayValue: case objectValue: @@ -2633,13 +2951,13 @@ Value::~Value() { JSON_ASSERT_UNREACHABLE; } - if (comments_) - delete[] comments_; + delete[] comments_; + + value_.uint_ = 0; } -Value &Value::operator=(const Value &other) { - Value temp(other); - swap(temp); +Value& Value::operator=(Value other) { + swap(other); return *this; } @@ -2656,6 +2974,8 @@ void Value::swapPayload(Value& other) { void Value::swap(Value& other) { swapPayload(other); std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); } ValueType Value::type() const { return type_; } @@ -2695,7 +3015,8 @@ bool Value::operator<(const Value& other) const { char const* other_str; decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - unsigned min_len = std::min(this_len, other_len); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); int comp = memcmp(this_str, other_str, min_len); if (comp < 0) return true; if (comp > 0) return false; @@ -2751,6 +3072,7 @@ bool Value::operator==(const Value& other) const { decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); if (this_len != other_len) return false; + JSON_ASSERT(this_str && other_str); int comp = memcmp(this_str, other_str, this_len); return comp == 0; } @@ -2776,6 +3098,18 @@ const char* Value::asCString() const { return this_str; } +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_len; +} +#endif + bool Value::getString(char const** str, char const** cend) const { if (type_ != stringValue) return false; if (value_.string_ == 0) return false; @@ -2785,7 +3119,7 @@ bool Value::getString(char const** str, char const** cend) const { return true; } -std::string Value::asString() const { +JSONCPP_STRING Value::asString() const { switch (type_) { case nullValue: return ""; @@ -2795,7 +3129,7 @@ std::string Value::asString() const { unsigned this_len; char const* this_str; decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return std::string(this_str, this_len); + return JSONCPP_STRING(this_str, this_len); } case booleanValue: return value_.bool_ ? "true" : "false"; @@ -2955,7 +3289,8 @@ float Value::asFloat() const { #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(value_.uint_); #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast(integerToDouble(value_.uint_)); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return static_cast(value_.real_); @@ -3058,6 +3393,8 @@ void Value::clear() { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || type_ == objectValue, "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; switch (type_) { case arrayValue: case objectValue: @@ -3082,7 +3419,7 @@ void Value::resize(ArrayIndex newSize) { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); } - assert(size() == newSize); + JSON_ASSERT(size() == newSize); } } @@ -3097,7 +3434,7 @@ Value& Value::operator[](ArrayIndex index) { if (it != value_.map_->end() && (*it).first == key) return (*it).second; - ObjectValues::value_type defaultValue(key, nullRef); + ObjectValues::value_type defaultValue(key, nullSingleton()); it = value_.map_->insert(it, defaultValue); return (*it).second; } @@ -3114,11 +3451,11 @@ const Value& Value::operator[](ArrayIndex index) const { type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); if (type_ == nullValue) - return nullRef; + return nullSingleton(); CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); if (it == value_.map_->end()) - return nullRef; + return nullSingleton(); return (*it).second; } @@ -3133,6 +3470,8 @@ void Value::initBasic(ValueType vtype, bool allocated) { type_ = vtype; allocated_ = allocated; comments_ = 0; + start_ = 0; + limit_ = 0; } // Access an object value by name, create a null member if it does not exist. @@ -3150,7 +3489,7 @@ Value& Value::resolveReference(const char* key) { if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; - ObjectValues::value_type defaultValue(actualKey, nullRef); + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; @@ -3170,7 +3509,7 @@ Value& Value::resolveReference(char const* key, char const* cend) if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; - ObjectValues::value_type defaultValue(actualKey, nullRef); + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; @@ -3178,7 +3517,7 @@ Value& Value::resolveReference(char const* key, char const* cend) Value Value::get(ArrayIndex index, const Value& defaultValue) const { const Value* value = &((*this)[index]); - return value == &nullRef ? defaultValue : *value; + return value == &nullSingleton() ? defaultValue : *value; } bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } @@ -3197,13 +3536,13 @@ Value const* Value::find(char const* key, char const* cend) const const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); - if (!found) return nullRef; + if (!found) return nullSingleton(); return *found; } -Value const& Value::operator[](std::string const& key) const +Value const& Value::operator[](JSONCPP_STRING const& key) const { Value const* found = find(key.data(), key.data() + key.length()); - if (!found) return nullRef; + if (!found) return nullSingleton(); return *found; } @@ -3211,7 +3550,7 @@ Value& Value::operator[](const char* key) { return resolveReference(key, key + strlen(key)); } -Value& Value::operator[](const std::string& key) { +Value& Value::operator[](const JSONCPP_STRING& key) { return resolveReference(key.data(), key.data() + key.length()); } @@ -3226,7 +3565,7 @@ Value& Value::operator[](const CppTL::ConstString& key) { Value const& Value::operator[](CppTL::ConstString const& key) const { Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullRef; + if (!found) return nullSingleton(); return *found; } #endif @@ -3242,7 +3581,7 @@ Value Value::get(char const* key, Value const& defaultValue) const { return get(key, key + strlen(key), defaultValue); } -Value Value::get(std::string const& key, Value const& defaultValue) const +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const { return get(key.data(), key.data() + key.length(), defaultValue); } @@ -3265,7 +3604,7 @@ bool Value::removeMember(const char* key, Value* removed) { return removeMember(key, key + strlen(key), removed); } -bool Value::removeMember(std::string const& key, Value* removed) +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } @@ -3274,13 +3613,13 @@ Value Value::removeMember(const char* key) JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) - return nullRef; + return nullSingleton(); Value removed; // null removeMember(key, key + strlen(key), &removed); return removed; // still null if removeMember() did nothing } -Value Value::removeMember(const std::string& key) +Value Value::removeMember(const JSONCPP_STRING& key) { return removeMember(key.c_str()); } @@ -3324,7 +3663,7 @@ bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); } -bool Value::isMember(std::string const& key) const +bool Value::isMember(JSONCPP_STRING const& key) const { return isMember(key.data(), key.data() + key.length()); } @@ -3346,7 +3685,7 @@ Value::Members Value::getMemberNames() const { ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); for (; it != itEnd; ++it) { - members.push_back(std::string((*it).first.data(), + members.push_back(JSONCPP_STRING((*it).first.data(), (*it).first.length())); } return members; @@ -3389,7 +3728,11 @@ bool Value::isBool() const { return type_ == booleanValue; } bool Value::isInt() const { switch (type_) { case intValue: +#if defined(JSON_HAS_INT64) return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif case uintValue: return value_.uint_ <= UInt(maxInt); case realValue: @@ -3404,9 +3747,17 @@ bool Value::isInt() const { bool Value::isUInt() const { switch (type_) { case intValue: +#if defined(JSON_HAS_INT64) return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif case uintValue: +#if defined(JSON_HAS_INT64) return value_.uint_ <= maxUInt; +#else + return true; +#endif case realValue: return value_.real_ >= 0 && value_.real_ <= maxUInt && IsIntegral(value_.real_); @@ -3464,9 +3815,9 @@ bool Value::isIntegral() const { #endif } -bool Value::isDouble() const { return type_ == realValue || isIntegral(); } +bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; } -bool Value::isNumeric() const { return isIntegral() || isDouble(); } +bool Value::isNumeric() const { return isDouble(); } bool Value::isString() const { return type_ == stringValue; } @@ -3488,7 +3839,7 @@ void Value::setComment(const char* comment, CommentPlacement placement) { setComment(comment, strlen(comment), placement); } -void Value::setComment(const std::string& comment, CommentPlacement placement) { +void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { setComment(comment.c_str(), comment.length(), placement); } @@ -3496,13 +3847,21 @@ bool Value::hasComment(CommentPlacement placement) const { return comments_ != 0 && comments_[placement].comment_ != 0; } -std::string Value::getComment(CommentPlacement placement) const { +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { if (hasComment(placement)) return comments_[placement].comment_; return ""; } -std::string Value::toStyledString() const { +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +JSONCPP_STRING Value::toStyledString() const { StyledWriter writer; return writer.write(*this); } @@ -3570,13 +3929,13 @@ PathArgument::PathArgument(ArrayIndex index) PathArgument::PathArgument(const char* key) : key_(key), index_(), kind_(kindKey) {} -PathArgument::PathArgument(const std::string& key) +PathArgument::PathArgument(const JSONCPP_STRING& key) : key_(key.c_str()), index_(), kind_(kindKey) {} // class Path // ////////////////////////////////////////////////////////////////// -Path::Path(const std::string& path, +Path::Path(const JSONCPP_STRING& path, const PathArgument& a1, const PathArgument& a2, const PathArgument& a3, @@ -3591,7 +3950,7 @@ Path::Path(const std::string& path, makePath(path, in); } -void Path::makePath(const std::string& path, const InArgs& in) { +void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { const char* current = path.c_str(); const char* end = current + path.length(); InArgs::const_iterator itInArg = in.begin(); @@ -3606,23 +3965,23 @@ void Path::makePath(const std::string& path, const InArgs& in) { index = index * 10 + ArrayIndex(*current - '0'); args_.push_back(index); } - if (current == end || *current++ != ']') + if (current == end || *++current != ']') invalidPath(path, int(current - path.c_str())); } else if (*current == '%') { addPathInArg(path, in, itInArg, PathArgument::kindKey); ++current; - } else if (*current == '.') { + } else if (*current == '.' || *current == ']') { ++current; } else { const char* beginName = current; while (current != end && !strchr("[.", *current)) ++current; - args_.push_back(std::string(beginName, current)); + args_.push_back(JSONCPP_STRING(beginName, current)); } } } -void Path::addPathInArg(const std::string& /*path*/, +void Path::addPathInArg(const JSONCPP_STRING& /*path*/, const InArgs& in, InArgs::const_iterator& itInArg, PathArgument::Kind kind) { @@ -3631,11 +3990,11 @@ void Path::addPathInArg(const std::string& /*path*/, } else if ((*itInArg)->kind_ != kind) { // Error: bad argument type } else { - args_.push_back(**itInArg); + args_.push_back(**itInArg++); } } -void Path::invalidPath(const std::string& /*path*/, int /*location*/) { +void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { // Error: invalid path. } @@ -3646,16 +4005,19 @@ const Value& Path::resolve(const Value& root) const { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) { // Error: unable to resolve path (array value expected at position... + return Value::null; } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: unable to resolve path (object value expected at position...) + return Value::null; } node = &((*node)[arg.key_]); - if (node == &Value::nullRef) { + if (node == &Value::nullSingleton()) { // Error: unable to resolve path (object has no member named '' at // position...) + return Value::null; } } } @@ -3674,7 +4036,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const { if (!node->isObject()) return defaultValue; node = &((*node)[arg.key_]); - if (node == &Value::nullRef) + if (node == &Value::nullSingleton()) return defaultValue; } } @@ -3729,7 +4091,7 @@ Value& Path::make(Value& root) const { #include #include #include -//#include +#include #include #include @@ -3737,20 +4099,47 @@ Value& Path::make(Value& root) const { #include #define isfinite _finite #elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) #include #define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include +#define isfinite finite +#endif +#endif #else #include +#if !(defined(__QNXNTO__)) // QNX already defines isfinite #define isfinite std::isfinite #endif +#endif -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else #define snprintf _snprintf -#elif defined(__ANDROID__) +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) #define snprintf snprintf #elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) #define snprintf std::snprintf #endif +#endif #if defined(__BORLANDC__) #include @@ -3765,7 +4154,7 @@ Value& Path::make(Value& root) const { namespace Json { -#if __cplusplus >= 201103L +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef std::unique_ptr StreamWriterPtr; #else typedef std::auto_ptr StreamWriterPtr; @@ -3789,20 +4178,23 @@ static bool containsControlCharacter0(const char* str, unsigned len) { return false; } -std::string valueToString(LargestInt value) { +JSONCPP_STRING valueToString(LargestInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); - bool isNegative = value < 0; - if (isNegative) - value = -value; - uintToString(LargestUInt(value), current); - if (isNegative) + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } assert(current >= buffer); return current; } -std::string valueToString(LargestUInt value) { +JSONCPP_STRING valueToString(LargestUInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); uintToString(value, current); @@ -3812,68 +4204,71 @@ std::string valueToString(LargestUInt value) { #if defined(JSON_HAS_INT64) -std::string valueToString(Int value) { +JSONCPP_STRING valueToString(Int value) { return valueToString(LargestInt(value)); } -std::string valueToString(UInt value) { +JSONCPP_STRING valueToString(UInt value) { return valueToString(LargestUInt(value)); } #endif // # if defined(JSON_HAS_INT64) -std::string valueToString(double value) { +namespace { +JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { // Allocate a buffer that is more than large enough to store the 16 digits of // precision requested below. - char buffer[32]; + char buffer[36]; int len = -1; -// Print into the buffer. We need not request the alternative representation -// that always has a decimal point because JSON doesn't distingish the -// concepts of reals and integers. -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with - // visual studio 2005 to - // avoid warning. -#if defined(WINCE) - len = _snprintf(buffer, sizeof(buffer), "%.17g", value); -#else - len = sprintf_s(buffer, sizeof(buffer), "%.17g", value); -#endif -#else + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), "%.17g", value); + len = snprintf(buffer, sizeof(buffer), formatString, value); + + // try to ensure we preserve the fact that this was given to us as a double on input + if (!strstr(buffer, ".") && !strstr(buffer, "e")) { + strcat(buffer, ".0"); + } + } else { // IEEE standard states that NaN values will not compare to themselves if (value != value) { - len = snprintf(buffer, sizeof(buffer), "null"); + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); } else if (value < 0) { - len = snprintf(buffer, sizeof(buffer), "-1e+9999"); + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); } else { - len = snprintf(buffer, sizeof(buffer), "1e+9999"); + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); } // For those, we do not need to call fixNumLoc, but it is fast. } -#endif assert(len >= 0); fixNumericLocale(buffer, buffer + len); return buffer; } +} -std::string valueToString(bool value) { return value ? "true" : "false"; } +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } -std::string valueToQuotedString(const char* value) { +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +JSONCPP_STRING valueToQuotedString(const char* value) { if (value == NULL) return ""; // Not sure how to handle unicode... if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter(value)) - return std::string("\"") + value + "\""; + return JSONCPP_STRING("\"") + value + "\""; // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = + JSONCPP_STRING::size_type maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL - std::string result; + JSONCPP_STRING result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; for (const char* c = value; *c != 0; ++c) { @@ -3909,7 +4304,7 @@ std::string valueToQuotedString(const char* value) { // sequence from occurring. default: if (isControlCharacter(*c)) { - std::ostringstream oss; + JSONCPP_OSTRINGSTREAM oss; oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast(*c); result += oss.str(); @@ -3938,19 +4333,19 @@ static char const* strnpbrk(char const* s, char const* accept, size_t n) { } return NULL; } -static std::string valueToQuotedStringN(const char* value, unsigned length) { +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { if (value == NULL) return ""; // Not sure how to handle unicode... if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && !containsControlCharacter0(value, length)) - return std::string("\"") + value + "\""; + return JSONCPP_STRING("\"") + value + "\""; // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = + JSONCPP_STRING::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL - std::string result; + JSONCPP_STRING result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; char const* end = value + length; @@ -3987,7 +4382,7 @@ static std::string valueToQuotedStringN(const char* value, unsigned length) { // sequence from occurring. default: if ((isControlCharacter(*c)) || (*c == 0)) { - std::ostringstream oss; + JSONCPP_OSTRINGSTREAM oss; oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast(*c); result += oss.str(); @@ -4009,21 +4404,28 @@ Writer::~Writer() {} // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false) {} + : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } -std::string FastWriter::write(const Value& root) { +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { document_ = ""; writeValue(root); - document_ += "\n"; + if (!omitEndingLineFeed_) + document_ += "\n"; return document_; } void FastWriter::writeValue(const Value& value) { switch (value.type()) { case nullValue: - document_ += "null"; + if (!dropNullPlaceholders_) + document_ += "null"; break; case intValue: document_ += valueToString(value.asLargestInt()); @@ -4036,7 +4438,7 @@ void FastWriter::writeValue(const Value& value) { break; case stringValue: { - // Is NULL possible for value.string_? + // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); @@ -4048,8 +4450,8 @@ void FastWriter::writeValue(const Value& value) { break; case arrayValue: { document_ += '['; - int size = value.size(); - for (int index = 0; index < size; ++index) { + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { if (index > 0) document_ += ','; writeValue(value[index]); @@ -4061,7 +4463,7 @@ void FastWriter::writeValue(const Value& value) { document_ += '{'; for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) { - const std::string& name = *it; + const JSONCPP_STRING& name = *it; if (it != members.begin()) document_ += ','; document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); @@ -4079,7 +4481,7 @@ void FastWriter::writeValue(const Value& value) { StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3), addChildValues_() {} -std::string StyledWriter::write(const Value& root) { +JSONCPP_STRING StyledWriter::write(const Value& root) { document_ = ""; addChildValues_ = false; indentString_ = ""; @@ -4106,7 +4508,7 @@ void StyledWriter::writeValue(const Value& value) { break; case stringValue: { - // Is NULL possible for value.string_? + // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); @@ -4129,7 +4531,7 @@ void StyledWriter::writeValue(const Value& value) { indent(); Value::Members::iterator it = members.begin(); for (;;) { - const std::string& name = *it; + const JSONCPP_STRING& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); @@ -4193,26 +4595,25 @@ void StyledWriter::writeArrayValue(const Value& value) { } bool StyledWriter::isMultineArray(const Value& value) { - int size = value.size(); + ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && + isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { if (hasCommentForValue(value[index])) { isMultiLine = true; } writeValue(value[index]); - lineLength += int(childValues_[index].length()); + lineLength += static_cast(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4220,7 +4621,7 @@ bool StyledWriter::isMultineArray(const Value& value) { return isMultiLine; } -void StyledWriter::pushValue(const std::string& value) { +void StyledWriter::pushValue(const JSONCPP_STRING& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4238,15 +4639,15 @@ void StyledWriter::writeIndent() { document_ += indentString_; } -void StyledWriter::writeWithIndent(const std::string& value) { +void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { writeIndent(); document_ += value; } -void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } +void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } void StyledWriter::unindent() { - assert(int(indentString_.size()) >= indentSize_); + assert(indentString_.size() >= indentSize_); indentString_.resize(indentString_.size() - indentSize_); } @@ -4256,8 +4657,8 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) { document_ += "\n"; writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { document_ += *iter; if (*iter == '\n' && @@ -4290,11 +4691,11 @@ bool StyledWriter::hasCommentForValue(const Value& value) { // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// -StyledStreamWriter::StyledStreamWriter(std::string indentation) +StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) : document_(NULL), rightMargin_(74), indentation_(indentation), addChildValues_() {} -void StyledStreamWriter::write(std::ostream& out, const Value& root) { +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { document_ = &out; addChildValues_ = false; indentString_ = ""; @@ -4324,7 +4725,7 @@ void StyledStreamWriter::writeValue(const Value& value) { break; case stringValue: { - // Is NULL possible for value.string_? + // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); @@ -4347,7 +4748,7 @@ void StyledStreamWriter::writeValue(const Value& value) { indent(); Value::Members::iterator it = members.begin(); for (;;) { - const std::string& name = *it; + const JSONCPP_STRING& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); @@ -4413,26 +4814,25 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { } bool StyledStreamWriter::isMultineArray(const Value& value) { - int size = value.size(); + ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && + isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { if (hasCommentForValue(value[index])) { isMultiLine = true; } writeValue(value[index]); - lineLength += int(childValues_[index].length()); + lineLength += static_cast(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4440,7 +4840,7 @@ bool StyledStreamWriter::isMultineArray(const Value& value) { return isMultiLine; } -void StyledStreamWriter::pushValue(const std::string& value) { +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4455,7 +4855,7 @@ void StyledStreamWriter::writeIndent() { *document_ << '\n' << indentString_; } -void StyledStreamWriter::writeWithIndent(const std::string& value) { +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { if (!indented_) writeIndent(); *document_ << value; indented_ = false; @@ -4473,8 +4873,8 @@ void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { return; if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { *document_ << *iter; if (*iter == '\n' && @@ -4519,44 +4919,50 @@ struct CommentStyle { struct BuiltStyledStreamWriter : public StreamWriter { BuiltStyledStreamWriter( - std::string const& indentation, + JSONCPP_STRING const& indentation, CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol); - virtual int write(Value const& root, std::ostream* sout); + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; private: void writeValue(Value const& value); void writeArrayValue(Value const& value); bool isMultineArray(Value const& value); - void pushValue(std::string const& value); + void pushValue(JSONCPP_STRING const& value); void writeIndent(); - void writeWithIndent(std::string const& value); + void writeWithIndent(JSONCPP_STRING const& value); void indent(); void unindent(); void writeCommentBeforeValue(Value const& root); void writeCommentAfterValueOnSameLine(Value const& root); static bool hasCommentForValue(const Value& value); - typedef std::vector ChildValues; + typedef std::vector ChildValues; ChildValues childValues_; - std::string indentString_; - int rightMargin_; - std::string indentation_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; CommentStyle::Enum cs_; - std::string colonSymbol_; - std::string nullSymbol_; - std::string endingLineFeedSymbol_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; bool addChildValues_ : 1; bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; }; BuiltStyledStreamWriter::BuiltStyledStreamWriter( - std::string const& indentation, + JSONCPP_STRING const& indentation, CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol) + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) : rightMargin_(74) , indentation_(indentation) , cs_(cs) @@ -4565,9 +4971,11 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter( , endingLineFeedSymbol_(endingLineFeedSymbol) , addChildValues_(false) , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) { } -int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) { sout_ = sout; addChildValues_ = false; @@ -4594,11 +5002,11 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { pushValue(valueToString(value.asLargestUInt())); break; case realValue: - pushValue(valueToString(value.asDouble())); + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); break; case stringValue: { - // Is NULL is possible for value.string_? + // Is NULL is possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); @@ -4621,7 +5029,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { indent(); Value::Members::iterator it = members.begin(); for (;;) { - std::string const& name = *it; + JSONCPP_STRING const& name = *it; Value const& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedStringN(name.data(), static_cast(name.length()))); @@ -4679,7 +5087,7 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { if (!indentation_.empty()) *sout_ << " "; for (unsigned index = 0; index < size; ++index) { if (index > 0) - *sout_ << ", "; + *sout_ << ((!indentation_.empty()) ? ", " : ","); *sout_ << childValues_[index]; } if (!indentation_.empty()) *sout_ << " "; @@ -4689,26 +5097,25 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { } bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { - int size = value.size(); + ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { Value const& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && + isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { if (hasCommentForValue(value[index])) { isMultiLine = true; } writeValue(value[index]); - lineLength += int(childValues_[index].length()); + lineLength += static_cast(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4716,7 +5123,7 @@ bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { return isMultiLine; } -void BuiltStyledStreamWriter::pushValue(std::string const& value) { +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4735,7 +5142,7 @@ void BuiltStyledStreamWriter::writeIndent() { } } -void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { if (!indented_) writeIndent(); *sout_ << value; indented_ = false; @@ -4754,8 +5161,8 @@ void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { return; if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { *sout_ << *iter; if (*iter == '\n' && @@ -4805,10 +5212,12 @@ StreamWriterBuilder::~StreamWriterBuilder() {} StreamWriter* StreamWriterBuilder::newStreamWriter() const { - std::string indentation = settings_["indentation"].asString(); - std::string cs_str = settings_["commentStyle"].asString(); + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); bool eyc = settings_["enableYAMLCompatibility"].asBool(); bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); CommentStyle::Enum cs = CommentStyle::All; if (cs_str == "All") { cs = CommentStyle::All; @@ -4817,47 +5226,50 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const } else { throwRuntimeError("commentStyle must be 'All' or 'None'"); } - std::string colonSymbol = " : "; + JSONCPP_STRING colonSymbol = " : "; if (eyc) { colonSymbol = ": "; } else if (indentation.empty()) { colonSymbol = ":"; } - std::string nullSymbol = "null"; + JSONCPP_STRING nullSymbol = "null"; if (dnp) { nullSymbol = ""; } - std::string endingLineFeedSymbol = ""; + if (pre > 17) pre = 17; + JSONCPP_STRING endingLineFeedSymbol = ""; return new BuiltStyledStreamWriter( indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol); + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); } -static void getValidWriterKeys(std::set* valid_keys) +static void getValidWriterKeys(std::set* valid_keys) { valid_keys->clear(); valid_keys->insert("indentation"); valid_keys->insert("commentStyle"); valid_keys->insert("enableYAMLCompatibility"); valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); } bool StreamWriterBuilder::validate(Json::Value* invalid) const { Json::Value my_invalid; if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL Json::Value& inv = *invalid; - std::set valid_keys; + std::set valid_keys; getValidWriterKeys(&valid_keys); Value::Members keys = settings_.getMemberNames(); size_t n = keys.size(); for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; + JSONCPP_STRING const& key = keys[i]; if (valid_keys.find(key) == valid_keys.end()) { inv[key] = settings_[key]; } } return 0u == inv.size(); } -Value& StreamWriterBuilder::operator[](std::string key) +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; } @@ -4869,17 +5281,19 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings) (*settings)["indentation"] = "\t"; (*settings)["enableYAMLCompatibility"] = false; (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; //! [StreamWriterBuilderDefaults] } -std::string writeString(StreamWriter::Factory const& builder, Value const& root) { - std::ostringstream sout; +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { + JSONCPP_OSTRINGSTREAM sout; StreamWriterPtr const writer(builder.newStreamWriter()); writer->write(root, &sout); return sout.str(); } -std::ostream& operator<<(std::ostream& sout, Value const& root) { +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { StreamWriterBuilder builder; StreamWriterPtr const writer(builder.newStreamWriter()); writer->write(root, &sout); diff --git a/src/Makefile.am b/src/Makefile.am index 7deb76623..9f3ff1363 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -132,6 +132,11 @@ neutrino_LDADD += -lgif else neutrino_LDADD += -lungif endif + +if ENABLE_FRIBIDI +neutrino_LDADD += -lfribidi +endif + if ENABLE_LUA neutrino_LDADD += @LUA_LIBS@ endif diff --git a/src/driver/fontrenderer.cpp b/src/driver/fontrenderer.cpp index bf36f897a..3f212842c 100644 --- a/src/driver/fontrenderer.cpp +++ b/src/driver/fontrenderer.cpp @@ -39,6 +39,10 @@ #include #include +#ifdef ENABLE_FRIBIDI +#include +#endif + FT_Error FBFontRenderClass::myFTC_Face_Requester(FTC_FaceID face_id, FT_Library /*library*/, FT_Pointer request_data, @@ -388,6 +392,49 @@ int UTF8ToUnicode(const char * &text, const bool utf8_encoded) // returns -1 on return unicode_value; } +#ifdef ENABLE_FRIBIDI +static std::string fribidi_shape_char(const char * text) +{ + if(text && *text) + { + int len = strlen(text); + char * rtl_text = NULL; + int rtl_len = 0; + + fribidi_set_mirroring(true); + fribidi_set_reorder_nsm(false); + + // init to utf-8 + FriBidiCharSet fribidi_charset = FRIBIDI_CHAR_SET_UTF8; + + // tell bidi that we need bidirectional + FriBidiCharType fribidi_chartype = FRIBIDI_TYPE_L; + + // our buffer + FriBidiChar *logical = (FriBidiChar *)alloca(sizeof(FriBidiChar)*(len + 1)); + FriBidiChar *visual = (FriBidiChar *)alloca(sizeof(FriBidiChar)*(len + 1)); + + // convert from the selected charset to Unicode + rtl_len = fribidi_charset_to_unicode(fribidi_charset, const_cast(text), len, logical); + //printf("len: %d rtl_len: %d\n", len, rtl_len); + + // logical to visual + if (fribidi_log2vis(logical, rtl_len, &fribidi_chartype, visual, NULL, NULL, NULL)) + { + // removes bidirectional marks + fribidi_remove_bidi_marks(visual, rtl_len, NULL, NULL, NULL); + + rtl_text = (char *)alloca(sizeof(char)*(rtl_len * 4 + 1)); + fribidi_unicode_to_charset(fribidi_charset, visual, rtl_len, rtl_text); + + return std::string(rtl_text); + } + } + + return std::string(text); +} +#endif + void Font::paintFontPixel(fb_pixel_t *td, uint8_t src) { #define DST_BLUE 0x80 @@ -448,6 +495,11 @@ void Font::RenderString(int x, int y, const int width, const char *text, const f pthread_mutex_lock( &renderer->render_mutex ); +#ifdef ENABLE_FRIBIDI + std::string Text = fribidi_shape_char(text); + text = Text.c_str(); +#endif + FT_Error err = FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size); if (err != 0) { @@ -640,6 +692,11 @@ int Font::getRenderWidth(const char *text, const bool utf8_encoded) { pthread_mutex_lock( &renderer->render_mutex ); +#ifdef ENABLE_FRIBIDI + std::string Text = fribidi_shape_char(text); + text = Text.c_str(); +#endif + FT_Error err = FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size); if (err != 0) { diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 13193de4f..cabaf9297 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -32,7 +32,7 @@ AM_CPPFLAGS += \ -I$(top_srcdir)/lib/connection \ -I$(top_srcdir)/lib/xmltree \ -I$(top_srcdir)/lib/libupnpclient \ - -I$(top_srcdir)/lib/jsoncpp/include \ + -I$(top_srcdir)/lib/jsoncpp \ @SIGC_CFLAGS@ \ @CURL_CFLAGS@ \ @FREETYPE_CFLAGS@ \ diff --git a/src/gui/lua/Makefile.am b/src/gui/lua/Makefile.am index 05a3b91a8..2e8165ce1 100644 --- a/src/gui/lua/Makefile.am +++ b/src/gui/lua/Makefile.am @@ -12,7 +12,7 @@ AM_CPPFLAGS += \ -I$(top_srcdir)/lib/connection \ -I$(top_srcdir)/lib/xmltree \ -I$(top_srcdir)/lib/libupnpclient \ - -I$(top_srcdir)/lib/jsoncpp/include \ + -I$(top_srcdir)/lib/jsoncpp \ @SIGC_CFLAGS@ \ @CURL_CFLAGS@ \ @FREETYPE_CFLAGS@ \ @@ -37,6 +37,7 @@ libneutrino_gui_lua_a_SOURCES = \ lua_menue.cpp \ lua_messagebox.cpp \ lua_misc.cpp \ + lua_progresswindow.cpp \ lua_stringinput.cpp \ lua_threads.cpp \ lua_threads_copy.cpp \ diff --git a/src/gui/lua/lua_api_version.h b/src/gui/lua/lua_api_version.h index 55b19f4e0..9e8343ca1 100644 --- a/src/gui/lua/lua_api_version.h +++ b/src/gui/lua/lua_api_version.h @@ -4,4 +4,4 @@ * to luainstance.h changes */ #define LUA_API_VERSION_MAJOR 1 -#define LUA_API_VERSION_MINOR 70 +#define LUA_API_VERSION_MINOR 72 diff --git a/src/gui/lua/lua_cc_window.cpp b/src/gui/lua/lua_cc_window.cpp index 2225797bc..819fe18d2 100644 --- a/src/gui/lua/lua_cc_window.cpp +++ b/src/gui/lua/lua_cc_window.cpp @@ -220,7 +220,10 @@ int CLuaInstCCWindow::CCWindowSetCaption(lua_State *L) std::string name = ""; tableLookup(L, "name", name) || tableLookup(L, "title", name) || tableLookup(L, "caption", name); - D->w->setWindowCaption(name); + lua_Integer alignment = (lua_Integer)CTextBox::NO_AUTO_LINEBREAK; + tableLookup(L, "alignment", alignment); + + D->w->setWindowCaption(name, alignment | (lua_Integer)CTextBox::NO_AUTO_LINEBREAK); return 0; } diff --git a/src/gui/lua/lua_progresswindow.cpp b/src/gui/lua/lua_progresswindow.cpp new file mode 100644 index 000000000..c6bc45d01 --- /dev/null +++ b/src/gui/lua/lua_progresswindow.cpp @@ -0,0 +1,175 @@ +/* + * lua progress window + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "luainstance.h" +#include "lua_progresswindow.h" + +CLuaInstProgressWindow* CLuaInstProgressWindow::getInstance() +{ + static CLuaInstProgressWindow* LuaInstProgressWindow = NULL; + + if(!LuaInstProgressWindow) + LuaInstProgressWindow = new CLuaInstProgressWindow(); + return LuaInstProgressWindow; +} + +void CLuaInstProgressWindow::ProgressWindowRegister(lua_State *L) +{ + luaL_Reg meth[] = { + { "new", CLuaInstProgressWindow::CProgressWindowNew }, + { "paint", CLuaInstProgressWindow::CProgressWindowPaint }, + { "hide", CLuaInstProgressWindow::CProgressWindowHide }, + { "showStatus", CLuaInstProgressWindow::CProgressWindowShowLocalStatus}, + { "showLocalStatus", CLuaInstProgressWindow::CProgressWindowShowLocalStatus}, + { "showGlobalStatus",CLuaInstProgressWindow::CProgressWindowShowGlobalStatus }, + { "setTitle", CLuaInstProgressWindow::CProgressWindowSetTitle}, + { "__gc", CLuaInstProgressWindow::CProgressWindowDelete }, + { NULL, NULL } + }; + + luaL_newmetatable(L, "cprogresswindow"); + luaL_setfuncs(L, meth, 0); + lua_pushvalue(L, -1); + lua_setfield(L, -1, "__index"); + lua_setglobal(L, "cprogresswindow"); +} + + +int CLuaInstProgressWindow::CProgressWindowNew(lua_State *L) +{ + lua_assert(lua_istable(L,1)); + + std::string name = ""; + tableLookup(L, "name", name) || tableLookup(L, "title", name) || tableLookup(L, "caption", name); + + CLuaCProgressWindow **udata = (CLuaCProgressWindow **) lua_newuserdata(L, sizeof(CLuaCProgressWindow *)); + *udata = new CLuaCProgressWindow(); + +#if 0 + /* Enable when pu/fb-setmode branch is merged in master */ + (*udata)->w = new CProgressWindow(name); +#else + (*udata)->w = new CProgressWindow(); + (*udata)->w->setTitle(name); +#endif + + luaL_getmetatable(L, "cprogresswindow"); + lua_setmetatable(L, -2); + return 1; +} + +CLuaCProgressWindow *CLuaInstProgressWindow::CProgressWindowCheck(lua_State *L, int n) +{ + return *(CLuaCProgressWindow **) luaL_checkudata(L, n, "cprogresswindow"); +} + +int CLuaInstProgressWindow::CProgressWindowPaint(lua_State *L) +{ + lua_assert(lua_istable(L,1)); + CLuaCProgressWindow *D = CProgressWindowCheck(L, 1); + if (!D) return 0; + + bool do_save_bg = true; + if (!tableLookup(L, "do_save_bg", do_save_bg)) { + std::string tmp = "true"; + if (tableLookup(L, "do_save_bg", tmp)) + paramBoolDeprecated(L, tmp.c_str()); + do_save_bg = (tmp == "true" || tmp == "1" || tmp == "yes"); + } + D->w->paint(do_save_bg); + return 0; +} + +int CLuaInstProgressWindow::CProgressWindowHide(lua_State *L) +{ + lua_assert(lua_istable(L,1)); + CLuaCProgressWindow *D = CProgressWindowCheck(L, 1); + if (!D) return 0; + + bool tmp1 = false; + std::string tmp2 = "false"; + if ((tableLookup(L, "no_restore", tmp1)) || (tableLookup(L, "no_restore", tmp2))) + obsoleteHideParameter(L); + + D->w->hide(); + return 0; +} + +int CLuaInstProgressWindow::CProgressWindowSetTitle(lua_State *L) +{ + lua_assert(lua_istable(L,1)); + CLuaCProgressWindow *D = CProgressWindowCheck(L, 1); + if (!D) return 0; + + std::string name = ""; + tableLookup(L, "name", name) || tableLookup(L, "title", name) || tableLookup(L, "caption", name); + + D->w->setTitle(name); + return 0; +} + +int CLuaInstProgressWindow::CProgressWindowShowStatusInternal(lua_State *L, bool local) +{ + lua_assert(lua_istable(L,1)); + CLuaCProgressWindow *D = CProgressWindowCheck(L, 1); + if (!D) return 0; + + lua_Unsigned prog; + std::string statusText = std::string(); + lua_Integer max = 100 ; + + tableLookup(L, "prog", prog); + tableLookup(L, "statusText", statusText); + tableLookup(L, "max", max); + + if (local) + D->w->showLocalStatus(prog, max, statusText); + else + D->w->showGlobalStatus(prog, max, statusText); + + return 0; +} + +int CLuaInstProgressWindow::CProgressWindowShowLocalStatus(lua_State *L) +{ + return CProgressWindowShowStatusInternal(L, true); +} + +int CLuaInstProgressWindow::CProgressWindowShowGlobalStatus(lua_State *L) +{ + return CProgressWindowShowStatusInternal(L, false); +} + +int CLuaInstProgressWindow::CProgressWindowDelete(lua_State *L) +{ + LUA_DEBUG("CLuaInstProgressWindow::%s %d\n", __func__, lua_gettop(L)); + CLuaCProgressWindow *D = CProgressWindowCheck(L, 1); + if (!D) return 0; + delete D; + return 0; +} diff --git a/src/gui/lua/lua_progresswindow.h b/src/gui/lua/lua_progresswindow.h new file mode 100644 index 000000000..f1701a97e --- /dev/null +++ b/src/gui/lua/lua_progresswindow.h @@ -0,0 +1,49 @@ +/* + * lua progress window + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _LUAPROGRESSWINDOW_H_ +#define _LUAPROGRESSWINDOW_H_ + +class CLuaCProgressWindow +{ + public: + CProgressWindow *w; + CLuaCProgressWindow() { w = NULL; } + ~CLuaCProgressWindow() { delete w; } +}; + +class CLuaInstProgressWindow +{ + public: + CLuaInstProgressWindow() {}; + ~CLuaInstProgressWindow() {}; + static CLuaInstProgressWindow* getInstance(); + static void ProgressWindowRegister(lua_State *L); + + private: + static int CProgressWindowNew(lua_State *L); + static CLuaCProgressWindow *CProgressWindowCheck(lua_State *L, int n); + static int CProgressWindowPaint(lua_State *L); + static int CProgressWindowHide(lua_State *L); + static int CProgressWindowSetTitle(lua_State *L); + static int CProgressWindowDelete(lua_State *L); + static int CProgressWindowShowStatusInternal(lua_State *L, bool local); + static int CProgressWindowShowLocalStatus(lua_State *L); + static int CProgressWindowShowGlobalStatus(lua_State *L); +}; + +#endif //_LUAPROGRESSWINDOW_H_ diff --git a/src/gui/lua/luainstance.cpp b/src/gui/lua/luainstance.cpp index 9adfa1d4e..ee304db0a 100644 --- a/src/gui/lua/luainstance.cpp +++ b/src/gui/lua/luainstance.cpp @@ -51,6 +51,7 @@ #include "lua_menue.h" #include "lua_messagebox.h" #include "lua_misc.h" +#include "lua_progresswindow.h" #include "lua_stringinput.h" #include "lua_threads.h" #include "lua_video.h" @@ -383,22 +384,35 @@ static void set_lua_variables(lua_State *L) { NULL, 0 } }; + /* + * possible text allignment modes usable for window header caption + * API: >= v1.71 + */ + table_key text_alignment[] = + { + { "DEFAULT", (lua_Integer)CTextBox::NO_AUTO_LINEBREAK}, + { "CENTER", (lua_Integer)CTextBox::CENTER}, + { "RIGHT", (lua_Integer)CTextBox::RIGHT}, + { NULL, 0 } + }; + /* list of environment variable arrays to be exported */ lua_envexport e[] = { - { "RC", keyname }, - { "SCREEN", screenopts }, - { "FONT", fontlist }, - { "CORNER", corners }, - { "OFFSET", offsets }, - { "MENU_RETURN", menureturn }, - { "APIVERSION", apiversion }, - { "PLAYSTATE", playstate }, - { "CC", ccomponents }, - { "DYNFONT", dynfont }, - { "CURL", curl_status }, - { "NMODE", neutrino_mode }, - { "POSTMSG", post_msg }, + { "RC", keyname }, + { "SCREEN", screenopts }, + { "FONT", fontlist }, + { "CORNER", corners }, + { "OFFSET", offsets }, + { "MENU_RETURN", menureturn }, + { "APIVERSION", apiversion }, + { "PLAYSTATE", playstate }, + { "CC", ccomponents }, + { "DYNFONT", dynfont }, + { "CURL", curl_status }, + { "NMODE", neutrino_mode }, + { "POSTMSG", post_msg }, + { "TEXT_ALIGNMENT", text_alignment }, { NULL, NULL } }; @@ -660,6 +674,8 @@ void LuaInstRegisterFunctions(lua_State *L, bool fromThreads/*=false*/) CLuaInstStringInput::getInstance()->StringInputRegister(L); CLuaInstMisc::getInstance()->LuaMiscRegister(L); CLuaInstVideo::getInstance()->LuaVideoRegister(L); + CLuaInstProgressWindow::getInstance()->ProgressWindowRegister(L); + if (!fromThreads) CLLThread::getInstance()->LuaThreadsRegister(L); } diff --git a/src/lcddisplay/fontrenderer.cpp b/src/lcddisplay/fontrenderer.cpp index 4a0bfa7ec..b4b8aac40 100644 --- a/src/lcddisplay/fontrenderer.cpp +++ b/src/lcddisplay/fontrenderer.cpp @@ -35,6 +35,10 @@ #include #include FT_FREETYPE_H +#ifdef ENABLE_FRIBIDI +#include +#endif + FT_Error LcdFontRenderClass::myFTC_Face_Requester(FTC_FaceID face_id, FT_Library /*library*/, FT_Pointer request_data, @@ -230,11 +234,20 @@ extern int UTF8ToUnicode(const char * &text, const bool utf8_encoded); // return } #endif +#ifdef ENABLE_FRIBIDI +std::string fribidi_shape_char(const char * text); +#endif + void LcdFont::RenderString(int x, int y, const int width, const char * text, const int color, const int selected, const bool utf8_encoded) { int err; pthread_mutex_lock(&renderer->render_mutex); +#ifdef ENABLE_FRIBIDI + std::string Text = fribidi_shape_char(text); + text = Text.c_str(); +#endif + FTC_ScalerRec scaler; scaler.face_id = font.face_id; @@ -316,6 +329,12 @@ int LcdFont::getRenderWidth(const std::string &text, const bool utf8_encoded) int LcdFont::getRenderWidth(const char * text, const bool utf8_encoded) { pthread_mutex_lock(&renderer->render_mutex); + +#ifdef ENABLE_FRIBIDI + std::string Text = fribidi_shape_char(text); + text = Text.c_str(); +#endif + FT_Error err; FTC_ScalerRec scaler; scaler.face_id = font.face_id; diff --git a/src/system/Makefile.am b/src/system/Makefile.am index bfdd80b24..916037323 100644 --- a/src/system/Makefile.am +++ b/src/system/Makefile.am @@ -16,7 +16,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/lib/libconfigfile \ -I$(top_srcdir)/lib/libmd5sum \ -I$(top_srcdir)/lib/xmltree \ - -I$(top_srcdir)/lib/jsoncpp/include \ + -I$(top_srcdir)/lib/jsoncpp \ @SIGC_CFLAGS@ \ @FREETYPE_CFLAGS@ \ @AVFORMAT_CFLAGS@ \