|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
rules.c
Abstract:
Implements the "rule" algorithm that scores script patterns and keeps them in reverse-sorted order.
Author:
Jim Schmidt (jimschm) 12-May-2000
Revision History:
<alias> <date> <comments>
--*/
//
// Includes
//
#include "pch.h"
#include "v1p.h"
#define DBG_V1 "v1"
//
// Strings
//
// None
//
// Constants
//
// None
//
// Macros
//
// None
//
// Types
//
typedef struct _TAG_RULE { PCTSTR ObjectBase; MIG_OBJECTSTRINGHANDLE ObjectPattern; POBSPARSEDPATTERN ParsedPattern; UINT Score; ACTIONGROUP ActionGroup; DWORD ActionFlags; ACTION_STRUCT ActionStruct; struct _TAG_RULE *NextRule; } RULE, *PRULE;
typedef struct _TAG_CHAR_NODE { PRULE RuleList; WORD Char; WORD Flags; struct _TAG_CHAR_NODE *NextLevel; struct _TAG_CHAR_NODE *NextPeer; } CHAR_NODE, *PCHAR_NODE;
typedef struct { MIG_OBJECTTYPEID ObjectTypeId; PRULE RuleList; PCHAR_NODE FirstLevel; } TYPE_RULE, *PTYPE_RULE;
typedef struct { MIG_OBJECTTYPEID ObjectTypeId; TYPE_RULE TypeRule; } TYPETORULE, *PTYPETORULE;
//
// Globals
//
GROWBUFFER g_TypeToIncRule = INIT_GROWBUFFER; GROWBUFFER g_TypeToPriRule = INIT_GROWBUFFER; GROWBUFFER g_TypeToCollRule = INIT_GROWBUFFER; GROWBUFFER g_TypeRuleList = INIT_GROWBUFFER; PMHANDLE g_RulePool;
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
// None
//
// Macro expansion definition
//
// None
//
// Code
//
BOOL pAddRuleToTypeRule ( IN PTYPE_RULE TypeRule, IN PRULE Rule ) { PCHAR_NODE node, currNode, prevNode; PTSTR objectBase; PCTSTR p; WORD w; BOOL found;
if (Rule->ObjectBase) { currNode = TypeRule->FirstLevel; prevNode = currNode; objectBase = DuplicatePathString (Rule->ObjectBase, 0); CharLower (objectBase); p = objectBase; while (*p) { w = (WORD) _tcsnextc (p); p = _tcsinc (p); if (currNode) { if (currNode->Char == w) { if (!*p) { Rule->NextRule = currNode->RuleList; currNode->RuleList = Rule; } prevNode = currNode; currNode = currNode->NextLevel; } else { found = FALSE; while (!found && currNode->NextPeer) { if (currNode->NextPeer->Char == w) { if (!*p) { Rule->NextRule = currNode->NextPeer->RuleList; currNode->NextPeer->RuleList = Rule; } prevNode = currNode->NextPeer; currNode = prevNode->NextLevel; found = TRUE; break; } currNode = currNode->NextPeer; } if (!found) { node = PmGetMemory (g_RulePool, sizeof (CHAR_NODE)); ZeroMemory (node, sizeof (CHAR_NODE)); if (!*p) { node->RuleList = Rule; } node->Char = w; node->NextPeer = currNode->NextPeer; currNode->NextPeer = node; prevNode = node; currNode = node->NextLevel; } } } else { node = PmGetMemory (g_RulePool, sizeof (CHAR_NODE)); ZeroMemory (node, sizeof (CHAR_NODE)); if (!*p) { node->RuleList = Rule; } node->Char = w; if (prevNode) { prevNode->NextLevel = node; } else { TypeRule->FirstLevel = node; } prevNode = node; currNode = prevNode->NextLevel; } } FreePathString (objectBase); } else { Rule->NextRule = TypeRule->RuleList; TypeRule->RuleList = Rule; } return TRUE; }
UINT pComputeSubScore ( IN BOOL ExcludeLastPatSeg, IN PCTSTR String, IN UINT WildcardScore, IN UINT FixedCharScore, IN UINT WackScoreBeforeWildcard, IN UINT WackScoreAfterWildcard ) { PCTSTR p; BOOL skipExtendedPattern; UINT score = 0; BOOL patternEncountered = FALSE; CHARTYPE ch; UINT state = 0; UINT delScore = 0;
for (p = String ; *p ; p = _tcsinc (p)) {
skipExtendedPattern = FALSE;
switch (_tcsnextc (p)) {
case TEXT('*'): if (state == 1) { state = 2; } if (state == 2) { delScore += WildcardScore; } score += WildcardScore; skipExtendedPattern = TRUE; patternEncountered = TRUE; break;
case TEXT('?'): if (state == 1) { state = 2; } if (state == 2) { delScore += WildcardScore; } score += WildcardScore; skipExtendedPattern = TRUE; patternEncountered = TRUE; break;
case TEXT('\\'): state = 1; if (patternEncountered) { score += WackScoreAfterWildcard; delScore = WackScoreAfterWildcard; } else { score += WackScoreBeforeWildcard; delScore = WackScoreBeforeWildcard; } break;
case TEXT(':'): //
// Special case: if just a drive spec with no wacks,
// add the wack score
//
if (p[1] == 0) { score += WackScoreBeforeWildcard; break; }
// fall through
default: state = 0; delScore = 0; score += FixedCharScore; break; }
if (skipExtendedPattern) { if (_tcsnextc (_tcsinc (p)) == TEXT('[')) { do { p = _tcsinc (p);
ch = (CHARTYPE) _tcsnextc (p); if (ch == TEXT('^')) { p++; }
} while (ch != TEXT(']')); } } }
if (ExcludeLastPatSeg) { if (score > delScore) { score -= delScore; if (delScore && score > 0) { score -= 1; } } else { score = 0; } }
return score; }
UINT pComputeScore ( IN MIG_OBJECTSTRINGHANDLE EncodedString ) { PCTSTR node; PCTSTR leaf; UINT score = 0;
IsmCreateObjectStringsFromHandle (EncodedString, &node, &leaf);
if (node) { score += 1000 * pComputeSubScore (TRUE, node, 0, 10, 1000, 500); }
if (leaf) { score += pComputeSubScore (FALSE, leaf, 0, 10, 0, 0); }
IsmDestroyObjectString (node); IsmDestroyObjectString (leaf);
return score; }
PTYPE_RULE pGetListForType ( IN PGROWBUFFER TypeToRule, IN MIG_OBJECTTYPEID ObjectTypeId ) { PTYPE_RULE pos; PTYPE_RULE end;
ObjectTypeId &= ~(PLATFORM_MASK);
pos = (PTYPE_RULE) TypeToRule->Buf; end = (PTYPE_RULE) (TypeToRule->Buf + TypeToRule->End);
while (pos < end) { if (pos->ObjectTypeId == ObjectTypeId) { return pos; } pos++; }
pos = (PTYPE_RULE) GbGrow (TypeToRule, sizeof (TYPE_RULE));
ZeroMemory (pos, sizeof (TYPE_RULE)); pos->ObjectTypeId = ObjectTypeId;
return pos; }
VOID InitRules ( VOID ) { g_RulePool = PmCreateNamedPoolEx ("Rule Data", 32768); PmDisableTracking (g_RulePool); }
VOID TerminateRules ( VOID ) { GbFree (&g_TypeToIncRule); GbFree (&g_TypeToPriRule); GbFree (&g_TypeToCollRule); GbFree (&g_TypeRuleList);
PmEmptyPool (g_RulePool); PmDestroyPool (g_RulePool); INVALID_POINTER (g_RulePool); }
UINT pGetActionWeight ( IN ACTIONGROUP ActionGroup ) { switch (ActionGroup) { case ACTIONGROUP_DEFAULTPRIORITY: return ACTIONWEIGHT_DEFAULTPRIORITY; case ACTIONGROUP_SPECIFICPRIORITY: return ACTIONWEIGHT_SPECIFICPRIORITY; case ACTIONGROUP_EXCLUDE: return ACTIONWEIGHT_EXCLUDE; case ACTIONGROUP_EXCLUDEEX: return ACTIONWEIGHT_EXCLUDEEX; case ACTIONGROUP_INCLUDE: return ACTIONWEIGHT_INCLUDE; case ACTIONGROUP_INCLUDEEX: return ACTIONWEIGHT_INCLUDEEX; case ACTIONGROUP_RENAME: return ACTIONWEIGHT_RENAME; case ACTIONGROUP_RENAMEEX: return ACTIONWEIGHT_RENAMEEX; case ACTIONGROUP_INCLUDERELEVANT: return ACTIONWEIGHT_INCLUDERELEVANT; case ACTIONGROUP_INCLUDERELEVANTEX: return ACTIONWEIGHT_INCLUDERELEVANTEX; case ACTIONGROUP_RENAMERELEVANT: return ACTIONWEIGHT_RENAMERELEVANT; case ACTIONGROUP_RENAMERELEVANTEX: return ACTIONWEIGHT_RENAMERELEVANTEX; case ACTIONGROUP_REGFILE: return ACTIONWEIGHT_REGFILE; case ACTIONGROUP_REGFILEEX: return ACTIONWEIGHT_REGFILEEX; case ACTIONGROUP_REGFOLDER: return ACTIONWEIGHT_REGFOLDER; case ACTIONGROUP_REGFOLDEREX: return ACTIONWEIGHT_REGFOLDEREX; case ACTIONGROUP_REGICON: return ACTIONWEIGHT_REGICON; case ACTIONGROUP_REGICONEX: return ACTIONWEIGHT_REGICONEX; case ACTIONGROUP_DELREGKEY: return ACTIONWEIGHT_DELREGKEY; default: return 0; } }
BOOL AddRuleEx ( IN MIG_OBJECTTYPEID Type, IN MIG_OBJECTSTRINGHANDLE ObjectBase, IN MIG_OBJECTSTRINGHANDLE ObjectPattern, IN ACTIONGROUP ActionGroup, IN DWORD ActionFlags, IN PACTION_STRUCT ActionStruct, OPTIONAL IN RULEGROUP RuleGroup ) { PTYPE_RULE typeRule; MIG_SEGMENTS nodeSegment; MIG_SEGMENTS leafSegment; PCTSTR ourEncodedString; PCTSTR node; PCTSTR leaf; PRULE rule; PGROWBUFFER ruleStruct;
switch (RuleGroup) {
case RULEGROUP_NORMAL: ruleStruct = &g_TypeToIncRule; break;
case RULEGROUP_PRIORITY: ruleStruct = &g_TypeToPriRule; break;
case RULEGROUP_COLLPATTERN: ruleStruct = &g_TypeToCollRule; break; }
typeRule = pGetListForType (ruleStruct, Type); if (!typeRule) { return FALSE; }
//
// Make sure both node an leaf are specified
//
IsmCreateObjectStringsFromHandleEx (ObjectPattern, &node, &leaf, TRUE);
nodeSegment.Segment = node ? node : TEXT("*"); nodeSegment.IsPattern = TRUE;
leafSegment.Segment = leaf ? leaf : TEXT("*"); leafSegment.IsPattern = TRUE;
ourEncodedString = IsmCreateObjectPattern ( &nodeSegment, 1, &leafSegment, 1 );
IsmDestroyObjectString (node); IsmDestroyObjectString (leaf);
//
// Insert the rule based on score
//
rule = PmGetMemory (g_RulePool, sizeof (RULE)); ZeroMemory (rule, sizeof (RULE)); if (ObjectBase) { IsmCreateObjectStringsFromHandle (ObjectBase, &node, &leaf); if (node) { rule->ObjectBase = PmDuplicateString (g_RulePool, node); } IsmDestroyObjectString (node); IsmDestroyObjectString (leaf); } rule->ObjectPattern = PmDuplicateString (g_RulePool, ourEncodedString); rule->ParsedPattern = ObsCreateParsedPatternEx (g_RulePool, ourEncodedString, FALSE);
MYASSERT (rule->ParsedPattern); if (rule->ParsedPattern) { rule->Score = pComputeScore (ourEncodedString); rule->Score = rule->Score * 10 + pGetActionWeight (ActionGroup); rule->ActionGroup = ActionGroup; rule->ActionFlags = ActionFlags; if (ActionStruct) { if (ActionStruct->ObjectBase) { rule->ActionStruct.ObjectBase = PmDuplicateString (g_RulePool, ActionStruct->ObjectBase); } if (ActionStruct->ObjectDest) { rule->ActionStruct.ObjectDest = PmDuplicateString (g_RulePool, ActionStruct->ObjectDest); } if (ActionStruct->AddnlDest) { rule->ActionStruct.AddnlDest = PmDuplicateString (g_RulePool, ActionStruct->AddnlDest); } if (ActionStruct->ObjectHint) { rule->ActionStruct.ObjectHint = PmDuplicateString (g_RulePool, ActionStruct->ObjectHint); } }
pAddRuleToTypeRule (typeRule, rule); } else { IsmCreateObjectStringsFromHandleEx (ourEncodedString, &node, &leaf, TRUE); LOG ((LOG_ERROR, (PCSTR) MSG_OBJECT_SPEC_ERROR, node, leaf)); IsmDestroyObjectString (node); IsmDestroyObjectString (leaf); }
IsmDestroyObjectHandle (ourEncodedString);
return TRUE; }
BOOL QueryRuleEx ( IN MIG_OBJECTTYPEID Type, IN MIG_OBJECTSTRINGHANDLE EncodedString, IN PCTSTR ObjectNode, OUT PACTIONGROUP ActionGroup, OUT PDWORD ActionFlags, OUT PACTION_STRUCT ActionStruct, OPTIONAL IN RULEGROUP RuleGroup ) { PTYPE_RULE typeRule; PCHAR_NODE charNode; PTSTR objectBase; PCTSTR p; WORD w; PRULE rule; PRULE foundRule; UINT maxScore; ACTIONGROUP initialAction = ACTIONGROUP_NONE; DWORD matchingFlags = 0; PGROWBUFFER ruleStruct;
switch (RuleGroup) {
case RULEGROUP_NORMAL: ruleStruct = &g_TypeToIncRule; break;
case RULEGROUP_PRIORITY: ruleStruct = &g_TypeToPriRule; break;
case RULEGROUP_COLLPATTERN: ruleStruct = &g_TypeToCollRule; break; }
if (ActionStruct) { ZeroMemory (ActionStruct, sizeof (ACTION_STRUCT)); }
typeRule = pGetListForType (ruleStruct, Type); if (!typeRule) { return FALSE; }
//
// Let's walk the structure finding all possible rules and put them in a grow buffer
// Later we'll examine the rules one by one. Note that the root rules always qualify
//
if (ObjectNode) { objectBase = DuplicatePathString (ObjectNode, 0); CharLower (objectBase); } g_TypeRuleList.End = 0; p = objectBase; if (p) { w = (WORD) _tcsnextc (p); charNode = typeRule->FirstLevel; while (charNode && *p) { if (charNode->Char == w) { if (charNode->RuleList) { CopyMemory (GbGrow (&g_TypeRuleList, sizeof (PRULE)), &(charNode->RuleList), sizeof (PRULE)); } charNode = charNode->NextLevel; p = _tcsinc (p); w = (WORD) _tcsnextc (p); } else { charNode = charNode->NextPeer; } } } maxScore = 0; foundRule = NULL; while (g_TypeRuleList.End) { CopyMemory (&rule, &(g_TypeRuleList.Buf[g_TypeRuleList.End - sizeof (PRULE)]), sizeof (PRULE)); while (rule) { if (maxScore <= rule->Score) { if (IsmParsedPatternMatch ((MIG_PARSEDPATTERN)rule->ParsedPattern, Type, EncodedString)) { if (foundRule && (maxScore == rule->Score)) { if (initialAction == rule->ActionGroup) { matchingFlags |= rule->ActionFlags; } } else { foundRule = rule; initialAction = foundRule->ActionGroup; matchingFlags = foundRule->ActionFlags; maxScore = rule->Score; } } } rule = rule->NextRule; } g_TypeRuleList.End -= sizeof (PRULE); } rule = typeRule->RuleList; while (rule) { if (maxScore <= rule->Score) { if (IsmParsedPatternMatch ((MIG_PARSEDPATTERN)rule->ParsedPattern, Type, EncodedString)) { if (foundRule && (maxScore == rule->Score)) { if (initialAction == rule->ActionGroup) { matchingFlags |= rule->ActionFlags; } } else { foundRule = rule; initialAction = foundRule->ActionGroup; matchingFlags = foundRule->ActionFlags; maxScore = rule->Score; } } } rule = rule->NextRule; }
if (foundRule) { *ActionGroup = initialAction; *ActionFlags = matchingFlags; if (ActionStruct && (!ActionStruct->ObjectBase) && (foundRule->ActionStruct.ObjectBase)) { ActionStruct->ObjectBase = foundRule->ActionStruct.ObjectBase; } if (ActionStruct && (!ActionStruct->ObjectDest) && (foundRule->ActionStruct.ObjectDest)) { ActionStruct->ObjectDest = foundRule->ActionStruct.ObjectDest; } if (ActionStruct && (!ActionStruct->AddnlDest) && (foundRule->ActionStruct.AddnlDest)) { ActionStruct->AddnlDest = foundRule->ActionStruct.AddnlDest; } if (ActionStruct && (!ActionStruct->ObjectHint) && (foundRule->ActionStruct.ObjectHint)) { ActionStruct->ObjectHint = foundRule->ActionStruct.ObjectHint; } }
FreePathString (objectBase);
return (foundRule != NULL); }
|