#include "stdinc.h" static const char File[] = __FILE__; #include "handle.h" #include "mystring.h" #include #include #include "rpc.h" // std::binary_search lamely only returns a bool, not an iterator // it is a simple layer over std::lower_bound template inline Iterator_t BinarySearch(Iterator_t First, Iterator_t Last, const T& t) { Iterator_t Iterator = std::lower_bound(First, Last, t); if (Iterator != Last && !(t < *Iterator) // this is a way to check for equality actually ) return Iterator; return Last; } // // This is just like remove_copy_if, but it is missing an exclamation point // template inline OutputIterator_t CopyIf(InputIterator_t First, InputIterator_t Last, OutputIterator_t Out, Predicate_t Predicate) { for (; First != Last; ++First) if (/*!*/Predicate(*First)) *Out++ = *First; return (Out); } // // get msvcrt.dll wildcard processing on the command line // extern "C" { int _dowildcard = 1; } typedef std::vector StringVector_t; typedef std::deque StringDeque_t; typedef StringVector_t::iterator StringVectorIterator_t; typedef StringVector_t::const_iterator StringVectorConstIterator_t; typedef std::set StringSet_t; typedef StringSet_t::iterator StringSetIterator_t; typedef StringSet_t::const_iterator StringSetConstIterator_t; template class FixedSizeArray_t : public std::vector { public: ~FixedSizeArray_t() { } FixedSizeArray_t() { reserve(N); } }; class FileSystemPath_t { public: void Realize(String_t & str); FileSystemPath_t * m_pParent; String_t m_str; }; void FileSystemPath_t::Realize(String_t & str) { if (m_pParent != NULL) { m_pParent->RealizePath(str); str += L"\\"; } str += m_str; } typedef std::deque FileSystemPathsDeque_t; void IfFailedThrow(HRESULT hr) { if (SUCCEEDED(hr)) return; throw hr; } void CollectFilePathsRecursivelyHelper( const String_t& directory, FileSystemPathsDeque_t& paths, WIN32_FIND_DATAW& wfd ) { CFindFile FindFile; HRESULT hr; IfFailedThrow(hr = FindFile.HrCreate((directory + L"\\*).c_str(), &wfd)); do { if (FusionpIsDotOrDotDot(wfd.cFileName)) continue; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { } else { } } while (::FindNextFileW(FindFile, &wfd)); } void CollectFilePathsRecursively( const String_t & directory, FileSystemPathsDeque_t & paths ) { WIN32_FIND_DATAW wfd; CollectFilePathsRecursivelyHelper(directory, paths, wfd); } class DelayloadTool_t { private: typedef DelayloadTool_t This_t; DelayloadTool_t(const DelayloadTool_t&); void operator=(const DelayloadTool_t&); public: typedef String_t File_t; ~DelayloadTool_t() { } Print_t Print; DelayloadTool_t() : Argv0base_cstr(L"") { } static bool IsPathSeperator(wchar_t ch) { return (ch == '\\' || ch == '/'); } static bool IsAbsolutePath(const String_t& s) { return (s.length() > 2 && (s[1] == ':' || (IsPathSeperator(s[0] && IsPathSeperator(s[1]))))); } // // This transform lets LoadLibrary's search be more like CreateFile's search. // static String_t PrependDotSlashToRelativePath(const String_t& Path) { if (!IsAbsolutePath(Path)) return L".\\" + Path; else return Path; } String_t Argv0; String_t Argv0base; PCWSTR Argv0base_cstr; typedef std::vector Files_t; typedef std::set Tuples_t; Files_t Files; Tuples_t Tuples; bool ShouldPrint; }; typedef String_t::const_iterator StringConstIterator_t; void DelayloadToolAssertFailed(const char* Expression, const char* File, unsigned long Line) { fprintf(stderr, "ASSERTION FAILURE: File %s, Line %lu, Expression %s\n", File, Line, Expression); abort(); } void DelayloadToolInternalErrorCheckFailed(const char* Expression, const char* File, unsigned long Line) { fprintf(stderr, "INTERNAL ERROR: File %s, Line %lu, Expression %s\n", File, Line, Expression); abort(); } String_t NumberToString(ULONG Number, PCWSTR Format = L"0x%lx") { // the size needed is really dependent on Format.. WCHAR NumberAsString[BITS_OF(Number) + 5]; _snwprintf(NumberAsString, NUMBER_OF(NumberAsString), Format, Number); NumberAsString[NUMBER_OF(NumberAsString) - 1] = 0; return NumberAsString; } String_t GetLastErrorString() { PWSTR s = NULL; DWORD Error = GetLastError(); String_t ErrorString = NumberToString(Error, L"%lu"); PWSTR FormatMessageAllocatedBuffer = NULL; if (!FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Error, 0, reinterpret_cast(&FormatMessageAllocatedBuffer), 100, NULL ) || FormatMessageAllocatedBuffer == NULL ) { goto Exit; } if (FormatMessageAllocatedBuffer[0] == 0) { goto Exit; } // // Error messages often end with vertical whitespce, remove it. // s = FormatMessageAllocatedBuffer + StringLength(FormatMessageAllocatedBuffer) - 1; while (s != FormatMessageAllocatedBuffer && (*s == '\n' || *s == '\r')) *s-- = 0; ErrorString = ErrorString + L" (" + FormatMessageAllocatedBuffer + L")"; Exit: LocalFree(FormatMessageAllocatedBuffer); return ErrorString; } bool GetFileSize(PCWSTR Path, __int64& Size) { CFindFile FindFile; WIN32_FIND_DATAW wfd; LARGE_INTEGER liSize; if (!FindFile.Win32Create(Path, &wfd)) return false; liSize.HighPart = wfd.nFileSizeHigh; liSize.LowPart = wfd.nFileSizeLow; Size = liSize.QuadPart; return true; } String_t RemoveOptionChar(const String_t& s) { if (s.Length() != 0) { if (s[0] == '-') return s.substr(1); else if (s[0] == '/') return s.substr(1); else if (s[0] == ':') // hacky.. return s.substr(1); else if (s[0] == '=') // hacky.. return s.substr(1); } return s; } // // String_t has specialized find_first_not_of that uses integral positions, // and globally there is only find_first_of. Here we provide the expected // iterator-based find_first_not_of, based on the std::string code. // // Find the first occurence in [first1, last1) of an element in [first2, last). // // eg: // find_first_not_of("abc":"12;3", ":;"); // ^ // find_first_not_of(":12;3", ":;"); // ^ // find_first_not_of("3", ":;"); // ^ // template Iterator FindFirstNotOf(Iterator first1, Iterator last1, Iterator first2, Iterator last2) { if (first2 == last2) return last1; for ( ; first1 != last1 ; ++first1) { if (std::find(first2, last2, *first1) == last2) { break; } } return first1; } // // consistent style.. // template Iterator FindFirstOf(Iterator first1, Iterator last1, Iterator first2, Iterator last2) { return std::find_first_of(first1, last1, first2, last2); } template void SplitString(const String_t& String, const String_t& Delim, std::vector& Fields) { String_t::const_iterator FieldBegin; String_t::const_iterator FieldEnd = String.begin(); while ((FieldBegin = FindFirstNotOf(FieldEnd, String.end(), Delim.begin(), Delim.end())) != String.end()) { FieldEnd = FindFirstOf(FieldBegin, String.end(), Delim.begin(), Delim.end()); Fields.push_back(String_t(FieldBegin, FieldEnd)); } } void __cdecl Error(const wchar_t* s, ...) { printf("%s\n", s); exit(EXIT_FAILURE); } int DelayloadTool_t::Main(const StringVector_t& args) { StringVectorConstIterator_t i; Operation_t Operation = NULL; for (i = args.begin() ; i != args.end() ; ++i) { String_t s; String_t t; bool PrintAll = false; bool PrintNone = false; bool PrintValue = true; bool PrintUnequal = false; s = *i; s = RemoveOptionChar(s); if (s == L"Sxid12Tool1") { StringVector_t restArgs(i + 1, args.end()); return Sxid12Tool1(restArgs); } else if (GetFileAttributesW(s) != 0xFFFFFFFF) { goto FileLabel; } else if (s.Starts(t = L"Query")) { Operation = &This_t::Query; } else if (s.Starts(t = L"FindDuplicates")) { Operation = &This_t::FindDuplicates; } else if (s.Starts(t = L"Explode")) { Operation = &This_t::Explode; } else if (s.Starts(t = L"Diff")) { Operation = &This_t::FindDuplicates; Print.LeftOnly = true; Print.RightOnly = true; Print.Equal = true; Print.UnequalContents = true; Print.UnequalSize = true; } else if (s.Starts(t = L"Delete")) Operation = &This_t::Delete; else if (s.Starts(t = L"Dump")) Operation = &This_t::Dump; else if (s.Starts(t = L"FindAndDeleteDuplicates")) Operation = &This_t::FindAndDeleteDuplicates; else if (s.Starts(t = L"NoPrint")) { PrintValue = !PrintValue; goto PrintCommonLabel; } else if (s.Starts(t = L"Print")) { PrintCommonLabel: s = RemoveOptionChar(s.substr(t.Length())); bool* Member = NULL; if (s == (t = L"UnequalSize")) Member = &this->Print.UnequalSize; else if (s == (t = L"UnequalContents")) Member = &this->Print.UnequalContents; else if (s == (t = L"UnequalSize")) Member = &this->Print.UnequalSize; else if (s == (t = L"Keep")) Member = &this->Print.Keep; else if (s == (t = L"Delete")) Member = &this->Print.Delete; else if (s == (t = L"Success")) Member = &this->Print.Success; else if (s == (t = L"Unchanged")) Member = &this->Print.Unchanged; else if (s == (t = L"Equal")) Member = &this->Print.Equal; else if (s == (t = L"LeftOnly")) Member = &this->Print.LeftOnly; else if (s == (t = L"RightOnly")) Member = &this->Print.RightOnly; else if (s == L"All") { PrintAll = true; Print.SetAll(true); } else if (s == L"None") { PrintNone = true; Print.SetAll(false); } else if (s == L"Unequal") { PrintUnequal = true; this->Print.UnequalContents = true; this->Print.UnequalSize = true; } if (PrintAll || PrintNone || PrintUnequal) { // nothing } else if (Member == NULL) { printf("%ls : WARNING: unknown print option \"%ls\" ignored\n", Argv0base_cstr, static_cast(s)); continue; } else { bool knownValue = true; s = RemoveOptionChar(s.substr(t.Length())); if (s != L"") { // // This doesn't work because of the equality comparisons above. They need // ignore whatever follows the colon. // if (s == L"No" || s == L"False") PrintValue = !PrintValue; else if (s == L"Yes" || s == L"True") { /* nothing */ } else { knownValue = false; printf("%ls : WARNING: unknown print option \"%ls\" ignored\n", Argv0base_cstr, static_cast(s)); continue; } } if (knownValue) *Member = PrintValue; } continue; } else if (s.Starts(t = L"File")) { FileLabel: s = RemoveOptionChar(s.substr(t.Length())); Files.push_back(s); continue; } else { Files.push_back(s); continue; } s = RemoveOptionChar(s.substr(t.Length())); SplitResourceTupleString(s, Tuples); } //std::sort(Tuples.begin(), Tuples.end()); if (Operation == NULL) { printf("Usage...\n"); return EXIT_FAILURE; } (this->*Operation)(); return EXIT_SUCCESS; } extern "C" { void __cdecl mainCRTStartup(void); void __cdecl wmainCRTStartup(void); } int __cdecl main(int argc, char** argv) { wmainCRTStartup(); return 0; } extern "C" int __cdecl wmain(int argc, wchar_t** argv) { DelayloadTool_t tool; StringVector_t args; args.reserve(argc); tool.Argv0 = argv[0]; String_t::size_type p = tool.Argv0.find_last_of(L"\\/"); if (p != tool.Argv0.npos) tool.Argv0base = tool.Argv0.substr(1 + p); else tool.Argv0base = tool.Argv0; p = tool.Argv0base.find_last_of(L"."); if (p != tool.Argv0base.npos) tool.Argv0base = tool.Argv0base.substr(0, p); tool.Argv0base_cstr = tool.Argv0base.c_str(); std::copy(argv + 1, argv + argc, std::back_inserter(args)); int ret = tool.Main(args); return ret; }