From 3f36421f86877a5b59e30dd5c34f18b3d2ff4ab7 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Mon, 28 Aug 2000 21:49:11 +0000 Subject: [PATCH] Added/fixed resource 'loader'. svn path=/trunk/; revision=1324 --- reactos/include/ddk/ldrfuncs.h | 21 +++- reactos/lib/kernel32/misc/res.c | 35 ++++-- reactos/lib/ntdll/def/ntdll.def | 4 +- reactos/lib/ntdll/def/ntdll.edf | 4 +- reactos/lib/ntdll/ldr/utils.c | 207 +++++++++++++++----------------- reactos/ntoskrnl/ldr/resource.c | 184 ++++++++++++++++++++++++++++ reactos/ntoskrnl/ldr/rtl.c | 62 +++++++++- reactos/ntoskrnl/makefile_rex | 3 +- reactos/ntoskrnl/ntoskrnl.def | 6 +- reactos/ntoskrnl/ntoskrnl.edf | 6 +- 10 files changed, 401 insertions(+), 131 deletions(-) create mode 100644 reactos/ntoskrnl/ldr/resource.c diff --git a/reactos/include/ddk/ldrfuncs.h b/reactos/include/ddk/ldrfuncs.h index af731e6f904..47d3b192e90 100644 --- a/reactos/include/ddk/ldrfuncs.h +++ b/reactos/include/ddk/ldrfuncs.h @@ -1,6 +1,19 @@ #ifndef __INCLUDE_DDK_LDRFUNCS_H #define __INCLUDE_DDK_LDRFUNCS_H -/* $Id: ldrfuncs.h,v 1.1 2000/08/27 22:35:22 ekohl Exp $ */ +/* $Id: ldrfuncs.h,v 1.2 2000/08/28 21:45:08 ekohl Exp $ */ + +typedef struct _LDR_RESOURCE_INFO +{ + ULONG Type; + ULONG Name; + ULONG Language; +} LDR_RESOURCE_INFO, *PLDR_RESOURCE_INFO; + +#define RESOURCE_TYPE_LEVEL 0 +#define RESOURCE_NAME_LEVEL 1 +#define RESOURCE_LANGUAGE_LEVEL 2 +#define RESOURCE_DATA_LEVEL 3 + NTSTATUS STDCALL LdrAccessResource(IN PVOID BaseAddress, @@ -8,4 +21,10 @@ LdrAccessResource(IN PVOID BaseAddress, OUT PVOID *Resource OPTIONAL, OUT PULONG Size OPTIONAL); +NTSTATUS STDCALL +LdrFindResource_U(IN PVOID BaseAddress, + IN PLDR_RESOURCE_INFO ResourceInfo, + IN ULONG Level, + OUT PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry); + #endif /* __INCLUDE_DDK_LDRFUNCS_H */ diff --git a/reactos/lib/kernel32/misc/res.c b/reactos/lib/kernel32/misc/res.c index d66d4991840..36b77d41c27 100644 --- a/reactos/lib/kernel32/misc/res.c +++ b/reactos/lib/kernel32/misc/res.c @@ -1,4 +1,4 @@ -/* $Id: res.c,v 1.6 2000/08/27 22:37:45 ekohl Exp $ +/* $Id: res.c,v 1.7 2000/08/28 21:45:43 ekohl Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT : ReactOS user mode libraries @@ -101,7 +101,8 @@ FindResourceExW ( WORD wLanguage ) { - IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry; + PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry = NULL; + LDR_RESOURCE_INFO ResourceInfo; NTSTATUS Status; int i,l; ULONG nType = 0, nName = 0; @@ -112,13 +113,17 @@ FindResourceExW ( if ( HIWORD(lpName) != 0 ) { if ( lpName[0] == L'#' ) { l = lstrlenW(lpName) -1; - + for(i=0;iBaseAddress; return STATUS_SUCCESS; } -/* - RtlInitAnsiString( - & AnsiString, - fqname - ); - RtlAnsiStringToUnicodeString( - & UnicodeString, - & AnsiString, - TRUE - ); -*/ + RtlInitUnicodeString(&UnicodeString, fqname); @@ -305,7 +292,6 @@ LdrLoadDll (IN PWSTR SearchPath OPTIONAL, * NOTE * */ -//static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name) static NTSTATUS LdrFindDll(PDLL* Dll, PUNICODE_STRING Name) { PIMAGE_EXPORT_DIRECTORY ExportDir; @@ -727,8 +713,6 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders, Status = LdrLoadDll(NULL, 0, &DllName, -// (PCHAR)(ImageBase -// +ImportModuleDirectory->dwRVAModuleName), &BaseAddress); RtlFreeUnicodeString (&DllName); if (!NT_SUCCESS(Status)) @@ -954,110 +938,115 @@ LdrUnloadDll (IN PVOID BaseAddress) } -static PIMAGE_RESOURCE_DIRECTORY_ENTRY -LdrGetNextEntry(IMAGE_RESOURCE_DIRECTORY *ResourceDir, LPCWSTR ResourceName, ULONG Offset) +NTSTATUS STDCALL +LdrFindResource_U(PVOID BaseAddress, + PLDR_RESOURCE_INFO ResourceInfo, + ULONG Level, + PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry) { - WORD NumberOfNamedEntries; - WORD NumberOfIdEntries; - WORD Entries; - ULONG Length; + PIMAGE_RESOURCE_DIRECTORY ResDir; + PIMAGE_RESOURCE_DIRECTORY ResBase; + PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry; + NTSTATUS Status = STATUS_SUCCESS; + ULONG EntryCount; + PWCHAR ws; + ULONG i; + ULONG Id; - if ( (((ULONG)ResourceDir) & 0xF0000000) != 0 ) { - return (IMAGE_RESOURCE_DIRECTORY_ENTRY *)NULL; - } + DPRINT ("LdrFindResource_U()\n"); - NumberOfIdEntries = ResourceDir->NumberOfIdEntries; - NumberOfNamedEntries = ResourceDir->NumberOfNamedEntries; - if ( ( NumberOfIdEntries + NumberOfNamedEntries) == 0) { - return &ResourceDir->DirectoryEntries[0]; - } + /* Get the pointer to the resource directory */ + ResDir = (PIMAGE_RESOURCE_DIRECTORY) + RtlImageDirectoryEntryToData (BaseAddress, + TRUE, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + &i); + if (ResDir == NULL) + { + return STATUS_RESOURCE_DATA_NOT_FOUND; + } - if ( HIWORD(ResourceName) != 0 ) { - Length = wcslen(ResourceName); - Entries = ResourceDir->NumberOfNamedEntries; - do { - IMAGE_RESOURCE_DIR_STRING_U *DirString; + DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir); - Entries--; - DirString = (IMAGE_RESOURCE_DIR_STRING_U *)(((ULONG)ResourceDir->DirectoryEntries[Entries].Name & (~0xF0000000)) + Offset); - - if ( DirString->Length == Length && wcscmp(DirString->NameString, ResourceName ) == 0 ) { - return &ResourceDir->DirectoryEntries[Entries]; - } - } while (Entries > 0); - } - else { - Entries = ResourceDir->NumberOfIdEntries + ResourceDir->NumberOfNamedEntries; - do { - Entries--; + ResBase = ResDir; - if ( (LPWSTR)ResourceDir->DirectoryEntries[Entries].Name == ResourceName ) { - return &ResourceDir->DirectoryEntries[Entries]; - } - } while (Entries > ResourceDir->NumberOfNamedEntries); - - } + /* Let's go into resource tree */ + for (i = 0; i < Level; i++) + { + DPRINT("ResDir: %x\n", (ULONG)ResDir); + Id = ((PULONG)ResourceInfo)[i]; + EntryCount = ResDir->NumberOfNamedEntries; + ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1); + DPRINT("ResEntry %x\n", (ULONG)ResEntry); + if (Id & 0xFFFF0000) + { + /* Resource name is a unicode string */ + for (; EntryCount--; ResEntry++) + { + /* Scan entries for equal name */ + if (ResEntry->Name & 0x80000000) + { + ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF)); + if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) && + wcslen((PWCHAR)Id) == (int)*ws ) + { + goto found; + } + } + } + } + else + { + /* We use ID number instead of string */ + ResEntry += EntryCount; + EntryCount = ResDir->NumberOfIdEntries; + for (; EntryCount--; ResEntry++) + { + /* Scan entries for equal name */ + if (ResEntry->Name == Id) + { + DPRINT("ID entry found %x\n", Id); + goto found; + } + } + } + DPRINT("Error %lu\n", i); - return NULL; -} + switch (i) + { + case 0: + return STATUS_RESOURCE_TYPE_NOT_FOUND; + case 1: + return STATUS_RESOURCE_NAME_NOT_FOUND; + case 2: + if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries) + { + /* Use the first available language */ + ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1); + break; + } + return STATUS_RESOURCE_LANG_NOT_FOUND; -NTSTATUS LdrFindResource_U(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY **ResourceDataEntry,LPCWSTR ResourceName, ULONG ResourceType,ULONG Language) -{ - IMAGE_RESOURCE_DIRECTORY *ResourceTypeDir; - IMAGE_RESOURCE_DIRECTORY *ResourceNameDir; - IMAGE_RESOURCE_DIRECTORY *ResourceLangDir; + case 3: + return STATUS_RESOURCE_DATA_NOT_FOUND; - IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceTypeDirEntry; - IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceNameDirEntry; - IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceLangDirEntry; + default: + return STATUS_INVALID_PARAMETER; + } +found:; + ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase + + (ResEntry->OffsetToData & 0x7FFFFFFF)); + } + DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir); - PIMAGE_OPTIONAL_HEADER OptionalHeader; - - - - ULONG Offset; - - OptionalHeader = & Dll->Headers->OptionalHeader; - ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY) - OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; - ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY) - ((ULONG)ResourceTypeDir + (ULONG)Dll->BaseAddress); - - - Offset = (ULONG)ResourceTypeDir; - - ResourceTypeDirEntry = LdrGetNextEntry(ResourceTypeDir, (LPWSTR)ResourceType, Offset); - - if ( ResourceTypeDirEntry != NULL ) { - ResourceNameDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceTypeDirEntry->OffsetToData & (~0xF0000000)) + Offset); - - ResourceNameDirEntry = LdrGetNextEntry(ResourceNameDir, ResourceName, Offset); - - if ( ResourceNameDirEntry != NULL ) { - - ResourceLangDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceNameDirEntry->OffsetToData & (~0xF0000000)) + Offset); - - ResourceLangDirEntry = LdrGetNextEntry(ResourceLangDir, (LPWSTR)Language, Offset); - if ( ResourceLangDirEntry != NULL ) { - - *ResourceDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)(ResourceLangDirEntry->OffsetToData + - (ULONG)ResourceTypeDir); - return STATUS_SUCCESS; - } - else { - return -1; - } - } - else { - return -1; - } - - } - - return -1; + if (ResourceDataEntry) + { + *ResourceDataEntry = (PVOID)ResDir; + } + return Status; } diff --git a/reactos/ntoskrnl/ldr/resource.c b/reactos/ntoskrnl/ldr/resource.c new file mode 100644 index 00000000000..f6b5c1446a0 --- /dev/null +++ b/reactos/ntoskrnl/ldr/resource.c @@ -0,0 +1,184 @@ +/* $Id: resource.c,v 1.1 2000/08/28 21:49:11 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ldr/resource.c + * PURPOSE: Resource loader + * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de) + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS STDCALL +LdrAccessResource(IN PVOID BaseAddress, + IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + OUT PVOID *Resource OPTIONAL, + OUT PULONG Size OPTIONAL) +{ + PIMAGE_SECTION_HEADER Section; + PIMAGE_NT_HEADERS NtHeader; + ULONG SectionRva; + ULONG SectionVa; + ULONG DataSize; + ULONG Offset = 0; + ULONG Data; + + Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress, + TRUE, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + &DataSize); + if (Data == 0) + return STATUS_RESOURCE_DATA_NOT_FOUND; + + if ((ULONG)BaseAddress & 1) + { + /* loaded as ordinary file */ + NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL)); + Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); + if (Section == NULL) + { + return STATUS_RESOURCE_DATA_NOT_FOUND; + } + + if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData) + { + SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress; + SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL); + Offset = SectionRva - SectionVa + Data - Section->VirtualAddress; + } + } + + if (Resource) + { + *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress); + } + + if (Size) + { + *Size = ResourceDataEntry->Size; + } + + return STATUS_SUCCESS; +} + + +NTSTATUS STDCALL +LdrFindResource_U(PVOID BaseAddress, + PLDR_RESOURCE_INFO ResourceInfo, + ULONG Level, + PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry) +{ + PIMAGE_RESOURCE_DIRECTORY ResDir; + PIMAGE_RESOURCE_DIRECTORY ResBase; + PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry; + NTSTATUS Status = STATUS_SUCCESS; + ULONG EntryCount; + PWCHAR ws; + ULONG i; + ULONG Id; + + DPRINT ("LdrFindResource_U()\n"); + + /* Get the pointer to the resource directory */ + ResDir = (PIMAGE_RESOURCE_DIRECTORY) + RtlImageDirectoryEntryToData (BaseAddress, + TRUE, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + &i); + if (ResDir == NULL) + { + return STATUS_RESOURCE_DATA_NOT_FOUND; + } + + DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir); + + ResBase = ResDir; + + /* Let's go into resource tree */ + for (i = 0; i < Level; i++) + { + DPRINT("ResDir: %x\n", (ULONG)ResDir); + Id = ((PULONG)ResourceInfo)[i]; + EntryCount = ResDir->NumberOfNamedEntries; + ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1); + DPRINT("ResEntry %x\n", (ULONG)ResEntry); + if (Id & 0xFFFF0000) + { + /* Resource name is a unicode string */ + for (; EntryCount--; ResEntry++) + { + /* Scan entries for equal name */ + if (ResEntry->Name & 0x80000000) + { + ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF)); + if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) && + wcslen((PWCHAR)Id) == (int)*ws ) + { + goto found; + } + } + } + } + else + { + /* We use ID number instead of string */ + ResEntry += EntryCount; + EntryCount = ResDir->NumberOfIdEntries; + for (; EntryCount--; ResEntry++) + { + /* Scan entries for equal name */ + if (ResEntry->Name == Id) + { + DPRINT("ID entry found %x\n", Id); + goto found; + } + } + } + DPRINT("Error %lu\n", i); + + switch (i) + { + case 0: + return STATUS_RESOURCE_TYPE_NOT_FOUND; + + case 1: + return STATUS_RESOURCE_NAME_NOT_FOUND; + + case 2: + if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries) + { + /* Use the first available language */ + ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1); + break; + } + return STATUS_RESOURCE_LANG_NOT_FOUND; + + case 3: + return STATUS_RESOURCE_DATA_NOT_FOUND; + + default: + return STATUS_INVALID_PARAMETER; + } +found:; + ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase + + (ResEntry->OffsetToData & 0x7FFFFFFF)); + } + DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir); + + if (ResourceDataEntry) + { + *ResourceDataEntry = (PVOID)ResDir; + } + + return Status; +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ldr/rtl.c b/reactos/ntoskrnl/ldr/rtl.c index 9224dd7b83d..89fb78e83c9 100644 --- a/reactos/ntoskrnl/ldr/rtl.c +++ b/reactos/ntoskrnl/ldr/rtl.c @@ -1,4 +1,4 @@ -/* $Id: rtl.c,v 1.9 2000/08/05 18:01:53 dwelch Exp $ +/* $Id: rtl.c,v 1.10 2000/08/28 21:49:11 ekohl Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -92,6 +92,66 @@ RtlImageDirectoryEntryToData ( } +PIMAGE_SECTION_HEADER +STDCALL +RtlImageRvaToSection ( + PIMAGE_NT_HEADERS NtHeader, + PVOID BaseAddress, + ULONG Rva + ) +{ + PIMAGE_SECTION_HEADER Section; + ULONG Va; + ULONG Count; + + Count = NtHeader->FileHeader.NumberOfSections; + Section = (PIMAGE_SECTION_HEADER)((ULONG)&NtHeader->OptionalHeader + + NtHeader->FileHeader.SizeOfOptionalHeader); + while (Count) + { + Va = Section->VirtualAddress; + if ((Va <= Rva) && + (Rva < Va + Section->SizeOfRawData)) + return Section; + Section++; + } + return NULL; +} + + +ULONG +STDCALL +RtlImageRvaToVa ( + PIMAGE_NT_HEADERS NtHeader, + PVOID BaseAddress, + ULONG Rva, + PIMAGE_SECTION_HEADER *SectionHeader + ) +{ + PIMAGE_SECTION_HEADER Section = NULL; + + if (SectionHeader) + Section = *SectionHeader; + + if (Section == NULL || + Rva < Section->VirtualAddress || + Rva >= Section->VirtualAddress + Section->SizeOfRawData) + { + Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva); + if (Section == NULL) + return 0; + + if (SectionHeader) + *SectionHeader = Section; + } + + return (ULONG)(BaseAddress + + Rva + + Section->PointerToRawData - + Section->VirtualAddress); +} + + NTSTATUS STDCALL LdrGetProcedureAddress (IN PVOID BaseAddress, IN PANSI_STRING Name, diff --git a/reactos/ntoskrnl/makefile_rex b/reactos/ntoskrnl/makefile_rex index 184089e2d7e..34202c52cf1 100644 --- a/reactos/ntoskrnl/makefile_rex +++ b/reactos/ntoskrnl/makefile_rex @@ -1,4 +1,4 @@ -# $Id: makefile_rex,v 1.84 2000/08/18 22:27:02 dwelch Exp $ +# $Id: makefile_rex,v 1.85 2000/08/28 21:48:31 ekohl Exp $ # # ReactOS Operating System # @@ -234,6 +234,7 @@ OBJECTS_DBG = \ OBJECTS_LDR = \ ldr/init.o \ ldr/loader.o \ + ldr/resource.o \ ldr/rtl.o \ ldr/sysdll.o \ ldr/userldr.o diff --git a/reactos/ntoskrnl/ntoskrnl.def b/reactos/ntoskrnl/ntoskrnl.def index 4542b4aece0..a4e75f0eefd 100644 --- a/reactos/ntoskrnl/ntoskrnl.def +++ b/reactos/ntoskrnl/ntoskrnl.def @@ -1,4 +1,4 @@ -; $Id: ntoskrnl.def,v 1.86 2000/08/26 16:18:58 ekohl Exp $ +; $Id: ntoskrnl.def,v 1.87 2000/08/28 21:48:32 ekohl Exp $ ; ; reactos/ntoskrnl/ntoskrnl.def ; @@ -431,10 +431,10 @@ KiDispatchInterrupt@0 ;KiReleaseSpinLock@4 ;KiUnexpectedInterrupt ;Kii386SpinOnSpinLock -;LdrAccessResource@16 +LdrAccessResource@16 ;LdrEnumResources@20 ;LdrFindResourceDirectory_U@16 -;LdrFindResource_U@16 +LdrFindResource_U@16 ;LpcRequestPort@8 ;LsaCallAuthenticationPackage ;LsaDeregisterLogonProcess diff --git a/reactos/ntoskrnl/ntoskrnl.edf b/reactos/ntoskrnl/ntoskrnl.edf index 9142356cd32..96212c0563b 100644 --- a/reactos/ntoskrnl/ntoskrnl.edf +++ b/reactos/ntoskrnl/ntoskrnl.edf @@ -1,4 +1,4 @@ -; $Id: ntoskrnl.edf,v 1.73 2000/08/26 16:18:58 ekohl Exp $ +; $Id: ntoskrnl.edf,v 1.74 2000/08/28 21:48:32 ekohl Exp $ ; ; reactos/ntoskrnl/ntoskrnl.def ; @@ -431,10 +431,10 @@ KiDispatchInterrupt=KiDispatchInterrupt@0 ;KiReleaseSpinLock@4 ;KiUnexpectedInterrupt ;Kii386SpinOnSpinLock -;LdrAccessResource@16 +LdrAccessResource=LdrAccessResource@16 ;LdrEnumResources@20 ;LdrFindResourceDirectory_U@16 -;LdrFindResource_U@16 +LdrFindResource_U=LdrFindResource_U@16 ;LpcRequestPort@8 ;LsaCallAuthenticationPackage ;LsaDeregisterLogonProcess