Source code of Windows XP (NT5)
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.

1605 lines
53 KiB

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