0
0
mirror of https://github.com/mumble-voip/mumble.git synced 2024-12-04 04:27:20 +00:00
mumble-voip_mumble/scripts/generateIceWrapper.py
Robert Adam 330c356e71 MAINT: Remove copyright year from all copyright notices
Keeping these up-to-date is just super tedious and they don't really
fulfill any purpose these days.
2024-09-30 18:06:20 +02:00

203 lines
8.2 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright The Mumble Developers. All rights reserved.
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file at the root of the
# Mumble source tree or at <https://www.mumble.info/LICENSE>.
import argparse
import re
from datetime import datetime
import os
def comment_remover(text):
def replacer(match):
s = match.group(0)
if s.startswith('/'):
return ""
else:
return s
pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE
)
return re.sub(pattern, replacer, text)
def fix_lineEnding(text):
# Convert from Windows to Unix
text = text.replace("\r\n", "\n")
# Convert from old Mac to Unix
text = text.replace("\r", "\n")
return text
def create_disclaimerComment():
return "// This file was auto-generated by scripts/generateIceWrapper.py on " + datetime.now().strftime("%Y-%m-%d") + " -- DO NOT EDIT MANUALLY!\n"
def generateFunction(className, functionName, wrapArgs, callArgs):
function = "void ::MumbleServer::" + className + "I::" + functionName + "_async(" + (", ".join(wrapArgs)) + ") {\n"
function += "\t// qWarning() << \"" + functionName + "\" << meta->mp.qsIceSecretRead.isNull() << meta->mp.qsIceSecretRead.isEmpty();\n"
function += "#ifndef ACCESS_" + className + "_" + functionName + "_ALL\n"
function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\tif (!meta->mp.qsIceSecretRead.isNull()) {\n"
function += "\t\tbool ok = !meta->mp.qsIceSecretRead.isEmpty();\n"
function += "#\telse\n"
function += "\tif (!meta->mp.qsIceSecretRead.isNull() || !meta->mp.qsIceSecretWrite.isNull()) {\n"
function += "\t\tbool ok = !meta->mp.qsIceSecretWrite.isEmpty();\n"
function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\t\t::Ice::Context::const_iterator i = current.ctx.find(\"secret\");\n"
function += "\t\tok = ok && (i != current.ctx.end());\n"
function += "\t\tif (ok) {\n"
function += "\t\t\tconst QString &secret = u8((*i).second);\n"
function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\t\t\tok = ((secret == meta->mp.qsIceSecretRead) || (secret == meta->mp.qsIceSecretWrite));\n"
function += "#\telse\n"
function += "\t\t\tok = (secret == meta->mp.qsIceSecretWrite);\n"
function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n"
function += "\t\t}\n"
function += "\n"
function += "\t\tif (!ok) {\n"
function += "\t\t\tcb->ice_exception(InvalidSecretException());\n"
function += "\t\t\treturn;\n"
function += "\t\t}\n"
function += "\t}\n"
function += "#endif // ACCESS_" + className + "_" + functionName + "_ALL\n"
function += "\n"
function += "\tExecEvent *ie = new ExecEvent(boost::bind(&impl_" + className + "_" + functionName + ", " + ", ".join(callArgs) + "));\n"
function += "\tQCoreApplication::instance()->postEvent(mi, ie);\n"
function += "}\n"
return function
def main():
parser = argparse.ArgumentParser(description="Generates the wrapper files needed for the ICE server-interface")
parser.add_argument("-i", "--ice-file", help="Path to the ICE specification file (*.ice)", metavar="PATH")
parser.add_argument("-g", "--generated-ice-header", help="Path to the header file that was generated by ICE", metavar="PATH")
parser.add_argument("-o", "--out-file", help="Path to the file to write the generated output to. If omitted, the content will be written to std::out", metavar="PATH")
parser.add_argument("-q", "--quiet", action="store_true", help="Don't display used file paths")
args = parser.parse_args()
scriptPath = os.path.realpath(__file__)
rootDir = os.path.dirname(os.path.dirname(scriptPath))
if args.ice_file is None:
# Try to figure out the path to the ice-file (MumbleServer.ice)
args.ice_file = os.path.join(rootDir, "src", "murmur", "MumbleServer.ice")
if args.generated_ice_header is None:
# Try to figure out path to the generated header file (in the build dir)
args.generated_ice_header = os.path.join(rootDir, "build", "src", "murmur", "MumbleServer.h")
if not args.quiet:
print("Using ICE-file at \"%s\"" % args.ice_file)
print("Using ICE-generated header file at \"%s\"" % args.generated_ice_header)
iceSpec = fix_lineEnding(open(args.ice_file, "r").read())
generatedIceHeader = fix_lineEnding(open(args.generated_ice_header, "r").read())
# remove comments from the iceSpec
iceSpec = comment_remover(iceSpec)
# Remove all tabs from iceSpec
iceSpec = iceSpec.replace("\t", "")
# Remove empty lines form iceSpec
iceSpec = iceSpec.replace("\n\n", "\n")
# Escape all special characters so that iceSpec can be used in a std::string ctor
iceSpec = iceSpec.replace("\"", "\\\"") # quotes
iceSpec = iceSpec.replace("\n", "\\n") # newlines
wrapperContent = create_disclaimerComment()
# Include boost-bind as we'll need it later
wrapperContent += "\n#include <boost/bind/bind.hpp>\n\n"
className = ""
for currentLine in generatedIceHeader.split("\n"):
currentLine = currentLine.strip()
if not currentLine:
# Skip empty lines
continue
# find class name
match = re.match(r"^class\s+AMD_(.+)\s+:\s+(?:public\svirtual|virtual\s+public)\s+::Ice(?:::AMDCallback|Util::Shared)", currentLine)
if match:
className = "AMD_" + match.group(1)
match = re.match(r"virtual\s+void\s+ice_response\\((.*)\\)\s+=\s+0;", currentLine)
if match:
if not className:
raise RuntimeError("Expected a className to be found at this time")
match = re.match(r"virtual\s+void\s+(.+)_async\(const\s+(.+?)&\s*\w*,(.*)\s+const\s+::Ice::Current&", currentLine)
if match:
functionName = match.group(1)
objectName = match.group(2)
arguments = match.group(3)
if functionName == "getSlice":
# getSlice is handled separately
continue
targetClass = "Server" if "AMD_Server" in objectName else "Meta"
wrapArgs = []
callArgs = []
argIndex = 0
wrapArgs.append("const %s &cb" % objectName)
callArgs.append("cb")
if targetClass == "Server":
callArgs.append("QString::fromStdString(current.id.name).toInt()")
else:
callArgs.append("current.adapter")
for currentArg in arguments.split(","):
if not currentArg:
# skip empty entries
continue
parts = currentArg.split()
if len(parts) > 1:
lastPart = parts[len(parts) - 1]
if not ":" in lastPart and not "&" in lastPart:
# Omit the last part as it is only a parameter name. We however want the parameters
# to be named p1, p2, ... which we'll do below
currentArg = " ".join(parts[:len(parts) - 1])
if len(currentArg.split()) == 1 and currentArg == "const":
# Failsafe in order for us to not only leave const as the type
# We have to include lastPart after all
currentArg += " " + lastPart
argIndex += 1
wrapArgs.append("%s p%d" % (currentArg, argIndex))
callArgs.append("p%d" % argIndex)
wrapArgs.append("const ::Ice::Current &current")
wrapperContent += generateFunction(targetClass, functionName, wrapArgs, callArgs) + "\n"
wrapperContent += "void ::MumbleServer::MetaI::getSlice_async(const ::MumbleServer::AMD_Meta_getSlicePtr &cb, const Ice::Current&) {\n"
wrapperContent += "\tcb->ice_response(std::string(\"" + iceSpec + "\"));\n"
wrapperContent += "}\n"
if args.out_file is None:
# Write to std::out
print(wrapperContent)
else:
# Write to file
outFile = open(args.out_file, "w")
outFile.write(wrapperContent)
main()