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.

3141 lines
107 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2001, Microsoft Corporation All rights reserved.
  4. //
  5. // Module Name:
  6. //
  7. // infparser.cpp
  8. //
  9. // Abstract:
  10. //
  11. // This file contains the entry point of the infparser.exe utility.
  12. //
  13. // Revision History:
  14. //
  15. // 2001-06-20 lguindon Created.
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. ///////////////////////////////////////////////////////////////////////////////
  19. //
  20. // Includes Files.
  21. //
  22. ///////////////////////////////////////////////////////////////////////////////
  23. #include "stdafx.h"
  24. #include "infparser.h"
  25. #include "stdlib.h"
  26. #include "windows.h"
  27. #include "string.h"
  28. #include "ctype.h"
  29. ///////////////////////////////////////////////////////////////////////////////
  30. //
  31. // Global Definitions
  32. //
  33. ///////////////////////////////////////////////////////////////////////////////
  34. #define NO_INVALIDCHARS 31
  35. #define PRO_SKU_CONDITION "<Condition><![CDATA[NOT MsiNTSuitePersonal AND MsiNTProductType=1]]></Condition>"
  36. #define SRV_SKU_CONDITION "<Condition><![CDATA[MsiNTProductType<>1 AND NOT MsiNTSuiteDataCenter AND NOT MsiNTSuiteEnterprise AND NOT MsiNTSuiteWebServer AND NOT MsiNTSuiteSmallBusiness and NOT MsiNTSuiteSmallBusinessRestricted]]></Condition>"
  37. #define ADV_SKU_CONDITION "<Condition>MsiNTSuiteEnterprise</Condition>"
  38. #define SBS_SKU_CONDITION "<Condition>MsiNTSuiteSmallBusinessRestricted OR MsiNTSuiteSmallBusiness</Condition>"
  39. #define DTC_SKU_CONDITION "<Condition>MsiNTSuiteDataCenter</Condition>"
  40. #define BLA_SKU_CONDITION "<Condition>MsiNTSuiteWebServer</Condition>"
  41. #define PRO_SKU_INF "layout.inf"
  42. #define PER_SKU_INF "perinf\\layout.inf"
  43. #define SRV_SKU_INF "srvinf\\layout.inf"
  44. #define ADV_SKU_INF "entinf\\layout.inf"
  45. #define DTC_SKU_INF "dtcinf\\layout.inf"
  46. #define SBS_SKU_INF "sbsinf\\layout.inf"
  47. #define BLA_SKU_INF "blainf\\layout.inf"
  48. #define NO_SKUS 7
  49. #define PRO_SKU_INDEX 0
  50. #define PER_SKU_INDEX 1
  51. #define SRV_SKU_INDEX 2
  52. #define ADV_SKU_INDEX 3
  53. #define DTC_SKU_INDEX 4
  54. #define SBS_SKU_INDEX 5
  55. #define BLA_SKU_INDEX 6
  56. ///////////////////////////////////////////////////////////////////////////////
  57. //
  58. // Global variable.
  59. //
  60. ///////////////////////////////////////////////////////////////////////////////
  61. BOOL bSilence = TRUE;
  62. DWORD gBinType = BIN_UNDEFINED;
  63. DWORD dwComponentCounter = 0;
  64. DWORD dwDirectoryCounter = 1;
  65. WORD gBuildNumber = 0;
  66. TCHAR TempDirName[MAX_PATH] = { 0 };
  67. LPSTR sLDirName = NULL;
  68. LPSTR sLocBinDir = NULL;
  69. CHAR InvalidChars[NO_INVALIDCHARS] = { '`', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-',
  70. '=', '+', '[', '{', ']', '}', '\\', '|', ';', ':', '\'', '\"', ',', '<',
  71. '>', '/', '?', ' '
  72. };
  73. CHAR strArchSections[3][30] = {"SourceDisksFiles", "SourceDisksFiles.x86", "SourceDisksFiles.ia64"};
  74. LAYOUTINF SkuInfs[NO_SKUS];
  75. ///////////////////////////////////////////////////////////////////////////////
  76. //
  77. // Prototypes.
  78. //
  79. ///////////////////////////////////////////////////////////////////////////////
  80. BOOL DirectoryExist(LPSTR dirPath);
  81. BOOL ValidateLanguage(LPSTR dirPath, LPSTR langName, DWORD binType);
  82. WORD ConvertLanguage(LPSTR dirPath, LPSTR langName);
  83. int ListContents(LPSTR filename, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType);
  84. int ListComponents(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType);
  85. int ListMuiFiles(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType);
  86. void PrintFileList(FileList* list, HANDLE hFile, BOOL compressed, BOOL bWinDir, BOOL bPermanent, BOOL bX86OnIA64, DWORD flavor, DWORD binType);
  87. BOOL PrintLine(HANDLE hFile, LPCSTR lpLine);
  88. HANDLE CreateOutputFile(LPSTR filename);
  89. VOID removeSpace(LPSTR src, LPSTR dest);
  90. DWORD TransNum(LPTSTR lpsz);
  91. void Usage();
  92. BOOL GetTempDirName(LPSTR sLangName) ;
  93. BOOL GetFileShortName(const CHAR * pcIn, CHAR * pcOut, BOOL bInFileExists);
  94. void ReplaceInvalidChars(CHAR *pcInName);
  95. BOOL IsInvalidChar(CHAR cCheck);
  96. BOOL GetFileNameFromFullPath(const CHAR * pcInFullPath, CHAR * pcOutFileName);
  97. void RenameMuiExtension(CHAR * dstFileName);
  98. BOOL ContainSKUDirs(CHAR *pszSKUSearchPath);
  99. BOOL GetSKUConditionString(CHAR *pszBuffer, DWORD dwFlavour);
  100. BOOL IsFileForSKU(LPSTR strFileName, DWORD dwSKU, DWORD dwArch, FileLayoutExceptionList * exceptionList);
  101. BOOL IsFileInInf(CHAR * strFileName, UINT iSkuIndex, DWORD dwArch);
  102. BOOL ReadInLayoutInfFiles();
  103. ///////////////////////////////////////////////////////////////////////////////
  104. //
  105. // Main entry point.
  106. //
  107. ///////////////////////////////////////////////////////////////////////////////
  108. int __cdecl main(int argc, char* argv[])
  109. {
  110. LPSTR sLangName = NULL;
  111. LPSTR sDirPath = NULL;
  112. DWORD dwFlavor = FLV_UNDEFINED;
  113. DWORD dwBinType = BIN_UNDEFINED;
  114. DWORD dwArg = ARG_UNDEFINED;
  115. WORD wLangID = 0;
  116. HANDLE hFile;
  117. int argIndex = 1;
  118. LPSTR lpFileName = NULL;
  119. HRESULT hr = S_OK;
  120. INT iResult = 0;
  121. INT i = 0;
  122. //
  123. // Check if we have the minimal number of arguments.
  124. //
  125. if (argc < 6)
  126. {
  127. printf("Not all required parameters were found when executing infparser.exe.\n");
  128. Usage();
  129. return (-1);
  130. }
  131. //
  132. // Parse the command line.
  133. //
  134. while (argIndex < argc)
  135. {
  136. if (*argv[argIndex] == '/')
  137. {
  138. switch(*(argv[argIndex]+1))
  139. {
  140. case('p'):
  141. case('P'):
  142. //
  143. // switch for locating directory to external components this should be same as lang except for psu builds
  144. //
  145. sLDirName = (argv[argIndex]+3);
  146. dwArg |= ARG_CDLAYOUT;
  147. break;
  148. case('b'):
  149. case('B'):
  150. //
  151. // Binairy i386 or ia64
  152. //
  153. if ((*(argv[argIndex]+3) == '3') && (*(argv[argIndex]+4) == '2'))
  154. {
  155. dwBinType = BIN_32;
  156. }
  157. else if ((*(argv[argIndex]+3) == '6') && (*(argv[argIndex]+4) == '4'))
  158. {
  159. dwBinType = BIN_64;
  160. }
  161. else
  162. {
  163. return (argIndex);
  164. }
  165. dwArg |= ARG_BINARY;
  166. break;
  167. case('l'):
  168. case('L'):
  169. //
  170. // Language
  171. //
  172. sLangName = (argv[argIndex]+3);
  173. dwArg |= ARG_LANG;
  174. break;
  175. case('i'):
  176. case('I'):
  177. //
  178. // Inf root location (where localized binaries are located, same as _NTPOSTBLD env variable)
  179. //
  180. sLocBinDir = (argv[argIndex]+3);
  181. dwArg |= ARG_LOCBIN;
  182. break;
  183. case('f'):
  184. case('F'):
  185. //
  186. // Flavor requested
  187. //
  188. switch(*(argv[argIndex]+3))
  189. {
  190. case('c'):
  191. case('C'):
  192. dwFlavor = FLV_CORE;
  193. break;
  194. case('p'):
  195. case('P'):
  196. dwFlavor = FLV_PROFESSIONAL;
  197. break;
  198. case('s'):
  199. case('S'):
  200. dwFlavor = FLV_SERVER;
  201. break;
  202. case('a'):
  203. case('A'):
  204. dwFlavor = FLV_ADVSERVER;
  205. break;
  206. case('d'):
  207. case('D'):
  208. dwFlavor = FLV_DATACENTER;
  209. break;
  210. case('b'):
  211. case('B'):
  212. dwFlavor = FLV_WEBBLADE;
  213. break;
  214. case('l'):
  215. case('L'):
  216. dwFlavor = FLV_SMALLBUSINESS;
  217. break;
  218. default:
  219. return (argIndex);
  220. }
  221. dwArg |= ARG_FLAVOR;
  222. break;
  223. case('s'):
  224. case('S'):
  225. //
  226. // Binairy location
  227. //
  228. sDirPath = (argv[argIndex]+3);
  229. dwArg |= ARG_DIR;
  230. break;
  231. case('o'):
  232. case('O'):
  233. //
  234. // Output filename
  235. //
  236. /*
  237. if ((hFile = CreateOutputFile(argv[argIndex]+3)) == INVALID_HANDLE_VALUE)
  238. {
  239. return (argIndex);
  240. }
  241. */
  242. lpFileName = argv[argIndex]+3;
  243. dwArg |= ARG_OUT;
  244. break;
  245. case('v'):
  246. case('V'):
  247. //
  248. // Verbose mode
  249. //
  250. bSilence = FALSE;
  251. dwArg |= ARG_SILENT;
  252. break;
  253. default:
  254. printf("Invalid parameters found on the command line!\n");
  255. Usage();
  256. return (argIndex);
  257. }
  258. }
  259. else
  260. {
  261. printf("Invalid parameters found on the command line!\n");
  262. Usage();
  263. return (-1);
  264. }
  265. //
  266. // Next argument
  267. //
  268. argIndex++;
  269. }
  270. //
  271. // Validate arguments passed. Should have all five basic argument in order
  272. // to continue.
  273. //
  274. if ((dwArg == ARG_UNDEFINED) ||
  275. !((dwArg & ARG_BINARY) &&
  276. (dwArg & ARG_LANG) &&
  277. (dwArg & ARG_DIR) &&
  278. (dwArg & ARG_OUT) &&
  279. (dwArg & ARG_LOCBIN) &&
  280. (dwArg & ARG_CDLAYOUT) &&
  281. (dwArg & ARG_FLAVOR)))
  282. {
  283. Usage();
  284. return (-1);
  285. }
  286. //
  287. // Validate Source directory
  288. //
  289. if (!DirectoryExist(sDirPath))
  290. {
  291. return (-2);
  292. }
  293. if (!DirectoryExist(sLocBinDir))
  294. {
  295. return (-2);
  296. }
  297. //
  298. // Validate Language
  299. //
  300. if (!ValidateLanguage(sDirPath, sLangName, dwBinType))
  301. {
  302. return (-3);
  303. }
  304. //
  305. // Get LANGID from the language
  306. //
  307. if ( (gBuildNumber = ConvertLanguage(sDirPath, sLangName)) == 0x0000)
  308. {
  309. return (-4);
  310. }
  311. // update the temp directory global variable
  312. if (!GetTempDirName(sLangName))
  313. {
  314. return (-5);
  315. }
  316. gBinType = dwBinType;
  317. // Generate the layout.inf paths for every sku
  318. hr = StringCchPrintfA(SkuInfs[PRO_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, PRO_SKU_INF); // Professional
  319. if (FAILED(hr))
  320. {
  321. return (-6);
  322. }
  323. hr = StringCchPrintfA(SkuInfs[PER_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, PER_SKU_INF); // Personal
  324. if (FAILED(hr))
  325. {
  326. return (-6);
  327. }
  328. hr = StringCchPrintfA(SkuInfs[SRV_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, SRV_SKU_INF); // standard server
  329. if (FAILED(hr))
  330. {
  331. return (-6);
  332. }
  333. hr = StringCchPrintfA(SkuInfs[ADV_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, ADV_SKU_INF); // advanced server
  334. if (FAILED(hr))
  335. {
  336. return (-6);
  337. }
  338. hr = StringCchPrintfA(SkuInfs[DTC_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, DTC_SKU_INF); // datacenter server
  339. if (FAILED(hr))
  340. {
  341. return (-6);
  342. }
  343. hr = StringCchPrintfA(SkuInfs[SBS_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, SBS_SKU_INF); // small business server
  344. if (FAILED(hr))
  345. {
  346. return (-6);
  347. }
  348. hr = StringCchPrintfA(SkuInfs[BLA_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, BLA_SKU_INF); // web server
  349. if (FAILED(hr))
  350. {
  351. return (-6);
  352. }
  353. hr = StringCchCopyA(SkuInfs[PRO_SKU_INDEX].strSkuName, 4, TEXT("Pro")); // Professional
  354. if (FAILED(hr))
  355. {
  356. return (-6);
  357. }
  358. hr = StringCchCopyA(SkuInfs[PER_SKU_INDEX].strSkuName, 4, TEXT("Per")); // Personal
  359. if (FAILED(hr))
  360. {
  361. return (-6);
  362. }
  363. hr = StringCchCopyA(SkuInfs[SRV_SKU_INDEX].strSkuName, 4, TEXT("Srv")); // Standard Server
  364. if (FAILED(hr))
  365. {
  366. return (-6);
  367. }
  368. hr = StringCchCopyA(SkuInfs[ADV_SKU_INDEX].strSkuName, 4, TEXT("Adv")); // Advanced Server
  369. if (FAILED(hr))
  370. {
  371. return (-6);
  372. }
  373. hr = StringCchCopyA(SkuInfs[DTC_SKU_INDEX].strSkuName, 4, TEXT("Dtc")); // Datacenter
  374. if (FAILED(hr))
  375. {
  376. return (-6);
  377. }
  378. hr = StringCchCopyA(SkuInfs[SBS_SKU_INDEX].strSkuName, 4, TEXT("Sbs")); // Small Business Server
  379. if (FAILED(hr))
  380. {
  381. return (-6);
  382. }
  383. hr = StringCchCopyA(SkuInfs[BLA_SKU_INDEX].strSkuName, 4, TEXT("Bla")); // Blade server
  384. if (FAILED(hr))
  385. {
  386. return (-6);
  387. }
  388. if (FALSE == ReadInLayoutInfFiles())
  389. {
  390. if (!bSilence)
  391. {
  392. printf("Failed to populate layout.inf file lists.\n");
  393. }
  394. return (-7);
  395. }
  396. //
  397. // Generate the file list
  398. //
  399. if ((dwArg & ARG_OUT) && lpFileName)
  400. {
  401. iResult = ListContents(lpFileName, sDirPath, sLangName, dwFlavor, dwBinType);
  402. }
  403. return iResult;
  404. }
  405. ///////////////////////////////////////////////////////////////////////////////
  406. //
  407. // ListContents()
  408. //
  409. // Generate the file list contents.
  410. //
  411. ///////////////////////////////////////////////////////////////////////////////
  412. int ListContents(LPSTR filename, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType)
  413. {
  414. int iRet = 0;
  415. Uuid* uuid;
  416. CHAR schemaPath[MAX_PATH] = {0};
  417. CHAR outputString[4096] = {0};
  418. FileList fileList, rootfileList;
  419. HANDLE outputFile = CreateOutputFile(filename);
  420. HRESULT hr;
  421. if (outputFile == INVALID_HANDLE_VALUE)
  422. {
  423. iRet = -1;
  424. goto ListContents_EXIT;
  425. }
  426. //
  427. // Create a UUID for this module and the schema path
  428. //
  429. uuid = new Uuid();
  430. hr = StringCchPrintfA(schemaPath, ARRAYLEN(schemaPath), "%s\\msi\\MmSchema.xml", dirPath);
  431. if (!SUCCEEDED(hr)) {
  432. iRet = -1;
  433. goto ListContents_EXIT;
  434. }
  435. //
  436. // Print module header.
  437. //
  438. PrintLine(outputFile, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
  439. hr = StringCchPrintfA(outputString, ARRAYLEN(outputString), "<Module Name=\"MUIContent\" Id=\"%s\" Language=\"0\" Version=\"1.0\" xmlns=\"%s\">", uuid->getString(), schemaPath);
  440. if (!SUCCEEDED(hr)) {
  441. iRet = -1;
  442. goto ListContents_EXIT;
  443. }
  444. PrintLine(outputFile, outputString);
  445. hr = StringCchPrintfA(outputString, ARRAYLEN(outputString), " <Package Id=\"%s\"", uuid->getString());
  446. if (!SUCCEEDED(hr)) {
  447. iRet = -1;
  448. goto ListContents_EXIT;
  449. }
  450. PrintLine(outputFile, outputString);
  451. delete uuid;
  452. PrintLine(outputFile, " Description=\"Content module\"");
  453. if (BIN_32 == binType)
  454. PrintLine(outputFile, " Platforms=\"Intel\"");
  455. else
  456. PrintLine(outputFile," Platforms=\"Intel64\"");
  457. PrintLine(outputFile, " Languages=\"0\"");
  458. PrintLine(outputFile, " InstallerVersion=\"200\"");
  459. PrintLine(outputFile, " Manufacturer=\"Microsoft Corporation\"");
  460. PrintLine(outputFile, " Keywords=\"MergeModule, MSI, Database\"");
  461. PrintLine(outputFile, " Comments=\"This merge module contains all the MUI file content\"");
  462. PrintLine(outputFile, " ShortNames=\"yes\" Compressed=\"yes\"");
  463. PrintLine(outputFile, "/>");
  464. //
  465. // Generate components file list
  466. //
  467. if ( (iRet = ListComponents(&fileList, dirPath, lang, flavor, binType)) != 0)
  468. {
  469. goto ListContents_EXIT;
  470. }
  471. //
  472. // Generate Mui file list
  473. //
  474. if ((iRet =ListMuiFiles(&fileList, dirPath, lang, flavor, binType)) != 0)
  475. {
  476. goto ListContents_EXIT;
  477. }
  478. //
  479. // Add Specific MuiSetup files to a separate file list for output. Do this only in the core flavour
  480. // these files will be printed out as permanent
  481. //
  482. if (flavor == FLV_CORE)
  483. {
  484. File* file;
  485. file = new File( TEXT("muisetup.exe"),
  486. TEXT("MUI"),
  487. TEXT("muisetup.exe"),
  488. dirPath,
  489. TEXT("muisetup.exe"),
  490. 10);
  491. rootfileList.add(file);
  492. file = new File( TEXT("muisetup.hlp"),
  493. TEXT("MUI"),
  494. TEXT("muisetup.hlp"),
  495. dirPath,
  496. TEXT("muisetup.hlp"),
  497. 10);
  498. rootfileList.add(file);
  499. file = new File( TEXT("eula.txt"),
  500. TEXT("MUI"),
  501. TEXT("eula.txt"),
  502. dirPath,
  503. TEXT("eula.txt"),
  504. 10);
  505. rootfileList.add(file);
  506. file = new File( TEXT("relnotes.htm"),
  507. TEXT("MUI"),
  508. TEXT("relnotes.htm"),
  509. dirPath,
  510. TEXT("relnotes.htm"),
  511. 10);
  512. rootfileList.add(file);
  513. file = new File( TEXT("readme.txt"),
  514. TEXT("MUI"),
  515. TEXT("readme.txt"),
  516. dirPath,
  517. TEXT("readme.txt"),
  518. 10);
  519. rootfileList.add(file);
  520. file = new File( TEXT("mui.inf"),
  521. TEXT("MUI"),
  522. TEXT("mui.inf"),
  523. dirPath,
  524. TEXT("mui.inf"),
  525. 10);
  526. rootfileList.add(file);
  527. }
  528. //
  529. // Print compressed directory structure.
  530. //
  531. PrintLine(outputFile, "<Directory Name=\"SOURCEDIR\">TARGETDIR");
  532. if (fileList.isDirId(TRUE))
  533. {
  534. PrintLine(outputFile, " <Directory Name=\"Windows\" LongName=\"Windows\">WindowsFolder");
  535. PrintFileList(&rootfileList, outputFile, TRUE, TRUE, TRUE, FALSE, flavor, binType);
  536. PrintFileList(&fileList, outputFile, TRUE, TRUE, FALSE, FALSE, flavor, binType);
  537. PrintLine(outputFile, " </Directory>");
  538. }
  539. if (fileList.isDirId(FALSE))
  540. {
  541. if (binType == BIN_32)
  542. {
  543. PrintLine(outputFile, " <Directory Name=\"Progra~1\" LongName=\"ProgramFilesFolder\">ProgramFilesFolder");
  544. PrintFileList(&fileList, outputFile, TRUE, FALSE, FALSE, FALSE, flavor, binType);
  545. PrintLine(outputFile, " </Directory>");
  546. }
  547. else if (binType == BIN_64)
  548. {
  549. // First print out all the files for the programfiles64 folder - these corresponds to all the files which are designated for the "Program Files" folder in IA64 environement
  550. PrintLine(outputFile, " <Directory Name=\"Progra~1\" LongName=\"ProgramFilesFolder64\">ProgramFilesFolder64");
  551. PrintFileList(&fileList, outputFile, TRUE, FALSE, FALSE, FALSE, flavor, binType);
  552. PrintLine(outputFile, " </Directory>");
  553. // Now print out all the files for the programfiles folder - these corresponds to all the files which are designated for the "Program Files (X86)" folder in IA64 environement
  554. PrintLine(outputFile, " <Directory Name=\"Progra~2\" LongName=\"ProgramFilesFolder\">ProgramFilesFolder");
  555. PrintFileList(&fileList, outputFile, TRUE, FALSE, FALSE, TRUE, flavor, binType);
  556. PrintLine(outputFile, " </Directory>");
  557. }
  558. }
  559. PrintLine(outputFile, "</Directory>");
  560. //
  561. // Print module footer.
  562. //
  563. PrintLine(outputFile, "</Module>");
  564. ListContents_EXIT:
  565. if (outputFile)
  566. CloseHandle(outputFile);
  567. return (iRet);
  568. }
  569. ///////////////////////////////////////////////////////////////////////////////
  570. //
  571. // ListComponents()
  572. //
  573. // Generate the file list of each components.
  574. // Note that the external components are now temporarily copied to
  575. // MUI\Fallback\LCID\External directory, and then their infs are executed from those
  576. // places during the installation.
  577. //
  578. // The uninstallation happens as before, by executing copies of it from
  579. // MUI\Fallback\LCID - this means that there are now two copies of external components
  580. // on the target drive, but we will have to live with this for now and fix for setup in the
  581. // next release.
  582. //
  583. // Another change to this function is that it is now SKU aware, when building for different
  584. // SKUs, it will check for the SKU directory (see below for example) under the root directory where
  585. // the external components are located in. For CORE, it will check under the root external
  586. // component directory for it and use those if they exist. If it does not exist there will be no
  587. // external component files for that SKU.
  588. //
  589. // Here is a list of SKU directories that the function searches under for:
  590. //
  591. // 1. CORE: \External
  592. // 2. Professional: \External\
  593. // 3. StandardServer: \External\srvinf
  594. // 4. Advanced/EnterpriseServer: \External\entinf
  595. // 5. DatacenterServer: \External\datinf
  596. // 6. BladeServer: \External\blainf
  597. // 7. SmallBusinessServer: \External\sbsinf
  598. //
  599. //
  600. // The components will be parsed/scanned by looking for the component directory in the
  601. // mui.inf file, and each unique component directory will be copied as is to the destination dir.
  602. //
  603. ///////////////////////////////////////////////////////////////////////////////
  604. int ListComponents(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType)
  605. {
  606. HINF hFile;
  607. CHAR muiFilePath[MAX_PATH];
  608. CHAR muiExtCompRoot[MAX_PATH];
  609. DWORD lineCount, lineNum;
  610. INFCONTEXT context;
  611. ComponentList componentList;
  612. Component* component;
  613. CHAR muiSKUDir[20];
  614. HRESULT hr;
  615. //
  616. // check the flavour and assign the appropriate SKU subdirectory
  617. //
  618. switch (flavor)
  619. {
  620. case FLV_PROFESSIONAL:
  621. hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "");
  622. if (!SUCCEEDED(hr)) {
  623. goto exit;
  624. }
  625. break;
  626. case FLV_SERVER:
  627. hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\srvinf\0");
  628. if (!SUCCEEDED(hr)) {
  629. goto exit;
  630. }
  631. break;
  632. case FLV_ADVSERVER:
  633. hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\entinf\0");
  634. if (!SUCCEEDED(hr)) {
  635. goto exit;
  636. }
  637. break;
  638. case FLV_DATACENTER:
  639. hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\dtcinf\0");
  640. if (!SUCCEEDED(hr)) {
  641. goto exit;
  642. }
  643. break;
  644. case FLV_WEBBLADE:
  645. hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\blainf\0");
  646. if (!SUCCEEDED(hr)) {
  647. goto exit;
  648. }
  649. break;
  650. case FLV_SMALLBUSINESS:
  651. hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\sbsinf\0");
  652. if (!SUCCEEDED(hr)) {
  653. goto exit;
  654. }
  655. break;
  656. case FLV_CORE:
  657. hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "");
  658. if (!SUCCEEDED(hr)) {
  659. goto exit;
  660. }
  661. break;
  662. default:
  663. return(0); // invalid sku specified, just exit
  664. break;
  665. }
  666. //
  667. // Create the path to open the mui.inf file
  668. //
  669. hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\mui.inf", dirPath);
  670. if (!SUCCEEDED(hr)) {
  671. goto exit;
  672. }
  673. //
  674. // Open the MUI.INF file.
  675. //
  676. hFile = SetupOpenInfFile(muiFilePath, NULL, INF_STYLE_WIN4, NULL);
  677. if (hFile == INVALID_HANDLE_VALUE)
  678. {
  679. return (-1);
  680. }
  681. //
  682. // Get the number of component.
  683. //
  684. lineCount = (UINT)SetupGetLineCount(hFile, TEXT("Components"));
  685. if (lineCount > 0)
  686. {
  687. //
  688. // Go through all component of the list.
  689. //
  690. CHAR componentName[MAX_PATH];
  691. CHAR componentFolder[MAX_PATH];
  692. CHAR componentInf[MAX_PATH];
  693. CHAR componentInst[MAX_PATH];
  694. for (lineNum = 0; lineNum < lineCount; lineNum++)
  695. {
  696. if (SetupGetLineByIndex(hFile, TEXT("Components"), lineNum, &context) &&
  697. SetupGetStringField(&context, 0, componentName, MAX_PATH, NULL) &&
  698. SetupGetStringField(&context, 1, componentFolder, MAX_PATH, NULL) &&
  699. SetupGetStringField(&context, 2, componentInf, MAX_PATH, NULL) &&
  700. SetupGetStringField(&context, 3, componentInst, MAX_PATH, NULL))
  701. {
  702. //
  703. // Create the components and add to the list, but only if the componentFolder is unique, since we will be copying
  704. // all the files in the same component dirs we shouldn't miss anything
  705. //
  706. BOOL bUnique = TRUE;
  707. Component *pCIndex = NULL;
  708. pCIndex = componentList.getFirst();
  709. while (pCIndex)
  710. {
  711. if (_strnicmp(pCIndex->getFolderName(), componentFolder, strlen(componentFolder)) == 0)
  712. {
  713. bUnique = FALSE;
  714. break;
  715. }
  716. pCIndex = pCIndex->getNext();
  717. }
  718. if (bUnique)
  719. {
  720. if( (component = new Component( componentName,
  721. componentFolder,
  722. componentInf,
  723. componentInst)) != NULL)
  724. {
  725. componentList.add(component);
  726. }
  727. }
  728. }
  729. }
  730. }
  731. //
  732. // Close inf handle
  733. //
  734. SetupCloseInfFile(hFile);
  735. //
  736. // Output component information
  737. //
  738. component = componentList.getFirst();
  739. while (component != NULL)
  740. {
  741. CHAR componentInfPath[MAX_PATH];
  742. CHAR componentPath[MAX_PATH];
  743. CHAR SKUSearchPath[MAX_PATH];
  744. CHAR searchPath[MAX_PATH];
  745. CHAR srcFileName[MAX_PATH];
  746. CHAR dstFileName[MAX_PATH];
  747. CHAR shortFileName[MAX_PATH];
  748. CHAR tempShortPath[MAX_PATH];
  749. File* file;
  750. HANDLE hFind;
  751. WIN32_FIND_DATA wfdFindData;
  752. BOOL bFinished = FALSE;
  753. //
  754. // Compute the component inf path, we need to get it from the compressed version from old build
  755. // e.g. C:\nt.relbins.x86fre\psu\mui\release\x86\Temp\psu\ro.mui\i386
  756. //
  757. if (binType == BIN_32)
  758. {
  759. hr = StringCchPrintfA(componentInfPath, ARRAYLEN(componentInfPath),
  760. "%s\\release\\x86\\Temp\\%s\\%s.mui\\i386\\%s%s\\%s",
  761. dirPath,
  762. sLDirName,
  763. lang,
  764. component->getFolderName(),
  765. muiSKUDir,
  766. component->getInfName());
  767. if (!SUCCEEDED(hr)) {
  768. goto exit;
  769. }
  770. hr = StringCchPrintfA(componentPath, ARRAYLEN(componentPath),
  771. "%s\\release\\x86\\Temp\\%s\\%s.mui\\i386\\%s%s",
  772. dirPath,
  773. sLDirName,
  774. lang,
  775. component->getFolderName(),
  776. muiSKUDir);
  777. if (!SUCCEEDED(hr)) {
  778. goto exit;
  779. }
  780. hr = StringCchPrintfA(SKUSearchPath, ARRAYLEN(SKUSearchPath),
  781. "%s\\release\\x86\\Temp\\%s\\%s.mui\\i386\\%s",
  782. dirPath,
  783. sLDirName,
  784. lang,
  785. component->getFolderName());
  786. if (!SUCCEEDED(hr)) {
  787. goto exit;
  788. }
  789. }
  790. else
  791. {
  792. hr = StringCchPrintfA(componentInfPath, ARRAYLEN(componentInfPath),
  793. "%s\\release\\ia64\\Temp\\%s\\%s.mui\\ia64\\%s%s\\%s",
  794. dirPath,
  795. sLDirName,
  796. lang,
  797. component->getFolderName(),
  798. muiSKUDir,
  799. component->getInfName());
  800. if (!SUCCEEDED(hr)) {
  801. goto exit;
  802. }
  803. hr = StringCchPrintfA(componentPath, ARRAYLEN(componentPath),
  804. "%s\\release\\ia64\\Temp\\%s\\%s.mui\\ia64\\%s%s",
  805. dirPath,
  806. sLDirName,
  807. lang,
  808. component->getFolderName(),
  809. muiSKUDir);
  810. if (!SUCCEEDED(hr)) {
  811. goto exit;
  812. }
  813. hr = StringCchPrintfA(SKUSearchPath, ARRAYLEN(SKUSearchPath),
  814. "%s\\release\\ia64\\Temp\\%s\\%s.mui\\ia64\\%s",
  815. dirPath,
  816. sLDirName,
  817. lang,
  818. component->getFolderName());
  819. if (!SUCCEEDED(hr)) {
  820. goto exit;
  821. }
  822. }
  823. // if there are any other subdirectory under this component path, then the root directory files are actually
  824. // for the PRO SKU, and we should not add this component to CORE
  825. if ((FLV_CORE == flavor) && ContainSKUDirs(SKUSearchPath))
  826. {
  827. component = component->getNext();
  828. if (!bSilence)
  829. {
  830. printf("\n*** SKU subdirectory detected for this component and flavour is CORE, skipping component. %s\n", componentInfPath);
  831. }
  832. continue;
  833. }
  834. // if there are no other subdirectory under this component path, then the root directory files are actually
  835. // for the CORE SKU, and we should not add this component to PRO
  836. // this is one compromise we have to make right now since the NT SKU subdirs does not give us the ability to distinguish
  837. // between PRO SKU and something that is for every platform
  838. if ((FLV_PROFESSIONAL == flavor) && !ContainSKUDirs(SKUSearchPath))
  839. {
  840. component = component->getNext();
  841. if (!bSilence)
  842. {
  843. printf("\n*** SKU subdirectory not detected for this component and flavour is PRO, skipping component. %s\n", componentInfPath);
  844. }
  845. continue;
  846. }
  847. // form the temp component path on the target
  848. hr = StringCchPrintfA(muiExtCompRoot, ARRAYLEN(muiExtCompRoot), "MUI\\FALLBACK\\%04x\\External\\%s", gBuildNumber, component->getFolderName());
  849. if (!SUCCEEDED(hr)) {
  850. goto exit;
  851. }
  852. hr = StringCchPrintfA(searchPath, ARRAYLEN(searchPath), "%s\\*.*", componentPath);
  853. if (!SUCCEEDED(hr)) {
  854. goto exit;
  855. }
  856. if (!bSilence)
  857. {
  858. printf("\n*** Source component inf path is %s\n", componentInfPath);
  859. printf("\n*** Source component folder path is %s\n", componentPath);
  860. printf("\n*** Destination directory for this component is %s\n", muiExtCompRoot);
  861. }
  862. // Get a list of all the files in the component folder
  863. hFind = FindFirstFile(searchPath, &wfdFindData);
  864. if (hFind == INVALID_HANDLE_VALUE)
  865. {
  866. if (!bSilence)
  867. {
  868. printf("\n*** No files found in the component directory %s\n", muiExtCompRoot);
  869. }
  870. component = component->getNext();
  871. continue; // skip this component
  872. }
  873. else
  874. {
  875. bFinished = FALSE;
  876. while (!bFinished)
  877. {
  878. // only process files, not directories
  879. if ((wfdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  880. {
  881. if (!bSilence)
  882. {
  883. printf("\n*** Filename is %s\n", wfdFindData.cFileName);
  884. printf("\n*** Alternate Filename is %s\n", wfdFindData.cAlternateFileName);
  885. }
  886. hr = StringCchCopyA(srcFileName, ARRAYLEN(srcFileName), wfdFindData.cFileName);
  887. if (!SUCCEEDED(hr)) {
  888. goto exit;
  889. }
  890. if (!(wfdFindData.cAlternateFileName) || (strlen(wfdFindData.cAlternateFileName) == 0))
  891. {
  892. hr = StringCchCopyA(shortFileName, ARRAYLEN(shortFileName), wfdFindData.cFileName);
  893. if (!SUCCEEDED(hr)) {
  894. goto exit;
  895. }
  896. }
  897. else
  898. {
  899. hr = StringCchCopyA(shortFileName, ARRAYLEN(shortFileName), wfdFindData.cAlternateFileName);
  900. if (!SUCCEEDED(hr)) {
  901. goto exit;
  902. }
  903. }
  904. // here, we also need to rename all the files that ends with a .mui extension to .mu_ - since the infs are
  905. // expecting this.
  906. // RenameMuiExtension(shortFileName);
  907. hr = StringCchCopyA(dstFileName, ARRAYLEN(dstFileName), srcFileName);
  908. if (!SUCCEEDED(hr)) {
  909. goto exit;
  910. }
  911. // RenameMuiExtension(dstFileName);
  912. if ((file = new File(shortFileName,
  913. muiExtCompRoot,
  914. dstFileName,
  915. componentPath,
  916. srcFileName,
  917. 10)) != NULL)
  918. {
  919. dirList->add(file);
  920. }
  921. }
  922. else
  923. {
  924. if (!bSilence)
  925. {
  926. printf("\n*** Found a directory in the component dir %s\n", wfdFindData.cFileName);
  927. }
  928. }
  929. if (!FindNextFile(hFind, &wfdFindData))
  930. {
  931. bFinished = TRUE;
  932. }
  933. }
  934. }
  935. //
  936. // Next Component
  937. //
  938. component = component->getNext();
  939. }
  940. return 0;
  941. exit:
  942. printf("Error in ListComponents\n");
  943. return 1;
  944. }
  945. ///////////////////////////////////////////////////////////////////////////////
  946. //
  947. // ListMuiFiles()
  948. //
  949. // Generate the file list for MUI.
  950. //
  951. ///////////////////////////////////////////////////////////////////////////////
  952. int ListMuiFiles(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType)
  953. {
  954. HINF hFile;
  955. CHAR muiFilePath[MAX_PATH];
  956. CHAR muiFileSearchPath[MAX_PATH];
  957. int lineCount, lineNum, fieldCount;
  958. INFCONTEXT context;
  959. FileLayoutExceptionList exceptionList;
  960. WIN32_FIND_DATA findData;
  961. HANDLE fileHandle;
  962. File* file;
  963. HRESULT hr;
  964. //
  965. // Create the path to open the mui.inf file
  966. //
  967. hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\mui.inf", dirPath);
  968. if (!SUCCEEDED(hr)) {
  969. goto exit;
  970. }
  971. //
  972. // Open the MUI.INF file.
  973. //
  974. hFile = SetupOpenInfFile(muiFilePath, NULL, INF_STYLE_WIN4, NULL);
  975. if (hFile == INVALID_HANDLE_VALUE)
  976. {
  977. return (-1);
  978. }
  979. //
  980. // Get the number of file exception.
  981. //
  982. lineCount = (UINT)SetupGetLineCount(hFile, TEXT("File_Layout"));
  983. if (lineCount > 0)
  984. {
  985. //
  986. // Go through all file exception of the list.
  987. //
  988. CHAR originFilename[MAX_PATH];
  989. CHAR destFilename[MAX_PATH];
  990. CHAR fileFlavor[30];
  991. DWORD dwFlavor;
  992. for (lineNum = 0; lineNum < lineCount; lineNum++)
  993. {
  994. if (SetupGetLineByIndex(hFile, TEXT("File_Layout"), lineNum, &context) &&
  995. (fieldCount = SetupGetFieldCount(&context)))
  996. {
  997. if (SetupGetStringField(&context, 0, originFilename, MAX_PATH, NULL) &&
  998. SetupGetStringField(&context, 1, destFilename, MAX_PATH, NULL))
  999. {
  1000. FileLayout* fileException;
  1001. dwFlavor = 0;
  1002. for(int fieldId = 2; fieldId <= fieldCount; fieldId++)
  1003. {
  1004. if(SetupGetStringField(&context, fieldId, fileFlavor, MAX_PATH, NULL))
  1005. {
  1006. switch(*fileFlavor)
  1007. {
  1008. case('p'):
  1009. case('P'):
  1010. dwFlavor |= FLV_PROFESSIONAL;
  1011. break;
  1012. case('s'):
  1013. case('S'):
  1014. dwFlavor |= FLV_SERVER;
  1015. break;
  1016. case('d'):
  1017. case('D'):
  1018. dwFlavor |= FLV_DATACENTER;
  1019. break;
  1020. case('a'):
  1021. case('A'):
  1022. dwFlavor |= FLV_ADVSERVER;
  1023. break;
  1024. case('b'):
  1025. case('B'):
  1026. dwFlavor |= FLV_WEBBLADE;
  1027. break;
  1028. case('l'):
  1029. case('L'):
  1030. dwFlavor |= FLV_SMALLBUSINESS;
  1031. break;
  1032. }
  1033. }
  1034. }
  1035. //
  1036. // Add only information needed for this specific flavor.
  1037. //
  1038. fileException = new FileLayout(originFilename, destFilename, dwFlavor);
  1039. exceptionList.insert(fileException);
  1040. }
  1041. }
  1042. }
  1043. }
  1044. //
  1045. // Close inf handle
  1046. //
  1047. SetupCloseInfFile(hFile);
  1048. //
  1049. // Compute the binary source path.
  1050. //
  1051. if (binType == BIN_32)
  1052. {
  1053. hr = StringCchPrintfA(muiFileSearchPath, ARRAYLEN(muiFileSearchPath), "%s\\%s\\i386.uncomp", dirPath, lang);
  1054. if (!SUCCEEDED(hr)) {
  1055. goto exit;
  1056. }
  1057. hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\%s\\i386.uncomp\\*.*", dirPath, lang);
  1058. if (!SUCCEEDED(hr)) {
  1059. goto exit;
  1060. }
  1061. }
  1062. else
  1063. {
  1064. hr = StringCchPrintfA(muiFileSearchPath, ARRAYLEN(muiFileSearchPath), "%s\\%s\\ia64.uncomp", dirPath, lang);
  1065. if (!SUCCEEDED(hr)) {
  1066. goto exit;
  1067. }
  1068. hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\%s\\ia64.uncomp\\*.*", dirPath, lang);
  1069. if (!SUCCEEDED(hr)) {
  1070. goto exit;
  1071. }
  1072. }
  1073. //
  1074. // Scan uncomp source directory for file information
  1075. //
  1076. if ((fileHandle = FindFirstFile(muiFilePath, &findData)) != INVALID_HANDLE_VALUE)
  1077. {
  1078. //
  1079. // Look for files
  1080. //
  1081. do
  1082. {
  1083. LPSTR extensionPtr;
  1084. INT dirIdentifier = 0;
  1085. CHAR destDirectory[MAX_PATH] = {0};
  1086. CHAR destName[MAX_PATH] = {0};
  1087. FileLayout* fileException = NULL;
  1088. //
  1089. // Scan only files at this level.
  1090. //
  1091. if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1092. {
  1093. continue;
  1094. }
  1095. //
  1096. // Search the extension to determine the destination location and possibly
  1097. // exclude file destined for Personal.
  1098. //
  1099. if ((extensionPtr = strrchr(findData.cFileName, '.')) != NULL)
  1100. {
  1101. if( (_tcsicmp(extensionPtr, TEXT(".chm")) == 0) ||
  1102. (_tcsicmp(extensionPtr, TEXT(".chq")) == 0) ||
  1103. (_tcsicmp(extensionPtr, TEXT(".cnt")) == 0) ||
  1104. (_tcsicmp(extensionPtr, TEXT(".hlp")) == 0))
  1105. {
  1106. dirIdentifier = 18;
  1107. hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "MUI\\%04x", gBuildNumber);
  1108. if (!SUCCEEDED(hr)) {
  1109. goto exit;
  1110. }
  1111. }
  1112. else if (_tcsicmp(extensionPtr, TEXT(".mfl")) == 0)
  1113. {
  1114. dirIdentifier = 11;
  1115. hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "wbem\\MUI\\%04x", gBuildNumber);
  1116. if (!SUCCEEDED(hr)) {
  1117. goto exit;
  1118. }
  1119. }
  1120. else if (_tcsicmp(findData.cFileName, TEXT("hhctrlui.dll")) == 0)
  1121. {
  1122. dirIdentifier = 11;
  1123. hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "MUI\\%04x", gBuildNumber);
  1124. if (!SUCCEEDED(hr)) {
  1125. goto exit;
  1126. }
  1127. }
  1128. else
  1129. {
  1130. dirIdentifier = 10;
  1131. hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "MUI\\FALLBACK\\%04x", gBuildNumber);
  1132. if (!SUCCEEDED(hr)) {
  1133. goto exit;
  1134. }
  1135. }
  1136. }
  1137. //
  1138. // We need to remove the .MUI extension before passing the filename to search in the
  1139. // mui.inf file rename section
  1140. //
  1141. CHAR strTemp[MAX_PATH];
  1142. BOOL bBinaryFile = FALSE;
  1143. hr = StringCchCopyA(strTemp, ARRAYLEN(strTemp), findData.cFileName);
  1144. if (!SUCCEEDED(hr)){
  1145. goto exit;
  1146. }
  1147. // remove the extension .mui if it is there
  1148. if ((extensionPtr = strrchr(strTemp, '.')) != NULL)
  1149. {
  1150. if (_tcsicmp(extensionPtr, TEXT(".mui")) == 0)
  1151. {
  1152. *extensionPtr = NULL;
  1153. bBinaryFile = TRUE;
  1154. }
  1155. }
  1156. //
  1157. // Search for different destination name in the exception list.
  1158. //
  1159. if ((fileException = exceptionList.search(strTemp)) != NULL )
  1160. {
  1161. if (!bSilence)
  1162. {
  1163. printf("Source file %s exists in mui.inf.\n", findData.cFileName);
  1164. }
  1165. //
  1166. // Verify it's the needed flavor
  1167. // also check that it's not in every flavour if we are not
  1168. // building CORE merge modules
  1169. //
  1170. if ((fileException->isFlavor(flavor)) &&
  1171. !((flavor != FLV_CORE) &&
  1172. (fileException->isFlavor(FLV_ADVSERVER)) &&
  1173. (fileException->isFlavor(FLV_SERVER)) &&
  1174. (fileException->isFlavor(FLV_DATACENTER)) &&
  1175. (fileException->isFlavor(FLV_WEBBLADE)) &&
  1176. (fileException->isFlavor(FLV_SMALLBUSINESS))))
  1177. {
  1178. if (!bSilence)
  1179. {
  1180. printf("Flavor is not CORE, Source file %s is for the specified SKU.\n", findData.cFileName);
  1181. }
  1182. if (bBinaryFile)
  1183. {
  1184. hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s.mui", fileException->getDestFileName());
  1185. }
  1186. else
  1187. {
  1188. hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s", fileException->getDestFileName());
  1189. }
  1190. if (!SUCCEEDED(hr))
  1191. {
  1192. goto exit;
  1193. }
  1194. }
  1195. else if ((flavor == FLV_CORE) &&
  1196. (fileException->isFlavor(FLV_ADVSERVER)) &&
  1197. (fileException->isFlavor(FLV_SERVER)) &&
  1198. (fileException->isFlavor(FLV_DATACENTER)) &&
  1199. (fileException->isFlavor(FLV_WEBBLADE)) &&
  1200. (fileException->isFlavor(FLV_SMALLBUSINESS)))
  1201. {
  1202. if (!bSilence)
  1203. {
  1204. printf("Flavor is CORE, Source file %s is in every SKU.\n", findData.cFileName);
  1205. }
  1206. if (bBinaryFile)
  1207. {
  1208. hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s.mui", fileException->getDestFileName());
  1209. }
  1210. else
  1211. {
  1212. hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s", fileException->getDestFileName());
  1213. }
  1214. if (!SUCCEEDED(hr))
  1215. {
  1216. goto exit;
  1217. }
  1218. }
  1219. else
  1220. {
  1221. if (!bSilence)
  1222. {
  1223. printf("Source file %s (destination name %s) is not in this SKU.\n", findData.cFileName, fileException->getDestFileName() ? fileException->getDestFileName() : findData.cFileName);
  1224. }
  1225. //
  1226. // Skip the file. Not need in this flavor.
  1227. //
  1228. continue;
  1229. }
  1230. }
  1231. else
  1232. {
  1233. CHAR strOrigName[MAX_PATH];
  1234. hr = StringCchCopyA(strOrigName, ARRAYLEN(strOrigName), findData.cFileName);
  1235. if (!SUCCEEDED(hr)){
  1236. goto exit;
  1237. }
  1238. // remove the extension .mui if it is there
  1239. if ((extensionPtr = strrchr(strOrigName, '.')) != NULL)
  1240. {
  1241. if (_tcsicmp(extensionPtr, TEXT(".mui")) == 0)
  1242. {
  1243. *extensionPtr = NULL;
  1244. if (!bSilence)
  1245. {
  1246. printf("Filename is %s, original filename is %s.\n", findData.cFileName, strOrigName);
  1247. }
  1248. }
  1249. }
  1250. if (IsFileForSKU(strOrigName, flavor, binType, &exceptionList))
  1251. {
  1252. hr = StringCchCopyA(destName, ARRAYLEN(destName), findData.cFileName);
  1253. if (!SUCCEEDED(hr)){
  1254. goto exit;
  1255. }
  1256. }
  1257. else
  1258. {
  1259. continue;
  1260. }
  1261. }
  1262. //
  1263. // Create a file
  1264. //
  1265. CHAR sfilename[MAX_PATH];
  1266. GetFileShortName(destName, sfilename, FALSE);
  1267. if (file = new File(sfilename,
  1268. destDirectory,
  1269. destName,
  1270. muiFileSearchPath,
  1271. findData.cFileName,
  1272. dirIdentifier))
  1273. {
  1274. dirList->add(file);
  1275. }
  1276. }
  1277. while (FindNextFile(fileHandle, &findData));
  1278. FindClose(fileHandle);
  1279. }
  1280. return 0;
  1281. exit:
  1282. printf("Error in ListMuiFiles\n");
  1283. return 1;
  1284. }
  1285. ///////////////////////////////////////////////////////////////////////////////
  1286. //
  1287. // ValidateLanguage()
  1288. //
  1289. // Verify if the language given is valid and checks is the files are
  1290. // available.
  1291. //
  1292. ///////////////////////////////////////////////////////////////////////////////
  1293. BOOL ValidateLanguage(LPSTR dirPath, LPSTR langName, DWORD binType)
  1294. {
  1295. CHAR langPath[MAX_PATH] = {0};
  1296. HRESULT hr;
  1297. //
  1298. // Check if the binary type in order to determine the right path.
  1299. //
  1300. if (binType == BIN_32)
  1301. {
  1302. hr = StringCchPrintfA(langPath, ARRAYLEN(langPath), "%s\\%s\\i386.uncomp", dirPath, langName);
  1303. if (!SUCCEEDED(hr)) {
  1304. goto exit;
  1305. }
  1306. }
  1307. else
  1308. {
  1309. hr = StringCchPrintfA(langPath, ARRAYLEN(langPath), "%s\\%s\\ia64.uncomp", dirPath, langName);
  1310. if (!SUCCEEDED(hr)) {
  1311. goto exit;
  1312. }
  1313. }
  1314. return (DirectoryExist(langPath));
  1315. exit:
  1316. printf("Error in ValidateLanguage \n");
  1317. return FALSE;
  1318. }
  1319. ///////////////////////////////////////////////////////////////////////////////
  1320. //
  1321. // DirectoryExist()
  1322. //
  1323. // Verify if the given directory exists and contains files.
  1324. //
  1325. ///////////////////////////////////////////////////////////////////////////////
  1326. BOOL DirectoryExist(LPSTR dirPath)
  1327. {
  1328. WIN32_FIND_DATA FindData;
  1329. HANDLE FindHandle;
  1330. //
  1331. // Sanity check.
  1332. //
  1333. if (dirPath == NULL)
  1334. {
  1335. return FALSE;
  1336. }
  1337. //
  1338. // See if the language group directory exists.
  1339. //
  1340. FindHandle = FindFirstFile(dirPath, &FindData);
  1341. if (FindHandle != INVALID_HANDLE_VALUE)
  1342. {
  1343. FindClose(FindHandle);
  1344. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1345. {
  1346. //
  1347. // Return success.
  1348. //
  1349. return (TRUE);
  1350. }
  1351. }
  1352. //
  1353. // Return failure.
  1354. //
  1355. if (!bSilence)
  1356. {
  1357. printf("ERR[%s]: No files found in the directory.\n", dirPath);
  1358. }
  1359. return (FALSE);
  1360. }
  1361. ///////////////////////////////////////////////////////////////////////////////
  1362. //
  1363. // ConvertLanguage()
  1364. //
  1365. // Look into mui.inf file for the corresponding language identifier.
  1366. //
  1367. ///////////////////////////////////////////////////////////////////////////////
  1368. WORD ConvertLanguage(LPSTR dirPath, LPSTR langName)
  1369. {
  1370. HINF hFile;
  1371. CHAR muiFilePath[MAX_PATH];
  1372. CHAR muiLang[30];
  1373. UINT lineCount, lineNum;
  1374. INFCONTEXT context;
  1375. DWORD langId = 0x00000000;
  1376. HRESULT hr;
  1377. //
  1378. // Create the path to open the mui.inf file
  1379. //
  1380. hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\mui.inf", dirPath);
  1381. if (!SUCCEEDED(hr)) {
  1382. goto exit;
  1383. }
  1384. hr = StringCchPrintfA(muiLang, ARRAYLEN(muiLang), "%s.MUI", langName);
  1385. if (!SUCCEEDED(hr)) {
  1386. goto exit;
  1387. }
  1388. //
  1389. // Open the MUI.INF file.
  1390. //
  1391. hFile = SetupOpenInfFile(muiFilePath, NULL, INF_STYLE_WIN4, NULL);
  1392. if (hFile == INVALID_HANDLE_VALUE)
  1393. {
  1394. return (0x0000);
  1395. }
  1396. //
  1397. // Get the number of Language.
  1398. //
  1399. lineCount = (UINT)SetupGetLineCount(hFile, TEXT("Languages"));
  1400. if (lineCount > 0)
  1401. {
  1402. //
  1403. // Go through all language of the list to find a .
  1404. //
  1405. CHAR langID[MAX_PATH];
  1406. CHAR name[MAX_PATH];
  1407. for (lineNum = 0; lineNum < lineCount; lineNum++)
  1408. {
  1409. if (SetupGetLineByIndex(hFile, TEXT("Languages"), lineNum, &context) &&
  1410. SetupGetStringField(&context, 0, langID, MAX_PATH, NULL) &&
  1411. SetupGetStringField(&context, 1, name, MAX_PATH, NULL))
  1412. {
  1413. if ( _tcsicmp(name, muiLang) == 0)
  1414. {
  1415. langId = TransNum(langID);
  1416. SetupCloseInfFile(hFile);
  1417. return (WORD)(langId);
  1418. }
  1419. }
  1420. }
  1421. }
  1422. //
  1423. // Close inf handle
  1424. //
  1425. SetupCloseInfFile(hFile);
  1426. exit:
  1427. printf("Error in CovnertLanguage \n");
  1428. return (0x0000);
  1429. }
  1430. ////////////////////////////////////////////////////////////////////////////
  1431. //
  1432. // PrintFileList
  1433. //
  1434. // Print a file list in XML format.
  1435. //
  1436. ////////////////////////////////////////////////////////////////////////////
  1437. void PrintFileList(FileList* list, HANDLE hFile, BOOL compressed, BOOL bWinDir, BOOL bPermanent, BOOL bX86OnIA64, DWORD flavor, DWORD binType)
  1438. {
  1439. CHAR szSKUCondition[4096];
  1440. CHAR szIsWin64[4];
  1441. BOOL bPrintCondition = GetSKUConditionString(szSKUCondition, flavor);
  1442. HRESULT hr;
  1443. if (binType == BIN_32)
  1444. {
  1445. hr = StringCchCopyA(szIsWin64, ARRAYLEN(szIsWin64),"no");
  1446. }
  1447. else
  1448. {
  1449. hr = StringCchCopyA(szIsWin64, ARRAYLEN(szIsWin64),"yes");
  1450. }
  1451. if (compressed)
  1452. {
  1453. File* item;
  1454. CHAR itemDescription[4096];
  1455. CHAR spaces[30];
  1456. int j;
  1457. item = list->getFirst();
  1458. while (item != NULL)
  1459. {
  1460. LPSTR refDirPtr = NULL;
  1461. LPSTR dirPtr = NULL;
  1462. CHAR dirName[MAX_PATH];
  1463. CHAR dirName2[MAX_PATH];
  1464. CHAR dirObjectName[MAX_PATH+1];
  1465. LPSTR dirPtr2 = NULL;
  1466. LPSTR dirLvlPtr = NULL;
  1467. INT dirLvlCnt = 0;
  1468. BOOL componentInit = FALSE;
  1469. BOOL directoryInit = FALSE;
  1470. Uuid* uuid;
  1471. File* toBeRemoved;
  1472. CHAR fileObjectName[MAX_PATH+1];
  1473. UINT matchCount;
  1474. //
  1475. // Check destination directory.
  1476. //
  1477. if (item->isWindowsDir() != bWinDir)
  1478. {
  1479. item = item->getNext();
  1480. continue;
  1481. }
  1482. //
  1483. // Check if the destination directory is base dir
  1484. //
  1485. if (*(item->getDirectoryDestination()) == '\0')
  1486. {
  1487. //
  1488. // Component
  1489. //
  1490. uuid = new Uuid();
  1491. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1492. if (FALSE == bPermanent) {
  1493. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1494. if (!SUCCEEDED(hr)) {
  1495. goto exit;
  1496. }
  1497. }
  1498. else {
  1499. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Permanent='yes' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1500. if (!SUCCEEDED(hr)) {
  1501. goto exit;
  1502. }
  1503. }
  1504. delete uuid;
  1505. PrintLine(hFile, itemDescription);
  1506. // print a condition line for this component, if needed
  1507. if (TRUE == bPrintCondition)
  1508. {
  1509. PrintLine(hFile, szSKUCondition);
  1510. }
  1511. //
  1512. // File
  1513. //
  1514. for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1515. removeSpace(item->getName(), fileObjectName);
  1516. ReplaceInvalidChars(fileObjectName);
  1517. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription),
  1518. "%s<File Name=\"%s\" LongName=\"%s\" src=\"%s\\%s\">_%s.%x.%i</File>",
  1519. spaces,
  1520. item->getShortName(),
  1521. item->getName(),
  1522. item->getSrcDir(),
  1523. item->getSrcName(),
  1524. fileObjectName,
  1525. flavor,
  1526. dwComponentCounter);
  1527. if (!SUCCEEDED(hr)) {
  1528. goto exit;
  1529. }
  1530. PrintLine(hFile, itemDescription);
  1531. //
  1532. // </Component>
  1533. //
  1534. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1535. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Component>", spaces);
  1536. if (!SUCCEEDED(hr)) {
  1537. goto exit;
  1538. }
  1539. PrintLine(hFile, itemDescription);
  1540. dwComponentCounter++;
  1541. toBeRemoved = item;
  1542. item = item->getNext();
  1543. list->remove(toBeRemoved);
  1544. continue;
  1545. }
  1546. //
  1547. // Print directory
  1548. //
  1549. hr = StringCchCopyA(dirName, ARRAYLEN(dirName), item->getDirectoryDestination());
  1550. if(!SUCCEEDED(hr)) {
  1551. goto exit;
  1552. }
  1553. dirPtr = dirName;
  1554. refDirPtr = dirPtr;
  1555. CHAR sdirname[MAX_PATH];
  1556. while (dirPtr != NULL)
  1557. {
  1558. dirLvlPtr = strchr(dirPtr, '\\');
  1559. if (dirLvlPtr != NULL)
  1560. {
  1561. *dirLvlPtr = '\0';
  1562. for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1563. hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName),dirPtr);
  1564. if(!SUCCEEDED(hr)) {
  1565. goto exit;
  1566. }
  1567. ReplaceInvalidChars(dirObjectName);
  1568. GetFileShortName(dirPtr, sdirname, FALSE);
  1569. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Directory Name=\"%s\" LongName=\"%s\">_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter);
  1570. if (!SUCCEEDED(hr)) {
  1571. goto exit;
  1572. }
  1573. dwDirectoryCounter++;
  1574. PrintLine(hFile, itemDescription);
  1575. dirPtr = dirLvlPtr + 1;
  1576. dirLvlCnt++;
  1577. //
  1578. // Print all file under this specific directory
  1579. //
  1580. hr = StringCchCopyA(dirName2, ARRAYLEN(dirName2), item->getDirectoryDestination());
  1581. if(!SUCCEEDED(hr)) {
  1582. goto exit;
  1583. }
  1584. dirName2[dirLvlPtr-refDirPtr] = '\0';
  1585. File* sameLvlItem = NULL;
  1586. matchCount = 0;
  1587. while((sameLvlItem = list->search(item, dirName2)) != NULL)
  1588. {
  1589. //
  1590. // Component
  1591. //
  1592. if (!componentInit)
  1593. {
  1594. uuid = new Uuid();
  1595. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1596. if (FALSE == bPermanent) {
  1597. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1598. if (!SUCCEEDED(hr)) {
  1599. goto exit;
  1600. }
  1601. }
  1602. else{
  1603. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Permanent='yes' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1604. if (!SUCCEEDED(hr)) {
  1605. goto exit;
  1606. }
  1607. }
  1608. delete uuid;
  1609. PrintLine(hFile, itemDescription);
  1610. dwComponentCounter++;
  1611. componentInit = TRUE;
  1612. // print a condition line for this component, if needed
  1613. if (TRUE == bPrintCondition)
  1614. {
  1615. PrintLine(hFile, szSKUCondition);
  1616. }
  1617. }
  1618. //
  1619. // File
  1620. //
  1621. matchCount++;
  1622. for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1623. removeSpace(sameLvlItem->getName(), fileObjectName);
  1624. ReplaceInvalidChars(fileObjectName);
  1625. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription),
  1626. "%s<File Name=\"%s\" LongName=\"%s\" src=\"%s\\%s\">_%s.%x.%i</File>",
  1627. spaces,
  1628. sameLvlItem->getShortName(),
  1629. sameLvlItem->getName(),
  1630. sameLvlItem->getSrcDir(),
  1631. sameLvlItem->getSrcName(),
  1632. fileObjectName,
  1633. flavor,
  1634. dwComponentCounter);
  1635. if (!SUCCEEDED(hr)) {
  1636. goto exit;
  1637. }
  1638. PrintLine(hFile, itemDescription);
  1639. list->remove(sameLvlItem);
  1640. }
  1641. // kenhsu -this is incorrect, the file we are looking at may be deeper in the directory structure, we shouldn't print it out here
  1642. // until we have finished recursing its destination directory.
  1643. /* if (matchCount)
  1644. {
  1645. //
  1646. // File
  1647. //
  1648. for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1649. removeSpace(item->getName(), fileObjectName);
  1650. ReplaceInvalidChars(fileObjectName);
  1651. sprintf( itemDescription,
  1652. "%s<File Name=\"%s\" LongName=\"%s\" src=\"%s\\%s\">%s.%i</File>",
  1653. spaces,
  1654. item->getShortName(),
  1655. item->getName(),
  1656. item->getSrcDir(),
  1657. item->getSrcName(),
  1658. fileObjectName,
  1659. dwComponentCounter);
  1660. PrintLine(hFile, itemDescription);
  1661. dirPtr = NULL;
  1662. }
  1663. */
  1664. //
  1665. // Close component
  1666. //
  1667. if (componentInit)
  1668. {
  1669. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1670. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Component>", spaces);
  1671. if (!SUCCEEDED(hr)) {
  1672. goto exit;
  1673. }
  1674. PrintLine(hFile, itemDescription);
  1675. componentInit = FALSE;
  1676. }
  1677. //
  1678. // Close directory
  1679. //
  1680. if (directoryInit)
  1681. {
  1682. dirLvlCnt--;
  1683. for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1684. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Directory>", spaces);
  1685. if (!SUCCEEDED(hr)) {
  1686. goto exit;
  1687. }
  1688. PrintLine(hFile, itemDescription);
  1689. directoryInit = FALSE;
  1690. }
  1691. }
  1692. else
  1693. {
  1694. if (!directoryInit)
  1695. {
  1696. for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1697. hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName), dirPtr);
  1698. if(!SUCCEEDED(hr)) {
  1699. goto exit;
  1700. }
  1701. ReplaceInvalidChars(dirObjectName);
  1702. GetFileShortName(dirPtr, sdirname, FALSE);
  1703. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Directory Name=\"%s\" LongName=\"%s\">_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter);
  1704. if (!SUCCEEDED(hr)) {
  1705. goto exit;
  1706. }
  1707. dwDirectoryCounter++;
  1708. PrintLine(hFile, itemDescription);
  1709. dirLvlCnt++;
  1710. directoryInit = TRUE;
  1711. }
  1712. //
  1713. // Component
  1714. //
  1715. if (!componentInit)
  1716. {
  1717. uuid = new Uuid();
  1718. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1719. if (FALSE == bPermanent) {
  1720. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1721. if (!SUCCEEDED(hr)) {
  1722. goto exit;
  1723. }
  1724. }
  1725. else {
  1726. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Permanent='yes' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1727. if (!SUCCEEDED(hr)) {
  1728. goto exit;
  1729. }
  1730. }
  1731. delete uuid;
  1732. PrintLine(hFile, itemDescription);
  1733. componentInit = TRUE;
  1734. // print a condition line for this component, if needed
  1735. if (TRUE == bPrintCondition)
  1736. {
  1737. PrintLine(hFile, szSKUCondition);
  1738. }
  1739. }
  1740. //
  1741. // Print all file under this specific directory
  1742. //
  1743. File* sameLvlItem;
  1744. while((sameLvlItem = list->search(item, item->getDirectoryDestination())) != NULL)
  1745. {
  1746. //
  1747. // File
  1748. //
  1749. for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1750. removeSpace(sameLvlItem->getName(), fileObjectName);
  1751. ReplaceInvalidChars(fileObjectName);
  1752. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription),
  1753. "%s<File Name=\"%s\" LongName=\"%s\" src=\"%s\\%s\">_%s.%x.%i</File>",
  1754. spaces,
  1755. sameLvlItem->getShortName(),
  1756. sameLvlItem->getName(),
  1757. sameLvlItem->getSrcDir(),
  1758. sameLvlItem->getSrcName(),
  1759. fileObjectName,
  1760. flavor,
  1761. dwComponentCounter);
  1762. if (!SUCCEEDED(hr)) {
  1763. goto exit;
  1764. }
  1765. PrintLine(hFile, itemDescription);
  1766. list->remove(sameLvlItem);
  1767. }
  1768. //
  1769. // File
  1770. //
  1771. for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1772. removeSpace(item->getName(), fileObjectName);
  1773. ReplaceInvalidChars(fileObjectName);
  1774. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription),
  1775. "%s<File Name=\"%s\" LongName=\"%s\" src=\"%s\\%s\">_%s.%x.%i</File>",
  1776. spaces,
  1777. item->getShortName(),
  1778. item->getName(),
  1779. item->getSrcDir(),
  1780. item->getSrcName(),
  1781. fileObjectName,
  1782. flavor,
  1783. dwComponentCounter);
  1784. if (!SUCCEEDED(hr)) {
  1785. goto exit;
  1786. }
  1787. PrintLine(hFile, itemDescription);
  1788. dwComponentCounter++;
  1789. dirPtr = NULL;
  1790. //
  1791. // Close component
  1792. //
  1793. if (componentInit)
  1794. {
  1795. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1796. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Component>", spaces);
  1797. if (!SUCCEEDED(hr)) {
  1798. goto exit;
  1799. }
  1800. PrintLine(hFile, itemDescription);
  1801. componentInit = FALSE;
  1802. }
  1803. //
  1804. // Close directory
  1805. //
  1806. if (directoryInit)
  1807. {
  1808. dirLvlCnt--;
  1809. for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1810. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Directory>", spaces);
  1811. if (!SUCCEEDED(hr)) {
  1812. goto exit;
  1813. }
  1814. PrintLine(hFile, itemDescription);
  1815. directoryInit = FALSE;
  1816. }
  1817. }
  1818. }
  1819. for (int i = dirLvlCnt; i > 0; i--)
  1820. {
  1821. spaces[i] = '\0';
  1822. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Directory>", spaces);
  1823. if (!SUCCEEDED(hr)) {
  1824. goto exit;
  1825. }
  1826. PrintLine(hFile, itemDescription);
  1827. }
  1828. if (list->getFileNumber() > 1)
  1829. {
  1830. if (item->getNext() != NULL)
  1831. {
  1832. item = item->getNext();
  1833. list->remove(item->getPrevious());
  1834. }
  1835. else
  1836. {
  1837. list->remove(item);
  1838. item = NULL;
  1839. }
  1840. }
  1841. else
  1842. {
  1843. list->remove(item);
  1844. item = NULL;
  1845. }
  1846. }
  1847. }
  1848. else
  1849. {
  1850. File* item;
  1851. CHAR itemDescription[4096];
  1852. CHAR dirObjectName[MAX_PATH+1];
  1853. CHAR sdirname[MAX_PATH];
  1854. CHAR spaces[30];
  1855. int j;
  1856. item = list->getFirst();
  1857. while (item != NULL)
  1858. {
  1859. LPSTR dirPtr = NULL;
  1860. LPSTR dirLvlPtr = NULL;
  1861. INT dirLvlCnt = 0;
  1862. //
  1863. // Print directory
  1864. //
  1865. dirPtr = item->getDirectoryDestination();
  1866. while (dirPtr != NULL)
  1867. {
  1868. dirLvlPtr = strchr(dirPtr, '\\');
  1869. if (dirLvlPtr != NULL)
  1870. {
  1871. *dirLvlPtr = '\0';
  1872. for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1873. hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName), dirPtr);
  1874. if(!SUCCEEDED(hr)) {
  1875. goto exit;
  1876. }
  1877. ReplaceInvalidChars(dirObjectName);
  1878. GetFileShortName(dirPtr, sdirname, FALSE);
  1879. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Directory Name=\"%s\" LongName=\"%s\">_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter);
  1880. if (!SUCCEEDED(hr)) {
  1881. goto exit;
  1882. }
  1883. dwDirectoryCounter++;
  1884. PrintLine(hFile, itemDescription);
  1885. dirPtr = dirLvlPtr + 1;
  1886. dirLvlCnt++;
  1887. }
  1888. else
  1889. {
  1890. Uuid* uuid = new Uuid();
  1891. for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1892. hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName), dirPtr);
  1893. if(!SUCCEEDED(hr)) {
  1894. goto exit;
  1895. }
  1896. ReplaceInvalidChars(dirObjectName);
  1897. GetFileShortName(dirPtr, sdirname, FALSE);
  1898. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Directory Name=\"%s\" LongName=\"%s\">_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter);
  1899. if (!SUCCEEDED(hr)) {
  1900. goto exit;
  1901. }
  1902. dwDirectoryCounter++;
  1903. PrintLine(hFile, itemDescription);
  1904. dirLvlCnt++;
  1905. //
  1906. // Component
  1907. //
  1908. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1909. if (FALSE == bPermanent) {
  1910. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1911. if (!SUCCEEDED(hr)) {
  1912. goto exit;
  1913. }
  1914. }
  1915. else {
  1916. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s<Component Id='%s' Permanent='yes' Win64='%s'>Content%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter);
  1917. if (!SUCCEEDED(hr)) {
  1918. goto exit;
  1919. }
  1920. }
  1921. delete uuid;
  1922. PrintLine(hFile, itemDescription);
  1923. // print a condition line for this component, if needed
  1924. if (TRUE == bPrintCondition)
  1925. {
  1926. PrintLine(hFile, szSKUCondition);
  1927. }
  1928. //
  1929. // File
  1930. //
  1931. for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1932. CHAR fileObjectName[MAX_PATH+1];
  1933. removeSpace(item->getName(), fileObjectName);
  1934. ReplaceInvalidChars(fileObjectName);
  1935. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription),
  1936. "%s<File Name=\"%s\" LongName=\"%s\" src=\"%s\\%s\">_%s.%x.%i</File>",
  1937. spaces,
  1938. item->getShortName(),
  1939. item->getName(),
  1940. item->getSrcDir(),
  1941. item->getSrcName(),
  1942. fileObjectName,
  1943. flavor,
  1944. dwComponentCounter);
  1945. if (!SUCCEEDED(hr)) {
  1946. goto exit;
  1947. }
  1948. PrintLine(hFile, itemDescription);
  1949. dwComponentCounter++;
  1950. dirPtr = NULL;
  1951. }
  1952. }
  1953. for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';}
  1954. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Component>", spaces);
  1955. if (!SUCCEEDED(hr)) {
  1956. goto exit;
  1957. }
  1958. PrintLine(hFile, itemDescription);
  1959. for (int i = dirLvlCnt; i > 0; i--)
  1960. {
  1961. spaces[i] = '\0';
  1962. hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s</Directory>", spaces);
  1963. if (!SUCCEEDED(hr)) {
  1964. goto exit;
  1965. }
  1966. PrintLine(hFile, itemDescription);
  1967. }
  1968. item = item->getNext();
  1969. }
  1970. }
  1971. return;
  1972. /****************** DEBUG ******************
  1973. File* item;
  1974. CHAR itemDescription[4096];
  1975. item = list->getFirst();
  1976. while (item != NULL)
  1977. {
  1978. //
  1979. // Item description
  1980. //
  1981. sprintf(itemDescription,
  1982. " Source: %s\\%s",
  1983. item->getSrcDir(),
  1984. item->getSrcName());
  1985. PrintLine(hFile, itemDescription);
  1986. sprintf(itemDescription,
  1987. " Destination: %s\\%s",
  1988. item->getDirectoryDestination(),
  1989. item->getName());
  1990. PrintLine(hFile, itemDescription);
  1991. PrintLine(hFile, "");
  1992. item = item->getNext();
  1993. }
  1994. ****************** DEBUG ******************/
  1995. exit:
  1996. printf("Error in PrintFileList\n");
  1997. return;
  1998. }
  1999. ////////////////////////////////////////////////////////////////////////////
  2000. //
  2001. // PrintLine
  2002. //
  2003. // Add a line at the end of the file.
  2004. //
  2005. ////////////////////////////////////////////////////////////////////////////
  2006. BOOL PrintLine(HANDLE hFile, LPCSTR lpLine)
  2007. {
  2008. DWORD dwBytesWritten;
  2009. SetFilePointer(hFile, 0, NULL, FILE_END);
  2010. WriteFile( hFile,
  2011. lpLine,
  2012. _tcslen(lpLine) * sizeof(TCHAR),
  2013. &dwBytesWritten,
  2014. NULL );
  2015. SetFilePointer(hFile, 0, NULL, FILE_END);
  2016. WriteFile( hFile,
  2017. TEXT("\r\n"),
  2018. _tcslen(TEXT("\r\n")) * sizeof(TCHAR),
  2019. &dwBytesWritten,
  2020. NULL );
  2021. return (TRUE);
  2022. }
  2023. ///////////////////////////////////////////////////////////////////////////////
  2024. //
  2025. // CreateOutputFile()
  2026. //
  2027. // Create the file that would received the package file contents.
  2028. //
  2029. ///////////////////////////////////////////////////////////////////////////////
  2030. HANDLE CreateOutputFile(LPSTR filename)
  2031. {
  2032. SECURITY_ATTRIBUTES SecurityAttributes;
  2033. //
  2034. // Sanity check.
  2035. //
  2036. if (filename == NULL)
  2037. {
  2038. return INVALID_HANDLE_VALUE;
  2039. }
  2040. //
  2041. // Create a security descriptor the output file.
  2042. //
  2043. SecurityAttributes.nLength = sizeof(SecurityAttributes);
  2044. SecurityAttributes.lpSecurityDescriptor = NULL;
  2045. SecurityAttributes.bInheritHandle = FALSE;
  2046. //
  2047. // Create the file.
  2048. //
  2049. return CreateFile( filename,
  2050. GENERIC_WRITE,
  2051. 0,
  2052. &SecurityAttributes,
  2053. CREATE_ALWAYS,
  2054. FILE_ATTRIBUTE_NORMAL,
  2055. NULL );
  2056. }
  2057. ////////////////////////////////////////////////////////////////////////////
  2058. //
  2059. // removeSpace
  2060. //
  2061. // Remove all space from a string.
  2062. //
  2063. ////////////////////////////////////////////////////////////////////////////
  2064. VOID removeSpace(LPSTR src, LPSTR dest)
  2065. {
  2066. LPSTR strSrcPtr = src;
  2067. LPSTR strDestPtr = dest;
  2068. while (*strSrcPtr != '\0')
  2069. {
  2070. if (*strSrcPtr != ' ')
  2071. {
  2072. *strDestPtr = *strSrcPtr;
  2073. strDestPtr++;
  2074. }
  2075. strSrcPtr++;
  2076. }
  2077. *strDestPtr = '\0';
  2078. }
  2079. ////////////////////////////////////////////////////////////////////////////
  2080. //
  2081. // TransNum
  2082. //
  2083. // Converts a number string to a dword value (in hex).
  2084. //
  2085. ////////////////////////////////////////////////////////////////////////////
  2086. DWORD TransNum(LPTSTR lpsz)
  2087. {
  2088. DWORD dw = 0L;
  2089. TCHAR c;
  2090. while (*lpsz)
  2091. {
  2092. c = *lpsz++;
  2093. if (c >= TEXT('A') && c <= TEXT('F'))
  2094. {
  2095. c -= TEXT('A') - 0xa;
  2096. }
  2097. else if (c >= TEXT('0') && c <= TEXT('9'))
  2098. {
  2099. c -= TEXT('0');
  2100. }
  2101. else if (c >= TEXT('a') && c <= TEXT('f'))
  2102. {
  2103. c -= TEXT('a') - 0xa;
  2104. }
  2105. else
  2106. {
  2107. break;
  2108. }
  2109. dw *= 0x10;
  2110. dw += c;
  2111. }
  2112. return (dw);
  2113. }
  2114. ///////////////////////////////////////////////////////////////////////////////
  2115. //
  2116. // Usage
  2117. //
  2118. // Print the fonction usage.
  2119. //
  2120. ///////////////////////////////////////////////////////////////////////////////
  2121. void Usage()
  2122. {
  2123. printf("Create Merge module MUI WXM files for different OS SKUs\n");
  2124. printf("Usage: infparser /p:[cdlaout] /b:[32|64] /l:<lang> /f:[p|s|a|d] /s:<dir> /o:<file> /v\n");
  2125. printf(" where\n");
  2126. printf(" /p means the pseudo cd layout directory.\n");
  2127. printf(" <cdlayout>: is cd layout directory in mui release share, e.g. cd1 (for jpn), or psu (for psu)\n");
  2128. printf(" /b means the binary.\n");
  2129. printf(" 32: i386\n");
  2130. printf(" 64: ia64\n");
  2131. printf(" /l means the language flag.\n");
  2132. printf(" <lang>: is the target language\n");
  2133. printf(" /f means the flavor.\n");
  2134. printf(" p: Professional\n");
  2135. printf(" s: Server\n");
  2136. printf(" a: Advanced Server\n");
  2137. printf(" d: Data Center\n");
  2138. printf(" l: Server for Small Business Server\n");
  2139. printf(" w: Web Blade\n");
  2140. printf(" /i means the location of the localized binairy files.\n");
  2141. printf(" <dir>: Fully qualified path\n");
  2142. printf(" /s means the location of the binairy data.\n");
  2143. printf(" <dir>: Fully qualified path\n");
  2144. printf(" /o means the xml file contents of specific flavor.\n");
  2145. printf(" <file>: Fully qualified path\n");
  2146. printf(" /v means the verbose mode [optional].\n");
  2147. }
  2148. ///////////////////////////////////////////////////////////////////////////////
  2149. //
  2150. // GetTempDirName
  2151. //
  2152. // Return the MUI temporary directory name, create it if not found
  2153. //
  2154. ///////////////////////////////////////////////////////////////////////////////
  2155. BOOL GetTempDirName(LPSTR sLangName)
  2156. {
  2157. CHAR *pcBaseDirPtr = NULL;
  2158. BOOL bFoundDir = FALSE;
  2159. HRESULT hr;
  2160. pcBaseDirPtr = getenv(TEXT("_NTPOSTBLD"));
  2161. if (NULL != pcBaseDirPtr)
  2162. {
  2163. // sprintf(TempDirName, "%s\\%s\\%s\\%s\\%s", pcBaseDirPtr, sLangName, "mui", sLangName, "tmp\\infparser");
  2164. // sprintf(TempDirName, "%s\\%s\\%s\\%s", pcBaseDirPtr, "mui", sLangName, "tmp\\infparser");
  2165. hr = StringCchPrintfA(TempDirName, ARRAYLEN(TempDirName), "%s\\%s\\%s\\%s", pcBaseDirPtr, "mui", sLangName, "tmp\\infparser");
  2166. if (!SUCCEEDED(hr)) {
  2167. goto exit;
  2168. }
  2169. // we will create this directory if it does not exist - although it should be by this stage
  2170. if (FALSE == DirectoryExist(TempDirName))
  2171. {
  2172. if (TRUE == CreateDirectory(TempDirName, NULL))
  2173. {
  2174. bFoundDir = TRUE;
  2175. if (!bSilence)
  2176. printf("Infparser::GetTempDirName() - created MUI temp directory %s \n", TempDirName);
  2177. }
  2178. else
  2179. {
  2180. if (!bSilence)
  2181. printf("Infparser::GetTempDirName() - failed to create MUI temp directory %s - The error returned is %d\n", TempDirName, GetLastError());
  2182. }
  2183. }
  2184. else
  2185. bFoundDir = TRUE;
  2186. }
  2187. // if we cannot find the MUI temp directory and directory creation failed, use the default one instead
  2188. if (FALSE == bFoundDir)
  2189. {
  2190. DWORD dwBufferLength = 0;
  2191. dwBufferLength = GetTempPath(MAX_PATH, TempDirName); // tempdir returned contains an ending slash
  2192. if (dwBufferLength > 0)
  2193. {
  2194. if (TRUE == DirectoryExist(TempDirName))
  2195. {
  2196. bFoundDir = TRUE;
  2197. }
  2198. }
  2199. }
  2200. if (!bSilence)
  2201. {
  2202. if (FALSE == bFoundDir)
  2203. printf("GetTempDirName: Cannot find/create temporary directory!\n");
  2204. else
  2205. printf("GetTempDirName: temporary directory used is %s\n", TempDirName);
  2206. }
  2207. return bFoundDir;
  2208. exit:
  2209. printf("Error in GetTempDirName \n");
  2210. return FALSE;
  2211. }
  2212. BOOL GetFileShortName(const CHAR * pcInLongName, CHAR * pcOutShortName, BOOL bInFileExists)
  2213. {
  2214. CHAR LongFullPath[MAX_PATH];
  2215. CHAR ShortFullPath[MAX_PATH];
  2216. DWORD dwBufferSize = 0; // size of the returned shortname
  2217. HANDLE tmpHandle;
  2218. CHAR * pcIndex = NULL; // pointer index into src path of the file name
  2219. HRESULT hr;
  2220. if (NULL == pcInLongName || NULL == pcOutShortName)
  2221. return FALSE;
  2222. if (!bInFileExists)
  2223. {
  2224. hr = StringCchPrintfA(LongFullPath, ARRAYLEN(LongFullPath), "%s\\%s", TempDirName, pcInLongName);
  2225. if (!SUCCEEDED(hr)) {
  2226. goto exit;
  2227. }
  2228. if (!bSilence)
  2229. printf("GetFileShortName: LongFullPath is %s.\n", LongFullPath);
  2230. // create a temp file so that GetShortPathName will work
  2231. tmpHandle = CreateFile(LongFullPath,
  2232. GENERIC_ALL, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  2233. NULL,
  2234. OPEN_ALWAYS,
  2235. FILE_ATTRIBUTE_NORMAL,
  2236. NULL);
  2237. if (tmpHandle)
  2238. CloseHandle(tmpHandle);
  2239. }
  2240. else
  2241. {
  2242. hr = StringCchCopyA(LongFullPath, ARRAYLEN(LongFullPath), pcInLongName);
  2243. if(!SUCCEEDED(hr)) {
  2244. goto exit;
  2245. }
  2246. }
  2247. dwBufferSize = GetShortPathName(LongFullPath, ShortFullPath, MAX_PATH);
  2248. if (0 == dwBufferSize)
  2249. {
  2250. DWORD dwErrorCode = GetLastError();
  2251. if (!bSilence)
  2252. {
  2253. printf("GetFileShortName failed! GetShortPathName returned an error code of %d. Using longname as shortpath name. ", dwErrorCode);
  2254. printf("fullpath is %s\n", LongFullPath);
  2255. }
  2256. hr = StringCchCopyA(pcOutShortName, MAX_PATH, pcInLongName);
  2257. if(!SUCCEEDED(hr)) {
  2258. goto exit;
  2259. }
  2260. }
  2261. else
  2262. {
  2263. // find the filename from the path, if cannot find it, then use the source name
  2264. GetFileNameFromFullPath(ShortFullPath, pcOutShortName);
  2265. if (!pcOutShortName)
  2266. {
  2267. if (!bSilence)
  2268. printf("GetShortPathName returned an empty string, using source name %s\n", pcInLongName);
  2269. hr = StringCchCopyA(pcOutShortName, MAX_PATH, pcInLongName);
  2270. if(!SUCCEEDED(hr)) {
  2271. goto exit;
  2272. }
  2273. }
  2274. }
  2275. return TRUE;
  2276. exit:
  2277. printf("Error in GetFileShortName\n");
  2278. return FALSE;
  2279. }
  2280. BOOL IsInvalidChar(CHAR cCheck)
  2281. {
  2282. int i;
  2283. BOOL bResult = FALSE;
  2284. for (i=0; i < NO_INVALIDCHARS; i++)
  2285. {
  2286. if (cCheck == InvalidChars[i])
  2287. {
  2288. bResult = TRUE;
  2289. break;
  2290. }
  2291. }
  2292. return bResult;
  2293. }
  2294. void ReplaceInvalidChars(CHAR *pcInName)
  2295. {
  2296. // if first char is not a alphabet or underscore, add an underscore to the name
  2297. HRESULT hr;
  2298. if ((!isalpha(*pcInName) && (*pcInName != '_') ))
  2299. {
  2300. CHAR tempBuffer[MAX_PATH+1];
  2301. hr = StringCchCopyA(tempBuffer, ARRAYLEN(tempBuffer), pcInName);
  2302. if(!SUCCEEDED(hr)) {
  2303. goto exit;
  2304. }
  2305. hr = StringCchCopyA(pcInName, MAX_PATH, tempBuffer);
  2306. if(!SUCCEEDED(hr)) {
  2307. goto exit;
  2308. }
  2309. }
  2310. while (*pcInName)
  2311. {
  2312. if (IsInvalidChar(*pcInName))
  2313. *pcInName = '_'; // replace all invalid chars with underscores
  2314. pcInName++;
  2315. }
  2316. return;
  2317. exit:
  2318. printf("Error in ReplaceInvalidChars \n");
  2319. return;
  2320. }
  2321. BOOL GetFileNameFromFullPath(const CHAR * pcInFullPath, CHAR * pcOutFileName)
  2322. {
  2323. CHAR * pcIndex = NULL;
  2324. HRESULT hr;
  2325. if (!pcInFullPath)
  2326. {
  2327. return FALSE;
  2328. }
  2329. if (!pcOutFileName)
  2330. {
  2331. return FALSE;
  2332. }
  2333. // find the filename from the path, if cannot find it, then use the fullpath as the outputfilename
  2334. pcIndex = strrchr(pcInFullPath, '\\');
  2335. if (NULL != pcIndex)
  2336. {
  2337. pcIndex++;
  2338. if (!bSilence)
  2339. printf("Shortpath used is %s\n", pcIndex);
  2340. hr = StringCchCopyA(pcOutFileName, MAX_PATH, pcIndex); // pcOutFileName size is MAX_PATH
  2341. if(!SUCCEEDED(hr)) {
  2342. goto exit;
  2343. }
  2344. }
  2345. else if (0 < strlen(pcInFullPath)) // we just have the filename, use it as is.
  2346. {
  2347. if (!bSilence)
  2348. printf("GetFileNameFromFullPath returned a path without a \\ in the path. ShortFileName is %s.\n", pcInFullPath);
  2349. hr = StringCchCopyA(pcOutFileName, MAX_PATH, pcInFullPath); // pcOutFileName size is MAX_PATH
  2350. if(!SUCCEEDED(hr)) {
  2351. goto exit;
  2352. }
  2353. }
  2354. else // didn't find the filename, use the passed in parameter instead
  2355. {
  2356. if (!bSilence)
  2357. printf("GetFileNameFromFullPath returned an empty string, using source name %s\n", pcInFullPath);
  2358. hr = StringCchCopyA(pcOutFileName, MAX_PATH, pcInFullPath); // pcOutFileName size is MAX_PATH
  2359. if(!SUCCEEDED(hr)) {
  2360. goto exit;
  2361. }
  2362. }
  2363. return TRUE;
  2364. exit:
  2365. printf("Error in GetFileNameFromFullPath\n");
  2366. return TRUE;
  2367. }
  2368. void RenameMuiExtension(CHAR * dstFileName)
  2369. {
  2370. int iNameLen = 0;
  2371. if (NULL == dstFileName)
  2372. return;
  2373. iNameLen = strlen(dstFileName);
  2374. if (0 == iNameLen)
  2375. return;
  2376. // if the last char is a '/' or '\', remove it
  2377. if ((dstFileName[iNameLen-1] == '\\') || (dstFileName[iNameLen-1] == '/'))
  2378. {
  2379. dstFileName[iNameLen-1] = '\0';
  2380. iNameLen --;
  2381. }
  2382. // if the last 4 chars are '.mui', replace the 'i' with '_'
  2383. if (iNameLen >= 4)
  2384. {
  2385. if (_stricmp(dstFileName+(iNameLen-4), ".mui") == 0)
  2386. {
  2387. dstFileName[iNameLen-1] = '_';
  2388. }
  2389. }
  2390. return;
  2391. }
  2392. //
  2393. // This function checks to see if there are any SKU specific external component INF directories under the supplied component path.
  2394. // Note that the SKU subdirectories are as generated by the NT build environment. And also that the personal edition SKU directory
  2395. // "perinf" is not included in the search. i.e. if perinf dir exists the function still returns false.
  2396. //
  2397. BOOL ContainSKUDirs(CHAR *pszDirPath)
  2398. {
  2399. WIN32_FIND_DATA FindData;
  2400. HANDLE FindHandle = NULL;
  2401. FINDEX_INFO_LEVELS fInfoLevelId;
  2402. INT i;
  2403. CHAR szSKURootPath[MAX_PATH];
  2404. BOOL bResult = FALSE;
  2405. HRESULT hr;
  2406. CHAR *szSKUDirs[5] = {
  2407. "blainf\0",
  2408. "dtcinf\0",
  2409. "entinf\0",
  2410. "sbsinf\0",
  2411. "srvinf\0"
  2412. };
  2413. if (NULL == pszDirPath)
  2414. return FALSE;
  2415. if (0 == strlen(pszDirPath))
  2416. return FALSE;
  2417. for (i = 0; i < 5; i++)
  2418. {
  2419. // replace PathCombine(szSKURootPath, pszDirPath, szSKUDirs[i])
  2420. // with normal string operation.
  2421. // szSKURootPath = pszDirPath + "\\" + szSKUDirs[i];
  2422. hr = StringCchPrintfA(szSKURootPath, ARRAYLEN(szSKURootPath), "%s\\%s",pszDirPath,szSKUDirs[i]);
  2423. if (!SUCCEEDED(hr)) {
  2424. return FALSE;
  2425. }
  2426. FindHandle = FindFirstFileEx(szSKURootPath, FindExInfoStandard, &FindData, FindExSearchLimitToDirectories, NULL, 0);
  2427. if (FindHandle != INVALID_HANDLE_VALUE)
  2428. {
  2429. FindClose(FindHandle);
  2430. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2431. {
  2432. bResult = TRUE;
  2433. break;
  2434. }
  2435. }
  2436. }
  2437. return (bResult);
  2438. }
  2439. BOOL GetSKUConditionString(CHAR *pszBuffer, DWORD dwFlavour)
  2440. {
  2441. BOOL bReturn = TRUE;
  2442. HRESULT hr;
  2443. if (NULL == pszBuffer)
  2444. {
  2445. bReturn = FALSE;
  2446. // strcpy(pszBuffer, "");
  2447. goto Exit;
  2448. }
  2449. switch (dwFlavour)
  2450. {
  2451. case FLV_PROFESSIONAL:
  2452. hr = StringCchCopyA(pszBuffer, 4096, PRO_SKU_CONDITION);
  2453. if(!SUCCEEDED(hr)) {
  2454. goto exit;
  2455. }
  2456. break;
  2457. case FLV_SERVER:
  2458. hr = StringCchCopyA(pszBuffer, 4096, SRV_SKU_CONDITION);
  2459. if(!SUCCEEDED(hr)) {
  2460. goto exit;
  2461. }
  2462. break;
  2463. case FLV_ADVSERVER:
  2464. hr = StringCchCopyA(pszBuffer, 4096, ADV_SKU_CONDITION);
  2465. if(!SUCCEEDED(hr)) {
  2466. goto exit;
  2467. }
  2468. break;
  2469. case FLV_DATACENTER:
  2470. hr = StringCchCopyA(pszBuffer, 4096, DTC_SKU_CONDITION);
  2471. if(!SUCCEEDED(hr)) {
  2472. goto exit;
  2473. }
  2474. break;
  2475. case FLV_WEBBLADE:
  2476. hr = StringCchCopyA(pszBuffer, 4096, BLA_SKU_CONDITION);
  2477. if(!SUCCEEDED(hr)) {
  2478. goto exit;
  2479. }
  2480. break;
  2481. case FLV_SMALLBUSINESS:
  2482. hr = StringCchCopyA(pszBuffer, 4096, SBS_SKU_CONDITION);
  2483. if(!SUCCEEDED(hr)) {
  2484. goto exit;
  2485. }
  2486. break;
  2487. case FLV_PERSONAL:
  2488. case FLV_UNDEFINED:
  2489. case FLV_CORE:
  2490. default:
  2491. hr = StringCchCopyA(pszBuffer, 4096, "");
  2492. if(!SUCCEEDED(hr)) {
  2493. goto exit;
  2494. }
  2495. bReturn = FALSE;
  2496. break;
  2497. }
  2498. if (!bSilence)
  2499. {
  2500. printf("\nSKU Condition String is: %s\n", pszBuffer);
  2501. }
  2502. Exit:
  2503. return bReturn;
  2504. exit:
  2505. printf("Error GetSKUConditionString \n");
  2506. return FALSE;
  2507. }
  2508. ///////////////////////////////////////////////////////////////////////////
  2509. //
  2510. // IsFileForSKU:
  2511. //
  2512. // This function takes a file name, the SKU flavour, and the processor architecture as an
  2513. // argument. Then it checks to see if it exists as a source file in the SKU specified.
  2514. //
  2515. // the checking part is done by looking in the built layout.inf file for that sku to make sure
  2516. // the file appears for that SKU only, the layout.inf file for the skus are located at:
  2517. //
  2518. // PRO sku: _NTPOSTBLD
  2519. // PER sku: _NTPOSTBLD\perinf
  2520. // SRV sku: _NTPOSTBLD\srvinf
  2521. // ADS sku: _NTPOSTBLD\entinf
  2522. // DTC sku: _NTPOSTBLD\dtcinf
  2523. // SBS sku: _NTPOSTBLD\sbsinf
  2524. // BLA sku: _NTPOSTBLD\blainf
  2525. //
  2526. // for all skus, check all the inf files for every sku and make sure it doesn't appear in every inf
  2527. // but appears at least in the inf file designated for the sku we are searching for.
  2528. // For Core sku, it must appear in every infs (the reverse for the above)
  2529. // ignore and return false if personal or other undefined skus are specified
  2530. // check first in [SourceDisksFiles] (common file section)
  2531. // if not in there, we check based on arch, [SourceDiskFiles.x86] and [SourceDiskFiles.ia64]
  2532. // note that here, the source and destination file names are the same, since they are not in the exception list
  2533. //
  2534. // strFileName: source filename to be checked (not the destination name)
  2535. // dwSKU: SKU to check for (see infparser.h for the list of values)
  2536. // dwArch: Architecture type to check for (see infparser.h for list of values)
  2537. //
  2538. // NOTE: this function needs to be reworked if we want to incorporate PER/PRO skus back into
  2539. // the checking. Currently it only works for server skus.
  2540. //
  2541. ///////////////////////////////////////////////////////////////////////////
  2542. BOOL IsFileForSKU(CHAR * strFileName, DWORD dwSKU, DWORD dwArch, FileLayoutExceptionList * exceptionList)
  2543. {
  2544. BOOL bFound = TRUE;
  2545. BOOL bCoreFound = TRUE;
  2546. BOOL bSkuFound = FALSE;
  2547. BOOL bProPerFound = FALSE;
  2548. BOOL bSrvSkusFound = FALSE;
  2549. UINT i = 0; // index variable
  2550. UINT iDesignated = 0; // the sku we are searching for.
  2551. // validating parameters
  2552. if (NULL == strFileName)
  2553. {
  2554. if (!bSilence)
  2555. {
  2556. printf("IsFileForSKU: Passed in filename is empty.\n");
  2557. }
  2558. return FALSE;
  2559. }
  2560. // determines the inf files that we need to search
  2561. switch (dwSKU)
  2562. {
  2563. case FLV_PROFESSIONAL:
  2564. iDesignated = PRO_SKU_INDEX;
  2565. break;
  2566. case FLV_PERSONAL:
  2567. iDesignated = PER_SKU_INDEX;
  2568. break;
  2569. case FLV_SERVER:
  2570. iDesignated = SRV_SKU_INDEX;
  2571. break;
  2572. case FLV_ADVSERVER:
  2573. iDesignated = ADV_SKU_INDEX;
  2574. break;
  2575. case FLV_DATACENTER:
  2576. iDesignated = DTC_SKU_INDEX;
  2577. break;
  2578. case FLV_WEBBLADE:
  2579. iDesignated = BLA_SKU_INDEX;
  2580. break;
  2581. case FLV_SMALLBUSINESS:
  2582. iDesignated = SBS_SKU_INDEX;
  2583. break;
  2584. case FLV_CORE:
  2585. iDesignated = NO_SKUS;
  2586. break;
  2587. default:
  2588. return FALSE;
  2589. break;
  2590. }
  2591. if (!bSilence)
  2592. {
  2593. printf("File %s\n", strFileName);
  2594. }
  2595. // search for the infs
  2596. // NOTE: we search also in personal and professional skus, this is to make sure files we pick up
  2597. // which are in \bin that aren't in the server layout.infs are not also in layout.infs for pro/per
  2598. for (i = PRO_SKU_INDEX; i < NO_SKUS; i++)
  2599. {
  2600. bFound = IsFileInInf(strFileName, i, dwArch);
  2601. if (!bSilence)
  2602. {
  2603. printf("SKU %s: %s ", SkuInfs[i].strSkuName, bFound ? "yes" : "no");
  2604. }
  2605. if (iDesignated == i)
  2606. {
  2607. bSkuFound = bFound;
  2608. }
  2609. if ((i == PRO_SKU_INDEX) || (i == PER_SKU_INDEX))
  2610. {
  2611. bProPerFound = (bProPerFound || bFound);
  2612. }
  2613. else
  2614. {
  2615. bCoreFound = (bFound && bCoreFound);
  2616. bSkuFound = bFound || bSkuFound;
  2617. }
  2618. }
  2619. if (dwSKU == FLV_CORE)
  2620. {
  2621. bFound = bCoreFound;
  2622. // for CORE sku, if the file is not found in Pro/Per SKU, we will include it anyways
  2623. // as long as it is not a destination file for any SKU, otherwise we will have
  2624. // a MSI build error
  2625. if ((!bFound) && (!bProPerFound) && (!bSkuFound))
  2626. {
  2627. if (!exceptionList->searchDestName(strFileName))
  2628. bFound = TRUE;
  2629. else
  2630. bFound = FALSE;
  2631. }
  2632. }
  2633. else
  2634. {
  2635. bFound = (!bCoreFound && bSkuFound);
  2636. }
  2637. if (!bSilence)
  2638. {
  2639. printf("\n");
  2640. if (bFound)
  2641. {
  2642. printf("The file %s is found in this sku.\n", strFileName);
  2643. }
  2644. else
  2645. {
  2646. printf("The file %s is not found in this sku.\n", strFileName);
  2647. }
  2648. }
  2649. return bFound;
  2650. }
  2651. BOOL IsFileInInf(CHAR * strFileName, UINT iSkuIndex, DWORD dwArch)
  2652. {
  2653. UINT iLineCount = 0;
  2654. UINT iLineNum = 0;
  2655. FileLayoutExceptionList *flArch = NULL;
  2656. CHAR * archSection = NULL;
  2657. INFCONTEXT context;
  2658. // validating parameters
  2659. if (NULL == strFileName)
  2660. {
  2661. if (!bSilence)
  2662. {
  2663. printf("IsFileInInf: Passed in filename is empty.\n");
  2664. }
  2665. return FALSE;
  2666. }
  2667. switch (dwArch)
  2668. {
  2669. case BIN_32:
  2670. flArch = &(SkuInfs[iSkuIndex].flLayoutX86);
  2671. break;
  2672. case BIN_64:
  2673. flArch = &(SkuInfs[iSkuIndex].flLayoutIA64);
  2674. break;
  2675. default:
  2676. if (!bSilence)
  2677. {
  2678. printf("Invalid architecture specified.\n");
  2679. }
  2680. return FALSE;
  2681. break;
  2682. }
  2683. if (iSkuIndex > BLA_SKU_INDEX)
  2684. {
  2685. if (!bSilence)
  2686. {
  2687. printf("IsFileInInf: invalid SKU index passed in as parameter: %d.\n", iSkuIndex);
  2688. }
  2689. return FALSE;
  2690. }
  2691. if (SkuInfs[iSkuIndex].flLayoutCore.search(strFileName) != NULL)
  2692. {
  2693. return TRUE;
  2694. }
  2695. else if (flArch->search(strFileName) != NULL)
  2696. {
  2697. return TRUE;
  2698. }
  2699. else
  2700. {
  2701. return FALSE;
  2702. }
  2703. }
  2704. //
  2705. // This function reads in the layout.inf files for all the skus and stores the file information
  2706. // in the filelist structure for later accessing. We are doing this so that we can gain
  2707. // some performance instead of repeatedly using setup apis to read from the inf files itself
  2708. // when we have to repeatedly search through these inf files to build the final file list
  2709. //
  2710. BOOL ReadInLayoutInfFiles()
  2711. {
  2712. UINT i = 0;
  2713. UINT j = 0;
  2714. UINT iLineCount = 0;
  2715. UINT iLineNum = 0;
  2716. INFCONTEXT context;
  2717. FileLayout *file;
  2718. HINF hInfFile = NULL;
  2719. FileLayoutExceptionList *flist = NULL;
  2720. // populate the layout.inf filelists
  2721. for (i = 0; i < NO_SKUS; i++)
  2722. {
  2723. if (!bSilence)
  2724. {
  2725. printf("ReadInLayoutInfFiles: Reading files from %s for %s SKU.\n", SkuInfs[i].strLayoutInfPaths, SkuInfs[i].strSkuName);
  2726. }
  2727. hInfFile = SetupOpenInfFile(SkuInfs[i].strLayoutInfPaths, NULL, INF_STYLE_WIN4, NULL);
  2728. if (INVALID_HANDLE_VALUE == hInfFile)
  2729. {
  2730. if (!bSilence)
  2731. {
  2732. printf("ReadInLayoutInfFiles: Failure opening %s file\n", SkuInfs[i].strLayoutInfPaths);
  2733. }
  2734. return FALSE;
  2735. }
  2736. // read in SourceDisksFiles section
  2737. for (j = 0; j < 3; j++)
  2738. {
  2739. switch(j)
  2740. {
  2741. case (0):
  2742. flist = &(SkuInfs[i].flLayoutCore);
  2743. break;
  2744. case (1):
  2745. flist = &(SkuInfs[i].flLayoutX86);
  2746. break;
  2747. case (2):
  2748. flist = &(SkuInfs[i].flLayoutIA64);
  2749. break;
  2750. default:
  2751. // shouldn't happen
  2752. return FALSE;
  2753. }
  2754. iLineCount = (UINT)SetupGetLineCount(hInfFile, strArchSections[j]);
  2755. if (iLineCount > 0)
  2756. {
  2757. //
  2758. // try to find the file in sourcedisksfiles.
  2759. //
  2760. CHAR name[MAX_PATH];
  2761. for (iLineNum = 0; iLineNum < iLineCount; iLineNum++)
  2762. {
  2763. if (SetupGetLineByIndex(hInfFile, strArchSections[j], iLineNum, &context) &&
  2764. SetupGetStringField(&context, 0, name, MAX_PATH, NULL))
  2765. {
  2766. // add the file to the filelist, we are only interested in the source name, pass in bogus stuff for
  2767. // the other members, we don't care what the sku is, just insert 0 for now.
  2768. if (file = new FileLayout(name, name, 0))
  2769. {
  2770. flist->insert(file);
  2771. }
  2772. }
  2773. }
  2774. }
  2775. }
  2776. SetupCloseInfFile(hInfFile);
  2777. }
  2778. return TRUE;
  2779. }