mirror of
https://github.com/x64dbg/cpptripleslash.git
synced 2026-11-12 07:51:26 -10:00
203 lines
7.1 KiB
C#
203 lines
7.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace CppTripleSlash
|
|
{
|
|
public static class StringExtensions
|
|
{
|
|
public static string SuperTrim(this string str)
|
|
{
|
|
var sb = new StringBuilder(str.Length);
|
|
var space = false;
|
|
for (var i = 0; i < str.Length; i++)
|
|
{
|
|
if (!space && str[i] == ' ')
|
|
{
|
|
space = true;
|
|
sb.Append(' ');
|
|
}
|
|
else
|
|
{
|
|
space = false;
|
|
sb.Append(str[i]);
|
|
}
|
|
}
|
|
return sb.ToString().Trim();
|
|
}
|
|
|
|
public static string ReplaceWord(this string str, string pattern, string replacement)
|
|
{
|
|
return Regex.Replace(str, "\\b" + pattern + "\\b", replacement);
|
|
}
|
|
}
|
|
|
|
class Function
|
|
{
|
|
class ParseException : Exception
|
|
{
|
|
public ParseException(string message) : base(message) { }
|
|
}
|
|
|
|
public string ReturnType;
|
|
public List<string> Arguments = new List<string>();
|
|
|
|
private static string GetArgumentName(string arg)
|
|
{
|
|
if (arg == "...") //variadic
|
|
{
|
|
return arg;
|
|
}
|
|
if (arg.Contains("=")) //default value => "int n = 42"
|
|
{
|
|
int eqIndex = arg.IndexOf('=');
|
|
return GetArgumentName(arg.Substring(0, eqIndex));
|
|
}
|
|
Match match = Regex.Match(arg, @"\( *\* *([a-zA-Z0-9_]+) *\)");
|
|
if (match.Success) //function parameter => "int (*name)(...)"
|
|
{
|
|
return match.Groups[1].Value;
|
|
}
|
|
//char name[size]
|
|
var blockOpen = arg.IndexOf('[');
|
|
if (blockOpen != -1)
|
|
arg = arg.Substring(0, blockOpen);
|
|
//normal argument
|
|
arg = arg
|
|
.Replace('&', ' ')
|
|
.Replace('*', ' ')
|
|
.ReplaceWord("const", "")
|
|
.ReplaceWord("volatile", "")
|
|
.SuperTrim()
|
|
//http://en.cppreference.com/w/cpp/language/types
|
|
.ReplaceWord("unsigned long long int", "int")
|
|
.ReplaceWord("signed long long int", "int")
|
|
.ReplaceWord("unsigned long long", "int")
|
|
.ReplaceWord("unsigned short int", "int")
|
|
.ReplaceWord("unsigned long int", "int")
|
|
.ReplaceWord("signed long long", "int")
|
|
.ReplaceWord("signed short int", "int")
|
|
.ReplaceWord("signed long int", "int")
|
|
.ReplaceWord("unsigned short", "int")
|
|
.ReplaceWord("unsigned long", "int")
|
|
.ReplaceWord("long long int", "int")
|
|
.ReplaceWord("unsigned int", "int")
|
|
.ReplaceWord("signed short", "int")
|
|
.ReplaceWord("signed long", "int")
|
|
.ReplaceWord("long double", "int")
|
|
.ReplaceWord("signed int", "int")
|
|
.ReplaceWord("short int", "int")
|
|
.ReplaceWord("long long", "int")
|
|
.ReplaceWord("long int", "int")
|
|
.ReplaceWord("unsigned", "int")
|
|
.ReplaceWord("signed", "int")
|
|
.ReplaceWord("short", "int")
|
|
.ReplaceWord("long", "int");
|
|
int lastSpace = arg.LastIndexOf(' ');
|
|
if (lastSpace == -1)
|
|
{
|
|
return "";
|
|
}
|
|
return arg.Substring(lastSpace + 1).SuperTrim();
|
|
}
|
|
|
|
private static IEnumerable<string> SplitArgs(string args)
|
|
{
|
|
List<string> result = new List<string>();
|
|
int parenDepth = 0;
|
|
int templateDepth = 0;
|
|
StringBuilder sb = new StringBuilder();
|
|
foreach (char ch in args)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case '<':
|
|
templateDepth++;
|
|
break;
|
|
case '>':
|
|
templateDepth--;
|
|
if (templateDepth == 0)
|
|
{
|
|
sb.Append(' ');
|
|
}
|
|
break;
|
|
case '(':
|
|
parenDepth++;
|
|
if (templateDepth == 0)
|
|
{
|
|
sb.Append(ch);
|
|
}
|
|
break;
|
|
case ')':
|
|
parenDepth--;
|
|
if (templateDepth == 0)
|
|
{
|
|
sb.Append(ch);
|
|
}
|
|
break;
|
|
default:
|
|
if (parenDepth == 0 && templateDepth == 0 && ch == ',')
|
|
{
|
|
result.Add(sb.ToString());
|
|
sb.Clear();
|
|
}
|
|
else if (templateDepth == 0)
|
|
{
|
|
sb.Append(ch);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
result.Add(sb.ToString());
|
|
return result.Where(s => !string.IsNullOrEmpty(s)).Select(s => s.SuperTrim());
|
|
}
|
|
|
|
public void Parse(string decl)
|
|
{
|
|
ReturnType = null;
|
|
Arguments.Clear();
|
|
if (string.IsNullOrEmpty(decl))
|
|
{
|
|
throw new ParseException("NullOrEmpty");
|
|
}
|
|
decl = decl.SuperTrim();
|
|
if (!decl.EndsWith(";"))
|
|
{
|
|
throw new ParseException("NotEndsWithSemicolon");
|
|
}
|
|
int firstParen = decl.IndexOf('(');
|
|
if (firstParen == -1)
|
|
{
|
|
throw new ParseException("NoFirstParen");
|
|
}
|
|
int lastParen = decl.LastIndexOf(')');
|
|
if (lastParen == -1)
|
|
{
|
|
throw new ParseException("NoLastParen");
|
|
}
|
|
string nameReturnType = decl.Substring(0, firstParen).SuperTrim();
|
|
int lastSpace = nameReturnType.LastIndexOf(' ');
|
|
string args = decl.Substring(firstParen + 1, lastParen - firstParen - 1).SuperTrim();
|
|
foreach (string arg in SplitArgs(args))
|
|
{
|
|
Arguments.Add(GetArgumentName(arg).SuperTrim());
|
|
}
|
|
ReturnType = nameReturnType.Substring(0, lastSpace).Replace("static", "").SuperTrim();
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
var sb = new StringBuilder(ReturnType + "(");
|
|
for (var i = 0; i < Arguments.Count; i++)
|
|
{
|
|
if (i > 0)
|
|
sb.Append(',');
|
|
sb.Append($"\"{Arguments[i]}\"");
|
|
}
|
|
return sb.ToString() + ")";
|
|
}
|
|
}
|
|
}
|