--- /dev/null
+/* $Id$
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: lib/ntdll/ldr/res.c
+ * PURPOSE: Resource access for PE executables
+ * PROGRAMMERS: Jean Michault
+ * Rex Jolliff (rex@lvcablemodem.com)
+ * Robert Dickenson (robd@mok.lvcm.com)
+ */
+
+/*
+ * TODO:
+ * - any comments ??
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <reactos/config.h>
+#include <ddk/ntddk.h>
+#include <windows.h>
+#include <string.h>
+#include <wchar.h>
+#include <ntdll/ldr.h>
+#include <ntos/minmax.h>
+
+#define NDEBUG
+#include <ntdll/ntdll.h>
+
+/* PROTOTYPES ****************************************************************/
+
+
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ Status = LdrFindResource_U (hModule,
+ &ResourceInfo,
+ RESOURCE_DATA_LEVEL,
+ &ResourceDataEntry);
+ */
+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");
+ DPRINT("LdrFindResource_U(%08x, %08x, %d, %08x)\n", BaseAddress, ResourceInfo, Level, ResourceDataEntry);
+
+ /* 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 Size: %d\n", (ULONG)ResDir, (int)i);
+
+ ResBase = ResDir;
+
+ /* Let's go into resource tree */
+ for (i = 0; i < Level; i++) {
+ DPRINT("ResDir: %x Level: %d\n", (ULONG)ResDir, i);
+
+ Id = ((PULONG)ResourceInfo)[i];
+// ResourceInfo.Type = (ULONG)lpType;
+// ResourceInfo.Name = (ULONG)lpName;
+// ResourceInfo.Language = (ULONG)wLanguage;
+
+ EntryCount = ResDir->NumberOfNamedEntries;
+ DPRINT(" Id: %d NumberOfNamedEntries: %d\n", Id, EntryCount);
+ ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
+ //DPRINT("ResEntry %x\n", (ULONG)ResEntry);
+ if (Id & 0xFFFF0000) {
+ /* Resource name is a unicode string */
+ DPRINT("ResEntry %x - Resource name is a unicode string\n", (ULONG)ResEntry);
+ DPRINT("EntryCount %d\n", (ULONG)EntryCount);
+ 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 */
+ DPRINT("ResEntry %x - Resource ID number instead of string\n", (ULONG)ResEntry);
+ DPRINT("EntryCount %d\n", (ULONG)EntryCount);
+ ResEntry += EntryCount;
+ EntryCount = ResDir->NumberOfIdEntries;
+ DPRINT("EntryCount %d\n", (ULONG)EntryCount);
+ for (; EntryCount--; ResEntry++) {
+ /* Scan entries for equal name */
+ DPRINT("EntryCount %d ResEntry %x\n", (ULONG)EntryCount, ResEntry);
+ DPRINT("ResEntry->Name %x Id %x\n", (ULONG)ResEntry->Name, Id);
+ if (ResEntry->Name == Id) {
+ DPRINT("ID entry found %x\n", Id);
+ goto found;
+ }
+ }
+ }
+
+ //DPRINT("Error %lu\n", i);
+
+ switch (i) {
+ case 0:
+ DPRINT("Error %lu - STATUS_RESOURCE_TYPE_NOT_FOUND\n", i);
+ return STATUS_RESOURCE_TYPE_NOT_FOUND;
+ case 1:
+ DPRINT("Error %lu - STATUS_RESOURCE_NAME_NOT_FOUND\n", i);
+ 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;
+ }
+ DPRINT("Error %lu - STATUS_RESOURCE_LANG_NOT_FOUND\n", i);
+ return STATUS_RESOURCE_LANG_NOT_FOUND;
+ case 3:
+ DPRINT("Error %lu - STATUS_RESOURCE_DATA_NOT_FOUND\n", i);
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+ default:
+ DPRINT("Error %lu - STATUS_INVALID_PARAMETER\n", i);
+ 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;
+}
+
+
+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
+LdrFindResourceDirectory_U(IN PVOID BaseAddress,
+ WCHAR** name,
+ DWORD level,
+ OUT PVOID* addr)
+{
+ PIMAGE_RESOURCE_DIRECTORY ResDir;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
+ ULONG EntryCount;
+ ULONG i;
+ NTSTATUS Status = STATUS_SUCCESS;
+ WCHAR* ws;
+
+ /* 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;
+ }
+
+ /* Let's go into resource tree */
+ for (i = 0; i < level; i++, name++) {
+ EntryCount = ResDir->NumberOfNamedEntries;
+ ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
+ if ((ULONG)(*name) & 0xFFFF0000) {
+ /* Resource name is a unicode string */
+ for (; EntryCount--; ResEntry++) {
+ /* Scan entries for equal name */
+ if (ResEntry->Name & 0x80000000) {
+ ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
+ if (!wcsncmp(*name, ws + 1, *ws) && wcslen(*name) == (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 == (ULONG)(*name))
+ goto found;
+ }
+ }
+ switch (i) {
+ case 0:
+ return STATUS_RESOURCE_TYPE_NOT_FOUND;
+ case 1:
+ return STATUS_RESOURCE_NAME_NOT_FOUND;
+ case 2:
+ Status = STATUS_RESOURCE_LANG_NOT_FOUND;
+ /* Just use first language entry */
+ if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries) {
+ ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
+ break;
+ }
+ return Status;
+ case 3:
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+found:;
+ ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
+ }
+ if (addr) {
+ *addr = (PVOID)ResDir;
+ }
+ return Status;
+}
+
+/* EOF */