Parcourir la source

2009-05-08 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added xml-rpc request parser. The supported value types are:
	i4/int, string, double, struct, array, base64.  Currently only
	libxml2 version is provided.
	* src/Xml2XmlRpcRequestProcessor.cc
	* src/Xml2XmlRpcRequestProcessor.h
	* src/XmlRpcElements.cc
	* src/XmlRpcElements.h
	* src/XmlRpcRequest.h
	* src/XmlRpcRequestParserController.cc
	* src/XmlRpcRequestParserController.h
	* src/XmlRpcRequestParserState.h
	* src/XmlRpcRequestParserStateImpl.cc
	* src/XmlRpcRequestParserStateImpl.h
	* src/XmlRpcRequestParserStateMachine.cc
	* src/XmlRpcRequestParserStateMachine.h
	* src/XmlRpcRequestProcessor.h
	* test/XmlRpcRequestParserControllerTest.cc
	* test/XmlRpcRequestProcessorTest.cc
Tatsuhiro Tsujikawa il y a 16 ans
Parent
commit
3a81b3c3d7

+ 21 - 0
ChangeLog

@@ -1,3 +1,24 @@
+2009-05-08  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added xml-rpc request parser. The supported value types are:
+	i4/int, string, double, struct, array, base64.  Currently only
+	libxml2 version is provided.
+	* src/Xml2XmlRpcRequestProcessor.cc
+	* src/Xml2XmlRpcRequestProcessor.h
+	* src/XmlRpcElements.cc
+	* src/XmlRpcElements.h
+	* src/XmlRpcRequest.h
+	* src/XmlRpcRequestParserController.cc
+	* src/XmlRpcRequestParserController.h
+	* src/XmlRpcRequestParserState.h
+	* src/XmlRpcRequestParserStateImpl.cc
+	* src/XmlRpcRequestParserStateImpl.h
+	* src/XmlRpcRequestParserStateMachine.cc
+	* src/XmlRpcRequestParserStateMachine.h
+	* src/XmlRpcRequestProcessor.h
+	* test/XmlRpcRequestParserControllerTest.cc
+	* test/XmlRpcRequestProcessorTest.cc
+
 2009-05-08  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	* Release 1.3.3

+ 148 - 0
src/Xml2XmlRpcRequestProcessor.cc

@@ -0,0 +1,148 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "Xml2XmlRpcRequestProcessor.h"
+
+#include <stack>
+
+#include "XmlRpcRequestParserStateMachine.h"
+#include "Util.h"
+#include "DlAbortEx.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+struct SessionData {
+  XmlRpcRequestParserStateMachine* _stm;
+
+  std::stack<std::string> _charactersStack;
+
+  SessionData(XmlRpcRequestParserStateMachine* stm):_stm(stm) {}
+};
+
+static void mlStartElement(void* userData, const xmlChar* name,
+			   const xmlChar** attrs)
+{
+  SessionData* sd = reinterpret_cast<SessionData*>(userData);
+  std::map<std::string, std::string> attrmap;
+  if(attrs) {
+    const xmlChar** p = attrs;
+    while(*p != 0) {
+      std::string name = (const char*)*p++;
+      if(*p == 0) {
+	break;
+      }
+      std::string value = Util::trim((const char*)*p++);
+      attrmap[name] = value;
+    }
+  }
+  sd->_stm->beginElement((const char*)name, attrmap);
+  if(sd->_stm->needsCharactersBuffering()) {
+    sd->_charactersStack.push(std::string());
+  }
+}
+
+static void mlEndElement(void* userData, const xmlChar* name)
+{
+  SessionData* sd = reinterpret_cast<SessionData*>(userData);
+  std::string characters;
+  if(sd->_stm->needsCharactersBuffering()) {
+    characters = Util::trim(sd->_charactersStack.top());
+    sd->_charactersStack.pop();
+  }
+  sd->_stm->endElement((const char*)name, characters);
+}
+
+static void mlCharacters(void* userData, const xmlChar* ch, int len)
+{
+  SessionData* sd = reinterpret_cast<SessionData*>(userData);
+  if(sd->_stm->needsCharactersBuffering()) {
+    sd->_charactersStack.top() += std::string(&ch[0], &ch[len]);
+  }
+}
+
+static xmlSAXHandler mySAXHandler =
+{
+  0, // internalSubsetSAXFunc
+  0, // isStandaloneSAXFunc
+  0, // hasInternalSubsetSAXFunc
+  0, // hasExternalSubsetSAXFunc
+  0, // resolveEntitySAXFunc
+  0, // getEntitySAXFunc
+  0, // entityDeclSAXFunc
+  0, // notationDeclSAXFunc
+  0, // attributeDeclSAXFunc
+  0, // elementDeclSAXFunc
+  0, //   unparsedEntityDeclSAXFunc
+  0, //   setDocumentLocatorSAXFunc
+  0, //   startDocumentSAXFunc
+  0, //   endDocumentSAXFunc
+  &mlStartElement, //   startElementSAXFunc
+  &mlEndElement, //   endElementSAXFunc
+  0, //   referenceSAXFunc
+  &mlCharacters, //   charactersSAXFunc
+  0, //   ignorableWhitespaceSAXFunc
+  0, //   processingInstructionSAXFunc
+  0, //   commentSAXFunc
+  0, //   warningSAXFunc
+  0, //   errorSAXFunc
+  0, //   fatalErrorSAXFunc
+  0, //   getParameterEntitySAXFunc
+  0, //   cdataBlockSAXFunc
+  0, //   externalSubsetSAXFunc
+  0, //   unsigned int	initialized
+  0, //   void *	_private
+  0, //   startElementNsSAX2Func
+  0, //   endElementNsSAX2Func
+  0, //   xmlStructuredErrorFunc
+};
+
+XmlRpcRequest
+XmlRpcRequestProcessor::parseMemory(const std::string& xml)
+{
+  _stm.reset(new XmlRpcRequestParserStateMachine());
+  SharedHandle<SessionData> sessionData(new SessionData(_stm.get()));
+
+  int r = xmlSAXUserParseMemory(&mySAXHandler, sessionData.get(),
+				xml.data(), xml.size());
+  if(r != 0) {
+    throw DlAbortEx("Failed to parse xml-rpc request.");
+  }
+  return XmlRpcRequest(_stm->getMethodName(), _stm->getCurrentFrameValue());
+}
+
+} // namespace xmlrpc
+
+} // namespace aria2

+ 65 - 0
src/Xml2XmlRpcRequestProcessor.h

@@ -0,0 +1,65 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML2_XML_RPC_REQUEST_PROCESSOR_H_
+#define _D_XML2_XML_RPC_REQUEST_PROCESSOR_H_
+
+#include "common.h"
+
+#include <string>
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#include "SharedHandle.h"
+#include "XmlRpcRequest.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+class XmlRpcRequestParserStateMachine;
+
+class XmlRpcRequestProcessor {
+private:
+  SharedHandle<XmlRpcRequestParserStateMachine> _stm;
+public:
+  XmlRpcRequest parseMemory(const std::string& xml);
+};
+
+} // namespace xmlrpc
+
+} // namespace aria2
+
+#endif // _D_XML2_XML_RPC_REQUEST_PROCESSOR_H_

+ 61 - 0
src/XmlRpcElements.cc

@@ -0,0 +1,61 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "XmlRpcElements.h"
+
+namespace aria2 {
+namespace xmlrpc {
+namespace elements {
+
+const std::string METHOD_CALL("methodCall");
+const std::string METHOD_NAME("methodName");
+const std::string PARAMS("params");
+const std::string PARAM("param");
+const std::string VALUE("value");
+const std::string I4("i4");
+const std::string INT("int");
+const std::string BOOLEAN("boolean");
+const std::string STRING("string");
+const std::string DOUBLE("double");
+const std::string DATE_TIME_ISO8601("dateTime.iso8601");
+const std::string BASE64("base64");
+const std::string STRUCT("struct");
+const std::string MEMBER("member");
+const std::string NAME("name");
+const std::string ARRAY("array");
+const std::string DATA("data");
+
+} // namespace elements
+} // namespace xmlrpc
+} // namespace aria2

+ 68 - 0
src/XmlRpcElements.h

@@ -0,0 +1,68 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML_RPC_ELEMENTS_H_
+#define _D_XML_RPC_ELEMENTS_H_
+
+#include "common.h"
+
+#include <string>
+
+namespace aria2 {
+namespace xmlrpc {
+namespace elements {
+
+extern const std::string METHOD_CALL;
+extern const std::string METHOD_NAME;
+extern const std::string PARAMS;
+extern const std::string PARAM;
+extern const std::string VALUE;
+extern const std::string I4;
+extern const std::string INT;
+extern const std::string BOOLEAN;
+extern const std::string STRING;
+extern const std::string DOUBLE;
+extern const std::string DATE_TIME_ISO8601;
+extern const std::string BASE64;
+extern const std::string STRUCT;
+extern const std::string MEMBER;
+extern const std::string NAME;
+extern const std::string ARRAY;
+extern const std::string DATA;
+
+} // namespace elements
+} // namespace xmlrpc
+} // namespace aria2
+
+#endif // _D_XML_RPC_ELEMENTS_H_

+ 60 - 0
src/XmlRpcRequest.h

@@ -0,0 +1,60 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML_RPC_REQUEST_H_
+#define _D_XML_RPC_REQUEST_H_
+
+#include "common.h"
+
+#include <string>
+
+#include "BDE.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+struct XmlRpcRequest {
+  std::string _methodName;
+  BDE _params;
+
+  XmlRpcRequest(const std::string& methodName, const BDE& params):
+    _methodName(methodName), _params(params) {}
+};
+
+} // namespace xmlrpc
+
+} // namespace aria2
+
+#endif // _D_XML_RPC_REQUEST_H_

+ 77 - 0
src/XmlRpcRequestParserController.cc

@@ -0,0 +1,77 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "XmlRpcRequestParserController.h"
+
+#include <cassert>
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+void XmlRpcRequestParserController::pushFrame()
+{
+  _frameStack.push(_currentFrame);
+  _currentFrame = StateFrame();
+}
+
+void XmlRpcRequestParserController::popStructFrame()
+{
+  assert(!_frameStack.empty());
+
+  StateFrame parentFrame = _frameStack.top();
+  assert(parentFrame._value.isDict());
+  _frameStack.pop();
+  if(_currentFrame.validMember()) {
+    parentFrame._value[_currentFrame._name] = _currentFrame._value;
+  }
+  _currentFrame = parentFrame;
+}
+
+void XmlRpcRequestParserController::popArrayFrame()
+{
+  assert(!_frameStack.empty());
+
+  StateFrame parentFrame = _frameStack.top();
+  assert(parentFrame._value.isList());
+  _frameStack.pop();
+  if(!_currentFrame._value.isNone()) {
+    parentFrame._value << _currentFrame._value;
+  }
+  _currentFrame = parentFrame;
+}
+
+} // namespace xmlrpc
+  
+} // namespace aria2

+ 102 - 0
src/XmlRpcRequestParserController.h

@@ -0,0 +1,102 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML_RPC_REQUEST_PARSER_CONTROLLER_H_
+#define _D_XML_RPC_REQUEST_PARSER_CONTROLLER_H_
+
+#include "common.h"
+
+#include <stack>
+#include <string>
+
+#include "BDE.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+class XmlRpcRequestParserController {
+private:
+
+  struct StateFrame {
+    BDE _value;
+    std::string _name;
+
+    bool validMember() const
+    {
+      return !_value.isNone() && !_name.empty();
+    }
+  };
+
+  std::stack<StateFrame> _frameStack;
+
+  StateFrame _currentFrame;
+
+  std::string _methodName;
+public:
+  void pushFrame();
+
+  // Pops StateFrame p from _frameStack and set p[_currentFrame._name]
+  // = _currentFrame._value and _currentFrame = p;
+  void popStructFrame();
+
+  // Pops StateFrame p from _frameStack and add _currentFrame._value
+  // to p and _currentFrame = p;
+  void popArrayFrame();
+  
+  void setCurrentFrameValue(const BDE& value)
+  {
+    _currentFrame._value = value;
+  }
+
+  void setCurrentFrameName(const std::string& name)
+  {
+    _currentFrame._name = name;
+  }
+
+  const BDE& getCurrentFrameValue() const { return _currentFrame._value; }
+
+  void setMethodName(const std::string& methodName)
+  {
+    _methodName = methodName;
+  }
+
+  const std::string& getMethodName() const { return _methodName; }
+};
+
+} // namespace xmlrpc
+
+} // namespace aria2
+
+#endif // _D_XML_RPC_REQUEST_PARSER_CONTROLLER_H_

+ 68 - 0
src/XmlRpcRequestParserState.h

@@ -0,0 +1,68 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML_RPC_REQUEST_PARSER_STATE_H_
+#define _D_XML_RPC_REQUEST_PARSER_STATE_H_
+
+#include "common.h"
+
+#include <string>
+#include <map>
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+class XmlRpcRequestParserStateMachine;
+
+class XmlRpcRequestParserState {
+public:
+  virtual ~XmlRpcRequestParserState() {}
+
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs)= 0;
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) = 0;
+
+  virtual bool needsCharactersBuffering() const = 0;
+};
+
+} // namespace xmlrpc
+
+} // namespace aria2
+
+#endif // _D_XML_RPC_REQUEST_PARSER_STATE_H_

+ 329 - 0
src/XmlRpcRequestParserStateImpl.cc

@@ -0,0 +1,329 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "XmlRpcRequestParserStateImpl.h"
+#include "XmlRpcRequestParserStateMachine.h"
+#include "XmlRpcElements.h"
+#include "RecoverableException.h"
+#include "Util.h"
+#include "Base64.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+// InitialXmlRpcRequestParserState
+
+void InitialXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::METHOD_CALL) {
+    stm->pushMethodCallState();
+  } else {
+    stm->pushUnknownElementState();
+  }  
+}
+  
+void InitialXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{}
+
+// UnknownElementXmlRpcRequestParserState
+
+void UnknownElementXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  stm->pushUnknownElementState();
+}
+
+// MethodCallXmlRpcRequestParserState
+
+void MethodCallXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::METHOD_NAME) {
+    stm->pushMethodNameState();
+  } else if(name == elements::PARAMS) {
+    stm->setCurrentFrameValue(BDE::list());
+    stm->pushParamsState();
+  } else {
+    stm->pushUnknownElementState();
+  }  
+}
+  
+// MethodNameXmlRpcRequestParserState
+
+void MethodNameXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  stm->pushUnknownElementState();
+}
+  
+void MethodNameXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  stm->setMethodName(characters);
+}
+
+// ParamsXmlRpcRequestParserState
+
+void ParamsXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::PARAM) {
+    stm->pushFrame();
+    stm->pushParamState();
+  } else {
+    stm->pushUnknownElementState();
+  }
+}
+  
+// ParamXmlRpcRequestParserState
+
+void ParamXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::VALUE) {
+    stm->pushValueState();
+  } else {
+    stm->pushUnknownElementState();
+  }
+}
+
+void ParamXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  stm->popArrayFrame();
+}
+ 
+// ValueXmlRpcRequestParserState
+
+void ValueXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::I4 || name == elements::INT) {
+    stm->pushIntState();
+  } else if(name == elements::STRUCT) {
+    stm->setCurrentFrameValue(BDE::dict());
+    stm->pushStructState();
+  } else if(name == elements::ARRAY) {
+    stm->setCurrentFrameValue(BDE::list());
+    stm->pushArrayState();
+  } else if(name == elements::STRING || name == elements::DOUBLE) {
+    stm->pushStringState();
+  } else if(name == elements::BASE64) {
+    stm->pushBase64State();
+  } else {
+    stm->pushUnknownElementState();
+  }
+}
+  
+// IntXmlRpcRequestParserState
+
+void IntXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  stm->pushUnknownElementState();
+}
+  
+void IntXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  try {
+    int64_t value = Util::parseLLInt(characters);
+    stm->setCurrentFrameValue(BDE(value));
+  } catch(RecoverableException& e) {
+    // nothing to do here: We just leave current frame value to BDE::none
+  }
+}
+
+// StringXmlRpcRequestParserState
+
+void StringXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  stm->pushUnknownElementState();
+}
+  
+void StringXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  stm->setCurrentFrameValue(BDE(characters));
+}
+
+// Base64XmlRpcRequestParserState
+
+void Base64XmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  stm->pushUnknownElementState();
+}
+  
+void Base64XmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  stm->setCurrentFrameValue(BDE(Base64::decode(characters)));
+}
+
+// StructXmlRpcRequestParserState
+
+void StructXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::MEMBER) {
+    stm->pushFrame();
+    stm->pushMemberState();
+  } else {
+    stm->pushUnknownElementState();
+  }
+}
+
+// MemberXmlRpcRequestParserState
+
+void MemberXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::NAME) {
+    stm->pushNameState();
+  } else if(name == elements::VALUE) {
+    stm->pushValueState();
+  } else {
+    stm->pushUnknownElementState();
+  }
+}
+
+void MemberXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  stm->popStructFrame();
+}
+
+// NameXmlRpcRequestParserState
+
+void NameXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  stm->pushUnknownElementState();
+}
+
+void NameXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  stm->setCurrentFrameName(characters);
+}
+
+// ArrayXmlRpcRequestParserState
+
+void ArrayXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::DATA) {
+    stm->pushDataState();
+  } else {
+    stm->pushUnknownElementState();
+  }
+}
+
+// DataXmlRpcRequestParserState
+
+void DataXmlRpcRequestParserState::beginElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::map<std::string, std::string>& attrs)
+{
+  if(name == elements::VALUE) {
+    stm->pushFrame();
+    stm->pushArrayValueState();
+  } else {
+    stm->pushUnknownElementState();
+  }
+}
+
+// ArrayValueXmlRpcRequestParserState
+
+void ArrayValueXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  stm->popArrayFrame();
+}
+
+} // namespace xmlrpc
+
+} // namespace aria2

+ 238 - 0
src/XmlRpcRequestParserStateImpl.h

@@ -0,0 +1,238 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML_RPC_REQUEST_PARSER_STATE_IMPL_H_
+#define _D_XML_RPC_REQUEST_PARSER_STATE_IMPL_H_
+
+#include "XmlRpcRequestParserState.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+class InitialXmlRpcRequestParserState:public XmlRpcRequestParserState {
+public:
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class UnknownElementXmlRpcRequestParserState:public XmlRpcRequestParserState {
+public:
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) {}
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class MethodCallXmlRpcRequestParserState:public XmlRpcRequestParserState {
+public:
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) {}
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class MethodNameXmlRpcRequestParserState:public XmlRpcRequestParserState {
+public:
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return true; }
+};
+
+class ParamsXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) {}
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class ParamXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class ValueXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) {}
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class IntXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return true; }
+};
+
+class StringXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return true; }
+};
+
+class Base64XmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return true; }
+};
+
+class StructXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) {}
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class MemberXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class NameXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+
+  virtual bool needsCharactersBuffering() const { return true; }
+};
+
+class ArrayXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) {}
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class DataXmlRpcRequestParserState:public XmlRpcRequestParserState {
+  virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
+			    const std::string& name,
+			    const std::map<std::string, std::string>& attrs);
+  
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters) {}
+
+  virtual bool needsCharactersBuffering() const { return false; }
+};
+
+class ArrayValueXmlRpcRequestParserState:public ValueXmlRpcRequestParserState {
+  virtual void endElement(XmlRpcRequestParserStateMachine* stm,
+			  const std::string& name,
+			  const std::string& characters);
+};
+
+} // namespace xmlrpc
+
+} // namespace aria2
+
+#endif // _D_XML_RPC_REQUEST_PARSER_STATE_IMPL_H_

+ 118 - 0
src/XmlRpcRequestParserStateMachine.cc

@@ -0,0 +1,118 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "XmlRpcRequestParserStateMachine.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+InitialXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_initialState =
+  new InitialXmlRpcRequestParserState();
+
+UnknownElementXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_unknownElementState =
+  new UnknownElementXmlRpcRequestParserState();
+
+MethodCallXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_methodCallState =
+  new MethodCallXmlRpcRequestParserState();
+
+MethodNameXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_methodNameState =
+  new MethodNameXmlRpcRequestParserState();
+
+ParamsXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_paramsState =
+  new ParamsXmlRpcRequestParserState();
+
+ParamXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_paramState =
+  new ParamXmlRpcRequestParserState();
+
+ValueXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_valueState =
+  new ValueXmlRpcRequestParserState();
+
+IntXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_intState =
+  new IntXmlRpcRequestParserState();
+
+StringXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_stringState =
+  new StringXmlRpcRequestParserState();
+
+Base64XmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_base64State =
+  new Base64XmlRpcRequestParserState();
+
+StructXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_structState =
+  new StructXmlRpcRequestParserState();
+
+MemberXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_memberState =
+  new MemberXmlRpcRequestParserState();
+
+NameXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_nameState =
+  new NameXmlRpcRequestParserState();
+
+ArrayXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_arrayState = 
+  new ArrayXmlRpcRequestParserState();
+
+DataXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_dataState =
+  new DataXmlRpcRequestParserState();
+
+ArrayValueXmlRpcRequestParserState*
+XmlRpcRequestParserStateMachine::_arrayValueState =
+  new ArrayValueXmlRpcRequestParserState();
+
+XmlRpcRequestParserStateMachine::XmlRpcRequestParserStateMachine():
+  _controller(new XmlRpcRequestParserController())
+{
+  _stateStack.push(_initialState);
+}
+
+XmlRpcRequestParserStateMachine::~XmlRpcRequestParserStateMachine()
+{
+  delete _controller;
+}
+
+} // namespace xmlrpc
+
+} // namespace aria2

+ 174 - 0
src/XmlRpcRequestParserStateMachine.h

@@ -0,0 +1,174 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML_RPC_REQUEST_PARSER_STATE_MACHINE_H_
+#define _D_XML_RPC_REQUEST_PARSER_STATE_MACHINE_H_
+
+#include "common.h"
+
+#include <string>
+#include <map>
+#include <stack>
+
+#include "BDE.h"
+#include "XmlRpcRequestParserController.h"
+#include "XmlRpcRequestParserStateImpl.h"
+
+namespace aria2 {
+
+class BDE;
+
+namespace xmlrpc {
+
+class XmlRpcRequestParserStateMachine {
+private:
+  XmlRpcRequestParserController* _controller;
+
+  std::stack<XmlRpcRequestParserState*> _stateStack;
+
+  static InitialXmlRpcRequestParserState* _initialState;
+  static MethodCallXmlRpcRequestParserState* _methodCallState;
+  static MethodNameXmlRpcRequestParserState* _methodNameState;
+  static ParamsXmlRpcRequestParserState* _paramsState;
+  static ParamXmlRpcRequestParserState* _paramState;
+  static ValueXmlRpcRequestParserState* _valueState;
+  static IntXmlRpcRequestParserState* _intState;
+  static StringXmlRpcRequestParserState* _stringState;
+  static Base64XmlRpcRequestParserState* _base64State;
+  static StructXmlRpcRequestParserState* _structState;
+  static MemberXmlRpcRequestParserState* _memberState;
+  static NameXmlRpcRequestParserState* _nameState;
+  static ArrayXmlRpcRequestParserState* _arrayState;
+  static DataXmlRpcRequestParserState* _dataState;
+  static ArrayValueXmlRpcRequestParserState* _arrayValueState;
+  
+  static UnknownElementXmlRpcRequestParserState* _unknownElementState;
+public:
+  XmlRpcRequestParserStateMachine();
+
+  ~XmlRpcRequestParserStateMachine();
+
+  void beginElement(const std::string& name,
+		    const std::map<std::string, std::string>& attrs)
+  {
+    _stateStack.top()->beginElement(this, name, attrs);
+  }
+  
+  void endElement(const std::string& name, const std::string& characters)
+  {
+    _stateStack.top()->endElement(this, name, characters);
+    _stateStack.pop();
+  }
+
+  void setMethodName(const std::string& methodName)
+  {
+    _controller->setMethodName(methodName);
+  }
+
+  const std::string& getMethodName() const
+  {
+    return _controller->getMethodName();
+  }
+
+  void popArrayFrame()
+  {
+    _controller->popArrayFrame();
+  }
+
+  void popStructFrame()
+  {
+    _controller->popStructFrame();
+  }
+
+  void pushFrame()
+  {
+    _controller->pushFrame();
+  }
+
+  void setCurrentFrameValue(const BDE& value)
+  {
+    _controller->setCurrentFrameValue(value);
+  }
+
+  const BDE& getCurrentFrameValue() const
+  {
+    return _controller->getCurrentFrameValue();
+  }
+
+  void setCurrentFrameName(const std::string& name)
+  {
+    _controller->setCurrentFrameName(name);
+  }
+
+  bool needsCharactersBuffering() const
+  {
+    return _stateStack.top()->needsCharactersBuffering();
+  }
+
+  void pushUnknownElementState() { _stateStack.push(_unknownElementState); }
+
+  void pushMethodCallState() { _stateStack.push(_methodCallState); }
+
+  void pushMethodNameState() { _stateStack.push(_methodNameState); }
+
+  void pushParamsState() { _stateStack.push(_paramsState); }
+
+  void pushParamState() { _stateStack.push(_paramState); }
+
+  void pushValueState() { _stateStack.push(_valueState); }
+
+  void pushIntState() { _stateStack.push(_intState); }
+
+  void pushStringState() { _stateStack.push(_stringState); }
+
+  void pushBase64State() { _stateStack.push(_base64State); }
+
+  void pushStructState() { _stateStack.push(_structState); }
+
+  void pushMemberState() { _stateStack.push(_memberState); }
+
+  void pushNameState() { _stateStack.push(_nameState); }
+
+  void pushArrayState() { _stateStack.push(_arrayState); }
+
+  void pushDataState() { _stateStack.push(_dataState); }
+
+  void pushArrayValueState() { _stateStack.push(_arrayValueState); }
+};
+
+} // namespace xmlrpc
+
+} // namespace aria2
+
+#endif // _D_XML_RPC_REQUEST_PARSER_STATE_MACHINE_H_

+ 46 - 0
src/XmlRpcRequestProcessor.h

@@ -0,0 +1,46 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_XML_RPC_REQUEST_PROCESSOR_H_
+#define _D_XML_RPC_REQUEST_PROCESSOR_H_
+
+#include "common.h"
+
+#ifdef HAVE_LIBXML2
+# include "Xml2XmlRpcRequestProcessor.h"
+#elif HAVE_LIBEXPAT
+# include "ExpatXmlRpcRequestProcessor.h"
+#endif // HAVE_LIBEXPAT
+
+#endif // _D_XML_RPC_REQUEST_PROCESSOR_H_

+ 157 - 0
test/XmlRpcRequestParserControllerTest.cc

@@ -0,0 +1,157 @@
+#include "XmlRpcRequestParserController.h"
+
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+class XmlRpcRequestParserControllerTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(XmlRpcRequestParserControllerTest);
+  CPPUNIT_TEST(testPopStructFrame);
+  CPPUNIT_TEST(testPopStructFrame_noName);
+  CPPUNIT_TEST(testPopStructFrame_noValue);
+  CPPUNIT_TEST(testPopArrayFrame);
+  CPPUNIT_TEST(testPopArrayFrame_noValue);
+  CPPUNIT_TEST(testPopArrayFrame_compound);
+  CPPUNIT_TEST_SUITE_END();
+public:
+  void setUp() {}
+
+  void tearDown() {}
+
+  void testPopStructFrame();
+  void testPopStructFrame_noName();
+  void testPopStructFrame_noValue();
+  void testPopArrayFrame();
+  void testPopArrayFrame_noValue();
+  void testPopArrayFrame_compound();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(XmlRpcRequestParserControllerTest);
+
+void XmlRpcRequestParserControllerTest::testPopStructFrame()
+{
+  XmlRpcRequestParserController controller;
+  controller.setCurrentFrameValue(BDE::dict());
+  controller.pushFrame();
+  controller.setCurrentFrameValue(BDE("Hello, aria2"));
+  controller.setCurrentFrameName("greeting");
+  controller.popStructFrame();
+  const BDE& structValue = controller.getCurrentFrameValue();
+  CPPUNIT_ASSERT_EQUAL((size_t)1, structValue.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("Hello, aria2"),
+		       structValue["greeting"].s());
+}
+
+void XmlRpcRequestParserControllerTest::testPopStructFrame_noName()
+{
+  XmlRpcRequestParserController controller;
+  controller.setCurrentFrameValue(BDE::dict());
+  controller.pushFrame();
+  controller.setCurrentFrameValue(BDE("Hello, aria2"));
+  controller.popStructFrame();
+  const BDE& structValue = controller.getCurrentFrameValue();
+  CPPUNIT_ASSERT(structValue.empty());
+}
+
+void XmlRpcRequestParserControllerTest::testPopStructFrame_noValue()
+{
+  XmlRpcRequestParserController controller;
+  controller.setCurrentFrameValue(BDE::dict());
+  controller.pushFrame();
+  controller.setCurrentFrameName("greeting");
+  controller.popStructFrame();
+  const BDE& structValue = controller.getCurrentFrameValue();
+  CPPUNIT_ASSERT(structValue.empty());
+}
+
+void XmlRpcRequestParserControllerTest::testPopArrayFrame()
+{
+  XmlRpcRequestParserController controller;
+  controller.setCurrentFrameValue(BDE::list());
+  controller.pushFrame();
+  controller.setCurrentFrameValue(BDE(100));
+  controller.popArrayFrame();
+  const BDE& array = controller.getCurrentFrameValue();
+  CPPUNIT_ASSERT_EQUAL((size_t)1, array.size());
+  CPPUNIT_ASSERT_EQUAL((BDE::Integer)100, array[0].i());
+}
+
+void XmlRpcRequestParserControllerTest::testPopArrayFrame_noValue()
+{
+  XmlRpcRequestParserController controller;
+  controller.setCurrentFrameValue(BDE::list());
+  controller.pushFrame();
+  controller.popArrayFrame();
+  const BDE& array = controller.getCurrentFrameValue();
+  CPPUNIT_ASSERT(array.empty());
+}
+
+void XmlRpcRequestParserControllerTest::testPopArrayFrame_compound()
+{
+  XmlRpcRequestParserController controller;
+
+  // We are making following structs. [] = array, {key:value .. } = dict
+
+  // [ { "uris":["http://example.org/aria2","http://aria2.sf.net/"],
+  //     "options":{ "timeout":120 } },
+  //   [ "jp","us" ] ]
+
+  controller.setCurrentFrameValue(BDE::list());
+  controller.pushFrame();
+
+  controller.setCurrentFrameValue(BDE::dict());
+  controller.pushFrame();
+
+  controller.setCurrentFrameName("uris");
+  controller.setCurrentFrameValue(BDE::list());
+  controller.pushFrame();
+
+  controller.setCurrentFrameValue(BDE("http://example.org/aria2"));
+  controller.popArrayFrame();
+  controller.pushFrame();
+
+  controller.setCurrentFrameValue(BDE("http://aria2.sf.net/"));
+  controller.popArrayFrame();
+
+  controller.popStructFrame();
+  controller.pushFrame();
+
+  controller.setCurrentFrameName("options");
+  controller.setCurrentFrameValue(BDE::dict());
+  controller.pushFrame();
+
+  controller.setCurrentFrameName("timeout");
+  controller.setCurrentFrameValue(BDE(120));
+  controller.popStructFrame();
+
+  controller.popStructFrame();
+
+  controller.popArrayFrame();
+  controller.pushFrame();
+
+  controller.setCurrentFrameValue(BDE::list());
+  controller.pushFrame();
+
+  controller.setCurrentFrameValue(BDE("jp"));
+  controller.popArrayFrame();
+  controller.pushFrame();
+
+  controller.setCurrentFrameValue(BDE("us"));
+  controller.popArrayFrame();
+
+  controller.popArrayFrame();
+
+  const BDE& result = controller.getCurrentFrameValue();
+  CPPUNIT_ASSERT_EQUAL(std::string("http://aria2.sf.net/"),
+		       result[0]["uris"][1].s());
+  CPPUNIT_ASSERT_EQUAL((BDE::Integer)120, result[0]["options"]["timeout"].i());
+  CPPUNIT_ASSERT_EQUAL(std::string("jp"), result[1][0].s());
+}
+
+} // namespace xmlrpc
+
+} // namespace aria2

+ 77 - 0
test/XmlRpcRequestProcessorTest.cc

@@ -0,0 +1,77 @@
+#include "XmlRpcRequestProcessor.h"
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "XmlRpcRequestParserStateMachine.h"
+
+namespace aria2 {
+
+namespace xmlrpc {
+
+class XmlRpcRequestProcessorTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(XmlRpcRequestProcessorTest);
+  CPPUNIT_TEST(testParseMemory);
+  CPPUNIT_TEST_SUITE_END();
+public:
+  void setUp() {}
+
+  void tearDown() {}
+
+  void testParseMemory();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(XmlRpcRequestProcessorTest);
+
+void XmlRpcRequestProcessorTest::testParseMemory()
+{
+  XmlRpcRequestProcessor proc;
+  XmlRpcRequest req =
+    proc.parseMemory("<?xml version=\"1.0\"?>"
+		     "<methodCall>"
+		     "  <methodName>aria2.addURI</methodName>"
+		     "    <params>"
+		     "      <param>"
+		     "        <value><i4>100</i4></value>"
+		     "      </param>"
+		     "      <param>"
+		     "       <value>"
+		     "         <struct>"
+		     "           <member>"
+		     "             <name>max-count</name>"
+		     "             <value><i4>65535</i4></value>"
+		     "           </member>"
+		     "           <member>"
+		     "             <name>seed-ratio</name>"
+		     "             <value><double>0.99</double></value>"
+		     "           </member>"
+		     "         </struct>"
+		     "       </value>"
+		     "     </param>"
+		     "     <param>"
+		     "       <value>"
+		     "         <array>"
+		     "           <data>"
+		     "             <value><string>pudding</string></value>"
+		     "             <value><base64>aGVsbG8gd29ybGQ=</base64></value>"
+		     "           </data>"		     
+		     "         </array>"
+		     "       </value>"
+		     "     </param>"
+		     "   </params>"
+		     "</methodCall>");
+
+  CPPUNIT_ASSERT_EQUAL(std::string("aria2.addURI"), req._methodName);
+  CPPUNIT_ASSERT_EQUAL((size_t)3, req._params.size());
+  CPPUNIT_ASSERT_EQUAL((int64_t)100, req._params[0].i());
+  CPPUNIT_ASSERT_EQUAL((int64_t)65535, req._params[1]["max-count"].i());
+  // Current implementation handles double as string.
+  CPPUNIT_ASSERT_EQUAL(std::string("0.99"), req._params[1]["seed-ratio"].s());
+  CPPUNIT_ASSERT_EQUAL(std::string("pudding"), req._params[2][0].s());
+  CPPUNIT_ASSERT_EQUAL(std::string("hello world"), req._params[2][1].s());
+}
+
+} // namespace xmlrpc
+
+} // namespace aria2