You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
516 lines
14 KiB
516 lines
14 KiB
#include "stdinc.h"
|
|
static const char File[] = __FILE__;
|
|
#include "handle.h"
|
|
#include "mystring.h"
|
|
#include <functional>
|
|
#include <set>
|
|
#include "rpc.h"
|
|
|
|
// std::binary_search lamely only returns a bool, not an iterator
|
|
// it is a simple layer over std::lower_bound
|
|
template<class Iterator_t, class T> 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<class InputIterator_t, class OutputIterator_t, class Predicate_t> 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<String_t> StringVector_t;
|
|
typedef std::deque<String_t> StringDeque_t;
|
|
typedef StringVector_t::iterator StringVectorIterator_t;
|
|
typedef StringVector_t::const_iterator StringVectorConstIterator_t;
|
|
|
|
typedef std::set<String_t> StringSet_t;
|
|
typedef StringSet_t::iterator StringSetIterator_t;
|
|
typedef StringSet_t::const_iterator StringSetConstIterator_t;
|
|
|
|
template <typename T, size_t N>
|
|
class FixedSizeArray_t : public std::vector<T>
|
|
{
|
|
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<FileSystemPath_t> 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<File_t> Files_t;
|
|
typedef std::set<ResourceIdTuple_t> 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<PWSTR>(&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 <typename Iterator>
|
|
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 <typename Iterator>
|
|
Iterator FindFirstOf(Iterator first1, Iterator last1, Iterator first2, Iterator last2)
|
|
{
|
|
return std::find_first_of(first1, last1, first2, last2);
|
|
}
|
|
|
|
template <typename String_t>
|
|
void SplitString(const String_t& String, const String_t& Delim, std::vector<String_t>& 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<PCWSTR>(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<PCWSTR>(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;
|
|
}
|