#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include "CangjieDemangle.h"
#include "Demangler.h"
#include "StdString.h"
using namespace Cangjie;
namespace {
std::map<std::string, std::string> obfNames;
static void Println(const std::string& msg) { std::cout << msg << std::endl; }
void ReadMapFile(const std::string& name)
{
std::string line;
std::ifstream file(name);
const int elemNum = 2;
if (!file.is_open()) {
Println("Cannot open file " + name);
return;
}
while (getline(file, line)) {
std::istringstream iss(line);
std::string obfName;
std::string tmp;
for (int i = 0; i < elemNum; i++) {
if (!getline(iss, tmp, ' ')) {
break;
}
switch (i) {
case 0:
obfName = tmp;
break;
case 1:
obfNames[obfName] = tmp;
break;
default:
break;
}
}
}
file.close();
}
void ReadMapFiles(const std::string& names)
{
std::istringstream iss(names);
std::string name;
while (getline(iss, name, ',')) {
ReadMapFile(name);
}
}
void Usage()
{
Println("Usage:");
Println("\tcjfilt [option] name1 name2 ...");
Println("\tIf there is a '$' in a mangled name, use '' to quote it.");
Println("");
Println("Options:");
Println("\t-l\t\tlist detailed information");
Println("\t-T\t\tdemangle type name");
Println("\t-f\t\tsymbol mapping files generated by obfuscator");
}
bool CheckOption(const std::vector<std::string>& args, const std::string& option)
{
for (const auto& arg : args) {
if (arg == option) {
return true;
}
}
return false;
}
void Demangle(const std::string& mangledName, bool isDetailed)
{
auto demangler = Demangler<Cangjie::StdString>(mangledName.c_str(), '.');
Println(demangler.ScopeResolution());
auto di = demangler.Demangle();
std::string pkgName = std::string(di.GetPkgName().Str());
std::string demangledName =
pkgName + std::string(pkgName.empty() ? "" : ".") + di.GetFullName(demangler.ScopeResolution()).Str();
Println("demangled:\t\t" + demangledName);
if (isDetailed) {
auto identifier = std::string(di.GetIdentifier().Str());
auto argsInfo = std::string(di.GetArgTypesName().Str());
Println("package:\t\t" + pkgName);
Println("identifier:\t\t" + identifier);
Println("args:\t\t\t" + argsInfo);
Println("validation:\t\t" + std::string(di.IsValid() ? "valid" : "invalid"));
Println("is private declaration:\t" + std::string(di.isPrivateDeclaration ? "yes" : "no"));
}
}
void DemangleType(const std::string& mangledName, bool isDetailed)
{
auto demangler = Demangler<Cangjie::StdString>(mangledName.c_str(), '.');
auto di = demangler.Demangle(true);
std::string demangledName{ di.GetFullName(demangler.ScopeResolution()).Str() };
Println("demangled:\t\t" + demangledName);
if (isDetailed) {
std::string pkgName = std::string(di.GetPkgName().Str());
auto identifier = std::string(di.GetIdentifier().Str());
auto argsInfo = std::string(di.GetArgTypesName().Str());
Println("package:\t\t" + pkgName);
Println("identifier:\t\t" + identifier);
Println("args:\t\t\t" + argsInfo);
Println("validation:\t\t" + std::string(di.IsValid() ? "valid" : "invalid"));
}
}
}
int main(int argc, char* argv[])
{
std::vector<std::string> args;
for (int i = 0; i < argc; ++i) {
if (!argv[i]) {
continue;
}
args.emplace_back(argv[i]);
}
if (args.size() <= 1) {
Println("no arguments");
return 1;
}
if (CheckOption(args, "-h")) {
Usage();
return 0;
}
bool isDetailed = CheckOption(args, "-l");
bool isObfuscated = CheckOption(args, "-f");
bool isType = CheckOption(args, "-T");
for (size_t i = 1; i < args.size(); ++i) {
if (args[i] == "-l" || args[i] == "-f" || args[i] == "-T") {
continue;
}
if (isObfuscated && i > 1 && args[i - 1] == "-f") {
ReadMapFiles(args[i]);
continue;
}
if (isObfuscated && obfNames.find(args[i]) != obfNames.end()) {
Demangle(obfNames[args[i]], isDetailed);
} else if (isType) {
DemangleType(args[i], isDetailed);
} else {
Demangle(args[i], isDetailed);
}
}
return 0;
}