|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
For Internal use only!
Module Name:
INFSCAN parseinfctx.cpp
Abstract:
Information about an individual INF (either primary INF being parsed by InfScan or a secondary included INF)
WARNING! WARNING! All of this implementation relies on intimate knowledge of SetupAPI/TextMode Setup/GuiMode Setup parsing of INF files.
It is re-implemented here for speed due to having to process 700+ INF's in a single go at the cost of having to maintain this.
DO NOT (I repeat) DO NOT re-implement the code here without consultation with SetupAPI owner.
History:
Created July 2001 - JamieHun
--*/
#include "precomp.h"
#pragma hdrstop
int ParseInfContext::LoadSourceDisksFiles() /*++
Routine Description:
Determine all source media information (as of right now, we don't need target disk information) Build a per-file list of possible media/platform information MAINTAINANCE: Keep in step with SourceDisksFiles syntax and decorations
Arguments: NONE
Return Value: 0 on success
--*/ { static StringProdPair decorations[] = { //
// listed from most specific to most generic
//
{ TEXT("SourceDisksFiles.x86"), PLATFORM_MASK_NTX86 }, { TEXT("SourceDisksFiles.ia64"), PLATFORM_MASK_NTIA64 }, { TEXT("SourceDisksFiles.amd64"), PLATFORM_MASK_NTAMD64 }, { TEXT("SourceDisksFiles"), PLATFORM_MASK_ALL_ARCHITECTS }, { NULL, 0 } };
INFCONTEXT context; int i; DWORD platforms = pGlobalScan->Version.PlatformMask & (PLATFORM_MASK_NT|PLATFORM_MASK_WIN); int res;
for(i=0;decorations[i].String;i++) { DWORD plat = platforms & decorations[i].ProductMask; if(plat) { res = LoadSourceDisksFilesSection(plat,decorations[i].String); if(res != 0) { return res; } } }
return 0; }
int ParseInfContext::LoadSourceDisksFilesSection(DWORD platform,const SafeString & section) /*++
Routine Description:
Helper function for LoadSourceDisksFiles loading information for a specific (decorated) section
Arguments: platform - specific platform or platforms that section is valid for section - section to load
Return Value: 0 on success
--*/ { //
// see if specified section exists
// load section into TargetList of same name
//
INFCONTEXT context;
if(!SetupFindFirstLine(InfHandle,section.c_str(),NULL,&context)) { return 0; } do { SafeString filename; SafeString name; if(!MyGetStringField(&context,0,filename) || filename.empty()) { pInfScan->Fail(MSG_BAD_FILENAME_ENTRY,section); continue; } SourceDisksFilesEntry entry; entry.Used = FALSE; entry.Platform = platform; if(!SetupGetIntField(&context,1,&entry.DiskId)) { pInfScan->Fail(MSG_BAD_FILENAME_DISK,section,filename); continue; } if(MyGetStringField(&context,2,name) && name.length()) { entry.SubDir = name; } if(!SetupGetIntField(&context,8,&entry.TargetDirectory)) { entry.TargetDirectory = 0; } if(!SetupGetIntField(&context,9,&entry.UpgradeDisposition)) { entry.UpgradeDisposition = 3; } else if((entry.UpgradeDisposition == 0) && MyGetStringField(&context,9,name) && name.empty()) { //
// actually empty field
//
entry.UpgradeDisposition = 3; } if(!SetupGetIntField(&context,10,&entry.TextModeDisposition)) { entry.TextModeDisposition = 3; } else if((entry.TextModeDisposition == 0) && MyGetStringField(&context,10,name) && name.empty()) { //
// actually empty field
//
entry.TextModeDisposition = 3; } if(MyGetStringField(&context,11,name) && name.length()) { entry.TargetName = name; } if((entry.UpgradeDisposition != 3) || (entry.TextModeDisposition != 3)) { if(entry.TargetDirectory) { LooksLikeLayoutInf = TRUE; } else { pInfScan->Fail(MSG_TEXTMODE_DISPOSITION_MISSING_DIR,section,filename); } } //
// is this a completely new entry for this file?
//
StringToSourceDisksFilesList::iterator sdfl = SourceDisksFiles.find(filename); if(sdfl == SourceDisksFiles.end()) { //
// never come across this name before (typical case)
//
SourceDisksFilesList blankList; sdfl = SourceDisksFiles.insert(sdfl,StringToSourceDisksFilesList::value_type(filename,blankList)); SourceDisksFilesList & list = sdfl->second; list.push_back(entry); } else { //
// there's already an entry for this filename
// see if this is an alternate location/info
//
SourceDisksFilesList & list = sdfl->second; SourceDisksFilesList::iterator i; BOOL conflict = FALSE; BOOL duplicate = FALSE; for(i = list.begin(); i != list.end(); i++) { //
// existing entries
//
SourceDisksFilesEntry & e = *i; //
// test numerics first then strings
//
if(entry.DiskId == e.DiskId && entry.TargetDirectory == e.TargetDirectory && entry.TextModeDisposition == e.TextModeDisposition && entry.UpgradeDisposition == e.UpgradeDisposition && entry.SubDir == e.SubDir && entry.TargetName == e.TargetName) { //
// already listed
//
duplicate = TRUE; break; } //
// the existing entry might be more specific than what we have
// eg, specific ia64, generic everything else
// so remove the flags from existing entry from mask
//
entry.Platform &= ~ e.Platform; if(pInfScan->Pedantic()) { conflict = TRUE; } } if (duplicate) { //
// duplicate/compatible entry listed
//
i->Platform |= entry.Platform; } else { //
// no duplicate or compatible
//
if (conflict) { //
// different source listings for different platforms
// might be an error
//
pInfScan->Fail(MSG_SOURCE_CONFLICT,section,filename); } list.push_back(entry); } }
} while (SetupFindNextLine(&context,&context)); return 0; }
int ParseInfContext::QuerySourceFile(DWORD platforms,const SafeString & section,const SafeString & source,SourceDisksFilesList & Target) /*++
Routine Description:
See also InstallScan::QuerySourceFile Determine list of possible source entries for given source file This can be zero (bad layout) 1 (typical) >1 (multiple targets) WARNING! This shadows SetupAPI implementation always subject to change MAINTAINANCE: keep in step with SetupAPI
Arguments: platforms - bitmap list of platforms we're interested in section - name of the copy section or install section (for error reporting only) source - name of source file Target - returned list of source media information
Return Value: 0 on success
--*/ { //
// return list of entries matching source file
//
StringToSourceDisksFilesList::iterator sdfl = SourceDisksFiles.find(source);
if(sdfl == SourceDisksFiles.end()) { //
// not found
// don't fail here, caller will try a few more alternatives
//
return 0; }
SourceDisksFilesList & list = sdfl->second; SourceDisksFilesList::iterator i;
for(i = list.begin(); i != list.end(); i++) { //
// existing entries
//
SourceDisksFilesEntry & e = *i; if ((e.Platform & platforms) == 0) { continue; } Target.push_back(e); }
if(!Target.size()) { pInfScan->Fail(MSG_SOURCE_NOT_LISTED_PLATFORM,section,source); //
// indicate we errored out
//
return -1; }
return 0; }
int ParseInfContext::LoadWinntDirectories(IntToString & Target) /*++
Routine Description:
Load the Layout.INF specific [WinntDirectories] to aid in textmode vs setupapi consistency WARNING! This relies heavily on current textmode implementation subject to change MAINTAINANCE: Keep in step with textmode
Arguments: Target - initialized with <id> to <subdirectory> mapping
Return Value: 0 on success
--*/ { if(pGlobalScan->IgnoreErrors && !pGlobalScan->TargetsToo) { //
// don't bother if we're not interested in errors
// (unless we want target information)
//
return 0; } INFCONTEXT context;
if(!SetupFindFirstLine(InfHandle,TEXT("WinntDirectories"),NULL,&context)) { return 0; } do { int index; TCHAR path[MAX_PATH]; if(SetupGetIntField(&context,0,&index) && index) { if(!SetupGetStringField(&context,1,path,MAX_PATH,NULL) || !path[0]) { continue; } _tcslwr(path); IntToString::iterator i = Target.find(index); if(i == Target.end()) { Target[index] = path; } else { if(i->second.compare(path)!=0) { //
// mismatch
//
pInfScan->Fail(MSG_WINNT_DIRECTORY_CONFLICT,i->second,path); } } } } while (SetupFindNextLine(&context,&context)); return 0; }
int ParseInfContext::LoadDestinationDirs() /*++
Routine Description:
Load the [DestinationDirs] Also uses pGlobalScan->GlobalDirectories to remap certain ID's WARNING! This relies heavily on current SetupAPI and textmode implementations subject to change MAINTAINANCE: Keep in step with textmode vs SetupAPI directory ID's
Arguments: NONE
Return Value: 0 on success
--*/ { if(pGlobalScan->IgnoreErrors && !pGlobalScan->TargetsToo) { //
// don't bother if we're not interested in errors
// (unless we want target information)
//
return 0; } INFCONTEXT context;
if(!SetupFindFirstLine(InfHandle,TEXT("DestinationDirs"),NULL,&context)) { return 0; }
//
//
// MAINTAINANCE:
// this table needs to correlate to LAYOUT.INX
//
// process [DestinationDirs] if there is one
// <section> = dirid,subdir
//
// normalize following dirid's:
// 10,subdir - as is
// 11,subdir - 10,system32\subdir
// 12,subdir - 10,system32\drivers\subdir
// 17,subdir - 10,inf\subdir
// 18,subdir -
TCHAR section[LINE_LEN]; int dirid = 0; TCHAR subdir[MAX_PATH]; int global_equiv[] = { 0,0,0,0,0,0,0,0,0,0,0, // 0-10
2, // 11 - system32
4, // 12 - system32/drivers
0,0,0,0, // 13-16
20, // 17 - inf
21, // 18 - help
0, // 19
22, // 20 - fonts
0 };
do { int index; TCHAR path[MAX_PATH]; if(!SetupGetStringField(&context,0,section,LINE_LEN,NULL) || !section[0]) { continue; } _tcslwr(section); if(!SetupGetIntField(&context,1,&dirid) || dirid == 0) { pInfScan->Fail(MSG_DIRID_NOT_SPECIFIED,section); dirid = 0; } if(!SetupGetStringField(&context,2,subdir,MAX_PATH,NULL)) { subdir[0] = TEXT('\0'); } _tcslwr(subdir); TargetDirectoryEntry entry; entry.Used = false; entry.DirId = dirid; entry.SubDir = subdir; //
// certain dirid have a global equiv, remap
//
if(dirid>0 && dirid < ASIZE(global_equiv)) { int equiv = global_equiv[dirid]; if(equiv) { IntToString::iterator i = pGlobalScan->GlobalDirectories.find(equiv); if(i != pGlobalScan->GlobalDirectories.end()) { //
// we have a mapping relative to dirID 10.
//
entry.DirId = 10; entry.SubDir = PathConcat(i->second,subdir); } } } //
// make a note
//
DestinationDirectories[section] = entry;
} while (SetupFindNextLine(&context,&context));
//
// now determine default
//
CopySectionToTargetDirectoryEntry::iterator tde = DestinationDirectories.find(TEXT("defaultdestdir")); if(tde != DestinationDirectories.end()) { DefaultTargetDirectory = tde; }
return 0; }
void ParseInfContext::PartialCleanup() /*++
Routine Description:
Cleanup information not required by results phase In particular, INF handle must ALWAYS be closed
Arguments: NONE
Return Value: NONE
--*/ { if(InfHandle != INVALID_HANDLE_VALUE) { SetupCloseInfFile(InfHandle); InfHandle = INVALID_HANDLE_VALUE; } SourceDisksFiles.clear(); CompletedCopySections.clear(); }
|