|
|
/*++
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; }
|