def expand(self, match): # first we try to find the given arguments from the matched line, if needed # after that we find StringPositions from the payload # then we substitute each parameter match in the payload (not inside strings) start = match.start('name') end = match.end('name') identifier = match.group('name') #print("MATCH1: " + match.group(1)) subs = Substitution(match.group('name'), start, end) subs.string = "" subs.start = start if self.parameters: c = readchar(match.string, end) if not c or c != '(' and self.flag == False: errors.add(None, "No parameters for " + self.name) return False args = parseArgumentList(end, match.string) subs.end = end + args.length #print("namematch: " + str(args.arr)) replacement = self.payload strings = scanForStrings(replacement) if len(args.arr) != len(self.parameters): errors.add(None, "Invalid parameters") return None for i, p in enumerate(self.parameters): reg = re.compile(r"(\W|^)+(?P<name>" + p + r")(\W|$)+") while True: hits = 0 namematch = reg.finditer(replacement) for n in namematch: if checkIfInsideString(n.start('name'), strings): continue replacement = n.string[:n.start('name')] + args.arr[i] + n.string[n.end('name'):] hits += 1 break if hits == 0: break subs.string = replacement else: subs.string = self.payload return subs
def handlePragma(identifier, args): if identifier == "dumb_debug": args.dumb_debug = True elif identifier == "anticrap": args.anticrap = True elif identifier == "nomacros": args.nomacros = True else: errors.add("Invalid #pragma identifier") return args
def expandAll(string, macros, visited, state): macrokeys = getMacroKeys(macros, state) expanded = string line = string strings = [] for name in macrokeys: m = macros[name] if m.flag: continue if visited.contains(name): warnings.add(state.row, "Skipping recursive macro call " + name) continue try_match = True while (try_match): try_match = False strings = scanForStrings(expanded) namematch = m.nameregex.finditer(expanded) for n in namematch: if checkIfInsideString(n.start('name'), strings): continue if checkIfInsideComment(line, n.start('name')): continue if state.args.verbose: infos.add(state.row, "\tfound " + name) visited.push(name) length = getInvocationLength(n, m) subs = m.expand(n) visited.pop() if not subs: errors.add(state.row, "Invalid macro call " + name) return expanded final = expandAll(subs.string, macros, visited, state) expanded = strInsert(expanded, subs.start, subs.end, final) if state.args.verbose == True: infos.add(state.row, "Expand " + name + ": " + final) try_match = True break return expanded
def getInvocationLength(match, macro): start = match.start('name') end = match.end('name') identifier = match.group('name') c = readchar(match.string, end) if macro.flag == True: return len(match.group('name')) if not c or c != '(' and macro.parameters: errors.add(None, "No parameters for " + macro.name) return False args = parseArgumentList(match.end('name'), match.string) if not args: return False return args.length + len(identifier)
def process(self): args = self.args self.state.args = args state = self.state path = args.input inputfile = open(path) nextline = inputfile.readline() line = "" state.filename = ntpath.basename(path) state.row = 0 out = [] # the actual contents of the output file operations = [] operations.append(IfdefOperation()) operations.append(DebugOperation()) operations.append(CommentOperation()) operations.append(MacroOperation()) """ TODO: #include handling might clash with DECORATE definitions """ operations.append(MultilineMacroOperation()) operations.append(DotOperation()) operations.append(MinifyOperation()) operations.append(CullOperation()) while True: state.depth = 0 # paren depth state.instring = False discard = False line = nextline nextline = inputfile.readline() if not nextline: state.lastline = True if not line: break current_line = line state.row += 1 for o in operations: result = o.apply(current_line, state) if result.error != None: errors.add(state.row, result.error) if result.discard: discard = True break current_line = result.line if not discard: out.append(current_line) inputfile.close() outputfile = open(args.output, 'w') for r in out: print(r, file=outputfile, end='') outputfile.close() if args.show_report: print ("Found the following macros: ") for m in state.macros: print(str(state.macros[m])) print("") if args.wait_on_error: error_count = len(errors.getLog()) print(str(error_count) + " errors: ") for m in errors: print(" " + m.toString()) if error_count > 0: waitForEnter()
def expand(self, match): # first we try to find the given arguments from the matched line, if needed # after that we find StringPositions from the payload # then we substitute each parameter match in the payload (not inside strings) start = match.start('name') end = match.end('name') identifier = match.group('name') #print("MATCH1: " + match.group(1)) subs = Substitution(match.group('name'), start, end) subs.string = "" subs.start = start if self.parameters: c = readchar(match.string, end) if not c or c != '(' and self.flag == False: errors.add(None, "No parameters for " + self.name) return False args = parseArgumentList(end, match.string) subs.end = end + args.length #print("namematch: " + str(args.arr)) replacement = self.payload strings = scanForStrings(replacement) if len(args.arr) != len(self.parameters): errors.add(None, "Invalid parameters") return None for i, p in enumerate(self.parameters): reg = re.compile(r"(?P<name>(?P<hash>#)?" + p + r")(\W|$)+") while True: hits = 0 namematch = reg.finditer(replacement) for n in namematch: if checkIfInsideString(n.start('name'), strings): continue val = args.arr[i] if n.group('hash'): val = '"' + val + '"' replacement = n.string[:n.start( 'name')] + val + n.string[n.end('name'):] hits += 1 break if hits == 0: break subs.string = replacement else: subs.string = self.payload return subs