summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
authorspecial <special@e03df62e-2008-0410-955e-edbf42e46eb7>2007-09-13 14:55:21 +0000
committerspecial <special@e03df62e-2008-0410-955e-edbf42e46eb7>2007-09-13 14:55:21 +0000
commitf8f8c81e6fd8993a9de830af0be1709955c28a5f (patch)
tree896738495896a5e9cc31ebda20224555eac451ac /src/modules
parent15f624f682e73d61bf46ef60fe4f4d7a9dda3e8e (diff)
Redesigned m_rpc_json to work properly in a modular environment, and added the beginnings of a framework-inspecific RPC interface for modules. Be warned, this WILL change some - this can be considered an alpha :P
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@8033 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/json.h544
-rw-r--r--src/modules/m_rpc_json.cpp2374
-rw-r--r--src/modules/m_rpctest.cpp68
-rw-r--r--src/modules/rpc.h296
4 files changed, 688 insertions, 2594 deletions
diff --git a/src/modules/json.h b/src/modules/json.h
deleted file mode 100644
index 7643d9713..000000000
--- a/src/modules/json.h
+++ /dev/null
@@ -1,544 +0,0 @@
-#ifndef JSON_H
-#define JSON_H
-
-#include <string>
-#include <vector>
-#include <map>
-#include <deque>
-#include <stack>
-
-#if __GNUC__ >= 3
-# define maybe_expect(expr,value) __builtin_expect ((expr),(value))
-# define is_const(expr) __builtin_constant_p ((expr))
-#else
-# define maybe_expect(expr,value) (expr)
-# define is_const(expr) 0
-#endif
-
-#define expect_false(expr) maybe_expect ((expr) != 0, 0)
-#define expect_true(expr) maybe_expect ((expr) != 0, 1)
-
-#ifdef __GNUC__
-# define CURFUNC __PRETTY_FUNCTION__
-#elif defined(__BORLANDC__)
-# define CURFUNC __FUNC__
-#else
-# define CURFUNC __FUNCTION__
-#endif
-
-namespace json
-{
- class ValueIterator;
- class ValueConstIterator;
-
- enum ValueType
- {
- nullValue = 0,
- intValue,
- uintValue,
- realValue,
- stringValue,
- booleanValue,
- arrayValue,
- objectValue
- };
-
- class StaticString
- {
- public:
- explicit StaticString (char const *czstring)
- : str_ (czstring)
- {
- }
-
- operator char const *() const
- {
- return str_;
- }
-
- char const *c_str() const
- {
- return str_;
- }
-
- private:
- char const *str_;
- };
-
- class Value
- {
- friend class ValueIteratorBase;
- public:
- typedef std::vector<std::string> Members;
- typedef ValueIterator iterator;
- typedef ValueConstIterator const_iterator;
- typedef unsigned ArrayIndex;
-
- static const Value null;
- static const int minInt;
- static const int maxInt;
- static const unsigned maxUInt;
-
- private:
- class CZString
- {
- public:
- enum DuplicationPolicy
- {
- noDuplication = 0,
- duplicate,
- duplicateOnCopy
- };
- CZString (int index);
- CZString (char const *cstr, DuplicationPolicy allocate);
- CZString (const CZString &other);
- ~CZString ();
- CZString &operator = (const CZString &other);
- bool operator < (const CZString &other) const;
- bool operator == (const CZString &other) const;
- int index () const;
- char const *c_str () const;
- bool isStaticString () const;
- private:
- void swap (CZString &other);
- char const *cstr_;
- int index_;
- };
-
- public:
- typedef std::map<CZString, Value> ObjectValues;
-
- public:
- Value (ValueType type = nullValue);
- Value (int value);
- Value (unsigned value);
- Value (double value);
- Value (char const *value);
- Value (const StaticString &value);
- Value (const std::string &value);
- Value (bool value);
- Value (const Value &other);
- ~Value ();
-
- Value &operator = (const Value &other);
-
- void swap (Value &other);
-
- ValueType type () const;
-
- bool operator < (const Value &other) const;
- bool operator <= (const Value &other) const;
- bool operator >= (const Value &other) const;
- bool operator > (const Value &other) const;
-
- bool operator == (const Value &other) const;
- bool operator != (const Value &other) const;
-
- operator char const * () const;
- operator std::string () const;
- operator int () const;
- operator unsigned () const;
- operator double () const;
- operator bool () const;
-
- bool isNull () const;
- bool isBool () const;
- bool isInt () const;
- bool isUInt () const;
- bool isIntegral () const;
- bool isDouble () const;
- bool isNumeric () const;
- bool isString () const;
- bool isArray () const;
- bool isObject () const;
-
- bool isConvertibleTo (ValueType other) const;
-
- unsigned size () const;
-
- bool empty () const;
-
- bool operator ! () const;
-
- void clear ();
-
- void resize (unsigned size);
-
- Value &operator [] (int index);
- Value &operator [] (unsigned index);
- const Value &operator [] (int index) const;
- const Value &operator [] (unsigned index) const;
- Value get (int index, const Value &defaultValue) const;
- Value get (unsigned index, const Value &defaultValue) const;
- bool isValidIndex (int index) const;
- bool isValidIndex (unsigned index) const;
-
- Value &append (const Value &value);
-
- Value &operator [] (char const *key);
- const Value &operator [] (char const *key) const;
- Value &operator [] (const std::string &key);
- const Value &operator [] (const std::string &key) const;
- Value &operator [] (const StaticString &key);
- Value get (char const *key, const Value &defaultValue) const;
- Value get (const std::string &key, const Value &defaultValue) const;
- Value removeMember (char const* key);
- Value removeMember (const std::string &key);
-
- bool isMember (char const *key) const;
- bool isMember (const std::string &key) const;
-
- Members getMemberNames () const;
-
- const_iterator begin () const;
- const_iterator end () const;
-
- iterator begin ();
- iterator end ();
-
- private:
- Value &resolveReference (char const *key, bool isStatic);
-
- struct MemberNamesTransform
- {
- typedef char const *result_type;
- char const *operator () (const CZString &name) const
- {
- return name.c_str ();
- }
- };
-
- union ValueHolder
- {
- int int_;
- unsigned uint_;
- double real_;
- bool bool_;
- char *string_;
- ObjectValues *map_;
- } value_;
-
- ValueType type_ : 8;
- int allocated_ : 1;
- };
-
-
- class ValueAllocator
- {
- public:
- enum { unknown = (unsigned)-1 };
-
- virtual ~ValueAllocator ();
-
- virtual char *makeMemberName (char const *memberName) = 0;
- virtual void releaseMemberName (char *memberName) = 0;
- virtual char *duplicateStringValue (char const *value,
- unsigned length = unknown) = 0;
- virtual void releaseStringValue (char *value) = 0;
- };
-
- class ValueIteratorBase
- {
- public:
- typedef unsigned size_t;
- typedef int difference_type;
- typedef ValueIteratorBase SelfType;
-
- ValueIteratorBase ();
- explicit ValueIteratorBase (const Value::ObjectValues::iterator &current);
-
- bool operator == (const SelfType &other) const
- {
- return isEqual (other);
- }
-
- bool operator != (const SelfType &other) const
- {
- return !isEqual (other);
- }
-
- difference_type operator - (const SelfType &other) const
- {
- return computeDistance (other);
- }
-
- Value key () const;
-
- unsigned index () const;
-
- char const *memberName () const;
-
- protected:
- Value &deref () const;
-
- void increment ();
-
- void decrement ();
-
- difference_type computeDistance (const SelfType &other) const;
-
- bool isEqual (const SelfType &other) const;
-
- void copy (const SelfType &other);
-
- private:
- Value::ObjectValues::iterator current_;
- };
-
- class ValueConstIterator : public ValueIteratorBase
- {
- friend class Value;
- public:
- typedef unsigned size_t;
- typedef int difference_type;
- typedef const Value &reference;
- typedef const Value *pointer;
- typedef ValueConstIterator SelfType;
-
- ValueConstIterator ();
- private:
- explicit ValueConstIterator (const Value::ObjectValues::iterator &current);
- public:
- SelfType &operator = (const ValueIteratorBase &other);
-
- SelfType operator ++ (int)
- {
- SelfType temp (*this);
- ++*this;
- return temp;
- }
-
- SelfType operator -- (int)
- {
- SelfType temp (*this);
- --*this;
- return temp;
- }
-
- SelfType &operator -- ()
- {
- decrement ();
- return *this;
- }
-
- SelfType &operator ++ ()
- {
- increment ();
- return *this;
- }
-
- reference operator * () const
- {
- return deref ();
- }
- };
-
-
- class ValueIterator : public ValueIteratorBase
- {
- friend class Value;
- public:
- typedef unsigned size_t;
- typedef int difference_type;
- typedef Value &reference;
- typedef Value *pointer;
- typedef ValueIterator SelfType;
-
- ValueIterator ();
- ValueIterator (const ValueConstIterator &other);
- ValueIterator (const ValueIterator &other);
-
- private:
- explicit ValueIterator (const Value::ObjectValues::iterator &current);
-
- public:
-
- SelfType &operator = (const SelfType &other);
-
- SelfType operator ++ (int)
- {
- SelfType temp (*this);
- ++*this;
- return temp;
- }
-
- SelfType operator -- (int)
- {
- SelfType temp (*this);
- --*this;
- return temp;
- }
-
- SelfType &operator -- ()
- {
- decrement ();
- return *this;
- }
-
- SelfType &operator ++ ()
- {
- increment ();
- return *this;
- }
-
- reference operator * () const
- {
- return deref ();
- }
- };
-} // namespace json
-
-namespace json
-{
- class Value;
-
- class Reader
- {
- public:
- typedef char const *Location;
-
- Reader ();
-
- bool parse (const std::string &document, Value &root);
- bool parse (char const *beginDoc, char const *endDOc, Value &root);
- bool parse (std::istream &, Value &root);
-
- std::string error_msgs () const;
-
- private:
- enum TokenType
- {
- tokenEndOfStream = 0,
- tokenObjectBegin,
- tokenObjectEnd,
- tokenArrayBegin,
- tokenArrayEnd,
- tokenString,
- tokenNumber,
- tokenTrue,
- tokenFalse,
- tokenNull,
- tokenArraySeparator,
- tokenMemberSeparator,
- tokenComment,
- tokenError
- };
-
- class Token
- {
- public:
- TokenType type_;
- Location start_;
- Location end_;
- };
-
- class ErrorInfo
- {
- public:
- Token token_;
- std::string message_;
- Location extra_;
- };
-
- typedef std::deque<ErrorInfo> Errors;
-
- bool expectToken (TokenType type, Token &token, char const *message);
- bool readToken (Token &token);
- void skipSpaces ();
- bool match (Location pattern,
- int patternLength);
- bool readString ();
- void readNumber ();
- bool readValue ();
- bool readObject ();
- bool readArray ();
- bool decodeNumber (Token &token);
- bool decodeString (Token &token);
- bool decodeString (Token &token, std::string &decoded);
- bool decodeDouble (Token &token);
- bool decodeUnicodeEscapeSequence (Token &token,
- Location &current,
- Location end,
- unsigned &unicode);
- bool addError (const std::string &message,
- Token &token,
- Location extra = 0);
- bool recoverFromError (TokenType skipUntilToken);
- bool addErrorAndRecover (const std::string &message,
- Token &token,
- TokenType skipUntilToken);
- void skipUntilSpace ();
- Value &currentValue ();
- char getNextChar ();
- void getLocationLineAndColumn (Location location,
- int &line,
- int &column) const;
- std::string getLocationLineAndColumn (Location location) const;
-
- typedef std::stack<Value *> Nodes;
- Nodes nodes_;
- Errors errors_;
- std::string document_;
- Location begin_;
- Location end_;
- Location current_;
- Location lastValueEnd_;
- Value *lastValue_;
- };
-
- std::istream& operator >> (std::istream&, Value&);
-
-} // namespace json
-
-namespace json
-{
- class Value;
-
- class Writer
- {
- public:
- Writer () { }
- ~Writer () { }
-
- public:
- std::string write (const Value &root);
-
- private:
- void writeValue (const Value &value);
-
- std::string document_;
- };
-
- std::string valueToString (int value);
- std::string valueToString (unsigned value);
- std::string valueToString (double value);
- std::string valueToString (bool value);
- std::string valueToQuotedString (char const *value);
-} // namespace json
-
-/*
- * JSON-RPC implementation in C++
- */
-
-namespace json
-{
- namespace rpc
- {
- typedef void (Module::*method) (HTTPRequest *http, Value &request, Value &response);
-
- struct mfp
- {
- Module const *mod;
- method mth;
- };
-
- typedef std::map<std::string, mfp> method_map;
- extern method_map methods;
-
- void add_method (char *name, Module const *mod, method mth);
- void service (HTTPRequest *http, Value &request, Value &response);
- void process (HTTPRequest *http, std::string &response, char const *request);
- }
-}
-
-#endif // JSON_H
diff --git a/src/modules/m_rpc_json.cpp b/src/modules/m_rpc_json.cpp
index 8de1b8a29..d2886cf74 100644
--- a/src/modules/m_rpc_json.cpp
+++ b/src/modules/m_rpc_json.cpp
@@ -6,2095 +6,369 @@
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
- * the file COPYING for details.
+ * the file COPYING for details.
*
* ---------------------------------------------------
*/
-#include <cstddef>
-#include <cstdio>
-#include <iostream>
-#include <stdexcept>
-#include <utility>
-
#include "inspircd.h"
-#include "inspsocket.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
#include "httpd.h"
-#include "json.h"
+#include "rpc.h"
+#include <exception>
-/* $ModDesc: Provides a JSON-RPC interface for modules using m_httpd.so */
+/* $ModDesc: Encode and decode JSON-RPC requests for modules */
+/* $ModDep: httpd.h rpc.h */
-class ModuleRpcJson : public Module
+class JsonException : public std::exception
{
- void MthModuleVersion (HTTPRequest *http, json::Value &request, json::Value &response)
+ private:
+ std::string _what;
+ public:
+ JsonException(const std::string &what)
+ : _what(what)
{
- Version v = this->GetVersion();
- std::string result = ConvToStr(v.Major) + "." + ConvToStr(v.Minor) + "." + ConvToStr(v.Revision) + "." + ConvToStr(v.Build);
- response["result"] = result;
}
-
- void system_list_methods (HTTPRequest *http, json::Value &request, json::Value &response)
+
+ virtual ~JsonException() throw() { }
+
+ virtual const char *what() const throw()
{
- unsigned i = 0;
- json::Value method_list (json::arrayValue);
-
- json::rpc::method_map::iterator it;
- for (it = json::rpc::methods.begin(); it != json::rpc::methods.end(); ++it)
- {
- method_list[i] = json::Value (it->first);
- i++;
- }
-
- response["result"] = method_list;
+ return _what.c_str();
}
+};
+class ModuleRpcJson : public Module
+{
+ private:
+
public:
- ModuleRpcJson(InspIRCd* Me) : Module(Me)
+ ModuleRpcJson(InspIRCd *Me)
+ : Module::Module(Me)
{
- ServerInstance->Modules->PublishInterface("JSON-RPC", this);
- json::rpc::add_method ("system.listMethods", (Module *)this, (void (Module::*)(HTTPRequest*, json::Value&, json::Value&))&ModuleRpcJson::system_list_methods);
- json::rpc::add_method ("ircd.moduleVersion", (Module *)this, (void (Module::*)(HTTPRequest*, json::Value&, json::Value&))&ModuleRpcJson::MthModuleVersion);
+ ServerInstance->Modules->PublishInterface("RPC", this);
}
-
- void OnEvent(Event* event)
+
+ virtual ~ModuleRpcJson()
+ {
+ ServerInstance->Modules->UnpublishInterface("RPC", this);
+ }
+
+ virtual Version GetVersion()
+ {
+ return Version(1, 1, 0, 0, VF_SERVICEPROVIDER | VF_VENDOR, API_VERSION);
+ }
+
+ void Implements(char *List)
+ {
+ List[I_OnEvent] = 1;
+ }
+
+ virtual void OnEvent(Event *event)
{
- std::stringstream data("");
-
if (event->GetEventID() == "httpd_url")
{
- HTTPRequest* http = (HTTPRequest*)event->GetData();
-
- if (http->GetURI() == "/jsonrpc" && http->GetType() == "POST")
+ HTTPRequest *req = (HTTPRequest*) event->GetData();
+
+ if ((req->GetURI() == "/rpc/json") || (req->GetURI() == "/rpc/json/"))
{
+ std::stringstream data;
+
+ RPCValue *reqobj = NULL;
+
try
{
- std::string response_text;
- json::rpc::process (http, response_text, http->GetPostData().c_str());
- data << response_text;
+ reqobj = this->JSONParse(req->GetPostData());
+
+ if (!reqobj || (reqobj->GetType() != RPCObject))
+ throw JsonException("RPC requests must be in the form of a single object");
+
+ RPCValue *method = reqobj->GetObject("method");
+ if (!method || method->GetType() != RPCString)
+ throw JsonException("RPC requests must have a 'method' string field");
+
+ RPCValue *params = reqobj->GetObject("params");
+ if (!params || params->GetType() != RPCArray)
+ throw JsonException("RPC requests must have a 'params' array field");
+
+ RPCRequest modreq("json", method->GetString(), params);
+ Event mev((char*) &modreq, this, "RPCMethod");
+ mev.Send(ServerInstance);
+
+ if (!modreq.claimed)
+ throw JsonException("Unrecognized method");
+
+ if (!modreq.error.empty())
+ {
+ data << "{\"result\":null,\"error\":\"" << modreq.error << "\"";
+ }
+ else
+ {
+ data << "{\"result\":";
+ this->JSONSerialize(modreq.result, data);
+ data << ",\"error\":null";
+ }
+
+ if (reqobj->GetObject("id"))
+ {
+ data << ",\"id\":";
+ this->JSONSerialize(reqobj->GetObject("id"), data);
+ }
+ data << "}";
+
+ delete reqobj;
+ reqobj = NULL;
}
- catch (std::runtime_error &)
+ catch (std::exception &e)
{
- data << "{ \"result\": \"JSON Fault\", \"error\": \"Invalid RPC call\", \"id\": 1}";
+ if (reqobj)
+ delete reqobj;
+ data << "{\"result\":null,\"error\":\"" << e.what() << "\"}";
}
-
- /* Send the document back to m_httpd */
- HTTPDocument response(http->sock, &data, 200);
+
+ HTTPDocument response(req->sock, &data, 200);
response.headers.SetHeader("X-Powered-By", "m_rpc_json.so");
- response.headers.SetHeader("Content-Type", "application/json; charset=iso-8859-1");
+ response.headers.SetHeader("Content-Type", "application/json");
response.headers.SetHeader("Connection", "Keep-Alive");
- Request req((char*)&response, (Module*)this, event->GetSource());
- req.Send();
+
+ Request rreq((char*) &response, (Module*) this, event->GetSource());
+ rreq.Send();
}
}
}
-
- void Implements(char* List)
+
+ void AttachToParent(RPCValue *parent, RPCValue *child, const std::string &key = "")
{
- List[I_OnEvent] = 1;
+ if (!parent || !child)
+ return;
+
+ if (parent->GetType() == RPCArray)
+ parent->ArrayAdd(child);
+ else if (parent->GetType() == RPCObject)
+ parent->ObjectAdd(key, child);
+ else
+ throw JsonException("Cannot add a value to a non-container");
}
-
- virtual ~ModuleRpcJson()
+
+ void AttachToParentReset(RPCValue *parent, RPCValue *&child, std::string &key)
{
- ServerInstance->Modules->UnpublishInterface("JSON-RPC", this);
+ AttachToParent(parent, child, key);
+ child = NULL;
+ key.clear();
}
-
- virtual Version GetVersion()
+
+ RPCValue *JSONParse(const std::string &data)
{
- return Version(0, 1, 0, 0, VF_VENDOR, API_VERSION);
- }
-};
-
-namespace json
-{
- ValueIteratorBase::ValueIteratorBase ()
- {
- }
-
-
- ValueIteratorBase::ValueIteratorBase (const Value::ObjectValues::iterator &current)
- : 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 &current)
- : ValueIteratorBase (current)
- {
- }
-
- ValueConstIterator &
- ValueConstIterator::operator = (const ValueIteratorBase &other)
- {
- copy (other);
- return *this;
- }
-
-
- ValueIterator::ValueIterator ()
- {
- }
-
-
- ValueIterator::ValueIterator (const Value::ObjectValues::iterator &current)
- : 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':
+ bool pisobject = false;
+ bool instring = false;
+ std::string stmp;
+ std::string vkey;
+ std::string pvkey;
+ RPCValue *aparent = NULL;
+ RPCValue *value = NULL;
+
+ for (std::string::const_iterator i = data.begin(); i != data.end(); i++)
{
- unsigned unicode;
- if (!decodeUnicodeEscapeSequence (token, current, end, unicode))
- return false;
- // @todo encode unicode as utf8.
- // @todo remember to alter the writer too.
+ if (instring)
+ {
+ // TODO escape sequences
+ if (*i == '"')
+ {
+ instring = false;
+
+ if (pisobject && vkey.empty())
+ vkey = stmp;
+ else
+ value = new RPCValue(stmp);
+
+ stmp.clear();
+ }
+ else
+ stmp += *i;
+
+ continue;
+ }
+
+ if ((*i == ' ') || (*i == '\t') || (*i == '\r') || (*i == '\n'))
+ continue;
+
+ if (*i == '{')
+ {
+ // Begin object
+ if ((value) || (pisobject && vkey.empty()))
+ throw JsonException("Unexpected begin object token ('{')");
+
+ RPCValue *nobj = new RPCValue(RPCObject, aparent);
+ aparent = nobj;
+ pvkey = vkey;
+ vkey.clear();
+ pisobject = true;
+ }
+ else if (*i == '}')
+ {
+ // End object
+ if ((!aparent) || (!pisobject) || (!vkey.empty() && !value))
+ throw JsonException("Unexpected end object token ('}')");
+
+ // End value
+ if (value)
+ AttachToParentReset(aparent, value, vkey);
+
+ if (!aparent->parent)
+ return aparent;
+
+ value = aparent;
+ aparent = aparent->parent;
+ vkey = pvkey;
+ pvkey.clear();
+ pisobject = (aparent->GetType() == RPCObject);
+ }
+ else if (*i == '"')
+ {
+ // Begin string
+ if (value)
+ throw JsonException("Unexpected begin string token ('\"')");
+
+ instring = true;
+ }
+ else if (*i == ':')
+ {
+ if ((!aparent) || (!pisobject) || (vkey.empty()) || (value))
+ throw JsonException("Unexpected object value token (':')");
+ }
+ else if (*i == ',')
+ {
+ if ((!aparent) || (!value) || ((pisobject) && (vkey.empty())))
+ throw JsonException("Unexpected value seperator token (',')");
+
+ AttachToParentReset(aparent, value, vkey);
+ }
+ else if (*i == '[')
+ {
+ // Begin array
+ if ((value) || (pisobject && vkey.empty()))
+ throw JsonException("Unexpected begin array token ('[')");
+
+ RPCValue *nar = new RPCValue(RPCArray, aparent);
+ aparent = nar;
+ pvkey = vkey;
+ vkey.clear();
+ pisobject = false;
+ }
+ else if (*i == ']')
+ {
+ // End array (also an end value delimiter)
+ if (!aparent || pisobject)
+ throw JsonException("Unexpected end array token (']')");
+
+ if (value)
+ AttachToParentReset(aparent, value, vkey);
+
+ if (!aparent->parent)
+ return aparent;
+
+ value = aparent;
+ aparent = aparent->parent;
+ vkey = pvkey;
+ pvkey.clear();
+ pisobject = (aparent->GetType() == RPCObject);
+ }
+ else
+ {
+ // Numbers, false, null, and true fall under this heading.
+ if ((*i == 't') && ((i + 3) < data.end()) && (*(i + 1) == 'r') && (*(i + 2) == 'u') && (*(i + 3) == 'e'))
+ {
+ value = new RPCValue(true);
+ i += 3;
+ }
+ else if ((*i == 'f') && ((i + 4) < data.end()) && (*(i + 1) == 'a') && (*(i + 2) == 'l') && (*(i + 3) == 's') && (*(i + 4) == 'e'))
+ {
+ value = new RPCValue(false);
+ i += 4;
+ }
+ else if ((*i == 'n') && ((i + 3) < data.end()) && (*(i + 1) == 'u') && (*(i + 2) == 'l') && (*(i + 3) == 'l'))
+ {
+ value = new RPCValue();
+ i += 3;
+ }
+ else if ((*i == '-') || (*i == '+') || (*i == '.') || ((*i >= '0') && (*i <= '9')))
+ {
+ std::string ds = std::string(i, data.end());
+ char *eds = NULL;
+
+ errno = 0;
+ double v = strtod(ds.c_str(), &eds);
+
+ if (errno != 0)
+ throw JsonException("Error parsing numeric value");
+
+ value = new RPCValue(v);
+
+ i += eds - ds.c_str() - 1;
+ }
+ else
+ throw JsonException("Unknown data in value portion");
+ }
}
- break;
- default:
- return addError ("Bad escape sequence in string", token, current);
- }
- }
- else
- {
- decoded += c;
- }
- }
-
- return true;
- }
-
-
- bool
- Reader::decodeUnicodeEscapeSequence (Token &token,
- Location &current,
- Location end,
- unsigned &unicode)
- {
- if (end - current < 4)
- return addError ("Bad unicode escape sequence in string: four digits expected.", token, current);
- unicode = 0;
- for (int index = 0; index < 4; ++index)
- {
- char c = *current++;
- unicode *= 16;
- if (c >= '0' && c <= '9')
- unicode += c - '0';
- else if (c >= 'a' && c <= 'f')
- unicode += c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- unicode += c - 'A' + 10;
- else
- return addError ("Bad unicode escape sequence in string: hexadecimal digit expected.", token, current);
- }
- return true;
- }
-
-
- bool
- Reader::addError (const std::string &message,
- Token &token,
- Location extra)
- {
- ErrorInfo info;
- info.token_ = token;
- info.message_ = message;
- info.extra_ = extra;
- errors_.push_back (info);
- return false;
- }
-
-
- bool
- Reader::recoverFromError (TokenType skipUntilToken)
- {
- int errorCount = int (errors_.size ());
- Token skip;
- while (true)
- {
- if (!readToken (skip))
- errors_.resize (errorCount); // discard errors caused by recovery
- if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
- break;
- }
- errors_.resize (errorCount);
- return false;
- }
-
-
- bool
- Reader::addErrorAndRecover (const std::string &message,
- Token &token,
- TokenType skipUntilToken)
- {
- addError (message, token);
- return recoverFromError (skipUntilToken);
- }
-
-
- Value &
- Reader::currentValue ()
- {
- return *(nodes_.top ());
- }
-
-
- char
- Reader::getNextChar ()
- {
- if (current_ == end_)
- return 0;
- return *current_++;
- }
-
-
- void
- Reader::getLocationLineAndColumn (Location location,
- int &line,
- int &column) const
- {
- Location current = begin_;
- Location lastLineStart = current;
- line = 0;
- while (current < location && current != end_)
- {
- char c = *current++;
- if (c == '\r')
- {
- if (*current == '\n')
- ++current;
- lastLineStart = current;
- ++line;
- }
- else if (c == '\n')
- {
- lastLineStart = current;
- ++line;
- }
- }
- // column & line start at 1
- column = int (location - lastLineStart) + 1;
- ++line;
- }
-
-
- std::string
- Reader::getLocationLineAndColumn (Location location) const
- {
- int line, column;
- getLocationLineAndColumn (location, line, column);
- char buffer[18+16+16+1];
- sprintf (buffer, "Line %d, Column %d", line, column);
- return buffer;
- }
-
-
- std::string
- Reader::error_msgs () const
- {
- std::string formattedMessage;
- for (Errors::const_iterator itError = errors_.begin ();
- itError != errors_.end ();
- ++itError)
- {
- const ErrorInfo &error = *itError;
- formattedMessage += "* " + getLocationLineAndColumn (error.token_.start_) + "\n";
- formattedMessage += " " + error.message_ + "\n";
- if (error.extra_)
- formattedMessage += "See " + getLocationLineAndColumn (error.extra_) + " for detail.\n";
- }
- return formattedMessage;
- }
-} // namespace json
-
-namespace json
-{
- 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);
- }
-
- 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);
- }
-
- 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);
- }
-
-#define throw_unreachable unreachable_internal (__FILE__, __LINE__, CURFUNC)
-#define throw_unless(condition) if (!expect_false (condition)) throw_unless_internal (__FILE__, __LINE__, CURFUNC, #condition)
-#define throw_msg_unless(condition, message) if (!expect_false (condition)) throw_msg_unless_internal (__FILE__, __LINE__, CURFUNC, message)
-
- const Value Value::null;
- const int Value::minInt = int (~ (unsigned (-1)/2));
- const int Value::maxInt = int (unsigned (-1)/2);
- const unsigned Value::maxUInt = unsigned (-1);
-
- ValueAllocator::~ValueAllocator ()
- {
- }
-
- class DefaultValueAllocator : public ValueAllocator
- {
- public:
- virtual ~DefaultValueAllocator ()
- {
- }
-
- virtual char *makeMemberName (char const *memberName)
- {
- return duplicateStringValue (memberName);
- }
-
- virtual void releaseMemberName (char *memberName)
- {
- releaseStringValue (memberName);
- }
-
- virtual char *duplicateStringValue (char const *value, unsigned length = unknown)
- {
- //@todo invesgate this old optimization
-#if 0
- if (!value || value[0] == 0)
- return 0;
-#endif
-
- if (length == unknown)
- length = (unsigned)strlen (value);
- char *newString = static_cast<char *> (malloc (length + 1));
- memcpy (newString, value, length);
- newString[length] = 0;
- return newString;
- }
-
- virtual void releaseStringValue (char *value)
- {
- if (value)
- free (value);
- }
- };
-
- static ValueAllocator *&valueAllocator ()
- {
- static DefaultValueAllocator defaultAllocator;
- static ValueAllocator *valueAllocator = &defaultAllocator;
- return valueAllocator;
- }
-
- static struct DummyValueAllocatorInitializer {
- DummyValueAllocatorInitializer ()
- {
- valueAllocator (); // ensure valueAllocator () statics are initialized before main ().
- }
- } dummyValueAllocatorInitializer;
-
-
-
- Value::CZString::CZString (int index)
- : cstr_ (0)
- , index_ (index)
- {
- }
-
- Value::CZString::CZString (char const *cstr, DuplicationPolicy allocate)
- : cstr_ (allocate == duplicate ? valueAllocator()->makeMemberName (cstr)
- : cstr)
- , index_ (allocate)
- {
- }
-
- Value::CZString::CZString (const CZString &other)
- : cstr_ (other.index_ != noDuplication && other.cstr_ != 0
- ? valueAllocator()->makeMemberName (other.cstr_)
- : other.cstr_)
- , index_ (other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
- : other.index_)
- {
- }
-
- Value::CZString::~CZString ()
- {
- if (cstr_ && index_ == duplicate)
- valueAllocator()->releaseMemberName (const_cast<char *> (cstr_));
- }
-
- void
- Value::CZString::swap (CZString &other)
- {
- std::swap (cstr_, other.cstr_);
- std::swap (index_, other.index_);
- }
-
- Value::CZString &
- Value::CZString::operator = (const CZString &other)
- {
- CZString temp (other);
- swap (temp);
- return *this;
- }
-
- bool
- Value::CZString::operator < (const CZString &other) const
- {
- if (cstr_)
- return strcmp (cstr_, other.cstr_) < 0;
- return index_ < other.index_;
- }
-
- bool
- Value::CZString::operator == (const CZString &other) const
- {
- if (cstr_)
- return strcmp (cstr_, other.cstr_) == 0;
- return index_ == other.index_;
- }
-
-
- int
- Value::CZString::index () const
- {
- return index_;
- }
-
-
- char const *
- Value::CZString::c_str () const
- {
- return cstr_;
- }
-
- bool
- Value::CZString::isStaticString () const
- {
- return index_ == noDuplication;
- }
-
-
- // class Value::Value
-
- Value::Value (ValueType type)
- : type_ (type)
- , allocated_ (0)
- {
- switch (type)
- {
- case nullValue:
- break;
- case intValue:
- case uintValue:
- value_.int_ = 0;
- break;
- case realValue:
- value_.real_ = 0.0;
- break;
- case stringValue:
- value_.string_ = 0;
- break;
- case arrayValue:
- case objectValue:
- value_.map_ = new ObjectValues ();
- break;
- case booleanValue:
- value_.bool_ = false;
- break;
- default:
- throw_unreachable;
- }
- }
-
-
- Value::Value (int value)
- : type_ (intValue)
- {
- value_.int_ = value;
- }
-
-
- Value::Value (unsigned value)
- : type_ (uintValue)
- {
- value_.uint_ = value;
- }
-
- Value::Value (double value)
- : type_ (realValue)
- {
- value_.real_ = value;
- }
-
- Value::Value (char const *value)
- : type_ (stringValue)
- , allocated_ (true)
- {
- value_.string_ = valueAllocator()->duplicateStringValue (value);
- }
-
- Value::Value (const std::string &value)
- : type_ (stringValue)
- , allocated_ (true)
- {
- value_.string_ = valueAllocator()->duplicateStringValue (value.c_str (), (unsigned)value.length ());
- }
-
- Value::Value (const StaticString &value)
- : type_ (stringValue)
- , allocated_ (false)
- {
- value_.string_ = const_cast<char *> (value.c_str ());
- }
-
-
- Value::Value (bool value)
- : type_ (booleanValue)
- {
- value_.bool_ = value;
- }
-
-
- Value::Value (const Value &other)
- : type_ (other.type_)
- {
- switch (type_)
- {
- case nullValue:
- case intValue:
- case uintValue:
- case realValue:
- case booleanValue:
- value_ = other.value_;
- break;
- case stringValue:
- if (other.value_.string_)
- {
- value_.string_ = valueAllocator()->duplicateStringValue (other.value_.string_);
- allocated_ = true;
- }
- else
- value_.string_ = 0;
- break;
- case arrayValue:
- case objectValue:
- value_.map_ = new ObjectValues (*other.value_.map_);
- break;
- default:
- throw_unreachable;
- }
- }
-
-
- Value::~Value ()
- {
- switch (type_)
- {
- case nullValue:
- case intValue:
- case uintValue:
- case realValue:
- case booleanValue:
- break;
- case stringValue:
- if (allocated_)
- valueAllocator()->releaseStringValue (value_.string_);
- break;
- case arrayValue:
- case objectValue:
- delete value_.map_;
- break;
- default:
- throw_unreachable;
- }
- }
-
- Value &
- Value::operator = (const Value &other)
- {
- Value temp (other);
- swap (temp);
- 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;
- }
-
- ValueType
- Value::type () const
- {
- return type_;
- }
-
- bool
- Value::operator < (const Value &other) const
- {
- int typeDelta = type_ - other.type_;
- if (typeDelta)
- return typeDelta < 0 ? true : false;
- switch (type_)
- {
- case nullValue:
- return false;
- 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_ == 0 && other.value_.string_)
- || (other.value_.string_
- && value_.string_
- && strcmp (value_.string_, other.value_.string_) < 0);
- case arrayValue:
- case objectValue:
- {
- int delta = int (value_.map_->size () - other.value_.map_->size ());
- if (delta)
- return delta < 0;
- return (*value_.map_) < (*other.value_.map_);
- }
- 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 *&current)
- {
- *--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_ += "}";
+
+ if (instring)
+ throw JsonException("Unterminated string");
+
+ if (aparent && pisobject)
+ throw JsonException("Unterminated object");
+ else if (aparent && !pisobject)
+ throw JsonException("Unterminated array");
+
+ if (value)
+ return value;
+ else
+ throw JsonException("No JSON data found");
}
- break;
- }
- }
-} // namespace json
-
-/**
- * RPC
- */
-
-namespace json
-{
- namespace rpc
- {
- method_map methods;
-
- void
- add_method (char *name, Module const *mod, method mth)
- {
- mfp m = { mod, mth };
- methods[name] = m;
- }
-
- void
- service (HTTPRequest *http, Value &request, Value &response)
- {
- char const *methodName = static_cast<char const *> (request["method"]);
-
- method_map::iterator mthit = methods.find (methodName);
- if (mthit != methods.end ())
+
+ void JSONSerialize(RPCValue *value, std::stringstream &re)
{
- mfp m = mthit->second;
- Module *mod = new Module (*m.mod);
- method mth = m.mth;
- (mod->*mth) (http, request, response);
- delete mod;
+ int ac;
+ switch (value->GetType())
+ {
+ case RPCNull:
+ re << "null";
+ break;
+ case RPCBoolean:
+ re << ((value->GetBool()) ? "true" : "false");
+ break;
+ case RPCInteger:
+ re << value->GetInt();
+ break;
+ case RPCString:
+ re << "\"" << value->GetString() << "\"";
+ break;
+ case RPCArray:
+ re << "[";
+ ac = value->ArraySize();
+ for (int i = 0; i < ac; i++)
+ {
+ this->JSONSerialize(value->GetArray(i), re);
+ if (i != (ac - 1))
+ re << ",";
+ }
+ re << "]";
+ break;
+ case RPCObject:
+ re << "{";
+ std::pair<RPCObjectContainer::iterator,RPCObjectContainer::iterator> its = value->GetObjectIterator();
+ while (its.first != its.second)
+ {
+ re << "\"" << its.first->first << "\":";
+ this->JSONSerialize(its.first->second, re);
+ if (++its.first != its.second)
+ re << ",";
+ }
+ re << "}";
+ break;
+ }
}
- }
-
- void
- process (HTTPRequest *http, std::string &response_text, char const *request_text)
- {
- std::string text;
- bool parse_success;
- Value request (objectValue);
- Value response (objectValue);
- Reader r;
- Writer w;
-
- response["error"] = Value(nullValue);
- response["result"] = Value(nullValue);
-
- parse_success = r.parse (request_text, request_text + strlen (request_text), request);
-
- response["id"] = request["id"];
-
- service (http, request, response);
-
- text = w.write (response);
-
- response_text = text.c_str ();
-
- return;
- }
- } // namespace rpc
-} // namespace json
+};
-MODULE_INIT(ModuleRpcJson)
+MODULE_INIT(ModuleRpcJson);
diff --git a/src/modules/m_rpctest.cpp b/src/modules/m_rpctest.cpp
new file mode 100644
index 000000000..faa0f9279
--- /dev/null
+++ b/src/modules/m_rpctest.cpp
@@ -0,0 +1,68 @@
+/* +------------------------------------+
+ * | Inspire Internet Relay Chat Daemon |
+ * +------------------------------------+
+ *
+ * InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ * the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "rpc.h"
+
+/* $ModDesc: A test of the RPC API */
+/* $ModDep: rpc.h */
+
+class ModuleRPCTest : public Module
+{
+ private:
+
+ public:
+ ModuleRPCTest(InspIRCd *Me)
+ : Module::Module(Me)
+ {
+ }
+
+ virtual ~ModuleRPCTest()
+ {
+ }
+
+ virtual Version GetVersion()
+ {
+ return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+ }
+
+ void Implements(char *List)
+ {
+ List[I_OnEvent] = 1;
+ }
+
+ virtual void OnEvent(Event *ev)
+ {
+ if (ev->GetEventID() == "RPCMethod")
+ {
+ RPCRequest *req = (RPCRequest*) ev->GetData();
+
+ if (req->method == "test.echo")
+ {
+ req->claimed = true;
+ if (req->parameters->ArraySize() < 1)
+ {
+ req->error = "Insufficient parameters";
+ return;
+ }
+
+ req->result->SetString(req->parameters->GetArray(0)->GetString());
+ }
+ }
+ }
+};
+
+MODULE_INIT(ModuleRPCTest);
diff --git a/src/modules/rpc.h b/src/modules/rpc.h
new file mode 100644
index 000000000..cdaec4082
--- /dev/null
+++ b/src/modules/rpc.h
@@ -0,0 +1,296 @@
+#ifndef RPC_H
+#define RPC_H
+
+#include <string>
+#include <map>
+#include <stdexcept>
+
+class RPCValue;
+
+typedef enum
+{
+ RPCNull,
+ RPCBoolean,
+ RPCInteger,
+ RPCString,
+ RPCArray,
+ RPCObject
+} RPCValueType;
+
+typedef std::map<std::string,RPCValue*> RPCObjectContainer;
+typedef std::vector<RPCValue*> RPCArrayContainer;
+
+class RPCValue : public classbase
+{
+ protected:
+ RPCValueType type;
+ void *value;
+
+ double *CastInteger()
+ {
+ return (double*)value;
+ }
+
+ std::string *CastString()
+ {
+ return (std::string*)value;
+ }
+
+ RPCObjectContainer *CastObject()
+ {
+ return (RPCObjectContainer*)value;
+ }
+
+ RPCArrayContainer *CastArray()
+ {
+ return (RPCArrayContainer*)value;
+ }
+
+ void DestroyValue()
+ {
+ // Some versions of GCC complain about declaration in switch statements
+ RPCArrayContainer *a;
+ RPCObjectContainer *o;
+ switch (type)
+ {
+ case RPCInteger:
+ delete this->CastInteger();
+ break;
+ case RPCString:
+ delete this->CastString();
+ break;
+ case RPCArray:
+ a = this->CastArray();
+ for (RPCArrayContainer::iterator i = a->begin(); i != a->end(); i++)
+ delete *i;
+ delete a;
+ break;
+ case RPCObject:
+ o = this->CastObject();
+ for (RPCObjectContainer::iterator i = o->begin(); i != o->end(); i++)
+ delete i->second;
+ delete o;
+ break;
+ default:
+ break;
+ }
+
+ value = NULL;
+ }
+
+ void InitValue()
+ {
+ switch (type)
+ {
+ case RPCNull:
+ case RPCBoolean:
+ value = NULL;
+ break;
+ case RPCInteger:
+ value = new double;
+ break;
+ case RPCString:
+ value = new std::string;
+ break;
+ case RPCArray:
+ value = new RPCArrayContainer;
+ break;
+ case RPCObject:
+ value = new RPCObjectContainer;
+ break;
+ }
+ }
+
+ RPCValue(const RPCValue &v) { }
+
+ public:
+ RPCValue *parent;
+
+ RPCValue(RPCValue *parent = NULL) : type(RPCNull), value(NULL), parent(parent) { }
+ RPCValue(RPCValueType type, RPCValue *parent = NULL) : type(type), value(NULL), parent(parent) { InitValue(); }
+ RPCValue(bool nvalue, RPCValue *parent = NULL) : type(RPCBoolean), value((void*)nvalue), parent(parent) { }
+ RPCValue(double nvalue, RPCValue *parent = NULL) : type(RPCInteger), parent(parent) { value = new double(nvalue); }
+ RPCValue(const std::string &nvalue, RPCValue *parent = NULL) : type(RPCString), parent(parent) { value = new std::string(nvalue); }
+
+ virtual ~RPCValue()
+ {
+ DestroyValue();
+ }
+
+ RPCValueType GetType()
+ {
+ return type;
+ }
+
+ void SetNull()
+ {
+ DestroyValue();
+ type = RPCNull;
+ }
+
+ void SetBoolean(bool nvalue)
+ {
+ DestroyValue();
+ value = (void*)nvalue;
+ type = RPCBoolean;
+ }
+
+ void SetInteger(double nvalue)
+ {
+ if (type == RPCInteger)
+ {
+ *this->CastInteger() = nvalue;
+ }
+ else
+ {
+ DestroyValue();
+ value = new double(nvalue);
+ type = RPCInteger;
+ }
+ }
+
+ void SetString(const std::string &nvalue)
+ {
+ if (type == RPCString)
+ {
+ this->CastString()->assign(nvalue);
+ }
+ else
+ {
+ DestroyValue();
+ value = new std::string(nvalue);
+ type = RPCString;
+ }
+ }
+
+ void SetArray()
+ {
+ if (type == RPCArray)
+ {
+ this->CastArray()->clear();
+ }
+ else
+ {
+ DestroyValue();
+ type = RPCArray;
+ InitValue();
+ }
+ }
+
+ void SetObject()
+ {
+ if (type == RPCObject)
+ {
+ this->CastObject()->clear();
+ }
+ else
+ {
+ DestroyValue();
+ type = RPCObject;
+ InitValue();
+ }
+ }
+
+ void ArrayAdd(RPCValue *nvalue)
+ {
+ if (type != RPCArray)
+ return;
+ RPCArrayContainer *a = this->CastArray();
+ a->push_back(nvalue);
+ nvalue->parent = this;
+ }
+
+ void ObjectAdd(const std::string &key, RPCValue *nvalue)
+ {
+ if (type != RPCObject)
+ return;
+ RPCObjectContainer *o = this->CastObject();
+ o->insert(std::make_pair(key, nvalue));
+ nvalue->parent = this;
+ }
+
+ RPCValue *GetArray(int i)
+ {
+ if (type != RPCArray)
+ return NULL;
+ RPCArrayContainer *a = this->CastArray();
+ if ((i < 0) || (i >= (signed)a->size()))
+ return NULL;
+ return a->at(i);
+ }
+
+ int ArraySize()
+ {
+ if (type != RPCArray)
+ return 0;
+ RPCArrayContainer *a = this->CastArray();
+ return a->size();
+ }
+
+ RPCValue *GetObject(const std::string &key)
+ {
+ if (type != RPCObject)
+ return NULL;
+ RPCObjectContainer *o = this->CastObject();
+ RPCObjectContainer::iterator it = o->find(key);
+ if (it == o->end())
+ return NULL;
+ return it->second;
+ }
+
+ std::pair<RPCObjectContainer::iterator,RPCObjectContainer::iterator> GetObjectIterator() throw()
+ {
+ if (type != RPCObject)
+ throw std::runtime_error("Cannot get iterator for a non-object RPC value");
+ RPCObjectContainer *o = this->CastObject();
+ return std::make_pair(o->begin(), o->end());
+ }
+
+ std::string GetString()
+ {
+ if (type != RPCString)
+ return std::string();
+ return *this->CastString();
+ }
+
+ double GetInt()
+ {
+ if (type != RPCInteger)
+ return 0;
+ return *this->CastInteger();
+ }
+
+ bool GetBool()
+ {
+ if (type != RPCBoolean)
+ return 0;
+ return (value != NULL);
+ }
+};
+
+class RPCRequest : public classbase
+{
+ protected:
+
+ public:
+ std::string method;
+ RPCValue *parameters;
+ RPCValue *result;
+ std::string provider;
+ bool claimed;
+ std::string error;
+
+ RPCRequest(const std::string &provider, const std::string &method, RPCValue *parameters)
+ : method(method), parameters(parameters), provider(provider), claimed(false)
+ {
+ result = new RPCValue();
+ }
+
+ ~RPCRequest()
+ {
+ if (result)
+ delete result;
+ }
+};
+
+#endif