/*++ 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: --*/ /* +-------+ | 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 root1\node1 root1\node1 root1\node1 */ #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; }