#include #include #include #include #include #include #include #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 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::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; }