windows-nt/Source/XPSP1/NT/base/ntsetup/hwdb/utils/main/objstr.c

1820 lines
44 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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_LEAF_HEADA '<'
#define OBJSTR_LEAF_HEADW L'<'
#define OBJSTR_LEAF_TAILA '>'
#define OBJSTR_LEAF_TAILW L'>'
#define OBJSTR_SEPARATORA ' '
#define OBJSTR_SEPARATORW L' '
//
// 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
ObsEncodeStringA (
PSTR Destination,
PCSTR Source
)
{
MBCHAR ch;
while (*Source) {
ch = _mbsnextc (Source);
if (_mbschr (EscapedCharsA, ch)) {
*Destination = '^';
Destination ++;
}
// now copy the multibyte character
if (IsLeadByte (*Source)) {
*Destination = *Source;
Destination ++;
Source ++;
}
*Destination = *Source;
Destination ++;
Source ++;
}
*Destination = 0;
return TRUE;
}
BOOL
ObsEncodeStringW (
PWSTR Destination,
PCWSTR Source
)
{
while (*Source) {
if (wcschr (EscapedCharsW, *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;
}
/*++
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
ObsSplitObjectStringExA (
IN PCSTR EncodedObject,
OUT PSTR* DecodedNode, OPTIONAL
OUT PSTR* DecodedLeaf, OPTIONAL
IN PMHANDLE Pool, OPTIONAL
IN BOOL DecodeStrings
)
{
PCSTR p;
PCSTR q;
PCSTR nodeTerm;
PSTR leaf = NULL;
PCSTR lastWack = NULL;
PCSTR lastStar = NULL;
MYASSERT (EncodedObject);
if (!EncodedObject) {
return FALSE;
}
if (!Pool) {
Pool = g_ObjStrPool;
}
p = EncodedObject;
if (*p == '\\') {
//
// must be UNC format; check for syntax
//
p++;
if (*p != '\\') {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsSplitObjectStringExA: relative paths not supported: %s",
EncodedObject
));
return FALSE;
}
}
while (*p && *p != OBJSTR_LEAF_HEADA) {
if (*p == OBJSTR_SEPARATORA) {
q = p + 1;
while (*q == OBJSTR_SEPARATORA) {
q++;
}
if (*q == 0 || *q == OBJSTR_LEAF_HEADA) {
break;
}
p = q;
}
if (*p == '\\') {
if ((UBINT)p == (UBINT)lastWack + 1) {
//
// two wacks in a row? no way
//
DEBUGMSGA ((
DBG_OBJSTR,
"ObsSplitObjectStringExA: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
lastWack = p;
} else if (*p == '*') {
lastStar = p;
}
p = CharNextA (p);
}
if (p == EncodedObject) {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsSplitObjectStringExA: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
if (lastWack && lastWack + 1 == p && lastStar && lastStar + 1 != lastWack) {
nodeTerm = lastWack;
} else {
nodeTerm = p;
}
while (*p == OBJSTR_SEPARATORA) {
//
// *p is one byte wide
//
p++;
}
if (*p) {
if (*p != OBJSTR_LEAF_HEADA) {
//
// wrong start
//
DEBUGMSGA ((
DBG_OBJSTR,
"ObsSplitObjectStringExA: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
q = p + 1;
while (*q != OBJSTR_LEAF_TAILA) {
if (*q == 0) {
//
// incorrectly terminated
//
DEBUGMSGA ((
DBG_OBJSTR,
"ObsSplitObjectStringExA: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
q = CharNextA (q);
}
if (*(q + 1) != 0) {
//
// must end after the terminating char
//
DEBUGMSGA ((
DBG_OBJSTR,
"ObsSplitObjectStringExA: Bad EncodedObject: \"%s\"; chars after the leaf",
EncodedObject
));
return FALSE;
}
if (DecodedLeaf) {
leaf = pExtractStringABA (p + 1, q, Pool);
if (DecodeStrings) {
//
// decode chars
//
ObsDecodeStringA (leaf, leaf);
}
}
}
if (DecodedLeaf) {
*DecodedLeaf = leaf;
}
if (DecodedNode) {
*DecodedNode = pExtractStringABA (EncodedObject, nodeTerm, Pool);
if (DecodeStrings) {
//
// decode chars
//
ObsDecodeStringA (*DecodedNode, *DecodedNode);
}
}
return TRUE;
}
BOOL
ObsSplitObjectStringExW (
IN PCWSTR EncodedObject,
OUT PWSTR* DecodedNode, OPTIONAL
OUT PWSTR* DecodedLeaf, OPTIONAL
IN PMHANDLE Pool, OPTIONAL
IN BOOL DecodeStrings
)
{
PCWSTR p;
PCWSTR q;
PCWSTR nodeTerm;
PWSTR leaf = NULL;
PCWSTR lastWack = NULL;
PCWSTR lastStar = NULL;
MYASSERT (EncodedObject);
if (!EncodedObject) {
return FALSE;
}
if (!Pool) {
Pool = g_ObjStrPool;
}
p = EncodedObject;
if (*p == L'\\') {
//
// must be UNC format; check for syntax
//
p++;
if (*p != L'\\') {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsSplitObjectStringExW: relative paths not supported: %s",
EncodedObject
));
return FALSE;
}
}
while (*p && *p != OBJSTR_LEAF_HEADW) {
if (*p == OBJSTR_SEPARATORW) {
q = p + 1;
while (*q == OBJSTR_SEPARATORW) {
q++;
}
if (*q == 0 || *q == OBJSTR_LEAF_HEADW) {
break;
}
p = q;
}
if (*p == L'\\') {
if ((UBINT)p == (UBINT)lastWack + 1) {
//
// two wacks in a row? no way
//
DEBUGMSGW ((
DBG_OBJSTR,
"ObsSplitObjectStringExW: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
lastWack = p;
} else if (*p == L'*') {
lastStar = p;
}
p++;
}
if (p == EncodedObject) {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsSplitObjectStringExW: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
if (lastWack && lastWack + 1 == p && lastStar && lastStar + 1 != lastWack) {
nodeTerm = lastWack;
} else {
nodeTerm = p;
}
while (*p == OBJSTR_SEPARATORW) {
//
// *p is one WCHAR wide
//
p++;
}
if (*p) {
if (*p != OBJSTR_LEAF_HEADW) {
//
// wrong start
//
DEBUGMSGW ((
DBG_OBJSTR,
"ObsSplitObjectStringExW: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
q = p + 1;
while (*q != OBJSTR_LEAF_TAILW) {
if (*q == 0) {
//
// incorrectly terminated
//
DEBUGMSGW ((
DBG_OBJSTR,
"ObsSplitObjectStringExW: Bad EncodedObject: %s",
EncodedObject
));
return FALSE;
}
q++;
}
if (*(q + 1) != 0) {
//
// must end after the terminating char
//
DEBUGMSGW ((
DBG_OBJSTR,
"ObsSplitObjectStringExW: Bad EncodedObject: \"%s\"; chars after the leaf",
EncodedObject
));
return FALSE;
}
if (DecodedLeaf) {
leaf = pExtractStringABW (p + 1, q, Pool);
if (DecodeStrings) {
//
// decode chars
//
ObsDecodeStringW (leaf, leaf);
}
}
}
if (DecodedLeaf) {
*DecodedLeaf = leaf;
}
if (DecodedNode) {
*DecodedNode = pExtractStringABW (EncodedObject, nodeTerm, Pool);
if (DecodeStrings) {
//
// decode chars
//
ObsDecodeStringW (*DecodedNode, *DecodedNode);
}
}
return TRUE;
}
/*++
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
Return Value:
Pointer to the newly created object string
--*/
PSTR
ObsBuildEncodedObjectStringExA (
IN PCSTR DecodedNode,
IN PCSTR DecodedLeaf, OPTIONAL
IN BOOL EncodeObject
)
{
PSTR encodedNode;
PSTR encodedLeaf;
PSTR encodedString;
MYASSERT (DecodedNode);
if (!DecodedNode) {
return NULL;
}
//
// at most, one byte char will be expanded to 4 bytes (4 times)
//
if (EncodeObject) {
encodedNode = pObjStrAllocateMemory (4 * ByteCountA (DecodedNode) + DWSIZEOF(CHAR));
ObsEncodeStringA (encodedNode, DecodedNode);
} else {
encodedNode = DuplicateTextExA (g_ObjStrPool, DecodedNode, 0, NULL);
}
if (!DecodedLeaf) {
return encodedNode;
}
if (EncodeObject) {
encodedLeaf = pObjStrAllocateMemory (4 * ByteCountA (DecodedLeaf) + DWSIZEOF(CHAR));
ObsEncodeStringA (encodedLeaf, DecodedLeaf);
} else {
encodedLeaf = DuplicateTextExA (g_ObjStrPool, DecodedLeaf, 0, NULL);
}
//
// preferred format: %1 <%2> %1 - Node, %2 - Leaf
//
encodedString = pObjStrAllocateMemory (
ByteCountA (encodedNode) +
DWSIZEOF (" <>") +
ByteCountA (encodedLeaf)
);
wsprintfA (
encodedString,
"%s %c%s%c",
encodedNode,
OBJSTR_LEAF_HEADA,
encodedLeaf,
OBJSTR_LEAF_TAILA
);
pObjStrFreeMemory (encodedNode);
pObjStrFreeMemory (encodedLeaf);
return encodedString;
}
PWSTR
ObsBuildEncodedObjectStringExW (
IN PCWSTR DecodedNode,
IN PCWSTR DecodedLeaf, OPTIONAL
IN BOOL EncodeObject
)
{
PWSTR encodedNode;
PWSTR encodedLeaf;
PWSTR encodedString;
MYASSERT (DecodedNode);
if (!DecodedNode) {
return NULL;
}
//
// at most, one wide char will be expanded to 4 wide chars (4 times)
//
if (EncodeObject) {
encodedNode = pObjStrAllocateMemory (4 * ByteCountW (DecodedNode) + DWSIZEOF(WCHAR));
ObsEncodeStringW (encodedNode, DecodedNode);
} else {
encodedNode = DuplicateTextExW (g_ObjStrPool, DecodedNode, 0, NULL);
}
if (!DecodedLeaf) {
return encodedNode;
}
if (EncodeObject) {
encodedLeaf = pObjStrAllocateMemory (4 * ByteCountW (DecodedLeaf) + DWSIZEOF(WCHAR));
ObsEncodeStringW (encodedLeaf, DecodedLeaf);
} else {
encodedLeaf = DuplicateTextExW (g_ObjStrPool, DecodedLeaf, 0, NULL);
}
//
// preferred format: %1 <%2> %1 - Node, %2 - Leaf
//
encodedString = pObjStrAllocateMemory (
ByteCountW (encodedNode) +
DWSIZEOF (L" <>") +
ByteCountW (encodedLeaf)
);
wsprintfW (
encodedString,
L"%s %c%s%c",
encodedNode,
OBJSTR_LEAF_HEADW,
encodedLeaf,
OBJSTR_LEAF_TAILW
);
pObjStrFreeMemory (encodedNode);
pObjStrFreeMemory (encodedLeaf);
return encodedString;
}
/*++
Routine Description:
ObsCreateParsedPatternEx 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
ObsCreateParsedPatternExA (
IN PCSTR EncodedObject,
IN BOOL MakePrimaryRootEndWithWack
)
{
POBSPARSEDPATTERNA ospp;
PSTR decodedNode;
PSTR decodedLeaf;
PCSTR p;
PCSTR root;
MYASSERT (EncodedObject);
if (!ObsSplitObjectStringExA (EncodedObject, &decodedNode, &decodedLeaf, NULL, FALSE)) {
return NULL;
}
ospp = pObjStrAllocateMemory (DWSIZEOF(OBSPARSEDPATTERNA));
ZeroMemory (ospp, DWSIZEOF(OBSPARSEDPATTERNA));
ospp->MaxSubLevel = NODE_LEVEL_MAX;
MYASSERT (decodedNode);
if (!GetNodePatternMinMaxLevelsA (decodedNode, decodedNode, &ospp->MinNodeLevel, &ospp->MaxNodeLevel)) {
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (ospp);
return NULL;
}
MYASSERT (ospp->MinNodeLevel > 0 && ospp->MaxNodeLevel >= ospp->MinNodeLevel);
if (ospp->MaxNodeLevel != NODE_LEVEL_MAX) {
ospp->MaxSubLevel = ospp->MaxNodeLevel - ospp->MinNodeLevel;
}
ospp->NodePattern = CreateParsedPatternA (decodedNode);
if (!ospp->NodePattern) {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsCreateParsedPatternExA: Bad EncodedObject: %s",
EncodedObject
));
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (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);
pObjStrFreeMemory (ospp);
return NULL;
}
root = ParsedPatternGetRootA (ospp->NodePattern);
if (root) {
//
// extract the real root part
//
if (ParsedPatternIsExactMatchA (ospp->NodePattern)) {
ospp->Flags |= OBSPF_EXACTNODE;
ospp->ExactRoot = DuplicateTextExA (g_ObjStrPool, root, 0, NULL);
ospp->ExactRootBytes = ByteCountA (root);
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 && *root != '\\') {
//
// see if this is really the primary root
//
if (p == _mbschr (root, '\\')) {
//
// include it in the string
//
p++;
}
}
ospp->ExactRoot = pExtractStringABA (root, p, g_ObjStrPool);
ospp->ExactRootBytes = (DWORD)((PBYTE)p - (PBYTE)root);
}
}
} else if (ParsedPatternIsOptionalA (ospp->NodePattern)) {
ospp->Flags |= OBSPF_OPTIONALNODE;
}
if (decodedLeaf) {
if (*decodedLeaf) {
ospp->LeafPattern = CreateParsedPatternA (decodedLeaf);
if (!ospp->LeafPattern) {
DEBUGMSGA ((
DBG_OBJSTR,
"ObsCreateParsedPatternExA: Bad EncodedObject: %s",
EncodedObject
));
DestroyParsedPatternA (ospp->NodePattern);
pObjStrFreeMemory (ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (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);
pObjStrFreeMemory (ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (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->Flags |= OBSPF_EXACTLEAF;
}
ospp->Leaf = DuplicateTextExA (g_ObjStrPool, decodedLeaf, 0, NULL);
} else {
ospp->Flags |= OBSPF_NOLEAF;
}
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
return ospp;
}
POBSPARSEDPATTERNW
ObsCreateParsedPatternExW (
IN PCWSTR EncodedObject,
IN BOOL MakePrimaryRootEndWithWack
)
{
POBSPARSEDPATTERNW ospp;
PWSTR decodedNode;
PWSTR decodedLeaf;
PCWSTR p;
PCWSTR root;
MYASSERT (EncodedObject);
if (!ObsSplitObjectStringExW (EncodedObject, &decodedNode, &decodedLeaf, NULL, FALSE)) {
return NULL;
}
ospp = pObjStrAllocateMemory (DWSIZEOF(OBSPARSEDPATTERNW));
ZeroMemory (ospp, DWSIZEOF(OBSPARSEDPATTERNW));
ospp->MaxSubLevel = NODE_LEVEL_MAX;
MYASSERT (decodedNode);
if (!GetNodePatternMinMaxLevelsW (decodedNode, decodedNode, &ospp->MinNodeLevel, &ospp->MaxNodeLevel)) {
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (ospp);
return NULL;
}
MYASSERT (ospp->MinNodeLevel > 0 && ospp->MaxNodeLevel >= ospp->MinNodeLevel);
if (ospp->MaxNodeLevel != NODE_LEVEL_MAX) {
ospp->MaxSubLevel = ospp->MaxNodeLevel - ospp->MinNodeLevel;
}
ospp->NodePattern = CreateParsedPatternW (decodedNode);
if (!ospp->NodePattern) {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsCreateParsedPatternExW: Bad EncodedObject: %s",
EncodedObject
));
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (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);
pObjStrFreeMemory (ospp);
return NULL;
}
root = ParsedPatternGetRootW (ospp->NodePattern);
if (root) {
//
// extract the real root part
//
if (ParsedPatternIsExactMatchW (ospp->NodePattern)) {
ospp->Flags |= OBSPF_EXACTNODE;
ospp->ExactRoot = DuplicateTextExW (g_ObjStrPool, root, 0, NULL);
ospp->ExactRootBytes = ByteCountW (root);
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 && *root != L'\\') {
//
// see if this is really the primary root
//
if (p == wcschr (root, L'\\')) {
//
// include it in the string
//
p++;
}
}
ospp->ExactRoot = pExtractStringABW (root, p, g_ObjStrPool);
ospp->ExactRootBytes = (DWORD)((PBYTE)p - (PBYTE)root);
}
}
} else if (ParsedPatternIsOptionalW (ospp->NodePattern)) {
ospp->Flags |= OBSPF_OPTIONALNODE;
}
if (decodedLeaf) {
if (*decodedLeaf) {
ospp->LeafPattern = CreateParsedPatternW (decodedLeaf);
if (!ospp->LeafPattern) {
DEBUGMSGW ((
DBG_OBJSTR,
"ObsCreateParsedPatternExW: Bad EncodedObject: %s",
EncodedObject
));
DestroyParsedPatternW (ospp->NodePattern);
pObjStrFreeMemory (ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (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);
pObjStrFreeMemory (ospp->ExactRoot);
pObjStrFreeMemory (decodedNode);
pObjStrFreeMemory (decodedLeaf);
pObjStrFreeMemory (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->Flags |= OBSPF_EXACTLEAF;
}
ospp->Leaf = DuplicateTextExW (g_ObjStrPool, decodedLeaf, 0, NULL);
} 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) {
FreeTextExA (g_ObjStrPool, ParsedPattern->Leaf);
}
pObjStrFreeMemory (ParsedPattern->ExactRoot);
pObjStrFreeMemory (ParsedPattern);
}
}
VOID
ObsDestroyParsedPatternW (
IN POBSPARSEDPATTERNW ParsedPattern
)
{
if (ParsedPattern) {
if (ParsedPattern->NodePattern) {
DestroyParsedPatternW (ParsedPattern->NodePattern);
}
if (ParsedPattern->LeafPattern) {
DestroyParsedPatternW (ParsedPattern->LeafPattern);
}
if (ParsedPattern->Leaf) {
FreeTextExW (g_ObjStrPool, ParsedPattern->Leaf);
}
pObjStrFreeMemory (ParsedPattern->ExactRoot);
pObjStrFreeMemory (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, FALSE)) {
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, FALSE)) {
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_NOLEAF) && !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_NOLEAF) && !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;
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 = FALSE;
}
} else {
if (osNode) {
b = FALSE;
} else {
b = TRUE;
}
}
if (b) {
if (opLeaf) {
if (osLeaf) {
b = IsPatternMatchExABA (opLeaf, osLeaf, GetEndOfStringA (osLeaf));
} else {
b = TRUE;
}
} 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;
BOOL b = FALSE;
if (ObsSplitObjectStringExW (ObjectPattern, &opNode, &opLeaf, NULL, FALSE)) {
if (ObsSplitObjectStringExW (ObjectStr, &osNode, &osLeaf, NULL, FALSE)) {
if (opNode) {
if (osNode) {
b = IsPatternMatchExABW (opNode, osNode, GetEndOfStringW (osNode));
} else {
b = FALSE;
}
} else {
if (osNode) {
b = FALSE;
} else {
b = TRUE;
}
}
if (b) {
if (opLeaf) {
if (osLeaf) {
b = IsPatternMatchExABW (opLeaf, osLeaf, GetEndOfStringW (osLeaf));
} else {
b = FALSE;
}
} 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;
}