/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). /// It is intented to be used with #include // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: LICENSE // ////////////////////////////////////////////////////////////////////// /* The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... The author (Baptiste Lepilleur) explicitly disclaims copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License The full text of the MIT License follows: ======================================================================== Copyright (c) 2007-2010 Baptiste Lepilleur Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================================================================== (END LICENSE TEXT) The MIT license is compatible with both the GPL and commercial software, affording one all of the rights of Public Domain with the minor nuisance of being required to keep the above copyright notice and license text in the source code. Note also that by accepting the Public Domain "license" you can re-license your copy using whatever license you like. */ // ////////////////////////////////////////////////////////////////////// // End of content of file: LICENSE // ////////////////////////////////////////////////////////////////////// #include // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_tool.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED /* This header provides common string manipulation support, such as UTF-8, * portable conversion from/to string... * * It is an internal header that must not be exposed. */ namespace Json { /// Converts a unicode code-point to UTF-8. static inline std::string codePointToUTF8(unsigned int cp) { std::string result; // based on description from http://en.wikipedia.org/wiki/UTF-8 if (cp (cp); } else if (cp (0x80 | (0x3f & cp)); result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); } else if (cp (0x80 | (0x3f & cp)); result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); } else if (cp (0x80 | (0x3f & cp)); result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); } return result; } /// Returns true if ch is a control character (in range [0,32[). static inline bool isControlCharacter(char ch) { return ch > 0 && ch #include #include #include "json_tool.h" #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include #include #if defined(_MSC_VER) && _MSC_VER = 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif namespace Json { // Implementation of class Features // //////////////////////////////// Features::Features() : allowComments_(true), strictRoot_(false), allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} Features Features::all() { return Features(); } Features Features::strictMode() { Features features; features.allowComments_ = false; features.strictRoot_ = true; features.allowDroppedNullPlaceholders_ = false; features.allowNumericKeys_ = false; return features; } // Implementation of class Reader // //////////////////////////////// static inline bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4) { return c == c1 || c == c2 || c == c3 || c == c4; } static inline bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5) { return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; } static bool containsNewLine(Reader::Location begin, Reader::Location end) { for (; begin begin(sin); // std::istream_iterator end; // Those would allow streamed input from a file, if parse() were a // template function. // Since std::string is reference-counted, this at least does not // create an extra copy. std::string doc; std::getline(sin, doc, (char)EOF); return parse(doc, root, collectComments); } bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments) { if (!features_.allowComments_) { collectComments = false; } begin_ = beginDoc; end_ = endDoc; collectComments_ = collectComments; current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; commentsBefore_ = ""; errors_.clear(); while (!nodes_.empty()) nodes_.pop(); nodes_.push(&root); bool successful = readValue(); Token token; skipCommentTokens(token); if (collectComments_ && !commentsBefore_.empty()) root.setComment(commentsBefore_, commentAfter); if (features_.strictRoot_) { if (!root.isArray() && !root.isObject()) { // Set error location to start of doc, ideally should be first token found // in doc token.type_ = tokenError; token.start_ = beginDoc; token.end_ = endDoc; addError( "A valid JSON document must be either an array or an object value.", token); return false; } } return successful; } bool Reader::readValue() { Token token; skipCommentTokens(token); bool successful = true; if (collectComments_ && !commentsBefore_.empty()) { // Remove newline characters at the end of the comments size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n"); if (lastNonNewline != std::string::npos) { commentsBefore_.erase(lastNonNewline + 1); } else { commentsBefore_.clear(); } currentValue().setComment(commentsBefore_, commentBefore); commentsBefore_ = ""; } switch (token.type_) { case tokenObjectBegin: successful = readObject(token); currentValue().setOffsetLimit(current_ - begin_); break; case tokenArrayBegin: successful = readArray(token); currentValue().setOffsetLimit(current_ - begin_); break; case tokenNumber: successful = decodeNumber(token); break; case tokenString: successful = decodeString(token); break; case tokenTrue: currentValue() = true; currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); break; case tokenFalse: currentValue() = false; currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); break; case tokenNull: currentValue() = Value(); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); break; case tokenArraySeparator: if (features_.allowDroppedNullPlaceholders_) { // "Un-read" the current token and mark the current value as a null // token. current_--; currentValue() = Value(); currentValue().setOffsetStart(current_ - begin_ - 1); currentValue().setOffsetLimit(current_ - begin_); break; } // Else, fall through... default: currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); return addError("Syntax error: value, object or array expected.", token); } if (collectComments_) { lastValueEnd_ = current_; lastValue_ = &currentValue(); } return successful; } void Reader::skipCommentTokens(Token& token) { if (features_.allowComments_) { do { readToken(token); } while (token.type_ == tokenComment); } else { readToken(token); } } bool Reader::expectToken(TokenType type, Token& token, const char* message) { readToken(token); if (token.type_ != type) return addError(message, token); return true; } bool Reader::readToken(Token& token) { skipSpaces(); token.start_ = current_; Char c = getNextChar(); bool ok = true; switch (c) { case '{': token.type_ = tokenObjectBegin; break; case '}': token.type_ = tokenObjectEnd; break; case '[': token.type_ = tokenArrayBegin; break; case ']': token.type_ = tokenArrayEnd; break; case '"': token.type_ = tokenString; ok = readString(); break; case '/': token.type_ = tokenComment; ok = readComment(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': token.type_ = tokenNumber; readNumber(); break; case 't': token.type_ = tokenTrue; ok = match("rue", 3); break; case 'f': token.type_ = tokenFalse; ok = match("alse", 4); break; case 'n': token.type_ = tokenNull; ok = match("ull", 3); break; case ',': token.type_ = tokenArraySeparator; break; case ':': token.type_ = tokenMemberSeparator; break; case 0: token.type_ = tokenEndOfStream; break; default: ok = false; break; } if (!ok) token.type_ = tokenError; token.end_ = current_; return true; } void Reader::skipSpaces() { while (current_ != end_) { Char c = *current_; if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++current_; else break; } } bool Reader::match(Location pattern, int patternLength) { if (end_ - current_ setComment(std::string(begin, end), placement); } else { commentsBefore_ += std::string(begin, end); } } bool Reader::readCStyleComment() { while (current_ != end_) { Char c = getNextChar(); if (c == '*' && *current_ == '/') break; } return getNextChar() == '/'; } bool Reader::readCppStyleComment() { while (current_ != end_) { Char c = getNextChar(); if (c == '\r' || c == '\n') break; } return true; } void Reader::readNumber() { while (current_ != end_) { if (!(*current_ >= '0' && *current_ '9') return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); Value::UInt digit(c - '0'); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, b) this is the last digit, and // c) it's small enough to fit in that rounding delta, we're okay. // Otherwise treat this number as a double to avoid overflow. if (value > threshold || current != token.end_ || digit > maxIntegerValue % 10) { return decodeDouble(token, decoded); } } value = value * 10 + digit; } if (isNegative) decoded = -Value::LargestInt(value); else if (value = 0xD800 && unicode = '0' && c = 'a' && c = 'A' && c Reader::getStructuredErrors() const { std::vector<:structurederror> allErrors; for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { const ErrorInfo& error = *itError; Reader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; structured.offset_limit = error.token_.end_ - begin_; structured.message = error.message_; allErrors.push_back(structured); } return allErrors; } bool Reader::pushError(const Value& value, const std::string& message) { size_t length = end_ - begin_; if(value.getOffsetStart() > length || value.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; token.start_ = begin_ + value.getOffsetStart(); token.end_ = end_ + value.getOffsetLimit(); ErrorInfo info; info.token_ = token; info.message_ = message; info.extra_ = 0; errors_.push_back(info); return true; } bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) { size_t length = end_ - begin_; if(value.getOffsetStart() > length || value.getOffsetLimit() > length || extra.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; token.start_ = begin_ + value.getOffsetStart(); token.end_ = begin_ + value.getOffsetLimit(); ErrorInfo info; info.token_ = token; info.message_ = message; info.extra_ = begin_ + extra.getOffsetStart(); errors_.push_back(info); return true; } bool Reader::good() const { return !errors_.size(); } std::istream& operator>>(std::istream& sin, Value& root) { Json::Reader reader; bool ok = reader.parse(sin, root, true); if (!ok) { fprintf(stderr, "Error from reader: %s", reader.getFormattedErrorMessages().c_str()); JSON_FAIL_MESSAGE("reader error"); } return sin; } } // namespace Json // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_reader.cpp // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_batchallocator.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED #define JSONCPP_BATCHALLOCATOR_H_INCLUDED #include #include #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION namespace Json { /* Fast memory allocator. * * This memory allocator allocates memory for a batch of object (specified by * the page size, the number of object in each page). * * It does not allow the destruction of a single object. All the allocated * objects can be destroyed at once. The memory can be either released or reused * for future allocation. * * The in-place new operator must be used to construct the object using the * pointer returned by allocate. */ template class BatchAllocator { public: BatchAllocator(unsigned int objectsPerPage = 255) : freeHead_(0), objectsPerPage_(objectsPerPage) { // printf( "Size: %d => %s\n", sizeof(AllocatedType), // typeid(AllocatedType).name() ); assert(sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType*)); // We must be able to store a slist in the // object free space. assert(objectsPerPage >= 16); batches_ = allocateBatch(0); // allocated a dummy page currentBatch_ = batches_; } ~BatchAllocator() { for (BatchInfo* batch = batches_; batch;) { BatchInfo* nextBatch = batch->next_; free(batch); batch = nextBatch; } } /// allocate space for an array of objectPerAllocation object. /// @warning it is the responsability of the caller to call objects /// constructors. AllocatedType* allocate() { if (freeHead_) // returns node from free list. { AllocatedType* object = freeHead_; freeHead_ = *(AllocatedType**)object; return object; } if (currentBatch_->used_ == currentBatch_->end_) { currentBatch_ = currentBatch_->next_; while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_) currentBatch_ = currentBatch_->next_; if (!currentBatch_) // no free batch found, allocate a new one { currentBatch_ = allocateBatch(objectsPerPage_); currentBatch_->next_ = batches_; // insert at the head of the list batches_ = currentBatch_; } } AllocatedType* allocated = currentBatch_->used_; currentBatch_->used_ += objectPerAllocation; return allocated; } /// Release the object. /// @warning it is the responsability of the caller to actually destruct the /// object. void release(AllocatedType* object) { assert(object != 0); *(AllocatedType**)object = freeHead_; freeHead_ = object; } private: struct BatchInfo { BatchInfo* next_; AllocatedType* used_; AllocatedType* end_; AllocatedType buffer_[objectPerAllocation]; }; // disabled copy constructor and assignement operator. BatchAllocator(const BatchAllocator&); void operator=(const BatchAllocator&); static BatchInfo* allocateBatch(unsigned int objectsPerPage) { const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; BatchInfo* batch = static_cast(malloc(mallocSize)); batch->next_ = 0; batch->used_ = batch->buffer_; batch->end_ = batch->buffer_ + objectsPerPage; return batch; } BatchInfo* batches_; BatchInfo* currentBatch_; /// Head of a single linked list within the allocated space of freeed object AllocatedType* freeHead_; unsigned int objectsPerPage_; }; } // namespace Json #endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_batchallocator.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_valueiterator.inl // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE // included by json_value.cpp namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIteratorBase // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIteratorBase::ValueIteratorBase() #ifndef JSON_VALUE_USE_INTERNAL_MAP : current_(), isNull_(true) { } #else : isArray_(true), isNull_(true) { iterator_.array_ = ValueInternalArray::IteratorState(); } #endif #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator& current) : current_(current), isNull_(false) {} #else ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState& state) : isArray_(true) { iterator_.array_ = state; } ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState& state) : isArray_(false) { iterator_.map_ = state; } #endif Value& ValueIteratorBase::deref() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP return current_->second; #else if (isArray_) return ValueInternalArray::dereference(iterator_.array_); return ValueInternalMap::value(iterator_.map_); #endif } void ValueIteratorBase::increment() { #ifndef JSON_VALUE_USE_INTERNAL_MAP ++current_; #else if (isArray_) ValueInternalArray::increment(iterator_.array_); ValueInternalMap::increment(iterator_.map_); #endif } void ValueIteratorBase::decrement() { #ifndef JSON_VALUE_USE_INTERNAL_MAP --current_; #else if (isArray_) ValueInternalArray::decrement(iterator_.array_); ValueInternalMap::decrement(iterator_.map_); #endif } ValueIteratorBase::difference_type ValueIteratorBase::computeDistance(const SelfType& other) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP #ifdef JSON_USE_CPPTL_SMALLMAP return current_ - other.current_; #else // Iterator for null value are initialized using the default // constructor, which initialize current_ to the default // std::map::iterator. As begin() and end() are two instance // of the default std::map::iterator, they can not be compared. // To allow this, we handle this comparison specifically. if (isNull_ && other.isNull_) { return 0; } // Usage of std::distance is not portable (does not compile with Sun Studio 12 // RogueWave STL, // which is the one used by default). // Using a portable hand-made version for non random iterator instead: // return difference_type( std::distance( current_, other.current_ ) ); difference_type myDistance = 0; for (Value::ObjectValues::iterator it = current_; it != other.current_; ++it) { ++myDistance; } return myDistance; #endif #else if (isArray_) return ValueInternalArray::distance(iterator_.array_, other.iterator_.array_); return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_); #endif } bool ValueIteratorBase::isEqual(const SelfType& other) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP if (isNull_) { return other.isNull_; } return current_ == other.current_; #else if (isArray_) return ValueInternalArray::equals(iterator_.array_, other.iterator_.array_); return ValueInternalMap::equals(iterator_.map_, other.iterator_.map_); #endif } void ValueIteratorBase::copy(const SelfType& other) { #ifndef JSON_VALUE_USE_INTERNAL_MAP current_ = other.current_; isNull_ = other.isNull_; #else if (isArray_) iterator_.array_ = other.iterator_.array_; iterator_.map_ = other.iterator_.map_; #endif } Value ValueIteratorBase::key() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if (czstring.c_str()) { if (czstring.isStaticString()) return Value(StaticString(czstring.c_str())); return Value(czstring.c_str()); } return Value(czstring.index()); #else if (isArray_) return Value(ValueInternalArray::indexOf(iterator_.array_)); bool isStatic; const char* memberName = ValueInternalMap::key(iterator_.map_, isStatic); if (isStatic) return Value(StaticString(memberName)); return Value(memberName); #endif } UInt ValueIteratorBase::index() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if (!czstring.c_str()) return czstring.index(); return Value::UInt(-1); #else if (isArray_) return Value::UInt(ValueInternalArray::indexOf(iterator_.array_)); return Value::UInt(-1); #endif } const char* ValueIteratorBase::memberName() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const char* name = (*current_).first.c_str(); return name ? name : ""; #else if (!isArray_) return ValueInternalMap::key(iterator_.map_); return ""; #endif } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueConstIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueConstIterator::ValueConstIterator() {} #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator& current) : ValueIteratorBase(current) {} #else ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState& state) : ValueIteratorBase(state) {} ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState& state) : ValueIteratorBase(state) {} #endif ValueConstIterator& ValueConstIterator:: operator=(const ValueIteratorBase& other) { copy(other); return *this; } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIterator::ValueIterator() {} #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) : ValueIteratorBase(current) {} #else ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state) : ValueIteratorBase(state) {} ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state) : ValueIteratorBase(state) {} #endif ValueIterator::ValueIterator(const ValueConstIterator& other) : ValueIteratorBase(other) {} ValueIterator::ValueIterator(const ValueIterator& other) : ValueIteratorBase(other) {} ValueIterator& ValueIterator::operator=(const SelfType& other) { copy(other); return *this; } } // namespace Json // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_valueiterator.inl // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_value.cpp // ////////////////////////////////////////////////////////////////////// // Copyright 2011 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) #include #include #include #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #include "json_batchallocator.h" #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include #include #ifdef JSON_USE_CPPTL #include #endif #include // size_t #define JSON_ASSERT_UNREACHABLE assert(false) namespace Json { // This is a walkaround to avoid the static initialization of Value::null. // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of // 8 (instead of 4) as a bit of future-proofing. #if defined(__ARMEL__) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #else #define ALIGNAS(byte_alignment) #endif static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; const unsigned char& kNullRef = kNull[0]; const Value& Value::null = reinterpret_cast(kNullRef); const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); const UInt Value::maxUInt = UInt(-1); #if defined(JSON_HAS_INT64) const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); const UInt64 Value::maxUInt64 = UInt64(-1); // The constant is hard-coded because some compiler have trouble // converting Value::maxUInt64 to a double correctly (AIX/xlC). // Assumes that UInt64 is a 64 bits integer. static const double maxUInt64AsDouble = 18446744073709551615.0; #endif // defined(JSON_HAS_INT64) const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); const LargestUInt Value::maxLargestUInt = LargestUInt(-1); /// Unknown size marker static const unsigned int unknown = (unsigned)-1; #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template static inline bool InRange(double d, T min, U max) { return d >= min && d (Int64(value / 2)) * 2.0 + Int64(value & 1); } template static inline double integerToDouble(T value) { return static_cast(value); } template static inline bool InRange(double d, T min, U max) { return d >= integerToDouble(min) && d = (unsigned)Value::maxInt) length = Value::maxInt - 1; char* newString = static_cast(malloc(length + 1)); JSON_ASSERT_MESSAGE(newString != 0, "in Json::Value::duplicateStringValue(): " "Failed to allocate string value buffer"); memcpy(newString, value, length); newString[length] = 0; return newString; } /** Free the string duplicated by duplicateStringValue(). */ static inline void releaseStringValue(char* value) { free(value); } } // namespace Json // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ValueInternals... // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #if !defined(JSON_IS_AMALGAMATION) #ifdef JSON_VALUE_USE_INTERNAL_MAP #include "json_internalarray.inl" #include "json_internalmap.inl" #endif // JSON_VALUE_USE_INTERNAL_MAP #include "json_valueiterator.inl" #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::CommentInfo // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// Value::CommentInfo::CommentInfo() : comment_(0) {} Value::CommentInfo::~CommentInfo() { if (comment_) releaseStringValue(comment_); } void Value::CommentInfo::setComment(const char* text) { if (comment_) releaseStringValue(comment_); JSON_ASSERT(text != 0); JSON_ASSERT_MESSAGE( text[0] == '\0' || text[0] == '/', "in Json::Value::setComment(): Comments must start with /"); // It seems that /**/ style comments are acceptable as well. comment_ = duplicateStringValue(text); } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::CZString // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #ifndef JSON_VALUE_USE_INTERNAL_MAP // Notes: index_ indicates if the string was allocated when // a string is stored. Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate) : cstr_(allocate == duplicate ? duplicateStringValue(cstr) : cstr), index_(allocate) {} Value::CZString::CZString(const CZString& other) : cstr_(other.index_ != noDuplication && other.cstr_ != 0 ? duplicateStringValue(other.cstr_) : other.cstr_), index_(other.cstr_ ? static_cast(other.index_ == noDuplication ? noDuplication : duplicate) : other.index_) {} Value::CZString::~CZString() { if (cstr_ && index_ == duplicate) releaseStringValue(const_cast(cstr_)); } void Value::CZString::swap(CZString& other) { std::swap(cstr_, other.cstr_); std::swap(index_, other.index_); } Value::CZString& Value::CZString::operator=(CZString other) { swap(other); return *this; } bool Value::CZString::operatornewArray(); break; case objectValue: value_.map_ = mapAllocator()->newMap(); break; #endif case booleanValue: value_.bool_ = false; break; default: JSON_ASSERT_UNREACHABLE; } } Value::Value(Int value) { initBasic(intValue); value_.int_ = value; } Value::Value(UInt value) { initBasic(uintValue); value_.uint_ = value; } #if defined(JSON_HAS_INT64) Value::Value(Int64 value) { initBasic(intValue); value_.int_ = value; } Value::Value(UInt64 value) { initBasic(uintValue); value_.uint_ = value; } #endif // defined(JSON_HAS_INT64) Value::Value(double value) { initBasic(realValue); value_.real_ = value; } Value::Value(const char* value) { initBasic(stringValue, true); value_.string_ = duplicateStringValue(value); } Value::Value(const char* beginValue, const char* endValue) { initBasic(stringValue, true); value_.string_ = duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue)); } Value::Value(const std::string& value) { initBasic(stringValue, true); value_.string_ = duplicateStringValue(value.c_str(), (unsigned int)value.length()); } Value::Value(const StaticString& value) { initBasic(stringValue); value_.string_ = const_cast(value.c_str()); } #ifdef JSON_USE_CPPTL Value::Value(const CppTL::ConstString& value) { initBasic(stringValue, true); value_.string_ = duplicateStringValue(value, value.length()); } #endif Value::Value(bool value) { initBasic(booleanValue); value_.bool_ = value; } Value::Value(const Value& other) : type_(other.type_), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(other.start_), limit_(other.limit_) { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: value_ = other.value_; break; case stringValue: if (other.value_.string_) { value_.string_ = duplicateStringValue(other.value_.string_); allocated_ = true; } else { value_.string_ = 0; allocated_ = false; } break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(*other.value_.map_); break; #else case arrayValue: value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_); break; case objectValue: value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_); break; #endif default: JSON_ASSERT_UNREACHABLE; } if (other.comments_) { comments_ = new CommentInfo[numberOfCommentPlacement]; for (int comment = 0; comment destructArray(value_.array_); break; case objectValue: mapAllocator()->destructMap(value_.map_); break; #endif default: JSON_ASSERT_UNREACHABLE; } if (comments_) delete[] comments_; } Value& Value::operator=(Value other) { swap(other); return *this; } void Value::swap(Value& other) { ValueType temp = type_; type_ = other.type_; other.type_ = temp; std::swap(value_, other.value_); int temp2 = allocated_; allocated_ = other.allocated_; other.allocated_ = temp2; std::swap(start_, other.start_); std::swap(limit_, other.limit_); } ValueType Value::type() const { return type_; } int Value::compare(const Value& other) const { if (*this other) return 1; return 0; } bool Value::operatorsize() - other.value_.map_->size()); if (delta) return delta compare(*(other.value_.array_)) compare(*(other.value_.map_)) =(const Value& other) const { return !(*this (const Value& other) const { return other size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_); #else case arrayValue: return value_.array_->compare(*(other.value_.array_)) == 0; case objectValue: return value_.map_->compare(*(other.value_.map_)) == 0; #endif default: JSON_ASSERT_UNREACHABLE; } return false; // unreachable } bool Value::operator!=(const Value& other) const { return !(*this == other); } const char* Value::asCString() const { JSON_ASSERT_MESSAGE(type_ == stringValue, "in Json::Value::asCString(): requires stringValue"); return value_.string_; } std::string Value::asString() const { switch (type_) { case nullValue: return ""; case stringValue: return value_.string_ ? value_.string_ : ""; case booleanValue: return value_.bool_ ? "true" : "false"; case intValue: return valueToString(value_.int_); case uintValue: return valueToString(value_.uint_); case realValue: return valueToString(value_.real_); default: JSON_FAIL_MESSAGE("Type is not convertible to string"); } } #ifdef JSON_USE_CPPTL CppTL::ConstString Value::asConstString() const { return CppTL::ConstString(asString().c_str()); } #endif Value::Int Value::asInt() const { switch (type_) { case intValue: JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); return Int(value_.int_); case uintValue: JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); return Int(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), "double out of Int range"); return Int(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to Int."); } Value::UInt Value::asUInt() const { switch (type_) { case intValue: JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); return UInt(value_.int_); case uintValue: JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); return UInt(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), "double out of UInt range"); return UInt(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to UInt."); } #if defined(JSON_HAS_INT64) Value::Int64 Value::asInt64() const { switch (type_) { case intValue: return Int64(value_.int_); case uintValue: JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); return Int64(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range"); return Int64(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to Int64."); } Value::UInt64 Value::asUInt64() const { switch (type_) { case intValue: JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); return UInt64(value_.int_); case uintValue: return UInt64(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range"); return UInt64(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); } #endif // if defined(JSON_HAS_INT64) LargestInt Value::asLargestInt() const { #if defined(JSON_NO_INT64) return asInt(); #else return asInt64(); #endif } LargestUInt Value::asLargestUInt() const { #if defined(JSON_NO_INT64) return asUInt(); #else return asUInt64(); #endif } double Value::asDouble() const { switch (type_) { case intValue: return static_cast(value_.int_); case uintValue: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(value_.uint_); #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return integerToDouble(value_.uint_); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return value_.real_; case nullValue: return 0.0; case booleanValue: return value_.bool_ ? 1.0 : 0.0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to double."); } float Value::asFloat() const { switch (type_) { case intValue: return static_cast(value_.int_); case uintValue: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(value_.uint_); #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return integerToDouble(value_.uint_); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return static_cast(value_.real_); case nullValue: return 0.0; case booleanValue: return value_.bool_ ? 1.0f : 0.0f; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to float."); } bool Value::asBool() const { switch (type_) { case booleanValue: return value_.bool_; case nullValue: return false; case intValue: return value_.int_ ? true : false; case uintValue: return value_.uint_ ? true : false; case realValue: return value_.real_ ? true : false; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to bool."); } bool Value::isConvertibleTo(ValueType other) const { switch (other) { case nullValue: return (isNumeric() && asDouble() == 0.0) || (type_ == booleanValue && value_.bool_ == false) || (type_ == stringValue && asString() == "") || (type_ == arrayValue && value_.map_->size() == 0) || (type_ == objectValue && value_.map_->size() == 0) || type_ == nullValue; case intValue: return isInt() || (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || type_ == booleanValue || type_ == nullValue; case uintValue: return isUInt() || (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || type_ == booleanValue || type_ == nullValue; case realValue: return isNumeric() || type_ == booleanValue || type_ == nullValue; case booleanValue: return isNumeric() || type_ == booleanValue || type_ == nullValue; case stringValue: return isNumeric() || type_ == booleanValue || type_ == stringValue || type_ == nullValue; case arrayValue: return type_ == arrayValue || type_ == nullValue; case objectValue: return type_ == objectValue || type_ == nullValue; } JSON_ASSERT_UNREACHABLE; return false; } /// Number of values in array or object ArrayIndex Value::size() const { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: case stringValue: return 0; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: // size of the array is highest index + 1 if (!value_.map_->empty()) { ObjectValues::const_iterator itLast = value_.map_->end(); --itLast; return (*itLast).first.index() + 1; } return 0; case objectValue: return ArrayIndex(value_.map_->size()); #else case arrayValue: return Int(value_.array_->size()); case objectValue: return Int(value_.map_->size()); #endif } JSON_ASSERT_UNREACHABLE; return 0; // unreachable; } bool Value::empty() const { if (isNull() || isArray() || isObject()) return size() == 0u; else return false; } bool Value::operator!() const { return isNull(); } void Value::clear() { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || type_ == objectValue, "in Json::Value::clear(): requires complex value"); start_ = 0; limit_ = 0; switch (type_) { #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_->clear(); break; #else case arrayValue: value_.array_->clear(); break; case objectValue: value_.map_->clear(); break; #endif default: break; } } void Value::resize(ArrayIndex newSize) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, "in Json::Value::resize(): requires arrayValue"); if (type_ == nullValue) *this = Value(arrayValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP ArrayIndex oldSize = size(); if (newSize == 0) clear(); else if (newSize > oldSize) (*this)[newSize - 1]; else { for (ArrayIndex index = newSize; index erase(index); } assert(size() == newSize); } #else value_.array_->resize(newSize); #endif } Value& Value::operator[](ArrayIndex index) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex): requires arrayValue"); if (type_ == nullValue) *this = Value(arrayValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key(index); ObjectValues::iterator it = value_.map_->lower_bound(key); if (it != value_.map_->end() && (*it).first == key) return (*it).second; ObjectValues::value_type defaultValue(key, null); it = value_.map_->insert(it, defaultValue); return (*it).second; #else return value_.array_->resolveReference(index); #endif } Value& Value::operator[](int index) { JSON_ASSERT_MESSAGE( index >= 0, "in Json::Value::operator[](int index): index cannot be negative"); return (*this)[ArrayIndex(index)]; } const Value& Value::operator[](ArrayIndex index) const { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); if (type_ == nullValue) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); if (it == value_.map_->end()) return null; return (*it).second; #else Value* value = value_.array_->find(index); return value ? *value : null; #endif } const Value& Value::operator[](int index) const { JSON_ASSERT_MESSAGE( index >= 0, "in Json::Value::operator[](int index) const: index cannot be negative"); return (*this)[ArrayIndex(index)]; } Value& Value::operator[](const char* key) { return resolveReference(key, false); } void Value::initBasic(ValueType type, bool allocated) { type_ = type; allocated_ = allocated; #ifdef JSON_VALUE_USE_INTERNAL_MAP itemIsUsed_ = 0; #endif comments_ = 0; start_ = 0; limit_ = 0; } Value& Value::resolveReference(const char* key, bool isStatic) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::resolveReference(): requires objectValue"); if (type_ == nullValue) *this = Value(objectValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey( key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy); ObjectValues::iterator it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; ObjectValues::value_type defaultValue(actualKey, null); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; #else return value_.map_->resolveReference(key, isStatic); #endif } Value Value::get(ArrayIndex index, const Value& defaultValue) const { const Value* value = &((*this)[index]); return value == &null ? defaultValue : *value; } bool Value::isValidIndex(ArrayIndex index) const { return index find(actualKey); if (it == value_.map_->end()) return null; return (*it).second; #else const Value* value = value_.map_->find(key); return value ? *value : null; #endif } Value& Value::operator[](const std::string& key) { return (*this)[key.c_str()]; } const Value& Value::operator[](const std::string& key) const { return (*this)[key.c_str()]; } Value& Value::operator[](const StaticString& key) { return resolveReference(key, true); } #ifdef JSON_USE_CPPTL Value& Value::operator[](const CppTL::ConstString& key) { return (*this)[key.c_str()]; } const Value& Value::operator[](const CppTL::ConstString& key) const { return (*this)[key.c_str()]; } #endif Value& Value::append(const Value& value) { return (*this)[size()] = value; } Value Value::get(const char* key, const Value& defaultValue) const { const Value* value = &((*this)[key]); return value == &null ? defaultValue : *value; } Value Value::get(const std::string& key, const Value& defaultValue) const { return get(key.c_str(), defaultValue); } Value Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey(key, CZString::noDuplication); ObjectValues::iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return null; Value old(it->second); value_.map_->erase(it); return old; #else Value* value = value_.map_->find(key); if (value) { Value old(*value); value_.map_.remove(key); return old; } else { return null; } #endif } Value Value::removeMember(const std::string& key) { return removeMember(key.c_str()); } #ifdef JSON_USE_CPPTL Value Value::get(const CppTL::ConstString& key, const Value& defaultValue) const { return get(key.c_str(), defaultValue); } #endif bool Value::isMember(const char* key) const { const Value* value = &((*this)[key]); return value != &null; } bool Value::isMember(const std::string& key) const { return isMember(key.c_str()); } #ifdef JSON_USE_CPPTL bool Value::isMember(const CppTL::ConstString& key) const { return isMember(key.c_str()); } #endif Value::Members Value::getMemberNames() const { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::getMemberNames(), value must be objectValue"); if (type_ == nullValue) return Value::Members(); Members members; members.reserve(value_.map_->size()); #ifndef JSON_VALUE_USE_INTERNAL_MAP ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); for (; it != itEnd; ++it) members.push_back(std::string((*it).first.c_str())); #else ValueInternalMap::IteratorState it; ValueInternalMap::IteratorState itEnd; value_.map_->makeBeginIterator(it); value_.map_->makeEndIterator(itEnd); for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it)) members.push_back(std::string(ValueInternalMap::key(it))); #endif return members; } // //# ifdef JSON_USE_CPPTL // EnumMemberNames // Value::enumMemberNames() const //{ // if ( type_ == objectValue ) // { // return CppTL::Enum::any( CppTL::Enum::transform( // CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), // MemberNamesTransform() ) ); // } // return EnumMemberNames(); //} // // // EnumValues // Value::enumValues() const //{ // if ( type_ == objectValue || type_ == arrayValue ) // return CppTL::Enum::anyValues( *(value_.map_), // CppTL::Type() ); // return EnumValues(); //} // //# endif static bool IsIntegral(double d) { double integral_part; return modf(d, &integral_part) == 0.0; } bool Value::isNull() const { return type_ == nullValue; } bool Value::isBool() const { return type_ == booleanValue; } bool Value::isInt() const { switch (type_) { case intValue: return value_.int_ >= minInt && value_.int_ = minInt && value_.real_ = 0 && LargestUInt(value_.int_) = 0 && value_.real_ = double(minInt64) && value_.real_ = 0; case uintValue: return true; case realValue: // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we // require the value to be strictly less than the limit. return value_.real_ >= 0 && value_.real_ makeBeginIterator(it); return const_iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator(it); return const_iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->begin()); break; #endif default: break; } return const_iterator(); } Value::const_iterator Value::end() const { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator(it); return const_iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator(it); return const_iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->end()); break; #endif default: break; } return const_iterator(); } Value::iterator Value::begin() { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeBeginIterator(it); return iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator(it); return iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->begin()); break; #endif default: break; } return iterator(); } Value::iterator Value::end() { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator(it); return iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator(it); return iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->end()); break; #endif default: break; } return iterator(); } // class PathArgument // ////////////////////////////////////////////////////////////////// PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} PathArgument::PathArgument(ArrayIndex index) : key_(), index_(index), kind_(kindIndex) {} PathArgument::PathArgument(const char* key) : key_(key), index_(), kind_(kindKey) {} PathArgument::PathArgument(const std::string& key) : key_(key.c_str()), index_(), kind_(kindKey) {} // class Path // ////////////////////////////////////////////////////////////////// Path::Path(const std::string& path, const PathArgument& a1, const PathArgument& a2, const PathArgument& a3, const PathArgument& a4, const PathArgument& a5) { InArgs in; in.push_back(&a1); in.push_back(&a2); in.push_back(&a3); in.push_back(&a4); in.push_back(&a5); makePath(path, in); } void Path::makePath(const std::string& path, const InArgs& in) { const char* current = path.c_str(); const char* end = current + path.length(); InArgs::const_iterator itInArg = in.begin(); while (current != end) { if (*current == '[') { ++current; if (*current == '%') addPathInArg(path, in, itInArg, PathArgument::kindIndex); else { ArrayIndex index = 0; for (; current != end && *current >= '0' && *current kind_ != kind) { // Error: bad argument type } else { args_.push_back(**itInArg); } } void Path::invalidPath(const std::string& /*path*/, int /*location*/) { // Error: invalid path. } const Value& Path::resolve(const Value& root) const { const Value* node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument& arg = *it; if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) { // Error: unable to resolve path (array value expected at position... } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: unable to resolve path (object value expected at position...) } node = &((*node)[arg.key_]); if (node == &Value::null) { // Error: unable to resolve path (object has no member named '' at // position...) } } } return *node; } Value Path::resolve(const Value& root, const Value& defaultValue) const { const Value* node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument& arg = *it; if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) return defaultValue; node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) return defaultValue; node = &((*node)[arg.key_]); if (node == &Value::null) return defaultValue; } } return *node; } Value& Path::make(Value& root) const { Value* node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument& arg = *it; if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray()) { // Error: node is not an array at position ... } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: node is not an object at position... } node = &((*node)[arg.key_]); } } return *node; } } // namespace Json // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_value.cpp // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_writer.cpp // ////////////////////////////////////////////////////////////////////// // Copyright 2011 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) #include #include "json_tool.h" #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include #include #include #include #if defined(_MSC_VER) && _MSC_VER #define isfinite _finite #define snprintf _snprintf #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif namespace Json { static bool containsControlCharacter(const char* str) { while (*str) { if (isControlCharacter(*(str++))) return true; } return false; } std::string valueToString(LargestInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); bool isNegative = value = buffer); return current; } std::string valueToString(LargestUInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); uintToString(value, current); assert(current >= buffer); return current; } #if defined(JSON_HAS_INT64) std::string valueToString(Int value) { return valueToString(LargestInt(value)); } std::string valueToString(UInt value) { return valueToString(LargestUInt(value)); } #endif // # if defined(JSON_HAS_INT64) std::string valueToString(double value) { // Allocate a buffer that is more than large enough to store the 16 digits of // precision requested below. char buffer[32]; int len = -1; // Print into the buffer. We need not request the alternative representation // that always has a decimal point because JSON doesn't distingish the // concepts of reals and integers. #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with // visual studio 2005 to // avoid warning. #if defined(WINCE) len = _snprintf(buffer, sizeof(buffer), "%.16g", value); #else len = sprintf_s(buffer, sizeof(buffer), "%.16g", value); #endif #else if (isfinite(value)) { len = snprintf(buffer, sizeof(buffer), "%.16g", value); } else { // IEEE standard states that NaN values will not compare to themselves if (value != value) { len = snprintf(buffer, sizeof(buffer), "null"); } else if (value = 0); fixNumericLocale(buffer, buffer + len); return buffer; } std::string valueToString(bool value) { return value ? "true" : "false"; } std::string valueToQuotedString(const char* value) { if (value == NULL) return ""; // Not sure how to handle unicode... if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter(value)) return std::string("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to std::string is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) std::string::size_type maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL std::string result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; for (const char* c = value; *c != 0; ++c) { switch (*c) { case '\"': result += "\\\""; break; case '\\': result += "\\\\"; break; case '\b': result += "\\b"; break; case '\f': result += "\\f"; break; case '\n': result += "\\n"; break; case '\r': result += "\\r"; break; case '\t': result += "\\t"; break; // case '/': // Even though \/ is considered a legal escape in JSON, a bare // slash is also legal, so I see no reason to escape it. // (I hope I am not misunderstanding something. // blep notes: actually escaping \/ may be useful in javascript to avoid // sequence. // Should add a flag to allow this compatibility mode and prevent this // sequence from occurring. default: if (isControlCharacter(*c)) { std::ostringstream oss; oss (*c); result += oss.str(); } else { result += *c; } break; } } result += "\""; return result; } // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() {} // Class FastWriter // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), omitEndingLineFeed_(false) {} void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } std::string FastWriter::write(const Value& root) { document_ = ""; writeValue(root); if (!omitEndingLineFeed_) document_ += "\n"; return document_; } void FastWriter::writeValue(const Value& value) { switch (value.type()) { case nullValue: if (!dropNullPlaceholders_) document_ += "null"; break; case intValue: document_ += valueToString(value.asLargestInt()); break; case uintValue: document_ += valueToString(value.asLargestUInt()); break; case realValue: document_ += valueToString(value.asDouble()); break; case stringValue: document_ += valueToQuotedString(value.asCString()); break; case booleanValue: document_ += valueToString(value.asBool()); break; case arrayValue: { document_ += '['; int size = value.size(); for (int index = 0; index 0) document_ += ','; writeValue(value[index]); } document_ += ']'; } break; case objectValue: { Value::Members members(value.getMemberNames()); document_ += '{'; for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) { const std::string& name = *it; if (it != members.begin()) document_ += ','; document_ += valueToQuotedString(name.c_str()); document_ += yamlCompatiblityEnabled_ ? ": " : ":"; writeValue(value[name]); } document_ += '}'; } break; } } // Class StyledWriter // ////////////////////////////////////////////////////////////////// StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3), addChildValues_() {} std::string StyledWriter::write(const Value& root) { document_ = ""; addChildValues_ = false; indentString_ = ""; writeCommentBeforeValue(root); writeValue(root); writeCommentAfterValueOnSameLine(root); document_ += "\n"; return document_; } void StyledWriter::writeValue(const Value& value) { switch (value.type()) { case nullValue: pushValue("null"); break; case intValue: pushValue(valueToString(value.asLargestInt())); break; case uintValue: pushValue(valueToString(value.asLargestUInt())); break; case realValue: pushValue(valueToString(value.asDouble())); break; case stringValue: pushValue(valueToQuotedString(value.asCString())); break; case booleanValue: pushValue(valueToString(value.asBool())); break; case arrayValue: writeArrayValue(value); break; case objectValue: { Value::Members members(value.getMemberNames()); if (members.empty()) pushValue("{}"); else { writeWithIndent("{"); indent(); Value::Members::iterator it = members.begin(); for (;;) { const std::string& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); document_ += " : "; writeValue(childValue); if (++it == members.end()) { writeCommentAfterValueOnSameLine(childValue); break; } document_ += ','; writeCommentAfterValueOnSameLine(childValue); } unindent(); writeWithIndent("}"); } } break; } } void StyledWriter::writeArrayValue(const Value& value) { unsigned size = value.size(); if (size == 0) pushValue("[]"); else { bool isArrayMultiLine = isMultineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); bool hasChildValue = !childValues_.empty(); unsigned index = 0; for (;;) { const Value& childValue = value[index]; writeCommentBeforeValue(childValue); if (hasChildValue) writeWithIndent(childValues_[index]); else { writeIndent(); writeValue(childValue); } if (++index == size) { writeCommentAfterValueOnSameLine(childValue); break; } document_ += ','; writeCommentAfterValueOnSameLine(childValue); } unindent(); writeWithIndent("]"); } else // output on a single line { assert(childValues_.size() == size); document_ += "[ "; for (unsigned index = 0; index 0) document_ += ", "; document_ += childValues_[index]; } document_ += " ]"; } } } bool StyledWriter::isMultineArray(const Value& value) { int size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); for (int index = 0; index 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' for (int index = 0; index = rightMargin_; } return isMultiLine; } void StyledWriter::pushValue(const std::string& value) { if (addChildValues_) childValues_.push_back(value); else document_ += value; } void StyledWriter::writeIndent() { if (!document_.empty()) { char last = document_[document_.length() - 1]; if (last == ' ') // already indented return; if (last != '\n') // Comments may add new-line document_ += '\n'; } document_ += indentString_; } void StyledWriter::writeWithIndent(const std::string& value) { writeIndent(); document_ += value; } void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } void StyledWriter::unindent() { assert(int(indentString_.size()) >= indentSize_); indentString_.resize(indentString_.size() - indentSize_); } void StyledWriter::writeCommentBeforeValue(const Value& root) { if (!root.hasComment(commentBefore)) return; document_ += "\n"; writeIndent(); std::string normalizedComment = normalizeEOL(root.getComment(commentBefore)); std::string::const_iterator iter = normalizedComment.begin(); while (iter != normalizedComment.end()) { document_ += *iter; if (*iter == '\n' && *(iter + 1) == '/') writeIndent(); ++iter; } // Comments are stripped of newlines, so add one here document_ += "\n"; } void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { if (root.hasComment(commentAfterOnSameLine)) document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine)); if (root.hasComment(commentAfter)) { document_ += "\n"; document_ += normalizeEOL(root.getComment(commentAfter)); document_ += "\n"; } } bool StyledWriter::hasCommentForValue(const Value& value) { return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) || value.hasComment(commentAfter); } std::string StyledWriter::normalizeEOL(const std::string& text) { std::string normalized; normalized.reserve(text.length()); const char* begin = text.c_str(); const char* end = begin + text.length(); const char* current = begin; while (current != end) { char c = *current++; if (c == '\r') // mac or dos EOL { if (*current == '\n') // convert dos EOL ++current; normalized += '\n'; } else // handle unix EOL & other char normalized += c; } return normalized; } // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// StyledStreamWriter::StyledStreamWriter(std::string indentation) : document_(NULL), rightMargin_(74), indentation_(indentation), addChildValues_() {} void StyledStreamWriter::write(std::ostream& out, const Value& root) { document_ = &out; addChildValues_ = false; indentString_ = ""; writeCommentBeforeValue(root); writeValue(root); writeCommentAfterValueOnSameLine(root); *document_ 0) *document_ = rightMargin_; childValues_.clear(); for (int index = 0; index 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' for (int index = 0; index = rightMargin_; } return isMultiLine; } void StyledStreamWriter::pushValue(const std::string& value) { if (addChildValues_) childValues_.push_back(value); else *document_ = indentation_.size()); indentString_.resize(indentString_.size() - indentation_.size()); } void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { if (!root.hasComment(commentBefore)) return; *document_