|
|
/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
regtool.c
Abstract:
This file contains functions for supporting the registry tools REGINI, REGDMP, REGDIR and REGFIND
Author:
Steve Wood (stevewo) 15-Nov-1995
Revision History:
--*/
#include <tchar.h>
#include "regutil.h"
ULONG ValueBufferSize = (4096 * 100); PVOID ValueBuffer;
UCHAR BlanksForPadding[] = " ";
//
// routines for creating security descriptors (defined in regacl.c)
//
BOOLEAN RegInitializeSecurity( VOID );
BOOLEAN WINAPI RegUnicodeToDWORD( IN OUT PWSTR *String, IN DWORD Base OPTIONAL, OUT PDWORD Value );
BOOLEAN RegCreateSecurity( IN PWSTR Description, OUT PSECURITY_DESCRIPTOR SecurityDescriptor );
BOOLEAN RegFormatSecurity( IN PSECURITY_DESCRIPTOR SecurityDescriptor, OUT PWSTR AceList );
VOID RegDestroySecurity( IN PSECURITY_DESCRIPTOR SecurityDescriptor );
LONG RegLoadHive( IN PREG_CONTEXT RegistryContext, IN PWSTR HiveFileName, IN PWSTR HiveRootName );
void RegUnloadHive( IN PREG_CONTEXT RegistryContext );
struct { PWSTR TypeName; ULONG ValueType; BOOLEAN GetDataFromBinaryFile; BOOLEAN GetDataFromMultiSzFile; BOOLEAN ParseDateTime; } RegTypeNameTable[] = { {L"REG_SZ", REG_SZ, FALSE, FALSE, FALSE}, {L"REG_EXPAND_SZ", REG_EXPAND_SZ, FALSE, FALSE, FALSE}, {L"REG_MULTI_SZ", REG_MULTI_SZ, FALSE, FALSE, FALSE}, {L"REG_MULTISZ_FILE", REG_MULTI_SZ, FALSE, TRUE, FALSE}, {L"REG_DWORD", REG_DWORD, FALSE, FALSE, FALSE}, {L"REG_NONE", REG_NONE, FALSE, FALSE, FALSE}, {L"REG_BINARY", REG_BINARY, FALSE, FALSE, FALSE}, {L"REG_BINARYFILE", REG_BINARY, TRUE, FALSE, FALSE}, {L"REG_DATE", REG_BINARY, FALSE, FALSE, TRUE}, {L"REG_RESOURCE_LIST", REG_RESOURCE_LIST, FALSE, FALSE, FALSE}, {L"REG_RESOURCE_REQUIREMENTS_LIST", REG_RESOURCE_REQUIREMENTS_LIST, FALSE, FALSE, FALSE}, {L"REG_RESOURCE_REQUIREMENTS", REG_RESOURCE_REQUIREMENTS_LIST, FALSE, FALSE, FALSE}, {L"REG_FULL_RESOURCE_DESCRIPTOR", REG_FULL_RESOURCE_DESCRIPTOR, FALSE, FALSE, FALSE}, {NULL, REG_NONE, FALSE, FALSE, FALSE} };
struct { PWSTR ValueName; ULONG Value; } RegValueNameTable[] = { {L"ON", TRUE}, {L"YES", TRUE}, {L"TRUE", TRUE}, {L"OFF", FALSE}, {L"NO", FALSE}, {L"FALSE", FALSE}, {NULL, FALSE} };
int RegAnsiToUnicode( LPCSTR Source, PWSTR Destination, ULONG NumberOfChars ) { int NumberOfXlatedChars;
if (NumberOfChars == 0) { NumberOfChars = strlen( Source ); }
NumberOfXlatedChars = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, Source, NumberOfChars, Destination, NumberOfChars );
Destination[ NumberOfXlatedChars ] = UNICODE_NULL;
if ( NumberOfXlatedChars == 0 ) { SetLastError( ERROR_NO_UNICODE_TRANSLATION ); }
return NumberOfXlatedChars; }
int RegUnicodeToAnsi( PCWSTR Source, LPSTR Destination, ULONG NumberOfChars ) { int NumberOfXlatedChars;
if (NumberOfChars == 0) { NumberOfChars = wcslen( Source ); }
NumberOfXlatedChars = WideCharToMultiByte( CP_ACP, 0, Source, NumberOfChars, Destination, NumberOfChars * 2, NULL, NULL );
Destination[ NumberOfXlatedChars ] = '\0';
if ( NumberOfXlatedChars == 0 ) { SetLastError( ERROR_NO_UNICODE_TRANSLATION ); }
return NumberOfXlatedChars; }
typedef LONG (APIENTRY *LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE)( HKEY hKey, LPCSTR lpFileName, UINT Flags );
typedef LONG (APIENTRY *LPVMMREGLOADKEY_PROCEDURE)( HKEY hKey, LPCSTR lpSubKey, LPCSTR lpFileName );
typedef LONG (APIENTRY *LPVMMREGUNLOADKEY_PROCEDURE)( HKEY hKey, LPCSTR lpSubKey );
typedef LONG (APIENTRY *LPVMMREGCREATEKEY_PROCEDURE)( HKEY hKey, LPCSTR lpSubKey, PHKEY lphSubKey );
typedef LONG (APIENTRY *LPVMMREGDELETEKEY_PROCEDURE)( HKEY hKey, LPCSTR lpSubKey );
typedef LONG (APIENTRY *LPVMMREGOPENKEY_PROCEDURE)( HKEY hKey, LPCSTR lpSubKey, PHKEY lphSubKey );
typedef LONG (APIENTRY *LPVMMREGFLUSHKEY_PROCEDURE)( HKEY hKey );
typedef LONG (APIENTRY *LPVMMREGCLOSEKEY_PROCEDURE)( HKEY hKey );
typedef LONG (APIENTRY *LPVMMREGQUERYINFOKEY_PROCEDURE)( HKEY hKey, LPCSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueName, LPDWORD lpcbMaxValueData, LPVOID lpcbSecurityDescriptor, LPVOID lpftLastWriteTime );
typedef LONG (APIENTRY *LPVMMREGENUMKEY_PROCEDURE)( HKEY hKey, DWORD Index, LPSTR lpKeyName, DWORD cbKeyName );
typedef LONG (APIENTRY *LPVMMREGENUMVALUE_PROCEDURE)( HKEY hKey, DWORD Index, LPSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData );
typedef LONG (APIENTRY *LPVMMREGQUERYVALUEEX_PROCEDURE)( HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData );
typedef LONG (APIENTRY *LPVMMREGSETVALUEEX_PROCEDURE)( HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD Type, LPBYTE lpData, DWORD cbData );
typedef LONG (APIENTRY *LPVMMREGDELETEVALUE_PROCEDURE)( HKEY hKey, LPCSTR lpValueName );
HMODULE hVMMREG32; LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE _Win95RegMapPredefKeyToFile; LPVMMREGLOADKEY_PROCEDURE _Win95RegLoadKey; LPVMMREGUNLOADKEY_PROCEDURE _Win95RegUnLoadKey; LPVMMREGCREATEKEY_PROCEDURE _Win95RegCreateKey; LPVMMREGDELETEKEY_PROCEDURE _Win95RegDeleteKey; LPVMMREGOPENKEY_PROCEDURE _Win95RegOpenKey; LPVMMREGFLUSHKEY_PROCEDURE _Win95RegFlushKey; LPVMMREGCLOSEKEY_PROCEDURE _Win95RegCloseKey; LPVMMREGQUERYINFOKEY_PROCEDURE _Win95RegQueryInfoKey; LPVMMREGENUMKEY_PROCEDURE _Win95RegEnumKey; LPVMMREGENUMVALUE_PROCEDURE _Win95RegEnumValue; LPVMMREGQUERYVALUEEX_PROCEDURE _Win95RegQueryValueEx; LPVMMREGSETVALUEEX_PROCEDURE _Win95RegSetValueEx; LPVMMREGDELETEVALUE_PROCEDURE _Win95RegDeleteValue;
BOOLEAN RegInitWin95RegistryAccess( PREG_CONTEXT RegistryContext, PWSTR Win95Path, PWSTR Win95UserPath ) { LONG Error; char Buffer[ MAX_PATH+1 ];
if ((hVMMREG32 = LoadLibrary( L"VMMREG32" )) == NULL) { return FALSE; }
_Win95RegMapPredefKeyToFile = (LPVMMREGMAPPREDEFKEYTOFILE_PROCEDURE)GetProcAddress( hVMMREG32, "VMMRegMapPredefKeyToFile" ); _Win95RegLoadKey = (LPVMMREGLOADKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegLoadKey" ); _Win95RegUnLoadKey = (LPVMMREGUNLOADKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegUnLoadKey" ); _Win95RegCreateKey = (LPVMMREGCREATEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegCreateKey" ); _Win95RegDeleteKey = (LPVMMREGDELETEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegDeleteKey" ); _Win95RegOpenKey = (LPVMMREGOPENKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegOpenKey" ); _Win95RegFlushKey = (LPVMMREGFLUSHKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegFlushKey" ); _Win95RegCloseKey = (LPVMMREGCLOSEKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegCloseKey" ); _Win95RegQueryInfoKey = (LPVMMREGQUERYINFOKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegQueryInfoKey" ); _Win95RegEnumKey = (LPVMMREGENUMKEY_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegEnumKey" ); _Win95RegEnumValue = (LPVMMREGENUMVALUE_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegEnumValue" ); _Win95RegQueryValueEx = (LPVMMREGQUERYVALUEEX_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegQueryValueEx" ); _Win95RegSetValueEx = (LPVMMREGSETVALUEEX_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegSetValueEx" ); _Win95RegDeleteValue = (LPVMMREGDELETEVALUE_PROCEDURE )GetProcAddress( hVMMREG32, "VMMRegDeleteValue" );
if ((_Win95RegMapPredefKeyToFile == NULL) || (_Win95RegLoadKey == NULL) || (_Win95RegUnLoadKey == NULL) || (_Win95RegCreateKey == NULL) || (_Win95RegDeleteKey == NULL) || (_Win95RegOpenKey == NULL) || (_Win95RegFlushKey == NULL) || (_Win95RegCloseKey == NULL) || (_Win95RegQueryInfoKey == NULL) || (_Win95RegEnumKey == NULL) || (_Win95RegEnumValue == NULL) || (_Win95RegQueryValueEx == NULL) || (_Win95RegSetValueEx == NULL) || (_Win95RegDeleteValue == NULL) ) { FreeLibrary( hVMMREG32 ); SetLastError( ERROR_PROC_NOT_FOUND ); return FALSE; }
//
// Map HKEY_LOCAL_MACHINE of Win95 hive
//
RegUnicodeToAnsi( Win95Path, Buffer, 0 ); strcat( Buffer, "\\system.dat" ); Error = (_Win95RegMapPredefKeyToFile)( HKEY_LOCAL_MACHINE, Buffer, 0 ); if (Error == NO_ERROR) { RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE; RegUnicodeToAnsi( Win95Path, Buffer, 0 ); strcat( Buffer, "\\user.dat" ); Error = (_Win95RegMapPredefKeyToFile)( HKEY_USERS, Buffer, 0 ); if (Error == NO_ERROR) { RegistryContext->UsersRoot = HKEY_USERS; Error = (_Win95RegOpenKey)( HKEY_USERS, ".Default", &RegistryContext->CurrentUserRoot ); } }
if (Error != NO_ERROR) { if (RegistryContext->MachineRoot != NULL) { (_Win95RegMapPredefKeyToFile)( RegistryContext->MachineRoot, NULL, 0 ); }
if (RegistryContext->UsersRoot) { (_Win95RegMapPredefKeyToFile)( RegistryContext->UsersRoot, NULL, 0 ); }
FreeLibrary( hVMMREG32 ); SetLastError( Error ); return FALSE; }
wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" ); wcscpy( RegistryContext->CurrentUserPath, RegistryContext->UsersPath ); wcscat( RegistryContext->CurrentUserPath, L"\\.Default" ); return TRUE; }
BOOLEAN PrivilegeEnabled; BOOLEAN RestoreWasEnabled; BOOLEAN BackupWasEnabled;
BOOLEAN RTEnableBackupRestorePrivilege( void ) { NTSTATUS Status;
//
// Try to enable backup and restore privileges
//
Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE, TRUE, // Enable
FALSE, // Not impersonating
&RestoreWasEnabled // previous state
); if (!NT_SUCCESS( Status )) { return FALSE; }
Status = RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE, TRUE, // Enable
FALSE, // Not impersonating
&BackupWasEnabled // previous state
); if (!NT_SUCCESS( Status )) { return FALSE; }
PrivilegeEnabled = TRUE; return TRUE; }
void RTDisableBackupRestorePrivilege( void ) { //
// Restore privileges to what they were
//
RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE, RestoreWasEnabled, FALSE, &RestoreWasEnabled );
RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE, BackupWasEnabled, FALSE, &BackupWasEnabled );
PrivilegeEnabled = FALSE; return; }
BOOLEAN RTInitialize( void ) /*++
Routine Description:
DLL initialization function.
Arguments:
hInstance - Instance handle Reason - Reason for the entrypoint being called Context - Context record
Return Value:
TRUE - Initialization succeeded FALSE - Initialization failed
--*/
{ ValueBuffer = VirtualAlloc( NULL, ValueBufferSize, MEM_COMMIT, PAGE_READWRITE ); if (ValueBuffer == NULL) { return FALSE; }
if (!RegInitializeSecurity()) { return FALSE; }
return TRUE; }
LONG RTConnectToRegistry( IN PWSTR MachineName, IN PWSTR HiveFileName, IN PWSTR HiveRootName, IN PWSTR Win95Path, IN PWSTR Win95UserName, OUT PWSTR *DefaultRootKeyName, OUT PREG_CONTEXT RegistryContext ) { LONG Error;
if (MachineName != NULL) { if (HiveRootName || HiveFileName || Win95Path || Win95UserName) { return ERROR_INVALID_PARAMETER; }
Error = RegConnectRegistry( MachineName, HKEY_LOCAL_MACHINE, (PHKEY)&RegistryContext->MachineRoot ); if (Error == NO_ERROR) { Error = RegConnectRegistry( MachineName, HKEY_USERS, (PHKEY)&RegistryContext->UsersRoot ); if (Error == NO_ERROR) { Error = RegOpenKey( RegistryContext->UsersRoot, L".Default", &RegistryContext->CurrentUserRoot ); } }
if (Error != NO_ERROR) { if (RegistryContext->MachineRoot != NULL) { RegCloseKey( RegistryContext->MachineRoot ); RegistryContext->MachineRoot = NULL; }
if (RegistryContext->UsersRoot != NULL) { RegCloseKey( RegistryContext->UsersRoot ); RegistryContext->UsersRoot = NULL; }
return Error; }
wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" ); wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" ); wcscpy( RegistryContext->CurrentUserPath, L"\\Registry\\Users\\.Default" ); RegistryContext->Target = REG_TARGET_REMOTE_REGISTRY; } else if (HiveRootName != NULL || HiveFileName != NULL) { if (HiveRootName == NULL || HiveFileName == NULL || Win95Path != NULL || Win95UserName != NULL ) { return ERROR_INVALID_PARAMETER; }
if (!PrivilegeEnabled && !RTEnableBackupRestorePrivilege()) { return ERROR_PRIVILEGE_NOT_HELD; }
RegistryContext->MachineRoot = NULL; RegistryContext->UsersRoot = NULL; RegistryContext->CurrentUserRoot = NULL;
Error = RegLoadHive( RegistryContext, HiveFileName, HiveRootName ); if (Error != NO_ERROR) { return Error; }
if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) { *DefaultRootKeyName = HiveRootName; } RegistryContext->Target = REG_TARGET_HIVE_REGISTRY; } else if (Win95Path != NULL || Win95UserName != NULL) { if (!RegInitWin95RegistryAccess( RegistryContext, Win95Path, Win95UserName ) ) { return GetLastError(); }
RegistryContext->Target = REG_TARGET_WIN95_REGISTRY; } else { NTSTATUS Status; UNICODE_STRING CurrentUserKeyPath;
RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE; RegistryContext->UsersRoot = HKEY_USERS; RegistryContext->CurrentUserRoot = HKEY_CURRENT_USER;
wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" ); wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" ); Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath ); if (!NT_SUCCESS( Status )) { SetLastError( RtlNtStatusToDosError( Status ) ); return FALSE; }
wcscpy( RegistryContext->CurrentUserPath, CurrentUserKeyPath.Buffer ); RtlFreeUnicodeString( &CurrentUserKeyPath );
RegistryContext->Target = REG_TARGET_LOCAL_REGISTRY; }
if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) { *DefaultRootKeyName = L"\\Registry"; } RegistryContext->MachinePathLength = wcslen( RegistryContext->MachinePath ); RegistryContext->UsersPathLength = wcslen( RegistryContext->UsersPath ); RegistryContext->CurrentUserPathLength = wcslen( RegistryContext->CurrentUserPath ); return NO_ERROR; }
LONG RTDisconnectFromRegistry( IN PREG_CONTEXT RegistryContext ) { switch( RegistryContext->Target ) { case REG_TARGET_DISCONNECTED: break;
case REG_TARGET_LOCAL_REGISTRY: break;
case REG_TARGET_REMOTE_REGISTRY: break;
case REG_TARGET_WIN95_REGISTRY: // (_Win95RegMapPredefKeyToFile)( RegistryContext->MachineRoot, NULL, 0 );
// (_Win95RegMapPredefKeyToFile)( RegistryContext->UsersRoot, NULL, 0 );
(_Win95RegCloseKey)( RegistryContext->CurrentUserRoot ); FreeLibrary( hVMMREG32 ); break;
case REG_TARGET_HIVE_REGISTRY: RegUnloadHive( RegistryContext ); break; }
if (PrivilegeEnabled) { RTDisableBackupRestorePrivilege(); }
RegistryContext->Target = REG_TARGET_DISCONNECTED; return NO_ERROR; }
UNICODE_STRING RegHiveRootName;
LONG RegLoadHive( IN PREG_CONTEXT RegistryContext, IN PWSTR HiveFileName, IN PWSTR HiveRootName ) { NTSTATUS Status; UNICODE_STRING NtFileName; OBJECT_ATTRIBUTES File; SECURITY_DESCRIPTOR SecurityDescriptor;
//
// Create security descriptor with a NULL Dacl. This is necessary
// because the security descriptor we pass in gets used in system
// context. So if we just pass in NULL, then the Wrong Thing happens.
// (but only on NTFS!)
//
Status = RtlCreateSecurityDescriptor( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); if (!NT_SUCCESS( Status )) { return RtlNtStatusToDosError( Status ); }
Status = RtlSetDaclSecurityDescriptor( &SecurityDescriptor, TRUE, // Dacl present
NULL, // but grants all access
FALSE ); if (!NT_SUCCESS( Status )) { return RtlNtStatusToDosError( Status ); }
if (!RtlDosPathNameToNtPathName_U( HiveFileName, &NtFileName, NULL, NULL ) ) { return ERROR_BAD_PATHNAME; } InitializeObjectAttributes( &File, &NtFileName, OBJ_CASE_INSENSITIVE, NULL, &SecurityDescriptor );
RtlInitUnicodeString( &RegHiveRootName, L"\\Registry"); InitializeObjectAttributes( &RegistryContext->HiveRootKey, &RegHiveRootName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey( &RegistryContext->HiveRootHandle, MAXIMUM_ALLOWED, &RegistryContext->HiveRootKey ); if (!NT_SUCCESS(Status)) { return RtlNtStatusToDosError( Status ); }
RtlInitUnicodeString( &RegHiveRootName, HiveRootName ); InitializeObjectAttributes( &RegistryContext->HiveRootKey, &RegHiveRootName, OBJ_CASE_INSENSITIVE, RegistryContext->HiveRootHandle, NULL ); NtUnloadKey( &RegistryContext->HiveRootKey ); Status = NtLoadKey( &RegistryContext->HiveRootKey, &File ); if (!NT_SUCCESS( Status )) { return RtlNtStatusToDosError( Status ); }
return NO_ERROR;
}
void RegUnloadHive( IN PREG_CONTEXT RegistryContext ) { NTSTATUS Status; HANDLE Handle; PREG_CONTEXT_OPEN_HIVE_KEY p, p1;
Status = NtOpenKey( &Handle, MAXIMUM_ALLOWED, &RegistryContext->HiveRootKey ); if (NT_SUCCESS( Status )) { NtFlushKey( Handle ); NtClose( Handle ); }
p = RegistryContext->OpenHiveKeys; while (p) { RegCloseKey( p->KeyHandle ); p1 = p; p = p->Next; HeapFree( GetProcessHeap(), 0, p1 ); };
do { Status = NtUnloadKey( &RegistryContext->HiveRootKey ); } while (NT_SUCCESS( Status ) );
NtClose( RegistryContext->HiveRootHandle ); return; }
void RegRememberOpenKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle ) { PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
pp = &RegistryContext->OpenHiveKeys; while ((p = *pp) != NULL) { if (p->KeyHandle == KeyHandle) { p->ReferenceCount += 1; return; } else { pp = &p->Next; } }
p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) ); if (p != NULL) { p->KeyHandle = KeyHandle; p->ReferenceCount = 1; p->Next = NULL; *pp = p; }
return; }
void RegForgetOpenKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle ) { PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
pp = &RegistryContext->OpenHiveKeys; while ((p = *pp) != NULL) { if (p->KeyHandle == KeyHandle) { p->ReferenceCount -= 1; if (p->ReferenceCount == 0) { *pp = p->Next; HeapFree( GetProcessHeap(), 0, p ); return; } } else { pp = &p->Next; } }
return; }
BOOLEAN RegCheckPrefix( IN OUT PCWSTR *s, IN PCWSTR Prefix, IN ULONG PrefixLength ) { if (PrefixLength == 0) { return FALSE; }
if (!_wcsnicmp( *s, Prefix, PrefixLength )) { *s += PrefixLength; return TRUE; }
return FALSE; }
BOOLEAN RegValidateKeyPath( IN PREG_CONTEXT RegistryContext, IN OUT PHKEY RootKeyHandle, IN OUT PCWSTR *SubKeyName ) { PCWSTR s;
s = *SubKeyName; if (*RootKeyHandle == NULL) { if (RegCheckPrefix( &s, L"USER:", 5 ) || RegCheckPrefix( &s, L"HKEY_CURRENT_USER", 17 ) ) { if (RegistryContext->CurrentUserRoot == NULL) { SetLastError( ERROR_BAD_PATHNAME ); return FALSE; }
if (*s == L'\\') { s += 1; } else if (s[-1] != L':' && *s != UNICODE_NULL) { SetLastError( ERROR_BAD_PATHNAME ); return FALSE; }
*RootKeyHandle = RegistryContext->CurrentUserRoot; } else if (RegCheckPrefix( &s, L"HKEY_LOCAL_MACHINE", 18 )) { if (*s == L'\\') { s += 1; } else if (*s != UNICODE_NULL) { SetLastError( ERROR_BAD_PATHNAME ); return FALSE; }
*RootKeyHandle = RegistryContext->MachineRoot; } else if (RegCheckPrefix( &s, L"HKEY_USERS", 10 )) { if (*s == L'\\') { s += 1; } else if (*s != UNICODE_NULL) { SetLastError( ERROR_BAD_PATHNAME ); return FALSE; }
*RootKeyHandle = RegistryContext->UsersRoot; } else if (*s != L'\\') { SetLastError( ERROR_BAD_PATHNAME ); return FALSE; } else if (RegCheckPrefix( &s, RegistryContext->MachinePath, RegistryContext->MachinePathLength )) { *RootKeyHandle = RegistryContext->MachineRoot; if (*s == L'\\') { s += 1; } } else if (RegCheckPrefix( &s, RegistryContext->UsersPath, RegistryContext->UsersPathLength )) { *RootKeyHandle = RegistryContext->UsersRoot; if (*s == L'\\') { s += 1; } } else if (RegCheckPrefix( &s, RegistryContext->CurrentUserPath, RegistryContext->CurrentUserPathLength )) { *RootKeyHandle = RegistryContext->CurrentUserRoot; if (*s == L'\\') { s += 1; } } else if (!_wcsicmp( *SubKeyName, L"\\Registry" )) { *RootKeyHandle = NULL; } else { SetLastError( ERROR_BAD_PATHNAME ); return FALSE; } } else if (*s == L'\\') { SetLastError( ERROR_BAD_PATHNAME ); return FALSE; }
*SubKeyName = s; return TRUE; }
LONG RTCreateKey( IN PREG_CONTEXT RegistryContext, IN HKEY RootKeyHandle, IN PCWSTR SubKeyName, IN ACCESS_MASK DesiredAccess, IN ULONG CreateOptions, IN PVOID SecurityDescriptor, OUT PHKEY ReturnedKeyHandle, OUT PULONG Disposition ) { LONG Error;
if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) { return GetLastError(); }
if (RootKeyHandle == NULL) { *Disposition = REG_OPENED_EXISTING_KEY; *ReturnedKeyHandle = HKEY_REGISTRY_ROOT; return NO_ERROR; } else if (RootKeyHandle == HKEY_REGISTRY_ROOT) { *ReturnedKeyHandle = NULL; if (!_wcsicmp( SubKeyName, L"Machine" )) { *ReturnedKeyHandle = RegistryContext->MachineRoot; } else if (!_wcsicmp( SubKeyName, L"Users" )) { *ReturnedKeyHandle = RegistryContext->UsersRoot; }
if (*ReturnedKeyHandle != NULL) { return NO_ERROR; } else { return ERROR_PATH_NOT_FOUND; } }
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
if (SubKeyName != NULL) { if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) { return GetLastError(); }
p = AnsiSubKeyName; } else { p = NULL; }
Error = (_Win95RegOpenKey)( RootKeyHandle, p, ReturnedKeyHandle ); if (Error == NO_ERROR) { *Disposition = REG_OPENED_EXISTING_KEY; } else { Error = (_Win95RegCreateKey)( RootKeyHandle, p, ReturnedKeyHandle ); if (Error == NO_ERROR) { *Disposition = REG_CREATED_NEW_KEY; } } } else { SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength = sizeof( SecurityAttributes ); SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor; SecurityAttributes.bInheritHandle = FALSE; Error = RegCreateKeyEx( RootKeyHandle, SubKeyName, 0, NULL, CreateOptions, (REGSAM)DesiredAccess, &SecurityAttributes, ReturnedKeyHandle, Disposition ); if (Error == NO_ERROR && RegistryContext->Target == REG_TARGET_HIVE_REGISTRY ) { RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle ); }
if (Error == NO_ERROR && *Disposition == REG_OPENED_EXISTING_KEY && SecurityDescriptor != NULL ) { RegSetKeySecurity( *ReturnedKeyHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor ); } }
return Error; }
LONG RTOpenKey( IN PREG_CONTEXT RegistryContext, IN HKEY RootKeyHandle, IN PCWSTR SubKeyName, IN ACCESS_MASK DesiredAccess, IN ULONG OpenOptions, OUT PHKEY ReturnedKeyHandle ) { LONG Error;
if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) { return GetLastError(); }
if (RootKeyHandle == NULL) { *ReturnedKeyHandle = HKEY_REGISTRY_ROOT; return NO_ERROR; } else if (RootKeyHandle == HKEY_REGISTRY_ROOT) { *ReturnedKeyHandle = NULL; if (!_wcsicmp( SubKeyName, L"Machine" )) { *ReturnedKeyHandle = RegistryContext->MachineRoot; } else if (!_wcsicmp( SubKeyName, L"Users" )) { *ReturnedKeyHandle = RegistryContext->UsersRoot; }
if (*ReturnedKeyHandle != NULL) { return NO_ERROR; } else { return ERROR_PATH_NOT_FOUND; } }
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
if (SubKeyName != NULL) { if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) { return GetLastError(); }
p = AnsiSubKeyName; } else { p = NULL; }
return (_Win95RegOpenKey)( RootKeyHandle, p, ReturnedKeyHandle ); } else { Error = RegOpenKeyEx( RootKeyHandle, SubKeyName, OpenOptions, DesiredAccess, ReturnedKeyHandle ); if (Error == NO_ERROR && RegistryContext->Target == REG_TARGET_HIVE_REGISTRY ) { RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle ); }
return Error; } }
LONG RTCloseKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle ) { LONG Error;
if (KeyHandle == HKEY_REGISTRY_ROOT) { return NO_ERROR; } else if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { return (_Win95RegCloseKey)( KeyHandle ); } else { Error = RegCloseKey( KeyHandle ); if (Error == NO_ERROR && RegistryContext->Target == REG_TARGET_HIVE_REGISTRY ) { RegForgetOpenKey( RegistryContext, KeyHandle ); }
return Error; } }
LONG RTFlushKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle ) { if (KeyHandle == HKEY_REGISTRY_ROOT) { return NO_ERROR; } else if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { return (_Win95RegFlushKey)( KeyHandle ); } else { return RegFlushKey( KeyHandle ); } }
LONG RTEnumerateKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle, IN ULONG Index, OUT PFILETIME LastWriteTime, IN OUT PULONG KeyNameLength, OUT PWSTR KeyName ) { ULONG Error;
if (KeyHandle == HKEY_REGISTRY_ROOT) { if (Index == 0) { if (*KeyNameLength <= 7) { return ERROR_MORE_DATA; } else { wcscpy( KeyName, L"Machine" ); return NO_ERROR; } } else if (Index == 1) { if (*KeyNameLength <= 5) { return ERROR_MORE_DATA; } else { wcscpy( KeyName, L"Users" ); return NO_ERROR; } } else { return ERROR_NO_MORE_ITEMS; } } else if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiKeyName[ MAX_PATH ]; ULONG AnsiKeyNameLength;
AnsiKeyNameLength = sizeof( AnsiKeyName ); Error = _Win95RegEnumKey( KeyHandle, Index, AnsiKeyName, AnsiKeyNameLength ); if (Error == NO_ERROR) { if (strlen( AnsiKeyName ) >= *KeyNameLength) { return ERROR_MORE_DATA; }
*KeyNameLength = RegAnsiToUnicode( AnsiKeyName, KeyName, AnsiKeyNameLength );
if (*KeyNameLength == 0) { return GetLastError(); }
RtlZeroMemory( LastWriteTime, sizeof( *LastWriteTime ) ); } } else { Error = RegEnumKeyEx( KeyHandle, Index, KeyName, KeyNameLength, NULL, NULL, NULL, LastWriteTime ); }
return Error; }
LONG RTEnumerateValueKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle, IN ULONG Index, OUT PULONG ValueType, IN OUT PULONG ValueNameLength, OUT PWSTR ValueName, IN OUT PULONG ValueDataLength, OUT PVOID ValueData ) { ULONG Error;
if (KeyHandle == HKEY_REGISTRY_ROOT) { return ERROR_NO_MORE_ITEMS; } else if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiValueName[ MAX_PATH ]; ULONG AnsiValueNameLength; LPSTR AnsiValueData; ULONG OriginalValueDataLength;
AnsiValueNameLength = sizeof( AnsiValueName ); OriginalValueDataLength = *ValueDataLength; Error = (_Win95RegEnumValue)( KeyHandle, Index, AnsiValueName, &AnsiValueNameLength, 0, ValueType, ValueData, ValueDataLength );
if (Error != NO_ERROR) { return Error; }
if (AnsiValueNameLength >= *ValueNameLength) { return ERROR_MORE_DATA; }
if (RegAnsiToUnicode( AnsiValueName, ValueName, AnsiValueNameLength ) == 0) { return GetLastError(); }
if (*ValueType == REG_SZ) { AnsiValueData = HeapAlloc( GetProcessHeap(), 0, *ValueDataLength ); if (AnsiValueData == NULL) { return ERROR_OUTOFMEMORY; }
RtlMoveMemory( AnsiValueData, ValueData, *ValueDataLength ); if (RegAnsiToUnicode( AnsiValueData, (PWSTR)ValueData, *ValueDataLength ) == 0) { Error = GetLastError(); } else { *ValueDataLength *= sizeof( WCHAR ); }
HeapFree( GetProcessHeap(), 0, AnsiValueData ); }
return Error; } else { Error = RegEnumValue( KeyHandle, Index, ValueName, ValueNameLength, NULL, ValueType, ValueData, ValueDataLength ); if (Error == NO_ERROR) { RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) ); }
return Error; } }
LONG RTQueryKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle, OUT PFILETIME LastWriteTime, OUT PULONG NumberOfSubkeys, OUT PULONG NumberOfValues ) { LONG Error;
if (KeyHandle == HKEY_REGISTRY_ROOT) { if (NumberOfSubkeys != NULL) { *NumberOfSubkeys = 2; }
if (NumberOfValues != NULL) { *NumberOfValues = 0; }
return NO_ERROR; } else if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { Error = (_Win95RegQueryInfoKey)( KeyHandle, NULL, NULL, NULL, NumberOfSubkeys, NULL, NULL, NumberOfValues, NULL, NULL, NULL, (PVOID)LastWriteTime ); } else { Error = RegQueryInfoKey( KeyHandle, // hKey,
NULL, // lpClass,
NULL, // lpcbClass,
NULL, // lpReserved,
NumberOfSubkeys, // lpcSubKeys,
NULL, // lpcbMaxSubKeyLen,
NULL, // lpcbMaxClassLen,
NumberOfValues, // lpcValues,
NULL, // lpcbMaxValueNameLen,
NULL, // lpcbMaxValueLen,
NULL, // lpcbSecurityDescriptor,
LastWriteTime // lpftLastWriteTime
); }
return Error; }
LONG RTQueryValueKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle, IN PWSTR ValueName, OUT PULONG ValueType, IN OUT PULONG ValueDataLength, OUT PVOID ValueData ) { LONG Error;
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiValueName[ MAX_PATH ], *p; ULONG OriginalValueDataLength;
if (ValueName != NULL) { if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) { return GetLastError(); }
p = AnsiValueName; } else { p = NULL; }
OriginalValueDataLength = *ValueDataLength; Error = (_Win95RegQueryValueEx)( KeyHandle, p, NULL, ValueType, ValueData, ValueDataLength ); if (Error == NO_ERROR && *ValueType == REG_SZ) { if ((*ValueDataLength * sizeof( WCHAR )) > OriginalValueDataLength) { return ERROR_MORE_DATA; }
p = HeapAlloc( GetProcessHeap(), 0, *ValueDataLength ); if (p == NULL) { return ERROR_OUTOFMEMORY; }
RtlMoveMemory( p, ValueData, *ValueDataLength ); if (RegAnsiToUnicode( (LPCSTR)p, (PWSTR)ValueData, *ValueDataLength ) == 0) { Error = GetLastError(); } else { *ValueDataLength *= sizeof( WCHAR ); *ValueDataLength += sizeof( UNICODE_NULL ); }
HeapFree( GetProcessHeap(), 0, p ); } } else { Error = RegQueryValueEx( KeyHandle, ValueName, NULL, ValueType, ValueData, ValueDataLength );
if (Error == NO_ERROR) { RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) ); } }
return Error; }
LONG RTSetValueKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle, IN PWSTR ValueName, IN ULONG ValueType, IN ULONG ValueDataLength, IN PVOID ValueData ) { LONG Error;
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiValueName[ MAX_PATH ], *p; ULONG OriginalValueDataLength; LPSTR AnsiValueData;
if (ValueName != NULL) { if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) { return GetLastError(); }
p = AnsiValueName; } else { p = NULL; }
if (ValueType == REG_SZ) { AnsiValueData = HeapAlloc( GetProcessHeap(), 0, ValueDataLength * 2 ); if (AnsiValueData == NULL) { return ERROR_OUTOFMEMORY; }
ValueDataLength = RegUnicodeToAnsi( ValueData, AnsiValueData, ValueDataLength ); if (ValueDataLength == 0) { return GetLastError(); }
ValueData = AnsiValueData; } else { AnsiValueData = NULL; }
Error = (_Win95RegSetValueEx)( KeyHandle, p, 0, ValueType, ValueData, ValueDataLength );
if (AnsiValueData != NULL) { HeapFree( GetProcessHeap(), 0, AnsiValueData ); }
if (p != NULL) { HeapFree( GetProcessHeap(), 0, p ); } } else { Error = RegSetValueEx( KeyHandle, ValueName, 0, ValueType, ValueData, ValueDataLength ); }
return Error; }
LONG RTDeleteKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle, IN PCWSTR SubKeyName ) { if (!RegValidateKeyPath( RegistryContext, &KeyHandle, &SubKeyName )) { return GetLastError(); }
if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiSubKeyName[ MAX_PATH ], *p;
if (SubKeyName != NULL) { if (!RegUnicodeToAnsi( SubKeyName, AnsiSubKeyName, 0 )) { return GetLastError(); }
p = AnsiSubKeyName; } else { p = NULL; }
return (_Win95RegDeleteKey)( KeyHandle, p ); } else { return RegDeleteKey( KeyHandle, SubKeyName ); } }
LONG RTDeleteValueKey( IN PREG_CONTEXT RegistryContext, IN HKEY KeyHandle, IN PWSTR ValueName ) { if (RegistryContext->Target == REG_TARGET_WIN95_REGISTRY) { UCHAR AnsiValueName[ MAX_PATH ], *p; ULONG OriginalValueDataLength; LPSTR AnsiValueData;
if (ValueName != NULL) { if (!RegUnicodeToAnsi( ValueName, AnsiValueName, 0 )) { return GetLastError(); }
p = AnsiValueName; } else { p = NULL; }
return (_Win95RegDeleteValue)( KeyHandle, p ); } else { return RegDeleteValue( KeyHandle, ValueName ); } }
LONG RTLoadAsciiFileAsUnicode( IN PWSTR FileName, OUT PREG_UNICODE_FILE UnicodeFile ) { LONG Error = NO_ERROR; HANDLE File; DWORD FileSize; DWORD CharsInFile; DWORD BytesRead; DWORD BufferSize, i, i1, LineCount, DeferredLineCount; PVOID BufferBase; PWSTR Src, Src1, Dst;
File = CreateFile( FileName, FILE_GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (File == INVALID_HANDLE_VALUE) { return GetLastError(); }
FileSize = GetFileSize( File, NULL ); if (FileSize == INVALID_FILE_SIZE) { CloseHandle( File ); return GetLastError(); }
BufferSize = FileSize * sizeof( WCHAR ); BufferSize += sizeof( UNICODE_NULL ); BufferBase = NULL; BufferBase = VirtualAlloc( NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE ); if (BufferBase != NULL) { if (ReadFile( File, BufferBase, FileSize, &BytesRead, NULL )) { if (BytesRead != FileSize) { Error = ERROR_HANDLE_EOF; } else if (!GetFileTime( File, NULL, NULL, &UnicodeFile->LastWriteTime )) { Error = GetLastError(); } else { Error = NO_ERROR; } }
if (Error != NO_ERROR) { VirtualFree( BufferBase, 0, MEM_RELEASE ); } } else { Error = GetLastError(); }
CloseHandle( File ); if (Error != NO_ERROR) { return Error; }
Src = (PWSTR)BufferBase;
if (!IsTextUnicode( BufferBase, FileSize, NULL )) { RtlMoveMemory( (PCHAR)BufferBase + FileSize, BufferBase, FileSize ); CharsInFile = RegAnsiToUnicode( (PCHAR)BufferBase + FileSize, BufferBase, FileSize ); if (CharsInFile == 0) { return GetLastError(); } } else { CharsInFile = FileSize / sizeof( WCHAR );
//
// Skip ByteOrderMark
//
if (Src[0] == 0xfeff || Src[0] == 0xfffe) { Src++; CharsInFile--; } }
DeferredLineCount = 0; Dst = (PWSTR)BufferBase;
i = 0;
//
// Now loop over the in memory copy of the file, collapsing all carriage
// return line feed pairs into just new lines, and removing all line
// continuation characters and the spaces that surround them. This lets
// RTParseNextLine see a single line for each Key Name or Value input,
// terminated by a new line character.
//
while (i < CharsInFile) { //
// See if we just went over a line continuation character
//
if (i > 0 && Src[-1] == L'\\' && (*Src == L'\r' || *Src == L'\n')) { //
// Move back over the line continuation we just copied the previous iteration
//
if (Dst[-1] == L'\\') { --Dst; }
//
// Move back over all but one of any space characters that preceed
// the line continuation character. The may be none, in which case
// we leave it be, as the user must want no space
//
while (Dst > (PWSTR)BufferBase) { if (Dst[-1] > L' ') { break; } Dst -= 1; }
//
// Leave one space, if there is one
//
if (Dst[0] == L' ') { Dst += 1; }
//
// Now, skip over the new line after the line continuation. We
// actually will skip over any number of them, keeping count so
// we can update the source file line number correctly.
//
LineCount = 0; while (i < CharsInFile) { if (*Src == L'\n') { i++; Src++; LineCount++; } else if (*Src == L'\r' && (i+1) < CharsInFile && Src[ 1 ] == L'\n' ) { i += 2; Src += 2; LineCount++; } else { break; } }
//
// If we saw more than just new line after the line continuation
// character, then put them back into the destination as just
// new lines, without any carriage returns.
//
if (LineCount > 1) { DeferredLineCount += LineCount; while (DeferredLineCount) { DeferredLineCount -= 1; *Dst++ = L'\n'; } } else { DeferredLineCount += 1;
//
// Skip leading spaces of next line of continuation
while (i < CharsInFile && (*Src == L' ' || *Src == L'\t')) { i++; Src++; } }
//
// All done if we hit the end of the file
//
if (i >= CharsInFile) { break; } } else if ((*Src == '\r' && Src[1] == '\n') || *Src == '\n') { while (TRUE) { while (i < CharsInFile && (*Src == '\r' || *Src == '\n')) { i++; Src++; } Src1 = Src; i1 = i; while (i1 < CharsInFile && (*Src1 == ' ' || *Src1 == '\t')) { i1++; Src1++; } if (i1 < CharsInFile && (*Src1 == '\r' && Src1[1] == '\n') || *Src1 == '\n' ) { Src = Src1; i = i1; } else { break; } }
while (DeferredLineCount) { DeferredLineCount -= 1; *Dst++ = L'\n'; } *Dst++ = L'\n'; } else { i++; *Dst++ = *Src++; } }
//
// Make sure line ends with a CRLF sequence.
//
while (DeferredLineCount) { DeferredLineCount -= 1; *Dst++ = L'\n'; } *Dst++ = L'\n'; *Dst = UNICODE_NULL; UnicodeFile->FileName = FileName; UnicodeFile->FileContents = BufferBase; UnicodeFile->EndOfFile = Dst; UnicodeFile->NextLine = BufferBase; UnicodeFile->NextLineNumber = 1;
return NO_ERROR; }
void RTUnloadUnicodeFile( IN OUT PREG_UNICODE_FILE UnicodeFile ) { VirtualFree( UnicodeFile->FileContents, 0, MEM_RELEASE ); return; }
#define ACL_LIST_START L'['
#define ACL_LIST_END L']'
BOOLEAN RegGetMultiString( IN BOOLEAN BackwardsCompatibleInput, IN OUT PWSTR *ValueString, IN OUT PWSTR *ValueData, IN ULONG MaximumValueLength, IN OUT PULONG ValueLength );
BOOLEAN RegReadMultiSzFile( IN OUT PREG_UNICODE_PARSE ParsedLine, IN BOOLEAN BackwardsCompatibleInput, IN PWSTR FileName, IN OUT PVOID ValueData, IN OUT PULONG ValueLength );
BOOLEAN RegReadBinaryFile( IN OUT PREG_UNICODE_PARSE ParsedLine, IN PWSTR FileName, IN OUT PVOID ValueData, IN OUT PULONG ValueLength );
BOOLEAN RTParseNextLine( IN OUT PREG_UNICODE_FILE UnicodeFile, OUT PREG_UNICODE_PARSE ParsedLine ) { PWSTR BeginLine, EqualSign, AclBracket, AclStart, s, s1; WCHAR QuoteChar;
if (ParsedLine->IsKeyName && ParsedLine->SecurityDescriptor) { RegDestroySecurity( ParsedLine->SecurityDescriptor ); }
RtlZeroMemory( ParsedLine, sizeof( *ParsedLine ) ); while (TRUE) { if (!(s = UnicodeFile->NextLine)) { ParsedLine->AtEndOfFile = TRUE; return FALSE; } UnicodeFile->NextLine = NULL; if (*s == UNICODE_NULL) { ParsedLine->AtEndOfFile = TRUE; return FALSE; }
while (*s <= L' ') { if (*s == L' ') { ParsedLine->IndentAmount += 1; } else if (*s == L'\t') { ParsedLine->IndentAmount = ((ParsedLine->IndentAmount + 8) - (ParsedLine->IndentAmount % 8) ); }
if (++s >= UnicodeFile->EndOfFile) { ParsedLine->AtEndOfFile = TRUE; return FALSE; } }
BeginLine = s; EqualSign = NULL; AclBracket = NULL; if (!UnicodeFile->BackwardsCompatibleInput && *s == L';') { while (s < UnicodeFile->EndOfFile) { if (*s == L'\n') { do { UnicodeFile->NextLineNumber += 1; *s++ = UNICODE_NULL; } while (*s == L'\n'); break; } else { s += 1; } }
BeginLine = s; UnicodeFile->NextLine = s; } else if (*s != '\n') {
//
// If not being backward compatible, see if the first thing on
// the line is the beginning of a quoted string.
//
if (!UnicodeFile->BackwardsCompatibleInput && (*s == L'"' || *s == L'\'')) { //
// Yes, it is either a quoted key name or value name. Find the
// the trailing quote. Specifically do NOT support quotes inside
// a quoted string, other than a different kind. Which means unless
// you want both types of quoted characters within the same name
// you wont care.
//
QuoteChar = *s++; BeginLine += 1; while (s < UnicodeFile->EndOfFile && *s != QuoteChar) { s += 1; }
//
// If trailing quote not found, then return an error
//
if (*s != QuoteChar) { ParsedLine->ParseFailureReason = ParseFailInvalidQuoteCharacter; return FALSE; }
//
// Mark the end of the name and move past the trailing quote
//
*s++ = UNICODE_NULL; }
//
// Now scan forward looking for one of the following:
//
// equal sign - this would mean the stuff to the left
// of the equal sign is a value name and the stuff
// to the right is the value type and data.
//
// left square bracket - this would mean the stuff to the
// left of the square bracket is a key name and the
// stuff to the right is the security descriptor information
//
// end of line - this would mean the stuff to the left
// is a key name, with no security descriptor.
//
while (s < UnicodeFile->EndOfFile) { if (*s == L'=') { //
// We found an equal sign, so value name is to the left
// and value type and data follows.
//
EqualSign = s;
//
// Ignore any left square bracket we might have seen
// in before this. It must have been part of the value
// name.
AclBracket = NULL;
//
// All done scanning
//
break; } else if (*s == ACL_LIST_START) { //
// We found a left square bracket. Keep scanning
// in case there is an equal sign later.
//
AclBracket = s; s += 1; } else if (*s == L'\n') { //
// We found end of line, so key name is to the left.
// Update where to start next time we are called.
//
UnicodeFile->NextLine = s + 1; break; } else if (*s == L'\t') { //
// Convert imbedded hard tabs to single spaces
//
*s++ = L' '; } else { //
// Nothing interesting, keep looking.
//
s += 1; } }
//
// Trim any trailing spaces off the end of what is to the
// left of where we are. The make sure we stop looking
// if we see the null character put down over the trailing
// quote character above, if any.
//
*s = UNICODE_NULL; while (s > BeginLine && *--s <= L' ' && *s) { *s = UNICODE_NULL; }
//
// BeginLine now points to either the null terminated value
// name or key name. EqualSign, if non-null, points to the
// equal sign, so scan forward and find the terminating new line,
// and store a null there to terminate the input. Otherwise,
// we already stored a null over the terminating new line above.
//
if (EqualSign != NULL) { s = EqualSign + 1; while (s < UnicodeFile->EndOfFile) { if (*s == '\n') { *s = UNICODE_NULL; break; }
s += 1; }
//
// Update where we should start next time we are called.
//
UnicodeFile->NextLine = s + 1; } else if (AclBracket != NULL) { //
// Since we did not stop on the AclBracket, go back an
// clobber it and any spaces before it.
//
s = AclBracket; *s = UNICODE_NULL; while (s > BeginLine && *--s <= L' ' && *s) { *s = UNICODE_NULL; } }
//
// Tell them which line number and where the line begins
//
ParsedLine->LineNumber = UnicodeFile->NextLineNumber; UnicodeFile->NextLineNumber += 1; ParsedLine->BeginLine = BeginLine;
//
// Now handle value or key semantics
//
if (EqualSign != NULL) { //
// We have ValueName = ValueType ValueData
//
//
// Value name is the beginning of the line, unless
// it was the special symbol or null
//
if (*BeginLine != L'@' && BeginLine != EqualSign) { ParsedLine->ValueName = BeginLine; }
//
// Skip any blanks after the equal sign.
//
while (*++EqualSign && *EqualSign <= L' ') { }
//
// If all that is left is the DELETE keyword, then
// tell the caller
//
if (!_wcsicmp( L"DELETE", EqualSign )) { ParsedLine->DeleteValue = TRUE; return TRUE; } else { //
// Otherwise parse the data after the equal sign.
//
ParsedLine->ValueString = EqualSign; return RTParseValueData( UnicodeFile, ParsedLine, ValueBuffer, ValueBufferSize, &ParsedLine->ValueType, &ParsedLine->ValueData, &ParsedLine->ValueLength ); } } else { //
// We have a key name. Tell the caller and handle any
// security descriptor info if present.
//
ParsedLine->IsKeyName = TRUE; ParsedLine->KeyName = BeginLine; if (AclBracket != NULL) { //
// We have found an ACL name
//
AclStart = ++AclBracket; ParsedLine->AclString = AclStart; while (*AclBracket != UNICODE_NULL && *AclBracket != ACL_LIST_END) { AclBracket += 1; } if (*AclBracket != ACL_LIST_END) { return FALSE; }
*AclBracket = UNICODE_NULL; if (!_wcsicmp( L"DELETE", AclStart )) { ParsedLine->DeleteKey = TRUE; } else { ParsedLine->SecurityDescriptor = &ParsedLine->SecurityDescriptorBuffer; if (!RegCreateSecurity( AclStart, ParsedLine->SecurityDescriptor )) { ParsedLine->SecurityDescriptor = NULL; return FALSE; } } }
return TRUE; } } else { UnicodeFile->NextLineNumber += 1; } }
return FALSE; }
BOOLEAN RTParseValueData( IN OUT PREG_UNICODE_FILE UnicodeFile, IN OUT PREG_UNICODE_PARSE ParsedLine, IN PVOID ValueBuffer, IN ULONG ValueBufferSize, OUT PULONG ValueType, OUT PVOID *ValueData, OUT PULONG ValueLength ) { PWSTR ValueString; ULONG PrefixLength, MaximumValueLength; PULONG p; PWSTR s, Src, Dst; ULONG i, n, cchValue; BOOLEAN BackwardsCompatibleInput = FALSE; BOOLEAN GetDataFromBinaryFile = FALSE; BOOLEAN GetDataFromMultiSzFile = FALSE; BOOLEAN ParseDateTime = FALSE;
if (UnicodeFile != NULL) { BackwardsCompatibleInput = UnicodeFile->BackwardsCompatibleInput; } ValueString = ParsedLine->ValueString; *ValueData = NULL; *ValueLength = 0; *ValueType = REG_SZ; for (i=0; RegTypeNameTable[i].TypeName != NULL; i++) { PrefixLength = wcslen( RegTypeNameTable[i].TypeName ); if (ValueString[ PrefixLength ] <= L' ' && !_wcsnicmp( RegTypeNameTable[i].TypeName, ValueString, PrefixLength ) ) { *ValueType = RegTypeNameTable[i].ValueType; GetDataFromBinaryFile = RegTypeNameTable[i].GetDataFromBinaryFile; GetDataFromMultiSzFile = RegTypeNameTable[i].GetDataFromMultiSzFile; ParseDateTime = RegTypeNameTable[i].ParseDateTime; break; } }
if (RegTypeNameTable[i].TypeName != NULL) { ValueString += PrefixLength; while (*ValueString != UNICODE_NULL && *ValueString <= L' ') { ValueString += 1; } }
if (GetDataFromMultiSzFile) { *ValueData = ValueBuffer; *ValueLength = ValueBufferSize; return RegReadMultiSzFile( ParsedLine, BackwardsCompatibleInput, ValueString, ValueBuffer, ValueLength ); }
if (GetDataFromBinaryFile) { *ValueData = ValueBuffer; *ValueLength = ValueBufferSize; return RegReadBinaryFile( ParsedLine, ValueString, ValueBuffer, ValueLength ); }
cchValue = wcslen( ValueString ); Src = ValueString; switch( *ValueType ) { case REG_SZ: case REG_EXPAND_SZ: //
// Strip off any surrounding quote characters
//
if (cchValue > 1 && Src[ 0 ] == Src[ cchValue - 1 ] && (Src[ 0 ] == L'"' || Src[ 0 ] == L'\'') ) { Src += 1; cchValue -= 2; }
//
// Fall through after stripping any quotes.
//
case REG_LINK: *ValueLength = (cchValue + 1) * sizeof( WCHAR ); if (*ValueLength > ValueBufferSize) { SetLastError( ERROR_BUFFER_OVERFLOW ); ParsedLine->ParseFailureReason = ParseFailValueTooLarge; return FALSE; } *ValueData = ValueBuffer; RtlMoveMemory( *ValueData, Src, *ValueLength ); *((PWSTR)*ValueData + cchValue) = UNICODE_NULL; return TRUE;
case REG_DWORD: *ValueData = ValueBuffer; *ValueLength = sizeof( ULONG ); for (i=0; RegValueNameTable[i].ValueName != NULL; i++) { PrefixLength = wcslen( RegValueNameTable[i].ValueName ); if (!_wcsnicmp( RegValueNameTable[i].ValueName, ValueString, PrefixLength ) ) { *(PULONG)*ValueData = RegValueNameTable[i].Value; return TRUE; } } return RegUnicodeToDWORD( &Src, 0, (PULONG)*ValueData );
case REG_BINARY: if (ParseDateTime) { #define NUMBER_DATE_TIME_FIELDS 6
ULONG FieldIndexes[ NUMBER_DATE_TIME_FIELDS ] = {1, 2, 0, 3, 4, 7}; //
// Month/Day/Year HH:MM DayOfWeek
//
ULONG CurrentField = 0; PCSHORT Fields; TIME_FIELDS DateTimeFields; PWSTR Field; ULONG FieldValue;
RtlZeroMemory( &DateTimeFields, sizeof( DateTimeFields ) ); Fields = &DateTimeFields.Year; while (cchValue) { if (CurrentField >= 7) { return( FALSE ); }
while (cchValue && *Src == L' ') { cchValue--; Src += 1; }
Field = Src; while (cchValue) { if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) { } else if (*Src < L'0' || *Src > L'9') { break; }
cchValue--; Src += 1; }
if (cchValue) { cchValue--; Src += 1; }
if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) { if (cchValue < 3) { SetLastError( ERROR_INVALID_PARAMETER ); ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid; return FALSE; }
if (DateTimeFields.Year != 0) { SetLastError( ERROR_INVALID_PARAMETER ); ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid; return FALSE; }
if (!_wcsnicmp( Field, L"SUN", 3 )) { FieldValue = 0; } else if (!_wcsnicmp( Field, L"MON", 3 )) { FieldValue = 1; } else if (!_wcsnicmp( Field, L"TUE", 3 )) { FieldValue = 2; } else if (!_wcsnicmp( Field, L"WED", 3 )) { FieldValue = 3; } else if (!_wcsnicmp( Field, L"THU", 3 )) { FieldValue = 4; } else if (!_wcsnicmp( Field, L"FRI", 3 )) { FieldValue = 5; } else if (!_wcsnicmp( Field, L"SAT", 3 )) { FieldValue = 6; } else { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } } else if (!RegUnicodeToDWORD( &Field, 0, &FieldValue )) { ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid; return FALSE; }
Fields[ FieldIndexes[ CurrentField++ ] ] = (CSHORT)FieldValue; }
if (DateTimeFields.Year == 0) { if (DateTimeFields.Day > 5) { SetLastError( ERROR_INVALID_PARAMETER ); ParsedLine->ParseFailureReason = ParseFailDateTimeFormatInvalid; return FALSE; } } else if (DateTimeFields.Year < 100) { DateTimeFields.Year += 1900; }
*ValueLength = sizeof( DateTimeFields ); if (*ValueLength > ValueBufferSize) { SetLastError( ERROR_BUFFER_OVERFLOW ); ParsedLine->ParseFailureReason = ParseFailValueTooLarge; return FALSE; } *ValueData = ValueBuffer; RtlMoveMemory( *ValueData, &DateTimeFields, sizeof( DateTimeFields ) ); return TRUE; }
case REG_RESOURCE_LIST: case REG_RESOURCE_REQUIREMENTS_LIST: case REG_FULL_RESOURCE_DESCRIPTOR: case REG_NONE: if (!RegUnicodeToDWORD( &Src, 0, ValueLength )) { ParsedLine->ParseFailureReason = ParseFailBinaryDataLengthMissing; return FALSE; }
if (*ValueLength >= ValueBufferSize) { SetLastError( ERROR_BUFFER_OVERFLOW ); ParsedLine->ParseFailureReason = ParseFailValueTooLarge; return FALSE; }
//
// Calculate number of DWORD's of data based on specified byte count
//
n = (*ValueLength + sizeof( ULONG ) - 1) / sizeof( ULONG );
//
// Store converted binary data in ValueBuffer
//
*ValueData = ValueBuffer; p = ValueBuffer;
//
// Src points to remaining text to convert.
//
while (n--) { if (!RegUnicodeToDWORD( &Src, 0, p )) { if (BackwardsCompatibleInput) { Src = UnicodeFile->NextLine; s = Src; while (TRUE) { if (*s == '\n') { *s = UNICODE_NULL; UnicodeFile->NextLineNumber += 1; break; } else if (s >= UnicodeFile->EndOfFile || *s == UNICODE_NULL) { UnicodeFile->NextLine = NULL; ParsedLine->ParseFailureReason = ParseFailBinaryDataNotEnough; SetLastError( ERROR_MORE_DATA ); return FALSE; } else { break; } }
UnicodeFile->NextLine = s + 1; n += 1; } else { if (p == ValueBuffer) { ParsedLine->ParseFailureReason = ParseFailBinaryDataOmitted; SetLastError( ERROR_NO_DATA ); } else { ParsedLine->ParseFailureReason = ParseFailBinaryDataNotEnough; SetLastError( ERROR_MORE_DATA ); }
return FALSE; } } else { p += 1; } } return TRUE;
case REG_MULTI_SZ: *ValueLength = 0; *ValueData = ValueBuffer; MaximumValueLength = ValueBufferSize; Dst = *ValueData; while (RegGetMultiString( BackwardsCompatibleInput, &Src, &Dst, MaximumValueLength, ValueLength ) ) { }
if (GetLastError() == NO_ERROR) { return TRUE; } else { ParsedLine->ParseFailureReason = ParseFailValueTooLarge; return FALSE; } break;
default: SetLastError( ERROR_INVALID_PARAMETER ); ParsedLine->ParseFailureReason = ParseFailInvalidRegistryType; return FALSE; }
}
BOOLEAN RegGetMultiString( IN BOOLEAN BackwardsCompatibleInput, IN OUT PWSTR *ValueString, IN OUT PWSTR *ValueData, IN ULONG MaximumValueLength, IN OUT PULONG ValueLength )
/*++
Routine Description:
This routine parses multi-strings of the form
"foo" "bar" "bletch"
Each time it is called, it strips the first string in quotes from the input string, and returns it as the multi-string.
INPUT ValueString: "foo" "bar" "bletch"
OUTPUT ValueString: "bar" "bletch" ValueData: foo
Arguments:
BackwardsCompatibleInput - TRUE if supporting old format input
ValueString - Supplies the string from which the multi-string will be parsed - Returns the remaining string after the multi-string is removed
ValueData - Supplies the location where the removed multi-string is to be stored. - Returns the location to the first byte after the returned multi-string
MaximumValueLength - Supplies the maximum length of data that can be stored in ValueData.
ValueLength - Supplies a pointer to the current length of data stored in ValueData. - Returns the size of the
Return Value:
TRUE if successful and FALSE if not.
--*/
{ PWSTR Src, Dst; ULONG n; BOOLEAN Result;
//
// Find the first quote mark.
//
Src = *ValueString; while (*Src != UNICODE_NULL && *Src != L'"') { Src += 1; }
Dst = *ValueData; if (*Src == UNICODE_NULL) { SetLastError( NO_ERROR ); Result = FALSE; } else { //
// We have found the start of the multi-string. Now find the end,
// building up our return ValueData as we go.
//
Src += 1; while (*Src != UNICODE_NULL) { if (*Src == L'"') { if (!BackwardsCompatibleInput && Src[1] == L'"' ) { Src += 1; } else { *Src++ = UNICODE_NULL; break; } }
*ValueLength += sizeof( WCHAR ); if (*ValueLength >= MaximumValueLength) { SetLastError( ERROR_BUFFER_OVERFLOW ); return FALSE; }
*Dst++ = *Src++; }
Result = TRUE; }
*ValueLength += sizeof( WCHAR ); if (*ValueLength >= MaximumValueLength) { SetLastError( ERROR_BUFFER_OVERFLOW ); return FALSE; }
*Dst++ = UNICODE_NULL; *ValueData = Dst; *ValueString = Src; return Result; }
BOOLEAN RegReadMultiSzFile( IN OUT PREG_UNICODE_PARSE ParsedLine, IN BOOLEAN BackwardsCompatibleInput, IN PWSTR FileName, IN OUT PVOID ValueData, IN OUT PULONG ValueLength ) { PWSTR Src, Dst; REG_UNICODE_FILE MultiSzFile; ULONG MaximumValueLength; BOOLEAN Result;
if (!RTLoadAsciiFileAsUnicode( FileName, &MultiSzFile )) { ParsedLine->ParseFailureReason = ParseFailUnableToAccessFile; return FALSE; }
MaximumValueLength = *ValueLength; *ValueLength = 0; Src = MultiSzFile.NextLine; Dst = ValueData; while (RegGetMultiString( BackwardsCompatibleInput, &Src, &Dst, MaximumValueLength, ValueLength ) ) { }
if (GetLastError() == NO_ERROR) { Result = TRUE; } else { ParsedLine->ParseFailureReason = ParseFailValueTooLarge; Result = FALSE; }
RTUnloadUnicodeFile( &MultiSzFile );
return Result; }
BOOLEAN RegReadBinaryFile( IN OUT PREG_UNICODE_PARSE ParsedLine, IN PWSTR FileName, IN OUT PVOID ValueData, IN OUT PULONG ValueLength ) { BOOLEAN Result; HANDLE File; DWORD FileSize, FileSizeHigh; DWORD BytesRead;
File = CreateFile( FileName, FILE_GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (File == INVALID_HANDLE_VALUE) { ParsedLine->ParseFailureReason = ParseFailUnableToAccessFile; return FALSE; }
ParsedLine->ParseFailureReason = ParseFailValueTooLarge; FileSize = GetFileSize( File, &FileSizeHigh ); if (FileSizeHigh != 0 || FileSize == INVALID_FILE_SIZE || FileSize >= *ValueLength ) { CloseHandle( File ); SetLastError( ERROR_BUFFER_OVERFLOW ); return FALSE; }
Result = FALSE; if (ReadFile( File, ValueData, FileSize, &BytesRead, NULL )) { if (BytesRead != FileSize) { SetLastError( ERROR_HANDLE_EOF ); } else { ParsedLine->ParseFailureReason = ParseFailNoFailure; *ValueLength = FileSize; Result = TRUE; } }
CloseHandle( File ); return Result; }
BOOLEAN NeedQuotedString( PWSTR Name, PWSTR Value, PWCHAR QuoteChar ) { ULONG i;
if (Name != NULL) { if (*Name != UNICODE_NULL && (*Name == L' ' || Name[ wcslen( Name ) - 1 ] == L' ') ) { *QuoteChar = '"'; return TRUE; } else { return FALSE; } } else { i = wcslen( Value ) - 1; if (*Value != UNICODE_NULL) { if ((*Value == L' ' || Value[ i ] == L' ' || Value[ i ] == L'\\')) { *QuoteChar = '"'; return TRUE; } else if (*Value == L'"' && Value[ i ] == L'"') { *QuoteChar = '\''; return TRUE; } else if (*Value == L'\'' && Value[ i ] == L'\'') { *QuoteChar = '"'; return TRUE; } }
return FALSE; } }
void RTFormatKeyName( PREG_OUTPUT_ROUTINE OutputRoutine, PVOID OutputRoutineParameter, ULONG IndentLevel, PWSTR KeyName ) { PWSTR pw; WCHAR QuoteChar;
if (NeedQuotedString( KeyName, NULL, &QuoteChar )) { (OutputRoutine)( OutputRoutineParameter, "%.*s%c%ws%c", IndentLevel, BlanksForPadding, QuoteChar, KeyName, QuoteChar ); } else { (OutputRoutine)( OutputRoutineParameter, "%.*s%ws", IndentLevel, BlanksForPadding, KeyName ); }
return; }
void RTFormatKeySecurity( PREG_OUTPUT_ROUTINE OutputRoutine, PVOID OutputRoutineParameter, HKEY KeyHandle, PSECURITY_DESCRIPTOR SecurityDescriptor ) { ULONG SecurityBufferLength; BOOLEAN FormattedAces; WCHAR AceList[ 256 ];
FormattedAces = FALSE; if (KeyHandle != NULL) { SecurityBufferLength = 0; if (RegGetKeySecurity( KeyHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor, &SecurityBufferLength ) == ERROR_INSUFFICIENT_BUFFER ) { SecurityDescriptor = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), 0, SecurityBufferLength );
if (SecurityDescriptor) { if (RegGetKeySecurity( KeyHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor, &SecurityBufferLength ) != NO_ERROR ) { HeapFree( GetProcessHeap(), 0, SecurityDescriptor ); } else { FormattedAces = RegFormatSecurity( SecurityDescriptor, AceList ); HeapFree( GetProcessHeap(), 0, SecurityDescriptor ); } } } } else if (SecurityDescriptor != NULL) { FormattedAces = RegFormatSecurity( SecurityDescriptor, AceList ); }
if (FormattedAces) { (OutputRoutine)( OutputRoutineParameter, " %wc%ws%wc", ACL_LIST_START, AceList, ACL_LIST_END ); }
return; }
void RegDisplayResourceListAsComment( ULONG OutputWidth, PREG_OUTPUT_ROUTINE OutputRoutine, PVOID OutputRoutineParameter, ULONG IndentLevel, ULONG ValueLength, ULONG ValueType, PWSTR ValueData );
void RTFormatKeyValue( ULONG OutputWidth, PREG_OUTPUT_ROUTINE OutputRoutine, PVOID OutputRoutineParameter, BOOLEAN SummaryOutput, ULONG IndentLevel, PWSTR ValueName, ULONG ValueLength, ULONG ValueType, PWSTR ValueData ) { PULONG p; PWSTR pw, pw1, pwBreak; WCHAR QuoteChar, BreakChar; ULONG i, j, k, m, cbPrefix, cb; PUCHAR pbyte; char eol[11];
cbPrefix = (OutputRoutine)( OutputRoutineParameter, "%.*s", IndentLevel, BlanksForPadding );
if (ValueName != NULL && *ValueName != UNICODE_NULL) { if (NeedQuotedString( ValueName, NULL, &QuoteChar )) { cbPrefix += (OutputRoutine)( OutputRoutineParameter, "%c%ws%c ", QuoteChar, ValueName, QuoteChar ); } else { cbPrefix += (OutputRoutine)( OutputRoutineParameter, "%ws ", ValueName ); } } cbPrefix += (OutputRoutine)( OutputRoutineParameter, "= " );
switch( ValueType ) { case REG_SZ: case REG_EXPAND_SZ:
if (ValueType == REG_EXPAND_SZ) { cbPrefix += (OutputRoutine)( OutputRoutineParameter, "REG_EXPAND_SZ " ); } pw = (PWSTR)ValueData; if (ValueLength & (sizeof(WCHAR)-1)) { (OutputRoutine)( OutputRoutineParameter, "(*** Length not multiple of WCHAR ***)" ); ValueLength = (ValueLength+sizeof(WCHAR)-1) & ~(sizeof(WCHAR)-1); }
if (ValueLength == 0 || *(PWSTR)((PCHAR)pw + ValueLength - sizeof( WCHAR )) != UNICODE_NULL ) { (OutputRoutine)( OutputRoutineParameter, "(*** MISSING TRAILING NULL CHARACTER ***)" ); *(PWSTR)((PCHAR)pw + ValueLength) = UNICODE_NULL; }
if (NeedQuotedString( NULL, pw, &QuoteChar )) { (OutputRoutine)( OutputRoutineParameter, "%c%ws%c", QuoteChar, pw, QuoteChar ); } else if ((cbPrefix + wcslen(pw)) <= OutputWidth) { (OutputRoutine)( OutputRoutineParameter, "%ws", pw ); } else { while (*pw) { pw1 = pw; pwBreak = NULL; while (*pw1 && *pw1 >= L' ') { if ((cbPrefix + (ULONG)(pw1 - pw)) > (OutputWidth-4)) { break; }
if (wcschr( L" ,;", *pw1 )) { pwBreak = pw1; }
pw1++; }
if (pwBreak != NULL) { while (*pwBreak == pwBreak[1]) { pwBreak += 1; } pw1 = pwBreak + 1; } else { while (*pw1) { pw1 += 1; } }
(OutputRoutine)( OutputRoutineParameter, "%.*ws", pw1 - pw, pw ); if (*pw1 == UNICODE_NULL) { break; } if (SummaryOutput) { (OutputRoutine)( OutputRoutineParameter, "\\..." ); break; }
(OutputRoutine)( OutputRoutineParameter, "\\\n%.*s", IndentLevel == 0 ? 4 : cbPrefix, BlanksForPadding ); pw = pw1; } }
(OutputRoutine)( OutputRoutineParameter, "\n" ); break;
case REG_RESOURCE_LIST: case REG_FULL_RESOURCE_DESCRIPTOR: case REG_RESOURCE_REQUIREMENTS_LIST: case REG_BINARY: case REG_NONE: switch( ValueType ) { case REG_NONE: pw = L"REG_NONE"; break; case REG_BINARY: pw = L"REG_BINARY"; break; case REG_RESOURCE_REQUIREMENTS_LIST: pw = L"REG_RESOURCE_REQUIREMENTS_LIST"; break; case REG_RESOURCE_LIST: pw = L"REG_RESOURCE_LIST"; break; case REG_FULL_RESOURCE_DESCRIPTOR: pw = L"REG_FULL_RESOURCE_DESCRIPTOR"; break; } cb = (OutputRoutine)( OutputRoutineParameter, "%ws 0x%08lx", pw, ValueLength );
if (ValueLength != 0) { p = (PULONG)ValueData; i = (ValueLength + 3) / sizeof( ULONG ); if (!SummaryOutput || i <= 2) { for (j=0; j<i; j++) { if ((cbPrefix + cb + 11) > (OutputWidth - 2)) { (OutputRoutine)( OutputRoutineParameter, " \\\n%.*s", IndentLevel == 0 ? 4 : cbPrefix, BlanksForPadding ); cb = 0; } else { cb += (OutputRoutine)( OutputRoutineParameter, " " ); }
cb += (OutputRoutine)( OutputRoutineParameter, "0x%08lx", *p++ ); } } else { (OutputRoutine)( OutputRoutineParameter, " \\..." ); } }
(OutputRoutine)( OutputRoutineParameter, "\n" );
if (!SummaryOutput) { RegDisplayResourceListAsComment( OutputWidth, OutputRoutine, OutputRoutineParameter, IndentLevel, ValueLength, ValueType, ValueData ); }
break;
// case REG_DWORD_LITTLE_ENDIAN:
case REG_DWORD: (OutputRoutine)( OutputRoutineParameter, "REG_DWORD 0x%08lx\n", *(PULONG)ValueData ); break;
case REG_DWORD_BIG_ENDIAN: (OutputRoutine)( OutputRoutineParameter, "REG_DWORD_BIG_ENDIAN 0x%08lx\n", *(PULONG)ValueData ); break;
case REG_LINK: (OutputRoutine)( OutputRoutineParameter, "REG_LINK %ws\n", (PWSTR)ValueData ); break;
case REG_MULTI_SZ: (!FullPathOutput) ? strcpy (eol, " \\\n%.*s") : strcpy (eol, " \\ ->%.*s"); cbPrefix += (OutputRoutine)( OutputRoutineParameter, "REG_MULTI_SZ " ); pw = (PWSTR)ValueData; i = 0; if (*pw) while (i < (ValueLength - 1) / sizeof( WCHAR )) { if (i > 0) { (OutputRoutine)( OutputRoutineParameter, eol, IndentLevel == 0 ? 4 : cbPrefix, BlanksForPadding ); } (OutputRoutine)( OutputRoutineParameter, "\""); do { if (pw[i] == '"') { (OutputRoutine)( OutputRoutineParameter, "%wc",pw[i]); } (OutputRoutine)( OutputRoutineParameter, "%wc",pw[i]); ++i; } while ( pw[i] != UNICODE_NULL ); (OutputRoutine)( OutputRoutineParameter, "\" ");
if (SummaryOutput) { (OutputRoutine)( OutputRoutineParameter, " \\..." ); break; }
++i; }
(OutputRoutine)( OutputRoutineParameter, "\n" ); break;
default: (OutputRoutine)( OutputRoutineParameter, "*** Unknown Registry Data Type (%08lx) Length: 0x%lx\n", ValueType, ValueLength ); break; }
return; }
void RegDisplayResourceListAsComment( ULONG OutputWidth, PREG_OUTPUT_ROUTINE OutputRoutine, PVOID OutputRoutineParameter, ULONG IndentLevel, ULONG ValueLength, ULONG ValueType, PWSTR ValueData ) { PCM_RESOURCE_LIST ResourceList = (PCM_RESOURCE_LIST)ValueData; PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor; ULONG i, j, k, l, count, cb; PWSTR TypeName; PWSTR FlagName; ULONG Size = ValueLength; PULONG p;
if (ValueType == REG_RESOURCE_LIST) { if (ValueLength < sizeof( *ResourceList )) { return; }
count = ResourceList->Count; FullDescriptor = &ResourceList->List[0]; (OutputRoutine)( OutputRoutineParameter, ";%.*sNumber of Full resource Descriptors = %d", IndentLevel - 1, BlanksForPadding, count ); } else if (ValueType == REG_FULL_RESOURCE_DESCRIPTOR) { if (ValueLength < sizeof( *FullDescriptor )) { return; }
count = 1; FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData; } else { return; }
for (i=0; i< count; i++) { (OutputRoutine)( OutputRoutineParameter, "\n;%.*sPartial List number %d\n", IndentLevel+4-1, BlanksForPadding, i );
switch(FullDescriptor->InterfaceType) { case InterfaceTypeUndefined: TypeName = L"Undefined";break; case Internal: TypeName = L"Internal"; break; case Isa: TypeName = L"Isa"; break; case Eisa: TypeName = L"Eisa"; break; case MicroChannel: TypeName = L"MicroChannel"; break; case TurboChannel: TypeName = L"TurboChannel"; break; case PCIBus: TypeName = L"PCI"; break; case VMEBus: TypeName = L"VME"; break; case NuBus: TypeName = L"NuBus"; break; case PCMCIABus: TypeName = L"PCMCIA"; break; case CBus: TypeName = L"CBUS"; break; case MPIBus: TypeName = L"MPI"; break; case MPSABus: TypeName = L"MPSA"; break; case ProcessorInternal: TypeName = L"ProcessorInternal";break; case InternalPowerBus: TypeName = L"InternalPower"; break; case PNPISABus: TypeName = L"PNP Isa"; break;
default: TypeName = L"***invalid bus type***"; break; }
(OutputRoutine)( OutputRoutineParameter, ";%.*sINTERFACE_TYPE %ws\n", IndentLevel+8-1, BlanksForPadding, TypeName );
(OutputRoutine)( OutputRoutineParameter, ";%.*sBUS_NUMBER %d\n", IndentLevel+8-1, BlanksForPadding, FullDescriptor->BusNumber );
//
// This is a basic test to see if the data format is right.
// We know at least some video resource list are bogus ...
//
if (Size < FullDescriptor->PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) ) {
(OutputRoutine)( OutputRoutineParameter, "\n;%.*s *** !!! Invalid ResourceList !!! *** \n", IndentLevel+8-1, BlanksForPadding, i );
break; }
Size -= FullDescriptor->PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
for (j=0; j<FullDescriptor->PartialResourceList.Count; j++) {
(OutputRoutine)( OutputRoutineParameter, ";%.*sDescriptor number %d\n", IndentLevel+12-1, BlanksForPadding, j );
PartialResourceDescriptor = &(FullDescriptor->PartialResourceList.PartialDescriptors[j]); switch(PartialResourceDescriptor->ShareDisposition) { case CmResourceShareUndetermined: TypeName = L"CmResourceShareUndetermined"; break; case CmResourceShareDeviceExclusive: TypeName = L"CmResourceDeviceExclusive"; break; case CmResourceShareDriverExclusive: TypeName = L"CmResourceDriverExclusive"; break; case CmResourceShareShared: TypeName = L"CmResourceShared"; break; default: TypeName = L"***invalid share disposition***"; break; }
(OutputRoutine)( OutputRoutineParameter, ";%.*sShare Disposition %ws\n", IndentLevel+12-1, BlanksForPadding, TypeName );
FlagName = L"***invalid Flags";
switch(PartialResourceDescriptor->Type) { case CmResourceTypeNull: TypeName = L"NULL"; FlagName = L"***Unused"; break; case CmResourceTypePort: TypeName = L"PORT"; if (PartialResourceDescriptor->Flags == CM_RESOURCE_PORT_MEMORY) { FlagName = L"CM_RESOURCE_PORT_MEMORY"; } if (PartialResourceDescriptor->Flags == CM_RESOURCE_PORT_IO) { FlagName = L"CM_RESOURCE_PORT_IO"; } break; case CmResourceTypeInterrupt: TypeName = L"INTERRUPT"; if (PartialResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) { FlagName = L"CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE"; } if (PartialResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED) { FlagName = L"CM_RESOURCE_INTERRUPT_LATCHED"; } break; case CmResourceTypeMemory: TypeName = L"MEMORY"; if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_READ_WRITE) { FlagName = L"CM_RESOURCE_MEMORY_READ_WRITE"; } if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_READ_ONLY) { FlagName = L"CM_RESOURCE_MEMORY_READ_ONLY"; } if (PartialResourceDescriptor->Flags == CM_RESOURCE_MEMORY_WRITE_ONLY) { FlagName = L"CM_RESOURCE_MEMORY_WRITE_ONLY"; } break; case CmResourceTypeDma: TypeName = L"DMA"; FlagName = L"***Unused"; break; case CmResourceTypeDeviceSpecific: TypeName = L"DEVICE SPECIFIC"; FlagName = L"***Unused"; break; default: TypeName = L"***invalid type***"; break; }
(OutputRoutine)( OutputRoutineParameter, ";%.*sTYPE %ws\n", IndentLevel+12-1, BlanksForPadding, TypeName );
(OutputRoutine)( OutputRoutineParameter, ";%.*sFlags %ws\n", IndentLevel+12-1, BlanksForPadding, FlagName );
switch(PartialResourceDescriptor->Type) { case CmResourceTypePort: (OutputRoutine)( OutputRoutineParameter, ";%.*sSTART 0x%08lx LENGTH 0x%08lx\n", IndentLevel+12-1, BlanksForPadding, PartialResourceDescriptor->u.Port.Start.LowPart, PartialResourceDescriptor->u.Port.Length ); break;
case CmResourceTypeInterrupt: (OutputRoutine)( OutputRoutineParameter, ";%.*sLEVEL %d VECTOR %d AFFINITY %d\n", IndentLevel+12-1, BlanksForPadding, PartialResourceDescriptor->u.Interrupt.Level, PartialResourceDescriptor->u.Interrupt.Vector, PartialResourceDescriptor->u.Interrupt.Affinity ); break;
case CmResourceTypeMemory: (OutputRoutine)( OutputRoutineParameter, ";%.*sSTART 0x%08lx%08lx LENGTH 0x%08lx\n", IndentLevel+12-1, BlanksForPadding, PartialResourceDescriptor->u.Memory.Start.HighPart, PartialResourceDescriptor->u.Memory.Start.LowPart, PartialResourceDescriptor->u.Memory.Length ); break;
case CmResourceTypeDma: (OutputRoutine)( OutputRoutineParameter, ";%.*sCHANNEL %d PORT %d\n", IndentLevel+12-1, BlanksForPadding, PartialResourceDescriptor->u.Dma.Channel, PartialResourceDescriptor->u.Dma.Port ); break;
case CmResourceTypeDeviceSpecific: cb = (OutputRoutine)( OutputRoutineParameter, ";%.*sDataSize 0x%08lx Data:", IndentLevel+12-1, BlanksForPadding, PartialResourceDescriptor->u.DeviceSpecificData.DataSize );
p = (PULONG)(PartialResourceDescriptor + 1); k = (PartialResourceDescriptor->u.DeviceSpecificData.DataSize + 3) / sizeof( ULONG ); for (l=0; l<k; l++) { if ((cb + 11) >= OutputWidth) { cb = (OutputRoutine)( OutputRoutineParameter, "\n;%.*s", IndentLevel+12-1, BlanksForPadding ) - 1; }
cb += (OutputRoutine)( OutputRoutineParameter, " 0x%08lx", *p++ ); }
(OutputRoutine)( OutputRoutineParameter, "\n" ); break;
default: (OutputRoutine)( OutputRoutineParameter, ";%.*s*** Unknown resource list type: 0x%x ****\n", IndentLevel+12-1, BlanksForPadding, PartialResourceDescriptor->Type ); break; }
(OutputRoutine)( OutputRoutineParameter, ";\n" ); }
FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) (PartialResourceDescriptor+1); }
return; }
|