summaryrefslogtreecommitdiff
path: root/tools/xml2cpp.cpp
diff options
context:
space:
mode:
authorpdurante <pdurante@30a43799-04e7-0310-8b2b-ea0d24f86d0e>2006-09-05 13:36:22 +0000
committerpdurante <pdurante@30a43799-04e7-0310-8b2b-ea0d24f86d0e>2006-09-05 13:36:22 +0000
commitacfeb85b879556475d1495c4c5979b1e2aa9ee8e (patch)
tree613d5da9a9536e5266342745180ac41d75e2ad7f /tools/xml2cpp.cpp
downloaddbus-c++-acfeb85b879556475d1495c4c5979b1e2aa9ee8e.tar.gz
imported D-Bus C++ library
git-svn-id: http://dev.openwengo.org/svn/openwengo/wengophone-ng/branches/wengophone-dbus-api/libs/dbus@7382 30a43799-04e7-0310-8b2b-ea0d24f86d0e
Diffstat (limited to 'tools/xml2cpp.cpp')
-rw-r--r--tools/xml2cpp.cpp742
1 files changed, 742 insertions, 0 deletions
diff --git a/tools/xml2cpp.cpp b/tools/xml2cpp.cpp
new file mode 100644
index 0000000..36a2838
--- /dev/null
+++ b/tools/xml2cpp.cpp
@@ -0,0 +1,742 @@
+/*
+ *
+ * D-Bus++ - C++ bindings for DBus
+ *
+ * Copyright (C) 2005-2006 Paolo Durante <shackan@gmail.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include "xml2cpp.h"
+
+#include <dbus/dbus.h>
+
+#include <string>
+#include <map>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+using namespace std;
+using namespace DBus;
+
+static const char* tab = " ";
+
+static const char* header = "\n\
+/* This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT! */\n\
+\n\
+";
+
+static const char* dbus_includes = "\n\
+#include <dbus-c++/dbus-c++.h>\n\
+\n\
+";
+
+typedef map<string,string> TypeCache;
+
+void usage( const char* argv0 )
+{
+ cerr << endl << "Usage: " << argv0 << " <xmlfile> [ --client=<outfile.h> ] [ --adaptor=<outfile.h> ]"
+ << endl << endl;
+ exit(-1);
+}
+
+void underscorize( std::string& str )
+{
+ for(unsigned int i = 0; i < str.length(); ++i)
+ {
+ if(!isalpha(str[i])) str[i] = '_';
+ }
+}
+
+std::string stub_name( std::string name )
+{
+ underscorize(name);
+
+ return "_" + name + "_stub";
+}
+
+int char_to_atomic_type( char t )
+{
+ if(strchr("ybnqiuxtdsgavre", t))
+ return t;
+
+ return DBUS_TYPE_INVALID;
+}
+
+const char* atomic_type_to_string( char t )
+{
+ static struct { char type; char* name; } atos[] =
+ {
+ { 'y', "DBus::Byte" },
+ { 'b', "DBus::Bool" },
+ { 'n', "DBus::Int16" },
+ { 'q', "DBus::UInt16" },
+ { 'i', "DBus::Int32" },
+ { 'u', "DBus::UInt32" },
+ { 'x', "DBus::Int64" },
+ { 't', "DBus::UInt64" },
+ { 'd', "DBus::Double" },
+ { 's', "DBus::String" },
+ { 'o', "DBus::Path" },
+ { 'g', "DBus::Signature" },
+ { 'v', "DBus::Variant" },
+ { '\0', "" }
+ };
+ int i;
+
+ for(i = 0; atos[i].type; ++i)
+ {
+ if(atos[i].type == t) break;
+ }
+ return atos[i].name;
+}
+
+bool is_atomic_type( const std::string& type )
+{
+ return type.length() == 1 && char_to_atomic_type(type[0]) != DBUS_TYPE_INVALID;
+}
+
+void _parse_signature( const std::string& signature, std::string& type, size_t& i )
+{
+ for(; i < signature.length(); ++i)
+ {
+ switch(signature[i])
+ {
+ case 'a':
+ {
+ switch(signature[++i])
+ {
+ case '{':
+ {
+ type += "DBus::Dict< ";
+
+ const char* atom = atomic_type_to_string(signature[++i]);
+ if(!atom)
+ {
+ cerr << "invalid signature" << endl;
+ exit(-1);
+ }
+ type += atom;
+ type += ", ";
+ ++i;
+ break;
+ }
+ default:
+ {
+ type += "DBus::Array< ";
+ break;
+ }
+ }
+ _parse_signature(signature, type, i);
+ type += " >";
+ continue;
+ }
+ case '(':
+ {
+ type += "DBus::Struct< ";
+ ++i;
+ _parse_signature(signature, type, i);
+ type += " >";
+ continue;
+ }
+ case ')':
+ case '}':
+ {
+ return;
+ }
+ default:
+ {
+ const char* atom = atomic_type_to_string(signature[i]);
+ if(!atom)
+ {
+ cerr << "invalid signature" << endl;
+ exit(-1);
+ }
+ type += atom;
+
+ if(signature[i+1] != ')' && signature[i+1] != '}' && i+1 < signature.length())
+ {
+ type += ", ";
+ }
+ break;
+ }
+ }
+ }
+}
+
+std::string signature_to_type( const std::string& signature )
+{
+ std::string type;
+ size_t i = 0;
+ _parse_signature(signature, type, i);
+ return type;
+}
+
+void generate_client( Xml::Document& doc, const char* filename )
+{
+ cerr << "writing " << filename << endl;
+
+ ofstream file(filename);
+ if(file.bad())
+ {
+ cerr << "unable to write file " << filename << endl;
+ exit(-1);
+ }
+
+ file << header;
+ std::string filestring = filename;
+ underscorize(filestring);
+
+ std::string cond_comp = "__dbusxx__" + filestring + "__CLIENT_MARSHAL_H";
+
+ file << "#ifndef " << cond_comp << endl;
+ file << "#define " << cond_comp << endl;
+
+ file << dbus_includes;
+#if 0
+ Xml::Node& root = *(doc.root);
+ Xml::Nodes interfaces = root["interface"];
+
+ for(Xml::Nodes::iterator i = interfaces.begin(); i != interfaces.end(); ++i)
+ {
+ Xml::Node& iface = **i;
+ Xml::Nodes methods = iface["method"];
+ Xml::Nodes signals = iface["signal"];
+
+ std::string ifacename = iface.get("name");
+ std::string ifaceclass = ifacename;
+ underscorize(ifaceclass);
+
+ cerr << "generating code for interface " << ifacename << "..." << endl;
+
+ file << "class " << ifaceclass << " : public DBus::InterfaceProxy" << endl
+ << "{" << endl
+ << "public:" << endl
+ << endl
+ << tab << ifaceclass << "()" << endl
+ << tab << ": DBus::InterfaceProxy(\"" << ifacename << "\")" << endl
+ << tab << "{" << endl;
+
+ for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
+ {
+ Xml::Node& signal = **si;
+
+ std::string marshname = "_" + signal.get("name") + "_stub";
+
+ file << tab << tab << "connect_signal(" << ifaceclass << ", " << marshname << ");" << endl;
+ }
+
+ file << tab << "}" << endl
+ << endl;
+
+ for(Xml::Nodes::iterator j = methods.begin(); j != methods.end(); ++j)
+ {
+ Xml::Node& method = **j;
+ std::string methodname = method.get("name");
+ std::string marshname = "_" + methodname + "_stub";
+
+ Xml::Nodes args = method["arg"];
+ Xml::Nodes args_in = args.select("direction","in");
+ Xml::Nodes args_out = args.select("direction","out");
+
+ file << endl;
+
+ if(args_out.size() == 1)
+ {
+ std::string ret_type = args_out.front()->get("type");
+ std::string ret_sig;
+
+ if(is_atomic_type(ret_type))
+ {
+ ret_sig = atomic_type_to_string(ret_type[0]);
+ }
+ else
+ {
+ }
+
+ file << tab << ret_sig << " " << methodname << "( ";
+
+ for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai)
+ {
+ Xml::Node& a = **ai;
+
+ file << "const ";
+
+ if(is_atomic_type(a.get("type")))
+ {
+ file << atomic_type_to_string(a.get("type")[0]);
+ }
+ else
+ {
+ }
+
+ file << "& " << a.get("name") << ( ai+1 != args_in.end() ? ", " : " " );
+ }
+
+ file << ")" << endl;
+ }
+ else
+ {
+ file << tab << "void " << methodname << "( args )" << endl;
+ }
+
+ file << tab << "{" << endl
+ << tab << tab << "DBus::CallMessage call;" << endl
+ << tab << tab << "DBus::MessageIter wi = call.w_iter();" << endl
+ << endl;
+
+ for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai)
+ {
+ Xml::Node& arg = **ai;
+ }
+
+ file << tab << tab << "call.member(\"" << methodname << "\");" << endl
+ << tab << tab << "DBus::Message ret = invoke_method(call);" << endl
+ << tab << tab << "DBus::MessageIter ri = ret.r_iter();" << endl
+ << endl;
+
+ file << tab << "}" << endl
+ << endl;
+
+ }
+
+ file << "};" << endl
+ << endl;
+ }
+#endif
+ file << "#endif//" << cond_comp << endl;
+
+ file.close();
+}
+
+void generate_adaptor( Xml::Document& doc, const char* filename )
+{
+ cerr << "writing " << filename << endl;
+
+ ofstream file(filename);
+ if(file.bad())
+ {
+ cerr << "unable to write file " << filename << endl;
+ exit(-1);
+ }
+
+ file << header;
+ std::string filestring = filename;
+ underscorize(filestring);
+
+ std::string cond_comp = "__dbusxx__" + filestring + "__ADAPTOR_MARSHAL_H";
+
+ file << "#ifndef " << cond_comp << endl
+ << "#define " << cond_comp << endl;
+
+ file << dbus_includes;
+
+ Xml::Node& root = *(doc.root);
+ Xml::Nodes interfaces = root["interface"];
+
+ for(Xml::Nodes::iterator i = interfaces.begin(); i != interfaces.end(); ++i)
+ {
+ Xml::Node& iface = **i;
+ Xml::Nodes methods = iface["method"];
+ Xml::Nodes signals = iface["signal"];
+ Xml::Nodes ms;
+ ms.insert(ms.end(), methods.begin(), methods.end());
+ ms.insert(ms.end(), signals.begin(), signals.end());
+
+ std::string ifacename = iface.get("name");
+ if(ifacename.find("org.freedesktop.DBus") == 0)
+ {
+ cerr << "skipping interface " << ifacename << endl;
+ continue;
+ }
+
+ std::istringstream ss(ifacename);
+ string nspace;
+ size_t nspaces = 0;
+
+ while(ss.str().find('.', ss.tellg()) != string::npos)
+ {
+ getline(ss, nspace, '.');
+
+ file << "namespace " << nspace << " {" << endl;
+
+ ++nspaces;
+ }
+ file << endl;
+
+ std::string ifaceclass;
+
+ getline(ss, ifaceclass);
+
+ cerr << "generating code for interface " << ifacename << "..." << endl;
+
+ file << "class " << ifaceclass << " : public DBus::InterfaceAdaptor" << endl
+ << "{" << endl
+ << "public:" << endl
+ << endl
+ << tab << ifaceclass << "()" << endl
+ << tab << ": DBus::InterfaceAdaptor(\"" << ifacename << "\")" << endl
+ << tab << "{" << endl;
+
+ for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
+ {
+ Xml::Node& method = **mi;
+
+ file << tab << tab << "register_method("
+ << ifaceclass << ", " << method.get("name") << ", "<< stub_name(method.get("name"))
+ << ");" << endl;
+ }
+
+ file << tab << "}" << endl
+ << endl;
+
+ file << tab << "DBus::IntrospectedInterface* const introspect() const " << endl
+ << tab << "{" << endl;
+
+ for(Xml::Nodes::iterator mi = ms.begin(); mi != ms.end(); ++mi)
+ {
+ Xml::Node& method = **mi;
+ Xml::Nodes args = method["arg"];
+
+ file << tab << tab << "static DBus::IntrospectedArgument " << method.get("name") << "_args[] = " << endl
+ << tab << tab << "{" << endl;
+
+ for(Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai)
+ {
+ Xml::Node& arg = **ai;
+
+ file << tab << tab << tab << "{ ";
+
+ if(arg.get("name").length())
+ {
+ file << "\"" << arg.get("name") << "\", ";
+ }
+ else
+ {
+ file << "0, ";
+ }
+ file << "\"" << arg.get("type") << "\", "
+ << ( arg.get("direction") == "in" ? "true" : "false" )
+ << " }," << endl;
+ }
+ file << tab << tab << tab << "{ 0, 0, 0 }" << endl
+ << tab << tab << "};" << endl;
+ }
+
+ file << tab << tab << "static DBus::IntrospectedMethod " << ifaceclass << "_methods[] = " << endl
+ << tab << tab << "{" << endl;
+
+ for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
+ {
+ Xml::Node& method = **mi;
+
+ file << tab << tab << tab << "{ \"" << method.get("name") << "\", " << method.get("name") << "_args }," << endl;
+ }
+
+ file << tab << tab << tab << "{ 0, 0 }" << endl
+ << tab << tab << "};" << endl;
+
+ file << tab << tab << "static DBus::IntrospectedMethod " << ifaceclass << "_signals[] = " << endl
+ << tab << tab << "{" << endl;
+
+ for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
+ {
+ Xml::Node& method = **si;
+
+ file << tab << tab << tab << "{ \"" << method.get("name") << "\", " << method.get("name") << "_args }," << endl;
+ }
+
+ file << tab << tab << tab << "{ 0, 0 }" << endl
+ << tab << tab << "};" << endl;
+
+ file << tab << tab << "static DBus::IntrospectedInterface " << ifaceclass << "_interface = " << endl
+ << tab << tab << "{" << endl
+ << tab << tab << tab << "\"" << ifacename << "\"," << endl
+ << tab << tab << tab << ifaceclass << "_methods," << endl
+ << tab << tab << tab << ifaceclass << "_signals," << endl
+ << tab << tab << "};" << endl
+ << tab << tab << "return &" << ifaceclass << "_interface;" << endl
+ << tab << "}" << endl
+ << endl;
+
+ file << "public:" << endl
+ << endl
+ << tab << "/* methods exported by this interface," << endl
+ << tab << " * you will have to implement them in your ObjectAdaptor" << endl
+ << tab << " */" << endl;
+
+ for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
+ {
+ Xml::Node& method = **mi;
+ Xml::Nodes args = method["arg"];
+ Xml::Nodes args_in = args.select("direction","in");
+ Xml::Nodes args_out = args.select("direction","out");
+
+ file << tab << "virtual ";
+
+ if(args_out.size() == 0 || args_out.size() > 1 )
+ {
+ file << "void ";
+ }
+ else if(args_out.size() == 1)
+ {
+ file << signature_to_type(args_out.front()->get("type")) << " ";
+ }
+
+ file << method.get("name") << "( ";
+
+ unsigned int i = 0;
+ for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
+ {
+ Xml::Node& arg = **ai;
+ file << "const " << signature_to_type(arg.get("type")) << "& ";
+
+ std::string arg_name = arg.get("name");
+ if(arg_name.length())
+ file << arg_name;
+
+ if((i+1 != args_in.size() || args_out.size() > 1))
+ file << ", ";
+ }
+
+ if(args_out.size() > 1)
+ {
+ unsigned int i = 0;
+ for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
+ {
+ Xml::Node& arg = **ao;
+ file << signature_to_type(arg.get("type")) << "&";
+
+ std::string arg_name = arg.get("name");
+ if(arg_name.length())
+ file << " " << arg_name;
+
+ if(i+1 != args_out.size())
+ file << ", ";
+ }
+ }
+ file << " ) = 0;" << endl;
+ }
+
+ file << endl
+ << "protected:" << endl
+ << endl
+ << tab << "/* signals emitted by this interface" << endl
+ << tab << " */" << endl;
+
+ for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
+ {
+ Xml::Node& signal = **si;
+ Xml::Nodes args = signal["arg"];
+
+ file << tab << "void " << signal.get("name") << "( ";
+
+ unsigned int i = 0;
+ for(Xml::Nodes::iterator a = args.begin(); a != args.end(); ++a, ++i)
+ {
+ Xml::Node& arg = **a;
+
+ file << "const " << signature_to_type(arg.get("type")) << "& arg" << i+1;
+
+ if(i+1 != args.size())
+ file << ", ";
+ }
+
+ file << " )" << endl
+ << tab << "{" << endl
+ << tab << tab << "DBus::SignalMessage sig(\"" << signal.get("name") <<"\");" << endl;;
+
+
+ if(args.size() > 0)
+ {
+ file << tab << tab << "DBus::MessageIter wi = sig.w_iter();" << endl;
+
+ for(unsigned int i = 0; i < args.size(); ++i)
+ {
+ file << tab << tab << "wi << arg" << i+1 << ";" << endl;
+ }
+ }
+
+ file << tab << tab << "emit_signal(sig);" << endl
+ << tab << "}" << endl;
+ }
+
+ file << endl
+ << "private:" << endl
+ << endl
+ << tab << "/* marshalers (to unpack the DBus message before calling the actual interface method)" << endl
+ << tab << " */" << endl;
+
+ for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
+ {
+ Xml::Node& method = **mi;
+ Xml::Nodes args = method["arg"];
+ Xml::Nodes args_in = args.select("direction","in");
+ Xml::Nodes args_out = args.select("direction","out");
+
+ file << tab << "DBus::Message " << stub_name(method.get("name")) << "( const DBus::CallMessage& call )" << endl
+ << tab << "{" << endl
+ << tab << tab << "DBus::MessageIter ri = call.r_iter();" << endl
+ << endl;
+
+ unsigned int i = 1;
+ for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
+ {
+ Xml::Node& arg = **ai;
+ file << tab << tab << signature_to_type(arg.get("type")) << " argin" << i << ";"
+ << " ri >> argin" << i << ";" << endl;
+ }
+
+ if(args_out.size() == 0)
+ {
+ file << tab << tab;
+ }
+ else if(args_out.size() == 1)
+ {
+ file << tab << tab << signature_to_type(args_out.front()->get("type")) << " argout1 = ";
+ }
+ else
+ {
+ unsigned int i = 1;
+ for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
+ {
+ Xml::Node& arg = **ao;
+ file << tab << tab << signature_to_type(arg.get("type")) << " argout" << i << ";" << endl;
+ }
+ file << tab << tab;
+ }
+
+ file << method.get("name") << "(";
+
+ for(unsigned int i = 0; i < args_in.size(); ++i)
+ {
+ file << "argin" << i+1;
+
+ if((i+1 != args_in.size() || args_out.size() > 1))
+ file << ", ";
+ }
+
+ if(args_out.size() > 1)
+ for(unsigned int i = 0; i < args_out.size(); ++i)
+ {
+ file << "argout" << i+1;
+
+ if(i+1 != args_out.size())
+ file << ", ";
+ }
+
+ file << ");" << endl;
+
+ file << tab << tab << "DBus::ReturnMessage reply(call);" << endl;
+
+ if(args_out.size() > 0)
+ {
+ file << tab << tab << "DBus::MessageIter wi = reply.w_iter();" << endl;
+
+ for(unsigned int i = 0; i < args_out.size(); ++i)
+ {
+ file << tab << tab << "wi << argout" << i+1 << ";" << endl;
+ }
+ }
+
+ file << tab << tab << "return reply;" << endl;
+
+ file << tab << "}" << endl;
+ }
+
+ file << "};" << endl
+ << endl;
+
+ for(size_t i = 0; i < nspaces; ++i)
+ {
+ file << "} ";
+ }
+ file << endl;
+ }
+
+ file << "#endif//" << cond_comp << endl;
+
+ file.close();
+}
+
+int main( int argc, char** argv )
+{
+ if(argc < 2)
+ {
+ usage(argv[0]);
+ }
+
+ bool client_mode, adaptor_mode;
+ char *client, *adaptor;
+
+ client_mode = false;
+ client = 0;
+
+ adaptor_mode = false;
+ adaptor = 0;
+
+ for(int a = 1; a < argc; ++a)
+ {
+ if(!strncmp(argv[a], "--client=", 9))
+ {
+ client_mode = true;
+ client = argv[a] +9;
+ }
+ else
+ if(!strncmp(argv[a], "--adaptor=", 10))
+ {
+ adaptor_mode = true;
+ adaptor = argv[a] +10;
+ }
+ }
+
+ if(!client_mode && !adaptor_mode) usage(argv[0]);
+
+ ifstream xmlfile(argv[1]);
+
+ if(xmlfile.bad())
+ {
+ cerr << "unable to open file " << argv[1] << endl;
+ return -1;
+ }
+
+ Xml::Document doc;
+
+ try
+ {
+ xmlfile >> doc;
+ //cout << doc.to_xml();
+ }
+ catch(Xml::Error& e)
+ {
+ cerr << "error parsing " << argv[1] << ": " << e.what() << endl;
+ return -1;
+ }
+
+ if(!doc.root)
+ {
+ cerr << "empty document" << endl;
+ return -1;
+ }
+
+ if(client_mode) generate_client(doc, client);
+ if(adaptor_mode) generate_adaptor(doc, adaptor);
+
+ return 0;
+}