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.
619 lines
16 KiB
619 lines
16 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
For Internal use only!
|
|
|
|
Module Name:
|
|
|
|
INFSCAN
|
|
verinfo.cpp
|
|
|
|
Abstract:
|
|
|
|
Platform version matching
|
|
|
|
WARNING! WARNING!
|
|
All of this implementation relies on intimate knowledge of
|
|
SetupAPI parsing of INF files. Particularly processing
|
|
of [Manufacturer] seciton.
|
|
|
|
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
|
|
|
|
BasicVerInfo::BasicVerInfo()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize BasicVerInfo data
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Return Value:
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
PlatformMask = PLATFORM_MASK_ALL;
|
|
VersionHigh = 0;
|
|
VersionLow = 0;
|
|
ProductType = 0;
|
|
ProductSuite = 0;
|
|
}
|
|
|
|
int BasicVerInfo::Parse(PTSTR verString)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse a (modifiable) verString
|
|
determining range of platforms supported
|
|
version supported
|
|
product type supported
|
|
range of product suites supported
|
|
and a bitmap of what was specified
|
|
|
|
syntax currently:
|
|
|
|
<plat>.<maj>.<min>.<typ>.<suite>
|
|
|
|
WARNING! This can be extended by SetupAPI
|
|
MAINTAINANCE: format must correlate with SetupAPI manufacturer/models version syntax
|
|
MAINTAINANCE: add all supported platforms
|
|
|
|
Arguments:
|
|
Version string, eg "ntx86.5.1"
|
|
|
|
Return Value:
|
|
0 if success
|
|
|
|
--*/
|
|
{
|
|
PlatformMask = 0;
|
|
|
|
int i;
|
|
PTSTR nn = verString;
|
|
|
|
for (i = 0;i<5;i++) {
|
|
PCTSTR n = nn;
|
|
while((*nn) && (*nn != TEXT('.'))) {
|
|
nn++;
|
|
}
|
|
TCHAR c = *nn;
|
|
*nn = TEXT('\0');
|
|
switch(i) {
|
|
case 0: // platform
|
|
if(!n[0]) {
|
|
PlatformMask |= PLATFORM_MASK_ALL_ARCHITECTS;
|
|
break;
|
|
}
|
|
if(_tcsicmp(n,TEXT("win"))==0) {
|
|
PlatformMask = (PlatformMask & ~PLATFORM_MASK_ALL_ARCHITECTS) | PLATFORM_MASK_WIN;
|
|
break;
|
|
}
|
|
if(_tcsicmp(n,TEXT("NTx86"))==0) {
|
|
PlatformMask = (PlatformMask & ~PLATFORM_MASK_ALL_ARCHITECTS) | PLATFORM_MASK_NTX86;
|
|
break;
|
|
}
|
|
if(_tcsicmp(n,TEXT("NTia64"))==0) {
|
|
PlatformMask = (PlatformMask & ~PLATFORM_MASK_ALL_ARCHITECTS) | PLATFORM_MASK_NTIA64;
|
|
break;
|
|
}
|
|
if(_tcsicmp(n,TEXT("NTamd64"))==0) {
|
|
PlatformMask = (PlatformMask & ~PLATFORM_MASK_ALL_ARCHITECTS) | PLATFORM_MASK_NTAMD64;
|
|
break;
|
|
}
|
|
if(_tcsicmp(n,TEXT("NT"))==0) {
|
|
PlatformMask = (PlatformMask & ~PLATFORM_MASK_ALL_ARCHITECTS) | PLATFORM_MASK_NT;
|
|
break;
|
|
}
|
|
return 4;
|
|
|
|
case 1: // major
|
|
if(!n[0]) {
|
|
PlatformMask |= PLATFORM_MASK_ALL_MAJOR_VER;
|
|
break;
|
|
}
|
|
PlatformMask &= ~PLATFORM_MASK_ALL_MAJOR_VER;
|
|
VersionHigh = _tcstoul(n,NULL,0);
|
|
break;
|
|
|
|
case 2: // minor
|
|
if(!n[0]) {
|
|
PlatformMask |= PLATFORM_MASK_ALL_MINOR_VER;
|
|
break;
|
|
}
|
|
PlatformMask &= ~PLATFORM_MASK_ALL_MINOR_VER;
|
|
VersionLow = _tcstoul(n,NULL,0);
|
|
break;
|
|
|
|
case 3: // type
|
|
if(!n[0]) {
|
|
PlatformMask |= PLATFORM_MASK_ALL_TYPE;
|
|
break;
|
|
}
|
|
PlatformMask &= ~PLATFORM_MASK_ALL_TYPE;
|
|
ProductType = _tcstoul(n,NULL,0);
|
|
break;
|
|
|
|
case 4: // suite
|
|
if(!n[0]) {
|
|
PlatformMask |= PLATFORM_MASK_ALL_SUITE;
|
|
break;
|
|
}
|
|
PlatformMask &= ~PLATFORM_MASK_ALL_SUITE;
|
|
ProductSuite = _tcstoul(n,NULL,0);
|
|
break;
|
|
|
|
}
|
|
if(c) {
|
|
*nn = c;
|
|
nn++;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
bool BasicVerInfo::IsCompatibleWith(BasicVerInfo & other)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if given version is compatible with other (actual) version
|
|
To put into context,
|
|
this: version of a model decoration
|
|
other: information about target OS
|
|
|
|
note that A.IsCompatibleWith(B)
|
|
does not imply B.IsCompatibleWith(A)
|
|
|
|
|
|
Arguments:
|
|
BasicVerInfo to compare against (usually GlobalScan::Version)
|
|
|
|
Return Value:
|
|
true if they are (loosely) compatible
|
|
false if mutually exclusive
|
|
|
|
ie. NTx86 is compatible with NTx86.5.1
|
|
NTx86 is mutually exclusive with NTia64
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// first match the platform architecture
|
|
//
|
|
if(!((other.PlatformMask & PlatformMask) & PLATFORM_MASK_ALL_ARCHITECTS)) {
|
|
//
|
|
// mutually exclusive platform
|
|
//
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Version
|
|
//
|
|
if(!((other.PlatformMask | PlatformMask) & PLATFORM_MASK_ALL_MAJOR_VER)) {
|
|
//
|
|
// explicit major version required
|
|
//
|
|
if(other.VersionHigh < VersionHigh) {
|
|
//
|
|
// this entry is not compatible with target
|
|
//
|
|
return FALSE;
|
|
}
|
|
if(other.VersionHigh == VersionHigh) {
|
|
//
|
|
// need to check VersionLow
|
|
//
|
|
if(!((other.PlatformMask | PlatformMask) & PLATFORM_MASK_ALL_MINOR_VER)) {
|
|
//
|
|
// explicit minor version required
|
|
//
|
|
if(other.VersionLow < VersionLow) {
|
|
//
|
|
// this entry is not compatible with target
|
|
//
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Product Type - must be explicit or wild-carded
|
|
//
|
|
if(!((other.PlatformMask | PlatformMask) & PLATFORM_MASK_ALL_TYPE)) {
|
|
if(other.ProductType != ProductType) {
|
|
//
|
|
// this entry is not compatible with target
|
|
//
|
|
return FALSE;
|
|
}
|
|
}
|
|
//
|
|
// Product Suite - must be mask or wild-carded
|
|
//
|
|
if(!((other.PlatformMask | PlatformMask) & PLATFORM_MASK_ALL_SUITE)) {
|
|
if(!(other.ProductSuite & ProductSuite)) {
|
|
//
|
|
// this entry is not compatible with target
|
|
//
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int BasicVerInfo::IsBetter(BasicVerInfo & other,BasicVerInfo & filter)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
More complex check between this & other
|
|
|
|
filter is target OS version (GlobalScan::Version)
|
|
|
|
Arguments:
|
|
BasicVerInfo to compare against (usually another model version)
|
|
|
|
Return Value:
|
|
if 'other' is definately better than primary, return 1
|
|
if 'other' and this likely are both just as good/bad (but not same), return 0
|
|
if 'other' is exactly the same as primary, return -1
|
|
if 'other' is definately worse than primary, return -2
|
|
|
|
|
|
--*/
|
|
{
|
|
//
|
|
//
|
|
// for a field:
|
|
//
|
|
// if field is filtered as not testable, then both primary and other are
|
|
// either 'same' or 'likely'
|
|
//
|
|
int testres;
|
|
int suggest;
|
|
|
|
//
|
|
// check platform
|
|
//
|
|
if((PlatformMask ^ other.PlatformMask) & PLATFORM_MASK_ALL_ARCHITECTS) {
|
|
//
|
|
// the two platform matches are different
|
|
// result will be 1/0/-2
|
|
//
|
|
DWORD o_plat = other.PlatformMask & filter.PlatformMask & PLATFORM_MASK_ALL_ARCHITECTS;
|
|
DWORD t_plat = PlatformMask & filter.PlatformMask & PLATFORM_MASK_ALL_ARCHITECTS;
|
|
|
|
if(o_plat == t_plat) {
|
|
//
|
|
// both are in the same realm
|
|
//
|
|
// a more generic one is allowable if a more specific one
|
|
// could get rejected for other reasons
|
|
// so mark this as a suggestion at this moment
|
|
//
|
|
if((o_plat ^ other.PlatformMask) & PLATFORM_MASK_ALL_ARCHITECTS) {
|
|
//
|
|
// 'other' is less specific
|
|
//
|
|
testres = -2;
|
|
} else {
|
|
//
|
|
// 'other' is more specific
|
|
//
|
|
testres = 1;
|
|
}
|
|
} else {
|
|
//
|
|
// consider both
|
|
//
|
|
return 0;
|
|
}
|
|
} else {
|
|
//
|
|
// they are exactly the same
|
|
//
|
|
testres = -1;
|
|
}
|
|
|
|
if(PlatformMask & PLATFORM_MASK_ALL_MAJOR_VER) {
|
|
//
|
|
// we have generic version
|
|
//
|
|
if(other.PlatformMask & PLATFORM_MASK_ALL_MAJOR_VER) {
|
|
//
|
|
// other also has generic version
|
|
//
|
|
suggest = -1;
|
|
} else {
|
|
//
|
|
// 'other' has specific version, so it wins
|
|
//
|
|
suggest = 1;
|
|
}
|
|
} else {
|
|
//
|
|
// we have specific version
|
|
//
|
|
if(other.PlatformMask & PLATFORM_MASK_ALL_MAJOR_VER) {
|
|
//
|
|
// 'other' has generic version, so we win
|
|
//
|
|
suggest = -2;
|
|
} else {
|
|
//
|
|
// both have specific major version
|
|
//
|
|
if(other.VersionHigh > VersionHigh) {
|
|
//
|
|
// 'other' has higher version, it wins
|
|
//
|
|
suggest = 1;
|
|
} else if(VersionHigh > other.VersionHigh) {
|
|
//
|
|
// we have higher version, we win
|
|
//
|
|
suggest = -2;
|
|
} else {
|
|
//
|
|
// version-high matches, need to check version low
|
|
//
|
|
if(PlatformMask & PLATFORM_MASK_ALL_MINOR_VER) {
|
|
//
|
|
// we have generic version
|
|
//
|
|
if(other.PlatformMask & PLATFORM_MASK_ALL_MINOR_VER) {
|
|
//
|
|
// other also has generic version, draw
|
|
//
|
|
suggest = -1;
|
|
} else {
|
|
//
|
|
// 'other' has specific version, so it wins
|
|
//
|
|
suggest = 1;
|
|
}
|
|
} else {
|
|
//
|
|
// we have specific version
|
|
//
|
|
if(other.PlatformMask & PLATFORM_MASK_ALL_MINOR_VER) {
|
|
//
|
|
// 'other' has generic version, so we win
|
|
//
|
|
suggest = -2;
|
|
} else {
|
|
//
|
|
// both have specific minor version, higher version wins
|
|
//
|
|
if(other.VersionLow > VersionLow) {
|
|
suggest = 1;
|
|
} else if(VersionLow > other.VersionLow) {
|
|
suggest = -2;
|
|
} else {
|
|
//
|
|
// draw
|
|
//
|
|
suggest = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(suggest != -1) {
|
|
//
|
|
// if we suggested anything other than a draw
|
|
//
|
|
if(filter.PlatformMask & PLATFORM_MASK_ALL_MINOR_VER) {
|
|
//
|
|
// consider as two possible outcomes
|
|
//
|
|
return 0;
|
|
|
|
} else if (testres == -1) {
|
|
//
|
|
// the two are no longer identical
|
|
//
|
|
testres = suggest;
|
|
}
|
|
}
|
|
|
|
if((PlatformMask ^other.PlatformMask) & PLATFORM_MASK_ALL_TYPE) {
|
|
//
|
|
// product types are different (one generic, one specific)
|
|
//
|
|
if(filter.PlatformMask & PLATFORM_MASK_ALL_TYPE) {
|
|
//
|
|
// consider both outcomes
|
|
//
|
|
return 0;
|
|
|
|
} else if (testres == -1) {
|
|
//
|
|
// we're keying off type
|
|
//
|
|
if(PlatformMask & PLATFORM_MASK_ALL_TYPE) {
|
|
//
|
|
// 'other' has specific suite
|
|
//
|
|
testres = 1;
|
|
} else {
|
|
//
|
|
// we have specific suite
|
|
//
|
|
testres = -2;
|
|
}
|
|
}
|
|
} else if(! (PlatformMask & other.PlatformMask & PLATFORM_MASK_ALL_TYPE)) {
|
|
//
|
|
// both specified type
|
|
//
|
|
if (ProductType != other.ProductType) {
|
|
//
|
|
// if types are different, consider both
|
|
//
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if((PlatformMask ^other.PlatformMask) & PLATFORM_MASK_ALL_SUITE) {
|
|
//
|
|
// product suites are different (one generic, one 'specific')
|
|
//
|
|
if(filter.PlatformMask & PLATFORM_MASK_ALL_SUITE) {
|
|
//
|
|
// consider both outcomes
|
|
//
|
|
return 0;
|
|
|
|
} else if (testres == -1) {
|
|
//
|
|
// we're keying off suite
|
|
//
|
|
if(PlatformMask & PLATFORM_MASK_ALL_SUITE) {
|
|
//
|
|
// 'other' has specific suite
|
|
//
|
|
testres = 1;
|
|
} else {
|
|
//
|
|
// we have specific suite
|
|
//
|
|
testres = -2;
|
|
}
|
|
}
|
|
} else if(! (PlatformMask & other.PlatformMask & PLATFORM_MASK_ALL_SUITE)) {
|
|
//
|
|
// both specified suite
|
|
//
|
|
if (ProductSuite != other.ProductSuite) {
|
|
return 0;
|
|
}
|
|
}
|
|
return testres;
|
|
}
|
|
|
|
//
|
|
//
|
|
// NodeVerInfo - adaptation of BasicVerInfo
|
|
// where a decoration string needs to be kept
|
|
// for selecting what decorations to consider
|
|
//
|
|
|
|
NodeVerInfo::NodeVerInfo()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize NodeVerInfo data
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Return Value:
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
Rejected = false;
|
|
}
|
|
|
|
|
|
int NodeVerInfo::Parse(PTSTR verString)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse a (modifiable) verString
|
|
and also save a copy as Decoration
|
|
|
|
Arguments:
|
|
Version string, eg "ntx86.5.1"
|
|
|
|
Return Value:
|
|
0 if success
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// copy it before it's modified
|
|
//
|
|
Decoration = verString;
|
|
return BasicVerInfo::Parse(verString);
|
|
}
|
|
|
|
int NodeVerInfo::Parse(const SafeString & str)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse an unmodifiable verString
|
|
|
|
Arguments:
|
|
Version string, eg "ntx86.5.1"
|
|
|
|
Return Value:
|
|
0 if success
|
|
|
|
--*/
|
|
{
|
|
PTSTR buf;
|
|
buf = new TCHAR[str.length()+1];
|
|
lstrcpy(buf,str.c_str());
|
|
int res = Parse(buf);
|
|
delete [] buf;
|
|
return res;
|
|
}
|
|
|
|
int NodeVerInfo::IsBetter(NodeVerInfo & other,BasicVerInfo & filter)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Specific variation of 'IsBetter'
|
|
|
|
Arguments:
|
|
Same as BasicVersion::IsBetter
|
|
|
|
Return Value:
|
|
Same as BasicVersion::IsBetter
|
|
|
|
--*/
|
|
{
|
|
int testres = BasicVerInfo::IsBetter(other,filter);
|
|
if(testres == -1) {
|
|
//
|
|
// we considered both equally ranked
|
|
// compare the strings. If the strings are
|
|
// different, consider both
|
|
//
|
|
if(Decoration.length() != other.Decoration.length()) {
|
|
return 0;
|
|
}
|
|
if(_tcsicmp(Decoration.c_str(),other.Decoration.c_str())!=0) {
|
|
return 0;
|
|
}
|
|
}
|
|
return testres;
|
|
}
|
|
|
|
|