/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2001, Microsoft Corporation All rights reserved. // // Module Name: // // infparser.cpp // // Abstract: // // This file contains the entry point of the infparser.exe utility. // // Revision History: // // 2001-06-20 lguindon Created. // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // Includes Files. // /////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "infparser.h" #include "stdlib.h" #include "windows.h" #include "string.h" #include "ctype.h" /////////////////////////////////////////////////////////////////////////////// // // Global Definitions // /////////////////////////////////////////////////////////////////////////////// #define NO_INVALIDCHARS 31 #define PRO_SKU_CONDITION "" #define SRV_SKU_CONDITION "1 AND NOT MsiNTSuiteDataCenter AND NOT MsiNTSuiteEnterprise AND NOT MsiNTSuiteWebServer AND NOT MsiNTSuiteSmallBusiness and NOT MsiNTSuiteSmallBusinessRestricted]]>" #define ADV_SKU_CONDITION "MsiNTSuiteEnterprise" #define SBS_SKU_CONDITION "MsiNTSuiteSmallBusinessRestricted OR MsiNTSuiteSmallBusiness" #define DTC_SKU_CONDITION "MsiNTSuiteDataCenter" #define BLA_SKU_CONDITION "MsiNTSuiteWebServer" #define PRO_SKU_INF "layout.inf" #define PER_SKU_INF "perinf\\layout.inf" #define SRV_SKU_INF "srvinf\\layout.inf" #define ADV_SKU_INF "entinf\\layout.inf" #define DTC_SKU_INF "dtcinf\\layout.inf" #define SBS_SKU_INF "sbsinf\\layout.inf" #define BLA_SKU_INF "blainf\\layout.inf" #define NO_SKUS 7 #define PRO_SKU_INDEX 0 #define PER_SKU_INDEX 1 #define SRV_SKU_INDEX 2 #define ADV_SKU_INDEX 3 #define DTC_SKU_INDEX 4 #define SBS_SKU_INDEX 5 #define BLA_SKU_INDEX 6 /////////////////////////////////////////////////////////////////////////////// // // Global variable. // /////////////////////////////////////////////////////////////////////////////// BOOL bSilence = TRUE; DWORD gBinType = BIN_UNDEFINED; DWORD dwComponentCounter = 0; DWORD dwDirectoryCounter = 1; WORD gBuildNumber = 0; TCHAR TempDirName[MAX_PATH] = { 0 }; LPSTR sLDirName = NULL; LPSTR sLocBinDir = NULL; CHAR InvalidChars[NO_INVALIDCHARS] = { '`', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '=', '+', '[', '{', ']', '}', '\\', '|', ';', ':', '\'', '\"', ',', '<', '>', '/', '?', ' ' }; CHAR strArchSections[3][30] = {"SourceDisksFiles", "SourceDisksFiles.x86", "SourceDisksFiles.ia64"}; LAYOUTINF SkuInfs[NO_SKUS]; /////////////////////////////////////////////////////////////////////////////// // // Prototypes. // /////////////////////////////////////////////////////////////////////////////// BOOL DirectoryExist(LPSTR dirPath); BOOL ValidateLanguage(LPSTR dirPath, LPSTR langName, DWORD binType); WORD ConvertLanguage(LPSTR dirPath, LPSTR langName); int ListContents(LPSTR filename, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType); int ListComponents(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType); int ListMuiFiles(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType); void PrintFileList(FileList* list, HANDLE hFile, BOOL compressed, BOOL bWinDir, BOOL bPermanent, BOOL bX86OnIA64, DWORD flavor, DWORD binType); BOOL PrintLine(HANDLE hFile, LPCSTR lpLine); HANDLE CreateOutputFile(LPSTR filename); VOID removeSpace(LPSTR src, LPSTR dest); DWORD TransNum(LPTSTR lpsz); void Usage(); BOOL GetTempDirName(LPSTR sLangName) ; BOOL GetFileShortName(const CHAR * pcIn, CHAR * pcOut, BOOL bInFileExists); void ReplaceInvalidChars(CHAR *pcInName); BOOL IsInvalidChar(CHAR cCheck); BOOL GetFileNameFromFullPath(const CHAR * pcInFullPath, CHAR * pcOutFileName); void RenameMuiExtension(CHAR * dstFileName); BOOL ContainSKUDirs(CHAR *pszSKUSearchPath); BOOL GetSKUConditionString(CHAR *pszBuffer, DWORD dwFlavour); BOOL IsFileForSKU(LPSTR strFileName, DWORD dwSKU, DWORD dwArch, FileLayoutExceptionList * exceptionList); BOOL IsFileInInf(CHAR * strFileName, UINT iSkuIndex, DWORD dwArch); BOOL ReadInLayoutInfFiles(); /////////////////////////////////////////////////////////////////////////////// // // Main entry point. // /////////////////////////////////////////////////////////////////////////////// int __cdecl main(int argc, char* argv[]) { LPSTR sLangName = NULL; LPSTR sDirPath = NULL; DWORD dwFlavor = FLV_UNDEFINED; DWORD dwBinType = BIN_UNDEFINED; DWORD dwArg = ARG_UNDEFINED; WORD wLangID = 0; HANDLE hFile; int argIndex = 1; LPSTR lpFileName = NULL; HRESULT hr = S_OK; INT iResult = 0; INT i = 0; // // Check if we have the minimal number of arguments. // if (argc < 6) { printf("Not all required parameters were found when executing infparser.exe.\n"); Usage(); return (-1); } // // Parse the command line. // while (argIndex < argc) { if (*argv[argIndex] == '/') { switch(*(argv[argIndex]+1)) { case('p'): case('P'): // // switch for locating directory to external components this should be same as lang except for psu builds // sLDirName = (argv[argIndex]+3); dwArg |= ARG_CDLAYOUT; break; case('b'): case('B'): // // Binairy i386 or ia64 // if ((*(argv[argIndex]+3) == '3') && (*(argv[argIndex]+4) == '2')) { dwBinType = BIN_32; } else if ((*(argv[argIndex]+3) == '6') && (*(argv[argIndex]+4) == '4')) { dwBinType = BIN_64; } else { return (argIndex); } dwArg |= ARG_BINARY; break; case('l'): case('L'): // // Language // sLangName = (argv[argIndex]+3); dwArg |= ARG_LANG; break; case('i'): case('I'): // // Inf root location (where localized binaries are located, same as _NTPOSTBLD env variable) // sLocBinDir = (argv[argIndex]+3); dwArg |= ARG_LOCBIN; break; case('f'): case('F'): // // Flavor requested // switch(*(argv[argIndex]+3)) { case('c'): case('C'): dwFlavor = FLV_CORE; break; case('p'): case('P'): dwFlavor = FLV_PROFESSIONAL; break; case('s'): case('S'): dwFlavor = FLV_SERVER; break; case('a'): case('A'): dwFlavor = FLV_ADVSERVER; break; case('d'): case('D'): dwFlavor = FLV_DATACENTER; break; case('b'): case('B'): dwFlavor = FLV_WEBBLADE; break; case('l'): case('L'): dwFlavor = FLV_SMALLBUSINESS; break; default: return (argIndex); } dwArg |= ARG_FLAVOR; break; case('s'): case('S'): // // Binairy location // sDirPath = (argv[argIndex]+3); dwArg |= ARG_DIR; break; case('o'): case('O'): // // Output filename // /* if ((hFile = CreateOutputFile(argv[argIndex]+3)) == INVALID_HANDLE_VALUE) { return (argIndex); } */ lpFileName = argv[argIndex]+3; dwArg |= ARG_OUT; break; case('v'): case('V'): // // Verbose mode // bSilence = FALSE; dwArg |= ARG_SILENT; break; default: printf("Invalid parameters found on the command line!\n"); Usage(); return (argIndex); } } else { printf("Invalid parameters found on the command line!\n"); Usage(); return (-1); } // // Next argument // argIndex++; } // // Validate arguments passed. Should have all five basic argument in order // to continue. // if ((dwArg == ARG_UNDEFINED) || !((dwArg & ARG_BINARY) && (dwArg & ARG_LANG) && (dwArg & ARG_DIR) && (dwArg & ARG_OUT) && (dwArg & ARG_LOCBIN) && (dwArg & ARG_CDLAYOUT) && (dwArg & ARG_FLAVOR))) { Usage(); return (-1); } // // Validate Source directory // if (!DirectoryExist(sDirPath)) { return (-2); } if (!DirectoryExist(sLocBinDir)) { return (-2); } // // Validate Language // if (!ValidateLanguage(sDirPath, sLangName, dwBinType)) { return (-3); } // // Get LANGID from the language // if ( (gBuildNumber = ConvertLanguage(sDirPath, sLangName)) == 0x0000) { return (-4); } // update the temp directory global variable if (!GetTempDirName(sLangName)) { return (-5); } gBinType = dwBinType; // Generate the layout.inf paths for every sku hr = StringCchPrintfA(SkuInfs[PRO_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, PRO_SKU_INF); // Professional if (FAILED(hr)) { return (-6); } hr = StringCchPrintfA(SkuInfs[PER_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, PER_SKU_INF); // Personal if (FAILED(hr)) { return (-6); } hr = StringCchPrintfA(SkuInfs[SRV_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, SRV_SKU_INF); // standard server if (FAILED(hr)) { return (-6); } hr = StringCchPrintfA(SkuInfs[ADV_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, ADV_SKU_INF); // advanced server if (FAILED(hr)) { return (-6); } hr = StringCchPrintfA(SkuInfs[DTC_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, DTC_SKU_INF); // datacenter server if (FAILED(hr)) { return (-6); } hr = StringCchPrintfA(SkuInfs[SBS_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, SBS_SKU_INF); // small business server if (FAILED(hr)) { return (-6); } hr = StringCchPrintfA(SkuInfs[BLA_SKU_INDEX].strLayoutInfPaths, MAX_PATH, "%s\\%s", sLocBinDir, BLA_SKU_INF); // web server if (FAILED(hr)) { return (-6); } hr = StringCchCopyA(SkuInfs[PRO_SKU_INDEX].strSkuName, 4, TEXT("Pro")); // Professional if (FAILED(hr)) { return (-6); } hr = StringCchCopyA(SkuInfs[PER_SKU_INDEX].strSkuName, 4, TEXT("Per")); // Personal if (FAILED(hr)) { return (-6); } hr = StringCchCopyA(SkuInfs[SRV_SKU_INDEX].strSkuName, 4, TEXT("Srv")); // Standard Server if (FAILED(hr)) { return (-6); } hr = StringCchCopyA(SkuInfs[ADV_SKU_INDEX].strSkuName, 4, TEXT("Adv")); // Advanced Server if (FAILED(hr)) { return (-6); } hr = StringCchCopyA(SkuInfs[DTC_SKU_INDEX].strSkuName, 4, TEXT("Dtc")); // Datacenter if (FAILED(hr)) { return (-6); } hr = StringCchCopyA(SkuInfs[SBS_SKU_INDEX].strSkuName, 4, TEXT("Sbs")); // Small Business Server if (FAILED(hr)) { return (-6); } hr = StringCchCopyA(SkuInfs[BLA_SKU_INDEX].strSkuName, 4, TEXT("Bla")); // Blade server if (FAILED(hr)) { return (-6); } if (FALSE == ReadInLayoutInfFiles()) { if (!bSilence) { printf("Failed to populate layout.inf file lists.\n"); } return (-7); } // // Generate the file list // if ((dwArg & ARG_OUT) && lpFileName) { iResult = ListContents(lpFileName, sDirPath, sLangName, dwFlavor, dwBinType); } return iResult; } /////////////////////////////////////////////////////////////////////////////// // // ListContents() // // Generate the file list contents. // /////////////////////////////////////////////////////////////////////////////// int ListContents(LPSTR filename, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType) { int iRet = 0; Uuid* uuid; CHAR schemaPath[MAX_PATH] = {0}; CHAR outputString[4096] = {0}; FileList fileList, rootfileList; HANDLE outputFile = CreateOutputFile(filename); HRESULT hr; if (outputFile == INVALID_HANDLE_VALUE) { iRet = -1; goto ListContents_EXIT; } // // Create a UUID for this module and the schema path // uuid = new Uuid(); hr = StringCchPrintfA(schemaPath, ARRAYLEN(schemaPath), "%s\\msi\\MmSchema.xml", dirPath); if (!SUCCEEDED(hr)) { iRet = -1; goto ListContents_EXIT; } // // Print module header. // PrintLine(outputFile, ""); hr = StringCchPrintfA(outputString, ARRAYLEN(outputString), "", uuid->getString(), schemaPath); if (!SUCCEEDED(hr)) { iRet = -1; goto ListContents_EXIT; } PrintLine(outputFile, outputString); hr = StringCchPrintfA(outputString, ARRAYLEN(outputString), " getString()); if (!SUCCEEDED(hr)) { iRet = -1; goto ListContents_EXIT; } PrintLine(outputFile, outputString); delete uuid; PrintLine(outputFile, " Description=\"Content module\""); if (BIN_32 == binType) PrintLine(outputFile, " Platforms=\"Intel\""); else PrintLine(outputFile," Platforms=\"Intel64\""); PrintLine(outputFile, " Languages=\"0\""); PrintLine(outputFile, " InstallerVersion=\"200\""); PrintLine(outputFile, " Manufacturer=\"Microsoft Corporation\""); PrintLine(outputFile, " Keywords=\"MergeModule, MSI, Database\""); PrintLine(outputFile, " Comments=\"This merge module contains all the MUI file content\""); PrintLine(outputFile, " ShortNames=\"yes\" Compressed=\"yes\""); PrintLine(outputFile, "/>"); // // Generate components file list // if ( (iRet = ListComponents(&fileList, dirPath, lang, flavor, binType)) != 0) { goto ListContents_EXIT; } // // Generate Mui file list // if ((iRet =ListMuiFiles(&fileList, dirPath, lang, flavor, binType)) != 0) { goto ListContents_EXIT; } // // Add Specific MuiSetup files to a separate file list for output. Do this only in the core flavour // these files will be printed out as permanent // if (flavor == FLV_CORE) { File* file; file = new File( TEXT("muisetup.exe"), TEXT("MUI"), TEXT("muisetup.exe"), dirPath, TEXT("muisetup.exe"), 10); rootfileList.add(file); file = new File( TEXT("muisetup.hlp"), TEXT("MUI"), TEXT("muisetup.hlp"), dirPath, TEXT("muisetup.hlp"), 10); rootfileList.add(file); file = new File( TEXT("eula.txt"), TEXT("MUI"), TEXT("eula.txt"), dirPath, TEXT("eula.txt"), 10); rootfileList.add(file); file = new File( TEXT("relnotes.htm"), TEXT("MUI"), TEXT("relnotes.htm"), dirPath, TEXT("relnotes.htm"), 10); rootfileList.add(file); file = new File( TEXT("readme.txt"), TEXT("MUI"), TEXT("readme.txt"), dirPath, TEXT("readme.txt"), 10); rootfileList.add(file); file = new File( TEXT("mui.inf"), TEXT("MUI"), TEXT("mui.inf"), dirPath, TEXT("mui.inf"), 10); rootfileList.add(file); } // // Print compressed directory structure. // PrintLine(outputFile, "TARGETDIR"); if (fileList.isDirId(TRUE)) { PrintLine(outputFile, " WindowsFolder"); PrintFileList(&rootfileList, outputFile, TRUE, TRUE, TRUE, FALSE, flavor, binType); PrintFileList(&fileList, outputFile, TRUE, TRUE, FALSE, FALSE, flavor, binType); PrintLine(outputFile, " "); } if (fileList.isDirId(FALSE)) { if (binType == BIN_32) { PrintLine(outputFile, " ProgramFilesFolder"); PrintFileList(&fileList, outputFile, TRUE, FALSE, FALSE, FALSE, flavor, binType); PrintLine(outputFile, " "); } else if (binType == BIN_64) { // 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 PrintLine(outputFile, " ProgramFilesFolder64"); PrintFileList(&fileList, outputFile, TRUE, FALSE, FALSE, FALSE, flavor, binType); PrintLine(outputFile, " "); // 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 PrintLine(outputFile, " ProgramFilesFolder"); PrintFileList(&fileList, outputFile, TRUE, FALSE, FALSE, TRUE, flavor, binType); PrintLine(outputFile, " "); } } PrintLine(outputFile, ""); // // Print module footer. // PrintLine(outputFile, ""); ListContents_EXIT: if (outputFile) CloseHandle(outputFile); return (iRet); } /////////////////////////////////////////////////////////////////////////////// // // ListComponents() // // Generate the file list of each components. // Note that the external components are now temporarily copied to // MUI\Fallback\LCID\External directory, and then their infs are executed from those // places during the installation. // // The uninstallation happens as before, by executing copies of it from // MUI\Fallback\LCID - this means that there are now two copies of external components // on the target drive, but we will have to live with this for now and fix for setup in the // next release. // // Another change to this function is that it is now SKU aware, when building for different // SKUs, it will check for the SKU directory (see below for example) under the root directory where // the external components are located in. For CORE, it will check under the root external // component directory for it and use those if they exist. If it does not exist there will be no // external component files for that SKU. // // Here is a list of SKU directories that the function searches under for: // // 1. CORE: \External // 2. Professional: \External\ // 3. StandardServer: \External\srvinf // 4. Advanced/EnterpriseServer: \External\entinf // 5. DatacenterServer: \External\datinf // 6. BladeServer: \External\blainf // 7. SmallBusinessServer: \External\sbsinf // // // The components will be parsed/scanned by looking for the component directory in the // mui.inf file, and each unique component directory will be copied as is to the destination dir. // /////////////////////////////////////////////////////////////////////////////// int ListComponents(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType) { HINF hFile; CHAR muiFilePath[MAX_PATH]; CHAR muiExtCompRoot[MAX_PATH]; DWORD lineCount, lineNum; INFCONTEXT context; ComponentList componentList; Component* component; CHAR muiSKUDir[20]; HRESULT hr; // // check the flavour and assign the appropriate SKU subdirectory // switch (flavor) { case FLV_PROFESSIONAL: hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), ""); if (!SUCCEEDED(hr)) { goto exit; } break; case FLV_SERVER: hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\srvinf\0"); if (!SUCCEEDED(hr)) { goto exit; } break; case FLV_ADVSERVER: hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\entinf\0"); if (!SUCCEEDED(hr)) { goto exit; } break; case FLV_DATACENTER: hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\dtcinf\0"); if (!SUCCEEDED(hr)) { goto exit; } break; case FLV_WEBBLADE: hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\blainf\0"); if (!SUCCEEDED(hr)) { goto exit; } break; case FLV_SMALLBUSINESS: hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), "\\sbsinf\0"); if (!SUCCEEDED(hr)) { goto exit; } break; case FLV_CORE: hr = StringCchCopyA(muiSKUDir, sizeof (muiSKUDir) / sizeof (CHAR), ""); if (!SUCCEEDED(hr)) { goto exit; } break; default: return(0); // invalid sku specified, just exit break; } // // Create the path to open the mui.inf file // hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\mui.inf", dirPath); if (!SUCCEEDED(hr)) { goto exit; } // // Open the MUI.INF file. // hFile = SetupOpenInfFile(muiFilePath, NULL, INF_STYLE_WIN4, NULL); if (hFile == INVALID_HANDLE_VALUE) { return (-1); } // // Get the number of component. // lineCount = (UINT)SetupGetLineCount(hFile, TEXT("Components")); if (lineCount > 0) { // // Go through all component of the list. // CHAR componentName[MAX_PATH]; CHAR componentFolder[MAX_PATH]; CHAR componentInf[MAX_PATH]; CHAR componentInst[MAX_PATH]; for (lineNum = 0; lineNum < lineCount; lineNum++) { if (SetupGetLineByIndex(hFile, TEXT("Components"), lineNum, &context) && SetupGetStringField(&context, 0, componentName, MAX_PATH, NULL) && SetupGetStringField(&context, 1, componentFolder, MAX_PATH, NULL) && SetupGetStringField(&context, 2, componentInf, MAX_PATH, NULL) && SetupGetStringField(&context, 3, componentInst, MAX_PATH, NULL)) { // // Create the components and add to the list, but only if the componentFolder is unique, since we will be copying // all the files in the same component dirs we shouldn't miss anything // BOOL bUnique = TRUE; Component *pCIndex = NULL; pCIndex = componentList.getFirst(); while (pCIndex) { if (_strnicmp(pCIndex->getFolderName(), componentFolder, strlen(componentFolder)) == 0) { bUnique = FALSE; break; } pCIndex = pCIndex->getNext(); } if (bUnique) { if( (component = new Component( componentName, componentFolder, componentInf, componentInst)) != NULL) { componentList.add(component); } } } } } // // Close inf handle // SetupCloseInfFile(hFile); // // Output component information // component = componentList.getFirst(); while (component != NULL) { CHAR componentInfPath[MAX_PATH]; CHAR componentPath[MAX_PATH]; CHAR SKUSearchPath[MAX_PATH]; CHAR searchPath[MAX_PATH]; CHAR srcFileName[MAX_PATH]; CHAR dstFileName[MAX_PATH]; CHAR shortFileName[MAX_PATH]; CHAR tempShortPath[MAX_PATH]; File* file; HANDLE hFind; WIN32_FIND_DATA wfdFindData; BOOL bFinished = FALSE; // // Compute the component inf path, we need to get it from the compressed version from old build // e.g. C:\nt.relbins.x86fre\psu\mui\release\x86\Temp\psu\ro.mui\i386 // if (binType == BIN_32) { hr = StringCchPrintfA(componentInfPath, ARRAYLEN(componentInfPath), "%s\\release\\x86\\Temp\\%s\\%s.mui\\i386\\%s%s\\%s", dirPath, sLDirName, lang, component->getFolderName(), muiSKUDir, component->getInfName()); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(componentPath, ARRAYLEN(componentPath), "%s\\release\\x86\\Temp\\%s\\%s.mui\\i386\\%s%s", dirPath, sLDirName, lang, component->getFolderName(), muiSKUDir); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(SKUSearchPath, ARRAYLEN(SKUSearchPath), "%s\\release\\x86\\Temp\\%s\\%s.mui\\i386\\%s", dirPath, sLDirName, lang, component->getFolderName()); if (!SUCCEEDED(hr)) { goto exit; } } else { hr = StringCchPrintfA(componentInfPath, ARRAYLEN(componentInfPath), "%s\\release\\ia64\\Temp\\%s\\%s.mui\\ia64\\%s%s\\%s", dirPath, sLDirName, lang, component->getFolderName(), muiSKUDir, component->getInfName()); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(componentPath, ARRAYLEN(componentPath), "%s\\release\\ia64\\Temp\\%s\\%s.mui\\ia64\\%s%s", dirPath, sLDirName, lang, component->getFolderName(), muiSKUDir); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(SKUSearchPath, ARRAYLEN(SKUSearchPath), "%s\\release\\ia64\\Temp\\%s\\%s.mui\\ia64\\%s", dirPath, sLDirName, lang, component->getFolderName()); if (!SUCCEEDED(hr)) { goto exit; } } // if there are any other subdirectory under this component path, then the root directory files are actually // for the PRO SKU, and we should not add this component to CORE if ((FLV_CORE == flavor) && ContainSKUDirs(SKUSearchPath)) { component = component->getNext(); if (!bSilence) { printf("\n*** SKU subdirectory detected for this component and flavour is CORE, skipping component. %s\n", componentInfPath); } continue; } // if there are no other subdirectory under this component path, then the root directory files are actually // for the CORE SKU, and we should not add this component to PRO // this is one compromise we have to make right now since the NT SKU subdirs does not give us the ability to distinguish // between PRO SKU and something that is for every platform if ((FLV_PROFESSIONAL == flavor) && !ContainSKUDirs(SKUSearchPath)) { component = component->getNext(); if (!bSilence) { printf("\n*** SKU subdirectory not detected for this component and flavour is PRO, skipping component. %s\n", componentInfPath); } continue; } // form the temp component path on the target hr = StringCchPrintfA(muiExtCompRoot, ARRAYLEN(muiExtCompRoot), "MUI\\FALLBACK\\%04x\\External\\%s", gBuildNumber, component->getFolderName()); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(searchPath, ARRAYLEN(searchPath), "%s\\*.*", componentPath); if (!SUCCEEDED(hr)) { goto exit; } if (!bSilence) { printf("\n*** Source component inf path is %s\n", componentInfPath); printf("\n*** Source component folder path is %s\n", componentPath); printf("\n*** Destination directory for this component is %s\n", muiExtCompRoot); } // Get a list of all the files in the component folder hFind = FindFirstFile(searchPath, &wfdFindData); if (hFind == INVALID_HANDLE_VALUE) { if (!bSilence) { printf("\n*** No files found in the component directory %s\n", muiExtCompRoot); } component = component->getNext(); continue; // skip this component } else { bFinished = FALSE; while (!bFinished) { // only process files, not directories if ((wfdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { if (!bSilence) { printf("\n*** Filename is %s\n", wfdFindData.cFileName); printf("\n*** Alternate Filename is %s\n", wfdFindData.cAlternateFileName); } hr = StringCchCopyA(srcFileName, ARRAYLEN(srcFileName), wfdFindData.cFileName); if (!SUCCEEDED(hr)) { goto exit; } if (!(wfdFindData.cAlternateFileName) || (strlen(wfdFindData.cAlternateFileName) == 0)) { hr = StringCchCopyA(shortFileName, ARRAYLEN(shortFileName), wfdFindData.cFileName); if (!SUCCEEDED(hr)) { goto exit; } } else { hr = StringCchCopyA(shortFileName, ARRAYLEN(shortFileName), wfdFindData.cAlternateFileName); if (!SUCCEEDED(hr)) { goto exit; } } // here, we also need to rename all the files that ends with a .mui extension to .mu_ - since the infs are // expecting this. // RenameMuiExtension(shortFileName); hr = StringCchCopyA(dstFileName, ARRAYLEN(dstFileName), srcFileName); if (!SUCCEEDED(hr)) { goto exit; } // RenameMuiExtension(dstFileName); if ((file = new File(shortFileName, muiExtCompRoot, dstFileName, componentPath, srcFileName, 10)) != NULL) { dirList->add(file); } } else { if (!bSilence) { printf("\n*** Found a directory in the component dir %s\n", wfdFindData.cFileName); } } if (!FindNextFile(hFind, &wfdFindData)) { bFinished = TRUE; } } } // // Next Component // component = component->getNext(); } return 0; exit: printf("Error in ListComponents\n"); return 1; } /////////////////////////////////////////////////////////////////////////////// // // ListMuiFiles() // // Generate the file list for MUI. // /////////////////////////////////////////////////////////////////////////////// int ListMuiFiles(FileList *dirList, LPSTR dirPath, LPSTR lang, DWORD flavor, DWORD binType) { HINF hFile; CHAR muiFilePath[MAX_PATH]; CHAR muiFileSearchPath[MAX_PATH]; int lineCount, lineNum, fieldCount; INFCONTEXT context; FileLayoutExceptionList exceptionList; WIN32_FIND_DATA findData; HANDLE fileHandle; File* file; HRESULT hr; // // Create the path to open the mui.inf file // hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\mui.inf", dirPath); if (!SUCCEEDED(hr)) { goto exit; } // // Open the MUI.INF file. // hFile = SetupOpenInfFile(muiFilePath, NULL, INF_STYLE_WIN4, NULL); if (hFile == INVALID_HANDLE_VALUE) { return (-1); } // // Get the number of file exception. // lineCount = (UINT)SetupGetLineCount(hFile, TEXT("File_Layout")); if (lineCount > 0) { // // Go through all file exception of the list. // CHAR originFilename[MAX_PATH]; CHAR destFilename[MAX_PATH]; CHAR fileFlavor[30]; DWORD dwFlavor; for (lineNum = 0; lineNum < lineCount; lineNum++) { if (SetupGetLineByIndex(hFile, TEXT("File_Layout"), lineNum, &context) && (fieldCount = SetupGetFieldCount(&context))) { if (SetupGetStringField(&context, 0, originFilename, MAX_PATH, NULL) && SetupGetStringField(&context, 1, destFilename, MAX_PATH, NULL)) { FileLayout* fileException; dwFlavor = 0; for(int fieldId = 2; fieldId <= fieldCount; fieldId++) { if(SetupGetStringField(&context, fieldId, fileFlavor, MAX_PATH, NULL)) { switch(*fileFlavor) { case('p'): case('P'): dwFlavor |= FLV_PROFESSIONAL; break; case('s'): case('S'): dwFlavor |= FLV_SERVER; break; case('d'): case('D'): dwFlavor |= FLV_DATACENTER; break; case('a'): case('A'): dwFlavor |= FLV_ADVSERVER; break; case('b'): case('B'): dwFlavor |= FLV_WEBBLADE; break; case('l'): case('L'): dwFlavor |= FLV_SMALLBUSINESS; break; } } } // // Add only information needed for this specific flavor. // fileException = new FileLayout(originFilename, destFilename, dwFlavor); exceptionList.insert(fileException); } } } } // // Close inf handle // SetupCloseInfFile(hFile); // // Compute the binary source path. // if (binType == BIN_32) { hr = StringCchPrintfA(muiFileSearchPath, ARRAYLEN(muiFileSearchPath), "%s\\%s\\i386.uncomp", dirPath, lang); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\%s\\i386.uncomp\\*.*", dirPath, lang); if (!SUCCEEDED(hr)) { goto exit; } } else { hr = StringCchPrintfA(muiFileSearchPath, ARRAYLEN(muiFileSearchPath), "%s\\%s\\ia64.uncomp", dirPath, lang); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\%s\\ia64.uncomp\\*.*", dirPath, lang); if (!SUCCEEDED(hr)) { goto exit; } } // // Scan uncomp source directory for file information // if ((fileHandle = FindFirstFile(muiFilePath, &findData)) != INVALID_HANDLE_VALUE) { // // Look for files // do { LPSTR extensionPtr; INT dirIdentifier = 0; CHAR destDirectory[MAX_PATH] = {0}; CHAR destName[MAX_PATH] = {0}; FileLayout* fileException = NULL; // // Scan only files at this level. // if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { continue; } // // Search the extension to determine the destination location and possibly // exclude file destined for Personal. // if ((extensionPtr = strrchr(findData.cFileName, '.')) != NULL) { if( (_tcsicmp(extensionPtr, TEXT(".chm")) == 0) || (_tcsicmp(extensionPtr, TEXT(".chq")) == 0) || (_tcsicmp(extensionPtr, TEXT(".cnt")) == 0) || (_tcsicmp(extensionPtr, TEXT(".hlp")) == 0)) { dirIdentifier = 18; hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "MUI\\%04x", gBuildNumber); if (!SUCCEEDED(hr)) { goto exit; } } else if (_tcsicmp(extensionPtr, TEXT(".mfl")) == 0) { dirIdentifier = 11; hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "wbem\\MUI\\%04x", gBuildNumber); if (!SUCCEEDED(hr)) { goto exit; } } else if (_tcsicmp(findData.cFileName, TEXT("hhctrlui.dll")) == 0) { dirIdentifier = 11; hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "MUI\\%04x", gBuildNumber); if (!SUCCEEDED(hr)) { goto exit; } } else { dirIdentifier = 10; hr = StringCchPrintfA(destDirectory, ARRAYLEN(destDirectory), "MUI\\FALLBACK\\%04x", gBuildNumber); if (!SUCCEEDED(hr)) { goto exit; } } } // // We need to remove the .MUI extension before passing the filename to search in the // mui.inf file rename section // CHAR strTemp[MAX_PATH]; BOOL bBinaryFile = FALSE; hr = StringCchCopyA(strTemp, ARRAYLEN(strTemp), findData.cFileName); if (!SUCCEEDED(hr)){ goto exit; } // remove the extension .mui if it is there if ((extensionPtr = strrchr(strTemp, '.')) != NULL) { if (_tcsicmp(extensionPtr, TEXT(".mui")) == 0) { *extensionPtr = NULL; bBinaryFile = TRUE; } } // // Search for different destination name in the exception list. // if ((fileException = exceptionList.search(strTemp)) != NULL ) { if (!bSilence) { printf("Source file %s exists in mui.inf.\n", findData.cFileName); } // // Verify it's the needed flavor // also check that it's not in every flavour if we are not // building CORE merge modules // if ((fileException->isFlavor(flavor)) && !((flavor != FLV_CORE) && (fileException->isFlavor(FLV_ADVSERVER)) && (fileException->isFlavor(FLV_SERVER)) && (fileException->isFlavor(FLV_DATACENTER)) && (fileException->isFlavor(FLV_WEBBLADE)) && (fileException->isFlavor(FLV_SMALLBUSINESS)))) { if (!bSilence) { printf("Flavor is not CORE, Source file %s is for the specified SKU.\n", findData.cFileName); } if (bBinaryFile) { hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s.mui", fileException->getDestFileName()); } else { hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s", fileException->getDestFileName()); } if (!SUCCEEDED(hr)) { goto exit; } } else if ((flavor == FLV_CORE) && (fileException->isFlavor(FLV_ADVSERVER)) && (fileException->isFlavor(FLV_SERVER)) && (fileException->isFlavor(FLV_DATACENTER)) && (fileException->isFlavor(FLV_WEBBLADE)) && (fileException->isFlavor(FLV_SMALLBUSINESS))) { if (!bSilence) { printf("Flavor is CORE, Source file %s is in every SKU.\n", findData.cFileName); } if (bBinaryFile) { hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s.mui", fileException->getDestFileName()); } else { hr = StringCchPrintfA(destName, ARRAYLEN(destName), "%s", fileException->getDestFileName()); } if (!SUCCEEDED(hr)) { goto exit; } } else { if (!bSilence) { printf("Source file %s (destination name %s) is not in this SKU.\n", findData.cFileName, fileException->getDestFileName() ? fileException->getDestFileName() : findData.cFileName); } // // Skip the file. Not need in this flavor. // continue; } } else { CHAR strOrigName[MAX_PATH]; hr = StringCchCopyA(strOrigName, ARRAYLEN(strOrigName), findData.cFileName); if (!SUCCEEDED(hr)){ goto exit; } // remove the extension .mui if it is there if ((extensionPtr = strrchr(strOrigName, '.')) != NULL) { if (_tcsicmp(extensionPtr, TEXT(".mui")) == 0) { *extensionPtr = NULL; if (!bSilence) { printf("Filename is %s, original filename is %s.\n", findData.cFileName, strOrigName); } } } if (IsFileForSKU(strOrigName, flavor, binType, &exceptionList)) { hr = StringCchCopyA(destName, ARRAYLEN(destName), findData.cFileName); if (!SUCCEEDED(hr)){ goto exit; } } else { continue; } } // // Create a file // CHAR sfilename[MAX_PATH]; GetFileShortName(destName, sfilename, FALSE); if (file = new File(sfilename, destDirectory, destName, muiFileSearchPath, findData.cFileName, dirIdentifier)) { dirList->add(file); } } while (FindNextFile(fileHandle, &findData)); FindClose(fileHandle); } return 0; exit: printf("Error in ListMuiFiles\n"); return 1; } /////////////////////////////////////////////////////////////////////////////// // // ValidateLanguage() // // Verify if the language given is valid and checks is the files are // available. // /////////////////////////////////////////////////////////////////////////////// BOOL ValidateLanguage(LPSTR dirPath, LPSTR langName, DWORD binType) { CHAR langPath[MAX_PATH] = {0}; HRESULT hr; // // Check if the binary type in order to determine the right path. // if (binType == BIN_32) { hr = StringCchPrintfA(langPath, ARRAYLEN(langPath), "%s\\%s\\i386.uncomp", dirPath, langName); if (!SUCCEEDED(hr)) { goto exit; } } else { hr = StringCchPrintfA(langPath, ARRAYLEN(langPath), "%s\\%s\\ia64.uncomp", dirPath, langName); if (!SUCCEEDED(hr)) { goto exit; } } return (DirectoryExist(langPath)); exit: printf("Error in ValidateLanguage \n"); return FALSE; } /////////////////////////////////////////////////////////////////////////////// // // DirectoryExist() // // Verify if the given directory exists and contains files. // /////////////////////////////////////////////////////////////////////////////// BOOL DirectoryExist(LPSTR dirPath) { WIN32_FIND_DATA FindData; HANDLE FindHandle; // // Sanity check. // if (dirPath == NULL) { return FALSE; } // // See if the language group directory exists. // FindHandle = FindFirstFile(dirPath, &FindData); if (FindHandle != INVALID_HANDLE_VALUE) { FindClose(FindHandle); if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // // Return success. // return (TRUE); } } // // Return failure. // if (!bSilence) { printf("ERR[%s]: No files found in the directory.\n", dirPath); } return (FALSE); } /////////////////////////////////////////////////////////////////////////////// // // ConvertLanguage() // // Look into mui.inf file for the corresponding language identifier. // /////////////////////////////////////////////////////////////////////////////// WORD ConvertLanguage(LPSTR dirPath, LPSTR langName) { HINF hFile; CHAR muiFilePath[MAX_PATH]; CHAR muiLang[30]; UINT lineCount, lineNum; INFCONTEXT context; DWORD langId = 0x00000000; HRESULT hr; // // Create the path to open the mui.inf file // hr = StringCchPrintfA(muiFilePath, ARRAYLEN(muiFilePath), "%s\\mui.inf", dirPath); if (!SUCCEEDED(hr)) { goto exit; } hr = StringCchPrintfA(muiLang, ARRAYLEN(muiLang), "%s.MUI", langName); if (!SUCCEEDED(hr)) { goto exit; } // // Open the MUI.INF file. // hFile = SetupOpenInfFile(muiFilePath, NULL, INF_STYLE_WIN4, NULL); if (hFile == INVALID_HANDLE_VALUE) { return (0x0000); } // // Get the number of Language. // lineCount = (UINT)SetupGetLineCount(hFile, TEXT("Languages")); if (lineCount > 0) { // // Go through all language of the list to find a . // CHAR langID[MAX_PATH]; CHAR name[MAX_PATH]; for (lineNum = 0; lineNum < lineCount; lineNum++) { if (SetupGetLineByIndex(hFile, TEXT("Languages"), lineNum, &context) && SetupGetStringField(&context, 0, langID, MAX_PATH, NULL) && SetupGetStringField(&context, 1, name, MAX_PATH, NULL)) { if ( _tcsicmp(name, muiLang) == 0) { langId = TransNum(langID); SetupCloseInfFile(hFile); return (WORD)(langId); } } } } // // Close inf handle // SetupCloseInfFile(hFile); exit: printf("Error in CovnertLanguage \n"); return (0x0000); } //////////////////////////////////////////////////////////////////////////// // // PrintFileList // // Print a file list in XML format. // //////////////////////////////////////////////////////////////////////////// void PrintFileList(FileList* list, HANDLE hFile, BOOL compressed, BOOL bWinDir, BOOL bPermanent, BOOL bX86OnIA64, DWORD flavor, DWORD binType) { CHAR szSKUCondition[4096]; CHAR szIsWin64[4]; BOOL bPrintCondition = GetSKUConditionString(szSKUCondition, flavor); HRESULT hr; if (binType == BIN_32) { hr = StringCchCopyA(szIsWin64, ARRAYLEN(szIsWin64),"no"); } else { hr = StringCchCopyA(szIsWin64, ARRAYLEN(szIsWin64),"yes"); } if (compressed) { File* item; CHAR itemDescription[4096]; CHAR spaces[30]; int j; item = list->getFirst(); while (item != NULL) { LPSTR refDirPtr = NULL; LPSTR dirPtr = NULL; CHAR dirName[MAX_PATH]; CHAR dirName2[MAX_PATH]; CHAR dirObjectName[MAX_PATH+1]; LPSTR dirPtr2 = NULL; LPSTR dirLvlPtr = NULL; INT dirLvlCnt = 0; BOOL componentInit = FALSE; BOOL directoryInit = FALSE; Uuid* uuid; File* toBeRemoved; CHAR fileObjectName[MAX_PATH+1]; UINT matchCount; // // Check destination directory. // if (item->isWindowsDir() != bWinDir) { item = item->getNext(); continue; } // // Check if the destination directory is base dir // if (*(item->getDirectoryDestination()) == '\0') { // // Component // uuid = new Uuid(); for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} if (FALSE == bPermanent) { hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } else { hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } delete uuid; PrintLine(hFile, itemDescription); // print a condition line for this component, if needed if (TRUE == bPrintCondition) { PrintLine(hFile, szSKUCondition); } // // File // for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} removeSpace(item->getName(), fileObjectName); ReplaceInvalidChars(fileObjectName); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s.%x.%i", spaces, item->getShortName(), item->getName(), item->getSrcDir(), item->getSrcName(), fileObjectName, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); // // // for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); dwComponentCounter++; toBeRemoved = item; item = item->getNext(); list->remove(toBeRemoved); continue; } // // Print directory // hr = StringCchCopyA(dirName, ARRAYLEN(dirName), item->getDirectoryDestination()); if(!SUCCEEDED(hr)) { goto exit; } dirPtr = dirName; refDirPtr = dirPtr; CHAR sdirname[MAX_PATH]; while (dirPtr != NULL) { dirLvlPtr = strchr(dirPtr, '\\'); if (dirLvlPtr != NULL) { *dirLvlPtr = '\0'; for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName),dirPtr); if(!SUCCEEDED(hr)) { goto exit; } ReplaceInvalidChars(dirObjectName); GetFileShortName(dirPtr, sdirname, FALSE); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter); if (!SUCCEEDED(hr)) { goto exit; } dwDirectoryCounter++; PrintLine(hFile, itemDescription); dirPtr = dirLvlPtr + 1; dirLvlCnt++; // // Print all file under this specific directory // hr = StringCchCopyA(dirName2, ARRAYLEN(dirName2), item->getDirectoryDestination()); if(!SUCCEEDED(hr)) { goto exit; } dirName2[dirLvlPtr-refDirPtr] = '\0'; File* sameLvlItem = NULL; matchCount = 0; while((sameLvlItem = list->search(item, dirName2)) != NULL) { // // Component // if (!componentInit) { uuid = new Uuid(); for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} if (FALSE == bPermanent) { hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } else{ hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } delete uuid; PrintLine(hFile, itemDescription); dwComponentCounter++; componentInit = TRUE; // print a condition line for this component, if needed if (TRUE == bPrintCondition) { PrintLine(hFile, szSKUCondition); } } // // File // matchCount++; for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} removeSpace(sameLvlItem->getName(), fileObjectName); ReplaceInvalidChars(fileObjectName); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s.%x.%i", spaces, sameLvlItem->getShortName(), sameLvlItem->getName(), sameLvlItem->getSrcDir(), sameLvlItem->getSrcName(), fileObjectName, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); list->remove(sameLvlItem); } // kenhsu -this is incorrect, the file we are looking at may be deeper in the directory structure, we shouldn't print it out here // until we have finished recursing its destination directory. /* if (matchCount) { // // File // for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} removeSpace(item->getName(), fileObjectName); ReplaceInvalidChars(fileObjectName); sprintf( itemDescription, "%s%s.%i", spaces, item->getShortName(), item->getName(), item->getSrcDir(), item->getSrcName(), fileObjectName, dwComponentCounter); PrintLine(hFile, itemDescription); dirPtr = NULL; } */ // // Close component // if (componentInit) { for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); componentInit = FALSE; } // // Close directory // if (directoryInit) { dirLvlCnt--; for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); directoryInit = FALSE; } } else { if (!directoryInit) { for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName), dirPtr); if(!SUCCEEDED(hr)) { goto exit; } ReplaceInvalidChars(dirObjectName); GetFileShortName(dirPtr, sdirname, FALSE); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter); if (!SUCCEEDED(hr)) { goto exit; } dwDirectoryCounter++; PrintLine(hFile, itemDescription); dirLvlCnt++; directoryInit = TRUE; } // // Component // if (!componentInit) { uuid = new Uuid(); for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} if (FALSE == bPermanent) { hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } else { hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } delete uuid; PrintLine(hFile, itemDescription); componentInit = TRUE; // print a condition line for this component, if needed if (TRUE == bPrintCondition) { PrintLine(hFile, szSKUCondition); } } // // Print all file under this specific directory // File* sameLvlItem; while((sameLvlItem = list->search(item, item->getDirectoryDestination())) != NULL) { // // File // for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} removeSpace(sameLvlItem->getName(), fileObjectName); ReplaceInvalidChars(fileObjectName); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s.%x.%i", spaces, sameLvlItem->getShortName(), sameLvlItem->getName(), sameLvlItem->getSrcDir(), sameLvlItem->getSrcName(), fileObjectName, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); list->remove(sameLvlItem); } // // File // for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} removeSpace(item->getName(), fileObjectName); ReplaceInvalidChars(fileObjectName); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s.%x.%i", spaces, item->getShortName(), item->getName(), item->getSrcDir(), item->getSrcName(), fileObjectName, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); dwComponentCounter++; dirPtr = NULL; // // Close component // if (componentInit) { for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); componentInit = FALSE; } // // Close directory // if (directoryInit) { dirLvlCnt--; for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); directoryInit = FALSE; } } } for (int i = dirLvlCnt; i > 0; i--) { spaces[i] = '\0'; hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); } if (list->getFileNumber() > 1) { if (item->getNext() != NULL) { item = item->getNext(); list->remove(item->getPrevious()); } else { list->remove(item); item = NULL; } } else { list->remove(item); item = NULL; } } } else { File* item; CHAR itemDescription[4096]; CHAR dirObjectName[MAX_PATH+1]; CHAR sdirname[MAX_PATH]; CHAR spaces[30]; int j; item = list->getFirst(); while (item != NULL) { LPSTR dirPtr = NULL; LPSTR dirLvlPtr = NULL; INT dirLvlCnt = 0; // // Print directory // dirPtr = item->getDirectoryDestination(); while (dirPtr != NULL) { dirLvlPtr = strchr(dirPtr, '\\'); if (dirLvlPtr != NULL) { *dirLvlPtr = '\0'; for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName), dirPtr); if(!SUCCEEDED(hr)) { goto exit; } ReplaceInvalidChars(dirObjectName); GetFileShortName(dirPtr, sdirname, FALSE); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter); if (!SUCCEEDED(hr)) { goto exit; } dwDirectoryCounter++; PrintLine(hFile, itemDescription); dirPtr = dirLvlPtr + 1; dirLvlCnt++; } else { Uuid* uuid = new Uuid(); for (j = -1; j < dirLvlCnt; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchCopyA(dirObjectName, ARRAYLEN(dirObjectName), dirPtr); if(!SUCCEEDED(hr)) { goto exit; } ReplaceInvalidChars(dirObjectName); GetFileShortName(dirPtr, sdirname, FALSE); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s%i", spaces, sdirname, dirPtr, dirObjectName, dwDirectoryCounter); if (!SUCCEEDED(hr)) { goto exit; } dwDirectoryCounter++; PrintLine(hFile, itemDescription); dirLvlCnt++; // // Component // for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} if (FALSE == bPermanent) { hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } else { hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%sContent%x.%i", spaces, uuid->getString(), szIsWin64, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } } delete uuid; PrintLine(hFile, itemDescription); // print a condition line for this component, if needed if (TRUE == bPrintCondition) { PrintLine(hFile, szSKUCondition); } // // File // for (j = -1; j < dirLvlCnt+2; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} CHAR fileObjectName[MAX_PATH+1]; removeSpace(item->getName(), fileObjectName); ReplaceInvalidChars(fileObjectName); hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s_%s.%x.%i", spaces, item->getShortName(), item->getName(), item->getSrcDir(), item->getSrcName(), fileObjectName, flavor, dwComponentCounter); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); dwComponentCounter++; dirPtr = NULL; } } for (j = -1; j < dirLvlCnt+1; j++) {spaces[j+1] = ' '; spaces[j+2] = '\0';} hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); for (int i = dirLvlCnt; i > 0; i--) { spaces[i] = '\0'; hr = StringCchPrintfA(itemDescription, ARRAYLEN(itemDescription), "%s", spaces); if (!SUCCEEDED(hr)) { goto exit; } PrintLine(hFile, itemDescription); } item = item->getNext(); } } return; /****************** DEBUG ****************** File* item; CHAR itemDescription[4096]; item = list->getFirst(); while (item != NULL) { // // Item description // sprintf(itemDescription, " Source: %s\\%s", item->getSrcDir(), item->getSrcName()); PrintLine(hFile, itemDescription); sprintf(itemDescription, " Destination: %s\\%s", item->getDirectoryDestination(), item->getName()); PrintLine(hFile, itemDescription); PrintLine(hFile, ""); item = item->getNext(); } ****************** DEBUG ******************/ exit: printf("Error in PrintFileList\n"); return; } //////////////////////////////////////////////////////////////////////////// // // PrintLine // // Add a line at the end of the file. // //////////////////////////////////////////////////////////////////////////// BOOL PrintLine(HANDLE hFile, LPCSTR lpLine) { DWORD dwBytesWritten; SetFilePointer(hFile, 0, NULL, FILE_END); WriteFile( hFile, lpLine, _tcslen(lpLine) * sizeof(TCHAR), &dwBytesWritten, NULL ); SetFilePointer(hFile, 0, NULL, FILE_END); WriteFile( hFile, TEXT("\r\n"), _tcslen(TEXT("\r\n")) * sizeof(TCHAR), &dwBytesWritten, NULL ); return (TRUE); } /////////////////////////////////////////////////////////////////////////////// // // CreateOutputFile() // // Create the file that would received the package file contents. // /////////////////////////////////////////////////////////////////////////////// HANDLE CreateOutputFile(LPSTR filename) { SECURITY_ATTRIBUTES SecurityAttributes; // // Sanity check. // if (filename == NULL) { return INVALID_HANDLE_VALUE; } // // Create a security descriptor the output file. // SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; SecurityAttributes.bInheritHandle = FALSE; // // Create the file. // return CreateFile( filename, GENERIC_WRITE, 0, &SecurityAttributes, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } //////////////////////////////////////////////////////////////////////////// // // removeSpace // // Remove all space from a string. // //////////////////////////////////////////////////////////////////////////// VOID removeSpace(LPSTR src, LPSTR dest) { LPSTR strSrcPtr = src; LPSTR strDestPtr = dest; while (*strSrcPtr != '\0') { if (*strSrcPtr != ' ') { *strDestPtr = *strSrcPtr; strDestPtr++; } strSrcPtr++; } *strDestPtr = '\0'; } //////////////////////////////////////////////////////////////////////////// // // TransNum // // Converts a number string to a dword value (in hex). // //////////////////////////////////////////////////////////////////////////// DWORD TransNum(LPTSTR lpsz) { DWORD dw = 0L; TCHAR c; while (*lpsz) { c = *lpsz++; if (c >= TEXT('A') && c <= TEXT('F')) { c -= TEXT('A') - 0xa; } else if (c >= TEXT('0') && c <= TEXT('9')) { c -= TEXT('0'); } else if (c >= TEXT('a') && c <= TEXT('f')) { c -= TEXT('a') - 0xa; } else { break; } dw *= 0x10; dw += c; } return (dw); } /////////////////////////////////////////////////////////////////////////////// // // Usage // // Print the fonction usage. // /////////////////////////////////////////////////////////////////////////////// void Usage() { printf("Create Merge module MUI WXM files for different OS SKUs\n"); printf("Usage: infparser /p:[cdlaout] /b:[32|64] /l: /f:[p|s|a|d] /s: /o: /v\n"); printf(" where\n"); printf(" /p means the pseudo cd layout directory.\n"); printf(" : is cd layout directory in mui release share, e.g. cd1 (for jpn), or psu (for psu)\n"); printf(" /b means the binary.\n"); printf(" 32: i386\n"); printf(" 64: ia64\n"); printf(" /l means the language flag.\n"); printf(" : is the target language\n"); printf(" /f means the flavor.\n"); printf(" p: Professional\n"); printf(" s: Server\n"); printf(" a: Advanced Server\n"); printf(" d: Data Center\n"); printf(" l: Server for Small Business Server\n"); printf(" w: Web Blade\n"); printf(" /i means the location of the localized binairy files.\n"); printf(" : Fully qualified path\n"); printf(" /s means the location of the binairy data.\n"); printf(" : Fully qualified path\n"); printf(" /o means the xml file contents of specific flavor.\n"); printf(" : Fully qualified path\n"); printf(" /v means the verbose mode [optional].\n"); } /////////////////////////////////////////////////////////////////////////////// // // GetTempDirName // // Return the MUI temporary directory name, create it if not found // /////////////////////////////////////////////////////////////////////////////// BOOL GetTempDirName(LPSTR sLangName) { CHAR *pcBaseDirPtr = NULL; BOOL bFoundDir = FALSE; HRESULT hr; pcBaseDirPtr = getenv(TEXT("_NTPOSTBLD")); if (NULL != pcBaseDirPtr) { // sprintf(TempDirName, "%s\\%s\\%s\\%s\\%s", pcBaseDirPtr, sLangName, "mui", sLangName, "tmp\\infparser"); // sprintf(TempDirName, "%s\\%s\\%s\\%s", pcBaseDirPtr, "mui", sLangName, "tmp\\infparser"); hr = StringCchPrintfA(TempDirName, ARRAYLEN(TempDirName), "%s\\%s\\%s\\%s", pcBaseDirPtr, "mui", sLangName, "tmp\\infparser"); if (!SUCCEEDED(hr)) { goto exit; } // we will create this directory if it does not exist - although it should be by this stage if (FALSE == DirectoryExist(TempDirName)) { if (TRUE == CreateDirectory(TempDirName, NULL)) { bFoundDir = TRUE; if (!bSilence) printf("Infparser::GetTempDirName() - created MUI temp directory %s \n", TempDirName); } else { if (!bSilence) printf("Infparser::GetTempDirName() - failed to create MUI temp directory %s - The error returned is %d\n", TempDirName, GetLastError()); } } else bFoundDir = TRUE; } // if we cannot find the MUI temp directory and directory creation failed, use the default one instead if (FALSE == bFoundDir) { DWORD dwBufferLength = 0; dwBufferLength = GetTempPath(MAX_PATH, TempDirName); // tempdir returned contains an ending slash if (dwBufferLength > 0) { if (TRUE == DirectoryExist(TempDirName)) { bFoundDir = TRUE; } } } if (!bSilence) { if (FALSE == bFoundDir) printf("GetTempDirName: Cannot find/create temporary directory!\n"); else printf("GetTempDirName: temporary directory used is %s\n", TempDirName); } return bFoundDir; exit: printf("Error in GetTempDirName \n"); return FALSE; } BOOL GetFileShortName(const CHAR * pcInLongName, CHAR * pcOutShortName, BOOL bInFileExists) { CHAR LongFullPath[MAX_PATH]; CHAR ShortFullPath[MAX_PATH]; DWORD dwBufferSize = 0; // size of the returned shortname HANDLE tmpHandle; CHAR * pcIndex = NULL; // pointer index into src path of the file name HRESULT hr; if (NULL == pcInLongName || NULL == pcOutShortName) return FALSE; if (!bInFileExists) { hr = StringCchPrintfA(LongFullPath, ARRAYLEN(LongFullPath), "%s\\%s", TempDirName, pcInLongName); if (!SUCCEEDED(hr)) { goto exit; } if (!bSilence) printf("GetFileShortName: LongFullPath is %s.\n", LongFullPath); // create a temp file so that GetShortPathName will work tmpHandle = CreateFile(LongFullPath, GENERIC_ALL, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (tmpHandle) CloseHandle(tmpHandle); } else { hr = StringCchCopyA(LongFullPath, ARRAYLEN(LongFullPath), pcInLongName); if(!SUCCEEDED(hr)) { goto exit; } } dwBufferSize = GetShortPathName(LongFullPath, ShortFullPath, MAX_PATH); if (0 == dwBufferSize) { DWORD dwErrorCode = GetLastError(); if (!bSilence) { printf("GetFileShortName failed! GetShortPathName returned an error code of %d. Using longname as shortpath name. ", dwErrorCode); printf("fullpath is %s\n", LongFullPath); } hr = StringCchCopyA(pcOutShortName, MAX_PATH, pcInLongName); if(!SUCCEEDED(hr)) { goto exit; } } else { // find the filename from the path, if cannot find it, then use the source name GetFileNameFromFullPath(ShortFullPath, pcOutShortName); if (!pcOutShortName) { if (!bSilence) printf("GetShortPathName returned an empty string, using source name %s\n", pcInLongName); hr = StringCchCopyA(pcOutShortName, MAX_PATH, pcInLongName); if(!SUCCEEDED(hr)) { goto exit; } } } return TRUE; exit: printf("Error in GetFileShortName\n"); return FALSE; } BOOL IsInvalidChar(CHAR cCheck) { int i; BOOL bResult = FALSE; for (i=0; i < NO_INVALIDCHARS; i++) { if (cCheck == InvalidChars[i]) { bResult = TRUE; break; } } return bResult; } void ReplaceInvalidChars(CHAR *pcInName) { // if first char is not a alphabet or underscore, add an underscore to the name HRESULT hr; if ((!isalpha(*pcInName) && (*pcInName != '_') )) { CHAR tempBuffer[MAX_PATH+1]; hr = StringCchCopyA(tempBuffer, ARRAYLEN(tempBuffer), pcInName); if(!SUCCEEDED(hr)) { goto exit; } hr = StringCchCopyA(pcInName, MAX_PATH, tempBuffer); if(!SUCCEEDED(hr)) { goto exit; } } while (*pcInName) { if (IsInvalidChar(*pcInName)) *pcInName = '_'; // replace all invalid chars with underscores pcInName++; } return; exit: printf("Error in ReplaceInvalidChars \n"); return; } BOOL GetFileNameFromFullPath(const CHAR * pcInFullPath, CHAR * pcOutFileName) { CHAR * pcIndex = NULL; HRESULT hr; if (!pcInFullPath) { return FALSE; } if (!pcOutFileName) { return FALSE; } // find the filename from the path, if cannot find it, then use the fullpath as the outputfilename pcIndex = strrchr(pcInFullPath, '\\'); if (NULL != pcIndex) { pcIndex++; if (!bSilence) printf("Shortpath used is %s\n", pcIndex); hr = StringCchCopyA(pcOutFileName, MAX_PATH, pcIndex); // pcOutFileName size is MAX_PATH if(!SUCCEEDED(hr)) { goto exit; } } else if (0 < strlen(pcInFullPath)) // we just have the filename, use it as is. { if (!bSilence) printf("GetFileNameFromFullPath returned a path without a \\ in the path. ShortFileName is %s.\n", pcInFullPath); hr = StringCchCopyA(pcOutFileName, MAX_PATH, pcInFullPath); // pcOutFileName size is MAX_PATH if(!SUCCEEDED(hr)) { goto exit; } } else // didn't find the filename, use the passed in parameter instead { if (!bSilence) printf("GetFileNameFromFullPath returned an empty string, using source name %s\n", pcInFullPath); hr = StringCchCopyA(pcOutFileName, MAX_PATH, pcInFullPath); // pcOutFileName size is MAX_PATH if(!SUCCEEDED(hr)) { goto exit; } } return TRUE; exit: printf("Error in GetFileNameFromFullPath\n"); return TRUE; } void RenameMuiExtension(CHAR * dstFileName) { int iNameLen = 0; if (NULL == dstFileName) return; iNameLen = strlen(dstFileName); if (0 == iNameLen) return; // if the last char is a '/' or '\', remove it if ((dstFileName[iNameLen-1] == '\\') || (dstFileName[iNameLen-1] == '/')) { dstFileName[iNameLen-1] = '\0'; iNameLen --; } // if the last 4 chars are '.mui', replace the 'i' with '_' if (iNameLen >= 4) { if (_stricmp(dstFileName+(iNameLen-4), ".mui") == 0) { dstFileName[iNameLen-1] = '_'; } } return; } // // This function checks to see if there are any SKU specific external component INF directories under the supplied component path. // Note that the SKU subdirectories are as generated by the NT build environment. And also that the personal edition SKU directory // "perinf" is not included in the search. i.e. if perinf dir exists the function still returns false. // BOOL ContainSKUDirs(CHAR *pszDirPath) { WIN32_FIND_DATA FindData; HANDLE FindHandle = NULL; FINDEX_INFO_LEVELS fInfoLevelId; INT i; CHAR szSKURootPath[MAX_PATH]; BOOL bResult = FALSE; HRESULT hr; CHAR *szSKUDirs[5] = { "blainf\0", "dtcinf\0", "entinf\0", "sbsinf\0", "srvinf\0" }; if (NULL == pszDirPath) return FALSE; if (0 == strlen(pszDirPath)) return FALSE; for (i = 0; i < 5; i++) { // replace PathCombine(szSKURootPath, pszDirPath, szSKUDirs[i]) // with normal string operation. // szSKURootPath = pszDirPath + "\\" + szSKUDirs[i]; hr = StringCchPrintfA(szSKURootPath, ARRAYLEN(szSKURootPath), "%s\\%s",pszDirPath,szSKUDirs[i]); if (!SUCCEEDED(hr)) { return FALSE; } FindHandle = FindFirstFileEx(szSKURootPath, FindExInfoStandard, &FindData, FindExSearchLimitToDirectories, NULL, 0); if (FindHandle != INVALID_HANDLE_VALUE) { FindClose(FindHandle); if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { bResult = TRUE; break; } } } return (bResult); } BOOL GetSKUConditionString(CHAR *pszBuffer, DWORD dwFlavour) { BOOL bReturn = TRUE; HRESULT hr; if (NULL == pszBuffer) { bReturn = FALSE; // strcpy(pszBuffer, ""); goto Exit; } switch (dwFlavour) { case FLV_PROFESSIONAL: hr = StringCchCopyA(pszBuffer, 4096, PRO_SKU_CONDITION); if(!SUCCEEDED(hr)) { goto exit; } break; case FLV_SERVER: hr = StringCchCopyA(pszBuffer, 4096, SRV_SKU_CONDITION); if(!SUCCEEDED(hr)) { goto exit; } break; case FLV_ADVSERVER: hr = StringCchCopyA(pszBuffer, 4096, ADV_SKU_CONDITION); if(!SUCCEEDED(hr)) { goto exit; } break; case FLV_DATACENTER: hr = StringCchCopyA(pszBuffer, 4096, DTC_SKU_CONDITION); if(!SUCCEEDED(hr)) { goto exit; } break; case FLV_WEBBLADE: hr = StringCchCopyA(pszBuffer, 4096, BLA_SKU_CONDITION); if(!SUCCEEDED(hr)) { goto exit; } break; case FLV_SMALLBUSINESS: hr = StringCchCopyA(pszBuffer, 4096, SBS_SKU_CONDITION); if(!SUCCEEDED(hr)) { goto exit; } break; case FLV_PERSONAL: case FLV_UNDEFINED: case FLV_CORE: default: hr = StringCchCopyA(pszBuffer, 4096, ""); if(!SUCCEEDED(hr)) { goto exit; } bReturn = FALSE; break; } if (!bSilence) { printf("\nSKU Condition String is: %s\n", pszBuffer); } Exit: return bReturn; exit: printf("Error GetSKUConditionString \n"); return FALSE; } /////////////////////////////////////////////////////////////////////////// // // IsFileForSKU: // // This function takes a file name, the SKU flavour, and the processor architecture as an // argument. Then it checks to see if it exists as a source file in the SKU specified. // // the checking part is done by looking in the built layout.inf file for that sku to make sure // the file appears for that SKU only, the layout.inf file for the skus are located at: // // PRO sku: _NTPOSTBLD // PER sku: _NTPOSTBLD\perinf // SRV sku: _NTPOSTBLD\srvinf // ADS sku: _NTPOSTBLD\entinf // DTC sku: _NTPOSTBLD\dtcinf // SBS sku: _NTPOSTBLD\sbsinf // BLA sku: _NTPOSTBLD\blainf // // for all skus, check all the inf files for every sku and make sure it doesn't appear in every inf // but appears at least in the inf file designated for the sku we are searching for. // For Core sku, it must appear in every infs (the reverse for the above) // ignore and return false if personal or other undefined skus are specified // check first in [SourceDisksFiles] (common file section) // if not in there, we check based on arch, [SourceDiskFiles.x86] and [SourceDiskFiles.ia64] // note that here, the source and destination file names are the same, since they are not in the exception list // // strFileName: source filename to be checked (not the destination name) // dwSKU: SKU to check for (see infparser.h for the list of values) // dwArch: Architecture type to check for (see infparser.h for list of values) // // NOTE: this function needs to be reworked if we want to incorporate PER/PRO skus back into // the checking. Currently it only works for server skus. // /////////////////////////////////////////////////////////////////////////// BOOL IsFileForSKU(CHAR * strFileName, DWORD dwSKU, DWORD dwArch, FileLayoutExceptionList * exceptionList) { BOOL bFound = TRUE; BOOL bCoreFound = TRUE; BOOL bSkuFound = FALSE; BOOL bProPerFound = FALSE; BOOL bSrvSkusFound = FALSE; UINT i = 0; // index variable UINT iDesignated = 0; // the sku we are searching for. // validating parameters if (NULL == strFileName) { if (!bSilence) { printf("IsFileForSKU: Passed in filename is empty.\n"); } return FALSE; } // determines the inf files that we need to search switch (dwSKU) { case FLV_PROFESSIONAL: iDesignated = PRO_SKU_INDEX; break; case FLV_PERSONAL: iDesignated = PER_SKU_INDEX; break; case FLV_SERVER: iDesignated = SRV_SKU_INDEX; break; case FLV_ADVSERVER: iDesignated = ADV_SKU_INDEX; break; case FLV_DATACENTER: iDesignated = DTC_SKU_INDEX; break; case FLV_WEBBLADE: iDesignated = BLA_SKU_INDEX; break; case FLV_SMALLBUSINESS: iDesignated = SBS_SKU_INDEX; break; case FLV_CORE: iDesignated = NO_SKUS; break; default: return FALSE; break; } if (!bSilence) { printf("File %s\n", strFileName); } // search for the infs // NOTE: we search also in personal and professional skus, this is to make sure files we pick up // which are in \bin that aren't in the server layout.infs are not also in layout.infs for pro/per for (i = PRO_SKU_INDEX; i < NO_SKUS; i++) { bFound = IsFileInInf(strFileName, i, dwArch); if (!bSilence) { printf("SKU %s: %s ", SkuInfs[i].strSkuName, bFound ? "yes" : "no"); } if (iDesignated == i) { bSkuFound = bFound; } if ((i == PRO_SKU_INDEX) || (i == PER_SKU_INDEX)) { bProPerFound = (bProPerFound || bFound); } else { bCoreFound = (bFound && bCoreFound); bSkuFound = bFound || bSkuFound; } } if (dwSKU == FLV_CORE) { bFound = bCoreFound; // for CORE sku, if the file is not found in Pro/Per SKU, we will include it anyways // as long as it is not a destination file for any SKU, otherwise we will have // a MSI build error if ((!bFound) && (!bProPerFound) && (!bSkuFound)) { if (!exceptionList->searchDestName(strFileName)) bFound = TRUE; else bFound = FALSE; } } else { bFound = (!bCoreFound && bSkuFound); } if (!bSilence) { printf("\n"); if (bFound) { printf("The file %s is found in this sku.\n", strFileName); } else { printf("The file %s is not found in this sku.\n", strFileName); } } return bFound; } BOOL IsFileInInf(CHAR * strFileName, UINT iSkuIndex, DWORD dwArch) { UINT iLineCount = 0; UINT iLineNum = 0; FileLayoutExceptionList *flArch = NULL; CHAR * archSection = NULL; INFCONTEXT context; // validating parameters if (NULL == strFileName) { if (!bSilence) { printf("IsFileInInf: Passed in filename is empty.\n"); } return FALSE; } switch (dwArch) { case BIN_32: flArch = &(SkuInfs[iSkuIndex].flLayoutX86); break; case BIN_64: flArch = &(SkuInfs[iSkuIndex].flLayoutIA64); break; default: if (!bSilence) { printf("Invalid architecture specified.\n"); } return FALSE; break; } if (iSkuIndex > BLA_SKU_INDEX) { if (!bSilence) { printf("IsFileInInf: invalid SKU index passed in as parameter: %d.\n", iSkuIndex); } return FALSE; } if (SkuInfs[iSkuIndex].flLayoutCore.search(strFileName) != NULL) { return TRUE; } else if (flArch->search(strFileName) != NULL) { return TRUE; } else { return FALSE; } } // // This function reads in the layout.inf files for all the skus and stores the file information // in the filelist structure for later accessing. We are doing this so that we can gain // some performance instead of repeatedly using setup apis to read from the inf files itself // when we have to repeatedly search through these inf files to build the final file list // BOOL ReadInLayoutInfFiles() { UINT i = 0; UINT j = 0; UINT iLineCount = 0; UINT iLineNum = 0; INFCONTEXT context; FileLayout *file; HINF hInfFile = NULL; FileLayoutExceptionList *flist = NULL; // populate the layout.inf filelists for (i = 0; i < NO_SKUS; i++) { if (!bSilence) { printf("ReadInLayoutInfFiles: Reading files from %s for %s SKU.\n", SkuInfs[i].strLayoutInfPaths, SkuInfs[i].strSkuName); } hInfFile = SetupOpenInfFile(SkuInfs[i].strLayoutInfPaths, NULL, INF_STYLE_WIN4, NULL); if (INVALID_HANDLE_VALUE == hInfFile) { if (!bSilence) { printf("ReadInLayoutInfFiles: Failure opening %s file\n", SkuInfs[i].strLayoutInfPaths); } return FALSE; } // read in SourceDisksFiles section for (j = 0; j < 3; j++) { switch(j) { case (0): flist = &(SkuInfs[i].flLayoutCore); break; case (1): flist = &(SkuInfs[i].flLayoutX86); break; case (2): flist = &(SkuInfs[i].flLayoutIA64); break; default: // shouldn't happen return FALSE; } iLineCount = (UINT)SetupGetLineCount(hInfFile, strArchSections[j]); if (iLineCount > 0) { // // try to find the file in sourcedisksfiles. // CHAR name[MAX_PATH]; for (iLineNum = 0; iLineNum < iLineCount; iLineNum++) { if (SetupGetLineByIndex(hInfFile, strArchSections[j], iLineNum, &context) && SetupGetStringField(&context, 0, name, MAX_PATH, NULL)) { // add the file to the filelist, we are only interested in the source name, pass in bogus stuff for // the other members, we don't care what the sku is, just insert 0 for now. if (file = new FileLayout(name, name, 0)) { flist->insert(file); } } } } } SetupCloseInfFile(hInfFile); } return TRUE; }