--- a
+++ b/scripts/sdeftoc.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+'''Turn UPnP service defintion XML file into a C++ skeleton based
+on libupnpp'''
+
+import sys
+import os
+import xml.sax.handler
+
+cprolog_text = \
+'''/* Copyright (C) 2016 J.F.Dockes
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "%s"
+
+#include <upnp/upnp.h>
+
+#include <functional>
+#include <iostream>
+#include <map>
+#include <utility>
+
+#include "libupnpp/log.hxx"
+#include "libupnpp/soaphelp.hxx"
+#include "libupnpp/device/device.hxx"
+
+using namespace std;
+using namespace std::placeholders;
+
+'''
+
+hprolog_text = \
+'''/* Copyright (C) 2016 J.F.Dockes
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef _%s_H_INCLUDED_
+#define _%s_H_INCLUDED_
+
+#include <string>
+#include <vector>
+
+#include "libupnpp/device/device.hxx"
+#include "libupnpp/soaphelp.hxx"
+
+using namespace UPnPP;
+
+'''
+
+def back(l):
+ return l[len(l)-1]
+
+def stripsuff(s):
+ dotpos = s.rfind('.')
+ if dotpos != -1:
+ s = s[:dotpos]
+ return s
+
+
+
+class MyHandler(xml.sax.handler.ContentHandler):
+ def __init__(self, classname, cfn, hfn):
+ self.classname = classname
+ self.cfn = cfn
+ self.hfn = hfn
+ self.elstack = []
+ self.chardata = u""
+ self.attrs = {}
+ self.inargs = []
+ self.outargs = []
+ self.actions = []
+ self.statevars = {}
+ self.cprolog = cprolog_text % os.path.basename(hfn)
+ self.cprolog += 'static const string sTp%s("urn:XXX");\n' % classname
+ self.cprolog += 'static const string sId%s("urn:XXX:1");\n\n' % classname
+ self.cprolog += '%s::%s(UPnPProvider::UpnpDevice *dev)\n' % \
+ (classname, classname)
+ self.cprolog += ' : UpnpService(sTp%s, sId%s, dev)\n' % \
+ (classname, classname)
+ self.cprolog += '{\n'
+ uh = stripsuff(os.path.basename(hfn)).upper()
+ self.hprolog = hprolog_text % (uh, uh)
+ self.hprolog += 'class %s : public UPnPProvider::UpnpService {\n' % classname
+ self.hprolog += 'public:\n'
+ self.hprolog += ' %s(UPnPProvider::UpnpDevice *dev);\n\n' % classname
+ self.hprolog += 'private:\n'
+
+ def setDocumentLocator(self, locator):
+ self.locator = locator
+
+ def startElement(self, name, attrs):
+ self.attrs = attrs
+ if name == 'stateVariable':
+ self.stvarev = False
+ self.stvarallow = []
+ if 'sendEvents' in attrs and attrs['sendEvents'] == 'yes':
+ self.stvarev = True
+ self.elstack.append(name)
+
+ def endElement(self, name):
+ self.elstack.pop()
+ chardata = self.chardata.strip()
+ self.chardata = u""
+
+ if name == 'action':
+ self.actions.append([self.actionname, self.inargs, self.outargs])
+ self.inargs = []
+ self.outargs = []
+ elif name == 'stateVariable':
+ self.statevars[self.stvarname] = [self.stvartype, self.stvarev, \
+ self.stvarallow]
+ self.stvartype = u''
+ self.stvarev = False
+ self.stvarallow = []
+ elif name == 'name':
+ if back(self.elstack) == 'action':
+ self.actionname = chardata
+ elif back(self.elstack) == 'argument':
+ self.argname = chardata
+ elif back(self.elstack) == 'stateVariable':
+ self.stvarname = chardata
+ elif name == 'dataType':
+ self.stvartype = chardata
+ elif name == 'allowedValue':
+ self.stvarallow.append(chardata)
+ elif name == 'sendEventsAttribute' and chardata == 'yes':
+ self.stvarev = True
+ elif name == 'direction':
+ self.argdir = chardata
+ elif name == 'relatedStateVariable':
+ self.relvar = chardata
+ elif name == 'argument':
+ if self.argdir == 'in':
+ self.inargs.append([self.argname, self.relvar])
+ else:
+ self.outargs.append([self.argname, self.relvar])
+ self.argname = u''
+ self.argdir = u''
+ self.relvar = u''
+
+ def characters(self, chars):
+ self.chardata += chars
+
+ def actionMethodText(self, actname, inargs, outargs):
+ methname = "%s::act%s" % (self.classname, actname)
+ txt = u''
+ txt += "int %s(const SoapIncoming& sc, SoapOutgoing& data)\n"\
+ % methname
+ txt += "{\n"
+ if len(inargs) != 0:
+ txt += " bool ok = false;\n"
+ for arg in inargs:
+ relvar = arg[1]
+ if relvar in self.statevars:
+ atype = self.statevars[relvar][0]
+ else:
+ atype = 'string'
+ if atype == 'string':
+ txt += ' std::string in_%s;\n' % arg[0]
+ elif atype == 'boolean':
+ txt += ' bool in_%s;\n' % arg[0]
+ else:
+ txt += ' int in_%s;\n' % arg[0]
+ txt += ' ok = sc.get("%s", &in_%s);\n' % (arg[0], arg[0])
+ txt += ' if (!ok) {\n'
+ txt += ' LOGERR("%s: no %s in params\\n");\n' %\
+ (methname, arg[0])
+ txt += ' return UPNP_E_INVALID_PARAM;\n'
+ txt += ' }\n'
+
+ txt += "\n"
+
+ for arg in outargs:
+ txt += ' std::string out_%s;\n' % arg[0]
+ for arg in outargs:
+ txt += ' data.addarg("%s", out_%s);\n' % (arg[0], arg[0])
+
+ txt += " return UPNP_E_SUCCESS;\n"
+ txt += "}\n\n"
+ return txt
+
+ def endDocument(self):
+ act_text = u''
+ for act in self.actions:
+ self.cprolog += ' dev->addActionMapping(\n'
+ self.cprolog += ' this, "%s",\n'% act[0]
+ self.cprolog += ' bind(&%s::act%s, this, _1, _2));\n' % \
+ (self.classname, act[0])
+ act_text += self.actionMethodText(act[0], act[1], act[2])
+
+ self.cprolog += '}\n\n'
+
+ f = open(self.cfn, "w")
+ print(self.cprolog, file = f)
+ print(act_text, file = f)
+ f.close()
+
+ f = open(self.hfn, "w")
+ for nm in self.actions:
+ self.hprolog += ' int act%s(const SoapIncoming& sc, SoapOutgoing& data);\n' % nm[0]
+ self.hprolog += '};\n'
+ self.hprolog += '#endif\n'
+ print(self.hprolog, file = f)
+ f.close
+
+def Usage():
+ print("Usage: %s xmlfilename cfn hfn" % os.path.basename(sys.argv[0]), file=sys.stderr)
+ sys.exit(1)
+
+if len(sys.argv) != 4:
+ Usage()
+
+inputname = sys.argv[1]
+cfn = sys.argv[2]
+hfn = sys.argv[3]
+
+classname = stripsuff(os.path.basename(inputname))
+
+handler = MyHandler(classname, cfn, hfn)
+parser = xml.sax.make_parser()
+
+xml.sax.parse(inputname, handler)
+