Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1522 lines
49 KiB

/*++
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 );
}