Leaked source code of windows server 2003
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.

1719 lines
59 KiB

  1. #include "stdinc.h"
  2. static const char SourceFile[] = __FILE__;
  3. #include "Handle.h"
  4. #include <functional>
  5. #include <set>
  6. #include "rpc.h"
  7. inline SIZE_T StringLength(LPCSTR psz) { return ::strlen(psz); }
  8. inline SIZE_T StringLength(LPCWSTR psz) { return ::wcslen(psz); }
  9. // std::binary_search lamely only returns a bool, not an iterator
  10. // it is a simple layer over std::lower_bound
  11. template<class Iterator_t, class T> inline
  12. Iterator_t BinarySearch(Iterator_t First, Iterator_t Last, const T& t)
  13. {
  14. Iterator_t Iterator = std::lower_bound(First, Last, t);
  15. if (Iterator != Last
  16. && !(t < *Iterator) // this is a way to check for equality actually
  17. )
  18. return Iterator;
  19. return Last;
  20. }
  21. //
  22. // This is just like remove_copy_if, but it is missing an exclamation point
  23. //
  24. template<class InputIterator_t, class OutputIterator_t, class Predicate_t> inline
  25. OutputIterator_t CopyIf(InputIterator_t First, InputIterator_t Last, OutputIterator_t Out, Predicate_t Predicate)
  26. {
  27. for (; First != Last; ++First)
  28. if (/*!*/Predicate(*First))
  29. *Out++ = *First;
  30. return (Out);
  31. }
  32. //
  33. // get msvcrt.dll wildcard processing on the command line
  34. //
  35. extern "C" { int _dowildcard = 1; }
  36. #define RESOURCE_PATH_LENGTH 3
  37. #define RESOURCE_TYPE_INDEX 0
  38. #define RESOURCE_NAME_INDEX 1 /* aka ID, but also each index is also called an id */
  39. #define RESOURCE_LANG_INDEX 2
  40. #define NUMBER_OF(x) (sizeof(x)/sizeof((x)[0]))
  41. class Resource_t;
  42. class ResourceId_t;
  43. class BuiltinResourceId_t;
  44. #include "MyString.h"
  45. typedef std::vector<String_t> StringVector_t;
  46. typedef StringVector_t::iterator StringVectorIterator_t;
  47. typedef StringVector_t::const_iterator StringVectorConstIterator_t;
  48. typedef std::set<String_t> StringSet_t;
  49. typedef StringSet_t::iterator StringSetIterator_t;
  50. typedef StringSet_t::const_iterator StringSetConstIterator_t;
  51. template <typename T, size_t N>
  52. class FixedSizeArray_t : public std::vector<T>
  53. {
  54. public:
  55. ~FixedSizeArray_t() { }
  56. FixedSizeArray_t() { reserve(N); }
  57. };
  58. String_t NormalizeResourceId(const String_t&);
  59. String_t NormalizeResourceId(PCWSTR);
  60. class BuiltinResourceId_t
  61. {
  62. public:
  63. friend bool operator<(const BuiltinResourceId_t& x, const String_t& y)
  64. { return _wcsicmp(x.Name, y) < 0; }
  65. friend bool operator<(const BuiltinResourceId_t& x, const BuiltinResourceId_t& y)
  66. { return _wcsicmp(x.Name, y.Name) < 0; }
  67. friend bool operator<(const String_t& x, const BuiltinResourceId_t& y)
  68. { return _wcsicmp(x, y.Name) < 0; }
  69. PCWSTR Name;
  70. ULONG_PTR Number;
  71. //WCHAR PoundNumberString[4];
  72. };
  73. class ResourceId_t : public String_t
  74. {
  75. private:
  76. typedef String_t Base;
  77. public:
  78. ResourceId_t() { }
  79. ~ResourceId_t() { }
  80. ResourceId_t(PCWSTR x) : Base(NormalizeResourceId(x)) { }
  81. ResourceId_t(const ResourceId_t& x) : Base(x) { }
  82. ResourceId_t(const String_t& x) : Base(NormalizeResourceId(x)) { }
  83. void operator=(PCWSTR x) { Base::operator=(NormalizeResourceId(x)); }
  84. void operator=(const ResourceId_t& x) { Base::operator=(x); }
  85. void operator=(const String_t& x) { Base::operator=(NormalizeResourceId(x)); }
  86. };
  87. String_t NumberToResourceId(ULONG Number)
  88. {
  89. WCHAR NumberAsString[BITS_OF(Number) + 5];
  90. _snwprintf(NumberAsString, NUMBER_OF(NumberAsString), L"#%lu", Number);
  91. NumberAsString[NUMBER_OF(NumberAsString) - 1] = 0;
  92. return NumberAsString;
  93. }
  94. class ResourceIdTuple_t
  95. {
  96. public:
  97. ~ResourceIdTuple_t() { }
  98. ResourceIdTuple_t() { }
  99. ResourceId_t Type;
  100. ResourceId_t Name;
  101. ResourceId_t Language;
  102. bool operator==(const ResourceIdTuple_t& Right) const
  103. {
  104. return !(*this < Right) && !(Right < *this);
  105. }
  106. static bool ResourceIdPointerLessThan(const ResourceId_t* x, const ResourceId_t* y)
  107. {
  108. return x->compare(*y) < 0;
  109. }
  110. bool operator<(const ResourceIdTuple_t& Right) const
  111. {
  112. // the order is NOT arbitrary (er..it wasn't, but now we don't care even about sorting)
  113. const ResourceId_t* LeftArray[] = { &this->Type, &this->Name, &this->Language };
  114. const ResourceId_t* RightArray[] = { &Right.Type, &Right.Name, &Right.Language };
  115. return std::lexicographical_compare(
  116. LeftArray, LeftArray + NUMBER_OF(LeftArray),
  117. RightArray, RightArray + NUMBER_OF(RightArray),
  118. ResourceIdPointerLessThan
  119. );
  120. }
  121. };
  122. bool Match(const ResourceId_t& Left, const ResourceId_t& Right);
  123. bool Match(const ResourceIdTuple_t& Left, const ResourceIdTuple_t& Right);
  124. class Resource_t
  125. {
  126. public:
  127. ~Resource_t() { }
  128. Resource_t() { }
  129. friend bool EqualByIdTuple(const Resource_t& Left, const Resource_t& Right)
  130. { return Left.IdTuple == Right.IdTuple; }
  131. friend bool LessThanByIdTuple(const Resource_t& Left, const Resource_t& Right)
  132. { return Left.IdTuple < Right.IdTuple; }
  133. // controversial..
  134. bool operator<(const Resource_t& Right) const
  135. {
  136. return LessThanByIdTuple(*this, Right);
  137. }
  138. bool Match(const ResourceIdTuple_t/*&*/ IdTuple) /*const*/
  139. {
  140. return ::Match(this->IdTuple, IdTuple);
  141. }
  142. //
  143. // For example, you may want to sort by size if looking for equal resources independent of resourceid tuple.
  144. //
  145. operator ResourceIdTuple_t&() { return IdTuple; }
  146. operator const ResourceIdTuple_t&() const { return IdTuple; }
  147. ResourceIdTuple_t IdTuple;
  148. PVOID Address; // DllHandle is assumed
  149. ULONG Size;
  150. };
  151. class LessThanByIdTuple_t
  152. {
  153. public:
  154. bool operator()(const Resource_t& Left, const ResourceIdTuple_t& Right)
  155. { return Left.IdTuple < Right; }
  156. bool operator()(const ResourceIdTuple_t& Left, const Resource_t& Right)
  157. { return Left < Right.IdTuple; }
  158. };
  159. bool Match(const ResourceId_t& Left, const ResourceId_t& Right)
  160. {
  161. if (Left == L"*" || Right == L"*" || Left == Right
  162. || (Left.Length() > 1 && Right.Length() > 1 && Left[0] == '!' && Right[0] != '!' && Left.substr(1) != Right)
  163. || (Left.Length() > 1 && Right.Length() > 1 && Right[0] == '!' && Left[0] != '!' && Right.substr(1) != Left)
  164. )
  165. return true;
  166. return false;
  167. }
  168. bool Match(const ResourceIdTuple_t& Left, const ResourceIdTuple_t& Right)
  169. {
  170. return Match(Left.Type, Right.Type)
  171. && Match(Left.Name, Right.Name)
  172. && Match(Left.Language, Right.Language)
  173. ;
  174. }
  175. typedef std::map<ResourceIdTuple_t, std::map<ResourceIdTuple_t, std::set<ResourceIdTuple_t> > > ResourceIdTree_t;
  176. void TransformTuplesToTree()
  177. //
  178. // transform the array of triples into a 3 level deep map..nope..
  179. //
  180. {
  181. }
  182. typedef std::set<Resource_t>::iterator EnumIterator_t;
  183. class ResourceTool_t
  184. {
  185. private:
  186. typedef ResourceTool_t This_t;
  187. ResourceTool_t(const ResourceTool_t&);
  188. void operator=(const ResourceTool_t&);
  189. public:
  190. typedef String_t File_t;
  191. ~ResourceTool_t() { }
  192. class Print_t
  193. {
  194. public:
  195. Print_t()
  196. :
  197. UnequalContents(false),
  198. UnequalSize(false),
  199. Equal(true),
  200. Keep(false),
  201. Delete(true),
  202. Success(false),
  203. Unchanged(false),
  204. LeftOnly(false),
  205. RightOnly(false)
  206. {
  207. }
  208. void SetAll(bool Value)
  209. {
  210. UnequalSize = UnequalContents = UnequalSize
  211. = Keep = Delete = Success = Unchanged
  212. = LeftOnly = RightOnly = Equal
  213. = Value;
  214. }
  215. bool UnequalContents;
  216. bool UnequalSize;
  217. bool Equal;
  218. bool Keep;
  219. bool Delete;
  220. bool Success;
  221. bool Unchanged;
  222. bool LeftOnly;
  223. bool RightOnly;
  224. };
  225. Print_t Print;
  226. ResourceTool_t() :
  227. Argv0base_cstr(L""),
  228. ShouldPrint(true)
  229. {
  230. }
  231. static BOOL __stdcall Sxid12EnumResourcesNameCallbackW_static(HMODULE hModule, PCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam);
  232. bool Sxid12EnumResourcesNameCallbackW(HMODULE hModule, PCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam);
  233. void DumpMessageTableResource(const File_t& File, EnumIterator_t EnumIterator);
  234. void DumpStringTableResource(const File_t& File, EnumIterator_t EnumIterator);
  235. void DumpManifestResource(const File_t& File, EnumIterator_t EnumIterator);
  236. void DumpBinaryResource(const File_t& File, EnumIterator_t EnumIterator);
  237. void DumpResource(const File_t& File, EnumIterator_t EnumIterator);
  238. int Sxid12Tool1(const StringVector_t args);
  239. void Query();
  240. void Dump();
  241. void FindDuplicates();
  242. void FindAndDeleteDuplicates();
  243. void Delete();
  244. void Diff(); // same analysis as FindDuplicates, but prints more
  245. void Explode() { } // not implemented
  246. void ChangeEmptyQueryToAllQuery();
  247. typedef void (This_t::*Operation_t)();
  248. int Main(const StringVector_t& args);
  249. static bool IsWildcard(const String_t& s)
  250. {
  251. return (s == L"*");
  252. }
  253. static bool IsPathSeperator(wchar_t ch)
  254. {
  255. return (ch == '\\' || ch == '/');
  256. }
  257. static bool IsAbsolutePath(const String_t& s)
  258. {
  259. return (s.length() > 2
  260. && (s[1] == ':' || (IsPathSeperator(s[0] && IsPathSeperator(s[1])))));
  261. }
  262. //
  263. // This transform lets LoadLibrary's search be more like CreateFile's search.
  264. //
  265. static String_t PrependDotSlashToRelativePath(const String_t& Path)
  266. {
  267. if (!IsAbsolutePath(Path))
  268. return L".\\" + Path;
  269. else
  270. return Path;
  271. }
  272. bool OpenResourceFile(ULONG Flags, DDynamicLinkLibrary& dll, String_t Path);
  273. String_t Argv0;
  274. String_t Argv0base;
  275. PCWSTR Argv0base_cstr;
  276. typedef std::vector<File_t> Files_t;
  277. typedef std::set<ResourceIdTuple_t> Tuples_t;
  278. Files_t Files;
  279. Tuples_t Tuples;
  280. bool ShouldPrint;
  281. };
  282. typedef String_t::const_iterator StringConstIterator_t;
  283. void PrintString(const wchar_t* s)
  284. {
  285. fputws(s, stdout);
  286. }
  287. void ResourceToolAssertFailed(const char* Expression, const char* File, unsigned long Line)
  288. {
  289. fprintf(stderr, "ASSERTION FAILURE: File %s, Line %lu, Expression %s\n", File, Line, Expression);
  290. abort();
  291. }
  292. void ResourceToolInternalErrorCheckFailed(const char* Expression, const char* File, unsigned long Line)
  293. {
  294. fprintf(stderr, "INTERNAL ERROR: File %s, Line %lu, Expression %s\n", File, Line, Expression);
  295. abort();
  296. }
  297. struct Sxid12EnumResourcesNameCallbackWParam_t
  298. {
  299. ResourceTool_t* This;
  300. String_t dllName;
  301. std::vector<ULONG> integralResourceIds;
  302. StringVector_t stringResourceIds;
  303. };
  304. BOOL __stdcall
  305. ResourceTool_t::Sxid12EnumResourcesNameCallbackW_static(
  306. HMODULE hModule,
  307. PCWSTR lpszType,
  308. LPWSTR lpszName,
  309. LONG_PTR lParam
  310. )
  311. {
  312. Sxid12EnumResourcesNameCallbackWParam_t* param = reinterpret_cast<Sxid12EnumResourcesNameCallbackWParam_t*>(lParam);
  313. return param->This->Sxid12EnumResourcesNameCallbackW(hModule, lpszType, lpszName, lParam);
  314. }
  315. bool
  316. ResourceTool_t::Sxid12EnumResourcesNameCallbackW(
  317. HMODULE hModule,
  318. PCWSTR lpszType,
  319. LPWSTR lpszName,
  320. LONG_PTR lParam
  321. )
  322. {
  323. Sxid12EnumResourcesNameCallbackWParam_t* param = reinterpret_cast<Sxid12EnumResourcesNameCallbackWParam_t*>(lParam);
  324. if (IS_INTRESOURCE(lpszName))
  325. {
  326. ULONG iType = static_cast<ULONG>(reinterpret_cast<LONG_PTR>(lpszName));
  327. printf("%ls note: %ls contains RT_MANIFEST with id %u\n", Argv0base_cstr, param->dllName.c_str(), iType);
  328. param->integralResourceIds.insert(param->integralResourceIds.end(), iType);
  329. }
  330. else
  331. {
  332. printf("%ls note: %ls contains RT_MANIFEST with id \"%ls\"\n", Argv0base_cstr, param->dllName.c_str(), lpszName);
  333. param->stringResourceIds.insert(param->stringResourceIds.end(), lpszName);
  334. }
  335. return true;
  336. }
  337. String_t NumberToString(ULONG Number, PCWSTR Format = L"0x%lx")
  338. {
  339. // the size needed is really dependent on Format..
  340. WCHAR NumberAsString[BITS_OF(Number) + 5];
  341. _snwprintf(NumberAsString, NUMBER_OF(NumberAsString), Format, Number);
  342. NumberAsString[NUMBER_OF(NumberAsString) - 1] = 0;
  343. return NumberAsString;
  344. }
  345. LONG StringToNumber(PCWSTR s)
  346. {
  347. int Base = 0;
  348. if (s == NULL || s[0] == 0)
  349. return 0;
  350. if (s[0] == '#')
  351. {
  352. Base = 10;
  353. ++s;
  354. }
  355. return wcstol(s, NULL, Base);
  356. }
  357. PCWSTR StringToResourceString(PCWSTR s)
  358. {
  359. if (s == NULL || s[0] == 0)
  360. return 0;
  361. if (s[0] == '#')
  362. {
  363. return reinterpret_cast<PCWSTR>(static_cast<ULONG_PTR>(StringToNumber(s)));
  364. }
  365. else
  366. {
  367. return s;
  368. }
  369. }
  370. String_t GetLastErrorString()
  371. {
  372. PWSTR s = NULL;
  373. DWORD Error = GetLastError();
  374. String_t ErrorString = NumberToString(Error, L"%lu");
  375. PWSTR FormatMessageAllocatedBuffer = NULL;
  376. if (!FormatMessageW(
  377. FORMAT_MESSAGE_ALLOCATE_BUFFER
  378. | FORMAT_MESSAGE_FROM_SYSTEM
  379. | FORMAT_MESSAGE_IGNORE_INSERTS,
  380. NULL,
  381. Error,
  382. 0,
  383. reinterpret_cast<PWSTR>(&FormatMessageAllocatedBuffer),
  384. 100,
  385. NULL
  386. )
  387. || FormatMessageAllocatedBuffer == NULL
  388. )
  389. {
  390. goto Exit;
  391. }
  392. if (FormatMessageAllocatedBuffer[0] == 0)
  393. {
  394. goto Exit;
  395. }
  396. //
  397. // Error messages often end with vertical whitespce, remove it.
  398. //
  399. s = FormatMessageAllocatedBuffer + StringLength(FormatMessageAllocatedBuffer) - 1;
  400. while (s != FormatMessageAllocatedBuffer && (*s == '\n' || *s == '\r'))
  401. *s-- = 0;
  402. ErrorString = ErrorString + L" (" + FormatMessageAllocatedBuffer + L")";
  403. Exit:
  404. LocalFree(FormatMessageAllocatedBuffer);
  405. return ErrorString;
  406. }
  407. bool GetFileSize(PCWSTR Path, __int64& Size)
  408. {
  409. DFindFile FindFile;
  410. WIN32_FIND_DATAW wfd;
  411. LARGE_INTEGER liSize;
  412. if (!FindFile.Win32Create(Path, &wfd))
  413. return false;
  414. liSize.HighPart = wfd.nFileSizeHigh;
  415. liSize.LowPart = wfd.nFileSizeLow;
  416. Size = liSize.QuadPart;
  417. return true;
  418. }
  419. //
  420. // This is the original sxid2rtool1, preserved
  421. //
  422. int ResourceTool_t::Sxid12Tool1(const StringVector_t args)
  423. {
  424. int ret = EXIT_SUCCESS;
  425. typedef StringVector_t args_t;
  426. __int64 FileSize = 0;
  427. for (args_t::const_iterator i = args.begin() ; i != args.end() ; ++i)
  428. {
  429. DDynamicLinkLibrary dll;
  430. String_t betterPath;
  431. //
  432. // prepend .\ so that LoadLibrary acts more like CreateFile.
  433. //
  434. betterPath = PrependDotSlashToRelativePath(*i);
  435. PCWSTR cstr = betterPath.c_str();
  436. //
  437. // skip empty files to avoid STATUS_MAPPED_FILE_SIZE_ZERO -> ERROR_FILE_INVALID,
  438. //
  439. if (!GetFileSize(cstr, FileSize))
  440. {
  441. String_t ErrorString = GetLastErrorString();
  442. printf("%ls : WARNING: %ls skipped : Error %ls\n", Argv0base_cstr, cstr, ErrorString.c_str());
  443. }
  444. if (FileSize == 0)
  445. {
  446. printf("%ls : WARNING: empty file %ls skipped\n", Argv0base_cstr, cstr);
  447. continue;
  448. }
  449. if (!dll.Win32Create(cstr, LOAD_LIBRARY_AS_DATAFILE))
  450. {
  451. DWORD Error = GetLastError();
  452. String_t ErrorString = GetLastErrorString();
  453. switch (Error)
  454. {
  455. case ERROR_BAD_EXE_FORMAT: // 16bit or not an .exe/.dll at all
  456. break;
  457. case ERROR_ACCESS_DENIED: // could be directory (should support sd ... syntax)
  458. {
  459. DWORD fileAttributes = GetFileAttributesW(cstr);
  460. if (fileAttributes != INVALID_FILE_ATTRIBUTES && (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  461. break;
  462. }
  463. // FALLTHROUGH
  464. default:
  465. printf("%ls : WARNING: %ls skipped : Error %ls\n", Argv0base_cstr, cstr, ErrorString.c_str());
  466. break;
  467. }
  468. continue;
  469. }
  470. Sxid12EnumResourcesNameCallbackWParam_t callbackParam;
  471. callbackParam.This = this;
  472. callbackParam.dllName = betterPath;
  473. EnumResourceNamesW(dll, MAKEINTRESOURCEW(RT_MANIFEST), Sxid12EnumResourcesNameCallbackW_static, reinterpret_cast<LONG_PTR>(&callbackParam));
  474. if (callbackParam.integralResourceIds.size() > 1)
  475. {
  476. printf("%ls WARNING: %ls contains multiple RT_MANIFESTs with integral ids\n", Argv0base_cstr, cstr);
  477. unsigned numberOfReservedManifests = 0;
  478. for (unsigned j = 0 ; j != callbackParam.integralResourceIds.size() ; ++j)
  479. {
  480. if (callbackParam.integralResourceIds[j] >= 1
  481. && callbackParam.integralResourceIds[j] <= 16
  482. )
  483. {
  484. numberOfReservedManifests += 1;
  485. if (numberOfReservedManifests > 1)
  486. {
  487. printf("%ls ERROR: %ls contains RT_MANIFESTs with multiple RESERVED integral ids\n", Argv0base_cstr, cstr);
  488. }
  489. }
  490. }
  491. ret = EXIT_FAILURE;
  492. }
  493. if (callbackParam.stringResourceIds.size() > 0)
  494. {
  495. printf("%ls WARNING: %ls contains RT_MANIFEST with string ids\n", Argv0base_cstr, cstr);
  496. ret = EXIT_FAILURE;
  497. }
  498. if ((callbackParam.integralResourceIds.size() + callbackParam.stringResourceIds.size()) > 1)
  499. {
  500. printf("%ls WARNING: %ls contains multiple RT_MANIFESTs\n", Argv0base_cstr, cstr);
  501. ret = EXIT_FAILURE;
  502. }
  503. }
  504. return ret;
  505. }
  506. String_t RemoveOptionChar(const String_t& s)
  507. {
  508. if (s.Length() != 0)
  509. {
  510. if (s[0] == '-')
  511. return s.substr(1);
  512. else if (s[0] == '/')
  513. return s.substr(1);
  514. else if (s[0] == ':') // hacky..
  515. return s.substr(1);
  516. else if (s[0] == '=') // hacky..
  517. return s.substr(1);
  518. }
  519. return s;
  520. }
  521. //
  522. // String_t has specialized find_first_not_of that uses integral positions,
  523. // and globally there is only find_first_of. Here we provide the expected
  524. // iterator-based find_first_not_of, based on the std::string code.
  525. //
  526. // Find the first occurence in [first1, last1) of an element in [first2, last).
  527. //
  528. // eg:
  529. // find_first_not_of("abc":"12;3", ":;");
  530. // ^
  531. // find_first_not_of(":12;3", ":;");
  532. // ^
  533. // find_first_not_of("3", ":;");
  534. // ^
  535. //
  536. template <typename Iterator>
  537. Iterator FindFirstNotOf(Iterator first1, Iterator last1, Iterator first2, Iterator last2)
  538. {
  539. if (first2 == last2)
  540. return last1;
  541. for ( ; first1 != last1 ; ++first1)
  542. {
  543. if (std::find(first2, last2, *first1) == last2)
  544. {
  545. break;
  546. }
  547. }
  548. return first1;
  549. }
  550. //
  551. // consistent style..
  552. //
  553. template <typename Iterator>
  554. Iterator FindFirstOf(Iterator first1, Iterator last1, Iterator first2, Iterator last2)
  555. {
  556. return std::find_first_of(first1, last1, first2, last2);
  557. }
  558. template <typename String_t>
  559. void SplitString(const String_t& String, const String_t& Delim, std::vector<String_t>& Fields)
  560. {
  561. String_t::const_iterator FieldBegin;
  562. String_t::const_iterator FieldEnd = String.begin();
  563. while ((FieldBegin = FindFirstNotOf(FieldEnd, String.end(), Delim.begin(), Delim.end())) != String.end())
  564. {
  565. FieldEnd = FindFirstOf(FieldBegin, String.end(), Delim.begin(), Delim.end());
  566. Fields.push_back(String_t(FieldBegin, FieldEnd));
  567. }
  568. }
  569. #define RT_MANIFEST MAKEINTRESOURCE(24)
  570. #define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE( 1)
  571. #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2)
  572. #define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3)
  573. #define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE( 1 /*inclusive*/)
  574. #define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(16 /*inclusive*/)
  575. #define DEFINE_POUND_NUMBER_STRING_(x) \
  576. { '#', ((x >= 10) ? ('0' + x / 10) : ('0' + x)), ((x >= 10) ? ('0' + x % 10) : 0), 0 }
  577. #define DEFINE_POUND_NUMBER_STRING(x) DEFINE_POUND_NUMBER_STRING_(reinterpret_cast<ULONG_PTR>(x))
  578. const WCHAR PoundRtString[] = DEFINE_POUND_NUMBER_STRING(RT_STRING);
  579. const WCHAR PoundRtManifest[] = DEFINE_POUND_NUMBER_STRING(RT_MANIFEST);
  580. const WCHAR PoundRtMessageTable[] = DEFINE_POUND_NUMBER_STRING(RT_MESSAGETABLE);
  581. BuiltinResourceId_t BuiltinResourceIds[] =
  582. {
  583. #define X(x) {L## #x, reinterpret_cast<ULONG_PTR>(x) /*, DEFINE_POUND_NUMBER_STRING(x) */ },
  584. X(CREATEPROCESS_MANIFEST_RESOURCE_ID)
  585. X(ISOLATIONAWARE_MANIFEST_RESOURCE_ID)
  586. X(ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID)
  587. X(MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID)
  588. X(MINIMUM_RESERVED_MANIFEST_RESOURCE_ID)
  589. X(RT_ACCELERATOR)
  590. X(RT_ANICURSOR)
  591. X(RT_ANIICON)
  592. X(RT_BITMAP)
  593. X(RT_CURSOR)
  594. X(RT_DIALOG)
  595. X(RT_DLGINCLUDE)
  596. X(RT_FONT)
  597. X(RT_FONTDIR)
  598. X(RT_GROUP_CURSOR)
  599. X(RT_GROUP_ICON)
  600. #if defined(RT_HTML)
  601. X(RT_HTML)
  602. #endif
  603. X(RT_ICON)
  604. X(RT_MANIFEST)
  605. X(RT_MENU)
  606. X(RT_MESSAGETABLE)
  607. X(RT_PLUGPLAY)
  608. X(RT_RCDATA)
  609. X(RT_STRING)
  610. X(RT_VERSION)
  611. X(RT_VXD)
  612. #undef X
  613. };
  614. String_t NormalizeResourceId(PCWSTR id)
  615. {
  616. if (IS_INTRESOURCE(id))
  617. return NumberToResourceId(static_cast<ULONG>(reinterpret_cast<ULONG_PTR>(id)));
  618. else
  619. return NormalizeResourceId(String_t(id));
  620. }
  621. String_t NormalizeResourceId(const String_t& id)
  622. {
  623. //
  624. // This code should be aware of leading "!" as well.
  625. //
  626. // RT_MANIFEST => #24
  627. // 24 => #24
  628. if (id.Length() == 0)
  629. return id;
  630. if (id[0] == '#')
  631. return id;
  632. if (iswdigit(id[0]))
  633. return L"#" + id;
  634. //
  635. // We should support stuff like JPN, en-us, etc.
  636. //
  637. BuiltinResourceId_t* a = BinarySearch(BuiltinResourceIds, BuiltinResourceIds + NUMBER_OF(BuiltinResourceIds), id);
  638. if (a != BuiltinResourceIds + NUMBER_OF(BuiltinResourceIds))
  639. {
  640. return NumberToResourceId(static_cast<ULONG>(a->Number));
  641. }
  642. return id;
  643. }
  644. void __cdecl Error(const wchar_t* s, ...)
  645. {
  646. printf("%ls\n", s);
  647. exit(EXIT_FAILURE);
  648. }
  649. void SplitResourceTupleString(const String_t& s, std::set<ResourceIdTuple_t>& ResourceTuples)
  650. {
  651. //
  652. // semicolon delimited list of dotted triples
  653. // wildcards are allowed, * only
  654. // missing elements are assumed be *
  655. //
  656. // RT_* are known (RT_MANIFEST, etc.)
  657. //
  658. std::vector<String_t> ResourceTuplesInStringContainer;
  659. std::vector<String_t> OneResourceTupleInStringVector;
  660. ResourceIdTuple_t ResourceIdTuple;
  661. OneResourceTupleInStringVector.resize(3);
  662. SplitString(s, String_t(L";"), ResourceTuplesInStringContainer);
  663. for (std::vector<String_t>::const_iterator Iterator = ResourceTuplesInStringContainer.begin();
  664. Iterator != ResourceTuplesInStringContainer.end();
  665. ++Iterator
  666. )
  667. {
  668. OneResourceTupleInStringVector.resize(0);
  669. SplitString(*Iterator, String_t(L"."), OneResourceTupleInStringVector);
  670. switch (OneResourceTupleInStringVector.size())
  671. {
  672. default:
  673. Error((String_t(L"bad query string '") + s + L"' bad.").c_str());
  674. case 1:
  675. OneResourceTupleInStringVector.push_back(L"*");
  676. // FALLTHROUGH
  677. case 2:
  678. OneResourceTupleInStringVector.push_back(L"*");
  679. // FALLTHROUGH
  680. case 3:
  681. break;
  682. }
  683. ResourceIdTuple.Type = NormalizeResourceId(OneResourceTupleInStringVector[0]);
  684. ResourceIdTuple.Name = NormalizeResourceId(OneResourceTupleInStringVector[1]);
  685. ResourceIdTuple.Language = NormalizeResourceId(OneResourceTupleInStringVector[2]);
  686. ResourceTuples.insert(ResourceTuples.end(), ResourceIdTuple);
  687. }
  688. }
  689. //
  690. // This class is important.
  691. // It does the three level nested Enum/callback pattern that is required
  692. // to enumerate all the resources in a .dll.
  693. //
  694. // By default, it requires all the tripls, as well as the size and address
  695. // of the resource, but you can alter this by overriding the virtual functions.
  696. //
  697. class EnumResources_t
  698. {
  699. typedef EnumResources_t This_t;
  700. public:
  701. virtual ~EnumResources_t() { }
  702. EnumResources_t() { }
  703. static BOOL CALLBACK StaticTypeCallback(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam)
  704. {
  705. return reinterpret_cast<This_t*>(lParam)->TypeCallback(hModule, lpType) ? TRUE : FALSE;
  706. }
  707. static BOOL CALLBACK StaticNameCallback(HMODULE hModule, PCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
  708. {
  709. return reinterpret_cast<This_t*>(lParam)->NameCallback(hModule, lpType, lpName) ? TRUE : FALSE;
  710. }
  711. static BOOL CALLBACK StaticLanguageCallback(HMODULE hModule, PCWSTR lpType, PCWSTR lpName, WORD wLanguage, LONG_PTR lParam)
  712. {
  713. return reinterpret_cast<This_t*>(lParam)->LanguageCallback(hModule, lpType, lpName, wLanguage) ? TRUE : FALSE;
  714. }
  715. virtual bool TypeCallback(HMODULE hModule, PCWSTR lpType)
  716. {
  717. if (EnumResourceNamesW(hModule, lpType, &This_t::StaticNameCallback, reinterpret_cast<LONG_PTR>(this)))
  718. return true;
  719. //if (GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)
  720. //return true;
  721. return false;
  722. }
  723. virtual bool NameCallback(HMODULE hModule, PCWSTR lpType, PCWSTR lpName)
  724. {
  725. if (EnumResourceLanguagesW(hModule, lpType, lpName, &This_t::StaticLanguageCallback, reinterpret_cast<LONG_PTR>(this)))
  726. return true;
  727. //if (GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)
  728. //return true;
  729. return false;
  730. }
  731. virtual bool LanguageCallback(HMODULE Module, PCWSTR lpType, PCWSTR lpName, WORD wLanguage)
  732. {
  733. Resource_t Resource;
  734. Resource.IdTuple.Type = lpType;
  735. Resource.IdTuple.Name = lpName;
  736. Resource.IdTuple.Language = NumberToResourceId(wLanguage);
  737. HRSRC ResourceHandle = FindResourceExW(Module, lpType, lpName, wLanguage);
  738. if (ResourceHandle == NULL)
  739. return false;
  740. HGLOBAL GlobalHandle = LoadResource(Module, ResourceHandle);
  741. if (GlobalHandle == NULL)
  742. return false;
  743. Resource.Address = LockResource(GlobalHandle);
  744. if (Resource.Address == 0)
  745. return false;
  746. Resource.Size = SizeofResource(Module, ResourceHandle);
  747. this->Resources.insert(Resources.end(), Resource);
  748. return true;
  749. }
  750. std::set<Resource_t> Resources;
  751. bool operator()(HMODULE DllHandle)
  752. {
  753. bool Result = EnumResourceTypesW(DllHandle, &This_t::StaticTypeCallback, reinterpret_cast<LONG_PTR>(this)) ? true : false;
  754. //std::sort(Resources.begin(), Resources.end(), std::ptr_fun(&LessThanByIdTuple));
  755. return Result;
  756. }
  757. };
  758. //#define OPEN_RESOURCE_FILE_MAKE_TEMP (0x00000001)
  759. bool ResourceTool_t::OpenResourceFile(ULONG Flags, DDynamicLinkLibrary& dll, String_t Path)
  760. {
  761. __int64 FileSize = 0;
  762. Path = PrependDotSlashToRelativePath(Path);
  763. //
  764. // skip empty files to avoid STATUS_MAPPED_FILE_SIZE_ZERO -> ERROR_FILE_INVALID,
  765. //
  766. if (!GetFileSize(Path, FileSize))
  767. {
  768. String_t ErrorString = GetLastErrorString();
  769. printf("%ls : WARNING: %ls skipped : Error %ls\n", Argv0base_cstr, Path.c_str(), ErrorString.c_str());
  770. return false;
  771. }
  772. if (FileSize == 0)
  773. {
  774. printf("%ls : WARNING: empty file %ls skipped\n", Argv0base_cstr, Path.c_str());
  775. return false;
  776. }
  777. if (!dll.Win32Create(Path, LOAD_LIBRARY_AS_DATAFILE))
  778. {
  779. DWORD Error = GetLastError();
  780. String_t ErrorString = GetLastErrorString();
  781. switch (Error)
  782. {
  783. case ERROR_BAD_EXE_FORMAT: // 16bit or not an .exe/.dll at all
  784. break;
  785. case ERROR_ACCESS_DENIED: // could be directory (should support sd ... syntax)
  786. {
  787. DWORD fileAttributes = GetFileAttributesW(Path);
  788. if (fileAttributes != INVALID_FILE_ATTRIBUTES && (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  789. break;
  790. }
  791. // FALLTHROUGH
  792. default:
  793. printf("%ls : WARNING: %ls skipped, Error %ls\n", Argv0base_cstr, Path.c_str(), ErrorString.c_str());
  794. break;
  795. }
  796. return false;
  797. }
  798. return true;
  799. }
  800. void ResourceTool_t::Query()
  801. {
  802. ChangeEmptyQueryToAllQuery();
  803. for (Files_t::iterator File = Files.begin() ; File != Files.end() ; ++File)
  804. {
  805. DDynamicLinkLibrary dll;
  806. if (!OpenResourceFile(0, dll, *File))
  807. continue;
  808. EnumResources_t EnumResources;
  809. EnumResources(dll);
  810. for ( std::set<Resource_t>::iterator EnumIterator = EnumResources.Resources.begin();
  811. EnumIterator != EnumResources.Resources.end();
  812. ++EnumIterator
  813. )
  814. {
  815. for ( Tuples_t::iterator QueryIterator = Tuples.begin();
  816. QueryIterator != Tuples.end();
  817. ++QueryIterator
  818. )
  819. {
  820. if (Match(*EnumIterator, *QueryIterator))
  821. {
  822. printf("%ls: %ls: %ls.%ls.%ls\n",
  823. Argv0base_cstr,
  824. File->c_str(),
  825. static_cast<PCWSTR>(EnumIterator->IdTuple.Type),
  826. static_cast<PCWSTR>(EnumIterator->IdTuple.Name),
  827. static_cast<PCWSTR>(EnumIterator->IdTuple.Language)
  828. );
  829. break;
  830. }
  831. }
  832. }
  833. }
  834. }
  835. void ResourceTool_t::DumpMessageTableResource(
  836. const File_t& File,
  837. EnumIterator_t EnumIterator)
  838. {
  839. PMESSAGE_RESOURCE_DATA MessageData = reinterpret_cast<PMESSAGE_RESOURCE_DATA>(EnumIterator->Address);
  840. /*
  841. printf( "%ls: %ls.%ls.%ls.%ls: NumberOfBlocks=0x%lx\n",
  842. Argv0base_cstr,
  843. File.c_str(),
  844. static_cast<PCWSTR>(EnumIterator->IdTuple.Type),
  845. static_cast<PCWSTR>(EnumIterator->IdTuple.Name),
  846. static_cast<PCWSTR>(EnumIterator->IdTuple.Language),
  847. MessageData->NumberOfBlocks
  848. );
  849. */
  850. for ( ULONG ul = 0; ul < MessageData->NumberOfBlocks; ul++ )
  851. {
  852. //
  853. // For each block...
  854. //
  855. /*
  856. printf( "%ls: %ls.%ls.%ls.%ls: Block=0x%lx, LowId=0x%lx - HighId=0x%lx, Offset=0x%lx\n",
  857. Argv0base_cstr,
  858. File.c_str(),
  859. static_cast<PCWSTR>(EnumIterator->IdTuple.Type),
  860. static_cast<PCWSTR>(EnumIterator->IdTuple.Name),
  861. static_cast<PCWSTR>(EnumIterator->IdTuple.Language),
  862. ul,
  863. MessageData->Blocks[ul].LowId,
  864. MessageData->Blocks[ul].HighId,
  865. MessageData->Blocks[ul].OffsetToEntries);
  866. */
  867. PMESSAGE_RESOURCE_ENTRY MessageEntries = (PMESSAGE_RESOURCE_ENTRY)(((PBYTE)EnumIterator->Address) + MessageData->Blocks[ul].OffsetToEntries);
  868. for (
  869. ULONG MessageId = MessageData->Blocks[ul].LowId;
  870. MessageId < MessageData->Blocks[ul].HighId;
  871. MessageId++ )
  872. {
  873. PCWSTR Text = reinterpret_cast<PCWSTR>(MessageEntries->Text);
  874. //int Length = static_cast<int>(::wcslen(Text));
  875. /*
  876. for ( ; Length != 0 && (Text[Length - 1] == '\r' || Text[Length - 1] == '\n' || Text[Length - 1] == ' ' || Text[Length - 1] == '\t' || Text[Length - 1] == 0) ; --Length)
  877. {
  878. }
  879. */
  880. StringW_t String(Text);
  881. for (PWSTR p = String.begin(); p != String.end() ; ++p)
  882. if (iswspace(*p))
  883. //if (*p == '\r' || *p == '\n' || *p == '\t')
  884. *p = ' ';
  885. printf(
  886. //"%ls: %ls.%ls.%ls.%ls: Block=0x%lx, Id=0x%lx Flags=0x%lx, Length=0x%lx : %.*ls\n",
  887. "%ls: %ls.%ls.%ls.%ls.0x%lx : %ls\n",
  888. Argv0base_cstr,
  889. File.c_str(),
  890. static_cast<PCWSTR>(EnumIterator->IdTuple.Type),
  891. static_cast<PCWSTR>(EnumIterator->IdTuple.Name),
  892. static_cast<PCWSTR>(EnumIterator->IdTuple.Language),
  893. //ul,
  894. MessageId,
  895. //MessageEntries->Flags,
  896. //MessageEntries->Length,
  897. //Length,
  898. //Text
  899. static_cast<PCWSTR>(String)
  900. );
  901. MessageEntries = reinterpret_cast<PMESSAGE_RESOURCE_ENTRY>(
  902. reinterpret_cast<PBYTE>(MessageEntries) + MessageEntries->Length);
  903. }
  904. }
  905. }
  906. void ResourceTool_t::DumpStringTableResource(const File_t& File, EnumIterator_t EnumIterator)
  907. {
  908. ULONG ResourceId = StringToNumber(EnumIterator->IdTuple.Name);
  909. ULONG StringId = (ResourceId - 1) << 4;
  910. PCWSTR Data = reinterpret_cast<PCWSTR>(EnumIterator->Address);
  911. ULONG Size = EnumIterator->Size;
  912. for (ULONG i = 0 ; i < 16 && Data < (Data + Size / sizeof(WCHAR)) ; ((++i), (++StringId), (Data += 1 + *Data)))
  913. {
  914. if (*Data != 0)
  915. {
  916. StringW_t String;
  917. String.assign(Data + 1, Data + 1 + *Data);
  918. for (PWSTR p = String.begin(); p != String.end() ; ++p)
  919. if (iswspace(*p))
  920. //if (*p == '\r' || *p == '\n' || *p == '\t')
  921. *p = ' ';
  922. printf(
  923. "%ls: %ls.%ls.%ls.%ls.0x%lx : %ls\n",
  924. Argv0base_cstr,
  925. File.c_str(),
  926. static_cast<PCWSTR>(EnumIterator->IdTuple.Type),
  927. static_cast<PCWSTR>(EnumIterator->IdTuple.Name),
  928. static_cast<PCWSTR>(EnumIterator->IdTuple.Language),
  929. StringId,
  930. String.c_str()
  931. );
  932. }
  933. }
  934. }
  935. void ResourceTool_t::DumpManifestResource(const File_t& File, EnumIterator_t EnumIterator)
  936. {
  937. StringW_t ResourceAsStringW;
  938. std::vector<WCHAR> MultiToWideBuffer;
  939. std::vector<StringW_t> LinesW;
  940. if (!::IsTextUnicode(reinterpret_cast<const void*>(EnumIterator->Address), static_cast<int>(EnumIterator->Size), NULL))
  941. {
  942. MultiToWideBuffer.resize(EnumIterator->Size + 2, 0);
  943. ::MultiByteToWideChar(CP_ACP, 0, reinterpret_cast<PCSTR>(EnumIterator->Address), EnumIterator->Size, &MultiToWideBuffer[0], MultiToWideBuffer.size() - 1);
  944. ResourceAsStringW = &MultiToWideBuffer[0];
  945. }
  946. else
  947. {
  948. ResourceAsStringW.assign(reinterpret_cast<PCWSTR>(EnumIterator->Address), EnumIterator->Size / sizeof(WCHAR));
  949. }
  950. SplitString(ResourceAsStringW, StringW_t(L"\r\n"), LinesW);
  951. for (std::vector<StringW_t>::iterator Line = LinesW.begin(); Line != LinesW.end() ; ++Line)
  952. {
  953. printf("%ls: %ls.%ls.%ls.%ls: %ls\n",
  954. Argv0base_cstr,
  955. File.c_str(),
  956. static_cast<PCWSTR>(EnumIterator->IdTuple.Type),
  957. static_cast<PCWSTR>(EnumIterator->IdTuple.Name),
  958. static_cast<PCWSTR>(EnumIterator->IdTuple.Language),
  959. static_cast<PCWSTR>(*Line)
  960. );
  961. }
  962. }
  963. void ResourceTool_t::DumpBinaryResource(const File_t& File, EnumIterator_t EnumIterator)
  964. {
  965. printf("%ls: %ls.%ls.%ls.%ls\n",
  966. Argv0base_cstr,
  967. File.c_str(),
  968. static_cast<PCWSTR>(EnumIterator->IdTuple.Type),
  969. static_cast<PCWSTR>(EnumIterator->IdTuple.Name),
  970. static_cast<PCWSTR>(EnumIterator->IdTuple.Language)
  971. );
  972. }
  973. void ResourceTool_t::DumpResource(const File_t& File, EnumIterator_t EnumIterator)
  974. {
  975. if (EnumIterator->IdTuple.Type == PoundRtManifest)
  976. DumpManifestResource(File, EnumIterator);
  977. else if (EnumIterator->IdTuple.Type == PoundRtString)
  978. DumpStringTableResource(File, EnumIterator);
  979. else if (EnumIterator->IdTuple.Type == PoundRtMessageTable)
  980. DumpMessageTableResource(File, EnumIterator);
  981. else
  982. DumpBinaryResource(File, EnumIterator);
  983. }
  984. void ResourceTool_t::Dump()
  985. {
  986. ChangeEmptyQueryToAllQuery();
  987. for (Files_t::iterator File = Files.begin() ; File != Files.end() ; ++File)
  988. {
  989. DDynamicLinkLibrary dll;
  990. if (!OpenResourceFile(0, dll, *File))
  991. continue;
  992. EnumResources_t EnumResources;
  993. EnumResources(dll);
  994. for ( std::set<Resource_t>::iterator EnumIterator = EnumResources.Resources.begin();
  995. EnumIterator != EnumResources.Resources.end();
  996. ++EnumIterator
  997. )
  998. {
  999. for ( Tuples_t::iterator QueryIterator = Tuples.begin();
  1000. QueryIterator != Tuples.end();
  1001. ++QueryIterator
  1002. )
  1003. {
  1004. if (Match(*EnumIterator, *QueryIterator))
  1005. {
  1006. DumpResource(*File, EnumIterator);
  1007. break;
  1008. }
  1009. }
  1010. }
  1011. }
  1012. }
  1013. void ResourceTool_t::Delete()
  1014. {
  1015. String_t ErrorString;
  1016. for (Files_t::iterator File = Files.begin() ; File != Files.end() ; ++File)
  1017. {
  1018. WCHAR Temp[MAX_PATH * 2];
  1019. Temp[0] = 0;
  1020. {
  1021. DDynamicLinkLibrary dll;
  1022. if (!OpenResourceFile(0, dll, *File))
  1023. continue;
  1024. EnumResources_t EnumResources;
  1025. EnumResources(dll);
  1026. std::set<Resource_t> Delete;
  1027. for ( std::set<Resource_t>::iterator EnumIterator = EnumResources.Resources.begin();
  1028. EnumIterator != EnumResources.Resources.end();
  1029. ++EnumIterator
  1030. )
  1031. {
  1032. for ( Tuples_t::iterator QueryIterator = Tuples.begin();
  1033. QueryIterator != Tuples.end();
  1034. ++QueryIterator
  1035. )
  1036. {
  1037. if (Match(*EnumIterator, *QueryIterator))
  1038. {
  1039. Delete.insert(Delete.end(), *EnumIterator);
  1040. }
  1041. }
  1042. }
  1043. if (Delete.size() != 0)
  1044. {
  1045. std::set<Resource_t> Keep;
  1046. std::set_difference(
  1047. EnumResources.Resources.begin(),
  1048. EnumResources.Resources.end(),
  1049. Delete.begin(),
  1050. Delete.end(),
  1051. std::inserter(Keep, Keep.end())
  1052. );
  1053. union
  1054. {
  1055. UUID Uuid;
  1056. __int64 Int64s[2];
  1057. } u;
  1058. ZeroMemory(&u, sizeof(u));
  1059. typedef RPC_STATUS (RPC_ENTRY * UuidCreateSequential_t)(UUID *Uuid);
  1060. UuidCreateSequential_t UuidCreateSequential = NULL;
  1061. RPC_STATUS RpcStatus = RPC_S_OK;
  1062. HMODULE Rpcrt4Dll = LoadLibraryW(L"Rpcrt4.dll");
  1063. if (Rpcrt4Dll != NULL)
  1064. UuidCreateSequential = reinterpret_cast<UuidCreateSequential_t>(GetProcAddress(Rpcrt4Dll, "UuidCreateSequential"));
  1065. if (UuidCreateSequential != NULL)
  1066. RpcStatus = UuidCreateSequential(&u.Uuid);
  1067. else
  1068. RpcStatus = UuidCreate(&u.Uuid);
  1069. WCHAR Original[MAX_PATH];
  1070. PWSTR FilePart = NULL;
  1071. Original[0] = 0;
  1072. if (!GetFullPathNameW(*File, MAX_PATH, Original, &FilePart))
  1073. {
  1074. ErrorString = GetLastErrorString();
  1075. PrintString((String_t(L"GetFullPathName(") + *File + L") FAILED: " + ErrorString + L"\n").c_str());
  1076. goto NextFile;
  1077. }
  1078. swprintf(Temp, L"%ls.%I64x%I64x", Original, u.Int64s[0], u.Int64s[1]);
  1079. if (!MoveFileW(Original, Temp))
  1080. {
  1081. ErrorString = GetLastErrorString();
  1082. PrintString((String_t(L"MoveFile(") + Original + L", " + Temp + L") FAILED: " + ErrorString + L"\n").c_str());
  1083. goto NextFile;
  1084. }
  1085. if (!CopyFileW(Temp, Original, TRUE))
  1086. {
  1087. ErrorString = GetLastErrorString();
  1088. if (!MoveFileW(Temp, Original))
  1089. {
  1090. String_t ErrorString2 = GetLastErrorString();
  1091. // THIS IS BAD.
  1092. PrintString((String_t(L"ROLLBACK MoveFile(") + Temp + L", " + Original + L") FAILED: " + ErrorString2 + L"\n").c_str());
  1093. goto NextFile;
  1094. }
  1095. PrintString((String_t(L"CopyFile(") + Temp + L", " + Original + L") FAILED: " + ErrorString + L"\n").c_str());
  1096. goto NextFile;
  1097. }
  1098. DResourceUpdateHandle ResourceUpdateHandle;
  1099. if (!ResourceUpdateHandle.Win32Create(*File, TRUE))
  1100. {
  1101. ErrorString = GetLastErrorString();
  1102. PrintString((String_t(Argv0base + L": ResourceUpdateHandle(") + *File + L" FAILED: " + ErrorString + L"\n").c_str());
  1103. break;
  1104. }
  1105. for ( std::set<Resource_t>::iterator KeepIterator = Keep.begin();
  1106. KeepIterator != Keep.end();
  1107. ++KeepIterator
  1108. )
  1109. {
  1110. PCWSTR ResourceType = StringToResourceString(KeepIterator->IdTuple.Type);
  1111. PCWSTR ResourceName = StringToResourceString(KeepIterator->IdTuple.Name);
  1112. if (!ResourceUpdateHandle.UpdateResource(
  1113. ResourceType,
  1114. ResourceName,
  1115. static_cast<WORD>(StringToNumber(KeepIterator->IdTuple.Language)),
  1116. KeepIterator->Address,
  1117. KeepIterator->Size))
  1118. {
  1119. ErrorString = GetLastErrorString();
  1120. PrintString((String_t(Argv0base + L": ResourceUpdateHandle.UpdateResource(") + *File + L" FAILED: " + ErrorString + L"\n").c_str());
  1121. goto NextFile;
  1122. }
  1123. if (Print.Keep)
  1124. printf("%ls: KEEP: %ls.%ls.%ls.%ls\n",
  1125. Argv0base_cstr,
  1126. File->c_str(),
  1127. static_cast<PCWSTR>(KeepIterator->IdTuple.Type),
  1128. static_cast<PCWSTR>(KeepIterator->IdTuple.Name),
  1129. static_cast<PCWSTR>(KeepIterator->IdTuple.Language)
  1130. );
  1131. }
  1132. if (Print.Delete)
  1133. {
  1134. for ( std::set<Resource_t>::iterator DeleteIterator = Delete.begin();
  1135. DeleteIterator != Delete.end();
  1136. ++DeleteIterator
  1137. )
  1138. {
  1139. printf("%ls: DELETE: %ls.%ls.%ls.%ls\n",
  1140. Argv0base_cstr,
  1141. File->c_str(),
  1142. static_cast<PCWSTR>(DeleteIterator->IdTuple.Type),
  1143. static_cast<PCWSTR>(DeleteIterator->IdTuple.Name),
  1144. static_cast<PCWSTR>(DeleteIterator->IdTuple.Language)
  1145. );
  1146. }
  1147. }
  1148. if (!ResourceUpdateHandle.Win32Close(false))
  1149. {
  1150. ErrorString = GetLastErrorString();
  1151. PrintString((String_t(Argv0base + L" : ResourceUpdateHandle.Win32Close(") + *File + L") FAILED: " + ErrorString + L"\n").c_str());
  1152. }
  1153. else
  1154. {
  1155. if (Print.Success)
  1156. PrintString((Argv0base + L" : SUCCESS: " + *File + L"\n").c_str());
  1157. }
  1158. }
  1159. else
  1160. {
  1161. if (Print.Unchanged)
  1162. PrintString((Argv0base + L": UNCHANGED: " + *File + L"\n").c_str());
  1163. }
  1164. } // FreeLibrary, so we can delete the temp
  1165. if (Temp[0] != 0)
  1166. {
  1167. BOOL DeleteSuccess = DeleteFileW(Temp);
  1168. if (!DeleteSuccess)
  1169. {
  1170. if (GetLastError() == ERROR_ACCESS_DENIED)
  1171. {
  1172. Sleep(100);
  1173. DeleteSuccess = DeleteFileW(Temp);
  1174. }
  1175. }
  1176. if (!DeleteSuccess)
  1177. {
  1178. ErrorString = GetLastErrorString();
  1179. PrintString(((Argv0base + L" : WARNING: DeleteFile(") + Temp + L") FAILED: " + ErrorString + L"\n").c_str());
  1180. if (!MoveFileExW(Temp, NULL, MOVEFILE_DELAY_UNTIL_REBOOT))
  1181. {
  1182. ErrorString = GetLastErrorString();
  1183. PrintString((Argv0base + L" : WARNING: MoveFileExW(" + Temp + L") FAILED: " + ErrorString + L"\n").c_str());
  1184. }
  1185. }
  1186. }
  1187. NextFile:
  1188. ;
  1189. }
  1190. }
  1191. void ResourceTool_t::FindAndDeleteDuplicates()
  1192. {
  1193. if (this->Files.size() != 2)
  1194. {
  1195. printf("%ls : ERROR : Usage...\n", Argv0base_cstr);
  1196. return;
  1197. }
  1198. this->ShouldPrint = false;
  1199. this->FindDuplicates();
  1200. File_t File = this->Files[1];
  1201. this->Files.clear();
  1202. this->Files.push_back(File);
  1203. this->ShouldPrint = true;
  1204. this->Delete();
  1205. }
  1206. void ResourceTool_t::ChangeEmptyQueryToAllQuery()
  1207. {
  1208. if (Tuples.size() == 0)
  1209. {
  1210. ResourceIdTuple_t Tuple;
  1211. Tuple.Language = L"*";
  1212. Tuple.Name = L"*";
  1213. Tuple.Type = L"*";
  1214. Tuples.insert(Tuples.end(), Tuple);
  1215. }
  1216. }
  1217. void ResourceTool_t::FindDuplicates()
  1218. {
  1219. if (Files.size() != 2)
  1220. {
  1221. printf("%ls : ERROR : Usage...\n", Argv0base_cstr);
  1222. return;
  1223. }
  1224. EnumResources_t EnumResources[2];
  1225. DDynamicLinkLibrary dll[2];
  1226. if (!OpenResourceFile(0, dll[0], Files[0]))
  1227. {
  1228. return;
  1229. }
  1230. if (!OpenResourceFile(0, dll[1], Files[1]))
  1231. {
  1232. return;
  1233. }
  1234. EnumResources[0](dll[0]);
  1235. EnumResources[1](dll[1]);
  1236. std::set<Resource_t> Matched[2];
  1237. std::set<Resource_t>::const_iterator Iterators[2];
  1238. Tuples_t DeleteTuples;
  1239. ChangeEmptyQueryToAllQuery();
  1240. Tuples_t::iterator QueryIterator;
  1241. for (QueryIterator = Tuples.begin(); QueryIterator != Tuples.end(); ++QueryIterator)
  1242. {
  1243. for (Iterators[0] = EnumResources[0].Resources.begin() ; Iterators[0] != EnumResources[0].Resources.end() ; ++Iterators[0] )
  1244. {
  1245. if (Match(*Iterators[0], *QueryIterator))
  1246. {
  1247. Matched[0].insert(Matched[0].end(), *Iterators[0]);
  1248. }
  1249. }
  1250. for (Iterators[1] = EnumResources[1].Resources.begin() ; Iterators[1] != EnumResources[1].Resources.end() ; ++Iterators[1] )
  1251. {
  1252. if (Match(*Iterators[1], *QueryIterator))
  1253. {
  1254. Matched[1].insert(Matched[1].end(), *Iterators[1]);
  1255. }
  1256. }
  1257. }
  1258. std::set<Resource_t> Only[2]; // leftonly, rightonly
  1259. Only[0] = Matched[0];
  1260. Only[1] = Matched[1];
  1261. for (QueryIterator = Tuples.begin(); QueryIterator != Tuples.end(); ++QueryIterator)
  1262. {
  1263. for (Iterators[0] = Matched[0].begin() ; Iterators[0] != Matched[0].end() ; ++Iterators[0])
  1264. {
  1265. for (Iterators[1] = Matched[1].begin(); Iterators[1] != Matched[1].end(); ++Iterators[1])
  1266. {
  1267. if (
  1268. Iterators[0]->IdTuple.Type == Iterators[1]->IdTuple.Type // hack
  1269. && Iterators[0]->IdTuple.Name == Iterators[1]->IdTuple.Name // hack
  1270. && Match(*Iterators[1], *QueryIterator) // kind of hacky..we don't query iterator[0]
  1271. )
  1272. {
  1273. Only[0].erase(*Iterators[0]);
  1274. Only[1].erase(*Iterators[1]);
  1275. if (Iterators[0]->Size != Iterators[1]->Size)
  1276. {
  1277. if (ShouldPrint
  1278. && Print.UnequalSize
  1279. )
  1280. printf("%ls : UNEQUAL_SIZE : %ls.%ls.%ls.%ls, %ls.%ls.%ls.%ls\n",
  1281. Argv0base_cstr,
  1282. static_cast<PCWSTR>(Files[0]),
  1283. static_cast<PCWSTR>(Iterators[0]->IdTuple.Type),
  1284. static_cast<PCWSTR>(Iterators[0]->IdTuple.Name),
  1285. static_cast<PCWSTR>(Iterators[0]->IdTuple.Language),
  1286. static_cast<PCWSTR>(Files[1]),
  1287. static_cast<PCWSTR>(Iterators[1]->IdTuple.Type),
  1288. static_cast<PCWSTR>(Iterators[1]->IdTuple.Name),
  1289. static_cast<PCWSTR>(Iterators[1]->IdTuple.Language)
  1290. );
  1291. //UnequalSize.insert(UnequalSize.end(), Iterators[1]->IdTuple);
  1292. }
  1293. else if (memcmp(Iterators[0]->Address, Iterators[1]->Address, Iterators[0]->Size) == 0)
  1294. {
  1295. if (ShouldPrint
  1296. && Print.Equal)
  1297. printf("%ls : EQUAL : %ls.%ls.%ls.%ls, %ls.%ls.%ls.%ls\n",
  1298. Argv0base_cstr,
  1299. static_cast<PCWSTR>(Files[0]),
  1300. static_cast<PCWSTR>(Iterators[0]->IdTuple.Type),
  1301. static_cast<PCWSTR>(Iterators[0]->IdTuple.Name),
  1302. static_cast<PCWSTR>(Iterators[0]->IdTuple.Language),
  1303. static_cast<PCWSTR>(Files[1]),
  1304. static_cast<PCWSTR>(Iterators[1]->IdTuple.Type),
  1305. static_cast<PCWSTR>(Iterators[1]->IdTuple.Name),
  1306. static_cast<PCWSTR>(Iterators[1]->IdTuple.Language)
  1307. );
  1308. DeleteTuples.insert(DeleteTuples.end(), Iterators[1]->IdTuple);
  1309. }
  1310. else
  1311. {
  1312. if (ShouldPrint
  1313. && Print.UnequalContents)
  1314. printf("%ls : UNEQUAL_CONTENTS : %ls.%ls.%ls.%ls, %ls.%ls.%ls.%ls\n",
  1315. Argv0base_cstr,
  1316. static_cast<PCWSTR>(Files[0]),
  1317. static_cast<PCWSTR>(Iterators[0]->IdTuple.Type),
  1318. static_cast<PCWSTR>(Iterators[0]->IdTuple.Name),
  1319. static_cast<PCWSTR>(Iterators[0]->IdTuple.Language),
  1320. static_cast<PCWSTR>(Files[1]),
  1321. static_cast<PCWSTR>(Iterators[1]->IdTuple.Type),
  1322. static_cast<PCWSTR>(Iterators[1]->IdTuple.Name),
  1323. static_cast<PCWSTR>(Iterators[1]->IdTuple.Language)
  1324. );
  1325. //UnequalContents.insert(UnequalSize.end(), Iterators[1]->IdTuple);
  1326. }
  1327. }
  1328. }
  1329. }
  1330. }
  1331. if (ShouldPrint && Print.LeftOnly)
  1332. {
  1333. for (Iterators[0] = Only[0].begin() ; Iterators[0] != Only[0].end() ; ++Iterators[0])
  1334. {
  1335. printf("%ls : LEFT_ONLY : %ls.%ls.%ls.%ls, %ls.%ls.%ls.%ls\n",
  1336. Argv0base_cstr,
  1337. static_cast<PCWSTR>(Files[0]),
  1338. static_cast<PCWSTR>(Iterators[0]->IdTuple.Type),
  1339. static_cast<PCWSTR>(Iterators[0]->IdTuple.Name),
  1340. static_cast<PCWSTR>(Iterators[0]->IdTuple.Language),
  1341. static_cast<PCWSTR>(Files[1]),
  1342. static_cast<PCWSTR>(Iterators[0]->IdTuple.Type),
  1343. static_cast<PCWSTR>(Iterators[0]->IdTuple.Name),
  1344. static_cast<PCWSTR>(Iterators[0]->IdTuple.Language)
  1345. );
  1346. }
  1347. }
  1348. if (ShouldPrint && Print.RightOnly)
  1349. {
  1350. for (Iterators[1] = Only[1].begin() ; Iterators[1] != Only[1].end() ; ++Iterators[1])
  1351. {
  1352. printf("%ls : RIGHT_ONLY : %ls.%ls.%ls.%ls, %ls.%ls.%ls.%ls\n",
  1353. Argv0base_cstr,
  1354. static_cast<PCWSTR>(Files[0]),
  1355. static_cast<PCWSTR>(Iterators[1]->IdTuple.Type),
  1356. static_cast<PCWSTR>(Iterators[1]->IdTuple.Name),
  1357. static_cast<PCWSTR>(Iterators[1]->IdTuple.Language),
  1358. static_cast<PCWSTR>(Files[1]),
  1359. static_cast<PCWSTR>(Iterators[1]->IdTuple.Type),
  1360. static_cast<PCWSTR>(Iterators[1]->IdTuple.Name),
  1361. static_cast<PCWSTR>(Iterators[1]->IdTuple.Language)
  1362. );
  1363. }
  1364. }
  1365. Tuples = DeleteTuples;
  1366. }
  1367. int ResourceTool_t::Main(const StringVector_t& args)
  1368. {
  1369. StringVectorConstIterator_t i;
  1370. Operation_t Operation = NULL;
  1371. for (i = args.begin() ; i != args.end() ; ++i)
  1372. {
  1373. String_t s;
  1374. String_t t;
  1375. bool PrintAll = false;
  1376. bool PrintNone = false;
  1377. bool PrintValue = true;
  1378. bool PrintUnequal = false;
  1379. s = *i;
  1380. s = RemoveOptionChar(s);
  1381. if (s == L"Sxid12Tool1")
  1382. {
  1383. StringVector_t restArgs(i + 1, args.end());
  1384. return Sxid12Tool1(restArgs);
  1385. }
  1386. else if (GetFileAttributesW(s) != 0xFFFFFFFF)
  1387. {
  1388. goto FileLabel;
  1389. }
  1390. else if (s.Starts(t = L"Query"))
  1391. Operation = &This_t::Query;
  1392. else if (s.Starts(t = L"FindDuplicates"))
  1393. Operation = &This_t::FindDuplicates;
  1394. else if (s.Starts(t = L"Explode"))
  1395. Operation = &This_t::Explode;
  1396. else if (s.Starts(t = L"Diff"))
  1397. {
  1398. Operation = &This_t::FindDuplicates;
  1399. Print.LeftOnly = true;
  1400. Print.RightOnly = true;
  1401. Print.Equal = true;
  1402. Print.UnequalContents = true;
  1403. Print.UnequalSize = true;
  1404. }
  1405. else if (s.Starts(t = L"Delete"))
  1406. Operation = &This_t::Delete;
  1407. else if (s.Starts(t = L"Dump"))
  1408. Operation = &This_t::Dump;
  1409. else if (s.Starts(t = L"FindAndDeleteDuplicates"))
  1410. Operation = &This_t::FindAndDeleteDuplicates;
  1411. else if (s.Starts(t = L"NoPrint"))
  1412. {
  1413. PrintValue = !PrintValue;
  1414. goto PrintCommonLabel;
  1415. }
  1416. else if (s.Starts(t = L"Print"))
  1417. {
  1418. PrintCommonLabel:
  1419. s = RemoveOptionChar(s.substr(t.Length()));
  1420. bool* Member = NULL;
  1421. if (s == (t = L"UnequalSize"))
  1422. Member = &this->Print.UnequalSize;
  1423. else if (s == (t = L"UnequalContents"))
  1424. Member = &this->Print.UnequalContents;
  1425. else if (s == (t = L"UnequalSize"))
  1426. Member = &this->Print.UnequalSize;
  1427. else if (s == (t = L"Keep"))
  1428. Member = &this->Print.Keep;
  1429. else if (s == (t = L"Delete"))
  1430. Member = &this->Print.Delete;
  1431. else if (s == (t = L"Success"))
  1432. Member = &this->Print.Success;
  1433. else if (s == (t = L"Unchanged"))
  1434. Member = &this->Print.Unchanged;
  1435. else if (s == (t = L"Equal"))
  1436. Member = &this->Print.Equal;
  1437. else if (s == (t = L"LeftOnly"))
  1438. Member = &this->Print.LeftOnly;
  1439. else if (s == (t = L"RightOnly"))
  1440. Member = &this->Print.RightOnly;
  1441. else if (s == L"All")
  1442. {
  1443. PrintAll = true;
  1444. Print.SetAll(true);
  1445. }
  1446. else if (s == L"None")
  1447. {
  1448. PrintNone = true;
  1449. Print.SetAll(false);
  1450. }
  1451. else if (s == L"Unequal")
  1452. {
  1453. PrintUnequal = true;
  1454. this->Print.UnequalContents = true;
  1455. this->Print.UnequalSize = true;
  1456. }
  1457. if (PrintAll || PrintNone || PrintUnequal)
  1458. {
  1459. // nothing
  1460. }
  1461. else if (Member == NULL)
  1462. {
  1463. printf("%ls : WARNING: unknown print option \"%ls\" ignored\n", Argv0base_cstr, static_cast<PCWSTR>(s));
  1464. continue;
  1465. }
  1466. else
  1467. {
  1468. bool knownValue = true;
  1469. s = RemoveOptionChar(s.substr(t.Length()));
  1470. if (s != L"")
  1471. {
  1472. //
  1473. // This doesn't work because of the equality comparisons above. They need
  1474. // ignore whatever follows the colon.
  1475. //
  1476. if (s == L"No" || s == L"False")
  1477. PrintValue = !PrintValue;
  1478. else if (s == L"Yes" || s == L"True")
  1479. {
  1480. /* nothing */
  1481. }
  1482. else
  1483. {
  1484. knownValue = false;
  1485. printf("%ls : WARNING: unknown print option \"%ls\" ignored\n", Argv0base_cstr, static_cast<PCWSTR>(s));
  1486. continue;
  1487. }
  1488. }
  1489. if (knownValue)
  1490. *Member = PrintValue;
  1491. }
  1492. continue;
  1493. }
  1494. else if (s.Starts(t = L"File"))
  1495. {
  1496. FileLabel:
  1497. s = RemoveOptionChar(s.substr(t.Length()));
  1498. Files.push_back(s);
  1499. continue;
  1500. }
  1501. else
  1502. {
  1503. Files.push_back(s);
  1504. continue;
  1505. }
  1506. s = RemoveOptionChar(s.substr(t.Length()));
  1507. SplitResourceTupleString(s, Tuples);
  1508. }
  1509. //std::sort(Tuples.begin(), Tuples.end());
  1510. if (Operation == NULL)
  1511. {
  1512. printf("Usage...\n");
  1513. return EXIT_FAILURE;
  1514. }
  1515. (this->*Operation)();
  1516. return EXIT_SUCCESS;
  1517. }
  1518. extern "C"
  1519. {
  1520. //void __cdecl mainCRTStartup(void);
  1521. void __cdecl wmainCRTStartup(void);
  1522. }
  1523. int __cdecl main(int argc, char** argv)
  1524. {
  1525. wmainCRTStartup();
  1526. return 0;
  1527. }
  1528. extern "C" int __cdecl wmain(int argc, wchar_t** argv)
  1529. {
  1530. ResourceTool_t rtool;
  1531. StringVector_t args;
  1532. args.reserve(argc);
  1533. rtool.Argv0 = argv[0];
  1534. String_t::size_type p = rtool.Argv0.find_last_of(L"\\/");
  1535. if (p != rtool.Argv0.npos)
  1536. rtool.Argv0base = rtool.Argv0.substr(1 + p);
  1537. else
  1538. rtool.Argv0base = rtool.Argv0;
  1539. p = rtool.Argv0base.find_last_of(L".");
  1540. if (p != rtool.Argv0base.npos)
  1541. rtool.Argv0base = rtool.Argv0base.substr(0, p);
  1542. rtool.Argv0base_cstr = rtool.Argv0base.c_str();
  1543. std::copy(argv + 1, argv + argc, std::back_inserter(args));
  1544. int ret = rtool.Main(args);
  1545. return ret;
  1546. }