windows-nt/Source/XPSP1/NT/base/crts/libw32/tools/source/wsfdiff.cpp
2020-09-26 16:20:57 +08:00

321 lines
8.3 KiB
C++

#include <windows.h>
#include <stdio.h>
#include <string>
#include <set>
#include <iostream>
#include <algorithm>
#include <dbghelp.h>
#define F_USE_USH_NAME 0x000001
#define F_OUT_DIFF 0x000002
#define F_OUT_USH 0x000004
#define F_OUT_WCH 0x000008
#define F_OUT_IDEN 0x000010
#define F_OUT_DNAME 0x000020
#define F_OUT_ALL 0x00001e
using namespace std;
int flags = 0;
enum Ext { none, lib, dll};
char tmp[512];
Ext FindExt(const char *Fname)
{
Fname = strrchr(Fname, '.');
if ( Fname == NULL)
return none;
else if ( !stricmp(Fname, ".Lib"))
return lib;
else if ( !stricmp(Fname, ".Dll"))
return dll;
else
return none;
}
char *filter(char* ch, Ext fext)
{
char *str = strchr(ch, '?');
return str == NULL ? ch: str;
}
const char* setflags(int argc, char *argv[])
{
const char *Fname = NULL;
for (int i = 1; i < argc; i++)
{
if (argv[i][0] == '-' || argv[i][0] == '/')
{
for ( int j = 1; argv[i][j] != '\0'; j++)
{
switch (argv[i][j])
{
case 'u':
case 'U':
flags |= F_OUT_USH;
break;
case 'w':
case 'W':
flags |= F_OUT_WCH;
break;
case 'd':
case 'D':
flags |= F_OUT_DNAME;
break;
case 'i':
case 'I':
flags |= F_OUT_IDEN;
break;
case 'x':
case 'X':
flags |= F_USE_USH_NAME;
break;
default:
return NULL;
}
}
}
else
{
if (!Fname)
Fname = argv[i];
else
return NULL;
}
}
if (!(flags & F_OUT_USH) && !(flags & F_OUT_WCH) && !(flags & F_OUT_IDEN))
flags |= F_OUT_ALL;
return Fname;
}
void print(string st)
{
if ( flags & F_OUT_DNAME)
{
if (UnDecorateSymbolName( st.c_str(), tmp, 511, 0))
cout << tmp << '\n';
else
cout << st << '\n';
} else {
cout << st << '\n';
}
}
int funccmp(const char *func1, const char *func2)
{
while (*func1 != 0 && *func2 != 0)
{
if ( *func1 == *func2)
func1++, func2++;
else if ( func1 == strstr(func1, "_W") &&
func2 == strstr(func2, "G"))
func1 += sizeof("_W"), func2 += sizeof("G");
else if ( func2 == strstr(func2, "_W") &&
func1 == strstr(func1, "G"))
func2 += sizeof("_W"), func1 += sizeof("G");
else
break;
}
if (*func1 < *func2)
return -1;
else if (*func1 > *func2)
return 1;
else
return 0;
}
int Funccmp(const char *func1, const char *func2)
{
static char tmp1[512];
UnDecorateSymbolName(func1, tmp, 511, 0);
UnDecorateSymbolName(func2, tmp1, 511, 0);
func1 = tmp;
func2 = tmp1;
if (strstr(tmp, "wchar_t") || strstr(tmp, "unsigned short"))
return 11;
else if (strstr(tmp1, "wchar_t") || strstr(tmp1, "unsigned short"))
return 22;
while (*func1 != 0 && *func2 != 0)
{
if ( *func1 == *func2)
func1++, func2++;
else if ( func1 == strstr(func1, "wchar_t") &&
func2 == strstr(func2, "unsigned short"))
func1 += sizeof("wchar_t"), func2 += sizeof("unsigned short");
else if ( func2 == strstr(func2, "wchar_t") &&
func1 == strstr(func1, "unsigned short"))
func2 += sizeof("wchar_t"), func1 += sizeof("unsigned short");
else
break;
}
if (*func1 < *func2)
return -1;
else if (*func1 > *func2)
return 1;
else
return 0;
}
int main(int argc, char *argv[])
{
FILE *phDumpbin;
Ext Fext;
const char *Fname;
int StripLine, i, result;
char ExeName[256];
char TmpStr[512];
char *tch;
set<string> Sdiff, Wdiff, Iden;
if (!(Fname = setflags(argc, argv)))
{
cout << "Usage : wsfdiff -[options] filename" << endl;
cout << "-x -X: Use unsigned char as data type in identical functions" << endl;
cout << "-u -U: Print diff with unsigned short version" << endl;
cout << "-w -W: Print diff with wchar_t version" << endl;
cout << "-i -I: Print Identical function" << endl;
cout << "-d -D: UnDname the function names" << endl;
cout << "filename can only have be .lib or .dll" << endl;
return -1;
}
strcpy(ExeName, "dumpbin ");
switch (Fext = FindExt(Fname))
{
case dll:
strcat(ExeName, "-exports ");
break;
case lib:
strcat(ExeName, "-linkermember ");
break;
case none:
return -1;
}
strcat(ExeName, Fname);
phDumpbin = _popen(ExeName, "r");
//Strip header
if (Fext == dll)
StripLine = 19;
else
StripLine = 18;
for ( i = 0; i < StripLine; i++)
{
fgets(TmpStr, 511, phDumpbin);
cerr << TmpStr;
}
set<string>::iterator spos, wpos;
while (fgets(TmpStr, 511, phDumpbin))
{
tch = filter(TmpStr, Fext);
tch[strlen(tch) -1] = '\0';
UnDecorateSymbolName(tch, tmp, 511, 0);
if (strstr (tmp, "wchar_t"))
{
spos = Sdiff.begin();
result = -1;
while(spos != Sdiff.end())
{
switch(result = funccmp(tch, (*spos).c_str()))
{
case 1:
++spos;
break;
case 0:
if (flags & F_USE_USH_NAME)
Iden.insert(*spos);
else
Iden.insert(string(tch));
Sdiff.erase(spos);
break;
}
if ( result != 1)
{
break;
}
}
if (result != 0)
Wdiff.insert(string(tch));
} else if ( strstr(tmp, "unsigned short"))
{
spos = Wdiff.begin();
result = -1;
while(spos != Wdiff.end())
{
switch(result = funccmp(tch, (*spos).c_str()))
{
case 1:
++spos;
break;
case 0:
if (flags & F_USE_USH_NAME)
Iden.insert(string(tch));
else
Iden.insert(*spos);
Wdiff.erase(spos);
break;
}
if ( result != 1)
break;
}
if (result != 0)
Sdiff.insert(string(tch));
}
}
// final checks for diffs and validity
for ( wpos = Wdiff.begin(), spos = Sdiff.begin();
spos != Sdiff.end() && wpos != Wdiff.end();)
{
switch(Funccmp((*wpos).c_str(), (*spos).c_str()))
{
case 0:
if (flags & F_USE_USH_NAME)
Iden.insert(*spos);
else
Iden.insert(*wpos);
spos = Sdiff.erase(spos);
wpos = Wdiff.erase(wpos);
break;
case 1:
++spos;
break;
case -1:
++wpos;
break;
case 11:
wpos = Wdiff.erase(wpos);
break;
case 22:
spos = Sdiff.erase(spos);
}
}
if ( flags & F_OUT_USH)
{
cout << "Only Unsigned Short version " << Sdiff.size() << '\n';
for_each (Sdiff.begin(), Sdiff.end(), print);
cout <<"-----------------------------------------------------------\n";
}
if ( flags & F_OUT_WCH)
{
cout << "Only wchar_t versions " << Wdiff.size() << '\n';
for_each (Wdiff.begin(), Wdiff.end(), print);
cout <<"-----------------------------------------------------------\n";
}
if ( flags & F_OUT_IDEN)
{
cout <<"Both the versions are present " << Iden.size() << '\n';
for_each (Iden.begin(), Iden.end(), print );
cout <<"-----------------------------------------------------------\n";
}
return 1;
}