1522 lines
49 KiB
C
1522 lines
49 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
regutil.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Utility routines for use by REGINI and REGDMP programs.
|
|||
|
Author:
|
|||
|
|
|||
|
Steve Wood (stevewo) 10-Mar-92
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "regutil.h"
|
|||
|
|
|||
|
#define RtlAllocateHeap(x,y,z) malloc(z)
|
|||
|
#define RtlFreeHeap(x,y,z) free(z)
|
|||
|
|
|||
|
UNICODE_STRING RiOnKeyword;
|
|||
|
UNICODE_STRING RiYesKeyword;
|
|||
|
UNICODE_STRING RiTrueKeyword;
|
|||
|
UNICODE_STRING RiOffKeyword;
|
|||
|
UNICODE_STRING RiNoKeyword;
|
|||
|
UNICODE_STRING RiFalseKeyword;
|
|||
|
UNICODE_STRING RiDeleteKeyword;
|
|||
|
UNICODE_STRING RiRegKeyword;
|
|||
|
UNICODE_STRING RiRegNoneKeyword;
|
|||
|
UNICODE_STRING RiRegSzKeyword;
|
|||
|
UNICODE_STRING RiRegExpandSzKeyword;
|
|||
|
UNICODE_STRING RiRegDwordKeyword;
|
|||
|
UNICODE_STRING RiRegBinaryKeyword;
|
|||
|
UNICODE_STRING RiRegBinaryFileKeyword;
|
|||
|
UNICODE_STRING RiRegLinkKeyword;
|
|||
|
UNICODE_STRING RiRegMultiSzKeyword;
|
|||
|
UNICODE_STRING RiRegMultiSzFileKeyword;
|
|||
|
UNICODE_STRING RiRegDateKeyword;
|
|||
|
|
|||
|
void
|
|||
|
RegInitialize( void )
|
|||
|
{
|
|||
|
RtlInitUnicodeString( &RiOnKeyword, L"ON" );
|
|||
|
RtlInitUnicodeString( &RiYesKeyword, L"YES" );
|
|||
|
RtlInitUnicodeString( &RiTrueKeyword, L"TRUE" );
|
|||
|
RtlInitUnicodeString( &RiOffKeyword, L"OFF" );
|
|||
|
RtlInitUnicodeString( &RiNoKeyword, L"NO" );
|
|||
|
RtlInitUnicodeString( &RiFalseKeyword, L"FALSE" );
|
|||
|
RtlInitUnicodeString( &RiDeleteKeyword, L"DELETE" );
|
|||
|
RtlInitUnicodeString( &RiRegKeyword, L"REG_" );
|
|||
|
RtlInitUnicodeString( &RiRegNoneKeyword, L"REG_NONE" );
|
|||
|
RtlInitUnicodeString( &RiRegSzKeyword, L"REG_SZ" );
|
|||
|
RtlInitUnicodeString( &RiRegExpandSzKeyword, L"REG_EXPAND_SZ" );
|
|||
|
RtlInitUnicodeString( &RiRegDwordKeyword, L"REG_DWORD" );
|
|||
|
RtlInitUnicodeString( &RiRegBinaryKeyword, L"REG_BINARY" );
|
|||
|
RtlInitUnicodeString( &RiRegBinaryFileKeyword, L"REG_BINARYFILE" );
|
|||
|
RtlInitUnicodeString( &RiRegLinkKeyword, L"REG_LINK" );
|
|||
|
RtlInitUnicodeString( &RiRegMultiSzKeyword, L"REG_MULTI_SZ" );
|
|||
|
RtlInitUnicodeString( &RiRegMultiSzFileKeyword, L"REG_MULTISZFILE" );
|
|||
|
RtlInitUnicodeString( &RiRegDateKeyword, L"REG_DATE" );
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RegReadMultiSzFile(
|
|||
|
IN PUNICODE_STRING FileName,
|
|||
|
OUT PVOID *ValueBuffer,
|
|||
|
OUT PULONG ValueLength
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING NtFileName;
|
|||
|
PWSTR s;
|
|||
|
UNICODE_STRING MultiSource;
|
|||
|
UNICODE_STRING MultiValue;
|
|||
|
REG_UNICODE_FILE MultiSzFile;
|
|||
|
ULONG MultiSzFileSize;
|
|||
|
|
|||
|
|
|||
|
FileName->Buffer[ FileName->Length/sizeof(WCHAR) ] = UNICODE_NULL;
|
|||
|
|
|||
|
RtlDosPathNameToNtPathName_U( FileName->Buffer,
|
|||
|
&NtFileName,
|
|||
|
NULL,
|
|||
|
NULL );
|
|||
|
|
|||
|
Status = RegLoadAsciiFileAsUnicode( &NtFileName, &MultiSzFile );
|
|||
|
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
MultiSzFileSize = (MultiSzFile.EndOfFile -
|
|||
|
MultiSzFile.NextLine) * sizeof(WCHAR);
|
|||
|
|
|||
|
*ValueLength = 0;
|
|||
|
*ValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0,
|
|||
|
MultiSzFileSize);
|
|||
|
|
|||
|
MultiSource.Buffer = MultiSzFile.NextLine;
|
|||
|
if (MultiSzFileSize <= MAXUSHORT) {
|
|||
|
MultiSource.Length =
|
|||
|
MultiSource.MaximumLength = (USHORT)MultiSzFileSize;
|
|||
|
} else {
|
|||
|
MultiSource.Length =
|
|||
|
MultiSource.MaximumLength = MAXUSHORT;
|
|||
|
}
|
|||
|
|
|||
|
while (RegGetMultiString(&MultiSource, &MultiValue)) {
|
|||
|
RtlMoveMemory( (PUCHAR)*ValueBuffer + *ValueLength,
|
|||
|
MultiValue.Buffer,
|
|||
|
MultiValue.Length );
|
|||
|
*ValueLength += MultiValue.Length;
|
|||
|
|
|||
|
s = MultiSource.Buffer;
|
|||
|
while ( *s != L'"' &&
|
|||
|
*s != L',' &&
|
|||
|
((s - MultiSource.Buffer) * sizeof(WCHAR)) <
|
|||
|
MultiSource.Length ) s++;
|
|||
|
if ( ((s - MultiSource.Buffer) * sizeof(WCHAR)) ==
|
|||
|
MultiSource.Length ||
|
|||
|
*s == L',' ||
|
|||
|
*s == L';' ) {
|
|||
|
|
|||
|
((PWSTR)*ValueBuffer)[ *ValueLength / sizeof(WCHAR) ] =
|
|||
|
UNICODE_NULL;
|
|||
|
*ValueLength += sizeof(UNICODE_NULL);
|
|||
|
if ( *s == L';' ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( (MultiSzFile.EndOfFile - MultiSource.Buffer) * sizeof(WCHAR) >=
|
|||
|
MAXUSHORT ) {
|
|||
|
MultiSource.Length =
|
|||
|
MultiSource.MaximumLength = MAXUSHORT;
|
|||
|
} else {
|
|||
|
MultiSource.Length =
|
|||
|
MultiSource.MaximumLength =
|
|||
|
(USHORT)((MultiSzFile.EndOfFile - MultiSource.Buffer) *
|
|||
|
sizeof(WCHAR));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
((PWSTR)*ValueBuffer)[ *ValueLength / sizeof(WCHAR) ] = UNICODE_NULL;
|
|||
|
*ValueLength += sizeof(UNICODE_NULL);
|
|||
|
|
|||
|
// Virtual memory for reading of MultiSzFile freed at process
|
|||
|
// death?
|
|||
|
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RegReadBinaryFile(
|
|||
|
IN PUNICODE_STRING FileName,
|
|||
|
OUT PVOID *ValueBuffer,
|
|||
|
OUT PULONG ValueLength
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING NtFileName;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
HANDLE File;
|
|||
|
FILE_STANDARD_INFORMATION FileInformation;
|
|||
|
WCHAR FileNameBuffer[ 256 ];
|
|||
|
PWSTR s;
|
|||
|
|
|||
|
FileName->Buffer[ FileName->Length/sizeof(WCHAR) ] = UNICODE_NULL;
|
|||
|
wcscpy( FileNameBuffer, L"\\DosDevices\\" );
|
|||
|
s = wcscat( FileNameBuffer, FileName->Buffer );
|
|||
|
while (*s != UNICODE_NULL) {
|
|||
|
if (*s == L'/') {
|
|||
|
*s = L'\\';
|
|||
|
}
|
|||
|
s++;
|
|||
|
}
|
|||
|
RtlInitUnicodeString( &NtFileName, FileNameBuffer );
|
|||
|
|
|||
|
InitializeObjectAttributes( &ObjectAttributes,
|
|||
|
&NtFileName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
(HANDLE)NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
Status = NtOpenFile( &File,
|
|||
|
SYNCHRONIZE | GENERIC_READ,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatus,
|
|||
|
FILE_SHARE_DELETE |
|
|||
|
FILE_SHARE_READ |
|
|||
|
FILE_SHARE_WRITE,
|
|||
|
FILE_SYNCHRONOUS_IO_NONALERT |
|
|||
|
FILE_NON_DIRECTORY_FILE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
Status = NtQueryInformationFile( File,
|
|||
|
&IoStatus,
|
|||
|
(PVOID)&FileInformation,
|
|||
|
sizeof( FileInformation ),
|
|||
|
FileStandardInformation
|
|||
|
);
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
if (FileInformation.EndOfFile.HighPart) {
|
|||
|
Status = STATUS_BUFFER_OVERFLOW;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
NtClose( File );
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
*ValueLength = FileInformation.EndOfFile.LowPart;
|
|||
|
*ValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *ValueLength );
|
|||
|
if (*ValueBuffer == NULL) {
|
|||
|
Status = STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
Status = NtReadFile( File,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&IoStatus,
|
|||
|
*ValueBuffer,
|
|||
|
*ValueLength,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
Status = IoStatus.Status;
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
if (IoStatus.Information != *ValueLength) {
|
|||
|
Status = STATUS_END_OF_FILE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
RtlFreeHeap( RtlProcessHeap(), 0, *ValueBuffer );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NtClose( File );
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RegLoadAsciiFileAsUnicode(
|
|||
|
IN PUNICODE_STRING FileName,
|
|||
|
OUT PREG_UNICODE_FILE UnicodeFile
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
HANDLE File;
|
|||
|
FILE_BASIC_INFORMATION FileDateTimeInfo;
|
|||
|
FILE_STANDARD_INFORMATION FileInformation;
|
|||
|
ULONG BufferSize, i, i1, LineCount;
|
|||
|
PVOID BufferBase;
|
|||
|
PCHAR Src, Src1;
|
|||
|
PWSTR Dst;
|
|||
|
|
|||
|
InitializeObjectAttributes( &ObjectAttributes,
|
|||
|
FileName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
(HANDLE)NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
Status = NtOpenFile( &File,
|
|||
|
SYNCHRONIZE | GENERIC_READ,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatus,
|
|||
|
FILE_SHARE_DELETE |
|
|||
|
FILE_SHARE_READ |
|
|||
|
FILE_SHARE_WRITE,
|
|||
|
FILE_SYNCHRONOUS_IO_NONALERT |
|
|||
|
FILE_NON_DIRECTORY_FILE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
Status = NtQueryInformationFile( File,
|
|||
|
&IoStatus,
|
|||
|
(PVOID)&FileInformation,
|
|||
|
sizeof( FileInformation ),
|
|||
|
FileStandardInformation
|
|||
|
);
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
if (FileInformation.EndOfFile.HighPart) {
|
|||
|
Status = STATUS_BUFFER_OVERFLOW;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
NtClose( File );
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BufferSize = FileInformation.EndOfFile.LowPart * sizeof( WCHAR );
|
|||
|
BufferSize += sizeof( UNICODE_NULL );
|
|||
|
BufferBase = NULL;
|
|||
|
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
|
|||
|
(PVOID *)&BufferBase,
|
|||
|
0,
|
|||
|
&BufferSize,
|
|||
|
MEM_COMMIT,
|
|||
|
PAGE_READWRITE
|
|||
|
);
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
Src = (PCHAR)BufferBase + ((FileInformation.EndOfFile.LowPart+1) & ~1);
|
|||
|
Dst = (PWSTR)BufferBase;
|
|||
|
Status = NtReadFile( File,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&IoStatus,
|
|||
|
Src,
|
|||
|
FileInformation.EndOfFile.LowPart,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
Status = IoStatus.Status;
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
if (IoStatus.Information != FileInformation.EndOfFile.LowPart) {
|
|||
|
Status = STATUS_END_OF_FILE;
|
|||
|
}
|
|||
|
else {
|
|||
|
Status = NtQueryInformationFile( File,
|
|||
|
&IoStatus,
|
|||
|
(PVOID)&FileDateTimeInfo,
|
|||
|
sizeof( FileDateTimeInfo ),
|
|||
|
FileBasicInformation
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
NtFreeVirtualMemory( NtCurrentProcess(),
|
|||
|
(PVOID *)&BufferBase,
|
|||
|
&BufferSize,
|
|||
|
MEM_RELEASE
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NtClose( File );
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
i = 0;
|
|||
|
while (i < FileInformation.EndOfFile.LowPart) {
|
|||
|
if (i > 1 && (Src[-2] == ' ' || Src[-2] == '\t') &&
|
|||
|
Src[-1] == '\\' && (*Src == '\r' || *Src == '\n')
|
|||
|
) {
|
|||
|
if (Dst[-1] == L'\\') {
|
|||
|
--Dst;
|
|||
|
}
|
|||
|
while (Dst > (PWSTR)BufferBase) {
|
|||
|
if (Dst[-1] > L' ') {
|
|||
|
break;
|
|||
|
}
|
|||
|
Dst--;
|
|||
|
}
|
|||
|
LineCount = 0;
|
|||
|
while (i < FileInformation.EndOfFile.LowPart) {
|
|||
|
if (*Src == '\n') {
|
|||
|
i++;
|
|||
|
Src++;
|
|||
|
LineCount++;
|
|||
|
}
|
|||
|
else
|
|||
|
if (*Src == '\r' &&
|
|||
|
(i+1) < FileInformation.EndOfFile.LowPart &&
|
|||
|
Src[ 1 ] == '\n'
|
|||
|
) {
|
|||
|
i += 2;
|
|||
|
Src += 2;
|
|||
|
LineCount++;
|
|||
|
}
|
|||
|
else {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (LineCount > 1) {
|
|||
|
*Dst++ = L'\n';
|
|||
|
}
|
|||
|
else {
|
|||
|
*Dst++ = L' ';
|
|||
|
while (i < FileInformation.EndOfFile.LowPart && (*Src == ' ' || *Src == '\t')) {
|
|||
|
i++;
|
|||
|
Src++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (i >= FileInformation.EndOfFile.LowPart) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
if ((*Src == '\r' && Src[1] == '\n') || *Src == '\n') {
|
|||
|
while (TRUE) {
|
|||
|
while (i < FileInformation.EndOfFile.LowPart && (*Src == '\r' || *Src == '\n')) {
|
|||
|
i++;
|
|||
|
Src++;
|
|||
|
}
|
|||
|
Src1 = Src;
|
|||
|
i1 = i;
|
|||
|
while (i1 < FileInformation.EndOfFile.LowPart && (*Src1 == ' ' || *Src1 == '\t')) {
|
|||
|
i1++;
|
|||
|
Src1++;
|
|||
|
}
|
|||
|
if (i1 < FileInformation.EndOfFile.LowPart &&
|
|||
|
(*Src1 == '\r' && Src1[1] == '\n') || *Src1 == '\n'
|
|||
|
) {
|
|||
|
Src = Src1;
|
|||
|
i = i1;
|
|||
|
}
|
|||
|
else {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*Dst++ = L'\n';
|
|||
|
}
|
|||
|
else {
|
|||
|
i++;
|
|||
|
*Dst++ = RtlAnsiCharToUnicodeChar( &Src );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
*Dst = UNICODE_NULL;
|
|||
|
UnicodeFile->FileContents = BufferBase;
|
|||
|
UnicodeFile->EndOfFile = Dst;
|
|||
|
UnicodeFile->BeginLine = NULL;
|
|||
|
UnicodeFile->EndOfLine = NULL;
|
|||
|
UnicodeFile->NextLine = BufferBase;
|
|||
|
UnicodeFile->LastWriteTime = FileDateTimeInfo.LastWriteTime;
|
|||
|
}
|
|||
|
else {
|
|||
|
NtFreeVirtualMemory( NtCurrentProcess(),
|
|||
|
(PVOID *)&BufferBase,
|
|||
|
&BufferSize,
|
|||
|
MEM_RELEASE
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
RegGetNextLine(
|
|||
|
IN OUT PREG_UNICODE_FILE UnicodeFile,
|
|||
|
OUT PULONG IndentAmount,
|
|||
|
OUT PWSTR *FirstEqual
|
|||
|
)
|
|||
|
{
|
|||
|
PWSTR s, s1;
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
if (!(s = UnicodeFile->NextLine)) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
*IndentAmount = 0;
|
|||
|
while (*s <= L' ') {
|
|||
|
if (*s == L' ') {
|
|||
|
*IndentAmount += 1;
|
|||
|
}
|
|||
|
else
|
|||
|
if (*s == L'\t') {
|
|||
|
*IndentAmount = ((*IndentAmount + 8) -
|
|||
|
(*IndentAmount % 8)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (++s >= UnicodeFile->EndOfFile) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
UnicodeFile->BeginLine = s;
|
|||
|
|
|||
|
*FirstEqual = NULL;
|
|||
|
UnicodeFile->NextLine = NULL;
|
|||
|
while (s < UnicodeFile->EndOfFile) {
|
|||
|
if (*s == L'=') {
|
|||
|
if (*FirstEqual == NULL) {
|
|||
|
*FirstEqual = s;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
if (*s == L'\n') {
|
|||
|
s1 = s;
|
|||
|
while (s > UnicodeFile->BeginLine && s[ -1 ] <= L' ') {
|
|||
|
s--;
|
|||
|
}
|
|||
|
UnicodeFile->EndOfLine = s;
|
|||
|
do {
|
|||
|
if (++s1 >= UnicodeFile->EndOfFile) {
|
|||
|
s1 = NULL;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
while (*s1 == L'\r' || *s1 == L'\n');
|
|||
|
|
|||
|
UnicodeFile->NextLine = s1;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (++s == UnicodeFile->EndOfFile) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (UnicodeFile->EndOfLine > UnicodeFile->BeginLine) {
|
|||
|
if (DebugOutput) {
|
|||
|
fprintf( stderr, "%02u %.*ws\n",
|
|||
|
*IndentAmount,
|
|||
|
UnicodeFile->EndOfLine - UnicodeFile->BeginLine,
|
|||
|
UnicodeFile->BeginLine
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RegDumpKeyValue(
|
|||
|
FILE *fh,
|
|||
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformation,
|
|||
|
ULONG IndentLevel
|
|||
|
)
|
|||
|
{
|
|||
|
PULONG p;
|
|||
|
PWSTR pw, pw1;
|
|||
|
ULONG i, j, k, m, cbPrefix;
|
|||
|
UNICODE_STRING ValueName;
|
|||
|
PUCHAR pbyte;
|
|||
|
|
|||
|
cbPrefix = fprintf( fh, "%.*s",
|
|||
|
IndentLevel,
|
|||
|
" "
|
|||
|
);
|
|||
|
ValueName.Buffer = (PWSTR)&(KeyValueInformation->Name[0]);
|
|||
|
ValueName.Length = (USHORT)KeyValueInformation->NameLength;
|
|||
|
ValueName.MaximumLength = (USHORT)KeyValueInformation->NameLength;
|
|||
|
|
|||
|
if (ValueName.Length) {
|
|||
|
cbPrefix += fprintf( fh, "%wZ ", &ValueName );
|
|||
|
}
|
|||
|
cbPrefix += fprintf( fh, "= " );
|
|||
|
|
|||
|
if (KeyValueInformation->DataLength == 0) {
|
|||
|
fprintf( fh, " [no data] \n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
switch( KeyValueInformation->Type ) {
|
|||
|
case REG_SZ:
|
|||
|
case REG_EXPAND_SZ:
|
|||
|
|
|||
|
if (KeyValueInformation->Type == REG_EXPAND_SZ) {
|
|||
|
cbPrefix += fprintf( fh, "REG_EXPAND_SZ " );
|
|||
|
}
|
|||
|
pw = (PWSTR)((PCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
|
|||
|
*(PWSTR)((PCHAR)pw + KeyValueInformation->DataLength) = UNICODE_NULL;
|
|||
|
i = 0;
|
|||
|
while (*pw) {
|
|||
|
if ((cbPrefix + wcslen(pw)) > 80) {
|
|||
|
pw1 = pw;
|
|||
|
while (*pw1 && *pw1 > L' ') {
|
|||
|
pw1++;
|
|||
|
}
|
|||
|
|
|||
|
if (*pw1) {
|
|||
|
*pw1++ = UNICODE_NULL;
|
|||
|
while (*pw1 && *pw1 <= L' ') {
|
|||
|
pw1++;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
pw1 = NULL;
|
|||
|
}
|
|||
|
if (i > 0) {
|
|||
|
fprintf( fh, " \\\n%.*s",
|
|||
|
cbPrefix,
|
|||
|
" "
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "%ws", pw );
|
|||
|
if (!pw1) {
|
|||
|
break;
|
|||
|
}
|
|||
|
i++;
|
|||
|
pw = pw1;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case REG_BINARY:
|
|||
|
fprintf( fh, "REG_BINARY 0x%08lx", KeyValueInformation->DataLength );
|
|||
|
p = (PULONG)((PCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
|
|||
|
i = (KeyValueInformation->DataLength + 3) / sizeof( ULONG );
|
|||
|
if (!SummaryOutput || i <= 8) {
|
|||
|
for (j=0; j<i; j++) {
|
|||
|
if ((j % 8) == 0) {
|
|||
|
fprintf( fh, "\n%.*s",
|
|||
|
IndentLevel+4,
|
|||
|
" "
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "0x%08lx ", *p++ );
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
fprintf( fh, " *** value display suppressed ***" );
|
|||
|
}
|
|||
|
fprintf( fh, "\n" );
|
|||
|
break;
|
|||
|
|
|||
|
// case REG_DWORD_LITTLE_ENDIAN:
|
|||
|
case REG_DWORD:
|
|||
|
fprintf( fh, "REG_DWORD 0x%08lx",
|
|||
|
*((PULONG)((PCHAR)KeyValueInformation + KeyValueInformation->DataOffset))
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case REG_DWORD_BIG_ENDIAN:
|
|||
|
fprintf( fh, "REG_DWORD_BIG_ENDIAN 0x%08lx",
|
|||
|
*((PULONG)((PCHAR)KeyValueInformation + KeyValueInformation->DataOffset))
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case REG_LINK:
|
|||
|
fprintf( fh, "REG_LINK %ws",
|
|||
|
((PWSTR)((PCHAR)KeyValueInformation + KeyValueInformation->DataOffset))
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case REG_MULTI_SZ:
|
|||
|
cbPrefix += fprintf( fh, "REG_MULTI_SZ " );
|
|||
|
pw = (PWSTR)((PCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
|
|||
|
i = 0;
|
|||
|
if (*pw)
|
|||
|
while (i < ((KeyValueInformation->DataLength-1) / sizeof(WCHAR))) {
|
|||
|
if (i > 0) {
|
|||
|
fprintf( fh, " \\\n%.*s",
|
|||
|
cbPrefix,
|
|||
|
" "
|
|||
|
);
|
|||
|
}
|
|||
|
fprintf(fh, "\"%ws\" ",pw+i);
|
|||
|
do {
|
|||
|
++i;
|
|||
|
} while ( pw[i] != UNICODE_NULL );
|
|||
|
++i;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case REG_RESOURCE_LIST:
|
|||
|
case REG_FULL_RESOURCE_DESCRIPTOR:
|
|||
|
{
|
|||
|
PCM_RESOURCE_LIST ResourceList = ((PCM_RESOURCE_LIST)((PCHAR)KeyValueInformation +
|
|||
|
KeyValueInformation->DataOffset));
|
|||
|
PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
|
|||
|
ULONG k, l, count;
|
|||
|
PWSTR TypeName;
|
|||
|
PWSTR FlagName;
|
|||
|
ULONG Size = KeyValueInformation->DataLength;
|
|||
|
|
|||
|
if (KeyValueInformation->Type == REG_RESOURCE_LIST) {
|
|||
|
|
|||
|
fprintf( fh, " REG_RESOURCE_LIST\n");
|
|||
|
|
|||
|
fprintf( fh, "%.*sNumber of Full resource Descriptors = %d",
|
|||
|
IndentLevel,
|
|||
|
" ",
|
|||
|
ResourceList->Count
|
|||
|
);
|
|||
|
|
|||
|
count = ResourceList->Count;
|
|||
|
FullDescriptor = &ResourceList->List[0];
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
fprintf( fh, " REG_FULL_RESOURCE_DESCRIPTOR\n");
|
|||
|
count = 1;
|
|||
|
FullDescriptor = ((PCM_FULL_RESOURCE_DESCRIPTOR)
|
|||
|
((PCHAR)KeyValueInformation + KeyValueInformation->DataOffset));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
for (i=0; i< count; i++) {
|
|||
|
|
|||
|
fprintf( fh, "\n%.*sPartial List number %d\n",
|
|||
|
IndentLevel+4,
|
|||
|
" ",
|
|||
|
i
|
|||
|
);
|
|||
|
|
|||
|
switch(FullDescriptor->InterfaceType) {
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
default:
|
|||
|
TypeName = L"***invalid bus type***";
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "%.*sINTERFACE_TYPE %ws\n",
|
|||
|
IndentLevel+8,
|
|||
|
" ",
|
|||
|
TypeName
|
|||
|
);
|
|||
|
|
|||
|
fprintf( fh, "%.*sBUS_NUMBER %d\n",
|
|||
|
IndentLevel+8,
|
|||
|
" ",
|
|||
|
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) ) {
|
|||
|
|
|||
|
fprintf( fh, "\n%.*s *** !!! Invalid ResourceList !!! *** \n",
|
|||
|
IndentLevel+8,
|
|||
|
" ",
|
|||
|
i
|
|||
|
);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Size -= FullDescriptor->PartialResourceList.Count *
|
|||
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
for (j=0; j<FullDescriptor->PartialResourceList.Count; j++) {
|
|||
|
|
|||
|
fprintf( fh, "%.*sDescriptor number %d\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "%.*sShare Disposition %ws\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "%.*sTYPE %ws\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
TypeName
|
|||
|
);
|
|||
|
|
|||
|
fprintf( fh, "%.*sFlags %ws\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
FlagName
|
|||
|
);
|
|||
|
|
|||
|
switch(PartialResourceDescriptor->Type) {
|
|||
|
|
|||
|
case CmResourceTypePort:
|
|||
|
fprintf( fh, "%.*sSTART 0x%08lx LENGTH 0x%08lx\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
PartialResourceDescriptor->u.Port.Start.LowPart,
|
|||
|
PartialResourceDescriptor->u.Port.Length
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
fprintf( fh, "%.*sLEVEL %d VECTOR %d AFFINITY %d\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
PartialResourceDescriptor->u.Interrupt.Level,
|
|||
|
PartialResourceDescriptor->u.Interrupt.Vector,
|
|||
|
PartialResourceDescriptor->u.Interrupt.Affinity
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
fprintf( fh, "%.*sSTART 0x%08lx%08lx LENGTH 0x%08lx\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
PartialResourceDescriptor->u.Memory.Start.HighPart,
|
|||
|
PartialResourceDescriptor->u.Memory.Start.LowPart,
|
|||
|
PartialResourceDescriptor->u.Memory.Length
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
fprintf( fh, "%.*sCHANNEL %d PORT %d\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
PartialResourceDescriptor->u.Dma.Channel,
|
|||
|
PartialResourceDescriptor->u.Dma.Port
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDeviceSpecific:
|
|||
|
fprintf( fh, "%.*sDataSize 0x%08lx\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
PartialResourceDescriptor->u.DeviceSpecificData.DataSize
|
|||
|
);
|
|||
|
|
|||
|
p = (PULONG)(PartialResourceDescriptor + 1);
|
|||
|
k = (PartialResourceDescriptor->u.DeviceSpecificData.DataSize + 3) / sizeof( ULONG );
|
|||
|
for (l=0; l<k; l++) {
|
|||
|
if ((l % 8) == 0) {
|
|||
|
fprintf( fh, "\n%.*s",
|
|||
|
IndentLevel+12,
|
|||
|
" "
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "0x%08lx ", *p++ );
|
|||
|
}
|
|||
|
fprintf( fh, "\n" );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
fprintf( fh, "%.*s*** Unknown resource list type: %c ****\n",
|
|||
|
IndentLevel+12,
|
|||
|
" ",
|
|||
|
PartialResourceDescriptor->Type
|
|||
|
);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "\n" );
|
|||
|
}
|
|||
|
|
|||
|
FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) (PartialResourceDescriptor+1);
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case REG_NONE:
|
|||
|
default:
|
|||
|
if (KeyValueInformation->Type == REG_NONE) {
|
|||
|
fprintf( fh, "REG_NONE\n");
|
|||
|
}
|
|||
|
else {
|
|||
|
fprintf( fh, "*** Unknown registry type (%08lx)",
|
|||
|
KeyValueInformation->Type
|
|||
|
);
|
|||
|
}
|
|||
|
fprintf( fh, "%.*s",
|
|||
|
IndentLevel,
|
|||
|
" "
|
|||
|
);
|
|||
|
fprintf( fh, " Length: 0x%lx\n", KeyValueInformation->DataLength );
|
|||
|
fprintf( fh, "\n%.*s",
|
|||
|
IndentLevel,
|
|||
|
" "
|
|||
|
);
|
|||
|
fprintf( fh, " Data: ");
|
|||
|
pbyte = ((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
|
|||
|
for ( k=0, m=1; k<KeyValueInformation->DataLength; k++,m++) {
|
|||
|
fprintf( fh, "%02x ", (*pbyte) );
|
|||
|
pbyte++;
|
|||
|
|
|||
|
if (m==8) {
|
|||
|
fprintf( fh, "\n%.*s",
|
|||
|
IndentLevel+12,
|
|||
|
" "
|
|||
|
);
|
|||
|
m=0;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
fprintf( fh, "\n" );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Define an upcase macro for temporary use by the upcase routines
|
|||
|
//
|
|||
|
|
|||
|
#define upcase(C) (WCHAR )(((C) >= 'a' && (C) <= 'z' ? (C) - ('a' - 'A') : (C)))
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
RegGetMultiString(
|
|||
|
IN OUT PUNICODE_STRING ValueString,
|
|||
|
OUT PUNICODE_STRING MultiString
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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"
|
|||
|
MultiString: foo
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ValueString - Supplies the string from which the multi-string will be
|
|||
|
parsed
|
|||
|
- Returns the remaining string after the multi-string is
|
|||
|
removed
|
|||
|
|
|||
|
MultiString - Returns the multi-string removed from ValueString
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - multi-string found and removed.
|
|||
|
|
|||
|
FALSE - no more multi-strings remaining.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Find the first quote mark.
|
|||
|
//
|
|||
|
while ((*(ValueString->Buffer) != L'"') &&
|
|||
|
(ValueString->Length > 0)) {
|
|||
|
++ValueString->Buffer;
|
|||
|
ValueString->Length -= sizeof(WCHAR);
|
|||
|
ValueString->MaximumLength -= sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
if (ValueString->Length == 0) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We have found the start of the multi-string. Now find the end,
|
|||
|
// building up our return MultiString as we go.
|
|||
|
//
|
|||
|
++ValueString->Buffer;
|
|||
|
ValueString->Length -= sizeof(WCHAR);
|
|||
|
ValueString->MaximumLength -= sizeof(WCHAR);
|
|||
|
MultiString->Buffer = ValueString->Buffer;
|
|||
|
MultiString->Length = 0;
|
|||
|
MultiString->MaximumLength = 0;
|
|||
|
while ((*(ValueString->Buffer) != L'"') &&
|
|||
|
(ValueString->Length > 0)) {
|
|||
|
++ValueString->Buffer;
|
|||
|
ValueString->Length -= sizeof(WCHAR);
|
|||
|
ValueString->MaximumLength -= sizeof(WCHAR);
|
|||
|
|
|||
|
MultiString->Length += sizeof(WCHAR);
|
|||
|
MultiString->MaximumLength += sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
if (ValueString->Length == 0) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
++ValueString->Buffer;
|
|||
|
ValueString->Length -= sizeof(WCHAR);
|
|||
|
ValueString->MaximumLength -= sizeof(WCHAR);
|
|||
|
|
|||
|
return( TRUE );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
RegGetKeyValue(
|
|||
|
IN PUNICODE_STRING InitialKeyValue,
|
|||
|
IN OUT PREG_UNICODE_FILE UnicodeFile,
|
|||
|
OUT PULONG ValueType,
|
|||
|
OUT PVOID *ValueBuffer,
|
|||
|
OUT PULONG ValueLength
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG PrefixLength;
|
|||
|
PWSTR s;
|
|||
|
PULONG p;
|
|||
|
ULONG n;
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG IndentAmount;
|
|||
|
PWSTR FirstEqual;
|
|||
|
UNICODE_STRING KeyValue;
|
|||
|
UNICODE_STRING MultiValue;
|
|||
|
BOOLEAN GetDataFromBinaryFile = FALSE;
|
|||
|
BOOLEAN GetDataFromMultiSzFile = FALSE;
|
|||
|
BOOLEAN ParseDateTime = FALSE;
|
|||
|
|
|||
|
KeyValue = *InitialKeyValue;
|
|||
|
if (RtlPrefixUnicodeString( &RiDeleteKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueBuffer = NULL;
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
else
|
|||
|
if (!RtlPrefixUnicodeString( &RiRegKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_SZ;
|
|||
|
PrefixLength = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegNoneKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_NONE;
|
|||
|
PrefixLength = RiRegNoneKeyword.Length;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegSzKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_SZ;
|
|||
|
PrefixLength = RiRegSzKeyword.Length;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegExpandSzKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_EXPAND_SZ;
|
|||
|
PrefixLength = RiRegExpandSzKeyword.Length;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegDwordKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_DWORD;
|
|||
|
PrefixLength = RiRegDwordKeyword.Length;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegBinaryFileKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_BINARY;
|
|||
|
PrefixLength = RiRegBinaryFileKeyword.Length;
|
|||
|
GetDataFromBinaryFile = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegBinaryKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_BINARY;
|
|||
|
PrefixLength = RiRegBinaryKeyword.Length;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegLinkKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_LINK;
|
|||
|
PrefixLength = RiRegLinkKeyword.Length;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegMultiSzFileKeyword, &KeyValue, TRUE)) {
|
|||
|
*ValueType = REG_MULTI_SZ;
|
|||
|
PrefixLength = RiRegMultiSzFileKeyword.Length;
|
|||
|
GetDataFromMultiSzFile = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegMultiSzKeyword, &KeyValue, TRUE)) {
|
|||
|
*ValueType = REG_MULTI_SZ;
|
|||
|
PrefixLength = RiRegMultiSzKeyword.Length;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiRegDateKeyword, &KeyValue, TRUE )) {
|
|||
|
*ValueType = REG_BINARY;
|
|||
|
ParseDateTime = TRUE;
|
|||
|
PrefixLength = RiRegDateKeyword.Length;
|
|||
|
}
|
|||
|
else {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
if (*ValueType != REG_NONE) {
|
|||
|
s = (PWSTR)
|
|||
|
((PCHAR)KeyValue.Buffer + PrefixLength);
|
|||
|
KeyValue.Length -= (USHORT)PrefixLength;
|
|||
|
while (KeyValue.Length != 0 && *s <= L' ') {
|
|||
|
s++;
|
|||
|
KeyValue.Length -= sizeof( WCHAR );
|
|||
|
}
|
|||
|
KeyValue.Buffer = s;
|
|||
|
}
|
|||
|
else {
|
|||
|
*ValueType = REG_SZ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (GetDataFromBinaryFile) {
|
|||
|
Status = RegReadBinaryFile( &KeyValue, ValueBuffer, ValueLength );
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
else {
|
|||
|
fprintf( stderr, "REGINI: Unable to read data from %wZ - Status == %lx\n", &KeyValue, Status );
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (GetDataFromMultiSzFile) {
|
|||
|
Status = RegReadMultiSzFile( &KeyValue, ValueBuffer, ValueLength );
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
else {
|
|||
|
fprintf( stderr, "REGINI: Unable to read data from %wZ - Status == %lx\n", &KeyValue, Status );
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
switch( *ValueType ) {
|
|||
|
case REG_SZ:
|
|||
|
case REG_EXPAND_SZ:
|
|||
|
case REG_LINK:
|
|||
|
*ValueLength = KeyValue.Length + sizeof( UNICODE_NULL );
|
|||
|
*ValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *ValueLength );
|
|||
|
if (*ValueBuffer == NULL) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory( *ValueBuffer, KeyValue.Buffer, KeyValue.Length );
|
|||
|
((PWSTR)*ValueBuffer)[ KeyValue.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
|
|||
|
return( TRUE );
|
|||
|
|
|||
|
case REG_DWORD:
|
|||
|
*ValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( ULONG ) );
|
|||
|
if (*ValueBuffer == NULL) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
if (RtlPrefixUnicodeString( &RiTrueKeyword, &KeyValue, TRUE ) ||
|
|||
|
RtlPrefixUnicodeString( &RiYesKeyword, &KeyValue, TRUE ) ||
|
|||
|
RtlPrefixUnicodeString( &RiOnKeyword, &KeyValue, TRUE )
|
|||
|
) {
|
|||
|
*(PULONG)*ValueBuffer = (ULONG)TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
if (RtlPrefixUnicodeString( &RiFalseKeyword, &KeyValue, TRUE ) ||
|
|||
|
RtlPrefixUnicodeString( &RiNoKeyword, &KeyValue, TRUE ) ||
|
|||
|
RtlPrefixUnicodeString( &RiOffKeyword, &KeyValue, TRUE )
|
|||
|
) {
|
|||
|
*(PULONG)*ValueBuffer = (ULONG)FALSE;
|
|||
|
}
|
|||
|
else {
|
|||
|
Status = RtlUnicodeStringToInteger( &KeyValue, 0, (PULONG)*ValueBuffer );
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
fprintf( stderr, "REGINI: CharToInteger( %wZ ) failed - Status == %lx\n", &KeyValue, Status );
|
|||
|
RtlFreeHeap( RtlProcessHeap(), 0, *ValueBuffer );
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*ValueLength = sizeof( ULONG );
|
|||
|
return( TRUE );
|
|||
|
|
|||
|
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;
|
|||
|
UNICODE_STRING Field;
|
|||
|
ULONG FieldValue;
|
|||
|
|
|||
|
RtlZeroMemory( &DateTimeFields, sizeof( DateTimeFields ) );
|
|||
|
Fields = &DateTimeFields.Year;
|
|||
|
while (KeyValue.Length) {
|
|||
|
if (CurrentField >= 7) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
s = KeyValue.Buffer;
|
|||
|
while (KeyValue.Length && *s == L' ') {
|
|||
|
KeyValue.Length--;
|
|||
|
s++;
|
|||
|
}
|
|||
|
|
|||
|
Field.Buffer = s;
|
|||
|
while (KeyValue.Length) {
|
|||
|
if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) {
|
|||
|
}
|
|||
|
else
|
|||
|
if (*s < L'0' || *s > L'9') {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
KeyValue.Length--;
|
|||
|
s++;
|
|||
|
}
|
|||
|
|
|||
|
Field.Length = (USHORT)((PCHAR)s - (PCHAR)Field.Buffer);
|
|||
|
Field.MaximumLength = Field.Length;
|
|||
|
|
|||
|
if (KeyValue.Length) {
|
|||
|
KeyValue.Length--;
|
|||
|
s++;
|
|||
|
}
|
|||
|
KeyValue.Buffer = s;
|
|||
|
|
|||
|
if (CurrentField == (NUMBER_DATE_TIME_FIELDS-1)) {
|
|||
|
if (Field.Length < 3) {
|
|||
|
printf( "REGINI: %wZ invalid day of week length\n", &Field );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (DateTimeFields.Year != 0) {
|
|||
|
printf( "REGINI: Year must be zero to specify day of week\n" );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (!_wcsnicmp( Field.Buffer, L"SUN", 3 )) {
|
|||
|
FieldValue = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsnicmp( Field.Buffer, L"MON", 3 )) {
|
|||
|
FieldValue = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsnicmp( Field.Buffer, L"TUE", 3 )) {
|
|||
|
FieldValue = 2;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsnicmp( Field.Buffer, L"WED", 3 )) {
|
|||
|
FieldValue = 3;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsnicmp( Field.Buffer, L"THU", 3 )) {
|
|||
|
FieldValue = 4;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsnicmp( Field.Buffer, L"FRI", 3 )) {
|
|||
|
FieldValue = 5;
|
|||
|
}
|
|||
|
else
|
|||
|
if (!_wcsnicmp( Field.Buffer, L"SAT", 3 )) {
|
|||
|
FieldValue = 6;
|
|||
|
}
|
|||
|
else {
|
|||
|
printf( "REGINI: %wZ invalid day of week\n", &Field );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
Status = RtlUnicodeStringToInteger( &Field, 10, &FieldValue );
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Fields[ FieldIndexes[ CurrentField++ ] ] = (CSHORT)FieldValue;
|
|||
|
}
|
|||
|
|
|||
|
if (DateTimeFields.Year == 0) {
|
|||
|
if (DateTimeFields.Day > 5) {
|
|||
|
printf( "REGINI: Day must be 0 - 5 if year is zero.\n" );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
if (DateTimeFields.Year < 100) {
|
|||
|
DateTimeFields.Year += 1900;
|
|||
|
}
|
|||
|
|
|||
|
*ValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( DateTimeFields ) );
|
|||
|
*ValueLength = sizeof( DateTimeFields );
|
|||
|
RtlMoveMemory( *ValueBuffer, &DateTimeFields, sizeof( DateTimeFields ) );
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
else {
|
|||
|
Status = RtlUnicodeStringToInteger( &KeyValue, 0, ValueLength );
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
s = KeyValue.Buffer;
|
|||
|
while (KeyValue.Length != 0 && *s > L' ') {
|
|||
|
s++;
|
|||
|
KeyValue.Length -= sizeof( WCHAR );
|
|||
|
}
|
|||
|
KeyValue.Buffer = s;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case REG_MULTI_SZ:
|
|||
|
*ValueLength = 0;
|
|||
|
*ValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, KeyValue.Length + sizeof( UNICODE_NULL ) );
|
|||
|
while (RegGetMultiString(&KeyValue, &MultiValue)) {
|
|||
|
RtlMoveMemory( (PUCHAR)*ValueBuffer + *ValueLength,
|
|||
|
MultiValue.Buffer,
|
|||
|
MultiValue.Length );
|
|||
|
*ValueLength += MultiValue.Length;
|
|||
|
((PWSTR)*ValueBuffer)[ *ValueLength / sizeof(WCHAR) ] = UNICODE_NULL;
|
|||
|
*ValueLength += sizeof(UNICODE_NULL);
|
|||
|
}
|
|||
|
((PWSTR)*ValueBuffer)[ *ValueLength / sizeof(WCHAR) ] = UNICODE_NULL;
|
|||
|
*ValueLength += sizeof(UNICODE_NULL);
|
|||
|
|
|||
|
return( TRUE );
|
|||
|
|
|||
|
default:
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
*ValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *ValueLength );
|
|||
|
p = *ValueBuffer;
|
|||
|
n = (*ValueLength + sizeof( ULONG ) - 1) / sizeof( ULONG );
|
|||
|
while (n--) {
|
|||
|
if (KeyValue.Length == 0) {
|
|||
|
if (!RegGetNextLine( UnicodeFile, &IndentAmount, &FirstEqual )) {
|
|||
|
RtlFreeHeap( RtlProcessHeap(), 0, *ValueBuffer );
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
KeyValue.Buffer = UnicodeFile->BeginLine;
|
|||
|
KeyValue.Length = (USHORT)
|
|||
|
((PCHAR)UnicodeFile->EndOfLine - (PCHAR)UnicodeFile->BeginLine);
|
|||
|
KeyValue.MaximumLength = KeyValue.Length;
|
|||
|
}
|
|||
|
|
|||
|
s = KeyValue.Buffer;
|
|||
|
while (KeyValue.Length != 0 && *s <= L' ') {
|
|||
|
s++;
|
|||
|
KeyValue.Length -= sizeof( WCHAR );
|
|||
|
}
|
|||
|
KeyValue.Buffer = s;
|
|||
|
if (KeyValue.Length != 0) {
|
|||
|
Status = RtlUnicodeStringToInteger( &KeyValue, 0, p );
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
RtlFreeHeap( RtlProcessHeap(), 0, *ValueBuffer );
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
p++;
|
|||
|
|
|||
|
s = KeyValue.Buffer;
|
|||
|
while (KeyValue.Length != 0 && *s > L' ') {
|
|||
|
s++;
|
|||
|
KeyValue.Length -= sizeof( WCHAR );
|
|||
|
}
|
|||
|
KeyValue.Buffer = s;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
RtlPrefixUnicodeString(
|
|||
|
IN PUNICODE_STRING String1,
|
|||
|
IN PUNICODE_STRING String2,
|
|||
|
IN BOOLEAN CaseInSensitive
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The RtlPrefixUnicodeString function determines if the String1
|
|||
|
counted string parameter is a prefix of the String2 counted string
|
|||
|
parameter.
|
|||
|
|
|||
|
The CaseInSensitive parameter specifies if case is to be ignored when
|
|||
|
doing the comparison.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
String1 - Pointer to the first unicode string.
|
|||
|
|
|||
|
String2 - Pointer to the second unicode string.
|
|||
|
|
|||
|
CaseInsensitive - TRUE if case should be ignored when doing the
|
|||
|
comparison.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean value that is TRUE if String1 equals a prefix of String2 and
|
|||
|
FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PWSTR s1, s2;
|
|||
|
ULONG n;
|
|||
|
WCHAR c1, c2;
|
|||
|
|
|||
|
s1 = String1->Buffer;
|
|||
|
s2 = String2->Buffer;
|
|||
|
if (String2->Length < String1->Length) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
n = String1->Length / sizeof( c1 );
|
|||
|
while (n) {
|
|||
|
c1 = *s1++;
|
|||
|
c2 = *s2++;
|
|||
|
|
|||
|
if (CaseInSensitive) {
|
|||
|
c1 = upcase(c1);
|
|||
|
c2 = upcase(c2);
|
|||
|
}
|
|||
|
if (c1 != c2) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
n--;
|
|||
|
}
|
|||
|
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
|