windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/common/migutil/regenum.c

1198 lines
24 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997-2001 Microsoft Corporation
Module Name:
regenum.c
Abstract:
Implements utilties to enumerate the registry.
Author:
Jim Schmidt (jimschm) 20-Mar-1997
Revisions:
<alias> <date> <comment>
--*/
#include "pch.h"
#include "regp.h"
#define DBG_REG "Reg"
//
// Private prototypes
//
BOOL
pPopRegKeyInfoA (
IN PREGTREE_ENUMA EnumPtr
);
BOOL
pPopRegKeyInfoW (
IN PREGTREE_ENUMW EnumPtr
);
/*++
Routine Description:
EnumFirstRegKeyA and EnumFirstRegKeyW begin an enumeration of registry
subkeys. They initialize the registy enumeration structure and
call the registry APIs to enumerate subkeys of the specified key handle.
Arguments:
EnumPtr - Receives the updated state of enumeration. The structure
can be accessed directly.
Key - Specifies the handle of the registry key to enumerate.
Return Value:
TRUE if successful, or FALSE if an error or if no more subkeys are available.
Call GetLastError for the failure code.
--*/
BOOL
EnumFirstRegKeyA (
OUT PREGKEY_ENUMA EnumPtr,
IN HKEY hKey
)
{
ZeroMemory (EnumPtr, sizeof (REGKEY_ENUMA));
EnumPtr->KeyHandle = hKey;
return EnumNextRegKeyA (EnumPtr);
}
BOOL
EnumFirstRegKeyW (
OUT PREGKEY_ENUMW EnumPtr,
IN HKEY hKey
)
{
ZeroMemory (EnumPtr, sizeof (REGKEY_ENUMW));
EnumPtr->KeyHandle = hKey;
return EnumNextRegKeyW (EnumPtr);
}
/*++
Routine Description:
EnumFirstRegKeyStrA and EnumFirstRegKeyStrW start an enumeration of
subkeys within the given key. In these functions, the key is specified
via a string instead of an HKEY value.
Arguments:
EnumPtr - Receives the updated state of enumeration. The structure
can be accessed directly.
RegKey - Specifies the full path of the registry key to enumerate.
Return Value:
TRUE if successful, or FALSE if an error or if no more subkeys are available.
Call GetLastError for the failure code.
--*/
BOOL
RealEnumFirstRegKeyStrA (
OUT PREGKEY_ENUMA EnumPtr,
IN PCSTR RegKey
DEBUG_TRACKING_PARAMS
)
{
HKEY Key;
BOOL b;
Key = RealOpenRegKeyStrA (RegKey /* , */ DEBUG_TRACKING_ARGS);
if (!Key) {
return FALSE;
}
b = EnumFirstRegKeyA (EnumPtr, Key);
if (!b) {
CloseRegKey (Key);
} else {
EnumPtr->OpenedByEnum = TRUE;
}
return b;
}
BOOL
RealEnumFirstRegKeyStrW (
IN PREGKEY_ENUMW EnumPtr,
IN PCWSTR RegKey
DEBUG_TRACKING_PARAMS
)
{
HKEY Key;
BOOL b;
Key = RealOpenRegKeyStrW (RegKey /* , */ DEBUG_TRACKING_ARGS);
if (!Key) {
return FALSE;
}
b = EnumFirstRegKeyW (EnumPtr, Key);
if (!b) {
CloseRegKey (Key);
} else {
EnumPtr->OpenedByEnum = TRUE;
}
return b;
}
/*++
Routine Description:
AbortRegKeyEnumA and AbortRegKeyEnumW release all resources associated
with a registry subkey enumeration. Call this function to stop the
enumeration before it completes by itself.
Arguments:
EnumPtr - Specifies the enumeration to stop. Receives the updated
state of enumeration.
Return Value:
none
--*/
VOID
AbortRegKeyEnumA (
IN OUT PREGKEY_ENUMA EnumPtr
)
{
if (EnumPtr->OpenedByEnum && EnumPtr->KeyHandle) {
CloseRegKey (EnumPtr->KeyHandle);
EnumPtr->KeyHandle = NULL;
}
}
VOID
AbortRegKeyEnumW (
IN OUT PREGKEY_ENUMW EnumPtr
)
{
if (EnumPtr->OpenedByEnum && EnumPtr->KeyHandle) {
CloseRegKey (EnumPtr->KeyHandle);
EnumPtr->KeyHandle = NULL;
}
}
/*++
Routine Description:
EnumNextRegKeyA and EnumNextRegKeyW continue an enumeration started by
one of the subkey enumeration routines above. If all items have been
enumerated, this function cleans up all resources and returns FALSE.
Arguments:
EnumPtr - Specifies the enumeration to continue. Receives the updated
state of enumeration. The structure can be accessed directly.
Return Value:
TRUE if successful, or FALSE if an error or if no more subkeys are available.
Call GetLastError for the failure code.
--*/
BOOL
EnumNextRegKeyA (
IN OUT PREGKEY_ENUMA EnumPtr
)
{
LONG rc;
rc = RegEnumKeyA (
EnumPtr->KeyHandle,
EnumPtr->Index,
EnumPtr->SubKeyName,
MAX_REGISTRY_KEYA
);
if (rc != ERROR_SUCCESS) {
if (EnumPtr->OpenedByEnum) {
CloseRegKey (EnumPtr->KeyHandle);
EnumPtr->KeyHandle = NULL;
}
if (rc == ERROR_NO_MORE_ITEMS) {
SetLastError (ERROR_SUCCESS);
} else {
SetLastError (rc);
}
return FALSE;
}
EnumPtr->Index += 1;
return TRUE;
}
BOOL
EnumNextRegKeyW (
IN OUT PREGKEY_ENUMW EnumPtr
)
{
LONG rc;
rc = RegEnumKeyW (
EnumPtr->KeyHandle,
EnumPtr->Index,
EnumPtr->SubKeyName,
MAX_REGISTRY_KEYW
);
if (rc != ERROR_SUCCESS) {
if (EnumPtr->OpenedByEnum) {
CloseRegKey (EnumPtr->KeyHandle);
EnumPtr->KeyHandle = NULL;
}
if (rc == ERROR_NO_MORE_ITEMS) {
SetLastError (ERROR_SUCCESS);
} else {
SetLastError (rc);
}
return FALSE;
}
EnumPtr->Index += 1;
return TRUE;
}
BOOL
pPushRegKeyInfoA (
IN PREGTREE_ENUMA EnumPtr,
IN PCSTR KeyName
)
{
PREGKEYINFOA RetVal;
PSTR p;
RetVal = (PREGKEYINFOA) PoolMemGetAlignedMemory (
EnumPtr->EnumPool,
sizeof (REGKEYINFOA)
);
if (!RetVal) {
return FALSE;
}
//
// Initialize struct to zero
//
ZeroMemory (RetVal, sizeof (REGKEYINFOA));
//
// Link parent and child pointers
//
RetVal->Parent = EnumPtr->CurrentKey;
if (EnumPtr->CurrentKey) {
EnumPtr->CurrentKey->Child = RetVal;
}
EnumPtr->CurrentKey = RetVal;
//
// Prepare full key path by appending the key name to the existing
// base
//
RetVal->BaseKeyBytes = EnumPtr->FullKeyNameBytes;
p = (PSTR) ((PBYTE) EnumPtr->FullKeyName + RetVal->BaseKeyBytes);
if (EnumPtr->FullKeyNameBytes) {
StringCopyA (p, "\\");
EnumPtr->FullKeyNameBytes += ByteCountA (p);
p = _mbsinc (p);
}
_mbssafecpy (p, KeyName, MAX_REGISTRY_KEYA - EnumPtr->FullKeyNameBytes);
EnumPtr->FullKeyNameBytes += ByteCountA (KeyName);
//
// Save the key name independent of the full registry path.
// Also open the key.
//
_mbssafecpy (RetVal->KeyName, KeyName, MAX_REGISTRY_KEYA);
RetVal->KeyHandle = OpenRegKeyStrA (EnumPtr->FullKeyName);
if (!RetVal->KeyHandle) {
pPopRegKeyInfoA (EnumPtr);
return FALSE;
}
return TRUE;
}
BOOL
pPushRegKeyInfoW (
IN PREGTREE_ENUMW EnumPtr,
IN PCWSTR KeyName
)
{
PREGKEYINFOW RetVal;
PWSTR p;
RetVal = (PREGKEYINFOW) PoolMemGetAlignedMemory (
EnumPtr->EnumPool,
sizeof (REGKEYINFOW)
);
if (!RetVal) {
return FALSE;
}
//
// Initialize struct to zero
//
ZeroMemory (RetVal, sizeof (REGKEYINFOW));
//
// Link parent and child pointers
//
RetVal->Parent = EnumPtr->CurrentKey;
if (EnumPtr->CurrentKey) {
EnumPtr->CurrentKey->Child = RetVal;
}
EnumPtr->CurrentKey = RetVal;
//
// Prepare full key path by appending the key name to the existing
// base
//
RetVal->BaseKeyBytes = EnumPtr->FullKeyNameBytes;
p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + RetVal->BaseKeyBytes);
if (EnumPtr->FullKeyNameBytes) {
StringCopyW (p, L"\\");
EnumPtr->FullKeyNameBytes += ByteCountW (p);
p++;
}
_wcssafecpy (p, KeyName, MAX_REGISTRY_KEYW - (EnumPtr->FullKeyNameBytes / sizeof (WCHAR)));
EnumPtr->FullKeyNameBytes += ByteCountW (KeyName);
//
// Save the key name independent of the full registry path.
// Also open the key.
//
_wcssafecpy (RetVal->KeyName, KeyName, MAX_REGISTRY_KEYW);
RetVal->KeyHandle = OpenRegKeyStrW (EnumPtr->FullKeyName);
if (!RetVal->KeyHandle) {
pPopRegKeyInfoW (EnumPtr);
return FALSE;
}
return TRUE;
}
BOOL
pPopRegKeyInfoA (
IN PREGTREE_ENUMA EnumPtr
)
{
PREGKEYINFOA FreeMe;
PSTR p;
FreeMe = EnumPtr->CurrentKey;
//
// Skip if nothing was ever pushed
//
if (!FreeMe) {
return FALSE;
}
//
// Trim the full key string
//
EnumPtr->CurrentKey = FreeMe->Parent;
EnumPtr->FullKeyNameBytes = FreeMe->BaseKeyBytes;
p = (PSTR) ((PBYTE) EnumPtr->FullKeyName + FreeMe->BaseKeyBytes);
*p = 0;
//
// Adjust the linkage
//
if (EnumPtr->CurrentKey) {
EnumPtr->CurrentKey->Child = NULL;
}
//
// Clean up resources
//
if (FreeMe->KeyHandle) {
CloseRegKey (FreeMe->KeyHandle);
}
AbortRegKeyEnumA (&FreeMe->KeyEnum);
PoolMemReleaseMemory (EnumPtr->EnumPool, (PVOID) FreeMe);
//
// Return FALSE if last item was poped
//
return EnumPtr->CurrentKey != NULL;
}
BOOL
pPopRegKeyInfoW (
IN PREGTREE_ENUMW EnumPtr
)
{
PREGKEYINFOW FreeMe;
PWSTR p;
FreeMe = EnumPtr->CurrentKey;
//
// Skip if nothing was ever pushed
//
if (!FreeMe) {
return FALSE;
}
//
// Trim the full key string
//
EnumPtr->CurrentKey = FreeMe->Parent;
EnumPtr->FullKeyNameBytes = FreeMe->BaseKeyBytes;
p = (PWSTR) ((PBYTE) EnumPtr->FullKeyName + FreeMe->BaseKeyBytes);
*p = 0;
//
// Adjust the linkage
//
if (EnumPtr->CurrentKey) {
EnumPtr->CurrentKey->Child = NULL;
}
//
// Clean up resources
//
if (FreeMe->KeyHandle) {
CloseRegKey (FreeMe->KeyHandle);
}
AbortRegKeyEnumW (&FreeMe->KeyEnum);
PoolMemReleaseMemory (EnumPtr->EnumPool, (PVOID) FreeMe);
//
// Return FALSE if last item was poped
//
return EnumPtr->CurrentKey != NULL;
}
BOOL
RealEnumFirstRegKeyInTreeA (
OUT PREGTREE_ENUMA EnumPtr,
IN PCSTR BaseKeyStr
)
{
ZeroMemory (EnumPtr, sizeof (REGTREE_ENUMA));
//
// Allocate pool for enum structs
//
EnumPtr->EnumPool = PoolMemInitNamedPool ("RegKeyInTreeA");
if (!EnumPtr->EnumPool) {
return FALSE;
}
PoolMemSetMinimumGrowthSize (EnumPtr->EnumPool, 32768);
PoolMemDisableTracking (EnumPtr->EnumPool);
//
// Push base key on the enum stack
//
if (!pPushRegKeyInfoA (EnumPtr, BaseKeyStr)) {
DEBUGMSG ((DBG_REG, "EnumFirstRegKeyInTreeA failed to push base key"));
AbortRegKeyTreeEnumA (EnumPtr);
return FALSE;
}
EnumPtr->EnumBaseBytes = ByteCountA (BaseKeyStr);
//
// Set state so EnumNextRegKeyInTree knows what to do
//
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
return TRUE;
}
BOOL
RealEnumFirstRegKeyInTreeW (
OUT PREGTREE_ENUMW EnumPtr,
IN PCWSTR BaseKeyStr
)
{
ZeroMemory (EnumPtr, sizeof (REGTREE_ENUMW));
//
// Allocate pool for enum structs
//
EnumPtr->EnumPool = PoolMemInitNamedPool ("RegKeyInTreeW");
if (!EnumPtr->EnumPool) {
return FALSE;
}
PoolMemSetMinimumGrowthSize (EnumPtr->EnumPool, 32768);
PoolMemDisableTracking (EnumPtr->EnumPool);
//
// Push base key on the enum stack
//
if (!pPushRegKeyInfoW (EnumPtr, BaseKeyStr)) {
DEBUGMSG ((DBG_REG, "EnumFirstRegKeyInTreeW failed to push base key"));
AbortRegKeyTreeEnumW (EnumPtr);
return FALSE;
}
EnumPtr->EnumBaseBytes = ByteCountW (BaseKeyStr);
//
// Set state so EnumNextRegKeyInTree knows what to do
//
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
return TRUE;
}
BOOL
RealEnumNextRegKeyInTreeA (
IN OUT PREGTREE_ENUMA EnumPtr
)
{
if (EnumPtr->State == NO_MORE_ITEMS) {
return FALSE;
}
for (;;) {
switch (EnumPtr->State) {
case ENUMERATE_SUBKEY_BEGIN:
//
// Start enumeration
//
if (EnumFirstRegKeyA (
&EnumPtr->CurrentKey->KeyEnum,
EnumPtr->CurrentKey->KeyHandle
)) {
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
} else {
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
}
break;
case ENUMERATE_SUBKEY_NEXT:
//
// Continue enumerations
//
if (EnumNextRegKeyA (&EnumPtr->CurrentKey->KeyEnum)) {
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
} else {
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
}
break;
case ENUMERATE_SUBKEY_DONE:
//
// Enumeration of this key is done; pop and continue.
//
if (!pPopRegKeyInfoA (EnumPtr)) {
EnumPtr->State = NO_MORE_ITEMS;
AbortRegKeyTreeEnumA (EnumPtr);
} else {
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
}
break;
case ENUMERATE_SUBKEY_RETURN:
//
// Return enumerated item to caller
//
if (!pPushRegKeyInfoA (EnumPtr, EnumPtr->CurrentKey->KeyEnum.SubKeyName)) {
DEBUGMSGA ((
DBG_REG,
"RealEnumNextRegKeyInTreeA failed to push sub key %s",
EnumPtr->CurrentKey->KeyEnum.SubKeyName
));
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
break;
}
if (!EnumPtr->FirstEnumerated) {
EnumPtr->FirstEnumerated = TRUE;
EnumPtr->EnumBaseBytes += sizeof (CHAR);
}
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
return TRUE;
default:
MYASSERT (EnumPtr->State == NO_MORE_ITEMS);
return FALSE;
}
}
}
BOOL
RealEnumNextRegKeyInTreeW (
IN OUT PREGTREE_ENUMW EnumPtr
)
{
if (EnumPtr->State == NO_MORE_ITEMS) {
return FALSE;
}
for (;;) {
switch (EnumPtr->State) {
case ENUMERATE_SUBKEY_BEGIN:
//
// Start enumeration
//
if (EnumFirstRegKeyW (
&EnumPtr->CurrentKey->KeyEnum,
EnumPtr->CurrentKey->KeyHandle
)) {
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
} else {
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
}
break;
case ENUMERATE_SUBKEY_NEXT:
//
// Continue enumerations
//
if (EnumNextRegKeyW (&EnumPtr->CurrentKey->KeyEnum)) {
EnumPtr->State = ENUMERATE_SUBKEY_RETURN;
} else {
EnumPtr->State = ENUMERATE_SUBKEY_DONE;
}
break;
case ENUMERATE_SUBKEY_DONE:
//
// Enumeration of this key is done; pop and continue.
//
if (!pPopRegKeyInfoW (EnumPtr)) {
EnumPtr->State = NO_MORE_ITEMS;
AbortRegKeyTreeEnumW (EnumPtr);
} else {
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
}
break;
case ENUMERATE_SUBKEY_RETURN:
//
// Return enumerated item to caller
//
if (!pPushRegKeyInfoW (EnumPtr, EnumPtr->CurrentKey->KeyEnum.SubKeyName)) {
DEBUGMSGW ((
DBG_REG,
"RealEnumNextRegKeyInTreeW failed to push sub key %s",
EnumPtr->CurrentKey->KeyEnum.SubKeyName
));
EnumPtr->State = ENUMERATE_SUBKEY_NEXT;
break;
}
if (!EnumPtr->FirstEnumerated) {
EnumPtr->FirstEnumerated = TRUE;
EnumPtr->EnumBaseBytes += sizeof (WCHAR);
}
EnumPtr->State = ENUMERATE_SUBKEY_BEGIN;
return TRUE;
default:
MYASSERT (EnumPtr->State == NO_MORE_ITEMS);
return FALSE;
}
}
}
VOID
AbortRegKeyTreeEnumA (
IN OUT PREGTREE_ENUMA EnumPtr
)
{
//
// Free all resources
//
while (pPopRegKeyInfoA (EnumPtr)) {
}
PoolMemDestroyPool (EnumPtr->EnumPool);
}
VOID
AbortRegKeyTreeEnumW (
IN OUT PREGTREE_ENUMW EnumPtr
)
{
//
// Free all resources
//
while (pPopRegKeyInfoW (EnumPtr)) {
}
PoolMemDestroyPool (EnumPtr->EnumPool);
}
/*++
Routine Description:
EnumFirstRegValueA and EnumerateFirstRegvalueW enumerate the first registry
value name in the specified subkey.
Arguments:
EnumPtr - Receives the updated state of enumeration. The structure
can be accessed directly.
hKey - Specifies handle of registry subkey to enumerate.
Return Value:
TRUE if successful, or FALSE if an error or if no more values are available.
Call GetLastError for the failure code.
--*/
BOOL
EnumFirstRegValueA (
IN PREGVALUE_ENUMA EnumPtr,
IN HKEY hKey
)
{
ZeroMemory (EnumPtr, sizeof (REGVALUE_ENUMA));
EnumPtr->KeyHandle = hKey;
return EnumNextRegValueA (EnumPtr);
}
BOOL
EnumFirstRegValueW (
IN PREGVALUE_ENUMW EnumPtr,
IN HKEY hKey
)
{
ZeroMemory (EnumPtr, sizeof (REGVALUE_ENUMW));
EnumPtr->KeyHandle = hKey;
return EnumNextRegValueW (EnumPtr);
}
/*++
Routine Description:
EnumNextRegValueA and EnumNextRegValueW continue the enumeration started
by EnumFirstRegValueA/W. The enumeration structure is updated to
reflect the next value name in the subkey being enumerated.
Arguments:
EnumPtr - Specifies the registry subkey and enumeration position.
Receives the updated state of enumeration. The structure
can be accessed directly.
Return Value:
TRUE if successful, or FALSE if an error or if no more values are available.
Call GetLastError for the failure code.
--*/
BOOL
EnumNextRegValueA (
IN OUT PREGVALUE_ENUMA EnumPtr
)
{
LONG rc;
DWORD ValueNameSize;
ValueNameSize = MAX_REGISTRY_VALUE_NAMEA;
rc = RegEnumValueA (
EnumPtr->KeyHandle,
EnumPtr->Index,
EnumPtr->ValueName,
&ValueNameSize,
NULL,
&EnumPtr->Type,
NULL,
&EnumPtr->DataSize
);
if (rc == ERROR_NO_MORE_ITEMS) {
SetLastError (ERROR_SUCCESS);
return FALSE;
} else if (rc != ERROR_SUCCESS) {
SetLastError (rc);
return FALSE;
}
EnumPtr->Index += 1;
return TRUE;
}
BOOL
EnumNextRegValueW (
IN OUT PREGVALUE_ENUMW EnumPtr
)
{
LONG rc;
DWORD ValueNameSize;
ValueNameSize = MAX_REGISTRY_VALUE_NAMEW;
rc = RegEnumValueW (
EnumPtr->KeyHandle,
EnumPtr->Index,
EnumPtr->ValueName,
&ValueNameSize,
NULL,
&EnumPtr->Type,
NULL,
&EnumPtr->DataSize
);
if (rc == ERROR_NO_MORE_ITEMS) {
SetLastError (ERROR_SUCCESS);
return FALSE;
} else if (rc != ERROR_SUCCESS) {
SetLastError (rc);
return FALSE;
}
EnumPtr->Index += 1;
return TRUE;
}
/*++
Routine Description:
DecodeRegistryString turns an encoded string back into a key, value name
and tree flag.
The caller must pass in buffers at least as big as MAX_REGISTRY_KEY and
MAX_REGISTRY_VALUE_NAME.
Arguments:
RegString - Specifies the encoded registry string that contains a key name,
and an optional value name or tree flag.
KeyBuf - Receives the key name
ValueBuf - Receives the value name
TreeFlag - Receives the tree flag, TRUE if the encoded string indicates a
registry key tree, FALSE otherwise.
Return Value:
TRUE if the encoded string contained a value, FALSE if it contained just a
key or key tree.
--*/
BOOL
DecodeRegistryStringA (
IN PCSTR RegString,
OUT PSTR KeyBuf, OPTIONAL
OUT PSTR ValueBuf, OPTIONAL
OUT PBOOL TreeFlag OPTIONAL
)
{
CHAR TempKeyBuf[MAX_REGISTRY_KEY];
PSTR End;
CHAR TempValueNameBuf[MAX_REGISTRY_VALUE_NAME];
BOOL TempTreeFlag = FALSE;
MBCHAR ch;
PSTR p;
BOOL b = FALSE;
//
// Walk through encoded string, pulling out key name
//
TempKeyBuf[0] = 0;
TempValueNameBuf[0] = 0;
End = TempKeyBuf + ARRAYSIZE(TempKeyBuf) - 2;
p = TempKeyBuf;
while (*RegString && *RegString != '*' && *RegString != '[') {
ch = GetNextRuleCharA (&RegString, NULL);
*((PWORD) p) = (WORD)ch;
p = _mbsinc (p);
if (p >= End) {
RegString = GetEndOfStringA (RegString);
break;
}
}
*p = 0;
p = (PSTR) SkipSpaceRA (TempKeyBuf, p);
*(_mbsinc (p)) = 0;
if (*RegString == '*' && _mbsnextc (p) == '\\') {
//
// If a tree, stop here
//
TempTreeFlag = TRUE;
*p = 0;
} else if (*RegString == '[') {
//
// If a value name, parse it
//
RegString++;
End = TempValueNameBuf + ARRAYSIZE(TempValueNameBuf) - 2;
p = TempValueNameBuf;
while (*RegString && *RegString != ']') {
ch = GetNextRuleCharA (&RegString, NULL);
*((PWORD) p) = (WORD)ch;
p = _mbsinc (p);
if (p >= End) {
RegString = GetEndOfStringA (RegString);
break;
}
}
*p = 0;
p = (PSTR) SkipSpaceRA (TempValueNameBuf, p);
if (p) // Guard against empty or all-whitespace value name.
*(p + 1) = 0;
RemoveWackAtEndA (TempKeyBuf);
b = TRUE;
}
if (KeyBuf) {
StringCopyA (KeyBuf, TempKeyBuf);
}
if (ValueBuf) {
StringCopyA (ValueBuf, TempValueNameBuf);
}
if (TreeFlag) {
*TreeFlag = TempTreeFlag;
}
return b;
}
BOOL
DecodeRegistryStringW (
IN PCWSTR RegString,
OUT PWSTR KeyBuf, OPTIONAL
OUT PWSTR ValueBuf, OPTIONAL
OUT PBOOL TreeFlag OPTIONAL
)
{
WCHAR TempKeyBuf[MAX_REGISTRY_KEY];
PWSTR End;
WCHAR TempValueNameBuf[MAX_REGISTRY_VALUE_NAME];
BOOL TempTreeFlag = FALSE;
WCHAR ch;
PWSTR p;
BOOL b = FALSE;
//
// Walk through encoded string, pulling out key name
//
TempKeyBuf[0] = 0;
TempValueNameBuf[0] = 0;
End = TempKeyBuf + ARRAYSIZE(TempKeyBuf) - 2;
p = TempKeyBuf;
while (*RegString && *RegString != L'*' && *RegString != L'[') {
ch = GetNextRuleCharW (&RegString, NULL);
*((PWORD) p) = ch;
p++;
if (p >= End) {
RegString = GetEndOfStringW (RegString);
break;
}
}
*p = 0;
p = (PWSTR) SkipSpaceRW (TempKeyBuf, p);
if (!p) {
return FALSE;
}
*(p + 1) = 0;
if (*RegString == L'*' && *p == L'\\') {
//
// If a tree, stop here
//
TempTreeFlag = TRUE;
*p = 0;
} else if (*RegString == L'[') {
//
// If a value name, parse it
//
RegString++;
End = TempValueNameBuf + ARRAYSIZE(TempValueNameBuf) - 2;
p = TempValueNameBuf;
while (*RegString && *RegString != L']') {
ch = GetNextRuleCharW (&RegString, NULL);
*((PWORD) p) = ch;
p++;
if (p >= End) {
RegString = GetEndOfStringW (RegString);
break;
}
}
*p = 0;
p = (PWSTR) SkipSpaceRW (TempValueNameBuf, p);
if (p) { // Guard against empty or all-whitespace value name.
*(p + 1) = 0;
}
RemoveWackAtEndW (TempKeyBuf);
b = TRUE;
}
if (KeyBuf) {
StringCopyW (KeyBuf, TempKeyBuf);
}
if (ValueBuf) {
StringCopyW (ValueBuf, TempValueNameBuf);
}
if (TreeFlag) {
*TreeFlag = TempTreeFlag;
}
return b;
}