diff options
Diffstat (limited to 'pluginvalidator')
-rwxr-xr-x | pluginvalidator/validate.py | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/pluginvalidator/validate.py b/pluginvalidator/validate.py new file mode 100755 index 0000000..064a494 --- /dev/null +++ b/pluginvalidator/validate.py @@ -0,0 +1,212 @@ +#! /usr/bin/env python2.7 +# -*- coding: utf8 -*- +# +# Copyright (C) 2015 Evol Online +# Author: Andrei Karas (4144) + +import os +import re + +serverSrcPath = "../../server-code/src/" +pluginSrcPath = "../../server-plugin/src/" +filtC = re.compile(".+[.]c", re.IGNORECASE) +filtH = re.compile(".+[.]h", re.IGNORECASE) +comaSplit = re.compile(",") + +class Session: + pass + +def walkFiles(parentDir, session, filt): + files = os.listdir(parentDir) + for file1 in files: + if file1[0] == ".": + continue + file2 = os.path.abspath(parentDir + os.path.sep + file1) + if not os.path.isfile(file2): + walkFiles(file2, session, filt) + elif filt.search(file1): + session.func(file2, session) + + +def extractPlugFuncions(path, session): + with open(path, "r") as f: + for line in f: + for s in session.funcList: + idx = line.find(" " + s) + if idx < 0: + idx = line.find("*" + s) + if idx > 0 and line.find("__attribute__((nonnull") < 0: + if len(line) < idx + len(s) + 1: + continue + ch = line[idx + len(s) + 1] + if ch != '(' and ch != ' ' and ch != '\t': + continue + data = line + if data.find(");") < 0: + for line in f: + data = data + line + if data.find(");") > 1: + session.decls[s] = data + break + else: + session.decls[s] = data + +def extractFuncFuncions(path, session): + with open(path, "r") as f: + for line in f: + for s in session.funcList: + idx = line.find(" " + s) + if idx < 0: + idx = line.find("*" + s) + if idx > 0 and line.find("__attribute__((nonnull") < 0: + if len(line) < idx + len(s) + 1: + continue + ch = line[idx + len(s) + 1] + if ch != '(' and ch != ' ' and ch != '\t': + continue + data = line + if data.find(")") < 0: + for line in f: + data = data + line + if data.find(")") > 1: + session.decls[s] = data + break + else: + session.decls[s] = data + +def loadHookedList(name): + funcToPlug = dict() + plugToFunc = dict() + with open(name, "r") as f: + for line in f: + idx = line.find("addHook") + if idx > 0: + idx = line.find(",") + idx2 = line.find(")") + plug = line[idx + 1 : idx2].strip() + func = plug[1:] + if func[-5:] == "_post": + func = func[:-5] + if func[-4:] == "_pre": + func = func[:-4] + if func not in funcToPlug: + funcToPlug[func] = set() + funcToPlug[func].add(plug); + if plug not in plugToFunc: + plugToFunc[plug] = set() + plugToFunc[plug].add(func); + return (funcToPlug, plugToFunc) + +def checkMissingFunctions(session): + for f in session.funcList: + if f not in session.decls: + print "Missing function {0} and {1}".format(f, session.funcList[f]) + +def decodeTypes(funcs): + arr = dict() + for f in funcs: + #print "{0}: {1}".format(f, funcs[f]) + fstr = funcs[f] + idx = fstr.find("(") + fstr = fstr[fstr.find("(") + 1 : fstr.rfind(")")] + parts = comaSplit.split(fstr) + lst = [] + cnt = 0 + if funcs[f][:5] == "void " and f[-5:] == "_post": + lst.append(("-", "-")) + cnt = cnt + 1 + for part in parts: + part = part.strip() + idx1 = part.rfind(" ") + idx2 = part.rfind("*") + if idx2 > idx1: + idx1 = idx2 + if idx1 < 0: + old = part + else: + # skip retVal first parameters + if cnt == 0 and part[idx1 + 1:].lower() == "retval" and f[-5:] == "_post": + lst.append(("-", "-")) + continue + old = part[:idx1 + 1] + old = old.replace("\r", "") + old = old.replace("\n", "") + part = old.replace(" ", "") + lst.append((old, part)) + cnt = cnt + 1 + #print "'{0}' -> '{1}'".format(old, part) + arr[f] = lst + return arr + +def fixParam(param): + if param[-6:] == "*const": + param = param[:-5] + if param == "structmap_session_data*": + param = "TBL_PC*" + if param == "structflooritem_data*": + param = "TBL_ITEM*" + return param + +def compareFuncs(session): + for func in session.plugDecls: + pfunc = session.plugDecls[func] + for func2 in session.plugToFunc[func]: + ffunc = session.funcDecls[func2] +# print "{0} - {1}".format(func, func2) +# print pfunc +# print ffunc + if func[-5:] == "_post": + if pfunc[0][1] != "-": + print "Error: missing first retVal parameter in function {0}.".format(func) + else: + pfunc = pfunc[1:] + sz1 = len(pfunc) + sz2 = len(ffunc) +# print "{0} - {1}".format(sz1, sz2) + if sz1 != sz2: + print "Error: wrong number of parameters in function {0}.".format(func) + continue + for idx in range(0, sz1): + pf = pfunc[idx][1] + ff = ffunc[idx][1] + pf = fixParam(pf) + ff = fixParam(ff) + if ff[-1] != "*" and ff != "void" and ff != "va_list": + ff = ff + "*" +# print pf +# print ff + if pf != ff: + print "Error: wrong parameters in function {0}.".format(func) + break + +def processServer(name1, name2): + (funcToPlug, plugToFunc) = loadHookedList(pluginSrcPath + name2 + "/init.c") + session = Session() + session.func = extractPlugFuncions + session.funcList = plugToFunc + session.altList = funcToPlug + session.funcToPlug = funcToPlug + session.plugToFunc = plugToFunc + session.decls = dict() + walkFiles(pluginSrcPath + name2, session, filtH) + checkMissingFunctions(session) + session.plugDecls = session.decls + session.plugDecls = decodeTypes(session.plugDecls) + #print session.plugDecls + + pluginfunctions = session.decls + session.func = extractFuncFuncions + session.funcList = funcToPlug + session.altList = plugToFunc + session.decls = dict() + walkFiles(serverSrcPath + name1, session, filtC) + checkMissingFunctions(session) + session.funcDecls = session.decls + session.funcDecls = decodeTypes(session.funcDecls) + #print session.funcDecls + + compareFuncs(session) + +processServer("login", "elogin") +processServer("char", "echar") +processServer("map", "emap") |