- return Version(0, 1, 0, 0, VF_VENDOR, API_VERSION);
- }
-};
-
-static void
-unreachable_internal (char const *file, int line, char const *function)
-{
- char buf[1024];
- snprintf (buf, 1024, "%s (%d) [%s] critical: Unreachable line reached.",
- file, line, function);
-
- throw std::runtime_error (buf);
-}
-
-static void
-throw_unless_internal (char const *file, int line, char const *function, char const *condition)
-{
- char buf[1024];
- snprintf (buf, 1024, "%s (%d) [%s] critical: Assertion `%s' failed.",
- file, line, function, condition);
-
- throw std::runtime_error (buf);
-}
-
-static void
-throw_msg_unless_internal (char const *file, int line, char const *function, char const *message)
-{
- char buf[1024];
- snprintf (buf, 1024, "%s (%d) [%s] critical: %s.",
- file, line, function, message);
-
- throw std::runtime_error (buf);
-}
-
-
-namespace json
-{
- ValueIteratorBase::ValueIteratorBase ()
- {
- }
-
-
- ValueIteratorBase::ValueIteratorBase (const Value::ObjectValues::iterator ¤t)
- : current_ (current)
- {
- }
-
- Value &
- ValueIteratorBase::deref () const
- {
- return current_->second;
- }
-
-
- void
- ValueIteratorBase::increment ()
- {
- ++current_;
- }
-
-
- void
- ValueIteratorBase::decrement ()
- {
- --current_;
- }
-
-
- ValueIteratorBase::difference_type
- ValueIteratorBase::computeDistance (const SelfType &other) const
- {
- return difference_type (std::distance (current_, other.current_));
- }
-
-
- bool
- ValueIteratorBase::isEqual (const SelfType &other) const
- {
- return current_ == other.current_;
- }
-
-
- void
- ValueIteratorBase::copy (const SelfType &other)
- {
- current_ = other.current_;
- }
-
-
- Value
- ValueIteratorBase::key () const
- {
- 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 ());
- }
-
-
- unsigned
- ValueIteratorBase::index () const
- {
- const Value::CZString czstring = (*current_).first;
- if (!czstring.c_str ())
- return czstring.index ();
- return unsigned (-1);
- }
-
-
- char const *
- ValueIteratorBase::memberName () const
- {
- char const *name = (*current_).first.c_str ();
- return name ? name : "";
- }
-
-
- ValueConstIterator::ValueConstIterator ()
- {
- }
-
-
- ValueConstIterator::ValueConstIterator (const Value::ObjectValues::iterator ¤t)
- : ValueIteratorBase (current)
- {
- }
-
- ValueConstIterator &
- ValueConstIterator::operator = (const ValueIteratorBase &other)
- {
- copy (other);
- return *this;
- }
-
-
- ValueIterator::ValueIterator ()
- {
- }
-
-
- ValueIterator::ValueIterator (const Value::ObjectValues::iterator ¤t)
- : ValueIteratorBase (current)
- {
- }
-
- 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
-{
- inline bool
- in (char c, char c1, char c2, char c3, char c4)
- {
- return c == c1 || c == c2 || c == c3 || c == c4;
- }
-
- inline bool
- in (char c, char c1, char c2, char c3, char c4, char c5)
- {
- return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
- }
-
-
- Reader::Reader ()
- {
- }
-
- bool
- Reader::parse (const std::string &document,
- Value &root)
- {
- document_ = document;
- char const *begin = document_.c_str ();
- char const *end = begin + document_.length ();
- return parse (begin, end, root);
- }
-
- bool
- Reader::parse (std::istream& sin,
- Value &root)
- {
- std::string doc;
- std::getline (sin, doc, (char)EOF);
- return parse (doc, root);
- }
-
- bool
- Reader::parse (char const *beginDoc, char const *endDOc,
- Value &root)
- {
- begin_ = beginDoc;
- end_ = endDOc;
- current_ = begin_;
- lastValueEnd_ = 0;
- lastValue_ = 0;
- errors_.clear ();
- while (!nodes_.empty ())
- nodes_.pop ();
- nodes_.push (&root);
-
- bool successful = readValue ();
- return successful;
- }
-
-
- bool
- Reader::readValue ()
- {
- Token token;
- do
- readToken (token);
- while (token.type_ == tokenComment);
- bool successful = true;
-
- switch (token.type_)
- {
- case tokenObjectBegin:
- successful = readObject ();
- break;
- case tokenArrayBegin:
- successful = readArray ();
- break;
- case tokenNumber:
- successful = decodeNumber (token);
- break;
- case tokenString:
- successful = decodeString (token);
- break;
- case tokenTrue:
- currentValue () = true;
- break;
- case tokenFalse:
- currentValue () = false;
- break;
- case tokenNull:
- currentValue () = Value ();
- break;
- default:
- return addError ("Syntax error: value, object or array expected.", token);
- }
-
- return successful;
- }
-
-
- bool
- Reader::expectToken (TokenType type, Token &token, char const *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;
-#if 0
-#ifdef __GNUC__
- case '0'...'9':
-#endif
-#else
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9':
-#endif
- 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_ < patternLength)
- return false;
- int index = patternLength;
- while (index--)
- if (current_[index] != pattern[index])
- return false;
- current_ += patternLength;
- return true;
- }
-
-
- void
- Reader::readNumber ()
- {
- while (current_ != end_)
- {
- if (!(*current_ >= '0' && *current_ <= '9') &&
- !in (*current_, '.', 'e', 'E', '+', '-'))
- break;
- ++current_;
- }
- }
-
- bool
- Reader::readString ()
- {
- char c = 0;
- while (current_ != end_)
- {
- c = getNextChar ();
- if (c == '\\')
- getNextChar ();
- else if (c == '"')
- break;
- }
- return c == '"';
- }
-
-
- bool
- Reader::readObject ()
- {
- Token tokenName;
- std::string name;
- currentValue () = Value (objectValue);
- while (readToken (tokenName))
- {
- if (tokenName.type_ == tokenObjectEnd && name.empty ()) // empty object
- return true;
- if (tokenName.type_ != tokenString)
- break;
-
- name = "";
- if (!decodeString (tokenName, name))
- return recoverFromError (tokenObjectEnd);
-
- Token colon;
- if (!readToken (colon) || colon.type_ != tokenMemberSeparator)
- {
- return addErrorAndRecover ("Missing ':' after object member name",
- colon,
- tokenObjectEnd);
- }
- Value &value = currentValue ()[ name ];
- nodes_.push (&value);
- bool ok = readValue ();
- nodes_.pop ();
- if (!ok) // error already set
- return recoverFromError (tokenObjectEnd);
-
- Token comma;
- if (!readToken (comma)
- || (comma.type_ != tokenObjectEnd &&
- comma.type_ != tokenArraySeparator))
- {
- return addErrorAndRecover ("Missing ',' or '}' in object declaration",
- comma,
- tokenObjectEnd);
- }
- if (comma.type_ == tokenObjectEnd)
- return true;
- }
- return addErrorAndRecover ("Missing '}' or object member name",
- tokenName,
- tokenObjectEnd);
- }
-
-
- bool
- Reader::readArray ()
- {
- currentValue () = Value (arrayValue);
- skipSpaces ();
- if (*current_ == ']') // empty array
- {
- Token endArray;
- readToken (endArray);
- return true;
- }
- int index = 0;
- while (true)
- {
- Value &value = currentValue ()[ index++ ];
- nodes_.push (&value);
- bool ok = readValue ();
- nodes_.pop ();
- if (!ok) // error already set
- return recoverFromError (tokenArrayEnd);
-
- Token token;
- if (!readToken (token)
- || (token.type_ != tokenArraySeparator &&
- token.type_ != tokenArrayEnd))
- {
- return addErrorAndRecover ("Missing ',' or ']' in array declaration",
- token,
- tokenArrayEnd);
- }
- if (token.type_ == tokenArrayEnd)
- break;
- }
- return true;
- }
-
-
- bool
- Reader::decodeNumber (Token &token)
- {
- bool isDouble = false;
- for (Location inspect = token.start_; inspect != token.end_; ++inspect)
- {
- isDouble = isDouble
- || in (*inspect, '.', 'e', 'E', '+')
- || (*inspect == '-' && inspect != token.start_);
- }
- if (isDouble)
- return decodeDouble (token);
- Location current = token.start_;
- bool isNegative = *current == '-';
- if (isNegative)
- ++current;
- unsigned threshold = (isNegative ? unsigned (-Value::minInt)
- : Value::maxUInt) / 10;
- unsigned value = 0;
- while (current < token.end_)
- {
- char c = *current++;
- if (c < '0' || c > '9')
- return addError ("'" + std::string (token.start_, token.end_) + "' is not a number.", token);
- if (value >= threshold)
- return decodeDouble (token);
- value = value * 10 + unsigned (c - '0');
- }
- if (isNegative)
- currentValue () = -int (value);
- else if (value <= unsigned (Value::maxInt))
- currentValue () = int (value);
- else
- currentValue () = value;
- return true;
- }
-
-
- bool
- Reader::decodeDouble (Token &token)
- {
- double value = 0;
- const int bufferSize = 32;
- int count;
- int length = int (token.end_ - token.start_);
- if (length <= bufferSize)
- {
- char buffer[bufferSize];
- memcpy (buffer, token.start_, length);
- buffer[length] = 0;
- count = sscanf (buffer, "%lf", &value);
- }
- else
- {
- std::string buffer (token.start_, token.end_);
- count = sscanf (buffer.c_str (), "%lf", &value);
- }
-
- if (count != 1)
- return addError ("'" + std::string (token.start_, token.end_) + "' is not a number.", token);
- currentValue () = value;
- return true;
- }
-
-
- bool
- Reader::decodeString (Token &token)
- {
- std::string decoded;
- if (!decodeString (token, decoded))
- return false;
- currentValue () = decoded;
- return true;
- }
-
-
- bool
- Reader::decodeString (Token &token, std::string &decoded)
- {
- Location current = token.start_ + 1; // skip '"'
- Location end = token.end_ - 1; // do not include '"'
- decoded.reserve (long (end - current));
-
- while (current != end)
- {
- char c = *current++;
- if (expect_false (c == '"'))
- break;
- else if (expect_false (c == '\\'))
- {
- if (expect_false (current == end))
- return addError ("Empty escape sequence in string", token, current);
- char escape = *current++;
- switch (escape)
- {
- case '"':
- case '/':
- case '\\': decoded += escape; break;
-
- case 'b': decoded += '\010'; break;
- case 't': decoded += '\011'; break;
- case 'n': decoded += '\012'; break;
- case 'f': decoded += '\014'; break;
- case 'r': decoded += '\015'; break;
- case 'u':