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.

1240 lines
36 KiB

  1. /*****************************************************************************
  2. Copyright (c) 2001, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. muirct.cpp
  5. Abstract:
  6. The main funtion of muirct program
  7. Revision History:
  8. 2001-10-01 sunggch created.
  9. Revision.
  10. *******************************************************************************/
  11. #include "muirct.h"
  12. #include "res.h"
  13. //#include "resource.h"
  14. #include "cmf.h"
  15. #define MAX_NUM_RESOURCE_TYPES 40
  16. #define LANG_CHECKSUM_DEFAULT 0x409
  17. BOOL GetFileNames(CMuiCmdInfo* pcmci, LPTSTR * pszSource, LPTSTR * pszNewFile, LPTSTR * pszMuiFile )
  18. /*++
  19. Abstract:
  20. Get the file names from the CMuiCmdInfo.
  21. Arguments:
  22. pcmci - CMuiCmdInof object; has values of these files..
  23. pszSource - destination of source file
  24. pszNewFile - destination of new dll, which is same with source file without selected resource
  25. pszMuiRes - destination of new mui file.
  26. Return:
  27. TRUE/FALSE
  28. --*/
  29. {
  30. DWORD dwCount = 0;
  31. LPTSTR *ppsz = NULL;
  32. if ( pcmci == NULL || pszSource == NULL || pszNewFile == NULL || pszMuiFile == NULL)
  33. return FALSE;
  34. ppsz = pcmci ->GetValueLists (_T("source"),dwCount );
  35. if ( ! ppsz ) {
  36. return FALSE;
  37. }
  38. *pszSource = *ppsz;
  39. ppsz = pcmci ->GetValueLists (_T("muidll"), dwCount );
  40. if ( ! ppsz ) {
  41. return FALSE;
  42. }
  43. *pszNewFile = *ppsz;
  44. ppsz = pcmci ->GetValueLists (_T("muires"), dwCount );
  45. if ( ! ppsz ) {
  46. return FALSE;
  47. }
  48. *pszMuiFile = *ppsz;
  49. return TRUE;
  50. }
  51. BOOL FilterRemRes ( cvcstring * cvRemovedResTypes, LPTSTR * ppRemoveRes, const UINT dwRemoveCount, BOOL fSanityCheck )
  52. /*++
  53. Abstract:
  54. Compare the resource types between cvRemovedResTypes and ppRemoveRes, and leave the ppRemoveRes values in the
  55. cvRemovedResTypes
  56. Arguments:
  57. cvRemovedResTypes - contains a resources types, which will be trimmed by ppRemoveRes
  58. ppRemoveRes - new resource types
  59. dwRemoveCount - number of count in ppRemoveRes
  60. Return:
  61. true/false
  62. --*/
  63. {
  64. DWORD dwCountofSameTypes =0;
  65. cvcstring * cvRemovedResTypesTemp = NULL;
  66. if ( cvRemovedResTypes == NULL || ppRemoveRes == NULL)
  67. return FALSE;
  68. cvRemovedResTypesTemp = new cvcstring(MAX_NUM_RESOURCE_TYPES);
  69. if (!cvRemovedResTypesTemp)
  70. return FALSE;
  71. for (UINT i = 0; i < cvRemovedResTypes -> Size() ; i ++ ) {
  72. BOOL fIsResourceSame = FALSE ;
  73. LPCTSTR lpResourceTypeInFile = cvRemovedResTypes->GetValue(i);
  74. for (UINT j = 0; j < dwRemoveCount; j ++ ) {
  75. if ( 0xFFFF0000 & PtrToUlong(lpResourceTypeInFile ) ) { // strings
  76. if (! _tcsicmp(ppRemoveRes[j],lpResourceTypeInFile ) ) {
  77. fIsResourceSame = TRUE; // remove resours has value
  78. break;
  79. }
  80. }
  81. else {
  82. if (! ( _tcstod (ppRemoveRes[j],NULL ) - (DWORD)PtrToUlong(lpResourceTypeInFile) ) ) {
  83. fIsResourceSame = TRUE; // remove resource has value
  84. break;
  85. }
  86. }
  87. }
  88. if (fIsResourceSame) {
  89. // we need to keep the order of resource types in cvRemovedResTypes because it affects
  90. // checksum
  91. cvRemovedResTypesTemp -> Push_back(cvRemovedResTypes -> GetValue (i) );
  92. dwCountofSameTypes++;
  93. }
  94. }
  95. if (fSanityCheck && (dwCountofSameTypes < dwRemoveCount) )
  96. {
  97. _tprintf(_T(" One of resource types isn't contained target source files\n"));
  98. _tprintf(_T(" You can avoid type check when you use -o argument\n"));
  99. _tprintf(_T(" Standard Resource Types: CURSOR(1) BITMAP(2) ICON(3) MENU(4) DIALOG(5)\n") );
  100. _tprintf(_T(" STRING(6) FONTDIR(7) FONT(8) ACCELERATORS(9) RCDATA(10) MESSAGETABLE(11)\n") );
  101. _tprintf(_T(" GROUP_CURSOR(12) GROUP_ICON(14) VERSION(16)\n") );
  102. delete cvRemovedResTypesTemp;
  103. return FALSE;
  104. }
  105. cvRemovedResTypes -> Clear();
  106. for ( i = 0; i < cvRemovedResTypesTemp ->Size(); i ++ )
  107. {
  108. cvRemovedResTypes ->Push_back ( cvRemovedResTypesTemp ->GetValue( i ) );
  109. }
  110. delete cvRemovedResTypesTemp;
  111. return TRUE;
  112. }
  113. cvcstring * FilterKeepRes ( cvcstring * cvRemovedResTypes, LPTSTR * ppKeepRes, cvcstring * cvKeepResTypes, UINT dwKeepCount, BOOL fSanityCheck )
  114. /*++
  115. Abstract:
  116. Fill cvKeepResTypes(cvcstring type) and check values existence inside cvRemovedResTypes(removed resource types) then
  117. return error when fSanityCheck is true.
  118. Arguments:
  119. cvRemovedResTypes - contains a resources types, which will be trimmed by ppRemoveRes
  120. ppKeepRes - new resource types
  121. dwRemoveCount - number of count in ppRemoveRes
  122. cvKeepResTypes - filtered resource types will be saved.
  123. fSanityCheck - do sanity check if it is true.
  124. Return:
  125. cvcstring, which include resource that should be removed.
  126. --*/
  127. {
  128. cvcstring * cvRemovedResTypesTemp = NULL;
  129. if ( cvRemovedResTypes == NULL || ppKeepRes == NULL || cvKeepResTypes == NULL)
  130. return FALSE;
  131. cvRemovedResTypesTemp = new cvcstring(MAX_NUM_RESOURCE_TYPES);
  132. BOOL fRet;
  133. //
  134. // this is just checking if value of -k is included in the -i value.
  135. //
  136. if (fSanityCheck) {
  137. for ( UINT i = 0; i < dwKeepCount; i ++ ) {
  138. fRet = TRUE ;
  139. for (UINT j = 0; j < cvRemovedResTypes -> Size(); j ++ ) {
  140. LPCTSTR lpResourceTypeInFile = cvRemovedResTypes->GetValue(j);
  141. if ( 0xFFFF0000 & PtrToUlong(lpResourceTypeInFile ) ) { // strings
  142. if (! _tcsicmp(ppKeepRes[i],lpResourceTypeInFile ) ) {
  143. fRet = FALSE; // remove resource has value
  144. break;
  145. }
  146. }
  147. else {
  148. if (! ( _tcstoul (ppKeepRes[i],NULL,10 ) - (DWORD)PtrToUlong(lpResourceTypeInFile ) ) ) {
  149. fRet = FALSE; // remove resours has value
  150. break;
  151. }
  152. }
  153. }
  154. if ( fRet ) {
  155. _tprintf(_T(" Resource Type %s does not exist in the -i value or file, \n "), ppKeepRes[i] );
  156. _tprintf(_T("You can't use this value for -k argument") );
  157. return NULL;
  158. };
  159. }
  160. }
  161. //
  162. // Delete -k argument value from -i value lists
  163. //
  164. for ( UINT i = 0; i < cvRemovedResTypes->Size(); i ++ ) {
  165. fRet = TRUE;
  166. LPCTSTR lpResourceTypeInFile = cvRemovedResTypes->GetValue(i);
  167. for ( UINT j = 0; j < dwKeepCount; j ++ ) {
  168. if ( 0xFFFF0000 & PtrToUlong(lpResourceTypeInFile ) ) { // REVISIT for Win64 . e.g. xxxxxxxx000000000
  169. if (! _tcsicmp(ppKeepRes[j],lpResourceTypeInFile ) ) {
  170. fRet = FALSE; // remove resource has value
  171. break;
  172. }
  173. }
  174. else {
  175. if (! ( _tcstoul(ppKeepRes[j],NULL,10 ) - (DWORD)PtrToUlong(cvRemovedResTypes->GetValue(i) ) ) ) {
  176. fRet = FALSE; // remove resours has value
  177. break;
  178. }
  179. }
  180. }
  181. if ( !fRet ) {
  182. cvKeepResTypes ->Push_back(lpResourceTypeInFile);
  183. }
  184. else {
  185. cvRemovedResTypesTemp->Push_back(lpResourceTypeInFile);// -i value, which is not in the -k value
  186. }
  187. }
  188. // if all values in -i and -k (-y) are identical.
  189. if (! cvRemovedResTypesTemp->Size() )
  190. return NULL;
  191. return cvRemovedResTypesTemp;
  192. }
  193. /*************************************************************************************
  194. void CheckTypePairs( cvstring * cvRemovedResTypes, cvstring * cvKeepResTypes )
  195. return : no.
  196. **************************************************************************************/
  197. void CheckTypePairs( cvcstring * cvRemovedResTypes, cvcstring * cvKeepResTypes )
  198. /*++
  199. Abstract:
  200. Some resource type should be pairs, in this case <1, 12 > < 3, 14>.
  201. Arguments:
  202. cvRemovedResTypes - resource types of being removed
  203. cvKeepResTypes - resource types of being mui created but not removed.
  204. Return:
  205. none
  206. --*/
  207. {
  208. if (cvRemovedResTypes == NULL || cvKeepResTypes == NULL)
  209. return ;
  210. if ( cvRemovedResTypes->Find((DWORD)3) && ! cvRemovedResTypes->Find((DWORD)14) ) {
  211. cvRemovedResTypes->Push_back( MAKEINTRESOURCE(14) );
  212. }
  213. else if ( ! cvRemovedResTypes->Find(3) && cvRemovedResTypes->Find(14) ) {
  214. cvRemovedResTypes->Push_back( MAKEINTRESOURCE(3) );
  215. }
  216. if ( cvRemovedResTypes->Find(1) && ! cvRemovedResTypes->Find(12) ) {
  217. cvRemovedResTypes->Push_back( MAKEINTRESOURCE(12) );
  218. }
  219. else if ( ! cvRemovedResTypes->Find(1) && cvRemovedResTypes->Find(12) ) {
  220. cvRemovedResTypes->Push_back( MAKEINTRESOURCE(1) );
  221. }
  222. if ( cvKeepResTypes->Find((DWORD)3) && ! cvKeepResTypes->Find((DWORD)14) ) {
  223. cvKeepResTypes->Push_back( MAKEINTRESOURCE(14) );
  224. }
  225. else if ( ! cvKeepResTypes->Find(3) && cvKeepResTypes->Find(14) ) {
  226. cvKeepResTypes->Push_back( MAKEINTRESOURCE(3) );
  227. }
  228. if ( cvKeepResTypes->Find(1) && ! cvKeepResTypes->Find(12) ) {
  229. cvKeepResTypes->Push_back( MAKEINTRESOURCE(12) );
  230. }
  231. else if ( ! cvKeepResTypes->Find(1) && cvKeepResTypes->Find(12) ) {
  232. cvKeepResTypes->Push_back( MAKEINTRESOURCE(1) );
  233. }
  234. }
  235. #ifdef NEVER
  236. BOOL CompareArgValues(cvcstring * cvAArgValues, cvcstring * cvBArgValues)
  237. /*++
  238. Abstract:
  239. Comapre the values of arguments
  240. Arguments:
  241. cvAArgValues : values of arugments
  242. cvBArgValues : values of arugments
  243. Return:
  244. true/false
  245. --*/
  246. {
  247. if (cvAArgValues == NULL || cvBArgValues == NULL)
  248. return FALSE;
  249. //
  250. // compare its values by while routine because values is initialzed NULL in the CMUICmdInfo.
  251. //
  252. LPTSTR * ppSrcValues = cvAArgValues;
  253. LPTSTR * ppDestValues = cvBArgValues;
  254. BOOL fNotIdentical = FALSE;
  255. for (UINT i = 0; i < cvAArgValues
  256. while (ppSrcValues ) {
  257. while ( ppDestValues ) {
  258. if ( _tcsicmp(*ppSrcValues,*ppDestValues) ) {
  259. fNotIdentical = TRUE;
  260. }
  261. ppDestValues ++;
  262. }
  263. ppSrcValues;
  264. }
  265. return fNotIdentical;
  266. }
  267. #endif
  268. /******************************************************************************************************
  269. BOOL CompactMui(CMuiCmdInfo* pcmci)
  270. *******************************************************************************************************/
  271. BOOL CompactMui(CMuiCmdInfo* pcmci)
  272. /*++
  273. Abstract:
  274. Called by main to call CCompactMUIFile for compacting mui files.
  275. Arguments:
  276. pcmci - arguments parser class.
  277. Return:
  278. true/false
  279. --*/
  280. {
  281. if ( pcmci == NULL)
  282. return FALSE;
  283. //
  284. // Read the arguments list
  285. //
  286. LPTSTR *ppszMuiFiles = NULL;
  287. LPTSTR *ppszCMFFile = NULL;
  288. LPTSTR *ppszCodeFileDir = NULL;
  289. CCompactMUIFile *pccmf = NULL;
  290. DWORD dwcMuiFiles = 0;
  291. DWORD dwCount = 0;
  292. ppszMuiFiles = pcmci->GetValueLists(_T("m"), dwcMuiFiles);
  293. if (! (ppszCMFFile = pcmci->GetValueLists(_T("f"),dwCount) ))
  294. {
  295. CError ce;
  296. ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(f),dwCount)") );
  297. return FALSE;
  298. }
  299. if(! (ppszCodeFileDir = pcmci->GetValueLists(_T("e"),dwCount)) )
  300. {
  301. CError ce;
  302. ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(e),dwCount)") );
  303. return FALSE;
  304. }
  305. //
  306. // Create CCompactMUIFile and write files.
  307. //
  308. pccmf = new CCompactMUIFile;
  309. if(!pccmf)
  310. return FALSE;
  311. if (pccmf->Create(*ppszCMFFile, ppszMuiFiles, dwcMuiFiles) )
  312. {
  313. if (pccmf->WriteCMFFile())
  314. {
  315. if (pccmf->UpdateCodeFiles(*ppszCodeFileDir, dwcMuiFiles ))
  316. {
  317. delete pccmf;
  318. return TRUE;
  319. }
  320. }
  321. }
  322. if(pccmf)
  323. delete pccmf;
  324. return FALSE;
  325. }
  326. BOOL UnCompactMui(PSTR pszCMFFile)
  327. /*++
  328. Abstract:
  329. Calling CCompactMUIFile for uncompact files
  330. Arguments:
  331. pszCMFFile - CMF file, which will be uncompacted to indivisual MUI files.
  332. Return:
  333. true/false
  334. --*/
  335. {
  336. BOOL bRet = FALSE;
  337. CCompactMUIFile *pccmf = NULL;
  338. if (pszCMFFile == NULL)
  339. return FALSE;
  340. //
  341. // Call CCompactMUIFile::UnCompactMUI
  342. //
  343. pccmf = new CCompactMUIFile();
  344. if(!pccmf)
  345. goto exit;
  346. if ( pccmf->UnCompactCMF(pszCMFFile))
  347. {
  348. pccmf->WriteCMFFile();
  349. bRet = TRUE;
  350. // REVIST ; how about uddating a binary files.
  351. }
  352. exit:
  353. if (pccmf)
  354. delete pccmf;
  355. return bRet;
  356. }
  357. BOOL DisplayHeader(PSTR pszCMFFile)
  358. /*++
  359. Abstract:
  360. Calling CCompactMUIFile for displaying the CMF headers information
  361. Arguments:
  362. pszCMFFile - CMF file.
  363. Return:
  364. true/false
  365. --*/
  366. {
  367. BOOL bRet = FALSE;
  368. CCompactMUIFile *pccmf = NULL;
  369. if (pszCMFFile == NULL)
  370. return FALSE;
  371. pccmf = new CCompactMUIFile();
  372. if(!pccmf)
  373. goto exit;
  374. if( pccmf->DisplayHeaders(pszCMFFile) )
  375. {
  376. bRet = TRUE;
  377. }
  378. exit:
  379. if (pccmf)
  380. delete pccmf;
  381. return bRet;
  382. }
  383. BOOL AddNewMUIFile(CMuiCmdInfo* pcmci)
  384. /*++
  385. Abstract:
  386. Calling CCompactMUIFile for adding MUI files into exsiting CMF file.
  387. Arguments:
  388. pcmci - argument parser class
  389. Return:
  390. true/false
  391. --*/
  392. {
  393. if (pcmci == NULL)
  394. return FALSE;
  395. // Read the arguments list
  396. //
  397. LPTSTR *ppszNewMuiFile = NULL;
  398. LPTSTR *ppszCMFFile = NULL;
  399. LPTSTR *ppszCodeFileDir = NULL;
  400. CCompactMUIFile *pccmf = NULL;
  401. DWORD dwcMuiFiles = 0;
  402. DWORD dwCount = 0;
  403. BOOL bRet = FALSE;
  404. // we don't have to check if it has value for this routine is called by the "a" arg. existence
  405. ppszNewMuiFile = pcmci->GetValueLists(_T("a"), dwcMuiFiles);
  406. if (! (ppszCMFFile = pcmci->GetValueLists(_T("f"),dwCount) ))
  407. {
  408. CError ce;
  409. ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(f),dwCount)") );
  410. goto exit;
  411. }
  412. if(! (ppszCodeFileDir = pcmci->GetValueLists(_T("e"),dwCount)) )
  413. {
  414. CError ce;
  415. ce.ErrorPrint(_T("CompactMui"),_T("return NULL at pcmci->GetValueLists(_T(e),dwCount)") );
  416. goto exit;
  417. }
  418. //
  419. // Add new mui file into existing cmf file.
  420. //
  421. pccmf = new CCompactMUIFile;
  422. if(!pccmf)
  423. goto exit;
  424. // TCHAR pszCMFName[MAX_PATH];
  425. if (pccmf->AddFile(*ppszCMFFile, ppszNewMuiFile, dwcMuiFiles ) )
  426. {
  427. // _tcscpy(pszCMFName, *ppszCMFFile);
  428. if( pccmf->Create(*ppszCMFFile))
  429. {
  430. if (pccmf->WriteCMFFile())
  431. {
  432. if (pccmf->UpdateCodeFiles(*ppszCodeFileDir, dwcMuiFiles ))
  433. {
  434. bRet = TRUE;
  435. goto exit;
  436. }
  437. }
  438. }
  439. }
  440. _tprintf(_T("Error happened on AddNewMUIFile, GetLastError(): %ld"), GetLastError() );
  441. exit:
  442. if (pccmf)
  443. delete pccmf;
  444. return bRet;
  445. }
  446. BOOL AddChecksumToFile(CMuiCmdInfo* pcmci)
  447. /*++
  448. Abstract:
  449. Adding checksum to external component. this is separted feature
  450. Arguments:
  451. pcmci - arguments parser class
  452. Return:
  453. true/false
  454. --*/
  455. {
  456. cvcstring * cvKeepResTypes= NULL;
  457. CMUIResource * pcmui = NULL;
  458. BOOL bRet = FALSE;
  459. if( pcmci == NULL ) {
  460. return FALSE;
  461. }
  462. LPTSTR *ppChecksumFile = NULL;
  463. LPTSTR *ppszTargetFileName = NULL;
  464. DWORD dwCount, dwRemoveCount, dwRemoveCountNoSanity;
  465. ppszTargetFileName = pcmci->GetValueLists(_T("z"), dwCount);
  466. if (!(ppChecksumFile=pcmci->GetValueLists(_T("c"), dwCount)))
  467. {
  468. _tprintf(_T("Checksum file NOT exist"));
  469. goto exit;
  470. }
  471. LPTSTR * ppRemoveRes = pcmci ->GetValueLists (_T("i"), dwRemoveCount ); // pszTmp would be copied to pszRemove
  472. LPTSTR * ppRemoveResNoSanity = pcmci ->GetValueLists (_T("o"), dwRemoveCountNoSanity );
  473. //
  474. // Create CMUIResource, which is main class for mui resource handling.
  475. //
  476. pcmui = new CMUIResource();
  477. if(!pcmui)
  478. goto exit;
  479. // load checksum file
  480. if (! pcmui -> Create(*ppChecksumFile )) // load the file for EnumRes..
  481. goto exit;
  482. //
  483. // Reorganise removing resource types.
  484. //
  485. cvcstring * cvRemovedResTypes = pcmui -> EnumResTypes (reinterpret_cast <LONG_PTR> ( pcmui )); // need to change : return LPCTSTR* rather than CVector;
  486. if ( cvRemovedResTypes -> Empty() ) {
  487. _tprintf(_T("The %s does not contain any resource \n"), *ppChecksumFile );
  488. goto exit;
  489. }
  490. else {
  491. // when there is remove argument and its value e.g. -i 3 4 Anvil ..
  492. if ( dwRemoveCount && !!_tcscmp(*ppRemoveRes,_T("ALL") ) ) {
  493. if (! FilterRemRes(cvRemovedResTypes,ppRemoveRes,dwRemoveCount, TRUE ) ) {
  494. goto exit;
  495. }
  496. } //if ( dwRemoveCount && _tcscmp(*ppRemoveRes,_T("ALL") ) ){
  497. else if (dwRemoveCountNoSanity)
  498. {
  499. // This is -o arg. build team does not know what resource type are included in the module, so
  500. // they use localizable resource, but -i return false when specified resourc type is not found in the
  501. // module. -o does not check sanity of resource type like -i arg.
  502. if (! FilterRemRes(cvRemovedResTypes, ppRemoveResNoSanity, dwRemoveCountNoSanity, FALSE ) ) {
  503. goto exit;
  504. }
  505. }
  506. // Stop if source only includes type 16. very few case, so use couple of api instead moving the module to front.
  507. if (cvRemovedResTypes->Size() == 1 && ! ( PtrToUlong(cvRemovedResTypes->GetValue(0)) - 16 ) ) {
  508. _tprintf(_T("The %s contains only VERSION resource \n"), *ppChecksumFile );
  509. goto exit;
  510. }
  511. } // cvRemovedResTypes.Empty()
  512. //
  513. // Some resource should be pairs <1, 12> <3, 14>
  514. //
  515. // we create bogus cvKeepResTypes for calling exisiting ChecktypePairs routine.
  516. cvKeepResTypes = new cvcstring (MAX_NUM_RESOURCE_TYPES);
  517. if(!cvKeepResTypes)
  518. goto exit;
  519. CheckTypePairs(cvRemovedResTypes, cvKeepResTypes);
  520. //
  521. // Create a checksum data
  522. //
  523. MD5_CTX * pMD5 = NULL;
  524. BYTE pbMD5Digest[RESOURCE_CHECKSUM_SIZE];
  525. DWORD dwLangCount =0;
  526. LPTSTR *ppChecksumLangId = pcmci ->GetValueLists (_T("b"), dwLangCount);
  527. WORD wChecksumLangId = LANG_CHECKSUM_DEFAULT;
  528. if (dwLangCount)
  529. {
  530. wChecksumLangId = (WORD)strtoul(*ppChecksumLangId, NULL, 0);
  531. }
  532. pMD5 = pcmui-> CreateChecksum(cvRemovedResTypes, wChecksumLangId);
  533. #ifdef CHECKSMU_ALL
  534. pMD5 = pcmui-> CreateChecksumWithAllRes(wChecksumLangId);
  535. #endif
  536. memcpy(pbMD5Digest, pMD5->digest, RESOURCE_CHECKSUM_SIZE);
  537. pcmui -> FreeLibrary();
  538. //
  539. // Add a checksum data to target file
  540. //
  541. if ( !pcmui->Create(*ppszTargetFileName))
  542. goto exit;
  543. if (! pcmui->AddChecksumToVersion(pbMD5Digest) ) { //add checksum into MUI file
  544. _tprintf(_T("Fail to add checksum to version ( %s)\n"),*ppszTargetFileName );
  545. goto exit;
  546. }
  547. pcmui -> FreeLibrary();
  548. bRet = TRUE;
  549. exit:
  550. if (pcmui)
  551. delete pcmui;
  552. return bRet;
  553. }
  554. /*************************************************************************************************************
  555. void _cdecl main (INT argc, void * argv[] )
  556. **************************************************************************************************************/
  557. void _cdecl main (INT argc, void * argv[] )
  558. {
  559. WORD wLangID;
  560. CMuiCmdInfo* pcmci = NULL;
  561. CMUIResource * pcmui = NULL;
  562. cvcstring * cvKeepResTypes = NULL;
  563. cvcstring * cvKeepResTypesIfExist = NULL;
  564. cvcstring * vRemnantRes = NULL;
  565. CMUIResource * pcmui2 = NULL;
  566. pcmci = new CMuiCmdInfo;
  567. if (!pcmci)
  568. goto exit;
  569. //
  570. // SetArgLists(Arglist, NeedValue, AllowFileValue, AllowMultipleFileValue)
  571. //
  572. pcmci->SetArgLists(_T("abcdefiklmopuvxyz"),_T("abcdefklmopuvyz"), _T("acdefmuz"), _T("am")); //set arg. lists.
  573. if (! pcmci->CreateArgList (argc,(TCHAR **) argv ) ) {
  574. goto exit;
  575. }
  576. DWORD dwCount = 0;
  577. if ( pcmci->GetValueLists(_T("m"),dwCount ) ){
  578. CompactMui(pcmci);
  579. goto exit;
  580. }
  581. if ( pcmci->GetValueLists(_T("a"),dwCount ) ){
  582. AddNewMUIFile(pcmci);
  583. goto exit;
  584. }
  585. LPTSTR *ppCMFFile = NULL;
  586. if ( ppCMFFile = pcmci->GetValueLists(_T("u"),dwCount ) ){
  587. UnCompactMui(*ppCMFFile);
  588. goto exit;
  589. }
  590. if ( ppCMFFile = pcmci->GetValueLists(_T("d"),dwCount ) ){
  591. DisplayHeader(*ppCMFFile);
  592. goto exit;
  593. }
  594. if (pcmci->GetValueLists(_T("z"),dwCount ) ){
  595. AddChecksumToFile(pcmci);
  596. goto exit;
  597. }
  598. //
  599. // Fill the CMUIResource intenal data : we don't care languge at this time, but soon add more code to
  600. //
  601. // handle the languge case.
  602. LPCTSTR lpLangID = NULL;
  603. LPTSTR * ppsz = NULL;
  604. BOOL fForceLocalizedLangID = FALSE;
  605. if ( ppsz = pcmci ->GetValueLists (_T("l"), dwCount ) ) {
  606. lpLangID = *ppsz;
  607. wLangID = (WORD)_tcstol(lpLangID, NULL, 0 );
  608. }
  609. else if(ppsz = pcmci ->GetValueLists (_T("x"), dwCount ) ) {
  610. lpLangID = *ppsz;
  611. wLangID = (WORD)_tcstol(lpLangID, NULL, 0 );
  612. fForceLocalizedLangID = TRUE;
  613. }
  614. else {
  615. _tprintf(_T(" Language ID is not specified, you need to specify the launge id. e.g. -l 0x0409 ") );
  616. goto exit;
  617. }
  618. //
  619. // get the source name and new resource free file, mui resource file name.
  620. //
  621. LPTSTR pszSource,pszNewFile,pszMuiFile ;
  622. pszSource = pszNewFile =pszMuiFile = NULL;
  623. if ( ! GetFileNames(pcmci, &pszSource, &pszNewFile, &pszMuiFile ) ) {
  624. _tprintf(_T("\n Can't find source name, or Name does not format of *.* \n") );
  625. _tprintf(_T("MUIRCT [-h|?] -l langid [-i resource_type] [-k resource_type] [-y resource_type] \n") );
  626. _tprintf(_T("source_filename, [language_neutral_filename], [MUI_filename] \n\n"));
  627. goto exit;
  628. }
  629. //
  630. // we need to change the attribute of source as read/write before copy. new file inherit old one attribute.
  631. //
  632. SetFileAttributes (pszSource, FILE_ATTRIBUTE_ARCHIVE );
  633. if ( _tcsicmp(pszSource,pszNewFile) ) { // new file name is same with source file.
  634. if (! CopyFile (pszSource, pszNewFile, FALSE ) ) {
  635. printf("GetLastError () : %d \n", GetLastError() );
  636. _tprintf (_T(" Copy File error, GetLastError() : %d \n "), GetLastError() );
  637. goto exit;
  638. }
  639. }
  640. //
  641. // Read the value of r (remove resource) , k (keep resource)
  642. //
  643. DWORD dwKeepCount, dwRemoveCount,dwKeepIfExistCount, dwRemoveCountNoSanity;
  644. dwKeepCount = dwRemoveCount = dwKeepIfExistCount = dwRemoveCountNoSanity = 0;
  645. LPTSTR * ppKeepRes = pcmci ->GetValueLists (_T("k"), dwKeepCount );
  646. LPTSTR * ppRemoveRes = pcmci ->GetValueLists (_T("i"), dwRemoveCount ); // pszTmp would be copied to pszRemove
  647. LPTSTR * ppRemoveResNoSanity = pcmci ->GetValueLists (_T("o"), dwRemoveCountNoSanity );
  648. LPSTR * ppKeepIfExists = pcmci->GetValueLists(_T("y"), dwKeepIfExistCount);
  649. #ifdef NEVER
  650. if (! CompareArgValues(ppRemoveRes,ppKeepRes ) ) { // if same, goto 0.
  651. goto exit;
  652. }
  653. #endif
  654. //
  655. // Create CMUIResource, which is main class for mui resource handling.
  656. //
  657. pcmui = new CMUIResource(); //(pszNewFile);
  658. if (! pcmui) {
  659. _tprintf(_T("Insufficient resource \n") );
  660. goto exit;
  661. }
  662. //
  663. // Create checksum data with all resource except version.Disabled at this time.
  664. //
  665. #ifdef CHECKSMU_ALL
  666. LPTSTR lpChecksumFile = NULL;
  667. BOOL fChecksum = FALSE;
  668. MD5_CTX * pMD5 = NULL;
  669. BYTE pbMD5Digest[RESOURCE_CHECKSUM_SIZE];
  670. if ( ppsz = pcmci ->GetValueLists (_T("c"), dwCount ) ) {
  671. lpChecksumFile = *ppsz ;
  672. // load checksum file
  673. if ( ! pcmui -> Create(lpChecksumFile ) ) // load the file for EnumRes..
  674. goto exit;
  675. // create a checksum MD5_CTX format ( 16 byte: all resources are caculated based on some algorithm.
  676. DWORD dwLangCount =0;
  677. LPTSTR *ppChecksumLangId = pcmci ->GetValueLists (_T("b"), dwLangCount);
  678. WORD wChecksumLangId = LANG_CHECKSUM_DEFAULT;
  679. if (dwLangCount)
  680. {
  681. wChecksumLangId = (WORD)strtoul(*ppChecksumLangId, NULL, 0);
  682. }
  683. pMD5 = pcmui-> CreateChecksumWithAllRes(wChecksumLangId);
  684. memcpy(pbMD5Digest, pMD5->digest, RESOURCE_CHECKSUM_SIZE);
  685. pcmui -> FreeLibrary();
  686. fChecksum = TRUE;
  687. }
  688. #endif
  689. //
  690. // load new MUI file
  691. //
  692. if (! pcmui -> Create(pszNewFile) ) { // load the file .
  693. goto exit;
  694. }
  695. //
  696. // Reorganise removing resource types.
  697. //
  698. cvcstring * cvRemovedResTypes = pcmui -> EnumResTypes (reinterpret_cast <LONG_PTR> ( pcmui )); // need to change : goto LPCTSTR* rather than CVector;
  699. if ( cvRemovedResTypes -> Empty() ) {
  700. _tprintf(_T("The %s does not contain any resource \n"), pszSource );
  701. goto exit;
  702. }
  703. else {
  704. // when there is remove argument and its value e.g. -i 3 4 Anvil ..
  705. if ( dwRemoveCount && !!_tcscmp(*ppRemoveRes,_T("ALL") ) ) {
  706. if (! FilterRemRes(cvRemovedResTypes,ppRemoveRes,dwRemoveCount, TRUE ) ) {
  707. goto exit;
  708. }
  709. } //if ( dwRemoveCount && _tcscmp(*ppRemoveRes,_T("ALL") ) ){
  710. else if (dwRemoveCountNoSanity)
  711. {
  712. // This is -o arg. build team does not know what resource type are included in the module, so
  713. // they use localizable resource, but -i goto false when specified resourc type is not found in the
  714. // module. -o does not check sanity of resource type like -i arg.
  715. if (! FilterRemRes(cvRemovedResTypes, ppRemoveResNoSanity, dwRemoveCountNoSanity, FALSE ) ) {
  716. goto exit;
  717. }
  718. }
  719. // Stop if source only includes type 16. very few case, so use couple of api instead moving the module to front.
  720. if (cvRemovedResTypes->Size() == 1 && ! ( PtrToUlong(cvRemovedResTypes->GetValue(0)) - 16 ) ) {
  721. if ( _tcsicmp(pszSource, pszNewFile) ) {
  722. pcmui->FreeLibrary();
  723. DeleteFile(pszNewFile);
  724. }
  725. _tprintf(_T("The %s contains only VERSION resource \n"), pszSource );
  726. goto exit;
  727. }
  728. } // cvRemovedResTypes.Empty()
  729. //
  730. // we need to get -k argument and check its sanity and save its valus into cvcstring format.
  731. // we also need to check if -i values and those of -k, -y are identical.
  732. // rethink : what if remove sanity check from -k arg. then we can delete -y arg. as well as most of below.
  733. //
  734. cvKeepResTypes = new cvcstring (MAX_NUM_RESOURCE_TYPES);
  735. if(!cvKeepResTypes)
  736. goto exit;
  737. cvKeepResTypesIfExist = new cvcstring (MAX_NUM_RESOURCE_TYPES);
  738. if(!cvKeepResTypesIfExist)
  739. goto exit;
  740. if ( dwKeepCount && dwKeepIfExistCount ) {
  741. // both of -k, -y arg. exist.
  742. if (!( vRemnantRes = FilterKeepRes(cvRemovedResTypes,ppKeepRes,cvKeepResTypes,dwKeepCount,TRUE ) ) ){
  743. goto exit;
  744. }
  745. if (! FilterKeepRes( vRemnantRes, ppKeepIfExists, cvKeepResTypesIfExist, dwKeepIfExistCount,FALSE) ) {
  746. goto exit;
  747. }
  748. }
  749. else if ( dwKeepCount) {
  750. // only -k arg. exist.
  751. if (!( vRemnantRes = FilterKeepRes(cvRemovedResTypes,ppKeepRes,cvKeepResTypes,dwKeepCount,TRUE ) ) ){
  752. goto exit;
  753. }
  754. }
  755. else if (dwKeepIfExistCount) {
  756. if ( ! FilterKeepRes( cvRemovedResTypes, ppKeepIfExists, cvKeepResTypesIfExist, dwKeepIfExistCount,FALSE)) {
  757. goto exit;
  758. }
  759. }
  760. //
  761. // Some resource should be pairs <1, 12> <3, 14>
  762. //
  763. CheckTypePairs(cvRemovedResTypes,cvKeepResTypes);
  764. // #ifndef CHECKSUM_ALL
  765. //
  766. // Create checksum with only selected resource types.
  767. //
  768. LPTSTR lpChecksumFile = NULL;
  769. BOOL fChecksum = FALSE;
  770. MD5_CTX * pMD5 = NULL;
  771. BYTE pbMD5Digest[RESOURCE_CHECKSUM_SIZE];
  772. if ( ppsz = pcmci ->GetValueLists (_T("c"), dwCount ) ) {
  773. pcmui2 = new CMUIResource();
  774. lpChecksumFile = *ppsz ;
  775. // load checksum file
  776. if ( ! pcmui2 -> Create(lpChecksumFile ) ) // load the file for EnumRes..
  777. goto exit;
  778. DWORD dwLangCount =0;
  779. LPTSTR *ppChecksumLangId = pcmci ->GetValueLists (_T("b"), dwLangCount);
  780. WORD wChecksumLangId = LANG_CHECKSUM_DEFAULT;
  781. if (dwLangCount)
  782. {
  783. wChecksumLangId = (WORD)strtoul(*ppChecksumLangId, NULL, 0);
  784. }
  785. // create a checksum MD5_CTX format ( 16 byte: all resources are caculated based on some algorithm.
  786. pMD5 = pcmui2-> CreateChecksum(cvRemovedResTypes, wChecksumLangId);
  787. memcpy(pbMD5Digest, pMD5->digest, RESOURCE_CHECKSUM_SIZE);
  788. pcmui2 -> FreeLibrary();
  789. fChecksum = TRUE;
  790. }
  791. // #endif
  792. //
  793. // Fill CMUIData field. it goto false when there is no LangID specified.
  794. // Is there any chance of no resource name when resource type exist ?
  795. //
  796. if ( !pcmui -> FillMuiData( cvRemovedResTypes, wLangID, fForceLocalizedLangID) ) {
  797. _tprintf (_T("Fail to get resouce name or lang id \n " ) );
  798. goto exit;
  799. };
  800. //
  801. // -p arugment; the valules of this argument(resourc type) should not be included in new MUI File.
  802. // although delete them from source file.
  803. //
  804. dwCount =0;
  805. if ( ppsz = pcmci ->GetValueLists (_T("p"), dwCount ) )
  806. {
  807. for (UINT i =0; i < dwCount; i ++)
  808. {
  809. LPCSTR lpDelResourceType = NULL;
  810. LPTSTR pszResType = *ppsz++;
  811. LPTSTR pszStopped = NULL;
  812. DWORD dwTypeID = _tcstoul(pszResType,&pszStopped,10 );
  813. if ( 0 == dwTypeID || *pszStopped != _T('\0')) { // string type
  814. lpDelResourceType = pszResType ;
  815. }
  816. else { // id
  817. lpDelResourceType = MAKEINTRESOURCE(dwTypeID);
  818. }
  819. pcmui->DeleteResItem( lpDelResourceType );
  820. }
  821. }
  822. DWORD dwVerbose = 0;
  823. if ( ppsz = pcmci ->GetValueLists (_T("v"), dwCount ) )
  824. dwVerbose = _tcstoul(*ppsz,NULL, 10 );
  825. // Set the link.exe path, link options.
  826. TCHAR lpCommandLine[] = _T(" /noentry /dll /nologo /nodefaultlib /SUBSYSTEM:WINDOWS,5.01");
  827. //
  828. // Create the mui resource files with the information from FillMuiData
  829. // We can use both of these way : WriteResFile : call link.exe inside after creation of RES file
  830. // CreatePE : using UpdateResource using
  831. // UpdateResource has bug to fail when udpated data is large. so we use link.
  832. //
  833. if ( ! pcmui -> WriteResFile (pszSource, pszMuiFile, lpCommandLine, wLangID ) ) {
  834. // if ( ! pcmui -> CreatePE ( pszMuiFile , pszSource ) ) { // this can be used after more investigation(if it is used, we can remove -s )
  835. _tprintf (_T(" Muirct fail to creat new mui rc file. GetLastError() : %d \n "), GetLastError() );
  836. }
  837. else
  838. {
  839. if ( dwVerbose == 1 || dwVerbose == 2) {
  840. _tprintf (_T(" MUI resource file(%s) is successfully created \n\n"), pszMuiFile );
  841. }
  842. if ( dwVerbose == 2) {
  843. pcmui ->PrtVerbose( 1 );
  844. _tprintf("\n");
  845. }
  846. }
  847. //
  848. // delete values of -k from -i values.
  849. //
  850. if (dwKeepCount) {
  851. for (UINT i = 0; i < cvKeepResTypes->Size(); i ++ ) {
  852. pcmui->DeleteResItem( cvKeepResTypes->GetValue (i) );
  853. }
  854. }
  855. //
  856. // handling of -y argument; it is same with -k argument except skip the checking of its existence.
  857. //
  858. if ( dwKeepIfExistCount ) {
  859. for (UINT i = 0; i < cvKeepResTypesIfExist->Size(); i++) {
  860. pcmui->DeleteResItem(cvKeepResTypesIfExist->GetValue(i) );
  861. }
  862. #ifdef NEVER
  863. for (UINT i = 0; i < dwKeepIfExistCount; i ++ ) {
  864. LPCSTR lpDelResourceType = NULL;
  865. LPTSTR pszValue = ppKeepIfExists[i];
  866. LPTSTR pszStopped = NULL;
  867. DWORD dwTypeID = _tcstoul(pszValue,&pszStopped,10 );
  868. if ( 0 == dwTypeID || *pszStopped != _T('\0')) { // string type
  869. lpDelResourceType = pszValue ;
  870. }
  871. else { // id
  872. lpDelResourceType = MAKEINTRESOURCE(dwTypeID);
  873. }
  874. pcmui->DeleteResItem( lpDelResourceType );
  875. }
  876. #endif
  877. }
  878. //
  879. // Delete resource from the pszNewFile
  880. //
  881. if ( ! pcmui -> DeleteResource () ) {
  882. _tprintf (_T(" Muirct fail to remove the resource from the file\n" ) );
  883. }
  884. else
  885. {
  886. if ( dwVerbose == 1 || dwVerbose == 2) {
  887. _tprintf (_T(" New Resource removed file(%s) is successfully created\n\n" ), pszNewFile );
  888. }
  889. if ( dwVerbose == 2) {
  890. _tprintf(_T(" Removed resource types \n\n") );
  891. pcmui ->PrtVerbose( 1 );
  892. _tprintf("\n");
  893. }
  894. }
  895. //
  896. // Adding a resource checksum into two files ( lang-neutral binary and mui file )
  897. //
  898. if ( fChecksum ){
  899. pcmui->Create(pszMuiFile);
  900. if (! pcmui->AddChecksumToVersion(pbMD5Digest) ) { //add checksum into MUI file
  901. _tprintf(_T("Fail to add checksum to version ( %s)\n"),pszMuiFile );
  902. }
  903. pcmui->Create(pszNewFile);
  904. if (! pcmui->AddChecksumToVersion(pbMD5Digest) ) { //add checksum into lang-neutral binary.
  905. _tprintf(_T("Fail to add checksum to version ( %s); \n"),pszNewFile );
  906. }
  907. }
  908. //
  909. // Updating file checksum in language-free binary
  910. //
  911. BOOL fSuccess = pcmui->UpdateNtHeader(pszNewFile,pcmui->CHECKSUM );
  912. exit:
  913. if (pcmci)
  914. delete pcmci;
  915. if (pcmui)
  916. delete pcmui;
  917. if(pcmui2)
  918. delete pcmui2;
  919. if (cvKeepResTypes)
  920. delete cvKeepResTypes;
  921. return;
  922. }