Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2084 lines
50 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
objstr.c
Abstract:
Implements a set of APIs to handle the string representation of nodes/leafs of a tree
Author:
03-Jan-2000 Ovidiu Temereanca (ovidiut) - File creation.
Revision History:
<alias> <date> <comments>
--*/
/*
+-------+
| root1 | Level 1
+-------+
/ \
/ \
+---------+ (-------)
| node1 | ( leaf1 ) Level 2
+---------+ (-------)
/ | \ \__________
/ | \ \
+-------+ +-------+ (-------) (-------)
| node2 | | node3 | ( leaf2 ) ( leaf3 ) Level 3
+-------+ +-------+ (-------) (-------)
/ \
/ \
+-------+ (-------)
| node4 | ( leaf4 ) Level 4
+-------+ (-------)
/ \
/ \
(-------) (-------)
( leaf5 ) ( leaf6 ) Level 5
(-------) (-------)
The string representation of some tree elements above:
root1
root1 <leaf1>
root1\node1
root1\node1 <leaf2>
root1\node1 <leaf3>
*/
#include "pch.h"
//
// Includes
//
// None
#define DBG_OBJSTR "ObjStr"
//
// Strings
//
#define S_OBJSTR "ObjStr"
//
// Constants
//
#define OBJSTR_NODE_BEGINA '\025'
#define OBJSTR_NODE_BEGINW L'\025'
#define OBJSTR_NODE_TERMA '\\'
#define OBJSTR_NODE_TERMW L'\\'
#define OBJSTR_NODE_LEAF_SEPA '\020'
#define OBJSTR_NODE_LEAF_SEPW L'\020'
#define OBJSTR_LEAF_BEGINA '\005'
#define OBJSTR_LEAF_BEGINW L'\005'
//
// Macros
//
#define pObjStrAllocateMemory(Size) PmGetMemory (g_ObjStrPool, Size)
#define pObjStrFreeMemory(Buffer) if (/*lint --e(774)*/Buffer) PmReleaseMemory (g_ObjStrPool, Buffer)
//
// Types
//
// None
//
// Globals
//
PMHANDLE g_ObjStrPool;
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
// None
//
// Macro expansion definition
//
// None
//
// Code
//
BOOL
ObsInitialize (
VOID
)
/*++
Routine Description:
ObsInitialize initializes this library.
Arguments:
none
Return Value:
TRUE if the init was successful.
FALSE if not. GetLastError() returns extended error info.
--*/
{
g_ObjStrPool = PmCreateNamedPool (S_OBJSTR);
return g_ObjStrPool != NULL;
}
VOID
ObsTerminate (
VOID
)
/*++
Routine Description:
ObsTerminate is called to free resources used by this lib.
Arguments:
none
Return Value:
none
--*/
{
if (g_ObjStrPool) {
PmDestroyPool (g_ObjStrPool);
g_ObjStrPool = NULL;
}
}
/*++
Routine Description:
pExtractStringAB is a private function that creates a new string in the given pool,
using a source string and a limit to copy up to.
Arguments:
Start - Specifies the source string
End - Specifies the point to copy up to (excluding it), within the same string
Pool - Specifies the pool to use for allocation
Return Value:
A pointer to the newly created string
--*/
PSTR
pExtractStringABA (
IN PCSTR Start,
IN PCSTR End,
IN PMHANDLE Pool
)
{
PSTR p;
p = PmGetMemory (Pool, (DWORD)(End - Start + 1) * DWSIZEOF (CHAR));
StringCopyABA (p, Start, End);
return p;
}
PWSTR
pExtractStringABW (
IN PCWSTR Start,
IN PCWSTR End,
IN PMHANDLE Pool
)
{
PWSTR p;
p = PmGetMemory (Pool, (DWORD)(End - Start + 1) * DWSIZEOF (WCHAR));
StringCopyABW (p, Start, End);
return p;
}
/*++
Routine Description:
ObsFree frees the given object from the private pool
Arguments:
EncodedObject - Specifies the source string
End - Specifies the point to copy up to (excluding it), within the same string
Pool - Specifies the pool to use for allocation
Return Value:
A pointer to the newly created string
--*/
VOID
ObsFreeA (
IN PCSTR EncodedObject
)
{
pObjStrFreeMemory ((PVOID)EncodedObject);
}
VOID
ObsFreeW (
IN PCWSTR EncodedObject
)
{
pObjStrFreeMemory ((PVOID)EncodedObject);
}
BOOL
ObsEncodeStringExA (
PSTR Destination,
PCSTR Source,
PCSTR CharsToEncode
)
{
MBCHAR ch;
if (!CharsToEncode) {
CharsToEncode = EscapedCharsA;
}
while (*Source) {
ch = _mbsnextc (Source);
if (_mbschr (CharsToEncode, ch)) {
*Destination = '^';
Destination ++;
}
// now copy the multibyte character
if (IsLeadByte (Source)) {
*Destination = *Source;
Destination ++;
Source ++;
}
*Destination = *Source;
Destination ++;
Source ++;
}
*Destination = 0;
return TRUE;
}
BOOL
ObsEncodeStringExW (
PWSTR Destination,
PCWSTR Source,
PCWSTR CharsToEncode
)
{
if (!CharsToEncode) {
CharsToEncode = EscapedCharsW;
}
while (*Source) {
if (wcschr (CharsToEncode, *Source)) {
*Destination = L'^';
Destination ++;
}
*Destination = *Source;
Destination ++;
Source ++;
}
*Destination = 0;
return TRUE;
}
BOOL
ObsDecodeStringA (
PSTR Destination,
PCSTR Source
)
{
BOOL escaping = FALSE;
while (*Source) {
if ((_mbsnextc (Source) == '^') && (!escaping)) {
escaping = TRUE;
Source ++;
} else {
escaping = FALSE;
// now copy the multibyte character
if (IsLeadByte (Source)) {
*Destination = *Source;
Destination ++;
Source ++;
}
*Destination = *Source;
Destination ++;
Source ++;
}
}
*Destination = 0;
return TRUE;
}
BOOL
ObsDecodeStringW (
PWSTR Destination,
PCWSTR Source
)
{
BOOL escaping = FALSE;
while (*Source) {
if ((*Source == L'^') && (!escaping)) {
escaping = TRUE;
Source ++;
} else {
escaping = FALSE;
*Destination = *Source;
Destination ++;
Source ++;
}
}
*Destination = 0;
return TRUE;
}
PCSTR
ObsFindNonEncodedCharInEncodedStringA (
IN PCSTR String,
IN MBCHAR Char
)
{
MBCHAR ch;
while (*String) {
ch = _mbsnextc (String);
if (ch == '^') {
String++;
} else if (ch == Char) {
return String;
}
String = _mbsinc (String);
}
return NULL;
}
PCWSTR
ObsFindNonEncodedCharInEncodedStringW (
IN PCWSTR String,
IN WCHAR Char
)
{
WCHAR ch;
while (*String) {
ch = *String;
if (ch == L'^') {
String++;
} else if (ch == Char) {
return String;
}
String++;
}
return NULL;
}
/*++
Routine Description:
ObsSplitObjectStringEx splits the given encoded object into components: node and
leaf. Strings are allocated from the given pool
Arguments:
EncodedObject - Specifies the source object string
DecodedNode - Receives the decoded node part; optional
DecodedLeaf - Receives the decoded leaf part; optional
Pool - Specifies the pool to use for allocation; optional; if not specified,
the module pool will be used and ObsFree needs to be called for them
to be freed
Return Value:
TRUE if the source object has a legal format and it has been split into components
--*/
BOOL
RealObsSplitObjectStringExA (
IN PCSTR EncodedObject,
OUT PCSTR* DecodedNode, OPTIONAL
OUT PCSTR* DecodedLeaf, OPTIONAL
IN PMHANDLE Pool, OPTIONAL
IN BOOL DecodeStrings
)
{
PCSTR currStr = EncodedObject;
PCSTR end;
PCSTR oneBack;
PCSTR next;
MBCHAR ch;
BOOL middle = FALSE;
MYASSERT (EncodedObject);
if (!EncodedObject) {
return FALSE;
}
if (!Pool) {
Pool = g_ObjStrPool;
}
if (DecodedNode) {
*DecodedNode = NULL;
}
if (DecodedLeaf) {
*DecodedLeaf = NULL;
}
for (;;) {
ch = _mbsnextc (currStr);
if (!middle && ch == OBJSTR_NODE_BEGINA) {
//
// Find the end of node
//
currStr++;
end = ObsFindNonEncodedCharInEncodedStringA (currStr, OBJSTR_NODE_LEAF_SEPA);
next = end;
MYASSERT (next);
if (*next) {
next++;
}
if (end > currStr) {
oneBack = _mbsdec (currStr, end);
if (_mbsnextc (oneBack) == '\\') {
end = oneBack;
}
}
if (DecodedNode) {
//
// Extract the string into a pool
//
*DecodedNode = pExtractStringABA (currStr, end, Pool);
//
// Decode if necessary
//
if (DecodeStrings) {
ObsDecodeStringA ((PSTR)(*DecodedNode), *DecodedNode);
}
}
//
// Continue on to leaf portion
//
currStr = next;
middle = TRUE;
} else if (ch == OBJSTR_LEAF_BEGINA) {
//
// Find the end of leaf
//
currStr++;
end = GetEndOfStringA (currStr);
if (DecodedLeaf) {
//
// Extract the string into a pool
//
*DecodedLeaf = pExtractStringABA (currStr, end, Pool);
//
// Decode if necessary
//
if (DecodeStrings) {
ObsDecodeStringA ((PSTR)(*DecodedLeaf), *DecodedLeaf);
}
}
//
// Done
//
break;
} else if (ch == 0 && middle) {
//
// Either no leaf or empty string
//
break;
} else if (!middle && ch == OBJSTR_NODE_LEAF_SEPA) {
middle = TRUE;
currStr++;
} else {
//
// Syntax error
//
DEBUGMSGA ((DBG_ERROR, "%s is an invalid string encoding", EncodedObject));
if (DecodedNode && *DecodedNode) {
ObsFreeA (*DecodedNode);
*DecodedNode = NULL;
}
if (DecodedLeaf && *DecodedLeaf) {
ObsFreeA (*DecodedLeaf);
*DecodedLeaf = NULL;
}
return FALSE;
}
}
return TRUE;
}
BOOL
RealObsSplitObjectStringExW (
IN PCWSTR EncodedObject,
OUT PCWSTR* DecodedNode, OPTIONAL
OUT PCWSTR* DecodedLeaf, OPTIONAL
IN PMHANDLE Pool, OPTIONAL
IN BOOL DecodeStrings
)
{
PCWSTR currStr = EncodedObject;
PCWSTR end;
PCWSTR oneBack;
PCWSTR next;
WCHAR ch;
BOOL middle = FALSE;
MYASSERT (EncodedObject);
if (!EncodedObject) {
return FALSE;
}
if (!Pool) {
Pool = g_ObjStrPool;
}
if (DecodedNode) {
*DecodedNode = NULL;
}
if (DecodedLeaf) {
*DecodedLeaf = NULL;
}
for (;;) {
ch = *currStr;
if (!middle && ch == OBJSTR_NODE_BEGINA) {
//
// Find the end of node
//
currStr++;
end = ObsFindNonEncodedCharInEncodedStringW (currStr, OBJSTR_NODE_LEAF_SEPA);
next = end;
MYASSERT (next);
if (*next) {
next++;
}
if (end > currStr) {
oneBack = end - 1;
if (*oneBack == L'\\') {
end = oneBack;
}
}
if (DecodedNode) {
//
// Extract the string into a pool
//
*DecodedNode = pExtractStringABW (currStr, end, Pool);
//
// Decode if necessary
//
if (DecodeStrings) {
ObsDecodeStringW ((PWSTR)(*DecodedNode), *DecodedNode);
}
}
//
// Continue on to leaf portion
//
currStr = next;
middle = TRUE;
} else if (ch == OBJSTR_LEAF_BEGINA) {
//
// Find the end of leaf
//
currStr++;
end = GetEndOfStringW (currStr);
if (DecodedLeaf) {
//
// Extract the string into a pool
//
*DecodedLeaf = pExtractStringABW (currStr, end, Pool);
//
// Decode if necessary
//
if (DecodeStrings) {
ObsDecodeStringW ((PWSTR)(*DecodedLeaf), *DecodedLeaf);
}
}
//
// Done
//
break;
} else if (ch == 0 && middle) {
//
// Either no leaf or empty string
//
break;
} else if (!middle && ch == OBJSTR_NODE_LEAF_SEPW) {
middle = TRUE;
currStr++;
} else {
//
// Syntax error
//
DEBUGMSGW ((DBG_ERROR, "%s is an invalid string encoding", EncodedObject));
if (DecodedNode && *DecodedNode) {
ObsFreeW (*DecodedNode);
*DecodedNode = NULL;
}
if (DecodedLeaf && *DecodedLeaf) {
ObsFreeW (*DecodedLeaf);
*DecodedLeaf = NULL;
}
return FALSE;
}
}
return TRUE;
}
BOOL
ObsHasNodeA (
IN PCSTR EncodedObject
)
{
return *EncodedObject == OBJSTR_NODE_BEGINA;
}
BOOL
ObsHasNodeW (
IN PCWSTR EncodedObject
)
{
return *EncodedObject == OBJSTR_NODE_BEGINW;
}
PCSTR
ObsGetLeafPortionOfEncodedStringA (
IN PCSTR EncodedObject
)
{
return ObsFindNonEncodedCharInEncodedStringA (EncodedObject, OBJSTR_LEAF_BEGINA);
}
PCWSTR
ObsGetLeafPortionOfEncodedStringW (
IN PCWSTR EncodedObject
)
{
return ObsFindNonEncodedCharInEncodedStringW (EncodedObject, OBJSTR_LEAF_BEGINW);
}
PCSTR
ObsGetNodeLeafDividerA (
IN PCSTR EncodedObject
)
{
return ObsFindNonEncodedCharInEncodedStringA (EncodedObject, OBJSTR_NODE_LEAF_SEPA);
}
PCWSTR
ObsGetNodeLeafDividerW (
IN PCWSTR EncodedObject
)
{
return ObsFindNonEncodedCharInEncodedStringW (EncodedObject, OBJSTR_NODE_LEAF_SEPW);
}
/*++
Routine Description:
ObsBuildEncodedObjectStringEx builds an encoded object from components: node and
leaf. The string is allocated from the module's pool
Arguments:
DecodedNode - Specifies the decoded node part
DecodedLeaf - Specifies the decoded leaf part; optional
EncodeObject - Specifies TRUE if the resulting object needs to be encoded using
encoding rules
Partial - Specifies TRUE if the node/leaf separator should not be added. In this
case, DecodedLeaf must be NULL.
Return Value:
Pointer to the newly created object string
--*/
PSTR
RealObsBuildEncodedObjectStringExA (
IN PCSTR DecodedNode, OPTIONAL
IN PCSTR DecodedLeaf, OPTIONAL
IN BOOL EncodeObject
)
{
PSTR result;
PSTR p;
UINT size;
//
// at most, one byte char will be expanded to 2 bytes (2 times)
//
if (EncodeObject) {
//
// Compute the result size
//
size = DWSIZEOF(OBJSTR_NODE_LEAF_SEPA);
if (DecodedNode) {
size += DWSIZEOF(OBJSTR_NODE_BEGINA);
size += ByteCountA (DecodedNode) * 2;
size += DWSIZEOF(OBJSTR_NODE_TERMA);
}
if (DecodedLeaf) {
size += DWSIZEOF(OBJSTR_LEAF_BEGINA);
size += ByteCountA (DecodedLeaf) * 2;
}
size += DWSIZEOF(CHAR);
//
// Build encoded string
//
result = (PSTR) pObjStrAllocateMemory (size);
p = result;
if (DecodedNode) {
*p++ = OBJSTR_NODE_BEGINA;
ObsEncodeStringA (p, DecodedNode);
p = GetEndOfStringA (p);
if (p == (result + 1) || _mbsnextc (_mbsdec (result, p)) != OBJSTR_NODE_TERMA) {
*p++ = OBJSTR_NODE_TERMA;
}
}
*p++ = OBJSTR_NODE_LEAF_SEPA;
if (DecodedLeaf) {
*p++ = OBJSTR_LEAF_BEGINA;
ObsEncodeStringA (p, DecodedLeaf);
} else {
*p = 0;
}
} else {
//
// Compute the result size
//
size = DWSIZEOF(OBJSTR_NODE_LEAF_SEPA);
if (DecodedNode) {
size += DWSIZEOF(OBJSTR_NODE_BEGINA);
size += ByteCountA (DecodedNode);
size += DWSIZEOF(OBJSTR_NODE_TERMA);
}
if (DecodedLeaf) {
size += DWSIZEOF(OBJSTR_LEAF_BEGINA);
size += ByteCountA (DecodedLeaf);
}
size += DWSIZEOF(CHAR);
//
// Build non-encoded string
//
result = (PSTR) pObjStrAllocateMemory (size);
p = result;
if (DecodedNode) {
*p++ = OBJSTR_NODE_BEGINA;
*p = 0;
p = StringCatA (p, DecodedNode);
if (p == (result + 1) || _mbsnextc (_mbsdec (result, p)) != OBJSTR_NODE_TERMA) {
*p++ = OBJSTR_NODE_TERMA;
}
}
*p++ = OBJSTR_NODE_LEAF_SEPA;
if (DecodedLeaf) {
*p++ = OBJSTR_LEAF_BEGINA;
StringCopyA (p, DecodedLeaf);
} else {
*p = 0;
}
}
return result;
}
PWSTR
RealObsBuildEncodedObjectStringExW (
IN PCWSTR DecodedNode,
IN PCWSTR DecodedLeaf, OPTIONAL
IN BOOL EncodeObject
)
{
PWSTR result;
PWSTR p;
UINT size;
//
// at most, one byte char will be expanded to 2 bytes (2 times)
//
if (EncodeObject) {
//
// Compute the result size
//
size = DWSIZEOF(OBJSTR_NODE_LEAF_SEPW);
if (DecodedNode) {
size += DWSIZEOF(OBJSTR_NODE_BEGINW);
size += ByteCountW (DecodedNode) * 2;
size += DWSIZEOF(OBJSTR_NODE_TERMW);
}
if (DecodedLeaf) {
size += DWSIZEOF(OBJSTR_LEAF_BEGINW);
size += ByteCountW (DecodedLeaf) * 2;
}
size += DWSIZEOF(WCHAR);
//
// Build encoded string
//
result = (PWSTR) pObjStrAllocateMemory (size);
p = result;
if (DecodedNode) {
*p++ = OBJSTR_NODE_BEGINW;
ObsEncodeStringW (p, DecodedNode);
p = GetEndOfStringW (p);
if (p == (result + 1) || *(p - 1) != OBJSTR_NODE_TERMW) {
*p++ = OBJSTR_NODE_TERMW;
}
}
*p++ = OBJSTR_NODE_LEAF_SEPW;
if (DecodedLeaf) {
*p++ = OBJSTR_LEAF_BEGINW;
ObsEncodeStringW (p, DecodedLeaf);
} else {
*p = 0;
}
} else {
//
// Compute the result size
//
size = DWSIZEOF(OBJSTR_NODE_LEAF_SEPW);
if (DecodedNode) {
size += DWSIZEOF(OBJSTR_NODE_BEGINW);
size += ByteCountW (DecodedNode);
size += DWSIZEOF(OBJSTR_NODE_TERMW);
}
if (DecodedLeaf) {
size += DWSIZEOF(OBJSTR_LEAF_BEGINW);
size += ByteCountW (DecodedLeaf);
}
size += DWSIZEOF(WCHAR);
//
// Build non-encoded string
//
result = (PWSTR) pObjStrAllocateMemory (size);
p = result;
if (DecodedNode) {
*p++ = OBJSTR_NODE_BEGINW;
*p = 0;
p = StringCatW (p, DecodedNode);
if (p == (result + 1) || *(p - 1) != OBJSTR_NODE_TERMW) {
*p++ = OBJSTR_NODE_TERMW;
}
}
*p++ = OBJSTR_NODE_LEAF_SEPW;
if (DecodedLeaf) {
*p++ = OBJSTR_LEAF_BEGINW;
StringCopyW (p, DecodedLeaf);
} else {
*p = 0;
}
}
return result;
}
/*++
Routine Description:
RealObsCreateParsedPatternEx parses the given object into an internal format for quick
pattern matching
Arguments:
EncodedObject - Specifies the source object string
Return Value:
A pointer to the newly created structure or NULL if the object was invalid
--*/
POBSPARSEDPATTERNA
RealObsCreateParsedPatternExA (
IN PMHANDLE Pool, OPTIONAL
IN PCSTR EncodedObject,
IN BOOL MakePrimaryRootEndWithWack
)
{
PMHANDLE pool;
BOOL externalPool = FALSE;
POBSPARSEDPATTERNA ospp;
PSTR decodedNode;
PSTR decodedLeaf;
PCSTR p;
PCSTR root;
PSTR encodedStr;
PSTR decodedStr;
MYASSERT (EncodedObject);
if (!ObsSplitObjectStringExA (EncodedObject, &decodedNode, &decodedLeaf, NULL, FALSE)) {
return NULL;
}
if (Pool) {
externalPool = TRUE;
pool = Pool;
} else {
pool = g_ObjStrPool;
}
ospp = PmGetMemory (pool, DWSIZEOF(OBSPARSEDPATTERNA));
ZeroMemory (ospp, DWSIZEOF(OBSPARSEDPATTERNA));
ospp->MaxSubLevel = NODE_LEVEL_MAX;
ospp->Pool = pool;
MYASSERT (decodedNode);
if (*decodedNode) {
if (!GetNodePatternMinMaxLevelsA (decodedNode, decodedNode, &ospp->MinNodeLevel, &ospp->MaxNodeLevel)) {
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
} else {
ospp->MinNodeLevel = 1;
ospp->MaxNodeLevel = NODE_LEVEL_MAX;
}
MYASSERT (ospp->MinNodeLevel > 0 && ospp->MaxNodeLevel >= ospp->MinNodeLevel);
if (ospp->MaxNodeLevel != NODE_LEVEL_MAX) {
ospp->MaxSubLevel = ospp->MaxNodeLevel - ospp->MinNodeLevel;
}
if (*decodedNode) {
ospp->NodePattern = CreateParsedPatternExA (Pool, decodedNode);
if (!ospp->NodePattern) {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsCreateParsedPatternExA: Bad EncodedObject: %s",
EncodedObject
));
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
if (ospp->NodePattern->PatternCount > 1) {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsCreateParsedPatternExA: Bad EncodedObject (multiple patterns specified): %s",
EncodedObject
));
DestroyParsedPatternA (ospp->NodePattern);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
root = ParsedPatternGetRootA (ospp->NodePattern);
if (root) {
//
// extract the real root part
//
if (ParsedPatternIsExactMatchA (ospp->NodePattern)) {
ospp->Flags |= OBSPF_EXACTNODE;
// the ExactRoot needs to be case sensitive, we rely on root to give
// us the size but we extract it from decodedNode
ospp->ExactRootBytes = ByteCountA (root);
ospp->ExactRoot = PmGetMemory (pool, ospp->ExactRootBytes + sizeof (CHAR));
CopyMemory (ospp->ExactRoot, decodedNode, ospp->ExactRootBytes);
ospp->ExactRoot [ospp->ExactRootBytes / sizeof (CHAR)] = 0;
ospp->MaxSubLevel = 0;
} else {
p = FindLastWackA (root);
if (p) {
//
// exact root specified
// if the last wack is actually the last character or is followed by star(s),
// optimize the matching by setting some flags
//
if (*(p + 1) == 0) {
if (ParsedPatternIsRootPlusStarA (ospp->NodePattern)) {
ospp->Flags |= OBSPF_NODEISROOTPLUSSTAR;
}
}
if (MakePrimaryRootEndWithWack && p == _mbschr (root, '\\')) {
//
// include it in the string
//
p++;
}
// the ExactRoot needs to be case sensitive, we rely on root to give
// us the size but we extract it from decodedNode
ospp->ExactRootBytes = (DWORD)((PBYTE)p - (PBYTE)root);
decodedStr = AllocPathStringA (ospp->ExactRootBytes / sizeof (CHAR) + 1);
encodedStr = AllocPathStringA (2 * ospp->ExactRootBytes / sizeof (CHAR) + 1);
CopyMemory (decodedStr, root, ospp->ExactRootBytes);
decodedStr [ospp->ExactRootBytes / sizeof (CHAR)] = 0;
ObsEncodeStringA (encodedStr, decodedStr);
ospp->ExactRootBytes = SizeOfStringA (encodedStr) - sizeof (CHAR);
ospp->ExactRoot = PmGetMemory (pool, ospp->ExactRootBytes + sizeof (CHAR));
CopyMemory (ospp->ExactRoot, decodedNode, ospp->ExactRootBytes);
FreePathStringA (encodedStr);
FreePathStringA (decodedStr);
ospp->ExactRoot [ospp->ExactRootBytes / sizeof (CHAR)] = 0;
}
}
} else if (ParsedPatternIsOptionalA (ospp->NodePattern)) {
ospp->Flags |= OBSPF_OPTIONALNODE;
}
}
if (decodedLeaf) {
if (*decodedLeaf) {
ospp->LeafPattern = CreateParsedPatternExA (Pool, decodedLeaf);
if (!ospp->LeafPattern) {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsCreateParsedPatternExA: Bad EncodedObject: %s",
EncodedObject
));
DestroyParsedPatternA (ospp->NodePattern);
PmReleaseMemory (pool, ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
if (ospp->LeafPattern->PatternCount > 1) {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsCreateParsedPatternExA: Bad EncodedObject (multiple patterns specified): %s",
EncodedObject
));
DestroyParsedPatternA (ospp->NodePattern);
DestroyParsedPatternA (ospp->LeafPattern);
PmReleaseMemory (pool, ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
if (ParsedPatternIsOptionalA (ospp->LeafPattern)) {
ospp->Flags |= OBSPF_OPTIONALLEAF;
} else if (ParsedPatternIsExactMatchA (ospp->LeafPattern)) {
ospp->Flags |= OBSPF_EXACTLEAF;
}
} else {
//
// accept empty string for leaf
//
ospp->LeafPattern = CreateParsedPatternExA (Pool, decodedLeaf);
ospp->Flags |= OBSPF_EXACTLEAF;
}
ospp->Leaf = PmDuplicateStringA (pool, decodedLeaf);
} else {
ospp->Flags |= OBSPF_NOLEAF;
}
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
return ospp;
}
POBSPARSEDPATTERNW
RealObsCreateParsedPatternExW (
IN PMHANDLE Pool, OPTIONAL
IN PCWSTR EncodedObject,
IN BOOL MakePrimaryRootEndWithWack
)
{
PMHANDLE pool;
BOOL externalPool = FALSE;
POBSPARSEDPATTERNW ospp;
PWSTR decodedNode;
PWSTR decodedLeaf;
PCWSTR p;
PCWSTR root;
PWSTR encodedStr;
PWSTR decodedStr;
MYASSERT (EncodedObject);
if (!ObsSplitObjectStringExW (EncodedObject, &decodedNode, &decodedLeaf, NULL, FALSE)) {
return NULL;
}
if (Pool) {
externalPool = TRUE;
pool = Pool;
} else {
pool = g_ObjStrPool;
}
ospp = PmGetMemory (pool, DWSIZEOF(OBSPARSEDPATTERNA));
ZeroMemory (ospp, DWSIZEOF(OBSPARSEDPATTERNW));
ospp->MaxSubLevel = NODE_LEVEL_MAX;
ospp->Pool = pool;
MYASSERT (decodedNode);
if (*decodedNode) {
if (!GetNodePatternMinMaxLevelsW (decodedNode, decodedNode, &ospp->MinNodeLevel, &ospp->MaxNodeLevel)) {
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (ospp);
return NULL;
}
} else {
ospp->MinNodeLevel = 1;
ospp->MaxNodeLevel = NODE_LEVEL_MAX;
}
MYASSERT (ospp->MinNodeLevel > 0 && ospp->MaxNodeLevel >= ospp->MinNodeLevel);
if (ospp->MaxNodeLevel != NODE_LEVEL_MAX) {
ospp->MaxSubLevel = ospp->MaxNodeLevel - ospp->MinNodeLevel;
}
if (*decodedNode) {
ospp->NodePattern = CreateParsedPatternExW (Pool, decodedNode);
if (!ospp->NodePattern) {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsCreateParsedPatternExW: Bad EncodedObject: %s",
EncodedObject
));
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
if (ospp->NodePattern->PatternCount > 1) {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsCreateParsedPatternExW: Bad EncodedObject (multiple patterns specified): %s",
EncodedObject
));
DestroyParsedPatternW (ospp->NodePattern);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
root = ParsedPatternGetRootW (ospp->NodePattern);
if (root) {
//
// extract the real root part
//
if (ParsedPatternIsExactMatchW (ospp->NodePattern)) {
ospp->Flags |= OBSPF_EXACTNODE;
// the ExactRoot needs to be case sensitive, we rely on root to give
// us the size but we extract it from decodedNode
ospp->ExactRootBytes = ByteCountW (root);
ospp->ExactRoot = PmGetMemory (pool, ospp->ExactRootBytes + sizeof (WCHAR));
CopyMemory (ospp->ExactRoot, decodedNode, ospp->ExactRootBytes);
ospp->ExactRoot [ospp->ExactRootBytes / sizeof (WCHAR)] = 0;
ospp->MaxSubLevel = 0;
} else {
p = FindLastWackW (root);
if (p) {
//
// exact root specified
// if the last wack is actually the last character or is followed by star(s),
// optimize the matching by setting some flags
//
if (*(p + 1) == 0) {
if (ParsedPatternIsRootPlusStarW (ospp->NodePattern)) {
ospp->Flags |= OBSPF_NODEISROOTPLUSSTAR;
}
}
if (MakePrimaryRootEndWithWack && p == wcschr (root, L'\\')) {
//
// include it in the string
//
p++;
}
// the ExactRoot needs to be case sensitive, we rely on root to give
// us the size but we extract it from decodedNode
ospp->ExactRootBytes = (DWORD)((PBYTE)p - (PBYTE)root);
decodedStr = AllocPathStringW (ospp->ExactRootBytes / sizeof (WCHAR) + 1);
encodedStr = AllocPathStringW (2 * ospp->ExactRootBytes / sizeof (WCHAR) + 1);
CopyMemory (decodedStr, root, ospp->ExactRootBytes);
decodedStr [ospp->ExactRootBytes / sizeof (WCHAR)] = 0;
ObsEncodeStringW (encodedStr, decodedStr);
ospp->ExactRootBytes = SizeOfStringW (encodedStr) - sizeof (WCHAR);
ospp->ExactRoot = PmGetMemory (pool, ospp->ExactRootBytes + sizeof (WCHAR));
CopyMemory (ospp->ExactRoot, decodedNode, ospp->ExactRootBytes);
FreePathStringW (encodedStr);
FreePathStringW (decodedStr);
ospp->ExactRoot [ospp->ExactRootBytes / sizeof (WCHAR)] = 0;
}
}
} else if (ParsedPatternIsOptionalW (ospp->NodePattern)) {
ospp->Flags |= OBSPF_OPTIONALNODE;
}
}
if (decodedLeaf) {
if (*decodedLeaf) {
ospp->LeafPattern = CreateParsedPatternExW (Pool, decodedLeaf);
if (!ospp->LeafPattern) {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsCreateParsedPatternExW: Bad EncodedObject: %s",
EncodedObject
));
DestroyParsedPatternW (ospp->NodePattern);
PmReleaseMemory (pool, ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
if (ospp->LeafPattern->PatternCount > 1) {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsCreateParsedPatternExW: Bad EncodedObject (multiple patterns specified): %s",
EncodedObject
));
DestroyParsedPatternW (ospp->NodePattern);
DestroyParsedPatternW (ospp->LeafPattern);
PmReleaseMemory (pool, ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
PmReleaseMemory (pool, ospp);
return NULL;
}
if (ParsedPatternIsOptionalW (ospp->LeafPattern)) {
ospp->Flags |= OBSPF_OPTIONALLEAF;
} else if (ParsedPatternIsExactMatchW (ospp->LeafPattern)) {
ospp->Flags |= OBSPF_EXACTLEAF;
}
} else {
//
// accept empty string for leaf
//
ospp->LeafPattern = CreateParsedPatternExW (Pool, decodedLeaf);
ospp->Flags |= OBSPF_EXACTLEAF;
}
ospp->Leaf = PmDuplicateStringW (pool, decodedLeaf);
} else {
ospp->Flags |= OBSPF_NOLEAF;
}
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
return ospp;
}
/*++
Routine Description:
ObsDestroyParsedPattern destroys the given structure, freeing resources
Arguments:
ParsedPattern - Specifies the parsed pattern structure
Return Value:
none
--*/
VOID
ObsDestroyParsedPatternA (
IN POBSPARSEDPATTERNA ParsedPattern
)
{
if (ParsedPattern) {
if (ParsedPattern->NodePattern) {
DestroyParsedPatternA (ParsedPattern->NodePattern);
}
if (ParsedPattern->LeafPattern) {
DestroyParsedPatternA (ParsedPattern->LeafPattern);
}
if (ParsedPattern->Leaf) {
PmReleaseMemory (ParsedPattern->Pool, ParsedPattern->Leaf);
}
if (ParsedPattern->ExactRoot) {
PmReleaseMemory (ParsedPattern->Pool, ParsedPattern->ExactRoot);
}
PmReleaseMemory (ParsedPattern->Pool, ParsedPattern);
}
}
VOID
ObsDestroyParsedPatternW (
IN POBSPARSEDPATTERNW ParsedPattern
)
{
if (ParsedPattern) {
if (ParsedPattern->NodePattern) {
DestroyParsedPatternW (ParsedPattern->NodePattern);
}
if (ParsedPattern->LeafPattern) {
DestroyParsedPatternW (ParsedPattern->LeafPattern);
}
if (ParsedPattern->Leaf) {
PmReleaseMemory (ParsedPattern->Pool, ParsedPattern->Leaf);
}
if (ParsedPattern->ExactRoot) {
PmReleaseMemory (ParsedPattern->Pool, ParsedPattern->ExactRoot);
}
PmReleaseMemory (ParsedPattern->Pool, ParsedPattern);
}
}
/*++
Routine Description:
ObsParsedPatternMatch tests the given object against a parsed pattern
Arguments:
ParsedPattern - Specifies the parsed pattern structure
EncodedObject - Specifies the object string to test against the pattern
Return Value:
TRUE if the string matches the pattern
--*/
BOOL
ObsParsedPatternMatchA (
IN POBSPARSEDPATTERNA ParsedPattern,
IN PCSTR EncodedObject
)
{
PSTR decodedNode;
PSTR decodedLeaf;
BOOL b;
if (!ObsSplitObjectStringExA (EncodedObject, &decodedNode, &decodedLeaf, NULL, TRUE)) {
return FALSE;
}
b = ObsParsedPatternMatchExA (ParsedPattern, decodedNode, decodedLeaf);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
return b;
}
BOOL
ObsParsedPatternMatchW (
IN POBSPARSEDPATTERNW ParsedPattern,
IN PCWSTR EncodedObject
)
{
PWSTR decodedNode;
PWSTR decodedLeaf;
BOOL b;
if (!ObsSplitObjectStringExW (EncodedObject, &decodedNode, &decodedLeaf, NULL, TRUE)) {
return FALSE;
}
b = ObsParsedPatternMatchExW (ParsedPattern, decodedNode, decodedLeaf);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
return b;
}
/*++
Routine Description:
ObsParsedPatternMatchEx tests the given object, given by its components,
against a parsed pattern
Arguments:
ParsedPattern - Specifies the parsed pattern structure
Node - Specifies the node part of the object string to test against the pattern
Leaf - Specifies the leaf part of the object string to test against the pattern
Return Value:
TRUE if the string components match the pattern
--*/
BOOL
ObsParsedPatternMatchExA (
IN POBSPARSEDPATTERNA ParsedPattern,
IN PCSTR Node,
IN PCSTR Leaf OPTIONAL
)
{
MYASSERT (Node && ParsedPattern->NodePattern);
if (!(Node && ParsedPattern->NodePattern)) {
return FALSE;
}
if (((ParsedPattern->Flags & OBSPF_NOLEAF) && Leaf) ||
((ParsedPattern->Flags & OBSPF_EXACTLEAF) && !Leaf)
) {
return FALSE;
}
if (!TestParsedPatternA (ParsedPattern->NodePattern, Node)) {
return FALSE;
}
return !Leaf || TestParsedPatternA (ParsedPattern->LeafPattern, Leaf);
}
BOOL
ObsParsedPatternMatchExW (
IN POBSPARSEDPATTERNW ParsedPattern,
IN PCWSTR Node, OPTIONAL
IN PCWSTR Leaf OPTIONAL
)
{
MYASSERT (Node && ParsedPattern->NodePattern);
if (!(Node && ParsedPattern->NodePattern)) {
return FALSE;
}
if (((ParsedPattern->Flags & OBSPF_NOLEAF) && Leaf) ||
((ParsedPattern->Flags & OBSPF_EXACTLEAF) && !Leaf)
) {
return FALSE;
}
if (!TestParsedPatternW (ParsedPattern->NodePattern, Node)) {
return FALSE;
}
return !Leaf || TestParsedPatternW (ParsedPattern->LeafPattern, Leaf);
}
/*++
Routine Description:
ObsPatternMatch tests an object string against a pattern object string
Arguments:
ParsedPattern - Specifies the parsed pattern structure
Node - Specifies the node part of the object string to test against the pattern
Leaf - Specifies the leaf part of the object string to test against the pattern
Return Value:
TRUE if the string components match the pattern
--*/
BOOL
ObsPatternMatchA (
IN PCSTR ObjectPattern,
IN PCSTR ObjectStr
)
{
PSTR opNode;
PSTR opLeaf;
PSTR osNode;
PSTR osLeaf;
CHAR dummy[] = "";
BOOL b = FALSE;
if (ObsSplitObjectStringExA (ObjectPattern, &opNode, &opLeaf, NULL, FALSE)) {
if (ObsSplitObjectStringExA (ObjectStr, &osNode, &osLeaf, NULL, TRUE)) {
if (opNode) {
if (osNode) {
b = IsPatternMatchExABA (opNode, osNode, GetEndOfStringA (osNode));
} else {
b = IsPatternMatchExABA (opNode, dummy, GetEndOfStringA (dummy));
}
} else {
if (osNode) {
b = FALSE;
} else {
b = TRUE;
}
}
if (b) {
if (opLeaf) {
if (osLeaf) {
b = IsPatternMatchExABA (opLeaf, osLeaf, GetEndOfStringA (osLeaf));
} else {
b = IsPatternMatchExABA (opLeaf, dummy, GetEndOfStringA (dummy));
}
} else {
if (osLeaf) {
b = FALSE;
} else {
b = TRUE;
}
}
}
pObjStrFreeMemory (osNode);
pObjStrFreeMemory (osLeaf);
}
ELSE_DEBUGMSGA ((DBG_OBJSTR, "ObsPatternMatchA: bad ObjectStr: %s", ObjectStr));
pObjStrFreeMemory (opNode);
pObjStrFreeMemory (opLeaf);
}
ELSE_DEBUGMSGA ((DBG_OBJSTR, "ObsPatternMatchA: bad ObjectPattern: %s", ObjectPattern));
return b;
}
BOOL
ObsPatternMatchW (
IN PCWSTR ObjectPattern,
IN PCWSTR ObjectStr
)
{
PWSTR opNode;
PWSTR opLeaf;
PWSTR osNode;
PWSTR osLeaf;
WCHAR dummy[] = L"";
BOOL b = FALSE;
if (ObsSplitObjectStringExW (ObjectPattern, &opNode, &opLeaf, NULL, FALSE)) {
if (ObsSplitObjectStringExW (ObjectStr, &osNode, &osLeaf, NULL, TRUE)) {
if (opNode) {
if (osNode) {
b = IsPatternMatchExABW (opNode, osNode, GetEndOfStringW (osNode));
} else {
b = IsPatternMatchExABW (opNode, dummy, GetEndOfStringW (dummy));
}
} else {
if (osNode) {
b = FALSE;
} else {
b = TRUE;
}
}
if (b) {
if (opLeaf) {
if (osLeaf) {
b = IsPatternMatchExABW (opLeaf, osLeaf, GetEndOfStringW (osLeaf));
} else {
b = IsPatternMatchExABW (opLeaf, dummy, GetEndOfStringW (dummy));
}
} else {
if (osLeaf) {
b = FALSE;
} else {
b = TRUE;
}
}
}
pObjStrFreeMemory (osNode);
pObjStrFreeMemory (osLeaf);
}
ELSE_DEBUGMSGW ((DBG_OBJSTR, "ObsPatternMatchW: bad ObjectStr: %s", ObjectStr));
pObjStrFreeMemory (opNode);
pObjStrFreeMemory (opLeaf);
}
ELSE_DEBUGMSGW ((DBG_OBJSTR, "ObsPatternMatchW: bad ObjectPattern: %s", ObjectPattern));
return b;
}
/*++
Routine Description:
ObsIsPatternContained compares two patterns to see if one of them is
included in the other. Both patterns may contain any of the following
expressions:
Arguments:
Container - Specifies the container pattern
Contained - Specifies the contained pattern
Return Value:
TRUE if Contained is contained in Container
--*/
BOOL
ObsIsPatternContainedA (
IN PCSTR Container,
IN PCSTR Contained
)
{
PSTR opNode;
PSTR opLeaf;
PSTR osNode;
PSTR osLeaf;
BOOL b = FALSE;
if (ObsSplitObjectStringExA (Container, &opNode, &opLeaf, NULL, FALSE)) {
if (ObsSplitObjectStringExA (Contained, &osNode, &osLeaf, NULL, FALSE)) {
if (opNode) {
if (osNode) {
b = IsPatternContainedExA (opNode, osNode);
} else {
b = FALSE;
}
} else {
if (osNode) {
b = FALSE;
} else {
b = TRUE;
}
}
if (b) {
if (opLeaf) {
if (osLeaf) {
b = IsPatternContainedExA (opLeaf, osLeaf);
} else {
b = TRUE;
}
} else {
if (osLeaf) {
b = FALSE;
} else {
b = TRUE;
}
}
}
pObjStrFreeMemory (osNode);
pObjStrFreeMemory (osLeaf);
}
ELSE_DEBUGMSGA ((DBG_OBJSTR, "ObsIsPatternContainedA: bad Contained string: %s", Contained));
pObjStrFreeMemory (opNode);
pObjStrFreeMemory (opLeaf);
}
ELSE_DEBUGMSGA ((DBG_OBJSTR, "ObsIsPatternContainedA: bad Container string: %s", Container));
return b;
}
BOOL
ObsIsPatternContainedW (
IN PCWSTR Container,
IN PCWSTR Contained
)
{
PWSTR opNode;
PWSTR opLeaf;
PWSTR osNode;
PWSTR osLeaf;
BOOL b = FALSE;
if (ObsSplitObjectStringExW (Container, &opNode, &opLeaf, NULL, FALSE)) {
if (ObsSplitObjectStringExW (Contained, &osNode, &osLeaf, NULL, FALSE)) {
if (opNode) {
if (osNode) {
b = IsPatternContainedExW (opNode, osNode);
} else {
b = FALSE;
}
} else {
if (osNode) {
b = FALSE;
} else {
b = TRUE;
}
}
if (b) {
if (opLeaf) {
if (osLeaf) {
b = IsPatternContainedExW (opLeaf, osLeaf);
} else {
b = TRUE;
}
} else {
if (osLeaf) {
b = FALSE;
} else {
b = TRUE;
}
}
}
pObjStrFreeMemory (osNode);
pObjStrFreeMemory (osLeaf);
}
ELSE_DEBUGMSGW ((DBG_OBJSTR, "ObsIsPatternContainedW: bad Contained string: %s", Contained));
pObjStrFreeMemory (opNode);
pObjStrFreeMemory (opLeaf);
}
ELSE_DEBUGMSGW ((DBG_OBJSTR, "ObsIsPatternContainedW: bad Container string: %s", Container));
return b;
}
/*++
Routine Description:
ObsGetPatternLevels gets the minimum and maximum levels of a string that would
match the given pattern.
Arguments:
ObjectPattern - Specifies the pattern
MinLevel - Receives the minimum possible level; the root has level 1
MaxLevel - Receives the maximum possible level; the root has level 1
Return Value:
TRUE if the pattern was correct and computing was done; FALSE otherwise
--*/
BOOL
ObsGetPatternLevelsA (
IN PCSTR ObjectPattern,
OUT PDWORD MinLevel, OPTIONAL
OUT PDWORD MaxLevel OPTIONAL
)
{
PSTR decodedNode;
PSTR decodedLeaf;
BOOL b;
if (!ObsSplitObjectStringExA (ObjectPattern, &decodedNode, &decodedLeaf, NULL, FALSE)) {
return FALSE;
}
if (decodedNode) {
b = GetNodePatternMinMaxLevelsA (decodedNode, decodedNode, MinLevel, MaxLevel);
} else {
b = FALSE;
}
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
return b;
}
BOOL
ObsGetPatternLevelsW (
IN PCWSTR ObjectPattern,
OUT PDWORD MinLevel,
OUT PDWORD MaxLevel
)
{
PWSTR decodedNode;
PWSTR decodedLeaf;
BOOL b;
if (!ObsSplitObjectStringExW (ObjectPattern, &decodedNode, &decodedLeaf, NULL, FALSE)) {
return FALSE;
}
if (decodedNode) {
b = GetNodePatternMinMaxLevelsW (decodedNode, decodedNode, MinLevel, MaxLevel);
} else {
b = FALSE;
}
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
return b;
}
/*++
Routine Description:
ObsPatternIncludesPattern decides if a given pattern includes another pattern,
meaning that any string that would match the second will match the first.
Arguments:
IncludingPattern - Specifies the first parsed pattern
IncludedPattern - Specifies the second parsed pattern
Return Value:
TRUE if the first pattern includes the second
--*/
BOOL
ObsPatternIncludesPatternA (
IN POBSPARSEDPATTERNA IncludingPattern,
IN POBSPARSEDPATTERNA IncludedPattern
)
{
MYASSERT (IncludingPattern->NodePattern && IncludedPattern->NodePattern);
if (!(IncludingPattern->NodePattern && IncludedPattern->NodePattern)) {
return FALSE;
}
if (IncludingPattern->MinNodeLevel > IncludedPattern->MinNodeLevel ||
IncludingPattern->MaxNodeLevel < IncludedPattern->MaxNodeLevel
) {
return FALSE;
}
if (!PatternIncludesPatternA (IncludingPattern->NodePattern, IncludedPattern->NodePattern)) {
return FALSE;
}
if (IncludingPattern->LeafPattern) {
if (!IncludedPattern->LeafPattern) {
return FALSE;
}
if (!PatternIncludesPatternA (IncludingPattern->LeafPattern, IncludedPattern->LeafPattern)) {
return FALSE;
}
} else {
if (IncludedPattern->LeafPattern) {
return FALSE;
}
}
return TRUE;
}
BOOL
ObsPatternIncludesPatternW (
IN POBSPARSEDPATTERNW IncludingPattern,
IN POBSPARSEDPATTERNW IncludedPattern
)
{
MYASSERT (IncludingPattern->NodePattern && IncludedPattern->NodePattern);
if (!(IncludingPattern->NodePattern && IncludedPattern->NodePattern)) {
return FALSE;
}
if (IncludingPattern->MinNodeLevel > IncludedPattern->MinNodeLevel ||
IncludingPattern->MaxNodeLevel < IncludedPattern->MaxNodeLevel
) {
return FALSE;
}
if (!PatternIncludesPatternW (IncludingPattern->NodePattern, IncludedPattern->NodePattern)) {
return FALSE;
}
if (IncludingPattern->LeafPattern) {
if (!IncludedPattern->LeafPattern) {
return FALSE;
}
if (!PatternIncludesPatternW (IncludingPattern->LeafPattern, IncludedPattern->LeafPattern)) {
return FALSE;
}
} else {
if (IncludedPattern->LeafPattern) {
return FALSE;
}
}
return TRUE;
}