├── json ├── version ├── json.a ├── LICENSE ├── json.h ├── forwards.h ├── features.h ├── config.h ├── json_batchallocator.h ├── writer.h ├── reader.h ├── json_valueiterator.inl ├── json_internalarray.inl ├── json_internalmap.inl ├── json_writer.cpp ├── json_reader.cpp ├── value.h └── json_value.cpp ├── README.md ├── LICENSE └── ledger.cpp /json/version: -------------------------------------------------------------------------------- 1 | 0.5.0 -------------------------------------------------------------------------------- /json/json.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoelKatz/getLedger/HEAD/json/json.a -------------------------------------------------------------------------------- /json/LICENSE: -------------------------------------------------------------------------------- 1 | The json-cpp library and this documentation are in Public Domain. 2 | -------------------------------------------------------------------------------- /json/json.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_JSON_H_INCLUDED 2 | # define JSON_JSON_H_INCLUDED 3 | 4 | # include "value.h" 5 | # include "reader.h" 6 | # include "writer.h" 7 | # include "features.h" 8 | 9 | #endif // JSON_JSON_H_INCLUDED 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # getLedger 2 | Retrieve an XRP Ledger in JSON by sequence number 3 | 4 | Run the "build" script. Edit it if necessary. 5 | 6 | It will produce two executables: 7 | ledger.compact will get ledgers in compact JSON 8 | ledger.pretty will get ledgers in pretty JSON 9 | 10 | Both programs take a single parameter, the ledger index 11 | to be retrieved. 12 | 13 | They will produce a file called ledger. which contains 14 | the ledger header, transactions (if any), and full state tree. 15 | 16 | This is quick and dirty code that has not been well-tested 17 | or thoroughly debugged. In particular, it does not handle 18 | error conditions well. 19 | -------------------------------------------------------------------------------- /json/forwards.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_FORWARDS_H_INCLUDED 2 | # define JSON_FORWARDS_H_INCLUDED 3 | 4 | # include "config.h" 5 | 6 | namespace Json { 7 | 8 | // writer.h 9 | class FastWriter; 10 | class StyledWriter; 11 | 12 | // reader.h 13 | class Reader; 14 | 15 | // features.h 16 | class Features; 17 | 18 | // value.h 19 | typedef int Int; 20 | typedef unsigned int UInt; 21 | class StaticString; 22 | class Path; 23 | class PathArgument; 24 | class Value; 25 | class ValueIteratorBase; 26 | class ValueIterator; 27 | class ValueConstIterator; 28 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 29 | class ValueAllocator; 30 | class ValueMapAllocator; 31 | class ValueInternalLink; 32 | class ValueInternalArray; 33 | class ValueInternalMap; 34 | #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP 35 | 36 | } // namespace Json 37 | 38 | 39 | #endif // JSON_FORWARDS_H_INCLUDED 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ripple 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /json/features.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_FEATURES_H_INCLUDED 2 | # define CPPTL_JSON_FEATURES_H_INCLUDED 3 | 4 | # include "forwards.h" 5 | 6 | namespace Json { 7 | 8 | /** \brief Configuration passed to reader and writer. 9 | * This configuration object can be used to force the Reader or Writer 10 | * to behave in a standard conforming way. 11 | */ 12 | class JSON_API Features 13 | { 14 | public: 15 | /** \brief A configuration that allows all features and assumes all strings are UTF-8. 16 | * - C & C++ comments are allowed 17 | * - Root object can be any JSON value 18 | * - Assumes Value strings are encoded in UTF-8 19 | */ 20 | static Features all(); 21 | 22 | /** \brief A configuration that is strictly compatible with the JSON specification. 23 | * - Comments are forbidden. 24 | * - Root object must be either an array or an object value. 25 | * - Assumes Value strings are encoded in UTF-8 26 | */ 27 | static Features strictMode(); 28 | 29 | /** \brief Initialize the configuration like JsonConfig::allFeatures; 30 | */ 31 | Features(); 32 | 33 | /// \c true if comments are allowed. Default: \c true. 34 | bool allowComments_; 35 | 36 | /// \c true if root must be either an array or an object value. Default: \c false. 37 | bool strictRoot_; 38 | }; 39 | 40 | } // namespace Json 41 | 42 | #endif // CPPTL_JSON_FEATURES_H_INCLUDED 43 | -------------------------------------------------------------------------------- /json/config.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_CONFIG_H_INCLUDED 2 | # define JSON_CONFIG_H_INCLUDED 3 | 4 | /// If defined, indicates that json library is embedded in CppTL library. 5 | //# define JSON_IN_CPPTL 1 6 | 7 | /// If defined, indicates that json may leverage CppTL library 8 | //# define JSON_USE_CPPTL 1 9 | /// If defined, indicates that cpptl vector based map should be used instead of std::map 10 | /// as Value container. 11 | //# define JSON_USE_CPPTL_SMALLMAP 1 12 | /// If defined, indicates that Json specific container should be used 13 | /// (hash table & simple deque container with customizable allocator). 14 | /// THIS FEATURE IS STILL EXPERIMENTAL! 15 | //# define JSON_VALUE_USE_INTERNAL_MAP 1 16 | /// Force usage of standard new/malloc based allocator instead of memory pool based allocator. 17 | /// The memory pools allocator used optimization (initializing Value and ValueInternalLink 18 | /// as if it was a POD) that may cause some validation tool to report errors. 19 | /// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. 20 | //# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 21 | 22 | /// If defined, indicates that Json use exception to report invalid type manipulation 23 | /// instead of C assert macro. 24 | # define JSON_USE_EXCEPTION 1 25 | 26 | # ifdef JSON_IN_CPPTL 27 | # include 28 | # ifndef JSON_USE_CPPTL 29 | # define JSON_USE_CPPTL 1 30 | # endif 31 | # endif 32 | 33 | # ifdef JSON_IN_CPPTL 34 | # define JSON_API CPPTL_API 35 | # elif defined(JSON_DLL_BUILD) 36 | # define JSON_API __declspec(dllexport) 37 | # elif defined(JSON_DLL) 38 | # define JSON_API __declspec(dllimport) 39 | # else 40 | # define JSON_API 41 | # endif 42 | 43 | #endif // JSON_CONFIG_H_INCLUDED 44 | -------------------------------------------------------------------------------- /json/json_batchallocator.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED 2 | # define JSONCPP_BATCHALLOCATOR_H_INCLUDED 3 | 4 | # include 5 | # include 6 | 7 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 8 | 9 | namespace Json { 10 | 11 | /* Fast memory allocator. 12 | * 13 | * This memory allocator allocates memory for a batch of object (specified by 14 | * the page size, the number of object in each page). 15 | * 16 | * It does not allow the destruction of a single object. All the allocated objects 17 | * can be destroyed at once. The memory can be either released or reused for future 18 | * allocation. 19 | * 20 | * The in-place new operator must be used to construct the object using the pointer 21 | * returned by allocate. 22 | */ 23 | template 25 | class BatchAllocator 26 | { 27 | public: 28 | typedef AllocatedType Type; 29 | 30 | BatchAllocator( unsigned int objectsPerPage = 255 ) 31 | : freeHead_( 0 ) 32 | , objectsPerPage_( objectsPerPage ) 33 | { 34 | // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); 35 | assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. 36 | assert( objectsPerPage >= 16 ); 37 | batches_ = allocateBatch( 0 ); // allocated a dummy page 38 | currentBatch_ = batches_; 39 | } 40 | 41 | ~BatchAllocator() 42 | { 43 | for ( BatchInfo *batch = batches_; batch; ) 44 | { 45 | BatchInfo *nextBatch = batch->next_; 46 | free( batch ); 47 | batch = nextBatch; 48 | } 49 | } 50 | 51 | /// allocate space for an array of objectPerAllocation object. 52 | /// @warning it is the responsability of the caller to call objects constructors. 53 | AllocatedType *allocate() 54 | { 55 | if ( freeHead_ ) // returns node from free list. 56 | { 57 | AllocatedType *object = freeHead_; 58 | freeHead_ = *(AllocatedType **)object; 59 | return object; 60 | } 61 | if ( currentBatch_->used_ == currentBatch_->end_ ) 62 | { 63 | currentBatch_ = currentBatch_->next_; 64 | while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) 65 | currentBatch_ = currentBatch_->next_; 66 | 67 | if ( !currentBatch_ ) // no free batch found, allocate a new one 68 | { 69 | currentBatch_ = allocateBatch( objectsPerPage_ ); 70 | currentBatch_->next_ = batches_; // insert at the head of the list 71 | batches_ = currentBatch_; 72 | } 73 | } 74 | AllocatedType *allocated = currentBatch_->used_; 75 | currentBatch_->used_ += objectPerAllocation; 76 | return allocated; 77 | } 78 | 79 | /// Release the object. 80 | /// @warning it is the responsability of the caller to actually destruct the object. 81 | void release( AllocatedType *object ) 82 | { 83 | assert( object != 0 ); 84 | *(AllocatedType **)object = freeHead_; 85 | freeHead_ = object; 86 | } 87 | 88 | private: 89 | struct BatchInfo 90 | { 91 | BatchInfo *next_; 92 | AllocatedType *used_; 93 | AllocatedType *end_; 94 | AllocatedType buffer_[objectPerAllocation]; 95 | }; 96 | 97 | // disabled copy constructor and assignement operator. 98 | BatchAllocator( const BatchAllocator & ); 99 | void operator =( const BatchAllocator &); 100 | 101 | static BatchInfo *allocateBatch( unsigned int objectsPerPage ) 102 | { 103 | const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation 104 | + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; 105 | BatchInfo *batch = static_cast( malloc( mallocSize ) ); 106 | batch->next_ = 0; 107 | batch->used_ = batch->buffer_; 108 | batch->end_ = batch->buffer_ + objectsPerPage; 109 | return batch; 110 | } 111 | 112 | BatchInfo *batches_; 113 | BatchInfo *currentBatch_; 114 | /// Head of a single linked list within the allocated space of freeed object 115 | AllocatedType *freeHead_; 116 | unsigned int objectsPerPage_; 117 | }; 118 | 119 | 120 | } // namespace Json 121 | 122 | # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION 123 | 124 | #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED 125 | 126 | -------------------------------------------------------------------------------- /json/writer.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_WRITER_H_INCLUDED 2 | # define JSON_WRITER_H_INCLUDED 3 | 4 | # include "value.h" 5 | # include 6 | # include 7 | # include 8 | 9 | namespace Json { 10 | 11 | class Value; 12 | 13 | /** \brief Abstract class for writers. 14 | */ 15 | class JSON_API Writer 16 | { 17 | public: 18 | virtual ~Writer(); 19 | 20 | virtual std::string write( const Value &root ) = 0; 21 | }; 22 | 23 | /** \brief Outputs a Value in JSON format without formatting (not human friendly). 24 | * 25 | * The JSON document is written in a single line. It is not intended for 'human' consumption, 26 | * but may be usefull to support feature such as RPC where bandwith is limited. 27 | * \sa Reader, Value 28 | */ 29 | class JSON_API FastWriter : public Writer 30 | { 31 | public: 32 | FastWriter(); 33 | virtual ~FastWriter(){} 34 | 35 | void enableYAMLCompatibility(); 36 | 37 | public: // overridden from Writer 38 | virtual std::string write( const Value &root ); 39 | 40 | private: 41 | void writeValue( const Value &value ); 42 | 43 | std::string document_; 44 | bool yamlCompatiblityEnabled_; 45 | }; 46 | 47 | /** \brief Writes a Value in JSON format in a human friendly way. 48 | * 49 | * The rules for line break and indent are as follow: 50 | * - Object value: 51 | * - if empty then print {} without indent and line break 52 | * - if not empty the print '{', line break & indent, print one value per line 53 | * and then unindent and line break and print '}'. 54 | * - Array value: 55 | * - if empty then print [] without indent and line break 56 | * - if the array contains no object value, empty array or some other value types, 57 | * and all the values fit on one lines, then print the array on a single line. 58 | * - otherwise, it the values do not fit on one line, or the array contains 59 | * object or non empty array, then print one value per line. 60 | * 61 | * If the Value have comments then they are outputed according to their #CommentPlacement. 62 | * 63 | * \sa Reader, Value, Value::setComment() 64 | */ 65 | class JSON_API StyledWriter: public Writer 66 | { 67 | public: 68 | StyledWriter(); 69 | virtual ~StyledWriter(){} 70 | 71 | public: // overridden from Writer 72 | /** \brief Serialize a Value in JSON format. 73 | * \param root Value to serialize. 74 | * \return String containing the JSON document that represents the root value. 75 | */ 76 | virtual std::string write( const Value &root ); 77 | 78 | private: 79 | void writeValue( const Value &value ); 80 | void writeArrayValue( const Value &value ); 81 | bool isMultineArray( const Value &value ); 82 | void pushValue( const std::string &value ); 83 | void writeIndent(); 84 | void writeWithIndent( const std::string &value ); 85 | void indent(); 86 | void unindent(); 87 | void writeCommentBeforeValue( const Value &root ); 88 | void writeCommentAfterValueOnSameLine( const Value &root ); 89 | bool hasCommentForValue( const Value &value ); 90 | static std::string normalizeEOL( const std::string &text ); 91 | 92 | typedef std::vector ChildValues; 93 | 94 | ChildValues childValues_; 95 | std::string document_; 96 | std::string indentString_; 97 | int rightMargin_; 98 | int indentSize_; 99 | bool addChildValues_; 100 | }; 101 | 102 | /** \brief Writes a Value in JSON format in a human friendly way, 103 | to a stream rather than to a string. 104 | * 105 | * The rules for line break and indent are as follow: 106 | * - Object value: 107 | * - if empty then print {} without indent and line break 108 | * - if not empty the print '{', line break & indent, print one value per line 109 | * and then unindent and line break and print '}'. 110 | * - Array value: 111 | * - if empty then print [] without indent and line break 112 | * - if the array contains no object value, empty array or some other value types, 113 | * and all the values fit on one lines, then print the array on a single line. 114 | * - otherwise, it the values do not fit on one line, or the array contains 115 | * object or non empty array, then print one value per line. 116 | * 117 | * If the Value have comments then they are outputed according to their #CommentPlacement. 118 | * 119 | * \param indentation Each level will be indented by this amount extra. 120 | * \sa Reader, Value, Value::setComment() 121 | */ 122 | class JSON_API StyledStreamWriter 123 | { 124 | public: 125 | StyledStreamWriter( std::string indentation="\t" ); 126 | ~StyledStreamWriter(){} 127 | 128 | public: 129 | /** \brief Serialize a Value in JSON format. 130 | * \param out Stream to write to. (Can be ostringstream, e.g.) 131 | * \param root Value to serialize. 132 | * \note There is no point in deriving from Writer, since write() should not return a value. 133 | */ 134 | void write( std::ostream &out, const Value &root ); 135 | 136 | private: 137 | void writeValue( const Value &value ); 138 | void writeArrayValue( const Value &value ); 139 | bool isMultineArray( const Value &value ); 140 | void pushValue( const std::string &value ); 141 | void writeIndent(); 142 | void writeWithIndent( const std::string &value ); 143 | void indent(); 144 | void unindent(); 145 | void writeCommentBeforeValue( const Value &root ); 146 | void writeCommentAfterValueOnSameLine( const Value &root ); 147 | bool hasCommentForValue( const Value &value ); 148 | static std::string normalizeEOL( const std::string &text ); 149 | 150 | typedef std::vector ChildValues; 151 | 152 | ChildValues childValues_; 153 | std::ostream* document_; 154 | std::string indentString_; 155 | int rightMargin_; 156 | std::string indentation_; 157 | bool addChildValues_; 158 | }; 159 | 160 | std::string JSON_API valueToString( Int value ); 161 | std::string JSON_API valueToString( UInt value ); 162 | std::string JSON_API valueToString( double value ); 163 | std::string JSON_API valueToString( bool value ); 164 | std::string JSON_API valueToQuotedString( const char *value ); 165 | 166 | /// \brief Output using the StyledStreamWriter. 167 | /// \see Json::operator>>() 168 | std::ostream& operator<<( std::ostream&, const Value &root ); 169 | 170 | } // namespace Json 171 | 172 | 173 | 174 | #endif // JSON_WRITER_H_INCLUDED 175 | -------------------------------------------------------------------------------- /json/reader.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_READER_H_INCLUDED 2 | # define CPPTL_JSON_READER_H_INCLUDED 3 | 4 | # include "features.h" 5 | # include "value.h" 6 | # include 7 | # include 8 | # include 9 | # include 10 | 11 | namespace Json { 12 | 13 | /** \brief Unserialize a JSON document into a Value. 14 | * 15 | */ 16 | class JSON_API Reader 17 | { 18 | public: 19 | typedef char Char; 20 | typedef const Char *Location; 21 | 22 | /** \brief Constructs a Reader allowing all features 23 | * for parsing. 24 | */ 25 | Reader(); 26 | 27 | /** \brief Constructs a Reader allowing the specified feature set 28 | * for parsing. 29 | */ 30 | Reader( const Features &features ); 31 | 32 | /** \brief Read a Value from a JSON document. 33 | * \param document UTF-8 encoded string containing the document to read. 34 | * \param root [out] Contains the root value of the document if it was 35 | * successfully parsed. 36 | * \param collectComments \c true to collect comment and allow writing them back during 37 | * serialization, \c false to discard comments. 38 | * This parameter is ignored if Features::allowComments_ 39 | * is \c false. 40 | * \return \c true if the document was successfully parsed, \c false if an error occurred. 41 | */ 42 | bool parse( const std::string &document, 43 | Value &root, 44 | bool collectComments = true ); 45 | 46 | /** \brief Read a Value from a JSON document. 47 | * \param document UTF-8 encoded string containing the document to read. 48 | * \param root [out] Contains the root value of the document if it was 49 | * successfully parsed. 50 | * \param collectComments \c true to collect comment and allow writing them back during 51 | * serialization, \c false to discard comments. 52 | * This parameter is ignored if Features::allowComments_ 53 | * is \c false. 54 | * \return \c true if the document was successfully parsed, \c false if an error occurred. 55 | */ 56 | bool parse( const char *beginDoc, const char *endDoc, 57 | Value &root, 58 | bool collectComments = true ); 59 | 60 | /// \brief Parse from input stream. 61 | /// \see Json::operator>>(std::istream&, Json::Value&). 62 | bool parse( std::istream &is, 63 | Value &root, 64 | bool collectComments = true ); 65 | 66 | /** \brief Returns a user friendly string that list errors in the parsed document. 67 | * \return Formatted error message with the list of errors with their location in 68 | * the parsed document. An empty string is returned if no error occurred 69 | * during parsing. 70 | */ 71 | std::string getFormatedErrorMessages() const; 72 | 73 | private: 74 | enum TokenType 75 | { 76 | tokenEndOfStream = 0, 77 | tokenObjectBegin, 78 | tokenObjectEnd, 79 | tokenArrayBegin, 80 | tokenArrayEnd, 81 | tokenString, 82 | tokenNumber, 83 | tokenTrue, 84 | tokenFalse, 85 | tokenNull, 86 | tokenArraySeparator, 87 | tokenMemberSeparator, 88 | tokenComment, 89 | tokenError 90 | }; 91 | 92 | class Token 93 | { 94 | public: 95 | TokenType type_; 96 | Location start_; 97 | Location end_; 98 | }; 99 | 100 | class ErrorInfo 101 | { 102 | public: 103 | Token token_; 104 | std::string message_; 105 | Location extra_; 106 | }; 107 | 108 | typedef std::deque Errors; 109 | 110 | bool expectToken( TokenType type, Token &token, const char *message ); 111 | bool readToken( Token &token ); 112 | void skipSpaces(); 113 | bool match( Location pattern, 114 | int patternLength ); 115 | bool readComment(); 116 | bool readCStyleComment(); 117 | bool readCppStyleComment(); 118 | bool readString(); 119 | void readNumber(); 120 | bool readValue(); 121 | bool readObject( Token &token ); 122 | bool readArray( Token &token ); 123 | bool decodeNumber( Token &token ); 124 | bool decodeString( Token &token ); 125 | bool decodeString( Token &token, std::string &decoded ); 126 | bool decodeDouble( Token &token ); 127 | bool decodeUnicodeCodePoint( Token &token, 128 | Location ¤t, 129 | Location end, 130 | unsigned int &unicode ); 131 | bool decodeUnicodeEscapeSequence( Token &token, 132 | Location ¤t, 133 | Location end, 134 | unsigned int &unicode ); 135 | bool addError( const std::string &message, 136 | Token &token, 137 | Location extra = 0 ); 138 | bool recoverFromError( TokenType skipUntilToken ); 139 | bool addErrorAndRecover( const std::string &message, 140 | Token &token, 141 | TokenType skipUntilToken ); 142 | void skipUntilSpace(); 143 | Value ¤tValue(); 144 | Char getNextChar(); 145 | void getLocationLineAndColumn( Location location, 146 | int &line, 147 | int &column ) const; 148 | std::string getLocationLineAndColumn( Location location ) const; 149 | void addComment( Location begin, 150 | Location end, 151 | CommentPlacement placement ); 152 | void skipCommentTokens( Token &token ); 153 | 154 | typedef std::stack Nodes; 155 | Nodes nodes_; 156 | Errors errors_; 157 | std::string document_; 158 | Location begin_; 159 | Location end_; 160 | Location current_; 161 | Location lastValueEnd_; 162 | Value *lastValue_; 163 | std::string commentsBefore_; 164 | Features features_; 165 | bool collectComments_; 166 | }; 167 | 168 | /** \brief Read from 'sin' into 'root'. 169 | 170 | Always keep comments from the input JSON. 171 | 172 | This can be used to read a file into a particular sub-object. 173 | For example: 174 | \code 175 | Json::Value root; 176 | cin >> root["dir"]["file"]; 177 | cout << root; 178 | \endcode 179 | Result: 180 | \verbatim 181 | { 182 | "dir": { 183 | "file": { 184 | // The input stream JSON would be nested here. 185 | } 186 | } 187 | } 188 | \endverbatim 189 | \throw std::exception on parse error. 190 | \see Json::operator<<() 191 | */ 192 | std::istream& operator>>( std::istream&, Value& ); 193 | 194 | } // namespace Json 195 | 196 | #endif // CPPTL_JSON_READER_H_INCLUDED 197 | -------------------------------------------------------------------------------- /json/json_valueiterator.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // ////////////////////////////////////////////////////////////////// 8 | // class ValueIteratorBase 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | // ////////////////////////////////////////////////////////////////// 12 | 13 | ValueIteratorBase::ValueIteratorBase() 14 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 15 | : current_() 16 | , isNull_( true ) 17 | { 18 | } 19 | #else 20 | : isArray_( true ) 21 | , isNull_( true ) 22 | { 23 | iterator_.array_ = ValueInternalArray::IteratorState(); 24 | } 25 | #endif 26 | 27 | 28 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 29 | ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) 30 | : current_( current ) 31 | , isNull_( false ) 32 | { 33 | } 34 | #else 35 | ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) 36 | : isArray_( true ) 37 | { 38 | iterator_.array_ = state; 39 | } 40 | 41 | 42 | ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) 43 | : isArray_( false ) 44 | { 45 | iterator_.map_ = state; 46 | } 47 | #endif 48 | 49 | Value & 50 | ValueIteratorBase::deref() const 51 | { 52 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 53 | return current_->second; 54 | #else 55 | if ( isArray_ ) 56 | return ValueInternalArray::dereference( iterator_.array_ ); 57 | return ValueInternalMap::value( iterator_.map_ ); 58 | #endif 59 | } 60 | 61 | 62 | void 63 | ValueIteratorBase::increment() 64 | { 65 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 66 | ++current_; 67 | #else 68 | if ( isArray_ ) 69 | ValueInternalArray::increment( iterator_.array_ ); 70 | ValueInternalMap::increment( iterator_.map_ ); 71 | #endif 72 | } 73 | 74 | 75 | void 76 | ValueIteratorBase::decrement() 77 | { 78 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 79 | --current_; 80 | #else 81 | if ( isArray_ ) 82 | ValueInternalArray::decrement( iterator_.array_ ); 83 | ValueInternalMap::decrement( iterator_.map_ ); 84 | #endif 85 | } 86 | 87 | 88 | ValueIteratorBase::difference_type 89 | ValueIteratorBase::computeDistance( const SelfType &other ) const 90 | { 91 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 92 | # ifdef JSON_USE_CPPTL_SMALLMAP 93 | return current_ - other.current_; 94 | # else 95 | // Iterator for null value are initialized using the default 96 | // constructor, which initialize current_ to the default 97 | // std::map::iterator. As begin() and end() are two instance 98 | // of the default std::map::iterator, they can not be compared. 99 | // To allow this, we handle this comparison specifically. 100 | if ( isNull_ && other.isNull_ ) 101 | { 102 | return 0; 103 | } 104 | 105 | 106 | // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, 107 | // which is the one used by default). 108 | // Using a portable hand-made version for non random iterator instead: 109 | // return difference_type( std::distance( current_, other.current_ ) ); 110 | difference_type myDistance = 0; 111 | for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) 112 | { 113 | ++myDistance; 114 | } 115 | return myDistance; 116 | # endif 117 | #else 118 | if ( isArray_ ) 119 | return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); 120 | return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); 121 | #endif 122 | } 123 | 124 | 125 | bool 126 | ValueIteratorBase::isEqual( const SelfType &other ) const 127 | { 128 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 129 | if ( isNull_ ) 130 | { 131 | return other.isNull_; 132 | } 133 | return current_ == other.current_; 134 | #else 135 | if ( isArray_ ) 136 | return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); 137 | return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); 138 | #endif 139 | } 140 | 141 | 142 | void 143 | ValueIteratorBase::copy( const SelfType &other ) 144 | { 145 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 146 | current_ = other.current_; 147 | #else 148 | if ( isArray_ ) 149 | iterator_.array_ = other.iterator_.array_; 150 | iterator_.map_ = other.iterator_.map_; 151 | #endif 152 | } 153 | 154 | 155 | Value 156 | ValueIteratorBase::key() const 157 | { 158 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 159 | const Value::CZString czstring = (*current_).first; 160 | if ( czstring.c_str() ) 161 | { 162 | if ( czstring.isStaticString() ) 163 | return Value( StaticString( czstring.c_str() ) ); 164 | return Value( czstring.c_str() ); 165 | } 166 | return Value( czstring.index() ); 167 | #else 168 | if ( isArray_ ) 169 | return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); 170 | bool isStatic; 171 | const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); 172 | if ( isStatic ) 173 | return Value( StaticString( memberName ) ); 174 | return Value( memberName ); 175 | #endif 176 | } 177 | 178 | 179 | UInt 180 | ValueIteratorBase::index() const 181 | { 182 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 183 | const Value::CZString czstring = (*current_).first; 184 | if ( !czstring.c_str() ) 185 | return czstring.index(); 186 | return Value::UInt( -1 ); 187 | #else 188 | if ( isArray_ ) 189 | return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); 190 | return Value::UInt( -1 ); 191 | #endif 192 | } 193 | 194 | 195 | const char * 196 | ValueIteratorBase::memberName() const 197 | { 198 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 199 | const char *name = (*current_).first.c_str(); 200 | return name ? name : ""; 201 | #else 202 | if ( !isArray_ ) 203 | return ValueInternalMap::key( iterator_.map_ ); 204 | return ""; 205 | #endif 206 | } 207 | 208 | 209 | // ////////////////////////////////////////////////////////////////// 210 | // ////////////////////////////////////////////////////////////////// 211 | // ////////////////////////////////////////////////////////////////// 212 | // class ValueConstIterator 213 | // ////////////////////////////////////////////////////////////////// 214 | // ////////////////////////////////////////////////////////////////// 215 | // ////////////////////////////////////////////////////////////////// 216 | 217 | ValueConstIterator::ValueConstIterator() 218 | { 219 | } 220 | 221 | 222 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 223 | ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) 224 | : ValueIteratorBase( current ) 225 | { 226 | } 227 | #else 228 | ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) 229 | : ValueIteratorBase( state ) 230 | { 231 | } 232 | 233 | ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) 234 | : ValueIteratorBase( state ) 235 | { 236 | } 237 | #endif 238 | 239 | ValueConstIterator & 240 | ValueConstIterator::operator =( const ValueIteratorBase &other ) 241 | { 242 | copy( other ); 243 | return *this; 244 | } 245 | 246 | 247 | // ////////////////////////////////////////////////////////////////// 248 | // ////////////////////////////////////////////////////////////////// 249 | // ////////////////////////////////////////////////////////////////// 250 | // class ValueIterator 251 | // ////////////////////////////////////////////////////////////////// 252 | // ////////////////////////////////////////////////////////////////// 253 | // ////////////////////////////////////////////////////////////////// 254 | 255 | ValueIterator::ValueIterator() 256 | { 257 | } 258 | 259 | 260 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 261 | ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) 262 | : ValueIteratorBase( current ) 263 | { 264 | } 265 | #else 266 | ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) 267 | : ValueIteratorBase( state ) 268 | { 269 | } 270 | 271 | ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) 272 | : ValueIteratorBase( state ) 273 | { 274 | } 275 | #endif 276 | 277 | ValueIterator::ValueIterator( const ValueConstIterator &other ) 278 | : ValueIteratorBase( other ) 279 | { 280 | } 281 | 282 | ValueIterator::ValueIterator( const ValueIterator &other ) 283 | : ValueIteratorBase( other ) 284 | { 285 | } 286 | 287 | ValueIterator & 288 | ValueIterator::operator =( const SelfType &other ) 289 | { 290 | copy( other ); 291 | return *this; 292 | } 293 | -------------------------------------------------------------------------------- /ledger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // This is very quick and dirty code to retrieve a ledger 9 | // by sequence number from the S2 full history cluster 10 | #ifndef RPC_URL 11 | #define RPC_URL "http://s2.ripple.com:51234" 12 | #endif 13 | 14 | // When compiling, define "COMPACT" if you want your JSON 15 | // to be as short as possible instead of being neatly 16 | // spaced and indented. 17 | 18 | char *out_buf; 19 | 20 | bool pretty = true; 21 | std::string space = " "; 22 | std::string eol = "\n"; 23 | std::string indent = "\t"; 24 | 25 | // Switch from pretty-printing to compact JSON 26 | void setCompact() 27 | { 28 | pretty = false; 29 | space = ""; 30 | eol = ""; 31 | indent = ""; 32 | } 33 | 34 | // Structure to pass to the CURL write callback 35 | struct user_data 36 | { 37 | char *buf; 38 | int so_far; 39 | }; 40 | 41 | // The CURL code needs this callback 42 | size_t write_callback (char *ptr, size_t size, size_t len, void *userdata) 43 | { 44 | struct user_data* ud = (struct user_data*) userdata; 45 | memcpy(ud->buf + ud->so_far, ptr, size * len); 46 | ud->so_far += size * len; 47 | return size * len; 48 | } 49 | 50 | // Write a JSON object to a stream 51 | void writeJson(std::ofstream& f, int step, Json::Value const &v) 52 | { 53 | std::string pre; 54 | std::string str; 55 | 56 | if (! pretty) 57 | { 58 | Json::FastWriter w; 59 | str = w.write (v); 60 | } 61 | else 62 | { 63 | for (int i = 0; i < step; ++i) 64 | pre += indent; 65 | Json::StyledStreamWriter w (indent); 66 | std::ostringstream out; 67 | w.write (out, v); 68 | std::istringstream in(out.str()); 69 | str = out.str(); 70 | } 71 | 72 | // Read the output line-by-line, apply 73 | // formatting as needed, and write to output 74 | std::string l; 75 | bool first = true; 76 | std::istringstream in (str); 77 | while (std::getline (in, l)) 78 | { 79 | if ((l == indent) || (l == "")) 80 | continue; 81 | if (first) 82 | first = false; 83 | else 84 | f << eol; 85 | f << pre << l; 86 | } 87 | } 88 | 89 | // Execute a query against the S2 cluster of full history XRP Ledger notes. 90 | // Note that this is a best-effort service that does not guarantee 91 | // any particular level of reliability. 92 | bool do_query_i (std::string const& method, Json::Value const& params, Json::Value& reply) 93 | { 94 | std::string q; 95 | 96 | { 97 | Json::Value query = Json::objectValue; 98 | query["method"] = method; 99 | Json::Value& p = (query["params"] = Json::arrayValue); 100 | p.append(params); 101 | 102 | Json::FastWriter w; 103 | q = w.write (query); 104 | } 105 | 106 | CURL* c = curl_easy_init(); 107 | if (c == NULL) 108 | return false; 109 | 110 | struct user_data ud; 111 | ud.buf = out_buf; 112 | ud.so_far = 0; 113 | 114 | CURLcode code; 115 | code = curl_easy_setopt (c, CURLOPT_URL, RPC_URL); 116 | code = curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, q.size()); 117 | code = curl_easy_setopt (c, CURLOPT_POSTFIELDS, q.c_str()); 118 | code = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, write_callback); 119 | code = curl_easy_setopt (c, CURLOPT_WRITEDATA, &ud); 120 | 121 | code = curl_easy_perform (c); 122 | if (code != CURLE_OK) 123 | { 124 | curl_easy_cleanup (c); 125 | return false; 126 | } 127 | ud.buf[ud.so_far] = 0; 128 | curl_easy_cleanup (c); 129 | 130 | Json::Reader reader; 131 | Json::Value root; 132 | if (!reader.parse(out_buf, root)) 133 | { 134 | fprintf(stderr, "%s\n", reader.getFormatedErrorMessages().c_str()); 135 | return false; 136 | } 137 | Json::Value& result = root["result"]; 138 | if (! result.isObject()) 139 | { 140 | fprintf(stderr, "Result is not object\n"); 141 | return false; 142 | } 143 | Json::Value& status = result["status"]; 144 | if (!status.isString() || (status.asString() != "success")) 145 | { 146 | fprintf(stderr, "Result is '%s', not success\n", status.asString().c_str()); 147 | fprintf(stderr, "\n%s\n", out_buf); 148 | reply = result; 149 | return false; 150 | } 151 | 152 | reply = std::move (root); 153 | return true; 154 | } 155 | 156 | bool do_query(std::string const& method, Json::Value const& params, Json::Value& reply) 157 | { 158 | for (int i = 0; i < 10; ++i) 159 | { 160 | if (do_query_i (method, params, reply)) 161 | return true; 162 | std::cout << "\x8" << i + 1 << "\x8" << std::flush; 163 | sleep (i + 2); 164 | std::cout << "\x8 \x8" << std::flush; 165 | } 166 | return false; 167 | } 168 | 169 | // Get the header of a ledger given its sequence number 170 | bool getHeader (unsigned ledger_seq, Json::Value& header) 171 | { 172 | Json::Value reply; 173 | Json::Value params = Json::objectValue; 174 | params["ledger_index"] = ledger_seq; 175 | if (! do_query ("ledger", params, reply)) 176 | { 177 | header = reply; 178 | return false; 179 | } 180 | header = reply["result"]["ledger"]; 181 | if (header.isObject() && !header.isNull()) 182 | return true; 183 | header = reply; 184 | return false; 185 | } 186 | 187 | // Get the transactions from a ledger given its sequence number 188 | // (with metadata) 189 | bool getTxns (unsigned ledger_seq, Json::Value& txns) 190 | { 191 | Json::Value reply; 192 | Json::Value params = Json::objectValue; 193 | params["ledger_index"] = ledger_seq; 194 | params["transactions"] = true; 195 | params["expand"] = true; 196 | if (! do_query ("ledger", params, reply)) 197 | return false; 198 | txns = std::move (reply["result"]["ledger"]); 199 | if (txns.isNull() || !txns.isObject()) 200 | return false; 201 | txns = std::move (txns["transactions"]); 202 | return txns.isArray() && !txns.isNull(); 203 | } 204 | 205 | // Get a chunk of a ledger's state tree 206 | bool getState (unsigned ledger_seq, Json::Value& entries, Json::Value& marker) 207 | { 208 | Json::Value reply; 209 | Json::Value params = Json::objectValue; 210 | params["ledger_index"] = ledger_seq; 211 | params["binary"] = false; 212 | if (! marker.isNull()) 213 | params["marker"] = marker; 214 | if (! do_query ("ledger_data", params, reply)) 215 | return false; 216 | reply = std::move (reply["result"]); 217 | marker = reply["marker"]; 218 | entries = std::move(reply["state"]); 219 | return true; 220 | } 221 | 222 | // Old school hacky progress indicator 223 | // Sorry, not sorry 224 | void do_progress(int max, Json::Value const& marker) 225 | { 226 | static int so_far = 0; 227 | static int phase = 0; 228 | char phases[4] = { '\\', '|', '/', '-' }; 229 | 230 | int progress = max; 231 | if (marker.isString()) 232 | { 233 | // Hashes are randomly distributed, so we can tell how much 234 | // progress we made by where we are in the hash space. 235 | // This code only looks at the first two characters, 00-FF. 236 | std::string m = marker.asString(); 237 | progress = 0; 238 | if (m[0] >= '0' && m[0] <= '9') progress += 16 * (m[0] - '0'); 239 | if (m[0] >= 'A' && m[0] <= 'Z') progress += 16 * (m[0] + 10 - 'A'); 240 | if (m[1] >= '0' && m[1] <= '9') progress += m[1] - '0'; 241 | if (m[1] >= 'A' && m[1] <= 'Z') progress += m[1] + 10 - 'A'; 242 | progress *= max; 243 | progress /= 255; 244 | } 245 | std::cout << "\x8 \x8"; 246 | while (so_far < progress) 247 | { 248 | std::cout << "*"; 249 | ++so_far; 250 | } 251 | std::cout << phases[++phase % 4] << std::flush; 252 | } 253 | 254 | int main(int argc, char* argv[]) 255 | { 256 | if (argc != 2) 257 | { 258 | fprintf (stderr, "You must specify a ledger by index\n"); 259 | return -1; 260 | } 261 | 262 | #ifdef COMPACT 263 | setCompact(); 264 | #endif 265 | 266 | out_buf = (char *) malloc (100000000); 267 | if (out_buf == NULL) 268 | return -1; 269 | 270 | unsigned seq = (unsigned) atoll(argv[1]); 271 | printf("Seq = %u\n", seq); 272 | 273 | char fbuf[512]; 274 | sprintf(fbuf, "ledger.%u", seq); 275 | std::ofstream f (fbuf, std::ofstream::out | std::ofstream::trunc); 276 | if (! f.is_open()) 277 | return -1; 278 | 279 | f << "{" << eol; 280 | 281 | Json::Value reply; 282 | if (! getHeader(seq, reply)) 283 | { 284 | fprintf(stderr, "Query failed"); 285 | std::cerr << reply; 286 | return -1; 287 | } 288 | f << indent << "\"ledger\"" << space << ":" << eol;; 289 | writeJson (f, 1, reply); 290 | f << "," << eol; 291 | 292 | printf("Got header\n"); 293 | 294 | // If transaction_hash is all zeroes, there are no transactions to get 295 | if (reply["transaction_hash"].asString() != 296 | "0000000000000000000000000000000000000000000000000000000000000000") 297 | { 298 | if (! getTxns(seq, reply)) 299 | { 300 | fprintf(stderr, "Query failed\n"); 301 | return -1; 302 | } 303 | f << indent << "\"transactions\":" << eol; 304 | writeJson (f, 1, reply); 305 | f << indent << "," << eol;; 306 | printf("Got %d transaction(s)\n", reply.size()); 307 | } 308 | else printf("No transactions\n"); 309 | printf("Getting state tree:\n"); 310 | int e = 0; 311 | 312 | std::string const progress = "0%--10%--20%--30%--40%--50%--60%--70%--80%--90%--100%"; 313 | std::cout << progress << std::endl; 314 | 315 | bool first = true; 316 | f << indent << "\"state\"" << space << ":" << eol << indent << "[" << eol; 317 | Json::Value marker = Json::nullValue; 318 | do 319 | { 320 | if (! getState (seq, reply, marker)) 321 | { 322 | fprintf(stderr, "Query failed\n"); 323 | return -1; 324 | } 325 | for (unsigned j = 0u; j < reply.size(); ++j) 326 | { 327 | // We need to write out each state entry 328 | // separately so we don't get start of object 329 | // and end of object stuff from the chunk 330 | if (first) 331 | first = false; 332 | else 333 | f << "," << eol; 334 | writeJson (f, 2, reply[j]); 335 | ++e; 336 | } 337 | do_progress (progress.size(), marker); 338 | // empty returned marker indicates last chunk of data 339 | } while (! marker.isNull()); 340 | 341 | std::cout << "\x8 " << std::endl; 342 | printf("%d state entries\n", e); 343 | 344 | f << eol << indent << "]" << eol; 345 | f << "}" << eol; 346 | f.close(); 347 | printf("File \"%s\" written\n", fbuf); 348 | 349 | return 0; 350 | } 351 | -------------------------------------------------------------------------------- /json/json_internalarray.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | // ////////////////////////////////////////////////////////////////// 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // class ValueInternalArray 8 | // ////////////////////////////////////////////////////////////////// 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | 12 | ValueArrayAllocator::~ValueArrayAllocator() 13 | { 14 | } 15 | 16 | // ////////////////////////////////////////////////////////////////// 17 | // class DefaultValueArrayAllocator 18 | // ////////////////////////////////////////////////////////////////// 19 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 20 | class DefaultValueArrayAllocator : public ValueArrayAllocator 21 | { 22 | public: // overridden from ValueArrayAllocator 23 | virtual ~DefaultValueArrayAllocator() 24 | { 25 | } 26 | 27 | virtual ValueInternalArray *newArray() 28 | { 29 | return new ValueInternalArray(); 30 | } 31 | 32 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 33 | { 34 | return new ValueInternalArray( other ); 35 | } 36 | 37 | virtual void destructArray( ValueInternalArray *array ) 38 | { 39 | delete array; 40 | } 41 | 42 | virtual void reallocateArrayPageIndex( Value **&indexes, 43 | ValueInternalArray::PageIndex &indexCount, 44 | ValueInternalArray::PageIndex minNewIndexCount ) 45 | { 46 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 47 | if ( minNewIndexCount > newIndexCount ) 48 | newIndexCount = minNewIndexCount; 49 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 50 | if ( !newIndexes ) 51 | throw std::bad_alloc(); 52 | indexCount = newIndexCount; 53 | indexes = static_cast( newIndexes ); 54 | } 55 | virtual void releaseArrayPageIndex( Value **indexes, 56 | ValueInternalArray::PageIndex indexCount ) 57 | { 58 | if ( indexes ) 59 | free( indexes ); 60 | } 61 | 62 | virtual Value *allocateArrayPage() 63 | { 64 | return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); 65 | } 66 | 67 | virtual void releaseArrayPage( Value *value ) 68 | { 69 | if ( value ) 70 | free( value ); 71 | } 72 | }; 73 | 74 | #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 75 | /// @todo make this thread-safe (lock when accessign batch allocator) 76 | class DefaultValueArrayAllocator : public ValueArrayAllocator 77 | { 78 | public: // overridden from ValueArrayAllocator 79 | virtual ~DefaultValueArrayAllocator() 80 | { 81 | } 82 | 83 | virtual ValueInternalArray *newArray() 84 | { 85 | ValueInternalArray *array = arraysAllocator_.allocate(); 86 | new (array) ValueInternalArray(); // placement new 87 | return array; 88 | } 89 | 90 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 91 | { 92 | ValueInternalArray *array = arraysAllocator_.allocate(); 93 | new (array) ValueInternalArray( other ); // placement new 94 | return array; 95 | } 96 | 97 | virtual void destructArray( ValueInternalArray *array ) 98 | { 99 | if ( array ) 100 | { 101 | array->~ValueInternalArray(); 102 | arraysAllocator_.release( array ); 103 | } 104 | } 105 | 106 | virtual void reallocateArrayPageIndex( Value **&indexes, 107 | ValueInternalArray::PageIndex &indexCount, 108 | ValueInternalArray::PageIndex minNewIndexCount ) 109 | { 110 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 111 | if ( minNewIndexCount > newIndexCount ) 112 | newIndexCount = minNewIndexCount; 113 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 114 | if ( !newIndexes ) 115 | throw std::bad_alloc(); 116 | indexCount = newIndexCount; 117 | indexes = static_cast( newIndexes ); 118 | } 119 | virtual void releaseArrayPageIndex( Value **indexes, 120 | ValueInternalArray::PageIndex indexCount ) 121 | { 122 | if ( indexes ) 123 | free( indexes ); 124 | } 125 | 126 | virtual Value *allocateArrayPage() 127 | { 128 | return static_cast( pagesAllocator_.allocate() ); 129 | } 130 | 131 | virtual void releaseArrayPage( Value *value ) 132 | { 133 | if ( value ) 134 | pagesAllocator_.release( value ); 135 | } 136 | private: 137 | BatchAllocator arraysAllocator_; 138 | BatchAllocator pagesAllocator_; 139 | }; 140 | #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 141 | 142 | static ValueArrayAllocator *&arrayAllocator() 143 | { 144 | static DefaultValueArrayAllocator defaultAllocator; 145 | static ValueArrayAllocator *arrayAllocator = &defaultAllocator; 146 | return arrayAllocator; 147 | } 148 | 149 | static struct DummyArrayAllocatorInitializer { 150 | DummyArrayAllocatorInitializer() 151 | { 152 | arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). 153 | } 154 | } dummyArrayAllocatorInitializer; 155 | 156 | // ////////////////////////////////////////////////////////////////// 157 | // class ValueInternalArray 158 | // ////////////////////////////////////////////////////////////////// 159 | bool 160 | ValueInternalArray::equals( const IteratorState &x, 161 | const IteratorState &other ) 162 | { 163 | return x.array_ == other.array_ 164 | && x.currentItemIndex_ == other.currentItemIndex_ 165 | && x.currentPageIndex_ == other.currentPageIndex_; 166 | } 167 | 168 | 169 | void 170 | ValueInternalArray::increment( IteratorState &it ) 171 | { 172 | JSON_ASSERT_MESSAGE( it.array_ && 173 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ 174 | != it.array_->size_, 175 | "ValueInternalArray::increment(): moving iterator beyond end" ); 176 | ++(it.currentItemIndex_); 177 | if ( it.currentItemIndex_ == itemsPerPage ) 178 | { 179 | it.currentItemIndex_ = 0; 180 | ++(it.currentPageIndex_); 181 | } 182 | } 183 | 184 | 185 | void 186 | ValueInternalArray::decrement( IteratorState &it ) 187 | { 188 | JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ 189 | && it.currentItemIndex_ == 0, 190 | "ValueInternalArray::decrement(): moving iterator beyond end" ); 191 | if ( it.currentItemIndex_ == 0 ) 192 | { 193 | it.currentItemIndex_ = itemsPerPage-1; 194 | --(it.currentPageIndex_); 195 | } 196 | else 197 | { 198 | --(it.currentItemIndex_); 199 | } 200 | } 201 | 202 | 203 | Value & 204 | ValueInternalArray::unsafeDereference( const IteratorState &it ) 205 | { 206 | return (*(it.currentPageIndex_))[it.currentItemIndex_]; 207 | } 208 | 209 | 210 | Value & 211 | ValueInternalArray::dereference( const IteratorState &it ) 212 | { 213 | JSON_ASSERT_MESSAGE( it.array_ && 214 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ 215 | < it.array_->size_, 216 | "ValueInternalArray::dereference(): dereferencing invalid iterator" ); 217 | return unsafeDereference( it ); 218 | } 219 | 220 | void 221 | ValueInternalArray::makeBeginIterator( IteratorState &it ) const 222 | { 223 | it.array_ = const_cast( this ); 224 | it.currentItemIndex_ = 0; 225 | it.currentPageIndex_ = pages_; 226 | } 227 | 228 | 229 | void 230 | ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const 231 | { 232 | it.array_ = const_cast( this ); 233 | it.currentItemIndex_ = index % itemsPerPage; 234 | it.currentPageIndex_ = pages_ + index / itemsPerPage; 235 | } 236 | 237 | 238 | void 239 | ValueInternalArray::makeEndIterator( IteratorState &it ) const 240 | { 241 | makeIterator( it, size_ ); 242 | } 243 | 244 | 245 | ValueInternalArray::ValueInternalArray() 246 | : pages_( 0 ) 247 | , size_( 0 ) 248 | , pageCount_( 0 ) 249 | { 250 | } 251 | 252 | 253 | ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) 254 | : pages_( 0 ) 255 | , pageCount_( 0 ) 256 | , size_( other.size_ ) 257 | { 258 | PageIndex minNewPages = other.size_ / itemsPerPage; 259 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); 260 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, 261 | "ValueInternalArray::reserve(): bad reallocation" ); 262 | IteratorState itOther; 263 | other.makeBeginIterator( itOther ); 264 | Value *value; 265 | for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) 266 | { 267 | if ( index % itemsPerPage == 0 ) 268 | { 269 | PageIndex pageIndex = index / itemsPerPage; 270 | value = arrayAllocator()->allocateArrayPage(); 271 | pages_[pageIndex] = value; 272 | } 273 | new (value) Value( dereference( itOther ) ); 274 | } 275 | } 276 | 277 | 278 | ValueInternalArray & 279 | ValueInternalArray::operator =( const ValueInternalArray &other ) 280 | { 281 | ValueInternalArray temp( other ); 282 | swap( temp ); 283 | return *this; 284 | } 285 | 286 | 287 | ValueInternalArray::~ValueInternalArray() 288 | { 289 | // destroy all constructed items 290 | IteratorState it; 291 | IteratorState itEnd; 292 | makeBeginIterator( it); 293 | makeEndIterator( itEnd ); 294 | for ( ; !equals(it,itEnd); increment(it) ) 295 | { 296 | Value *value = &dereference(it); 297 | value->~Value(); 298 | } 299 | // release all pages 300 | PageIndex lastPageIndex = size_ / itemsPerPage; 301 | for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) 302 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); 303 | // release pages index 304 | arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); 305 | } 306 | 307 | 308 | void 309 | ValueInternalArray::swap( ValueInternalArray &other ) 310 | { 311 | Value **tempPages = pages_; 312 | pages_ = other.pages_; 313 | other.pages_ = tempPages; 314 | ArrayIndex tempSize = size_; 315 | size_ = other.size_; 316 | other.size_ = tempSize; 317 | PageIndex tempPageCount = pageCount_; 318 | pageCount_ = other.pageCount_; 319 | other.pageCount_ = tempPageCount; 320 | } 321 | 322 | void 323 | ValueInternalArray::clear() 324 | { 325 | ValueInternalArray dummy; 326 | swap( dummy ); 327 | } 328 | 329 | 330 | void 331 | ValueInternalArray::resize( ArrayIndex newSize ) 332 | { 333 | if ( newSize == 0 ) 334 | clear(); 335 | else if ( newSize < size_ ) 336 | { 337 | IteratorState it; 338 | IteratorState itEnd; 339 | makeIterator( it, newSize ); 340 | makeIterator( itEnd, size_ ); 341 | for ( ; !equals(it,itEnd); increment(it) ) 342 | { 343 | Value *value = &dereference(it); 344 | value->~Value(); 345 | } 346 | PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; 347 | PageIndex lastPageIndex = size_ / itemsPerPage; 348 | for ( ; pageIndex < lastPageIndex; ++pageIndex ) 349 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); 350 | size_ = newSize; 351 | } 352 | else if ( newSize > size_ ) 353 | resolveReference( newSize ); 354 | } 355 | 356 | 357 | void 358 | ValueInternalArray::makeIndexValid( ArrayIndex index ) 359 | { 360 | // Need to enlarge page index ? 361 | if ( index >= pageCount_ * itemsPerPage ) 362 | { 363 | PageIndex minNewPages = (index + 1) / itemsPerPage; 364 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); 365 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); 366 | } 367 | 368 | // Need to allocate new pages ? 369 | ArrayIndex nextPageIndex = 370 | (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage 371 | : size_; 372 | if ( nextPageIndex <= index ) 373 | { 374 | PageIndex pageIndex = nextPageIndex / itemsPerPage; 375 | PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; 376 | for ( ; pageToAllocate-- > 0; ++pageIndex ) 377 | pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); 378 | } 379 | 380 | // Initialize all new entries 381 | IteratorState it; 382 | IteratorState itEnd; 383 | makeIterator( it, size_ ); 384 | size_ = index + 1; 385 | makeIterator( itEnd, size_ ); 386 | for ( ; !equals(it,itEnd); increment(it) ) 387 | { 388 | Value *value = &dereference(it); 389 | new (value) Value(); // Construct a default value using placement new 390 | } 391 | } 392 | 393 | Value & 394 | ValueInternalArray::resolveReference( ArrayIndex index ) 395 | { 396 | if ( index >= size_ ) 397 | makeIndexValid( index ); 398 | return pages_[index/itemsPerPage][index%itemsPerPage]; 399 | } 400 | 401 | Value * 402 | ValueInternalArray::find( ArrayIndex index ) const 403 | { 404 | if ( index >= size_ ) 405 | return 0; 406 | return &(pages_[index/itemsPerPage][index%itemsPerPage]); 407 | } 408 | 409 | ValueInternalArray::ArrayIndex 410 | ValueInternalArray::size() const 411 | { 412 | return size_; 413 | } 414 | 415 | int 416 | ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) 417 | { 418 | return indexOf(y) - indexOf(x); 419 | } 420 | 421 | 422 | ValueInternalArray::ArrayIndex 423 | ValueInternalArray::indexOf( const IteratorState &iterator ) 424 | { 425 | if ( !iterator.array_ ) 426 | return ArrayIndex(-1); 427 | return ArrayIndex( 428 | (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage 429 | + iterator.currentItemIndex_ ); 430 | } 431 | 432 | 433 | int 434 | ValueInternalArray::compare( const ValueInternalArray &other ) const 435 | { 436 | int sizeDiff( size_ - other.size_ ); 437 | if ( sizeDiff != 0 ) 438 | return sizeDiff; 439 | 440 | for ( ArrayIndex index =0; index < size_; ++index ) 441 | { 442 | int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( 443 | other.pages_[index/itemsPerPage][index%itemsPerPage] ); 444 | if ( diff != 0 ) 445 | return diff; 446 | } 447 | return 0; 448 | } 449 | -------------------------------------------------------------------------------- /json/json_internalmap.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | // ////////////////////////////////////////////////////////////////// 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // class ValueInternalMap 8 | // ////////////////////////////////////////////////////////////////// 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | 12 | /** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); 13 | * This optimization is used by the fast allocator. 14 | */ 15 | ValueInternalLink::ValueInternalLink() 16 | : previous_( 0 ) 17 | , next_( 0 ) 18 | { 19 | } 20 | 21 | ValueInternalLink::~ValueInternalLink() 22 | { 23 | for ( int index =0; index < itemPerLink; ++index ) 24 | { 25 | if ( !items_[index].isItemAvailable() ) 26 | { 27 | if ( !items_[index].isMemberNameStatic() ) 28 | free( keys_[index] ); 29 | } 30 | else 31 | break; 32 | } 33 | } 34 | 35 | 36 | 37 | ValueMapAllocator::~ValueMapAllocator() 38 | { 39 | } 40 | 41 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 42 | class DefaultValueMapAllocator : public ValueMapAllocator 43 | { 44 | public: // overridden from ValueMapAllocator 45 | virtual ValueInternalMap *newMap() 46 | { 47 | return new ValueInternalMap(); 48 | } 49 | 50 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 51 | { 52 | return new ValueInternalMap( other ); 53 | } 54 | 55 | virtual void destructMap( ValueInternalMap *map ) 56 | { 57 | delete map; 58 | } 59 | 60 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 61 | { 62 | return new ValueInternalLink[size]; 63 | } 64 | 65 | virtual void releaseMapBuckets( ValueInternalLink *links ) 66 | { 67 | delete [] links; 68 | } 69 | 70 | virtual ValueInternalLink *allocateMapLink() 71 | { 72 | return new ValueInternalLink(); 73 | } 74 | 75 | virtual void releaseMapLink( ValueInternalLink *link ) 76 | { 77 | delete link; 78 | } 79 | }; 80 | #else 81 | /// @todo make this thread-safe (lock when accessign batch allocator) 82 | class DefaultValueMapAllocator : public ValueMapAllocator 83 | { 84 | public: // overridden from ValueMapAllocator 85 | virtual ValueInternalMap *newMap() 86 | { 87 | ValueInternalMap *map = mapsAllocator_.allocate(); 88 | new (map) ValueInternalMap(); // placement new 89 | return map; 90 | } 91 | 92 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 93 | { 94 | ValueInternalMap *map = mapsAllocator_.allocate(); 95 | new (map) ValueInternalMap( other ); // placement new 96 | return map; 97 | } 98 | 99 | virtual void destructMap( ValueInternalMap *map ) 100 | { 101 | if ( map ) 102 | { 103 | map->~ValueInternalMap(); 104 | mapsAllocator_.release( map ); 105 | } 106 | } 107 | 108 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 109 | { 110 | return new ValueInternalLink[size]; 111 | } 112 | 113 | virtual void releaseMapBuckets( ValueInternalLink *links ) 114 | { 115 | delete [] links; 116 | } 117 | 118 | virtual ValueInternalLink *allocateMapLink() 119 | { 120 | ValueInternalLink *link = linksAllocator_.allocate(); 121 | memset( link, 0, sizeof(ValueInternalLink) ); 122 | return link; 123 | } 124 | 125 | virtual void releaseMapLink( ValueInternalLink *link ) 126 | { 127 | link->~ValueInternalLink(); 128 | linksAllocator_.release( link ); 129 | } 130 | private: 131 | BatchAllocator mapsAllocator_; 132 | BatchAllocator linksAllocator_; 133 | }; 134 | #endif 135 | 136 | static ValueMapAllocator *&mapAllocator() 137 | { 138 | static DefaultValueMapAllocator defaultAllocator; 139 | static ValueMapAllocator *mapAllocator = &defaultAllocator; 140 | return mapAllocator; 141 | } 142 | 143 | static struct DummyMapAllocatorInitializer { 144 | DummyMapAllocatorInitializer() 145 | { 146 | mapAllocator(); // ensure mapAllocator() statics are initialized before main(). 147 | } 148 | } dummyMapAllocatorInitializer; 149 | 150 | 151 | 152 | // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. 153 | 154 | /* 155 | use linked list hash map. 156 | buckets array is a container. 157 | linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) 158 | value have extra state: valid, available, deleted 159 | */ 160 | 161 | 162 | ValueInternalMap::ValueInternalMap() 163 | : buckets_( 0 ) 164 | , tailLink_( 0 ) 165 | , bucketsSize_( 0 ) 166 | , itemCount_( 0 ) 167 | { 168 | } 169 | 170 | 171 | ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) 172 | : buckets_( 0 ) 173 | , tailLink_( 0 ) 174 | , bucketsSize_( 0 ) 175 | , itemCount_( 0 ) 176 | { 177 | reserve( other.itemCount_ ); 178 | IteratorState it; 179 | IteratorState itEnd; 180 | other.makeBeginIterator( it ); 181 | other.makeEndIterator( itEnd ); 182 | for ( ; !equals(it,itEnd); increment(it) ) 183 | { 184 | bool isStatic; 185 | const char *memberName = key( it, isStatic ); 186 | const Value &aValue = value( it ); 187 | resolveReference(memberName, isStatic) = aValue; 188 | } 189 | } 190 | 191 | 192 | ValueInternalMap & 193 | ValueInternalMap::operator =( const ValueInternalMap &other ) 194 | { 195 | ValueInternalMap dummy( other ); 196 | swap( dummy ); 197 | return *this; 198 | } 199 | 200 | 201 | ValueInternalMap::~ValueInternalMap() 202 | { 203 | if ( buckets_ ) 204 | { 205 | for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) 206 | { 207 | ValueInternalLink *link = buckets_[bucketIndex].next_; 208 | while ( link ) 209 | { 210 | ValueInternalLink *linkToRelease = link; 211 | link = link->next_; 212 | mapAllocator()->releaseMapLink( linkToRelease ); 213 | } 214 | } 215 | mapAllocator()->releaseMapBuckets( buckets_ ); 216 | } 217 | } 218 | 219 | 220 | void 221 | ValueInternalMap::swap( ValueInternalMap &other ) 222 | { 223 | ValueInternalLink *tempBuckets = buckets_; 224 | buckets_ = other.buckets_; 225 | other.buckets_ = tempBuckets; 226 | ValueInternalLink *tempTailLink = tailLink_; 227 | tailLink_ = other.tailLink_; 228 | other.tailLink_ = tempTailLink; 229 | BucketIndex tempBucketsSize = bucketsSize_; 230 | bucketsSize_ = other.bucketsSize_; 231 | other.bucketsSize_ = tempBucketsSize; 232 | BucketIndex tempItemCount = itemCount_; 233 | itemCount_ = other.itemCount_; 234 | other.itemCount_ = tempItemCount; 235 | } 236 | 237 | 238 | void 239 | ValueInternalMap::clear() 240 | { 241 | ValueInternalMap dummy; 242 | swap( dummy ); 243 | } 244 | 245 | 246 | ValueInternalMap::BucketIndex 247 | ValueInternalMap::size() const 248 | { 249 | return itemCount_; 250 | } 251 | 252 | bool 253 | ValueInternalMap::reserveDelta( BucketIndex growth ) 254 | { 255 | return reserve( itemCount_ + growth ); 256 | } 257 | 258 | bool 259 | ValueInternalMap::reserve( BucketIndex newItemCount ) 260 | { 261 | if ( !buckets_ && newItemCount > 0 ) 262 | { 263 | buckets_ = mapAllocator()->allocateMapBuckets( 1 ); 264 | bucketsSize_ = 1; 265 | tailLink_ = &buckets_[0]; 266 | } 267 | // BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; 268 | return true; 269 | } 270 | 271 | 272 | const Value * 273 | ValueInternalMap::find( const char *key ) const 274 | { 275 | if ( !bucketsSize_ ) 276 | return 0; 277 | HashKey hashedKey = hash( key ); 278 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 279 | for ( const ValueInternalLink *current = &buckets_[bucketIndex]; 280 | current != 0; 281 | current = current->next_ ) 282 | { 283 | for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) 284 | { 285 | if ( current->items_[index].isItemAvailable() ) 286 | return 0; 287 | if ( strcmp( key, current->keys_[index] ) == 0 ) 288 | return ¤t->items_[index]; 289 | } 290 | } 291 | return 0; 292 | } 293 | 294 | 295 | Value * 296 | ValueInternalMap::find( const char *key ) 297 | { 298 | const ValueInternalMap *constThis = this; 299 | return const_cast( constThis->find( key ) ); 300 | } 301 | 302 | 303 | Value & 304 | ValueInternalMap::resolveReference( const char *key, 305 | bool isStatic ) 306 | { 307 | HashKey hashedKey = hash( key ); 308 | if ( bucketsSize_ ) 309 | { 310 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 311 | ValueInternalLink **previous = 0; 312 | BucketIndex index; 313 | for ( ValueInternalLink *current = &buckets_[bucketIndex]; 314 | current != 0; 315 | previous = ¤t->next_, current = current->next_ ) 316 | { 317 | for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) 318 | { 319 | if ( current->items_[index].isItemAvailable() ) 320 | return setNewItem( key, isStatic, current, index ); 321 | if ( strcmp( key, current->keys_[index] ) == 0 ) 322 | return current->items_[index]; 323 | } 324 | } 325 | } 326 | 327 | reserveDelta( 1 ); 328 | return unsafeAdd( key, isStatic, hashedKey ); 329 | } 330 | 331 | 332 | void 333 | ValueInternalMap::remove( const char *key ) 334 | { 335 | HashKey hashedKey = hash( key ); 336 | if ( !bucketsSize_ ) 337 | return; 338 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 339 | for ( ValueInternalLink *link = &buckets_[bucketIndex]; 340 | link != 0; 341 | link = link->next_ ) 342 | { 343 | BucketIndex index; 344 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) 345 | { 346 | if ( link->items_[index].isItemAvailable() ) 347 | return; 348 | if ( strcmp( key, link->keys_[index] ) == 0 ) 349 | { 350 | doActualRemove( link, index, bucketIndex ); 351 | return; 352 | } 353 | } 354 | } 355 | } 356 | 357 | void 358 | ValueInternalMap::doActualRemove( ValueInternalLink *link, 359 | BucketIndex index, 360 | BucketIndex bucketIndex ) 361 | { 362 | // find last item of the bucket and swap it with the 'removed' one. 363 | // set removed items flags to 'available'. 364 | // if last page only contains 'available' items, then desallocate it (it's empty) 365 | ValueInternalLink *&lastLink = getLastLinkInBucket( index ); 366 | BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 367 | for ( ; 368 | lastItemIndex < ValueInternalLink::itemPerLink; 369 | ++lastItemIndex ) // may be optimized with dicotomic search 370 | { 371 | if ( lastLink->items_[lastItemIndex].isItemAvailable() ) 372 | break; 373 | } 374 | 375 | BucketIndex lastUsedIndex = lastItemIndex - 1; 376 | Value *valueToDelete = &link->items_[index]; 377 | Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; 378 | if ( valueToDelete != valueToPreserve ) 379 | valueToDelete->swap( *valueToPreserve ); 380 | if ( lastUsedIndex == 0 ) // page is now empty 381 | { // remove it from bucket linked list and delete it. 382 | ValueInternalLink *linkPreviousToLast = lastLink->previous_; 383 | if ( linkPreviousToLast != 0 ) // can not deleted bucket link. 384 | { 385 | mapAllocator()->releaseMapLink( lastLink ); 386 | linkPreviousToLast->next_ = 0; 387 | lastLink = linkPreviousToLast; 388 | } 389 | } 390 | else 391 | { 392 | Value dummy; 393 | valueToPreserve->swap( dummy ); // restore deleted to default Value. 394 | valueToPreserve->setItemUsed( false ); 395 | } 396 | --itemCount_; 397 | } 398 | 399 | 400 | ValueInternalLink *& 401 | ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) 402 | { 403 | if ( bucketIndex == bucketsSize_ - 1 ) 404 | return tailLink_; 405 | ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; 406 | if ( !previous ) 407 | previous = &buckets_[bucketIndex]; 408 | return previous; 409 | } 410 | 411 | 412 | Value & 413 | ValueInternalMap::setNewItem( const char *key, 414 | bool isStatic, 415 | ValueInternalLink *link, 416 | BucketIndex index ) 417 | { 418 | char *duplicatedKey = valueAllocator()->makeMemberName( key ); 419 | ++itemCount_; 420 | link->keys_[index] = duplicatedKey; 421 | link->items_[index].setItemUsed(); 422 | link->items_[index].setMemberNameIsStatic( isStatic ); 423 | return link->items_[index]; // items already default constructed. 424 | } 425 | 426 | 427 | Value & 428 | ValueInternalMap::unsafeAdd( const char *key, 429 | bool isStatic, 430 | HashKey hashedKey ) 431 | { 432 | JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); 433 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 434 | ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); 435 | ValueInternalLink *link = previousLink; 436 | BucketIndex index; 437 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) 438 | { 439 | if ( link->items_[index].isItemAvailable() ) 440 | break; 441 | } 442 | if ( index == ValueInternalLink::itemPerLink ) // need to add a new page 443 | { 444 | ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); 445 | index = 0; 446 | link->next_ = newLink; 447 | previousLink = newLink; 448 | link = newLink; 449 | } 450 | return setNewItem( key, isStatic, link, index ); 451 | } 452 | 453 | 454 | ValueInternalMap::HashKey 455 | ValueInternalMap::hash( const char *key ) const 456 | { 457 | HashKey hash = 0; 458 | while ( *key ) 459 | hash += *key++ * 37; 460 | return hash; 461 | } 462 | 463 | 464 | int 465 | ValueInternalMap::compare( const ValueInternalMap &other ) const 466 | { 467 | int sizeDiff( itemCount_ - other.itemCount_ ); 468 | if ( sizeDiff != 0 ) 469 | return sizeDiff; 470 | // Strict order guaranty is required. Compare all keys FIRST, then compare values. 471 | IteratorState it; 472 | IteratorState itEnd; 473 | makeBeginIterator( it ); 474 | makeEndIterator( itEnd ); 475 | for ( ; !equals(it,itEnd); increment(it) ) 476 | { 477 | if ( !other.find( key( it ) ) ) 478 | return 1; 479 | } 480 | 481 | // All keys are equals, let's compare values 482 | makeBeginIterator( it ); 483 | for ( ; !equals(it,itEnd); increment(it) ) 484 | { 485 | const Value *otherValue = other.find( key( it ) ); 486 | int valueDiff = value(it).compare( *otherValue ); 487 | if ( valueDiff != 0 ) 488 | return valueDiff; 489 | } 490 | return 0; 491 | } 492 | 493 | 494 | void 495 | ValueInternalMap::makeBeginIterator( IteratorState &it ) const 496 | { 497 | it.map_ = const_cast( this ); 498 | it.bucketIndex_ = 0; 499 | it.itemIndex_ = 0; 500 | it.link_ = buckets_; 501 | } 502 | 503 | 504 | void 505 | ValueInternalMap::makeEndIterator( IteratorState &it ) const 506 | { 507 | it.map_ = const_cast( this ); 508 | it.bucketIndex_ = bucketsSize_; 509 | it.itemIndex_ = 0; 510 | it.link_ = 0; 511 | } 512 | 513 | 514 | bool 515 | ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) 516 | { 517 | return x.map_ == other.map_ 518 | && x.bucketIndex_ == other.bucketIndex_ 519 | && x.link_ == other.link_ 520 | && x.itemIndex_ == other.itemIndex_; 521 | } 522 | 523 | 524 | void 525 | ValueInternalMap::incrementBucket( IteratorState &iterator ) 526 | { 527 | ++iterator.bucketIndex_; 528 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, 529 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); 530 | if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) 531 | iterator.link_ = 0; 532 | else 533 | iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); 534 | iterator.itemIndex_ = 0; 535 | } 536 | 537 | 538 | void 539 | ValueInternalMap::increment( IteratorState &iterator ) 540 | { 541 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); 542 | ++iterator.itemIndex_; 543 | if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) 544 | { 545 | JSON_ASSERT_MESSAGE( iterator.link_ != 0, 546 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); 547 | iterator.link_ = iterator.link_->next_; 548 | if ( iterator.link_ == 0 ) 549 | incrementBucket( iterator ); 550 | } 551 | else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) 552 | { 553 | incrementBucket( iterator ); 554 | } 555 | } 556 | 557 | 558 | void 559 | ValueInternalMap::decrement( IteratorState &iterator ) 560 | { 561 | if ( iterator.itemIndex_ == 0 ) 562 | { 563 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); 564 | if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) 565 | { 566 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); 567 | --(iterator.bucketIndex_); 568 | } 569 | iterator.link_ = iterator.link_->previous_; 570 | iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; 571 | } 572 | } 573 | 574 | 575 | const char * 576 | ValueInternalMap::key( const IteratorState &iterator ) 577 | { 578 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 579 | return iterator.link_->keys_[iterator.itemIndex_]; 580 | } 581 | 582 | const char * 583 | ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) 584 | { 585 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 586 | isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); 587 | return iterator.link_->keys_[iterator.itemIndex_]; 588 | } 589 | 590 | 591 | Value & 592 | ValueInternalMap::value( const IteratorState &iterator ) 593 | { 594 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 595 | return iterator.link_->items_[iterator.itemIndex_]; 596 | } 597 | 598 | 599 | int 600 | ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) 601 | { 602 | int offset = 0; 603 | IteratorState it = x; 604 | while ( !equals( it, y ) ) 605 | increment( it ); 606 | return offset; 607 | } 608 | -------------------------------------------------------------------------------- /json/json_writer.cpp: -------------------------------------------------------------------------------- 1 | #include "writer.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if _MSC_VER >= 1400 // VC++ 8.0 11 | #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. 12 | #endif 13 | 14 | namespace Json { 15 | 16 | static bool isControlCharacter(char ch) 17 | { 18 | return ch > 0 && ch <= 0x1F; 19 | } 20 | 21 | static bool containsControlCharacter( const char* str ) 22 | { 23 | while ( *str ) 24 | { 25 | if ( isControlCharacter( *(str++) ) ) 26 | return true; 27 | } 28 | return false; 29 | } 30 | static void uintToString( unsigned int value, 31 | char *¤t ) 32 | { 33 | *--current = 0; 34 | do 35 | { 36 | *--current = (value % 10) + '0'; 37 | value /= 10; 38 | } 39 | while ( value != 0 ); 40 | } 41 | 42 | std::string valueToString( Int value ) 43 | { 44 | char buffer[32]; 45 | char *current = buffer + sizeof(buffer); 46 | bool isNegative = value < 0; 47 | if ( isNegative ) 48 | value = -value; 49 | uintToString( UInt(value), current ); 50 | if ( isNegative ) 51 | *--current = '-'; 52 | assert( current >= buffer ); 53 | return current; 54 | } 55 | 56 | 57 | std::string valueToString( UInt value ) 58 | { 59 | char buffer[32]; 60 | char *current = buffer + sizeof(buffer); 61 | uintToString( value, current ); 62 | assert( current >= buffer ); 63 | return current; 64 | } 65 | 66 | std::string valueToString( double value ) 67 | { 68 | char buffer[32]; 69 | #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 70 | sprintf_s(buffer, sizeof(buffer), "%#f", value); 71 | #else 72 | sprintf(buffer, "%#f", value); 73 | #endif 74 | char* ch = buffer + strlen(buffer) - 1; 75 | if (*ch != '0') return buffer; // nothing to truncate, so save time 76 | while(ch > buffer && *ch == '0'){ 77 | --ch; 78 | } 79 | char* last_nonzero = ch; 80 | while(ch >= buffer){ 81 | switch(*ch){ 82 | case '0': 83 | case '1': 84 | case '2': 85 | case '3': 86 | case '4': 87 | case '5': 88 | case '6': 89 | case '7': 90 | case '8': 91 | case '9': 92 | --ch; 93 | continue; 94 | case '.': 95 | // Truncate zeroes to save bytes in output, but keep one. 96 | *(last_nonzero+2) = '\0'; 97 | return buffer; 98 | default: 99 | return buffer; 100 | } 101 | } 102 | return buffer; 103 | } 104 | 105 | 106 | std::string valueToString( bool value ) 107 | { 108 | return value ? "true" : "false"; 109 | } 110 | 111 | std::string valueToQuotedString( const char *value ) 112 | { 113 | // Not sure how to handle unicode... 114 | if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) 115 | return std::string("\"") + value + "\""; 116 | // We have to walk value and escape any special characters. 117 | // Appending to std::string is not efficient, but this should be rare. 118 | // (Note: forward slashes are *not* rare, but I am not escaping them.) 119 | unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL 120 | std::string result; 121 | result.reserve(maxsize); // to avoid lots of mallocs 122 | result += "\""; 123 | for (const char* c=value; *c != 0; ++c) 124 | { 125 | switch(*c) 126 | { 127 | case '\"': 128 | result += "\\\""; 129 | break; 130 | case '\\': 131 | result += "\\\\"; 132 | break; 133 | case '\b': 134 | result += "\\b"; 135 | break; 136 | case '\f': 137 | result += "\\f"; 138 | break; 139 | case '\n': 140 | result += "\\n"; 141 | break; 142 | case '\r': 143 | result += "\\r"; 144 | break; 145 | case '\t': 146 | result += "\\t"; 147 | break; 148 | //case '/': 149 | // Even though \/ is considered a legal escape in JSON, a bare 150 | // slash is also legal, so I see no reason to escape it. 151 | // (I hope I am not misunderstanding something. 152 | // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); 161 | result += oss.str(); 162 | } 163 | else 164 | { 165 | result += *c; 166 | } 167 | break; 168 | } 169 | } 170 | result += "\""; 171 | return result; 172 | } 173 | 174 | // Class Writer 175 | // ////////////////////////////////////////////////////////////////// 176 | Writer::~Writer() 177 | { 178 | } 179 | 180 | 181 | // Class FastWriter 182 | // ////////////////////////////////////////////////////////////////// 183 | 184 | FastWriter::FastWriter() 185 | : yamlCompatiblityEnabled_( false ) 186 | { 187 | } 188 | 189 | 190 | void 191 | FastWriter::enableYAMLCompatibility() 192 | { 193 | yamlCompatiblityEnabled_ = true; 194 | } 195 | 196 | 197 | std::string 198 | FastWriter::write( const Value &root ) 199 | { 200 | document_ = ""; 201 | writeValue( root ); 202 | document_ += "\n"; 203 | return document_; 204 | } 205 | 206 | 207 | void 208 | FastWriter::writeValue( const Value &value ) 209 | { 210 | switch ( value.type() ) 211 | { 212 | case nullValue: 213 | document_ += "null"; 214 | break; 215 | case intValue: 216 | document_ += valueToString( value.asInt() ); 217 | break; 218 | case uintValue: 219 | document_ += valueToString( value.asUInt() ); 220 | break; 221 | case realValue: 222 | document_ += valueToString( value.asDouble() ); 223 | break; 224 | case stringValue: 225 | document_ += valueToQuotedString( value.asCString() ); 226 | break; 227 | case booleanValue: 228 | document_ += valueToString( value.asBool() ); 229 | break; 230 | case arrayValue: 231 | { 232 | document_ += "["; 233 | int size = value.size(); 234 | for ( int index =0; index < size; ++index ) 235 | { 236 | if ( index > 0 ) 237 | document_ += ","; 238 | writeValue( value[index] ); 239 | } 240 | document_ += "]"; 241 | } 242 | break; 243 | case objectValue: 244 | { 245 | Value::Members members( value.getMemberNames() ); 246 | document_ += "{"; 247 | for ( Value::Members::iterator it = members.begin(); 248 | it != members.end(); 249 | ++it ) 250 | { 251 | const std::string &name = *it; 252 | if ( it != members.begin() ) 253 | document_ += ","; 254 | document_ += valueToQuotedString( name.c_str() ); 255 | document_ += yamlCompatiblityEnabled_ ? ": " 256 | : ":"; 257 | writeValue( value[name] ); 258 | } 259 | document_ += "}"; 260 | } 261 | break; 262 | } 263 | } 264 | 265 | 266 | // Class StyledWriter 267 | // ////////////////////////////////////////////////////////////////// 268 | 269 | StyledWriter::StyledWriter() 270 | : rightMargin_( 74 ) 271 | , indentSize_( 3 ) 272 | { 273 | } 274 | 275 | 276 | std::string 277 | StyledWriter::write( const Value &root ) 278 | { 279 | document_ = ""; 280 | addChildValues_ = false; 281 | indentString_ = ""; 282 | writeCommentBeforeValue( root ); 283 | writeValue( root ); 284 | writeCommentAfterValueOnSameLine( root ); 285 | document_ += "\n"; 286 | return document_; 287 | } 288 | 289 | 290 | void 291 | StyledWriter::writeValue( const Value &value ) 292 | { 293 | switch ( value.type() ) 294 | { 295 | case nullValue: 296 | pushValue( "null" ); 297 | break; 298 | case intValue: 299 | pushValue( valueToString( value.asInt() ) ); 300 | break; 301 | case uintValue: 302 | pushValue( valueToString( value.asUInt() ) ); 303 | break; 304 | case realValue: 305 | pushValue( valueToString( value.asDouble() ) ); 306 | break; 307 | case stringValue: 308 | pushValue( valueToQuotedString( value.asCString() ) ); 309 | break; 310 | case booleanValue: 311 | pushValue( valueToString( value.asBool() ) ); 312 | break; 313 | case arrayValue: 314 | writeArrayValue( value); 315 | break; 316 | case objectValue: 317 | { 318 | Value::Members members( value.getMemberNames() ); 319 | if ( members.empty() ) 320 | pushValue( "{}" ); 321 | else 322 | { 323 | writeWithIndent( "{" ); 324 | indent(); 325 | Value::Members::iterator it = members.begin(); 326 | while ( true ) 327 | { 328 | const std::string &name = *it; 329 | const Value &childValue = value[name]; 330 | writeCommentBeforeValue( childValue ); 331 | writeWithIndent( valueToQuotedString( name.c_str() ) ); 332 | document_ += " : "; 333 | writeValue( childValue ); 334 | if ( ++it == members.end() ) 335 | { 336 | writeCommentAfterValueOnSameLine( childValue ); 337 | break; 338 | } 339 | document_ += ","; 340 | writeCommentAfterValueOnSameLine( childValue ); 341 | } 342 | unindent(); 343 | writeWithIndent( "}" ); 344 | } 345 | } 346 | break; 347 | } 348 | } 349 | 350 | 351 | void 352 | StyledWriter::writeArrayValue( const Value &value ) 353 | { 354 | unsigned size = value.size(); 355 | if ( size == 0 ) 356 | pushValue( "[]" ); 357 | else 358 | { 359 | bool isArrayMultiLine = isMultineArray( value ); 360 | if ( isArrayMultiLine ) 361 | { 362 | writeWithIndent( "[" ); 363 | indent(); 364 | bool hasChildValue = !childValues_.empty(); 365 | unsigned index =0; 366 | while ( true ) 367 | { 368 | const Value &childValue = value[index]; 369 | writeCommentBeforeValue( childValue ); 370 | if ( hasChildValue ) 371 | writeWithIndent( childValues_[index] ); 372 | else 373 | { 374 | writeIndent(); 375 | writeValue( childValue ); 376 | } 377 | if ( ++index == size ) 378 | { 379 | writeCommentAfterValueOnSameLine( childValue ); 380 | break; 381 | } 382 | document_ += ","; 383 | writeCommentAfterValueOnSameLine( childValue ); 384 | } 385 | unindent(); 386 | writeWithIndent( "]" ); 387 | } 388 | else // output on a single line 389 | { 390 | assert( childValues_.size() == size ); 391 | document_ += "[ "; 392 | for ( unsigned index =0; index < size; ++index ) 393 | { 394 | if ( index > 0 ) 395 | document_ += ", "; 396 | document_ += childValues_[index]; 397 | } 398 | document_ += " ]"; 399 | } 400 | } 401 | } 402 | 403 | 404 | bool 405 | StyledWriter::isMultineArray( const Value &value ) 406 | { 407 | int size = value.size(); 408 | bool isMultiLine = size*3 >= rightMargin_ ; 409 | childValues_.clear(); 410 | for ( int index =0; index < size && !isMultiLine; ++index ) 411 | { 412 | const Value &childValue = value[index]; 413 | isMultiLine = isMultiLine || 414 | ( (childValue.isArray() || childValue.isObject()) && 415 | childValue.size() > 0 ); 416 | } 417 | if ( !isMultiLine ) // check if line length > max line length 418 | { 419 | childValues_.reserve( size ); 420 | addChildValues_ = true; 421 | int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' 422 | for ( int index =0; index < size && !isMultiLine; ++index ) 423 | { 424 | writeValue( value[index] ); 425 | lineLength += int( childValues_[index].length() ); 426 | isMultiLine = isMultiLine && hasCommentForValue( value[index] ); 427 | } 428 | addChildValues_ = false; 429 | isMultiLine = isMultiLine || lineLength >= rightMargin_; 430 | } 431 | return isMultiLine; 432 | } 433 | 434 | 435 | void 436 | StyledWriter::pushValue( const std::string &value ) 437 | { 438 | if ( addChildValues_ ) 439 | childValues_.push_back( value ); 440 | else 441 | document_ += value; 442 | } 443 | 444 | 445 | void 446 | StyledWriter::writeIndent() 447 | { 448 | if ( !document_.empty() ) 449 | { 450 | char last = document_[document_.length()-1]; 451 | if ( last == ' ' ) // already indented 452 | return; 453 | if ( last != '\n' ) // Comments may add new-line 454 | document_ += '\n'; 455 | } 456 | document_ += indentString_; 457 | } 458 | 459 | 460 | void 461 | StyledWriter::writeWithIndent( const std::string &value ) 462 | { 463 | writeIndent(); 464 | document_ += value; 465 | } 466 | 467 | 468 | void 469 | StyledWriter::indent() 470 | { 471 | indentString_ += std::string( indentSize_, ' ' ); 472 | } 473 | 474 | 475 | void 476 | StyledWriter::unindent() 477 | { 478 | assert( int(indentString_.size()) >= indentSize_ ); 479 | indentString_.resize( indentString_.size() - indentSize_ ); 480 | } 481 | 482 | 483 | void 484 | StyledWriter::writeCommentBeforeValue( const Value &root ) 485 | { 486 | if ( !root.hasComment( commentBefore ) ) 487 | return; 488 | document_ += normalizeEOL( root.getComment( commentBefore ) ); 489 | document_ += "\n"; 490 | } 491 | 492 | 493 | void 494 | StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) 495 | { 496 | if ( root.hasComment( commentAfterOnSameLine ) ) 497 | document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); 498 | 499 | if ( root.hasComment( commentAfter ) ) 500 | { 501 | document_ += "\n"; 502 | document_ += normalizeEOL( root.getComment( commentAfter ) ); 503 | document_ += "\n"; 504 | } 505 | } 506 | 507 | 508 | bool 509 | StyledWriter::hasCommentForValue( const Value &value ) 510 | { 511 | return value.hasComment( commentBefore ) 512 | || value.hasComment( commentAfterOnSameLine ) 513 | || value.hasComment( commentAfter ); 514 | } 515 | 516 | 517 | std::string 518 | StyledWriter::normalizeEOL( const std::string &text ) 519 | { 520 | std::string normalized; 521 | normalized.reserve( text.length() ); 522 | const char *begin = text.c_str(); 523 | const char *end = begin + text.length(); 524 | const char *current = begin; 525 | while ( current != end ) 526 | { 527 | char c = *current++; 528 | if ( c == '\r' ) // mac or dos EOL 529 | { 530 | if ( *current == '\n' ) // convert dos EOL 531 | ++current; 532 | normalized += '\n'; 533 | } 534 | else // handle unix EOL & other char 535 | normalized += c; 536 | } 537 | return normalized; 538 | } 539 | 540 | 541 | // Class StyledStreamWriter 542 | // ////////////////////////////////////////////////////////////////// 543 | 544 | StyledStreamWriter::StyledStreamWriter( std::string indentation ) 545 | : document_(NULL) 546 | , rightMargin_( 74 ) 547 | , indentation_( indentation ) 548 | { 549 | } 550 | 551 | 552 | void 553 | StyledStreamWriter::write( std::ostream &out, const Value &root ) 554 | { 555 | document_ = &out; 556 | addChildValues_ = false; 557 | indentString_ = ""; 558 | writeCommentBeforeValue( root ); 559 | writeValue( root ); 560 | writeCommentAfterValueOnSameLine( root ); 561 | *document_ << "\n"; 562 | document_ = NULL; // Forget the stream, for safety. 563 | } 564 | 565 | 566 | void 567 | StyledStreamWriter::writeValue( const Value &value ) 568 | { 569 | switch ( value.type() ) 570 | { 571 | case nullValue: 572 | pushValue( "null" ); 573 | break; 574 | case intValue: 575 | pushValue( valueToString( value.asInt() ) ); 576 | break; 577 | case uintValue: 578 | pushValue( valueToString( value.asUInt() ) ); 579 | break; 580 | case realValue: 581 | pushValue( valueToString( value.asDouble() ) ); 582 | break; 583 | case stringValue: 584 | pushValue( valueToQuotedString( value.asCString() ) ); 585 | break; 586 | case booleanValue: 587 | pushValue( valueToString( value.asBool() ) ); 588 | break; 589 | case arrayValue: 590 | writeArrayValue( value); 591 | break; 592 | case objectValue: 593 | { 594 | Value::Members members( value.getMemberNames() ); 595 | if ( members.empty() ) 596 | pushValue( "{}" ); 597 | else 598 | { 599 | writeWithIndent( "{" ); 600 | indent(); 601 | Value::Members::iterator it = members.begin(); 602 | while ( true ) 603 | { 604 | const std::string &name = *it; 605 | const Value &childValue = value[name]; 606 | writeCommentBeforeValue( childValue ); 607 | writeWithIndent( valueToQuotedString( name.c_str() ) ); 608 | *document_ << " : "; 609 | writeValue( childValue ); 610 | if ( ++it == members.end() ) 611 | { 612 | writeCommentAfterValueOnSameLine( childValue ); 613 | break; 614 | } 615 | *document_ << ","; 616 | writeCommentAfterValueOnSameLine( childValue ); 617 | } 618 | unindent(); 619 | writeWithIndent( "}" ); 620 | } 621 | } 622 | break; 623 | } 624 | } 625 | 626 | 627 | void 628 | StyledStreamWriter::writeArrayValue( const Value &value ) 629 | { 630 | unsigned size = value.size(); 631 | if ( size == 0 ) 632 | pushValue( "[]" ); 633 | else 634 | { 635 | bool isArrayMultiLine = isMultineArray( value ); 636 | if ( isArrayMultiLine ) 637 | { 638 | writeWithIndent( "[" ); 639 | indent(); 640 | bool hasChildValue = !childValues_.empty(); 641 | unsigned index =0; 642 | while ( true ) 643 | { 644 | const Value &childValue = value[index]; 645 | writeCommentBeforeValue( childValue ); 646 | if ( hasChildValue ) 647 | writeWithIndent( childValues_[index] ); 648 | else 649 | { 650 | writeIndent(); 651 | writeValue( childValue ); 652 | } 653 | if ( ++index == size ) 654 | { 655 | writeCommentAfterValueOnSameLine( childValue ); 656 | break; 657 | } 658 | *document_ << ","; 659 | writeCommentAfterValueOnSameLine( childValue ); 660 | } 661 | unindent(); 662 | writeWithIndent( "]" ); 663 | } 664 | else // output on a single line 665 | { 666 | assert( childValues_.size() == size ); 667 | *document_ << "[ "; 668 | for ( unsigned index =0; index < size; ++index ) 669 | { 670 | if ( index > 0 ) 671 | *document_ << ", "; 672 | *document_ << childValues_[index]; 673 | } 674 | *document_ << " ]"; 675 | } 676 | } 677 | } 678 | 679 | 680 | bool 681 | StyledStreamWriter::isMultineArray( const Value &value ) 682 | { 683 | int size = value.size(); 684 | bool isMultiLine = size*3 >= rightMargin_ ; 685 | childValues_.clear(); 686 | for ( int index =0; index < size && !isMultiLine; ++index ) 687 | { 688 | const Value &childValue = value[index]; 689 | isMultiLine = isMultiLine || 690 | ( (childValue.isArray() || childValue.isObject()) && 691 | childValue.size() > 0 ); 692 | } 693 | if ( !isMultiLine ) // check if line length > max line length 694 | { 695 | childValues_.reserve( size ); 696 | addChildValues_ = true; 697 | int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' 698 | for ( int index =0; index < size && !isMultiLine; ++index ) 699 | { 700 | writeValue( value[index] ); 701 | lineLength += int( childValues_[index].length() ); 702 | isMultiLine = isMultiLine && hasCommentForValue( value[index] ); 703 | } 704 | addChildValues_ = false; 705 | isMultiLine = isMultiLine || lineLength >= rightMargin_; 706 | } 707 | return isMultiLine; 708 | } 709 | 710 | 711 | void 712 | StyledStreamWriter::pushValue( const std::string &value ) 713 | { 714 | if ( addChildValues_ ) 715 | childValues_.push_back( value ); 716 | else 717 | *document_ << value; 718 | } 719 | 720 | 721 | void 722 | StyledStreamWriter::writeIndent() 723 | { 724 | /* 725 | Some comments in this method would have been nice. ;-) 726 | 727 | if ( !document_.empty() ) 728 | { 729 | char last = document_[document_.length()-1]; 730 | if ( last == ' ' ) // already indented 731 | return; 732 | if ( last != '\n' ) // Comments may add new-line 733 | *document_ << '\n'; 734 | } 735 | */ 736 | *document_ << '\n' << indentString_; 737 | } 738 | 739 | 740 | void 741 | StyledStreamWriter::writeWithIndent( const std::string &value ) 742 | { 743 | writeIndent(); 744 | *document_ << value; 745 | } 746 | 747 | 748 | void 749 | StyledStreamWriter::indent() 750 | { 751 | indentString_ += indentation_; 752 | } 753 | 754 | 755 | void 756 | StyledStreamWriter::unindent() 757 | { 758 | assert( indentString_.size() >= indentation_.size() ); 759 | indentString_.resize( indentString_.size() - indentation_.size() ); 760 | } 761 | 762 | 763 | void 764 | StyledStreamWriter::writeCommentBeforeValue( const Value &root ) 765 | { 766 | if ( !root.hasComment( commentBefore ) ) 767 | return; 768 | *document_ << normalizeEOL( root.getComment( commentBefore ) ); 769 | *document_ << "\n"; 770 | } 771 | 772 | 773 | void 774 | StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) 775 | { 776 | if ( root.hasComment( commentAfterOnSameLine ) ) 777 | *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); 778 | 779 | if ( root.hasComment( commentAfter ) ) 780 | { 781 | *document_ << "\n"; 782 | *document_ << normalizeEOL( root.getComment( commentAfter ) ); 783 | *document_ << "\n"; 784 | } 785 | } 786 | 787 | 788 | bool 789 | StyledStreamWriter::hasCommentForValue( const Value &value ) 790 | { 791 | return value.hasComment( commentBefore ) 792 | || value.hasComment( commentAfterOnSameLine ) 793 | || value.hasComment( commentAfter ); 794 | } 795 | 796 | 797 | std::string 798 | StyledStreamWriter::normalizeEOL( const std::string &text ) 799 | { 800 | std::string normalized; 801 | normalized.reserve( text.length() ); 802 | const char *begin = text.c_str(); 803 | const char *end = begin + text.length(); 804 | const char *current = begin; 805 | while ( current != end ) 806 | { 807 | char c = *current++; 808 | if ( c == '\r' ) // mac or dos EOL 809 | { 810 | if ( *current == '\n' ) // convert dos EOL 811 | ++current; 812 | normalized += '\n'; 813 | } 814 | else // handle unix EOL & other char 815 | normalized += c; 816 | } 817 | return normalized; 818 | } 819 | 820 | 821 | std::ostream& operator<<( std::ostream &sout, const Value &root ) 822 | { 823 | Json::StyledStreamWriter writer; 824 | writer.write(sout, root); 825 | return sout; 826 | } 827 | 828 | 829 | } // namespace Json 830 | -------------------------------------------------------------------------------- /json/json_reader.cpp: -------------------------------------------------------------------------------- 1 | #include "reader.h" 2 | #include "value.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if _MSC_VER >= 1400 // VC++ 8.0 11 | #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. 12 | #endif 13 | 14 | namespace Json { 15 | 16 | // Implementation of class Features 17 | // //////////////////////////////// 18 | 19 | Features::Features() 20 | : allowComments_( true ) 21 | , strictRoot_( false ) 22 | { 23 | } 24 | 25 | 26 | Features 27 | Features::all() 28 | { 29 | return Features(); 30 | } 31 | 32 | 33 | Features 34 | Features::strictMode() 35 | { 36 | Features features; 37 | features.allowComments_ = false; 38 | features.strictRoot_ = true; 39 | return features; 40 | } 41 | 42 | // Implementation of class Reader 43 | // //////////////////////////////// 44 | 45 | 46 | static inline bool 47 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) 48 | { 49 | return c == c1 || c == c2 || c == c3 || c == c4; 50 | } 51 | 52 | static inline bool 53 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) 54 | { 55 | return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; 56 | } 57 | 58 | 59 | static bool 60 | containsNewLine( Reader::Location begin, 61 | Reader::Location end ) 62 | { 63 | for ( ;begin < end; ++begin ) 64 | if ( *begin == '\n' || *begin == '\r' ) 65 | return true; 66 | return false; 67 | } 68 | 69 | static std::string codePointToUTF8(unsigned int cp) 70 | { 71 | std::string result; 72 | 73 | // based on description from http://en.wikipedia.org/wiki/UTF-8 74 | 75 | if (cp <= 0x7f) 76 | { 77 | result.resize(1); 78 | result[0] = static_cast(cp); 79 | } 80 | else if (cp <= 0x7FF) 81 | { 82 | result.resize(2); 83 | result[1] = static_cast(0x80 | (0x3f & cp)); 84 | result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); 85 | } 86 | else if (cp <= 0xFFFF) 87 | { 88 | result.resize(3); 89 | result[2] = static_cast(0x80 | (0x3f & cp)); 90 | result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); 91 | result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); 92 | } 93 | else if (cp <= 0x10FFFF) 94 | { 95 | result.resize(4); 96 | result[3] = static_cast(0x80 | (0x3f & cp)); 97 | result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); 98 | result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); 99 | result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); 100 | } 101 | 102 | return result; 103 | } 104 | 105 | 106 | // Class Reader 107 | // ////////////////////////////////////////////////////////////////// 108 | 109 | Reader::Reader() 110 | : features_( Features::all() ) 111 | { 112 | } 113 | 114 | 115 | Reader::Reader( const Features &features ) 116 | : features_( features ) 117 | { 118 | } 119 | 120 | 121 | bool 122 | Reader::parse( const std::string &document, 123 | Value &root, 124 | bool collectComments ) 125 | { 126 | document_ = document; 127 | const char *begin = document_.c_str(); 128 | const char *end = begin + document_.length(); 129 | return parse( begin, end, root, collectComments ); 130 | } 131 | 132 | 133 | bool 134 | Reader::parse( std::istream& sin, 135 | Value &root, 136 | bool collectComments ) 137 | { 138 | //std::istream_iterator begin(sin); 139 | //std::istream_iterator end; 140 | // Those would allow streamed input from a file, if parse() were a 141 | // template function. 142 | 143 | // Since std::string is reference-counted, this at least does not 144 | // create an extra copy. 145 | std::string doc; 146 | std::getline(sin, doc, (char)EOF); 147 | return parse( doc, root, collectComments ); 148 | } 149 | 150 | bool 151 | Reader::parse( const char *beginDoc, const char *endDoc, 152 | Value &root, 153 | bool collectComments ) 154 | { 155 | if ( !features_.allowComments_ ) 156 | { 157 | collectComments = false; 158 | } 159 | 160 | begin_ = beginDoc; 161 | end_ = endDoc; 162 | collectComments_ = collectComments; 163 | current_ = begin_; 164 | lastValueEnd_ = 0; 165 | lastValue_ = 0; 166 | commentsBefore_ = ""; 167 | errors_.clear(); 168 | while ( !nodes_.empty() ) 169 | nodes_.pop(); 170 | nodes_.push( &root ); 171 | 172 | bool successful = readValue(); 173 | Token token; 174 | skipCommentTokens( token ); 175 | if ( collectComments_ && !commentsBefore_.empty() ) 176 | root.setComment( commentsBefore_, commentAfter ); 177 | if ( features_.strictRoot_ ) 178 | { 179 | if ( !root.isArray() && !root.isObject() ) 180 | { 181 | // Set error location to start of doc, ideally should be first token found in doc 182 | token.type_ = tokenError; 183 | token.start_ = beginDoc; 184 | token.end_ = endDoc; 185 | addError( "A valid JSON document must be either an array or an object value.", 186 | token ); 187 | return false; 188 | } 189 | } 190 | return successful; 191 | } 192 | 193 | 194 | bool 195 | Reader::readValue() 196 | { 197 | Token token; 198 | skipCommentTokens( token ); 199 | bool successful = true; 200 | 201 | if ( collectComments_ && !commentsBefore_.empty() ) 202 | { 203 | currentValue().setComment( commentsBefore_, commentBefore ); 204 | commentsBefore_ = ""; 205 | } 206 | 207 | 208 | switch ( token.type_ ) 209 | { 210 | case tokenObjectBegin: 211 | successful = readObject( token ); 212 | break; 213 | case tokenArrayBegin: 214 | successful = readArray( token ); 215 | break; 216 | case tokenNumber: 217 | successful = decodeNumber( token ); 218 | break; 219 | case tokenString: 220 | successful = decodeString( token ); 221 | break; 222 | case tokenTrue: 223 | currentValue() = true; 224 | break; 225 | case tokenFalse: 226 | currentValue() = false; 227 | break; 228 | case tokenNull: 229 | currentValue() = Value(); 230 | break; 231 | default: 232 | return addError( "Syntax error: value, object or array expected.", token ); 233 | } 234 | 235 | if ( collectComments_ ) 236 | { 237 | lastValueEnd_ = current_; 238 | lastValue_ = ¤tValue(); 239 | } 240 | 241 | return successful; 242 | } 243 | 244 | 245 | void 246 | Reader::skipCommentTokens( Token &token ) 247 | { 248 | if ( features_.allowComments_ ) 249 | { 250 | do 251 | { 252 | readToken( token ); 253 | } 254 | while ( token.type_ == tokenComment ); 255 | } 256 | else 257 | { 258 | readToken( token ); 259 | } 260 | } 261 | 262 | 263 | bool 264 | Reader::expectToken( TokenType type, Token &token, const char *message ) 265 | { 266 | readToken( token ); 267 | if ( token.type_ != type ) 268 | return addError( message, token ); 269 | return true; 270 | } 271 | 272 | 273 | bool 274 | Reader::readToken( Token &token ) 275 | { 276 | skipSpaces(); 277 | token.start_ = current_; 278 | Char c = getNextChar(); 279 | bool ok = true; 280 | switch ( c ) 281 | { 282 | case '{': 283 | token.type_ = tokenObjectBegin; 284 | break; 285 | case '}': 286 | token.type_ = tokenObjectEnd; 287 | break; 288 | case '[': 289 | token.type_ = tokenArrayBegin; 290 | break; 291 | case ']': 292 | token.type_ = tokenArrayEnd; 293 | break; 294 | case '"': 295 | token.type_ = tokenString; 296 | ok = readString(); 297 | break; 298 | case '/': 299 | token.type_ = tokenComment; 300 | ok = readComment(); 301 | break; 302 | case '0': 303 | case '1': 304 | case '2': 305 | case '3': 306 | case '4': 307 | case '5': 308 | case '6': 309 | case '7': 310 | case '8': 311 | case '9': 312 | case '-': 313 | token.type_ = tokenNumber; 314 | readNumber(); 315 | break; 316 | case 't': 317 | token.type_ = tokenTrue; 318 | ok = match( "rue", 3 ); 319 | break; 320 | case 'f': 321 | token.type_ = tokenFalse; 322 | ok = match( "alse", 4 ); 323 | break; 324 | case 'n': 325 | token.type_ = tokenNull; 326 | ok = match( "ull", 3 ); 327 | break; 328 | case ',': 329 | token.type_ = tokenArraySeparator; 330 | break; 331 | case ':': 332 | token.type_ = tokenMemberSeparator; 333 | break; 334 | case 0: 335 | token.type_ = tokenEndOfStream; 336 | break; 337 | default: 338 | ok = false; 339 | break; 340 | } 341 | if ( !ok ) 342 | token.type_ = tokenError; 343 | token.end_ = current_; 344 | return true; 345 | } 346 | 347 | 348 | void 349 | Reader::skipSpaces() 350 | { 351 | while ( current_ != end_ ) 352 | { 353 | Char c = *current_; 354 | if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) 355 | ++current_; 356 | else 357 | break; 358 | } 359 | } 360 | 361 | 362 | bool 363 | Reader::match( Location pattern, 364 | int patternLength ) 365 | { 366 | if ( end_ - current_ < patternLength ) 367 | return false; 368 | int index = patternLength; 369 | while ( index-- ) 370 | if ( current_[index] != pattern[index] ) 371 | return false; 372 | current_ += patternLength; 373 | return true; 374 | } 375 | 376 | 377 | bool 378 | Reader::readComment() 379 | { 380 | Location commentBegin = current_ - 1; 381 | Char c = getNextChar(); 382 | bool successful = false; 383 | if ( c == '*' ) 384 | successful = readCStyleComment(); 385 | else if ( c == '/' ) 386 | successful = readCppStyleComment(); 387 | if ( !successful ) 388 | return false; 389 | 390 | if ( collectComments_ ) 391 | { 392 | CommentPlacement placement = commentBefore; 393 | if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) 394 | { 395 | if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) 396 | placement = commentAfterOnSameLine; 397 | } 398 | 399 | addComment( commentBegin, current_, placement ); 400 | } 401 | return true; 402 | } 403 | 404 | 405 | void 406 | Reader::addComment( Location begin, 407 | Location end, 408 | CommentPlacement placement ) 409 | { 410 | assert( collectComments_ ); 411 | if ( placement == commentAfterOnSameLine ) 412 | { 413 | assert( lastValue_ != 0 ); 414 | lastValue_->setComment( std::string( begin, end ), placement ); 415 | } 416 | else 417 | { 418 | if ( !commentsBefore_.empty() ) 419 | commentsBefore_ += "\n"; 420 | commentsBefore_ += std::string( begin, end ); 421 | } 422 | } 423 | 424 | 425 | bool 426 | Reader::readCStyleComment() 427 | { 428 | while ( current_ != end_ ) 429 | { 430 | Char c = getNextChar(); 431 | if ( c == '*' && *current_ == '/' ) 432 | break; 433 | } 434 | return getNextChar() == '/'; 435 | } 436 | 437 | 438 | bool 439 | Reader::readCppStyleComment() 440 | { 441 | while ( current_ != end_ ) 442 | { 443 | Char c = getNextChar(); 444 | if ( c == '\r' || c == '\n' ) 445 | break; 446 | } 447 | return true; 448 | } 449 | 450 | 451 | void 452 | Reader::readNumber() 453 | { 454 | while ( current_ != end_ ) 455 | { 456 | if ( !(*current_ >= '0' && *current_ <= '9') && 457 | !in( *current_, '.', 'e', 'E', '+', '-' ) ) 458 | break; 459 | ++current_; 460 | } 461 | } 462 | 463 | bool 464 | Reader::readString() 465 | { 466 | Char c = 0; 467 | while ( current_ != end_ ) 468 | { 469 | c = getNextChar(); 470 | if ( c == '\\' ) 471 | getNextChar(); 472 | else if ( c == '"' ) 473 | break; 474 | } 475 | return c == '"'; 476 | } 477 | 478 | 479 | bool 480 | Reader::readObject( Token &tokenStart ) 481 | { 482 | Token tokenName; 483 | std::string name; 484 | currentValue() = Value( objectValue ); 485 | while ( readToken( tokenName ) ) 486 | { 487 | bool initialTokenOk = true; 488 | while ( tokenName.type_ == tokenComment && initialTokenOk ) 489 | initialTokenOk = readToken( tokenName ); 490 | if ( !initialTokenOk ) 491 | break; 492 | if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object 493 | return true; 494 | if ( tokenName.type_ != tokenString ) 495 | break; 496 | 497 | name = ""; 498 | if ( !decodeString( tokenName, name ) ) 499 | return recoverFromError( tokenObjectEnd ); 500 | 501 | Token colon; 502 | if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) 503 | { 504 | return addErrorAndRecover( "Missing ':' after object member name", 505 | colon, 506 | tokenObjectEnd ); 507 | } 508 | Value &value = currentValue()[ name ]; 509 | nodes_.push( &value ); 510 | bool ok = readValue(); 511 | nodes_.pop(); 512 | if ( !ok ) // error already set 513 | return recoverFromError( tokenObjectEnd ); 514 | 515 | Token comma; 516 | if ( !readToken( comma ) 517 | || ( comma.type_ != tokenObjectEnd && 518 | comma.type_ != tokenArraySeparator && 519 | comma.type_ != tokenComment ) ) 520 | { 521 | return addErrorAndRecover( "Missing ',' or '}' in object declaration", 522 | comma, 523 | tokenObjectEnd ); 524 | } 525 | bool finalizeTokenOk = true; 526 | while ( comma.type_ == tokenComment && 527 | finalizeTokenOk ) 528 | finalizeTokenOk = readToken( comma ); 529 | if ( comma.type_ == tokenObjectEnd ) 530 | return true; 531 | } 532 | return addErrorAndRecover( "Missing '}' or object member name", 533 | tokenName, 534 | tokenObjectEnd ); 535 | } 536 | 537 | 538 | bool 539 | Reader::readArray( Token &tokenStart ) 540 | { 541 | currentValue() = Value( arrayValue ); 542 | skipSpaces(); 543 | if ( *current_ == ']' ) // empty array 544 | { 545 | Token endArray; 546 | readToken( endArray ); 547 | return true; 548 | } 549 | int index = 0; 550 | while ( true ) 551 | { 552 | Value &value = currentValue()[ index++ ]; 553 | nodes_.push( &value ); 554 | bool ok = readValue(); 555 | nodes_.pop(); 556 | if ( !ok ) // error already set 557 | return recoverFromError( tokenArrayEnd ); 558 | 559 | Token token; 560 | // Accept Comment after last item in the array. 561 | ok = readToken( token ); 562 | while ( token.type_ == tokenComment && ok ) 563 | { 564 | ok = readToken( token ); 565 | } 566 | bool badTokenType = ( token.type_ == tokenArraySeparator && 567 | token.type_ == tokenArrayEnd ); 568 | if ( !ok || badTokenType ) 569 | { 570 | return addErrorAndRecover( "Missing ',' or ']' in array declaration", 571 | token, 572 | tokenArrayEnd ); 573 | } 574 | if ( token.type_ == tokenArrayEnd ) 575 | break; 576 | } 577 | return true; 578 | } 579 | 580 | 581 | bool 582 | Reader::decodeNumber( Token &token ) 583 | { 584 | bool isDouble = false; 585 | for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) 586 | { 587 | isDouble = isDouble 588 | || in( *inspect, '.', 'e', 'E', '+' ) 589 | || ( *inspect == '-' && inspect != token.start_ ); 590 | } 591 | if ( isDouble ) 592 | return decodeDouble( token ); 593 | Location current = token.start_; 594 | bool isNegative = *current == '-'; 595 | if ( isNegative ) 596 | ++current; 597 | Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) 598 | : Value::maxUInt) / 10; 599 | Value::UInt value = 0; 600 | while ( current < token.end_ ) 601 | { 602 | Char c = *current++; 603 | if ( c < '0' || c > '9' ) 604 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); 605 | if ( value >= threshold ) 606 | return decodeDouble( token ); 607 | value = value * 10 + Value::UInt(c - '0'); 608 | } 609 | if ( isNegative ) 610 | currentValue() = -Value::Int( value ); 611 | else if ( value <= Value::UInt(Value::maxInt) ) 612 | currentValue() = Value::Int( value ); 613 | else 614 | currentValue() = value; 615 | return true; 616 | } 617 | 618 | 619 | bool 620 | Reader::decodeDouble( Token &token ) 621 | { 622 | double value = 0; 623 | const int bufferSize = 32; 624 | int count; 625 | int length = int(token.end_ - token.start_); 626 | if ( length <= bufferSize ) 627 | { 628 | Char buffer[bufferSize]; 629 | memcpy( buffer, token.start_, length ); 630 | buffer[length] = 0; 631 | count = sscanf( buffer, "%lf", &value ); 632 | } 633 | else 634 | { 635 | std::string buffer( token.start_, token.end_ ); 636 | count = sscanf( buffer.c_str(), "%lf", &value ); 637 | } 638 | 639 | if ( count != 1 ) 640 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); 641 | currentValue() = value; 642 | return true; 643 | } 644 | 645 | 646 | bool 647 | Reader::decodeString( Token &token ) 648 | { 649 | std::string decoded; 650 | if ( !decodeString( token, decoded ) ) 651 | return false; 652 | currentValue() = decoded; 653 | return true; 654 | } 655 | 656 | 657 | bool 658 | Reader::decodeString( Token &token, std::string &decoded ) 659 | { 660 | decoded.reserve( token.end_ - token.start_ - 2 ); 661 | Location current = token.start_ + 1; // skip '"' 662 | Location end = token.end_ - 1; // do not include '"' 663 | while ( current != end ) 664 | { 665 | Char c = *current++; 666 | if ( c == '"' ) 667 | break; 668 | else if ( c == '\\' ) 669 | { 670 | if ( current == end ) 671 | return addError( "Empty escape sequence in string", token, current ); 672 | Char escape = *current++; 673 | switch ( escape ) 674 | { 675 | case '"': decoded += '"'; break; 676 | case '/': decoded += '/'; break; 677 | case '\\': decoded += '\\'; break; 678 | case 'b': decoded += '\b'; break; 679 | case 'f': decoded += '\f'; break; 680 | case 'n': decoded += '\n'; break; 681 | case 'r': decoded += '\r'; break; 682 | case 't': decoded += '\t'; break; 683 | case 'u': 684 | { 685 | unsigned int unicode; 686 | if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) 687 | return false; 688 | decoded += codePointToUTF8(unicode); 689 | } 690 | break; 691 | default: 692 | return addError( "Bad escape sequence in string", token, current ); 693 | } 694 | } 695 | else 696 | { 697 | decoded += c; 698 | } 699 | } 700 | return true; 701 | } 702 | 703 | bool 704 | Reader::decodeUnicodeCodePoint( Token &token, 705 | Location ¤t, 706 | Location end, 707 | unsigned int &unicode ) 708 | { 709 | 710 | if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) 711 | return false; 712 | if (unicode >= 0xD800 && unicode <= 0xDBFF) 713 | { 714 | // surrogate pairs 715 | if (end - current < 6) 716 | return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); 717 | unsigned int surrogatePair; 718 | if (*(current++) == '\\' && *(current++)== 'u') 719 | { 720 | if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) 721 | { 722 | unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); 723 | } 724 | else 725 | return false; 726 | } 727 | else 728 | return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); 729 | } 730 | return true; 731 | } 732 | 733 | bool 734 | Reader::decodeUnicodeEscapeSequence( Token &token, 735 | Location ¤t, 736 | Location end, 737 | unsigned int &unicode ) 738 | { 739 | if ( end - current < 4 ) 740 | return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); 741 | unicode = 0; 742 | for ( int index =0; index < 4; ++index ) 743 | { 744 | Char c = *current++; 745 | unicode *= 16; 746 | if ( c >= '0' && c <= '9' ) 747 | unicode += c - '0'; 748 | else if ( c >= 'a' && c <= 'f' ) 749 | unicode += c - 'a' + 10; 750 | else if ( c >= 'A' && c <= 'F' ) 751 | unicode += c - 'A' + 10; 752 | else 753 | return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); 754 | } 755 | return true; 756 | } 757 | 758 | 759 | bool 760 | Reader::addError( const std::string &message, 761 | Token &token, 762 | Location extra ) 763 | { 764 | ErrorInfo info; 765 | info.token_ = token; 766 | info.message_ = message; 767 | info.extra_ = extra; 768 | errors_.push_back( info ); 769 | return false; 770 | } 771 | 772 | 773 | bool 774 | Reader::recoverFromError( TokenType skipUntilToken ) 775 | { 776 | int errorCount = int(errors_.size()); 777 | Token skip; 778 | while ( true ) 779 | { 780 | if ( !readToken(skip) ) 781 | errors_.resize( errorCount ); // discard errors caused by recovery 782 | if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) 783 | break; 784 | } 785 | errors_.resize( errorCount ); 786 | return false; 787 | } 788 | 789 | 790 | bool 791 | Reader::addErrorAndRecover( const std::string &message, 792 | Token &token, 793 | TokenType skipUntilToken ) 794 | { 795 | addError( message, token ); 796 | return recoverFromError( skipUntilToken ); 797 | } 798 | 799 | 800 | Value & 801 | Reader::currentValue() 802 | { 803 | return *(nodes_.top()); 804 | } 805 | 806 | 807 | Reader::Char 808 | Reader::getNextChar() 809 | { 810 | if ( current_ == end_ ) 811 | return 0; 812 | return *current_++; 813 | } 814 | 815 | 816 | void 817 | Reader::getLocationLineAndColumn( Location location, 818 | int &line, 819 | int &column ) const 820 | { 821 | Location current = begin_; 822 | Location lastLineStart = current; 823 | line = 0; 824 | while ( current < location && current != end_ ) 825 | { 826 | Char c = *current++; 827 | if ( c == '\r' ) 828 | { 829 | if ( *current == '\n' ) 830 | ++current; 831 | lastLineStart = current; 832 | ++line; 833 | } 834 | else if ( c == '\n' ) 835 | { 836 | lastLineStart = current; 837 | ++line; 838 | } 839 | } 840 | // column & line start at 1 841 | column = int(location - lastLineStart) + 1; 842 | ++line; 843 | } 844 | 845 | 846 | std::string 847 | Reader::getLocationLineAndColumn( Location location ) const 848 | { 849 | int line, column; 850 | getLocationLineAndColumn( location, line, column ); 851 | char buffer[18+16+16+1]; 852 | sprintf( buffer, "Line %d, Column %d", line, column ); 853 | return buffer; 854 | } 855 | 856 | 857 | std::string 858 | Reader::getFormatedErrorMessages() const 859 | { 860 | std::string formattedMessage; 861 | for ( Errors::const_iterator itError = errors_.begin(); 862 | itError != errors_.end(); 863 | ++itError ) 864 | { 865 | const ErrorInfo &error = *itError; 866 | formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; 867 | formattedMessage += " " + error.message_ + "\n"; 868 | if ( error.extra_ ) 869 | formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; 870 | } 871 | return formattedMessage; 872 | } 873 | 874 | 875 | std::istream& operator>>( std::istream &sin, Value &root ) 876 | { 877 | Json::Reader reader; 878 | bool ok = reader.parse(sin, root, true); 879 | //JSON_ASSERT( ok ); 880 | if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); 881 | return sin; 882 | } 883 | 884 | 885 | } // namespace Json 886 | -------------------------------------------------------------------------------- /json/value.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_H_INCLUDED 2 | # define CPPTL_JSON_H_INCLUDED 3 | 4 | # include "forwards.h" 5 | # include 6 | # include 7 | 8 | # ifndef JSON_USE_CPPTL_SMALLMAP 9 | # include 10 | # else 11 | # include 12 | # endif 13 | # ifdef JSON_USE_CPPTL 14 | # include 15 | # endif 16 | 17 | /** \brief JSON (JavaScript Object Notation). 18 | */ 19 | namespace Json { 20 | 21 | /** \brief Type of the value held by a Value object. 22 | */ 23 | enum ValueType 24 | { 25 | nullValue = 0, ///< 'null' value 26 | intValue, ///< signed integer value 27 | uintValue, ///< unsigned integer value 28 | realValue, ///< double value 29 | stringValue, ///< UTF-8 string value 30 | booleanValue, ///< bool value 31 | arrayValue, ///< array value (ordered list) 32 | objectValue ///< object value (collection of name/value pairs). 33 | }; 34 | 35 | enum CommentPlacement 36 | { 37 | commentBefore = 0, ///< a comment placed on the line before a value 38 | commentAfterOnSameLine, ///< a comment just after a value on the same line 39 | commentAfter, ///< a comment on the line after a value (only make sense for root value) 40 | numberOfCommentPlacement 41 | }; 42 | 43 | //# ifdef JSON_USE_CPPTL 44 | // typedef CppTL::AnyEnumerator EnumMemberNames; 45 | // typedef CppTL::AnyEnumerator EnumValues; 46 | //# endif 47 | 48 | /** \brief Lightweight wrapper to tag static string. 49 | * 50 | * Value constructor and objectValue member assignement takes advantage of the 51 | * StaticString and avoid the cost of string duplication when storing the 52 | * string or the member name. 53 | * 54 | * Example of usage: 55 | * \code 56 | * Json::Value aValue( StaticString("some text") ); 57 | * Json::Value object; 58 | * static const StaticString code("code"); 59 | * object[code] = 1234; 60 | * \endcode 61 | */ 62 | class JSON_API StaticString 63 | { 64 | public: 65 | explicit StaticString( const char *czstring ) 66 | : str_( czstring ) 67 | { 68 | } 69 | 70 | operator const char *() const 71 | { 72 | return str_; 73 | } 74 | 75 | const char *c_str() const 76 | { 77 | return str_; 78 | } 79 | 80 | private: 81 | const char *str_; 82 | }; 83 | 84 | /** \brief Represents a JSON value. 85 | * 86 | * This class is a discriminated union wrapper that can represents a: 87 | * - signed integer [range: Value::minInt - Value::maxInt] 88 | * - unsigned integer (range: 0 - Value::maxUInt) 89 | * - double 90 | * - UTF-8 string 91 | * - boolean 92 | * - 'null' 93 | * - an ordered list of Value 94 | * - collection of name/value pairs (javascript object) 95 | * 96 | * The type of the held value is represented by a #ValueType and 97 | * can be obtained using type(). 98 | * 99 | * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. 100 | * Non const methods will automatically create the a #nullValue element 101 | * if it does not exist. 102 | * The sequence of an #arrayValue will be automatically resize and initialized 103 | * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. 104 | * 105 | * The get() methods can be used to obtanis default value in the case the required element 106 | * does not exist. 107 | * 108 | * It is possible to iterate over the list of a #objectValue values using 109 | * the getMemberNames() method. 110 | */ 111 | class JSON_API Value 112 | { 113 | friend class ValueIteratorBase; 114 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 115 | friend class ValueInternalLink; 116 | friend class ValueInternalMap; 117 | # endif 118 | public: 119 | typedef std::vector Members; 120 | typedef ValueIterator iterator; 121 | typedef ValueConstIterator const_iterator; 122 | typedef Json::UInt UInt; 123 | typedef Json::Int Int; 124 | typedef UInt ArrayIndex; 125 | 126 | static const Value null; 127 | static const Int minInt; 128 | static const Int maxInt; 129 | static const UInt maxUInt; 130 | 131 | private: 132 | #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 133 | # ifndef JSON_VALUE_USE_INTERNAL_MAP 134 | class CZString 135 | { 136 | public: 137 | enum DuplicationPolicy 138 | { 139 | noDuplication = 0, 140 | duplicate, 141 | duplicateOnCopy 142 | }; 143 | CZString( int index ); 144 | CZString( const char *cstr, DuplicationPolicy allocate ); 145 | CZString( const CZString &other ); 146 | ~CZString(); 147 | CZString &operator =( const CZString &other ); 148 | bool operator<( const CZString &other ) const; 149 | bool operator==( const CZString &other ) const; 150 | int index() const; 151 | const char *c_str() const; 152 | bool isStaticString() const; 153 | private: 154 | void swap( CZString &other ); 155 | const char *cstr_; 156 | int index_; 157 | }; 158 | 159 | public: 160 | # ifndef JSON_USE_CPPTL_SMALLMAP 161 | typedef std::map ObjectValues; 162 | # else 163 | typedef CppTL::SmallMap ObjectValues; 164 | # endif // ifndef JSON_USE_CPPTL_SMALLMAP 165 | # endif // ifndef JSON_VALUE_USE_INTERNAL_MAP 166 | #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 167 | 168 | public: 169 | /** \brief Create a default Value of the given type. 170 | 171 | This is a very useful constructor. 172 | To create an empty array, pass arrayValue. 173 | To create an empty object, pass objectValue. 174 | Another Value can then be set to this one by assignment. 175 | This is useful since clear() and resize() will not alter types. 176 | 177 | Examples: 178 | \code 179 | Json::Value null_value; // null 180 | Json::Value arr_value(Json::arrayValue); // [] 181 | Json::Value obj_value(Json::objectValue); // {} 182 | \endcode 183 | */ 184 | Value( ValueType type = nullValue ); 185 | Value( Int value ); 186 | Value( UInt value ); 187 | Value( double value ); 188 | Value( const char *value ); 189 | Value( const char *beginValue, const char *endValue ); 190 | /** \brief Constructs a value from a static string. 191 | 192 | * Like other value string constructor but do not duplicate the string for 193 | * internal storage. The given string must remain alive after the call to this 194 | * constructor. 195 | * Example of usage: 196 | * \code 197 | * Json::Value aValue( StaticString("some text") ); 198 | * \endcode 199 | */ 200 | Value( const StaticString &value ); 201 | Value( const std::string &value ); 202 | # ifdef JSON_USE_CPPTL 203 | Value( const CppTL::ConstString &value ); 204 | # endif 205 | Value( bool value ); 206 | Value( const Value &other ); 207 | ~Value(); 208 | 209 | Value &operator=( const Value &other ); 210 | /// Swap values. 211 | /// \note Currently, comments are intentionally not swapped, for 212 | /// both logic and efficiency. 213 | void swap( Value &other ); 214 | 215 | ValueType type() const; 216 | 217 | bool operator <( const Value &other ) const; 218 | bool operator <=( const Value &other ) const; 219 | bool operator >=( const Value &other ) const; 220 | bool operator >( const Value &other ) const; 221 | 222 | bool operator ==( const Value &other ) const; 223 | bool operator !=( const Value &other ) const; 224 | 225 | int compare( const Value &other ); 226 | 227 | const char *asCString() const; 228 | std::string asString() const; 229 | # ifdef JSON_USE_CPPTL 230 | CppTL::ConstString asConstString() const; 231 | # endif 232 | Int asInt() const; 233 | UInt asUInt() const; 234 | double asDouble() const; 235 | bool asBool() const; 236 | 237 | bool isNull() const; 238 | bool isBool() const; 239 | bool isInt() const; 240 | bool isUInt() const; 241 | bool isIntegral() const; 242 | bool isDouble() const; 243 | bool isNumeric() const; 244 | bool isString() const; 245 | bool isArray() const; 246 | bool isObject() const; 247 | 248 | bool isConvertibleTo( ValueType other ) const; 249 | 250 | /// Number of values in array or object 251 | UInt size() const; 252 | 253 | /// \brief Return true if empty array, empty object, or null; 254 | /// otherwise, false. 255 | bool empty() const; 256 | 257 | /// Return isNull() 258 | bool operator!() const; 259 | 260 | /// Remove all object members and array elements. 261 | /// \pre type() is arrayValue, objectValue, or nullValue 262 | /// \post type() is unchanged 263 | void clear(); 264 | 265 | /// Resize the array to size elements. 266 | /// New elements are initialized to null. 267 | /// May only be called on nullValue or arrayValue. 268 | /// \pre type() is arrayValue or nullValue 269 | /// \post type() is arrayValue 270 | void resize( UInt size ); 271 | 272 | /// Access an array element (zero based index ). 273 | /// If the array contains less than index element, then null value are inserted 274 | /// in the array so that its size is index+1. 275 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 276 | /// this from the operator[] which takes a string.) 277 | Value &operator[]( UInt index ); 278 | /// Access an array element (zero based index ) 279 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 280 | /// this from the operator[] which takes a string.) 281 | const Value &operator[]( UInt index ) const; 282 | /// If the array contains at least index+1 elements, returns the element value, 283 | /// otherwise returns defaultValue. 284 | Value get( UInt index, 285 | const Value &defaultValue ) const; 286 | /// Return true if index < size(). 287 | bool isValidIndex( UInt index ) const; 288 | /// \brief Append value to array at the end. 289 | /// 290 | /// Equivalent to jsonvalue[jsonvalue.size()] = value; 291 | Value &append( const Value &value ); 292 | 293 | /// Access an object value by name, create a null member if it does not exist. 294 | Value &operator[]( const char *key ); 295 | /// Access an object value by name, returns null if there is no member with that name. 296 | const Value &operator[]( const char *key ) const; 297 | /// Access an object value by name, create a null member if it does not exist. 298 | Value &operator[]( const std::string &key ); 299 | /// Access an object value by name, returns null if there is no member with that name. 300 | const Value &operator[]( const std::string &key ) const; 301 | /** \brief Access an object value by name, create a null member if it does not exist. 302 | 303 | * If the object as no entry for that name, then the member name used to store 304 | * the new entry is not duplicated. 305 | * Example of use: 306 | * \code 307 | * Json::Value object; 308 | * static const StaticString code("code"); 309 | * object[code] = 1234; 310 | * \endcode 311 | */ 312 | Value &operator[]( const StaticString &key ); 313 | # ifdef JSON_USE_CPPTL 314 | /// Access an object value by name, create a null member if it does not exist. 315 | Value &operator[]( const CppTL::ConstString &key ); 316 | /// Access an object value by name, returns null if there is no member with that name. 317 | const Value &operator[]( const CppTL::ConstString &key ) const; 318 | # endif 319 | /// Return the member named key if it exist, defaultValue otherwise. 320 | Value get( const char *key, 321 | const Value &defaultValue ) const; 322 | /// Return the member named key if it exist, defaultValue otherwise. 323 | Value get( const std::string &key, 324 | const Value &defaultValue ) const; 325 | # ifdef JSON_USE_CPPTL 326 | /// Return the member named key if it exist, defaultValue otherwise. 327 | Value get( const CppTL::ConstString &key, 328 | const Value &defaultValue ) const; 329 | # endif 330 | /// \brief Remove and return the named member. 331 | /// 332 | /// Do nothing if it did not exist. 333 | /// \return the removed Value, or null. 334 | /// \pre type() is objectValue or nullValue 335 | /// \post type() is unchanged 336 | Value removeMember( const char* key ); 337 | /// Same as removeMember(const char*) 338 | Value removeMember( const std::string &key ); 339 | 340 | /// Return true if the object has a member named key. 341 | bool isMember( const char *key ) const; 342 | /// Return true if the object has a member named key. 343 | bool isMember( const std::string &key ) const; 344 | # ifdef JSON_USE_CPPTL 345 | /// Return true if the object has a member named key. 346 | bool isMember( const CppTL::ConstString &key ) const; 347 | # endif 348 | 349 | /// \brief Return a list of the member names. 350 | /// 351 | /// If null, return an empty list. 352 | /// \pre type() is objectValue or nullValue 353 | /// \post if type() was nullValue, it remains nullValue 354 | Members getMemberNames() const; 355 | 356 | //# ifdef JSON_USE_CPPTL 357 | // EnumMemberNames enumMemberNames() const; 358 | // EnumValues enumValues() const; 359 | //# endif 360 | 361 | /// Comments must be //... or /* ... */ 362 | void setComment( const char *comment, 363 | CommentPlacement placement ); 364 | /// Comments must be //... or /* ... */ 365 | void setComment( const std::string &comment, 366 | CommentPlacement placement ); 367 | bool hasComment( CommentPlacement placement ) const; 368 | /// Include delimiters and embedded newlines. 369 | std::string getComment( CommentPlacement placement ) const; 370 | 371 | std::string toStyledString() const; 372 | 373 | const_iterator begin() const; 374 | const_iterator end() const; 375 | 376 | iterator begin(); 377 | iterator end(); 378 | 379 | private: 380 | Value &resolveReference( const char *key, 381 | bool isStatic ); 382 | 383 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 384 | inline bool isItemAvailable() const 385 | { 386 | return itemIsUsed_ == 0; 387 | } 388 | 389 | inline void setItemUsed( bool isUsed = true ) 390 | { 391 | itemIsUsed_ = isUsed ? 1 : 0; 392 | } 393 | 394 | inline bool isMemberNameStatic() const 395 | { 396 | return memberNameIsStatic_ == 0; 397 | } 398 | 399 | inline void setMemberNameIsStatic( bool isStatic ) 400 | { 401 | memberNameIsStatic_ = isStatic ? 1 : 0; 402 | } 403 | # endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP 404 | 405 | private: 406 | struct CommentInfo 407 | { 408 | CommentInfo(); 409 | ~CommentInfo(); 410 | 411 | void setComment( const char *text ); 412 | 413 | char *comment_; 414 | }; 415 | 416 | //struct MemberNamesTransform 417 | //{ 418 | // typedef const char *result_type; 419 | // const char *operator()( const CZString &name ) const 420 | // { 421 | // return name.c_str(); 422 | // } 423 | //}; 424 | 425 | union ValueHolder 426 | { 427 | Int int_; 428 | UInt uint_; 429 | double real_; 430 | bool bool_; 431 | char *string_; 432 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 433 | ValueInternalArray *array_; 434 | ValueInternalMap *map_; 435 | #else 436 | ObjectValues *map_; 437 | # endif 438 | } value_; 439 | ValueType type_ : 8; 440 | int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. 441 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 442 | unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. 443 | int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. 444 | # endif 445 | CommentInfo *comments_; 446 | }; 447 | 448 | 449 | /** \brief Experimental and untested: represents an element of the "path" to access a node. 450 | */ 451 | class PathArgument 452 | { 453 | public: 454 | friend class Path; 455 | 456 | PathArgument(); 457 | PathArgument( UInt index ); 458 | PathArgument( const char *key ); 459 | PathArgument( const std::string &key ); 460 | 461 | private: 462 | enum Kind 463 | { 464 | kindNone = 0, 465 | kindIndex, 466 | kindKey 467 | }; 468 | std::string key_; 469 | UInt index_; 470 | Kind kind_; 471 | }; 472 | 473 | /** \brief Experimental and untested: represents a "path" to access a node. 474 | * 475 | * Syntax: 476 | * - "." => root node 477 | * - ".[n]" => elements at index 'n' of root node (an array value) 478 | * - ".name" => member named 'name' of root node (an object value) 479 | * - ".name1.name2.name3" 480 | * - ".[0][1][2].name1[3]" 481 | * - ".%" => member name is provided as parameter 482 | * - ".[%]" => index is provied as parameter 483 | */ 484 | class Path 485 | { 486 | public: 487 | Path( const std::string &path, 488 | const PathArgument &a1 = PathArgument(), 489 | const PathArgument &a2 = PathArgument(), 490 | const PathArgument &a3 = PathArgument(), 491 | const PathArgument &a4 = PathArgument(), 492 | const PathArgument &a5 = PathArgument() ); 493 | 494 | const Value &resolve( const Value &root ) const; 495 | Value resolve( const Value &root, 496 | const Value &defaultValue ) const; 497 | /// Creates the "path" to access the specified node and returns a reference on the node. 498 | Value &make( Value &root ) const; 499 | 500 | private: 501 | typedef std::vector InArgs; 502 | typedef std::vector Args; 503 | 504 | void makePath( const std::string &path, 505 | const InArgs &in ); 506 | void addPathInArg( const std::string &path, 507 | const InArgs &in, 508 | InArgs::const_iterator &itInArg, 509 | PathArgument::Kind kind ); 510 | void invalidPath( const std::string &path, 511 | int location ); 512 | 513 | Args args_; 514 | }; 515 | 516 | /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. 517 | * 518 | * - makeMemberName() and releaseMemberName() are called to respectively duplicate and 519 | * free an Json::objectValue member name. 520 | * - duplicateStringValue() and releaseStringValue() are called similarly to 521 | * duplicate and free a Json::stringValue value. 522 | */ 523 | class ValueAllocator 524 | { 525 | public: 526 | enum { unknown = (unsigned)-1 }; 527 | 528 | virtual ~ValueAllocator(); 529 | 530 | virtual char *makeMemberName( const char *memberName ) = 0; 531 | virtual void releaseMemberName( char *memberName ) = 0; 532 | virtual char *duplicateStringValue( const char *value, 533 | unsigned int length = unknown ) = 0; 534 | virtual void releaseStringValue( char *value ) = 0; 535 | }; 536 | 537 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 538 | /** \brief Allocator to customize Value internal map. 539 | * Below is an example of a simple implementation (default implementation actually 540 | * use memory pool for speed). 541 | * \code 542 | class DefaultValueMapAllocator : public ValueMapAllocator 543 | { 544 | public: // overridden from ValueMapAllocator 545 | virtual ValueInternalMap *newMap() 546 | { 547 | return new ValueInternalMap(); 548 | } 549 | 550 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 551 | { 552 | return new ValueInternalMap( other ); 553 | } 554 | 555 | virtual void destructMap( ValueInternalMap *map ) 556 | { 557 | delete map; 558 | } 559 | 560 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 561 | { 562 | return new ValueInternalLink[size]; 563 | } 564 | 565 | virtual void releaseMapBuckets( ValueInternalLink *links ) 566 | { 567 | delete [] links; 568 | } 569 | 570 | virtual ValueInternalLink *allocateMapLink() 571 | { 572 | return new ValueInternalLink(); 573 | } 574 | 575 | virtual void releaseMapLink( ValueInternalLink *link ) 576 | { 577 | delete link; 578 | } 579 | }; 580 | * \endcode 581 | */ 582 | class JSON_API ValueMapAllocator 583 | { 584 | public: 585 | virtual ~ValueMapAllocator(); 586 | virtual ValueInternalMap *newMap() = 0; 587 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; 588 | virtual void destructMap( ValueInternalMap *map ) = 0; 589 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; 590 | virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; 591 | virtual ValueInternalLink *allocateMapLink() = 0; 592 | virtual void releaseMapLink( ValueInternalLink *link ) = 0; 593 | }; 594 | 595 | /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). 596 | * \internal previous_ & next_ allows for bidirectional traversal. 597 | */ 598 | class JSON_API ValueInternalLink 599 | { 600 | public: 601 | enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. 602 | enum InternalFlags { 603 | flagAvailable = 0, 604 | flagUsed = 1 605 | }; 606 | 607 | ValueInternalLink(); 608 | 609 | ~ValueInternalLink(); 610 | 611 | Value items_[itemPerLink]; 612 | char *keys_[itemPerLink]; 613 | ValueInternalLink *previous_; 614 | ValueInternalLink *next_; 615 | }; 616 | 617 | 618 | /** \brief A linked page based hash-table implementation used internally by Value. 619 | * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked 620 | * list in each bucket to handle collision. There is an addional twist in that 621 | * each node of the collision linked list is a page containing a fixed amount of 622 | * value. This provides a better compromise between memory usage and speed. 623 | * 624 | * Each bucket is made up of a chained list of ValueInternalLink. The last 625 | * link of a given bucket can be found in the 'previous_' field of the following bucket. 626 | * The last link of the last bucket is stored in tailLink_ as it has no following bucket. 627 | * Only the last link of a bucket may contains 'available' item. The last link always 628 | * contains at least one element unless is it the bucket one very first link. 629 | */ 630 | class JSON_API ValueInternalMap 631 | { 632 | friend class ValueIteratorBase; 633 | friend class Value; 634 | public: 635 | typedef unsigned int HashKey; 636 | typedef unsigned int BucketIndex; 637 | 638 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 639 | struct IteratorState 640 | { 641 | IteratorState() 642 | : map_(0) 643 | , link_(0) 644 | , itemIndex_(0) 645 | , bucketIndex_(0) 646 | { 647 | } 648 | ValueInternalMap *map_; 649 | ValueInternalLink *link_; 650 | BucketIndex itemIndex_; 651 | BucketIndex bucketIndex_; 652 | }; 653 | # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 654 | 655 | ValueInternalMap(); 656 | ValueInternalMap( const ValueInternalMap &other ); 657 | ValueInternalMap &operator =( const ValueInternalMap &other ); 658 | ~ValueInternalMap(); 659 | 660 | void swap( ValueInternalMap &other ); 661 | 662 | BucketIndex size() const; 663 | 664 | void clear(); 665 | 666 | bool reserveDelta( BucketIndex growth ); 667 | 668 | bool reserve( BucketIndex newItemCount ); 669 | 670 | const Value *find( const char *key ) const; 671 | 672 | Value *find( const char *key ); 673 | 674 | Value &resolveReference( const char *key, 675 | bool isStatic ); 676 | 677 | void remove( const char *key ); 678 | 679 | void doActualRemove( ValueInternalLink *link, 680 | BucketIndex index, 681 | BucketIndex bucketIndex ); 682 | 683 | ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); 684 | 685 | Value &setNewItem( const char *key, 686 | bool isStatic, 687 | ValueInternalLink *link, 688 | BucketIndex index ); 689 | 690 | Value &unsafeAdd( const char *key, 691 | bool isStatic, 692 | HashKey hashedKey ); 693 | 694 | HashKey hash( const char *key ) const; 695 | 696 | int compare( const ValueInternalMap &other ) const; 697 | 698 | private: 699 | void makeBeginIterator( IteratorState &it ) const; 700 | void makeEndIterator( IteratorState &it ) const; 701 | static bool equals( const IteratorState &x, const IteratorState &other ); 702 | static void increment( IteratorState &iterator ); 703 | static void incrementBucket( IteratorState &iterator ); 704 | static void decrement( IteratorState &iterator ); 705 | static const char *key( const IteratorState &iterator ); 706 | static const char *key( const IteratorState &iterator, bool &isStatic ); 707 | static Value &value( const IteratorState &iterator ); 708 | static int distance( const IteratorState &x, const IteratorState &y ); 709 | 710 | private: 711 | ValueInternalLink *buckets_; 712 | ValueInternalLink *tailLink_; 713 | BucketIndex bucketsSize_; 714 | BucketIndex itemCount_; 715 | }; 716 | 717 | /** \brief A simplified deque implementation used internally by Value. 718 | * \internal 719 | * It is based on a list of fixed "page", each page contains a fixed number of items. 720 | * Instead of using a linked-list, a array of pointer is used for fast item look-up. 721 | * Look-up for an element is as follow: 722 | * - compute page index: pageIndex = itemIndex / itemsPerPage 723 | * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] 724 | * 725 | * Insertion is amortized constant time (only the array containing the index of pointers 726 | * need to be reallocated when items are appended). 727 | */ 728 | class JSON_API ValueInternalArray 729 | { 730 | friend class Value; 731 | friend class ValueIteratorBase; 732 | public: 733 | enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. 734 | typedef Value::ArrayIndex ArrayIndex; 735 | typedef unsigned int PageIndex; 736 | 737 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 738 | struct IteratorState // Must be a POD 739 | { 740 | IteratorState() 741 | : array_(0) 742 | , currentPageIndex_(0) 743 | , currentItemIndex_(0) 744 | { 745 | } 746 | ValueInternalArray *array_; 747 | Value **currentPageIndex_; 748 | unsigned int currentItemIndex_; 749 | }; 750 | # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 751 | 752 | ValueInternalArray(); 753 | ValueInternalArray( const ValueInternalArray &other ); 754 | ValueInternalArray &operator =( const ValueInternalArray &other ); 755 | ~ValueInternalArray(); 756 | void swap( ValueInternalArray &other ); 757 | 758 | void clear(); 759 | void resize( ArrayIndex newSize ); 760 | 761 | Value &resolveReference( ArrayIndex index ); 762 | 763 | Value *find( ArrayIndex index ) const; 764 | 765 | ArrayIndex size() const; 766 | 767 | int compare( const ValueInternalArray &other ) const; 768 | 769 | private: 770 | static bool equals( const IteratorState &x, const IteratorState &other ); 771 | static void increment( IteratorState &iterator ); 772 | static void decrement( IteratorState &iterator ); 773 | static Value &dereference( const IteratorState &iterator ); 774 | static Value &unsafeDereference( const IteratorState &iterator ); 775 | static int distance( const IteratorState &x, const IteratorState &y ); 776 | static ArrayIndex indexOf( const IteratorState &iterator ); 777 | void makeBeginIterator( IteratorState &it ) const; 778 | void makeEndIterator( IteratorState &it ) const; 779 | void makeIterator( IteratorState &it, ArrayIndex index ) const; 780 | 781 | void makeIndexValid( ArrayIndex index ); 782 | 783 | Value **pages_; 784 | ArrayIndex size_; 785 | PageIndex pageCount_; 786 | }; 787 | 788 | /** \brief Experimental: do not use. Allocator to customize Value internal array. 789 | * Below is an example of a simple implementation (actual implementation use 790 | * memory pool). 791 | \code 792 | class DefaultValueArrayAllocator : public ValueArrayAllocator 793 | { 794 | public: // overridden from ValueArrayAllocator 795 | virtual ~DefaultValueArrayAllocator() 796 | { 797 | } 798 | 799 | virtual ValueInternalArray *newArray() 800 | { 801 | return new ValueInternalArray(); 802 | } 803 | 804 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 805 | { 806 | return new ValueInternalArray( other ); 807 | } 808 | 809 | virtual void destruct( ValueInternalArray *array ) 810 | { 811 | delete array; 812 | } 813 | 814 | virtual void reallocateArrayPageIndex( Value **&indexes, 815 | ValueInternalArray::PageIndex &indexCount, 816 | ValueInternalArray::PageIndex minNewIndexCount ) 817 | { 818 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 819 | if ( minNewIndexCount > newIndexCount ) 820 | newIndexCount = minNewIndexCount; 821 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 822 | if ( !newIndexes ) 823 | throw std::bad_alloc(); 824 | indexCount = newIndexCount; 825 | indexes = static_cast( newIndexes ); 826 | } 827 | virtual void releaseArrayPageIndex( Value **indexes, 828 | ValueInternalArray::PageIndex indexCount ) 829 | { 830 | if ( indexes ) 831 | free( indexes ); 832 | } 833 | 834 | virtual Value *allocateArrayPage() 835 | { 836 | return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); 837 | } 838 | 839 | virtual void releaseArrayPage( Value *value ) 840 | { 841 | if ( value ) 842 | free( value ); 843 | } 844 | }; 845 | \endcode 846 | */ 847 | class JSON_API ValueArrayAllocator 848 | { 849 | public: 850 | virtual ~ValueArrayAllocator(); 851 | virtual ValueInternalArray *newArray() = 0; 852 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; 853 | virtual void destructArray( ValueInternalArray *array ) = 0; 854 | /** \brief Reallocate array page index. 855 | * Reallocates an array of pointer on each page. 856 | * \param indexes [input] pointer on the current index. May be \c NULL. 857 | * [output] pointer on the new index of at least 858 | * \a minNewIndexCount pages. 859 | * \param indexCount [input] current number of pages in the index. 860 | * [output] number of page the reallocated index can handle. 861 | * \b MUST be >= \a minNewIndexCount. 862 | * \param minNewIndexCount Minimum number of page the new index must be able to 863 | * handle. 864 | */ 865 | virtual void reallocateArrayPageIndex( Value **&indexes, 866 | ValueInternalArray::PageIndex &indexCount, 867 | ValueInternalArray::PageIndex minNewIndexCount ) = 0; 868 | virtual void releaseArrayPageIndex( Value **indexes, 869 | ValueInternalArray::PageIndex indexCount ) = 0; 870 | virtual Value *allocateArrayPage() = 0; 871 | virtual void releaseArrayPage( Value *value ) = 0; 872 | }; 873 | #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP 874 | 875 | 876 | /** \brief base class for Value iterators. 877 | * 878 | */ 879 | class ValueIteratorBase 880 | { 881 | public: 882 | typedef unsigned int size_t; 883 | typedef int difference_type; 884 | typedef ValueIteratorBase SelfType; 885 | 886 | ValueIteratorBase(); 887 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 888 | explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); 889 | #else 890 | ValueIteratorBase( const ValueInternalArray::IteratorState &state ); 891 | ValueIteratorBase( const ValueInternalMap::IteratorState &state ); 892 | #endif 893 | 894 | bool operator ==( const SelfType &other ) const 895 | { 896 | return isEqual( other ); 897 | } 898 | 899 | bool operator !=( const SelfType &other ) const 900 | { 901 | return !isEqual( other ); 902 | } 903 | 904 | difference_type operator -( const SelfType &other ) const 905 | { 906 | return computeDistance( other ); 907 | } 908 | 909 | /// Return either the index or the member name of the referenced value as a Value. 910 | Value key() const; 911 | 912 | /// Return the index of the referenced Value. -1 if it is not an arrayValue. 913 | UInt index() const; 914 | 915 | /// Return the member name of the referenced Value. "" if it is not an objectValue. 916 | const char *memberName() const; 917 | 918 | protected: 919 | Value &deref() const; 920 | 921 | void increment(); 922 | 923 | void decrement(); 924 | 925 | difference_type computeDistance( const SelfType &other ) const; 926 | 927 | bool isEqual( const SelfType &other ) const; 928 | 929 | void copy( const SelfType &other ); 930 | 931 | private: 932 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 933 | Value::ObjectValues::iterator current_; 934 | // Indicates that iterator is for a null value. 935 | bool isNull_; 936 | #else 937 | union 938 | { 939 | ValueInternalArray::IteratorState array_; 940 | ValueInternalMap::IteratorState map_; 941 | } iterator_; 942 | bool isArray_; 943 | #endif 944 | }; 945 | 946 | /** \brief const iterator for object and array value. 947 | * 948 | */ 949 | class ValueConstIterator : public ValueIteratorBase 950 | { 951 | friend class Value; 952 | public: 953 | typedef unsigned int size_t; 954 | typedef int difference_type; 955 | typedef const Value &reference; 956 | typedef const Value *pointer; 957 | typedef ValueConstIterator SelfType; 958 | 959 | ValueConstIterator(); 960 | private: 961 | /*! \internal Use by Value to create an iterator. 962 | */ 963 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 964 | explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); 965 | #else 966 | ValueConstIterator( const ValueInternalArray::IteratorState &state ); 967 | ValueConstIterator( const ValueInternalMap::IteratorState &state ); 968 | #endif 969 | public: 970 | SelfType &operator =( const ValueIteratorBase &other ); 971 | 972 | SelfType operator++( int ) 973 | { 974 | SelfType temp( *this ); 975 | ++*this; 976 | return temp; 977 | } 978 | 979 | SelfType operator--( int ) 980 | { 981 | SelfType temp( *this ); 982 | --*this; 983 | return temp; 984 | } 985 | 986 | SelfType &operator--() 987 | { 988 | decrement(); 989 | return *this; 990 | } 991 | 992 | SelfType &operator++() 993 | { 994 | increment(); 995 | return *this; 996 | } 997 | 998 | reference operator *() const 999 | { 1000 | return deref(); 1001 | } 1002 | }; 1003 | 1004 | 1005 | /** \brief Iterator for object and array value. 1006 | */ 1007 | class ValueIterator : public ValueIteratorBase 1008 | { 1009 | friend class Value; 1010 | public: 1011 | typedef unsigned int size_t; 1012 | typedef int difference_type; 1013 | typedef Value &reference; 1014 | typedef Value *pointer; 1015 | typedef ValueIterator SelfType; 1016 | 1017 | ValueIterator(); 1018 | ValueIterator( const ValueConstIterator &other ); 1019 | ValueIterator( const ValueIterator &other ); 1020 | private: 1021 | /*! \internal Use by Value to create an iterator. 1022 | */ 1023 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 1024 | explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); 1025 | #else 1026 | ValueIterator( const ValueInternalArray::IteratorState &state ); 1027 | ValueIterator( const ValueInternalMap::IteratorState &state ); 1028 | #endif 1029 | public: 1030 | 1031 | SelfType &operator =( const SelfType &other ); 1032 | 1033 | SelfType operator++( int ) 1034 | { 1035 | SelfType temp( *this ); 1036 | ++*this; 1037 | return temp; 1038 | } 1039 | 1040 | SelfType operator--( int ) 1041 | { 1042 | SelfType temp( *this ); 1043 | --*this; 1044 | return temp; 1045 | } 1046 | 1047 | SelfType &operator--() 1048 | { 1049 | decrement(); 1050 | return *this; 1051 | } 1052 | 1053 | SelfType &operator++() 1054 | { 1055 | increment(); 1056 | return *this; 1057 | } 1058 | 1059 | reference operator *() const 1060 | { 1061 | return deref(); 1062 | } 1063 | }; 1064 | 1065 | 1066 | } // namespace Json 1067 | 1068 | 1069 | #endif // CPPTL_JSON_H_INCLUDED 1070 | -------------------------------------------------------------------------------- /json/json_value.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "value.h" 3 | #include "writer.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #ifdef JSON_USE_CPPTL 9 | # include 10 | #endif 11 | #include // size_t 12 | 13 | #include 14 | 15 | #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 16 | # include "json_batchallocator.h" 17 | #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 18 | 19 | #define JSON_ASSERT_UNREACHABLE assert( false ) 20 | #define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw 21 | #define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); 22 | 23 | namespace Json { 24 | 25 | const Value Value::null; 26 | const Int Value::minInt = Int( ~(UInt(-1)/2) ); 27 | const Int Value::maxInt = Int( UInt(-1)/2 ); 28 | const UInt Value::maxUInt = UInt(-1); 29 | 30 | // A "safe" implementation of strdup. Allow null pointer to be passed. 31 | // Also avoid warning on msvc80. 32 | // 33 | //inline char *safeStringDup( const char *czstring ) 34 | //{ 35 | // if ( czstring ) 36 | // { 37 | // const size_t length = (unsigned int)( strlen(czstring) + 1 ); 38 | // char *newString = static_cast( malloc( length ) ); 39 | // memcpy( newString, czstring, length ); 40 | // return newString; 41 | // } 42 | // return 0; 43 | //} 44 | // 45 | //inline char *safeStringDup( const std::string &str ) 46 | //{ 47 | // if ( !str.empty() ) 48 | // { 49 | // const size_t length = str.length(); 50 | // char *newString = static_cast( malloc( length + 1 ) ); 51 | // memcpy( newString, str.c_str(), length ); 52 | // newString[length] = 0; 53 | // return newString; 54 | // } 55 | // return 0; 56 | //} 57 | 58 | ValueAllocator::~ValueAllocator() 59 | { 60 | } 61 | 62 | class DefaultValueAllocator : public ValueAllocator 63 | { 64 | public: 65 | virtual ~DefaultValueAllocator() 66 | { 67 | } 68 | 69 | virtual char *makeMemberName( const char *memberName ) 70 | { 71 | return duplicateStringValue( memberName ); 72 | } 73 | 74 | virtual void releaseMemberName( char *memberName ) 75 | { 76 | releaseStringValue( memberName ); 77 | } 78 | 79 | virtual char *duplicateStringValue( const char *value, 80 | unsigned int length = unknown ) 81 | { 82 | //@todo invesgate this old optimization 83 | //if ( !value || value[0] == 0 ) 84 | // return 0; 85 | 86 | if ( length == unknown ) 87 | length = (unsigned int)strlen(value); 88 | char *newString = static_cast( malloc( length + 1 ) ); 89 | memcpy( newString, value, length ); 90 | newString[length] = 0; 91 | return newString; 92 | } 93 | 94 | virtual void releaseStringValue( char *value ) 95 | { 96 | if ( value ) 97 | free( value ); 98 | } 99 | }; 100 | 101 | static ValueAllocator *&valueAllocator() 102 | { 103 | static DefaultValueAllocator defaultAllocator; 104 | static ValueAllocator *valueAllocator = &defaultAllocator; 105 | return valueAllocator; 106 | } 107 | 108 | static struct DummyValueAllocatorInitializer { 109 | DummyValueAllocatorInitializer() 110 | { 111 | valueAllocator(); // ensure valueAllocator() statics are initialized before main(). 112 | } 113 | } dummyValueAllocatorInitializer; 114 | 115 | 116 | 117 | // ////////////////////////////////////////////////////////////////// 118 | // ////////////////////////////////////////////////////////////////// 119 | // ////////////////////////////////////////////////////////////////// 120 | // ValueInternals... 121 | // ////////////////////////////////////////////////////////////////// 122 | // ////////////////////////////////////////////////////////////////// 123 | // ////////////////////////////////////////////////////////////////// 124 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 125 | # include "json_internalarray.inl" 126 | # include "json_internalmap.inl" 127 | #endif // JSON_VALUE_USE_INTERNAL_MAP 128 | 129 | # include "json_valueiterator.inl" 130 | 131 | 132 | // ////////////////////////////////////////////////////////////////// 133 | // ////////////////////////////////////////////////////////////////// 134 | // ////////////////////////////////////////////////////////////////// 135 | // class Value::CommentInfo 136 | // ////////////////////////////////////////////////////////////////// 137 | // ////////////////////////////////////////////////////////////////// 138 | // ////////////////////////////////////////////////////////////////// 139 | 140 | 141 | Value::CommentInfo::CommentInfo() 142 | : comment_( 0 ) 143 | { 144 | } 145 | 146 | Value::CommentInfo::~CommentInfo() 147 | { 148 | if ( comment_ ) 149 | valueAllocator()->releaseStringValue( comment_ ); 150 | } 151 | 152 | 153 | void 154 | Value::CommentInfo::setComment( const char *text ) 155 | { 156 | if ( comment_ ) 157 | valueAllocator()->releaseStringValue( comment_ ); 158 | JSON_ASSERT( text ); 159 | JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); 160 | // It seems that /**/ style comments are acceptable as well. 161 | comment_ = valueAllocator()->duplicateStringValue( text ); 162 | } 163 | 164 | 165 | // ////////////////////////////////////////////////////////////////// 166 | // ////////////////////////////////////////////////////////////////// 167 | // ////////////////////////////////////////////////////////////////// 168 | // class Value::CZString 169 | // ////////////////////////////////////////////////////////////////// 170 | // ////////////////////////////////////////////////////////////////// 171 | // ////////////////////////////////////////////////////////////////// 172 | # ifndef JSON_VALUE_USE_INTERNAL_MAP 173 | 174 | // Notes: index_ indicates if the string was allocated when 175 | // a string is stored. 176 | 177 | Value::CZString::CZString( int index ) 178 | : cstr_( 0 ) 179 | , index_( index ) 180 | { 181 | } 182 | 183 | Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) 184 | : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) 185 | : cstr ) 186 | , index_( allocate ) 187 | { 188 | } 189 | 190 | Value::CZString::CZString( const CZString &other ) 191 | : cstr_( other.index_ != noDuplication && other.cstr_ != 0 192 | ? valueAllocator()->makeMemberName( other.cstr_ ) 193 | : other.cstr_ ) 194 | , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) 195 | : other.index_ ) 196 | { 197 | } 198 | 199 | Value::CZString::~CZString() 200 | { 201 | if ( cstr_ && index_ == duplicate ) 202 | valueAllocator()->releaseMemberName( const_cast( cstr_ ) ); 203 | } 204 | 205 | void 206 | Value::CZString::swap( CZString &other ) 207 | { 208 | std::swap( cstr_, other.cstr_ ); 209 | std::swap( index_, other.index_ ); 210 | } 211 | 212 | Value::CZString & 213 | Value::CZString::operator =( const CZString &other ) 214 | { 215 | CZString temp( other ); 216 | swap( temp ); 217 | return *this; 218 | } 219 | 220 | bool 221 | Value::CZString::operator<( const CZString &other ) const 222 | { 223 | if ( cstr_ ) 224 | return strcmp( cstr_, other.cstr_ ) < 0; 225 | return index_ < other.index_; 226 | } 227 | 228 | bool 229 | Value::CZString::operator==( const CZString &other ) const 230 | { 231 | if ( cstr_ ) 232 | return strcmp( cstr_, other.cstr_ ) == 0; 233 | return index_ == other.index_; 234 | } 235 | 236 | 237 | int 238 | Value::CZString::index() const 239 | { 240 | return index_; 241 | } 242 | 243 | 244 | const char * 245 | Value::CZString::c_str() const 246 | { 247 | return cstr_; 248 | } 249 | 250 | bool 251 | Value::CZString::isStaticString() const 252 | { 253 | return index_ == noDuplication; 254 | } 255 | 256 | #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP 257 | 258 | 259 | // ////////////////////////////////////////////////////////////////// 260 | // ////////////////////////////////////////////////////////////////// 261 | // ////////////////////////////////////////////////////////////////// 262 | // class Value::Value 263 | // ////////////////////////////////////////////////////////////////// 264 | // ////////////////////////////////////////////////////////////////// 265 | // ////////////////////////////////////////////////////////////////// 266 | 267 | /*! \internal Default constructor initialization must be equivalent to: 268 | * memset( this, 0, sizeof(Value) ) 269 | * This optimization is used in ValueInternalMap fast allocator. 270 | */ 271 | Value::Value( ValueType type ) 272 | : type_( type ) 273 | , allocated_( 0 ) 274 | , comments_( 0 ) 275 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 276 | , itemIsUsed_( 0 ) 277 | #endif 278 | { 279 | switch ( type ) 280 | { 281 | case nullValue: 282 | break; 283 | case intValue: 284 | case uintValue: 285 | value_.int_ = 0; 286 | break; 287 | case realValue: 288 | value_.real_ = 0.0; 289 | break; 290 | case stringValue: 291 | value_.string_ = 0; 292 | break; 293 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 294 | case arrayValue: 295 | case objectValue: 296 | value_.map_ = new ObjectValues(); 297 | break; 298 | #else 299 | case arrayValue: 300 | value_.array_ = arrayAllocator()->newArray(); 301 | break; 302 | case objectValue: 303 | value_.map_ = mapAllocator()->newMap(); 304 | break; 305 | #endif 306 | case booleanValue: 307 | value_.bool_ = false; 308 | break; 309 | default: 310 | JSON_ASSERT_UNREACHABLE; 311 | } 312 | } 313 | 314 | 315 | Value::Value( Int value ) 316 | : type_( intValue ) 317 | , comments_( 0 ) 318 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 319 | , itemIsUsed_( 0 ) 320 | #endif 321 | { 322 | value_.int_ = value; 323 | } 324 | 325 | 326 | Value::Value( UInt value ) 327 | : type_( uintValue ) 328 | , comments_( 0 ) 329 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 330 | , itemIsUsed_( 0 ) 331 | #endif 332 | { 333 | value_.uint_ = value; 334 | } 335 | 336 | Value::Value( double value ) 337 | : type_( realValue ) 338 | , comments_( 0 ) 339 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 340 | , itemIsUsed_( 0 ) 341 | #endif 342 | { 343 | value_.real_ = value; 344 | } 345 | 346 | Value::Value( const char *value ) 347 | : type_( stringValue ) 348 | , allocated_( true ) 349 | , comments_( 0 ) 350 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 351 | , itemIsUsed_( 0 ) 352 | #endif 353 | { 354 | value_.string_ = valueAllocator()->duplicateStringValue( value ); 355 | } 356 | 357 | 358 | Value::Value( const char *beginValue, 359 | const char *endValue ) 360 | : type_( stringValue ) 361 | , allocated_( true ) 362 | , comments_( 0 ) 363 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 364 | , itemIsUsed_( 0 ) 365 | #endif 366 | { 367 | value_.string_ = valueAllocator()->duplicateStringValue( beginValue, 368 | UInt(endValue - beginValue) ); 369 | } 370 | 371 | 372 | Value::Value( const std::string &value ) 373 | : type_( stringValue ) 374 | , allocated_( true ) 375 | , comments_( 0 ) 376 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 377 | , itemIsUsed_( 0 ) 378 | #endif 379 | { 380 | value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), 381 | (unsigned int)value.length() ); 382 | 383 | } 384 | 385 | Value::Value( const StaticString &value ) 386 | : type_( stringValue ) 387 | , allocated_( false ) 388 | , comments_( 0 ) 389 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 390 | , itemIsUsed_( 0 ) 391 | #endif 392 | { 393 | value_.string_ = const_cast( value.c_str() ); 394 | } 395 | 396 | 397 | # ifdef JSON_USE_CPPTL 398 | Value::Value( const CppTL::ConstString &value ) 399 | : type_( stringValue ) 400 | , allocated_( true ) 401 | , comments_( 0 ) 402 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 403 | , itemIsUsed_( 0 ) 404 | #endif 405 | { 406 | value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); 407 | } 408 | # endif 409 | 410 | Value::Value( bool value ) 411 | : type_( booleanValue ) 412 | , comments_( 0 ) 413 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 414 | , itemIsUsed_( 0 ) 415 | #endif 416 | { 417 | value_.bool_ = value; 418 | } 419 | 420 | 421 | Value::Value( const Value &other ) 422 | : type_( other.type_ ) 423 | , comments_( 0 ) 424 | # ifdef JSON_VALUE_USE_INTERNAL_MAP 425 | , itemIsUsed_( 0 ) 426 | #endif 427 | { 428 | switch ( type_ ) 429 | { 430 | case nullValue: 431 | case intValue: 432 | case uintValue: 433 | case realValue: 434 | case booleanValue: 435 | value_ = other.value_; 436 | break; 437 | case stringValue: 438 | if ( other.value_.string_ ) 439 | { 440 | value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); 441 | allocated_ = true; 442 | } 443 | else 444 | value_.string_ = 0; 445 | break; 446 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 447 | case arrayValue: 448 | case objectValue: 449 | value_.map_ = new ObjectValues( *other.value_.map_ ); 450 | break; 451 | #else 452 | case arrayValue: 453 | value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); 454 | break; 455 | case objectValue: 456 | value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); 457 | break; 458 | #endif 459 | default: 460 | JSON_ASSERT_UNREACHABLE; 461 | } 462 | if ( other.comments_ ) 463 | { 464 | comments_ = new CommentInfo[numberOfCommentPlacement]; 465 | for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) 466 | { 467 | const CommentInfo &otherComment = other.comments_[comment]; 468 | if ( otherComment.comment_ ) 469 | comments_[comment].setComment( otherComment.comment_ ); 470 | } 471 | } 472 | } 473 | 474 | 475 | Value::~Value() 476 | { 477 | switch ( type_ ) 478 | { 479 | case nullValue: 480 | case intValue: 481 | case uintValue: 482 | case realValue: 483 | case booleanValue: 484 | break; 485 | case stringValue: 486 | if ( allocated_ ) 487 | valueAllocator()->releaseStringValue( value_.string_ ); 488 | break; 489 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 490 | case arrayValue: 491 | case objectValue: 492 | delete value_.map_; 493 | break; 494 | #else 495 | case arrayValue: 496 | arrayAllocator()->destructArray( value_.array_ ); 497 | break; 498 | case objectValue: 499 | mapAllocator()->destructMap( value_.map_ ); 500 | break; 501 | #endif 502 | default: 503 | JSON_ASSERT_UNREACHABLE; 504 | } 505 | 506 | if ( comments_ ) 507 | delete[] comments_; 508 | } 509 | 510 | Value & 511 | Value::operator=( const Value &other ) 512 | { 513 | Value temp( other ); 514 | swap( temp ); 515 | return *this; 516 | } 517 | 518 | void 519 | Value::swap( Value &other ) 520 | { 521 | ValueType temp = type_; 522 | type_ = other.type_; 523 | other.type_ = temp; 524 | std::swap( value_, other.value_ ); 525 | int temp2 = allocated_; 526 | allocated_ = other.allocated_; 527 | other.allocated_ = temp2; 528 | } 529 | 530 | ValueType 531 | Value::type() const 532 | { 533 | return type_; 534 | } 535 | 536 | 537 | int 538 | Value::compare( const Value &other ) 539 | { 540 | /* 541 | int typeDelta = other.type_ - type_; 542 | switch ( type_ ) 543 | { 544 | case nullValue: 545 | 546 | return other.type_ == type_; 547 | case intValue: 548 | if ( other.type_.isNumeric() 549 | case uintValue: 550 | case realValue: 551 | case booleanValue: 552 | break; 553 | case stringValue, 554 | break; 555 | case arrayValue: 556 | delete value_.array_; 557 | break; 558 | case objectValue: 559 | delete value_.map_; 560 | default: 561 | JSON_ASSERT_UNREACHABLE; 562 | } 563 | */ 564 | return 0; // unreachable 565 | } 566 | 567 | bool 568 | Value::operator <( const Value &other ) const 569 | { 570 | int typeDelta = type_ - other.type_; 571 | if ( typeDelta ) 572 | return typeDelta < 0 ? true : false; 573 | switch ( type_ ) 574 | { 575 | case nullValue: 576 | return false; 577 | case intValue: 578 | return value_.int_ < other.value_.int_; 579 | case uintValue: 580 | return value_.uint_ < other.value_.uint_; 581 | case realValue: 582 | return value_.real_ < other.value_.real_; 583 | case booleanValue: 584 | return value_.bool_ < other.value_.bool_; 585 | case stringValue: 586 | return ( value_.string_ == 0 && other.value_.string_ ) 587 | || ( other.value_.string_ 588 | && value_.string_ 589 | && strcmp( value_.string_, other.value_.string_ ) < 0 ); 590 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 591 | case arrayValue: 592 | case objectValue: 593 | { 594 | int delta = int( value_.map_->size() - other.value_.map_->size() ); 595 | if ( delta ) 596 | return delta < 0; 597 | return (*value_.map_) < (*other.value_.map_); 598 | } 599 | #else 600 | case arrayValue: 601 | return value_.array_->compare( *(other.value_.array_) ) < 0; 602 | case objectValue: 603 | return value_.map_->compare( *(other.value_.map_) ) < 0; 604 | #endif 605 | default: 606 | JSON_ASSERT_UNREACHABLE; 607 | } 608 | return 0; // unreachable 609 | } 610 | 611 | bool 612 | Value::operator <=( const Value &other ) const 613 | { 614 | return !(other > *this); 615 | } 616 | 617 | bool 618 | Value::operator >=( const Value &other ) const 619 | { 620 | return !(*this < other); 621 | } 622 | 623 | bool 624 | Value::operator >( const Value &other ) const 625 | { 626 | return other < *this; 627 | } 628 | 629 | bool 630 | Value::operator ==( const Value &other ) const 631 | { 632 | //if ( type_ != other.type_ ) 633 | // GCC 2.95.3 says: 634 | // attempt to take address of bit-field structure member `Json::Value::type_' 635 | // Beats me, but a temp solves the problem. 636 | int temp = other.type_; 637 | if ( type_ != temp ) 638 | return false; 639 | switch ( type_ ) 640 | { 641 | case nullValue: 642 | return true; 643 | case intValue: 644 | return value_.int_ == other.value_.int_; 645 | case uintValue: 646 | return value_.uint_ == other.value_.uint_; 647 | case realValue: 648 | return value_.real_ == other.value_.real_; 649 | case booleanValue: 650 | return value_.bool_ == other.value_.bool_; 651 | case stringValue: 652 | return ( value_.string_ == other.value_.string_ ) 653 | || ( other.value_.string_ 654 | && value_.string_ 655 | && strcmp( value_.string_, other.value_.string_ ) == 0 ); 656 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 657 | case arrayValue: 658 | case objectValue: 659 | return value_.map_->size() == other.value_.map_->size() 660 | && (*value_.map_) == (*other.value_.map_); 661 | #else 662 | case arrayValue: 663 | return value_.array_->compare( *(other.value_.array_) ) == 0; 664 | case objectValue: 665 | return value_.map_->compare( *(other.value_.map_) ) == 0; 666 | #endif 667 | default: 668 | JSON_ASSERT_UNREACHABLE; 669 | } 670 | return 0; // unreachable 671 | } 672 | 673 | bool 674 | Value::operator !=( const Value &other ) const 675 | { 676 | return !( *this == other ); 677 | } 678 | 679 | const char * 680 | Value::asCString() const 681 | { 682 | JSON_ASSERT( type_ == stringValue ); 683 | return value_.string_; 684 | } 685 | 686 | 687 | std::string 688 | Value::asString() const 689 | { 690 | switch ( type_ ) 691 | { 692 | case nullValue: 693 | return ""; 694 | case stringValue: 695 | return value_.string_ ? value_.string_ : ""; 696 | case booleanValue: 697 | return value_.bool_ ? "true" : "false"; 698 | case intValue: 699 | return boost::lexical_cast(value_.int_); 700 | case uintValue: 701 | case realValue: 702 | case arrayValue: 703 | case objectValue: 704 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); 705 | default: 706 | JSON_ASSERT_UNREACHABLE; 707 | } 708 | return ""; // unreachable 709 | } 710 | 711 | # ifdef JSON_USE_CPPTL 712 | CppTL::ConstString 713 | Value::asConstString() const 714 | { 715 | return CppTL::ConstString( asString().c_str() ); 716 | } 717 | # endif 718 | 719 | Value::Int 720 | Value::asInt() const 721 | { 722 | switch ( type_ ) 723 | { 724 | case nullValue: 725 | return 0; 726 | case intValue: 727 | return value_.int_; 728 | case uintValue: 729 | JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); 730 | return value_.uint_; 731 | case realValue: 732 | JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); 733 | return Int( value_.real_ ); 734 | case booleanValue: 735 | return value_.bool_ ? 1 : 0; 736 | case stringValue: 737 | return boost::lexical_cast(value_.string_); 738 | case arrayValue: 739 | case objectValue: 740 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); 741 | default: 742 | JSON_ASSERT_UNREACHABLE; 743 | } 744 | return 0; // unreachable; 745 | } 746 | 747 | Value::UInt 748 | Value::asUInt() const 749 | { 750 | switch ( type_ ) 751 | { 752 | case nullValue: 753 | return 0; 754 | case intValue: 755 | JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); 756 | return value_.int_; 757 | case uintValue: 758 | return value_.uint_; 759 | case realValue: 760 | JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); 761 | return UInt( value_.real_ ); 762 | case booleanValue: 763 | return value_.bool_ ? 1 : 0; 764 | case stringValue: 765 | return boost::lexical_cast(value_.string_); 766 | case arrayValue: 767 | case objectValue: 768 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); 769 | default: 770 | JSON_ASSERT_UNREACHABLE; 771 | } 772 | return 0; // unreachable; 773 | } 774 | 775 | double 776 | Value::asDouble() const 777 | { 778 | switch ( type_ ) 779 | { 780 | case nullValue: 781 | return 0.0; 782 | case intValue: 783 | return value_.int_; 784 | case uintValue: 785 | return value_.uint_; 786 | case realValue: 787 | return value_.real_; 788 | case booleanValue: 789 | return value_.bool_ ? 1.0 : 0.0; 790 | case stringValue: 791 | case arrayValue: 792 | case objectValue: 793 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); 794 | default: 795 | JSON_ASSERT_UNREACHABLE; 796 | } 797 | return 0; // unreachable; 798 | } 799 | 800 | bool 801 | Value::asBool() const 802 | { 803 | switch ( type_ ) 804 | { 805 | case nullValue: 806 | return false; 807 | case intValue: 808 | case uintValue: 809 | return value_.int_ != 0; 810 | case realValue: 811 | return value_.real_ != 0.0; 812 | case booleanValue: 813 | return value_.bool_; 814 | case stringValue: 815 | return value_.string_ && value_.string_[0] != 0; 816 | case arrayValue: 817 | case objectValue: 818 | return value_.map_->size() != 0; 819 | default: 820 | JSON_ASSERT_UNREACHABLE; 821 | } 822 | return false; // unreachable; 823 | } 824 | 825 | 826 | bool 827 | Value::isConvertibleTo( ValueType other ) const 828 | { 829 | switch ( type_ ) 830 | { 831 | case nullValue: 832 | return true; 833 | case intValue: 834 | return ( other == nullValue && value_.int_ == 0 ) 835 | || other == intValue 836 | || ( other == uintValue && value_.int_ >= 0 ) 837 | || other == realValue 838 | || other == stringValue 839 | || other == booleanValue; 840 | case uintValue: 841 | return ( other == nullValue && value_.uint_ == 0 ) 842 | || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) 843 | || other == uintValue 844 | || other == realValue 845 | || other == stringValue 846 | || other == booleanValue; 847 | case realValue: 848 | return ( other == nullValue && value_.real_ == 0.0 ) 849 | || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) 850 | || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) 851 | || other == realValue 852 | || other == stringValue 853 | || other == booleanValue; 854 | case booleanValue: 855 | return ( other == nullValue && value_.bool_ == false ) 856 | || other == intValue 857 | || other == uintValue 858 | || other == realValue 859 | || other == stringValue 860 | || other == booleanValue; 861 | case stringValue: 862 | return other == stringValue 863 | || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); 864 | case arrayValue: 865 | return other == arrayValue 866 | || ( other == nullValue && value_.map_->size() == 0 ); 867 | case objectValue: 868 | return other == objectValue 869 | || ( other == nullValue && value_.map_->size() == 0 ); 870 | default: 871 | JSON_ASSERT_UNREACHABLE; 872 | } 873 | return false; // unreachable; 874 | } 875 | 876 | 877 | /// Number of values in array or object 878 | Value::UInt 879 | Value::size() const 880 | { 881 | switch ( type_ ) 882 | { 883 | case nullValue: 884 | case intValue: 885 | case uintValue: 886 | case realValue: 887 | case booleanValue: 888 | case stringValue: 889 | return 0; 890 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 891 | case arrayValue: // size of the array is highest index + 1 892 | if ( !value_.map_->empty() ) 893 | { 894 | ObjectValues::const_iterator itLast = value_.map_->end(); 895 | --itLast; 896 | return (*itLast).first.index()+1; 897 | } 898 | return 0; 899 | case objectValue: 900 | return Int( value_.map_->size() ); 901 | #else 902 | case arrayValue: 903 | return Int( value_.array_->size() ); 904 | case objectValue: 905 | return Int( value_.map_->size() ); 906 | #endif 907 | default: 908 | JSON_ASSERT_UNREACHABLE; 909 | } 910 | return 0; // unreachable; 911 | } 912 | 913 | 914 | bool 915 | Value::empty() const 916 | { 917 | if ( isNull() || isArray() || isObject() ) 918 | return size() == 0u; 919 | else 920 | return false; 921 | } 922 | 923 | 924 | bool 925 | Value::operator!() const 926 | { 927 | return isNull(); 928 | } 929 | 930 | 931 | void 932 | Value::clear() 933 | { 934 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); 935 | 936 | switch ( type_ ) 937 | { 938 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 939 | case arrayValue: 940 | case objectValue: 941 | value_.map_->clear(); 942 | break; 943 | #else 944 | case arrayValue: 945 | value_.array_->clear(); 946 | break; 947 | case objectValue: 948 | value_.map_->clear(); 949 | break; 950 | #endif 951 | default: 952 | break; 953 | } 954 | } 955 | 956 | void 957 | Value::resize( UInt newSize ) 958 | { 959 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); 960 | if ( type_ == nullValue ) 961 | *this = Value( arrayValue ); 962 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 963 | UInt oldSize = size(); 964 | if ( newSize == 0 ) 965 | clear(); 966 | else if ( newSize > oldSize ) 967 | (*this)[ newSize - 1 ]; 968 | else 969 | { 970 | for ( UInt index = newSize; index < oldSize; ++index ) 971 | value_.map_->erase( index ); 972 | assert( size() == newSize ); 973 | } 974 | #else 975 | value_.array_->resize( newSize ); 976 | #endif 977 | } 978 | 979 | 980 | Value & 981 | Value::operator[]( UInt index ) 982 | { 983 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); 984 | if ( type_ == nullValue ) 985 | *this = Value( arrayValue ); 986 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 987 | CZString key( index ); 988 | ObjectValues::iterator it = value_.map_->lower_bound( key ); 989 | if ( it != value_.map_->end() && (*it).first == key ) 990 | return (*it).second; 991 | 992 | ObjectValues::value_type defaultValue( key, null ); 993 | it = value_.map_->insert( it, defaultValue ); 994 | return (*it).second; 995 | #else 996 | return value_.array_->resolveReference( index ); 997 | #endif 998 | } 999 | 1000 | 1001 | const Value & 1002 | Value::operator[]( UInt index ) const 1003 | { 1004 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); 1005 | if ( type_ == nullValue ) 1006 | return null; 1007 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 1008 | CZString key( index ); 1009 | ObjectValues::const_iterator it = value_.map_->find( key ); 1010 | if ( it == value_.map_->end() ) 1011 | return null; 1012 | return (*it).second; 1013 | #else 1014 | Value *value = value_.array_->find( index ); 1015 | return value ? *value : null; 1016 | #endif 1017 | } 1018 | 1019 | 1020 | Value & 1021 | Value::operator[]( const char *key ) 1022 | { 1023 | return resolveReference( key, false ); 1024 | } 1025 | 1026 | 1027 | Value & 1028 | Value::resolveReference( const char *key, 1029 | bool isStatic ) 1030 | { 1031 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); 1032 | if ( type_ == nullValue ) 1033 | *this = Value( objectValue ); 1034 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 1035 | CZString actualKey( key, isStatic ? CZString::noDuplication 1036 | : CZString::duplicateOnCopy ); 1037 | ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); 1038 | if ( it != value_.map_->end() && (*it).first == actualKey ) 1039 | return (*it).second; 1040 | 1041 | ObjectValues::value_type defaultValue( actualKey, null ); 1042 | it = value_.map_->insert( it, defaultValue ); 1043 | Value &value = (*it).second; 1044 | return value; 1045 | #else 1046 | return value_.map_->resolveReference( key, isStatic ); 1047 | #endif 1048 | } 1049 | 1050 | 1051 | Value 1052 | Value::get( UInt index, 1053 | const Value &defaultValue ) const 1054 | { 1055 | const Value *value = &((*this)[index]); 1056 | return value == &null ? defaultValue : *value; 1057 | } 1058 | 1059 | 1060 | bool 1061 | Value::isValidIndex( UInt index ) const 1062 | { 1063 | return index < size(); 1064 | } 1065 | 1066 | 1067 | 1068 | const Value & 1069 | Value::operator[]( const char *key ) const 1070 | { 1071 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); 1072 | if ( type_ == nullValue ) 1073 | return null; 1074 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 1075 | CZString actualKey( key, CZString::noDuplication ); 1076 | ObjectValues::const_iterator it = value_.map_->find( actualKey ); 1077 | if ( it == value_.map_->end() ) 1078 | return null; 1079 | return (*it).second; 1080 | #else 1081 | const Value *value = value_.map_->find( key ); 1082 | return value ? *value : null; 1083 | #endif 1084 | } 1085 | 1086 | 1087 | Value & 1088 | Value::operator[]( const std::string &key ) 1089 | { 1090 | return (*this)[ key.c_str() ]; 1091 | } 1092 | 1093 | 1094 | const Value & 1095 | Value::operator[]( const std::string &key ) const 1096 | { 1097 | return (*this)[ key.c_str() ]; 1098 | } 1099 | 1100 | Value & 1101 | Value::operator[]( const StaticString &key ) 1102 | { 1103 | return resolveReference( key, true ); 1104 | } 1105 | 1106 | 1107 | # ifdef JSON_USE_CPPTL 1108 | Value & 1109 | Value::operator[]( const CppTL::ConstString &key ) 1110 | { 1111 | return (*this)[ key.c_str() ]; 1112 | } 1113 | 1114 | 1115 | const Value & 1116 | Value::operator[]( const CppTL::ConstString &key ) const 1117 | { 1118 | return (*this)[ key.c_str() ]; 1119 | } 1120 | # endif 1121 | 1122 | 1123 | Value & 1124 | Value::append( const Value &value ) 1125 | { 1126 | return (*this)[size()] = value; 1127 | } 1128 | 1129 | 1130 | Value 1131 | Value::get( const char *key, 1132 | const Value &defaultValue ) const 1133 | { 1134 | const Value *value = &((*this)[key]); 1135 | return value == &null ? defaultValue : *value; 1136 | } 1137 | 1138 | 1139 | Value 1140 | Value::get( const std::string &key, 1141 | const Value &defaultValue ) const 1142 | { 1143 | return get( key.c_str(), defaultValue ); 1144 | } 1145 | 1146 | Value 1147 | Value::removeMember( const char* key ) 1148 | { 1149 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); 1150 | if ( type_ == nullValue ) 1151 | return null; 1152 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 1153 | CZString actualKey( key, CZString::noDuplication ); 1154 | ObjectValues::iterator it = value_.map_->find( actualKey ); 1155 | if ( it == value_.map_->end() ) 1156 | return null; 1157 | Value old(it->second); 1158 | value_.map_->erase(it); 1159 | return old; 1160 | #else 1161 | Value *value = value_.map_->find( key ); 1162 | if (value){ 1163 | Value old(*value); 1164 | value_.map_.remove( key ); 1165 | return old; 1166 | } else { 1167 | return null; 1168 | } 1169 | #endif 1170 | } 1171 | 1172 | Value 1173 | Value::removeMember( const std::string &key ) 1174 | { 1175 | return removeMember( key.c_str() ); 1176 | } 1177 | 1178 | # ifdef JSON_USE_CPPTL 1179 | Value 1180 | Value::get( const CppTL::ConstString &key, 1181 | const Value &defaultValue ) const 1182 | { 1183 | return get( key.c_str(), defaultValue ); 1184 | } 1185 | # endif 1186 | 1187 | bool 1188 | Value::isMember( const char *key ) const 1189 | { 1190 | const Value *value = &((*this)[key]); 1191 | return value != &null; 1192 | } 1193 | 1194 | 1195 | bool 1196 | Value::isMember( const std::string &key ) const 1197 | { 1198 | return isMember( key.c_str() ); 1199 | } 1200 | 1201 | 1202 | # ifdef JSON_USE_CPPTL 1203 | bool 1204 | Value::isMember( const CppTL::ConstString &key ) const 1205 | { 1206 | return isMember( key.c_str() ); 1207 | } 1208 | #endif 1209 | 1210 | Value::Members 1211 | Value::getMemberNames() const 1212 | { 1213 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); 1214 | if ( type_ == nullValue ) 1215 | return Value::Members(); 1216 | Members members; 1217 | members.reserve( value_.map_->size() ); 1218 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 1219 | ObjectValues::const_iterator it = value_.map_->begin(); 1220 | ObjectValues::const_iterator itEnd = value_.map_->end(); 1221 | for ( ; it != itEnd; ++it ) 1222 | members.push_back( std::string( (*it).first.c_str() ) ); 1223 | #else 1224 | ValueInternalMap::IteratorState it; 1225 | ValueInternalMap::IteratorState itEnd; 1226 | value_.map_->makeBeginIterator( it ); 1227 | value_.map_->makeEndIterator( itEnd ); 1228 | for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) 1229 | members.push_back( std::string( ValueInternalMap::key( it ) ) ); 1230 | #endif 1231 | return members; 1232 | } 1233 | // 1234 | //# ifdef JSON_USE_CPPTL 1235 | //EnumMemberNames 1236 | //Value::enumMemberNames() const 1237 | //{ 1238 | // if ( type_ == objectValue ) 1239 | // { 1240 | // return CppTL::Enum::any( CppTL::Enum::transform( 1241 | // CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), 1242 | // MemberNamesTransform() ) ); 1243 | // } 1244 | // return EnumMemberNames(); 1245 | //} 1246 | // 1247 | // 1248 | //EnumValues 1249 | //Value::enumValues() const 1250 | //{ 1251 | // if ( type_ == objectValue || type_ == arrayValue ) 1252 | // return CppTL::Enum::anyValues( *(value_.map_), 1253 | // CppTL::Type() ); 1254 | // return EnumValues(); 1255 | //} 1256 | // 1257 | //# endif 1258 | 1259 | 1260 | bool 1261 | Value::isNull() const 1262 | { 1263 | return type_ == nullValue; 1264 | } 1265 | 1266 | 1267 | bool 1268 | Value::isBool() const 1269 | { 1270 | return type_ == booleanValue; 1271 | } 1272 | 1273 | 1274 | bool 1275 | Value::isInt() const 1276 | { 1277 | return type_ == intValue; 1278 | } 1279 | 1280 | 1281 | bool 1282 | Value::isUInt() const 1283 | { 1284 | return type_ == uintValue; 1285 | } 1286 | 1287 | 1288 | bool 1289 | Value::isIntegral() const 1290 | { 1291 | return type_ == intValue 1292 | || type_ == uintValue 1293 | || type_ == booleanValue; 1294 | } 1295 | 1296 | 1297 | bool 1298 | Value::isDouble() const 1299 | { 1300 | return type_ == realValue; 1301 | } 1302 | 1303 | 1304 | bool 1305 | Value::isNumeric() const 1306 | { 1307 | return isIntegral() || isDouble(); 1308 | } 1309 | 1310 | 1311 | bool 1312 | Value::isString() const 1313 | { 1314 | return type_ == stringValue; 1315 | } 1316 | 1317 | 1318 | bool 1319 | Value::isArray() const 1320 | { 1321 | return type_ == nullValue || type_ == arrayValue; 1322 | } 1323 | 1324 | 1325 | bool 1326 | Value::isObject() const 1327 | { 1328 | return type_ == nullValue || type_ == objectValue; 1329 | } 1330 | 1331 | 1332 | void 1333 | Value::setComment( const char *comment, 1334 | CommentPlacement placement ) 1335 | { 1336 | if ( !comments_ ) 1337 | comments_ = new CommentInfo[numberOfCommentPlacement]; 1338 | comments_[placement].setComment( comment ); 1339 | } 1340 | 1341 | 1342 | void 1343 | Value::setComment( const std::string &comment, 1344 | CommentPlacement placement ) 1345 | { 1346 | setComment( comment.c_str(), placement ); 1347 | } 1348 | 1349 | 1350 | bool 1351 | Value::hasComment( CommentPlacement placement ) const 1352 | { 1353 | return comments_ != 0 && comments_[placement].comment_ != 0; 1354 | } 1355 | 1356 | std::string 1357 | Value::getComment( CommentPlacement placement ) const 1358 | { 1359 | if ( hasComment(placement) ) 1360 | return comments_[placement].comment_; 1361 | return ""; 1362 | } 1363 | 1364 | 1365 | std::string 1366 | Value::toStyledString() const 1367 | { 1368 | StyledWriter writer; 1369 | return writer.write( *this ); 1370 | } 1371 | 1372 | 1373 | Value::const_iterator 1374 | Value::begin() const 1375 | { 1376 | switch ( type_ ) 1377 | { 1378 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 1379 | case arrayValue: 1380 | if ( value_.array_ ) 1381 | { 1382 | ValueInternalArray::IteratorState it; 1383 | value_.array_->makeBeginIterator( it ); 1384 | return const_iterator( it ); 1385 | } 1386 | break; 1387 | case objectValue: 1388 | if ( value_.map_ ) 1389 | { 1390 | ValueInternalMap::IteratorState it; 1391 | value_.map_->makeBeginIterator( it ); 1392 | return const_iterator( it ); 1393 | } 1394 | break; 1395 | #else 1396 | case arrayValue: 1397 | case objectValue: 1398 | if ( value_.map_ ) 1399 | return const_iterator( value_.map_->begin() ); 1400 | break; 1401 | #endif 1402 | default: 1403 | break; 1404 | } 1405 | return const_iterator(); 1406 | } 1407 | 1408 | Value::const_iterator 1409 | Value::end() const 1410 | { 1411 | switch ( type_ ) 1412 | { 1413 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 1414 | case arrayValue: 1415 | if ( value_.array_ ) 1416 | { 1417 | ValueInternalArray::IteratorState it; 1418 | value_.array_->makeEndIterator( it ); 1419 | return const_iterator( it ); 1420 | } 1421 | break; 1422 | case objectValue: 1423 | if ( value_.map_ ) 1424 | { 1425 | ValueInternalMap::IteratorState it; 1426 | value_.map_->makeEndIterator( it ); 1427 | return const_iterator( it ); 1428 | } 1429 | break; 1430 | #else 1431 | case arrayValue: 1432 | case objectValue: 1433 | if ( value_.map_ ) 1434 | return const_iterator( value_.map_->end() ); 1435 | break; 1436 | #endif 1437 | default: 1438 | break; 1439 | } 1440 | return const_iterator(); 1441 | } 1442 | 1443 | 1444 | Value::iterator 1445 | Value::begin() 1446 | { 1447 | switch ( type_ ) 1448 | { 1449 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 1450 | case arrayValue: 1451 | if ( value_.array_ ) 1452 | { 1453 | ValueInternalArray::IteratorState it; 1454 | value_.array_->makeBeginIterator( it ); 1455 | return iterator( it ); 1456 | } 1457 | break; 1458 | case objectValue: 1459 | if ( value_.map_ ) 1460 | { 1461 | ValueInternalMap::IteratorState it; 1462 | value_.map_->makeBeginIterator( it ); 1463 | return iterator( it ); 1464 | } 1465 | break; 1466 | #else 1467 | case arrayValue: 1468 | case objectValue: 1469 | if ( value_.map_ ) 1470 | return iterator( value_.map_->begin() ); 1471 | break; 1472 | #endif 1473 | default: 1474 | break; 1475 | } 1476 | return iterator(); 1477 | } 1478 | 1479 | Value::iterator 1480 | Value::end() 1481 | { 1482 | switch ( type_ ) 1483 | { 1484 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 1485 | case arrayValue: 1486 | if ( value_.array_ ) 1487 | { 1488 | ValueInternalArray::IteratorState it; 1489 | value_.array_->makeEndIterator( it ); 1490 | return iterator( it ); 1491 | } 1492 | break; 1493 | case objectValue: 1494 | if ( value_.map_ ) 1495 | { 1496 | ValueInternalMap::IteratorState it; 1497 | value_.map_->makeEndIterator( it ); 1498 | return iterator( it ); 1499 | } 1500 | break; 1501 | #else 1502 | case arrayValue: 1503 | case objectValue: 1504 | if ( value_.map_ ) 1505 | return iterator( value_.map_->end() ); 1506 | break; 1507 | #endif 1508 | default: 1509 | break; 1510 | } 1511 | return iterator(); 1512 | } 1513 | 1514 | 1515 | // class PathArgument 1516 | // ////////////////////////////////////////////////////////////////// 1517 | 1518 | PathArgument::PathArgument() 1519 | : kind_( kindNone ) 1520 | { 1521 | } 1522 | 1523 | 1524 | PathArgument::PathArgument( Value::UInt index ) 1525 | : index_( index ) 1526 | , kind_( kindIndex ) 1527 | { 1528 | } 1529 | 1530 | 1531 | PathArgument::PathArgument( const char *key ) 1532 | : key_( key ) 1533 | , kind_( kindKey ) 1534 | { 1535 | } 1536 | 1537 | 1538 | PathArgument::PathArgument( const std::string &key ) 1539 | : key_( key.c_str() ) 1540 | , kind_( kindKey ) 1541 | { 1542 | } 1543 | 1544 | // class Path 1545 | // ////////////////////////////////////////////////////////////////// 1546 | 1547 | Path::Path( const std::string &path, 1548 | const PathArgument &a1, 1549 | const PathArgument &a2, 1550 | const PathArgument &a3, 1551 | const PathArgument &a4, 1552 | const PathArgument &a5 ) 1553 | { 1554 | InArgs in; 1555 | in.push_back( &a1 ); 1556 | in.push_back( &a2 ); 1557 | in.push_back( &a3 ); 1558 | in.push_back( &a4 ); 1559 | in.push_back( &a5 ); 1560 | makePath( path, in ); 1561 | } 1562 | 1563 | 1564 | void 1565 | Path::makePath( const std::string &path, 1566 | const InArgs &in ) 1567 | { 1568 | const char *current = path.c_str(); 1569 | const char *end = current + path.length(); 1570 | InArgs::const_iterator itInArg = in.begin(); 1571 | while ( current != end ) 1572 | { 1573 | if ( *current == '[' ) 1574 | { 1575 | ++current; 1576 | if ( *current == '%' ) 1577 | addPathInArg( path, in, itInArg, PathArgument::kindIndex ); 1578 | else 1579 | { 1580 | Value::UInt index = 0; 1581 | for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) 1582 | index = index * 10 + Value::UInt(*current - '0'); 1583 | args_.push_back( index ); 1584 | } 1585 | if ( current == end || *current++ != ']' ) 1586 | invalidPath( path, int(current - path.c_str()) ); 1587 | } 1588 | else if ( *current == '%' ) 1589 | { 1590 | addPathInArg( path, in, itInArg, PathArgument::kindKey ); 1591 | ++current; 1592 | } 1593 | else if ( *current == '.' ) 1594 | { 1595 | ++current; 1596 | } 1597 | else 1598 | { 1599 | const char *beginName = current; 1600 | while ( current != end && !strchr( "[.", *current ) ) 1601 | ++current; 1602 | args_.push_back( std::string( beginName, current ) ); 1603 | } 1604 | } 1605 | } 1606 | 1607 | 1608 | void 1609 | Path::addPathInArg( const std::string &path, 1610 | const InArgs &in, 1611 | InArgs::const_iterator &itInArg, 1612 | PathArgument::Kind kind ) 1613 | { 1614 | if ( itInArg == in.end() ) 1615 | { 1616 | // Error: missing argument %d 1617 | } 1618 | else if ( (*itInArg)->kind_ != kind ) 1619 | { 1620 | // Error: bad argument type 1621 | } 1622 | else 1623 | { 1624 | args_.push_back( **itInArg ); 1625 | } 1626 | } 1627 | 1628 | 1629 | void 1630 | Path::invalidPath( const std::string &path, 1631 | int location ) 1632 | { 1633 | // Error: invalid path. 1634 | } 1635 | 1636 | 1637 | const Value & 1638 | Path::resolve( const Value &root ) const 1639 | { 1640 | const Value *node = &root; 1641 | for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) 1642 | { 1643 | const PathArgument &arg = *it; 1644 | if ( arg.kind_ == PathArgument::kindIndex ) 1645 | { 1646 | if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) 1647 | { 1648 | // Error: unable to resolve path (array value expected at position... 1649 | } 1650 | node = &((*node)[arg.index_]); 1651 | } 1652 | else if ( arg.kind_ == PathArgument::kindKey ) 1653 | { 1654 | if ( !node->isObject() ) 1655 | { 1656 | // Error: unable to resolve path (object value expected at position...) 1657 | } 1658 | node = &((*node)[arg.key_]); 1659 | if ( node == &Value::null ) 1660 | { 1661 | // Error: unable to resolve path (object has no member named '' at position...) 1662 | } 1663 | } 1664 | } 1665 | return *node; 1666 | } 1667 | 1668 | 1669 | Value 1670 | Path::resolve( const Value &root, 1671 | const Value &defaultValue ) const 1672 | { 1673 | const Value *node = &root; 1674 | for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) 1675 | { 1676 | const PathArgument &arg = *it; 1677 | if ( arg.kind_ == PathArgument::kindIndex ) 1678 | { 1679 | if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) 1680 | return defaultValue; 1681 | node = &((*node)[arg.index_]); 1682 | } 1683 | else if ( arg.kind_ == PathArgument::kindKey ) 1684 | { 1685 | if ( !node->isObject() ) 1686 | return defaultValue; 1687 | node = &((*node)[arg.key_]); 1688 | if ( node == &Value::null ) 1689 | return defaultValue; 1690 | } 1691 | } 1692 | return *node; 1693 | } 1694 | 1695 | 1696 | Value & 1697 | Path::make( Value &root ) const 1698 | { 1699 | Value *node = &root; 1700 | for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) 1701 | { 1702 | const PathArgument &arg = *it; 1703 | if ( arg.kind_ == PathArgument::kindIndex ) 1704 | { 1705 | if ( !node->isArray() ) 1706 | { 1707 | // Error: node is not an array at position ... 1708 | } 1709 | node = &((*node)[arg.index_]); 1710 | } 1711 | else if ( arg.kind_ == PathArgument::kindKey ) 1712 | { 1713 | if ( !node->isObject() ) 1714 | { 1715 | // Error: node is not an object at position... 1716 | } 1717 | node = &((*node)[arg.key_]); 1718 | } 1719 | } 1720 | return *node; 1721 | } 1722 | 1723 | 1724 | } // namespace Json 1725 | --------------------------------------------------------------------------------