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