- default:
- throw_unreachable;
- }
- return 0; // unreachable
- }
-
- bool
- Value::operator <= (const Value &other) const
- {
- return !(other > *this);
- }
-
- bool
- Value::operator >= (const Value &other) const
- {
- return !(*this < other);
- }
-
- bool
- Value::operator > (const Value &other) const
- {
- return other < *this;
- }
-
- bool
- Value::operator == (const Value &other) const
- {
- if (type_ != other.type_)
- return false;
-
- switch (type_)
- {
- case nullValue:
- return true;
- case intValue:
- return value_.int_ == other.value_.int_;
- case uintValue:
- return value_.uint_ == other.value_.uint_;
- case realValue:
- return value_.real_ == other.value_.real_;
- case booleanValue:
- return value_.bool_ == other.value_.bool_;
- case stringValue:
- return (value_.string_ == other.value_.string_)
- || (other.value_.string_
- && value_.string_
- && strcmp (value_.string_, other.value_.string_) == 0);
- case arrayValue:
- case objectValue:
- return value_.map_->size () == other.value_.map_->size ()
- && (*value_.map_) == (*other.value_.map_);
- default:
- throw_unreachable;
- }
- return 0; // unreachable
- }
-
- bool
- Value::operator != (const Value &other) const
- {
- return !(*this == other);
- }
-
- Value::operator char const * () const
- {
- throw_unless (type_ == stringValue);
- return value_.string_;
- }
-
-
- Value::operator std::string () const
- {
- switch (type_)
- {
- case nullValue:
- return "";
- case stringValue:
- return value_.string_ ? value_.string_ : "";
- case booleanValue:
- return value_.bool_ ? "true" : "false";
- case intValue:
- case uintValue:
- case realValue:
- case arrayValue:
- case objectValue:
- throw_msg_unless (false, "Type is not convertible to string");
- default:
- throw_unreachable;
- }
- return ""; // unreachable
- }
-
- Value::operator int () const
- {
- switch (type_)
- {
- case nullValue:
- return 0;
- case intValue:
- return value_.int_;
- case uintValue:
- throw_msg_unless (value_.uint_ < (unsigned)maxInt, "integer out of signed integer range");
- return value_.uint_;
- case realValue:
- throw_msg_unless (value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range");
- return int (value_.real_);
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- case stringValue:
- case arrayValue:
- case objectValue:
- throw_msg_unless (false, "Type is not convertible to int");
- default:
- throw_unreachable;
- }
- return 0; // unreachable;
- }
-
- Value::operator unsigned () const
- {
- switch (type_)
- {
- case nullValue:
- return 0;
- case intValue:
- throw_msg_unless (value_.int_ >= 0, "Negative integer can not be converted to unsigned integer");
- return value_.int_;
- case uintValue:
- return value_.uint_;
- case realValue:
- throw_msg_unless (value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range");
- return unsigned (value_.real_);
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- case stringValue:
- case arrayValue:
- case objectValue:
- throw_msg_unless (false, "Type is not convertible to uint");
- default:
- throw_unreachable;
- }
- return 0; // unreachable;
- }
-
- Value::operator double () const
- {
- switch (type_)
- {
- case nullValue:
- return 0.0;
- case intValue:
- return value_.int_;
- case uintValue:
- return value_.uint_;
- case realValue:
- return value_.real_;
- case booleanValue:
- return value_.bool_ ? 1.0 : 0.0;
- case stringValue:
- case arrayValue:
- case objectValue:
- throw_msg_unless (false, "Type is not convertible to double");
- default:
- throw_unreachable;
- }
- return 0; // unreachable;
- }
-
- Value::operator bool () const
- {
- switch (type_)
- {
- case nullValue:
- return false;
- case intValue:
- case uintValue:
- return value_.int_ != 0;
- case realValue:
- return value_.real_ != 0.0;
- case booleanValue:
- return value_.bool_;
- case stringValue:
- return value_.string_ && value_.string_[0] != 0;
- case arrayValue:
- case objectValue:
- return value_.map_->size () != 0;
- default:
- throw_unreachable;
- }
- return false; // unreachable;
- }
-
-
- bool
- Value::isConvertibleTo (ValueType other) const
- {
- switch (type_)
- {
- case nullValue:
- return true;
- case intValue:
- return (other == nullValue && value_.int_ == 0)
- || other == intValue
- || (other == uintValue && value_.int_ >= 0)
- || other == realValue
- || other == stringValue
- || other == booleanValue;
- case uintValue:
- return (other == nullValue && value_.uint_ == 0)
- || (other == intValue && value_.uint_ <= (unsigned)maxInt)
- || other == uintValue
- || other == realValue
- || other == stringValue
- || other == booleanValue;
- case realValue:
- return (other == nullValue && value_.real_ == 0.0)
- || (other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt)
- || (other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt)
- || other == realValue
- || other == stringValue
- || other == booleanValue;
- case booleanValue:
- return (other == nullValue && value_.bool_ == false)
- || other == intValue
- || other == uintValue
- || other == realValue
- || other == stringValue
- || other == booleanValue;
- case stringValue:
- return other == stringValue
- || (other == nullValue && (!value_.string_ || value_.string_[0] == 0));
- case arrayValue:
- return other == arrayValue
- || (other == nullValue && value_.map_->size () == 0);
- case objectValue:
- return other == objectValue
- || (other == nullValue && value_.map_->size () == 0);
- default:
- throw_unreachable;
- }
- return false; // unreachable;
- }
-
-
- /// Number of values in array or object
- unsigned
- Value::size () const
- {
- switch (type_)
- {
- case nullValue:
- case intValue:
- case uintValue:
- case realValue:
- case booleanValue:
- case stringValue:
- return 0;
- 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 int (value_.map_->size ());
- default:
- throw_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 ()
- {
- throw_unless (type_ == nullValue || type_ == arrayValue || type_ == objectValue);
-
- switch (type_)
- {
- case arrayValue:
- case objectValue:
- value_.map_->clear ();
- break;
- default:
- break;
- }
- }
-
- void
- Value::resize (unsigned newSize)
- {
- throw_unless (type_ == nullValue || type_ == arrayValue);
- if (type_ == nullValue)
- *this = Value (arrayValue);
- unsigned oldSize = size ();
- if (newSize == 0)
- clear ();
- else if (newSize > oldSize)
- (*this)[ newSize - 1 ];
- else
- {
- for (unsigned index = newSize; index < oldSize; ++index)
- value_.map_->erase (index);
- throw_unless (size () == newSize);
- }
- }
-
-
- Value &
- Value::operator [] (int index)
- {
- return operator [] (static_cast<unsigned> (index));
- }
-
-
- Value &
- Value::operator [] (unsigned index)
- {
- throw_unless (type_ == nullValue || type_ == arrayValue);
- if (type_ == nullValue)
- *this = Value (arrayValue);
- 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;
- }
-
-
- const Value &
- Value::operator [] (int index) const
- {
- return operator [] (static_cast<unsigned> (index));
- }
-
-
- const Value &
- Value::operator [] (unsigned index) const
- {
- throw_unless (type_ == nullValue || type_ == arrayValue);
- if (type_ == nullValue)
- return null;
- CZString key (index);
- ObjectValues::const_iterator it = value_.map_->find (key);
- if (it == value_.map_->end ())
- return null;
- return it->second;
- }
-
-
- Value &
- Value::operator [] (char const *key)
- {
- return resolveReference (key, false);
- }
-
-
- Value &
- Value::resolveReference (char const *key, bool isStatic)
- {
- throw_unless (type_ == nullValue || type_ == objectValue);
- if (type_ == nullValue)
- *this = Value (objectValue);
- 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;
- }
-
-
- Value
- Value::get (int index, const Value &defaultValue) const
- {
- return get (static_cast<unsigned> (index), defaultValue);
- }
-
-
- Value
- Value::get (unsigned index, const Value &defaultValue) const
- {
- const Value *value = &((*this)[index]);
- return value == &null ? defaultValue : *value;
- }
-
-
- bool
- Value::isValidIndex (int index) const
- {
- return isValidIndex (static_cast<unsigned> (index));
- }
-
-
- bool
- Value::isValidIndex (unsigned index) const
- {
- return index < size ();
- }
-
-
-
- const Value &
- Value::operator [] (char const *key) const
- {
- throw_unless (type_ == nullValue || type_ == objectValue);
- if (type_ == nullValue)
- return null;
- CZString actualKey (key, CZString::noDuplication);
- ObjectValues::const_iterator it = value_.map_->find (actualKey);
- if (it == value_.map_->end ())
- return null;
- return it->second;
- }
-
-
- 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);
- }
-
-
- Value &
- Value::append (const Value &value)
- {
- return (*this)[size ()] = value;
- }
-
-
- Value
- Value::get (char const *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 (char const *key)
- {
- throw_unless (type_ == nullValue || type_ == objectValue);
- if (type_ == nullValue)
- return null;
- 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;
- }
-
- Value
- Value::removeMember (const std::string &key)
- {
- return removeMember (key.c_str ());
- }
-
- bool
- Value::isMember (char const *key) const
- {
- const Value *value = &((*this)[key]);
- return value != &null;
- }
-
-
- bool
- Value::isMember (const std::string &key) const
- {
- return isMember (key.c_str ());
- }
-
-
- Value::Members
- Value::getMemberNames () const
- {
- throw_unless (type_ == nullValue || type_ == objectValue);
- if (type_ == nullValue)
- return Value::Members ();
- Members members;
- members.reserve (value_.map_->size ());
- ObjectValues::const_iterator it;
- ObjectValues::const_iterator itEnd = value_.map_->end ();
- for (it = value_.map_->begin (); it != itEnd; ++it)
- members.push_back (std::string (it->first.c_str()));
- return members;
- }
-
- bool
- Value::isNull () const
- {
- return type_ == nullValue;
- }
-
-
- bool
- Value::isBool () const
- {
- return type_ == booleanValue;
- }
-
-
- bool
- Value::isInt () const
- {
- return type_ == intValue;
- }
-
-
- bool
- Value::isUInt () const
- {
- return type_ == uintValue;
- }
-
-
- bool
- Value::isIntegral () const
- {
- return type_ == intValue
- || type_ == uintValue
- || type_ == booleanValue;
- }
-
-
- bool
- Value::isDouble () const
- {
- return type_ == realValue;
- }
-
-
- bool
- Value::isNumeric () const
- {
- return isIntegral () || isDouble ();
- }
-
-
- bool
- Value::isString () const
- {
- return type_ == stringValue;
- }
-
-
- bool
- Value::isArray () const
- {
- return type_ == nullValue || type_ == arrayValue;
- }
-
-
- bool
- Value::isObject () const
- {
- return type_ == nullValue || type_ == objectValue;
- }
-
-
- Value::const_iterator
- Value::begin () const
- {
- switch (type_)
- {
- case arrayValue:
- case objectValue:
- if (value_.map_)
- return const_iterator (value_.map_->begin ());
- break;
- default:
- break;
- }
- return const_iterator ();
- }
-
- Value::const_iterator
- Value::end () const
- {
- switch (type_)
- {
- case arrayValue:
- case objectValue:
- if (value_.map_)
- return const_iterator (value_.map_->end ());
- break;
- default:
- break;
- }
- return const_iterator ();
- }
-
-
- Value::iterator
- Value::begin ()
- {
- switch (type_)
- {
- case arrayValue:
- case objectValue:
- if (value_.map_)
- return iterator (value_.map_->begin ());
- break;
- default:
- break;
- }
- return iterator ();
- }
-
- Value::iterator
- Value::end ()
- {
- switch (type_)
- {
- case arrayValue:
- case objectValue:
- if (value_.map_)
- return iterator (value_.map_->end ());
- break;
- default:
- break;
- }
- return iterator ();
- }
-} // namespace json
-
-namespace json
-{
- static void uintToString (unsigned value,
- char *¤t)
- {
- *--current = 0;
- do
- {
- *--current = (value % 10) + '0';
- value /= 10;
- }
- while (value != 0);
- }
-
- std::string valueToString (int value)
- {
- char buffer[32];
- char *current = buffer + sizeof (buffer);
- bool isNegative = value < 0;
- if (isNegative)
- value = -value;
- uintToString (unsigned (value), current);
- if (isNegative)
- *--current = '-';
- throw_unless (current >= buffer);
- return current;
- }
-
-
- std::string valueToString (unsigned value)
- {
- char buffer[32];
- char *current = buffer + sizeof (buffer);
- uintToString (value, current);
- throw_unless (current >= buffer);
- return current;
- }
-
- std::string valueToString (double value)
- {
- char buffer[32];
- sprintf (buffer, "%.16g", value);
- return buffer;
- }
-
-
- std::string valueToString (bool value)
- {
- return value ? "true" : "false";
- }
-
- std::string valueToQuotedString (char const *value)
- {
- // Not sure how to handle unicode...
- if (std::strpbrk (value, "\"\\\b\f\n\r\t") == NULL)
- 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.)
- unsigned maxsize = strlen (value) * 2 + 3; // allescaped+quotes+NULL
- std::string result;
- result.reserve (maxsize); // to avoid lots of mallocs
- result += "\"";
- for (char const* 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.)
- default:
- result += *c;
- }
- }
- result += "\"";
- return result;
- }
-
- // Class Writer
- std::string
- Writer::write (const Value &root)
- {
- document_ = "";
- writeValue (root);
- document_ += "\n";
- return document_;
- }
-
-
- void
- Writer::writeValue (const Value &value)
- {
- switch (value.type ())
- {
- case nullValue:
- document_ += "null";
- break;
- case intValue:
- document_ += valueToString (static_cast<int> (value));
- break;
- case uintValue:
- document_ += valueToString (static_cast<unsigned> (value));
- break;
- case realValue:
- document_ += valueToString (static_cast<double> (value));
- break;
- case stringValue:
- document_ += valueToQuotedString (static_cast<char const *> (value));
- break;
- case booleanValue:
- document_ += valueToString (static_cast<bool> (value));
- break;
- case arrayValue:
- {
- document_ += "[";
- int size = value.size ();
- for (int index = 0; index < size; ++index)
- {
- if (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_ += ":";
- writeValue (value[name]);
- }
- document_ += "}";
- }
- break;
- }
- }
-} // namespace json
-
-/**
- * RPC
- */
-
-namespace json
-{
- namespace rpc
- {
- typedef std::map<std::string, void (*) (HTTPRequest *, Value &, Value &)> method_map;
-
- method_map methods;
-
- void
- add_method (char *name, method mth)
- {
- methods[name] = mth;
- }
-
- void
- system_list_methods (HTTPRequest *http, Value &request, Value &response)
- {
- unsigned i = 0;
- Value method_list (arrayValue);
-
- method_map::iterator it;
- for (it = methods.begin(); it != methods.end(); ++it)