diff options
Diffstat (limited to 'private/ntos/rtl/ldrrsrc.c')
-rw-r--r-- | private/ntos/rtl/ldrrsrc.c | 930 |
1 files changed, 930 insertions, 0 deletions
diff --git a/private/ntos/rtl/ldrrsrc.c b/private/ntos/rtl/ldrrsrc.c new file mode 100644 index 000000000..95e664f2b --- /dev/null +++ b/private/ntos/rtl/ldrrsrc.c @@ -0,0 +1,930 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ldrrsrc.c + +Abstract: + + Loader API calls for accessing resource sections. + +Author: + + Steve Wood (stevewo) 16-Sep-1991 + +Revision History: + +--*/ + +#include "ntrtlp.h" + +#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) +#pragma alloc_text(PAGE,LdrAccessResource) +#pragma alloc_text(PAGE,LdrpAccessResourceData) +#pragma alloc_text(PAGE,LdrFindEntryForAddress) +#pragma alloc_text(PAGE,LdrFindResource_U) +#pragma alloc_text(PAGE,LdrFindResourceDirectory_U) +#pragma alloc_text(PAGE,LdrpCompareResourceNames_U) +#pragma alloc_text(PAGE,LdrpSearchResourceSection_U) +#pragma alloc_text(PAGE,LdrEnumResources) +#endif + +NTSTATUS +LdrAccessResource( + IN PVOID DllHandle, + IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + OUT PVOID *Address OPTIONAL, + OUT PULONG Size OPTIONAL + ) + +/*++ + +Routine Description: + + This function locates the address of the specified resource in the + specified DLL and returns its address. + +Arguments: + + DllHandle - Supplies a handle to the image file that the resource is + contained in. + + ResourceDataEntry - Supplies a pointer to the resource data entry in + the resource data section of the image file specified by the + DllHandle parameter. This pointer should have been one returned + by the LdrFindResource function. + + Address - Optional pointer to a variable that will receive the + address of the resource specified by the first two parameters. + + Size - Optional pointer to a variable that will receive the size of + the resource specified by the first two parameters. + +Return Value: + + TBD + +--*/ + +{ + RTL_PAGED_CODE(); + + return LdrpAccessResourceData( + DllHandle, + ResourceDataEntry, + Address, + Size + ); +} + + +NTSTATUS +LdrpAccessResourceData( + IN PVOID DllHandle, + IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + OUT PVOID *Address OPTIONAL, + OUT PULONG Size OPTIONAL + ) + +/*++ + +Routine Description: + + This function returns the data necessary to actually examine the + contents of a particular resource. + +Arguments: + + DllHandle - Supplies a handle to the image file that the resource is + contained in. + + ResourceDataEntry - Supplies a pointer to the resource data entry in + the resource data directory of the image file specified by the + DllHandle parameter. This pointer should have been one returned + by the LdrFindResource function. + + Address - Optional pointer to a variable that will receive the + address of the resource specified by the first two parameters. + + Size - Optional pointer to a variable that will receive the size of + the resource specified by the first two parameters. + + +Return Value: + + TBD + +--*/ + +{ + PIMAGE_RESOURCE_DIRECTORY ResourceDirectory; + ULONG ResourceSize; + PIMAGE_NT_HEADERS NtHeaders; + ULONG VirtualAddressOffset; + PIMAGE_SECTION_HEADER NtSection; + + RTL_PAGED_CODE(); + + ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) + RtlImageDirectoryEntryToData(DllHandle, + TRUE, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + &ResourceSize + ); + if (!ResourceDirectory) { + return( STATUS_RESOURCE_DATA_NOT_FOUND ); + } + + if ((ULONG)DllHandle & 0x00000001) { + DllHandle = (PVOID)((ULONG)DllHandle & ~0x00000001); + NtHeaders = RtlImageNtHeader( DllHandle ); + VirtualAddressOffset = + (ULONG)DllHandle + + NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress - + (ULONG)ResourceDirectory; + + // + // Now, we must check to see if the resource is not in the + // same section as the resource table. If it's in .rsrc1, + // we've got to adjust the RVA in the ResourceDataEntry + // to point to the correct place in the non-VA data file. + // + NtSection= RtlSectionTableFromVirtualAddress( NtHeaders, DllHandle, + (PVOID)NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress ); + if (!NtSection) { + return( STATUS_RESOURCE_DATA_NOT_FOUND ); + } + if ( ResourceDataEntry->OffsetToData > NtSection->Misc.VirtualSize ) { + ULONG rva; + + rva = NtSection->VirtualAddress; + NtSection= RtlSectionTableFromVirtualAddress + ( + NtHeaders, + DllHandle, + (PVOID)ResourceDataEntry->OffsetToData + ); + VirtualAddressOffset += + ((ULONG)NtSection->VirtualAddress - rva) - + ((ULONG)RtlAddressInSectionTable ( NtHeaders, DllHandle, (PVOID)NtSection->VirtualAddress ) - (ULONG)ResourceDirectory); + } + } + else { + VirtualAddressOffset = 0; + } + + try { + if (ARGUMENT_PRESENT( Address )) { + *Address = (PVOID)( (ULONG)DllHandle + + (ResourceDataEntry->OffsetToData - VirtualAddressOffset) + ); + } + + if (ARGUMENT_PRESENT( Size )) { + *Size = ResourceDataEntry->Size; + } + } + except (EXCEPTION_EXECUTE_HANDLER) { + return GetExceptionCode(); + } + + return( STATUS_SUCCESS ); +} + + +NTSTATUS +LdrFindEntryForAddress( + IN PVOID Address, + OUT PLDR_DATA_TABLE_ENTRY *TableEntry + ) +/*++ + +Routine Description: + + This function returns the load data table entry that describes the virtual + address range that contains the passed virtual address. + +Arguments: + + Address - Supplies a 32-bit virtual address. + + TableEntry - Supplies a pointer to the variable that will receive the + address of the loader data table entry. + + +Return Value: + + Status + +--*/ +{ + PPEB_LDR_DATA Ldr; + PLIST_ENTRY Head, Next; + PLDR_DATA_TABLE_ENTRY Entry; + PIMAGE_NT_HEADERS NtHeaders; + PVOID ImageBase; + PVOID EndOfImage; + + Ldr = NtCurrentPeb()->Ldr; + if (Ldr == NULL) { + return( STATUS_NO_MORE_ENTRIES ); + } + + Head = &Ldr->InMemoryOrderModuleList; + Next = Head->Flink; + while ( Next != Head ) { + Entry = CONTAINING_RECORD( Next, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks ); + + NtHeaders = RtlImageNtHeader( Entry->DllBase ); + if (NtHeaders != NULL) { + ImageBase = (PVOID)Entry->DllBase; + + EndOfImage = (PVOID) + ((ULONG)ImageBase + NtHeaders->OptionalHeader.SizeOfImage); + + if ((ULONG)Address >= (ULONG)ImageBase && (ULONG)Address < (ULONG)EndOfImage) { + *TableEntry = Entry; + return( STATUS_SUCCESS ); + } + } + + Next = Next->Flink; + } + + return( STATUS_NO_MORE_ENTRIES ); +} + + +NTSTATUS +LdrFindResource_U( + IN PVOID DllHandle, + IN PULONG ResourceIdPath, + IN ULONG ResourceIdPathLength, + OUT PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry + ) + +/*++ + +Routine Description: + + This function locates the address of the specified resource in the + specified DLL and returns its address. + +Arguments: + + DllHandle - Supplies a handle to the image file that the resource is + contained in. + + ResourceIdPath - Supplies a pointer to an array of 32-bit resource + identifiers. Each identifier is either an integer or a pointer + to a STRING structure that specifies a resource name. The array + is used to traverse the directory structure contained in the + resource section in the image file specified by the DllHandle + parameter. + + ResourceIdPathLength - Supplies the number of elements in the + ResourceIdPath array. + + ResourceDataEntry - Supplies a pointer to a variable that will + receive the address of the resource data entry in the resource + data section of the image file specified by the DllHandle + parameter. + +Return Value: + + TBD + +--*/ + +{ + RTL_PAGED_CODE(); + + return LdrpSearchResourceSection_U( + DllHandle, + ResourceIdPath, + ResourceIdPathLength, + FALSE, // Look for a leaf node + (PVOID *)ResourceDataEntry + ); +} + + +NTSTATUS +LdrFindResourceDirectory_U( + IN PVOID DllHandle, + IN PULONG ResourceIdPath, + IN ULONG ResourceIdPathLength, + OUT PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory + ) + +/*++ + +Routine Description: + + This function locates the address of the specified resource directory in + specified DLL and returns its address. + +Arguments: + + DllHandle - Supplies a handle to the image file that the resource + directory is contained in. + + ResourceIdPath - Supplies a pointer to an array of 32-bit resource + identifiers. Each identifier is either an integer or a pointer + to a STRING structure that specifies a resource name. The array + is used to traverse the directory structure contained in the + resource section in the image file specified by the DllHandle + parameter. + + ResourceIdPathLength - Supplies the number of elements in the + ResourceIdPath array. + + ResourceDirectory - Supplies a pointer to a variable that will + receive the address of the resource directory specified by + ResourceIdPath in the resource data section of the image file + the DllHandle parameter. + +Return Value: + + TBD + +--*/ + +{ + RTL_PAGED_CODE(); + + return LdrpSearchResourceSection_U( + DllHandle, + ResourceIdPath, + ResourceIdPathLength, + TRUE, // Look for a directory node + (PVOID *)ResourceDirectory + ); +} + + +LONG +LdrpCompareResourceNames_U( + IN ULONG ResourceName, + IN PIMAGE_RESOURCE_DIRECTORY ResourceDirectory, + IN PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirectoryEntry + ) +{ + LONG li; + PIMAGE_RESOURCE_DIR_STRING_U ResourceNameString; + + if (ResourceName & LDR_RESOURCE_ID_NAME_MASK) { + if (!ResourceDirectoryEntry->NameIsString) { + return( -1 ); + } + + ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) + ((PCHAR)ResourceDirectory + ResourceDirectoryEntry->NameOffset); + + li = wcsncmp( (LPWSTR)ResourceName, + ResourceNameString->NameString, + ResourceNameString->Length + ); + + if (!li && wcslen((PWSTR)ResourceName) != ResourceNameString->Length) { + return( 1 ); + } + + return(li); + } + else { + if (ResourceDirectoryEntry->NameIsString) { + return( 1 ); + } + + return( ResourceName - ResourceDirectoryEntry->Name ); + } +} + + +#define USE_FIRSTAVAILABLE_LANGID (0xFFFFFFFF & ~LDR_RESOURCE_ID_NAME_MASK) + +NTSTATUS +LdrpSearchResourceSection_U( + IN PVOID DllHandle, + IN PULONG ResourceIdPath, + IN ULONG ResourceIdPathLength, + IN BOOLEAN FindDirectoryEntry, + OUT PVOID *ResourceDirectoryOrData + ) + +/*++ + +Routine Description: + + This function locates the address of the specified resource in the + specified DLL and returns its address. + +Arguments: + + DllHandle - Supplies a handle to the image file that the resource is + contained in. + + ResourceIdPath - Supplies a pointer to an array of 32-bit resource + identifiers. Each identifier is either an integer or a pointer + to a null terminated string (PSZ) that specifies a resource + name. The array is used to traverse the directory structure + contained in the resource section in the image file specified by + the DllHandle parameter. + + ResourceIdPathLength - Supplies the number of elements in the + ResourceIdPath array. + + FindDirectoryEntry - Supplies a boolean that is TRUE if caller is + searching for a resource directory, otherwise the caller is + searching for a resource data entry. + + ResourceDirectoryOrData - Supplies a pointer to a variable that will + receive the address of the resource directory or data entry in + the resource data section of the image file specified by the + DllHandle parameter. + +Return Value: + + TBD + +--*/ + +{ + NTSTATUS Status; + PIMAGE_RESOURCE_DIRECTORY LanguageResourceDirectory, ResourceDirectory, TopResourceDirectory; + PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntLow; + PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntMiddle; + PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntHigh; + PIMAGE_RESOURCE_DATA_ENTRY ResourceEntry; + USHORT n, half; + LONG dir; + ULONG size; + ULONG ResourceIdRetry, RetryCount; + LCID DefaultThreadLocale, DefaultSystemLocale; + LANGID NewLangId; + PULONG IdPath = ResourceIdPath; + ULONG IdPathLength = ResourceIdPathLength; + BOOLEAN fIsNeutral = FALSE; + LANGID GivenLanguage; + + RTL_PAGED_CODE(); + + TopResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) + RtlImageDirectoryEntryToData(DllHandle, + TRUE, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + &size + ); + if (!TopResourceDirectory) { + return( STATUS_RESOURCE_DATA_NOT_FOUND ); + } + + try { + ResourceDirectory = TopResourceDirectory; + ResourceIdRetry = USE_FIRSTAVAILABLE_LANGID; + RetryCount = 0; + ResourceEntry = NULL; + LanguageResourceDirectory = NULL; + while (ResourceDirectory != NULL && ResourceIdPathLength--) { + // + // If search path includes a language id, then attempt to + // match the following language ids in this order: + // + // (0) use given language id + // (1) use primary language of given language id + // (2) use id 0 (neutral resource) + // + // If the PRIMARY language id is ZERO, then ALSO attempt to + // match the following language ids in this order: + // + // (3) use lang id from locale in TEB + // (4) use lang id from user's locale id + // (5) use primary language of user's locale id + // (6) use lang id from system default locale id + // (7) use primary language of system default locale id + // (8) use US English lang id + // (9) use any lang id that matches requested info + // + if (ResourceIdPathLength == 0 && IdPathLength == 3) { + LanguageResourceDirectory = ResourceDirectory; + } + + if (LanguageResourceDirectory != NULL) { + GivenLanguage = (LANGID)IdPath[ 2 ]; + fIsNeutral = (PRIMARYLANGID( GivenLanguage ) == LANG_NEUTRAL); +TryNextLangId: + switch( RetryCount++ ) { + case 0: // Use given language id + NewLangId = GivenLanguage; + break; + + case 1: // Use primary language of given language id + NewLangId = PRIMARYLANGID( GivenLanguage ); + break; + + case 2: // Use id 0 (neutral resource) + NewLangId = LANG_USER_DEFAULT; + NewLangId = LANG_SYSTEM_DEFAULT; + NewLangId = 0; + break; + + case 3: // Use lang id from locale in TEB + if ( !fIsNeutral ) { + // Stop looking - Not in the neutral case + goto ReturnFailure; + break; + } + + if (SUBLANGID( GivenLanguage ) == SUBLANG_SYS_DEFAULT) { + // Skip over all USER locale options + DefaultThreadLocale = 0; + RetryCount += 2; + break; + } + + if (NtCurrentTeb() != NULL) { + NewLangId = LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale); + } + break; + + case 4: // Use User's default locale + Status = NtQueryDefaultLocale( TRUE, &DefaultThreadLocale ); + if (NT_SUCCESS( Status )) { + NewLangId = LANGIDFROMLCID(DefaultThreadLocale); + break; + } + + RetryCount++; + break; + + case 5: // Use primary language of User's default locale + NewLangId = PRIMARYLANGID( (LANGID)ResourceIdRetry ); + break; + + case 6: // Use System default locale + Status = NtQueryDefaultLocale( FALSE, &DefaultSystemLocale ); + if (!NT_SUCCESS( Status )) { + RetryCount++; + break; + } + + if (DefaultSystemLocale != DefaultThreadLocale) { + NewLangId = LANGIDFROMLCID(DefaultSystemLocale); + break; + } + + RetryCount += 2; + // fall through + + case 8: // Use US English language + NewLangId = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ); + break; + + case 7: // Use primary language of System default locale + NewLangId = PRIMARYLANGID( (LANGID)ResourceIdRetry ); + break; + + case 9: // Take any lang id that matches + NewLangId = USE_FIRSTAVAILABLE_LANGID; + break; + + default: // No lang ids to match + goto ReturnFailure; + break; + } + + // + // If looking for a specific language id and same as the + // one we just looked up, then skip it. + // + if (NewLangId != USE_FIRSTAVAILABLE_LANGID && + NewLangId == ResourceIdRetry + ) { + goto TryNextLangId; + } + + // + // Try this new language Id + // + ResourceIdRetry = (ULONG)NewLangId; + ResourceIdPath = &ResourceIdRetry; + ResourceDirectory = LanguageResourceDirectory; + } + + n = ResourceDirectory->NumberOfNamedEntries; + ResourceDirEntLow = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResourceDirectory+1); + if (!(*ResourceIdPath & LDR_RESOURCE_ID_NAME_MASK)) { + ResourceDirEntLow += n; + n = ResourceDirectory->NumberOfIdEntries; + } + + if (!n) { + ResourceDirectory = NULL; + goto NotFound; + } + + if (LanguageResourceDirectory != NULL && + *ResourceIdPath == USE_FIRSTAVAILABLE_LANGID + ) { + ResourceDirectory = NULL; + ResourceIdRetry = ResourceDirEntLow->Name; + ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY) + ((PCHAR)TopResourceDirectory + + ResourceDirEntLow->OffsetToData + ); + + break; + } + + ResourceDirectory = NULL; + ResourceDirEntHigh = ResourceDirEntLow + n - 1; + while (ResourceDirEntLow <= ResourceDirEntHigh) { + if ((half = (n >> 1)) != 0) { + ResourceDirEntMiddle = ResourceDirEntLow; + if (*(PUCHAR)&n & 1) { + ResourceDirEntMiddle += half; + } + else { + ResourceDirEntMiddle += half - 1; + } + dir = LdrpCompareResourceNames_U( *ResourceIdPath, + TopResourceDirectory, + ResourceDirEntMiddle + ); + if (!dir) { + if (ResourceDirEntMiddle->DataIsDirectory) { + ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) + ((PCHAR)TopResourceDirectory + + ResourceDirEntMiddle->OffsetToDirectory + ); + } + else { + ResourceDirectory = NULL; + ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY) + ((PCHAR)TopResourceDirectory + + ResourceDirEntMiddle->OffsetToData + ); + } + + break; + } + else { + if (dir < 0) { + ResourceDirEntHigh = ResourceDirEntMiddle - 1; + if (*(PUCHAR)&n & 1) { + n = half; + } + else { + n = half - 1; + } + } + else { + ResourceDirEntLow = ResourceDirEntMiddle + 1; + n = half; + } + } + } + else { + if (n != 0) { + dir = LdrpCompareResourceNames_U( *ResourceIdPath, + TopResourceDirectory, + ResourceDirEntLow + ); + if (!dir) { + if (ResourceDirEntLow->DataIsDirectory) { + ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) + ((PCHAR)TopResourceDirectory + + ResourceDirEntLow->OffsetToDirectory + ); + } + else { + ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY) + ((PCHAR)TopResourceDirectory + + ResourceDirEntLow->OffsetToData + ); + } + } + } + + break; + } + } + + ResourceIdPath++; + } + + if (ResourceEntry != NULL && !FindDirectoryEntry) { + *ResourceDirectoryOrData = (PVOID)ResourceEntry; + Status = STATUS_SUCCESS; + } + else + if (ResourceDirectory != NULL && FindDirectoryEntry) { + *ResourceDirectoryOrData = (PVOID)ResourceDirectory; + Status = STATUS_SUCCESS; + } + else { +NotFound: + switch( IdPathLength - ResourceIdPathLength) { + case 3: Status = STATUS_RESOURCE_LANG_NOT_FOUND; break; + case 2: Status = STATUS_RESOURCE_NAME_NOT_FOUND; break; + case 1: Status = STATUS_RESOURCE_TYPE_NOT_FOUND; break; + default: Status = STATUS_INVALID_PARAMETER; break; + } + } + + if (Status == STATUS_RESOURCE_LANG_NOT_FOUND && + LanguageResourceDirectory != NULL + ) { + ResourceEntry = NULL; + goto TryNextLangId; +ReturnFailure: ; + } + } + except (EXCEPTION_EXECUTE_HANDLER) { + Status = GetExceptionCode(); + } + + return Status; +} + +NTSTATUS +LdrEnumResources( + IN PVOID DllHandle, + IN PULONG ResourceIdPath, + IN ULONG ResourceIdPathLength, + IN OUT PULONG NumberOfResources, + OUT PLDR_ENUM_RESOURCE_ENTRY Resources OPTIONAL + ) +{ + NTSTATUS Status; + PIMAGE_RESOURCE_DIRECTORY TopResourceDirectory; + PIMAGE_RESOURCE_DIRECTORY TypeResourceDirectory; + PIMAGE_RESOURCE_DIRECTORY NameResourceDirectory; + PIMAGE_RESOURCE_DIRECTORY LangResourceDirectory; + PIMAGE_RESOURCE_DIRECTORY_ENTRY TypeResourceDirectoryEntry; + PIMAGE_RESOURCE_DIRECTORY_ENTRY NameResourceDirectoryEntry; + PIMAGE_RESOURCE_DIRECTORY_ENTRY LangResourceDirectoryEntry; + ULONG TypeDirectoryIndex, NumberOfTypeDirectoryEntries; + ULONG NameDirectoryIndex, NumberOfNameDirectoryEntries; + ULONG LangDirectoryIndex, NumberOfLangDirectoryEntries; + BOOLEAN ScanTypeDirectory; + BOOLEAN ScanNameDirectory; + BOOLEAN ReturnThisResource; + PIMAGE_RESOURCE_DIR_STRING_U ResourceNameString; + ULONG TypeResourceNameOrId; + ULONG NameResourceNameOrId; + ULONG LangResourceNameOrId; + PLDR_ENUM_RESOURCE_ENTRY ResourceInfo; + PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry; + ULONG ResourceIndex, MaxResourceIndex; + ULONG Size; + + ResourceIndex = 0; + if (!ARGUMENT_PRESENT( Resources )) { + MaxResourceIndex = 0; + } + else { + MaxResourceIndex = *NumberOfResources; + } + *NumberOfResources = 0; + + TopResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) + RtlImageDirectoryEntryToData( DllHandle, + TRUE, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + &Size + ); + if (!TopResourceDirectory) { + return STATUS_RESOURCE_DATA_NOT_FOUND; + } + + TypeResourceDirectory = TopResourceDirectory; + TypeResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(TypeResourceDirectory+1); + NumberOfTypeDirectoryEntries = TypeResourceDirectory->NumberOfNamedEntries + + TypeResourceDirectory->NumberOfIdEntries; + TypeDirectoryIndex = 0; + Status = STATUS_SUCCESS; + for (TypeDirectoryIndex=0; + TypeDirectoryIndex<NumberOfTypeDirectoryEntries; + TypeDirectoryIndex++, TypeResourceDirectoryEntry++ + ) { + if (ResourceIdPathLength > 0) { + ScanTypeDirectory = LdrpCompareResourceNames_U( ResourceIdPath[ 0 ], + TopResourceDirectory, + TypeResourceDirectoryEntry + ) == 0; + } + else { + ScanTypeDirectory = TRUE; + } + if (ScanTypeDirectory) { + if (!TypeResourceDirectoryEntry->DataIsDirectory) { + return STATUS_INVALID_IMAGE_FORMAT; + } + if (TypeResourceDirectoryEntry->NameIsString) { + ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) + ((PCHAR)TopResourceDirectory + TypeResourceDirectoryEntry->NameOffset); + + TypeResourceNameOrId = (ULONG)ResourceNameString; + } + else { + TypeResourceNameOrId = (ULONG)TypeResourceDirectoryEntry->Id; + } + + NameResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) + ((PCHAR)TopResourceDirectory + TypeResourceDirectoryEntry->OffsetToDirectory); + NameResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(NameResourceDirectory+1); + NumberOfNameDirectoryEntries = NameResourceDirectory->NumberOfNamedEntries + + NameResourceDirectory->NumberOfIdEntries; + NameDirectoryIndex = 0; + for (NameDirectoryIndex=0; + NameDirectoryIndex<NumberOfNameDirectoryEntries; + NameDirectoryIndex++, NameResourceDirectoryEntry++ + ) { + if (ResourceIdPathLength > 1) { + ScanNameDirectory = LdrpCompareResourceNames_U( ResourceIdPath[ 1 ], + TopResourceDirectory, + NameResourceDirectoryEntry + ) == 0; + } + else { + ScanNameDirectory = TRUE; + } + if (ScanNameDirectory) { + if (!NameResourceDirectoryEntry->DataIsDirectory) { + return STATUS_INVALID_IMAGE_FORMAT; + } + + if (NameResourceDirectoryEntry->NameIsString) { + ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) + ((PCHAR)TopResourceDirectory + NameResourceDirectoryEntry->NameOffset); + + NameResourceNameOrId = (ULONG)ResourceNameString; + } + else { + NameResourceNameOrId = (ULONG)NameResourceDirectoryEntry->Id; + } + + LangResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) + ((PCHAR)TopResourceDirectory + NameResourceDirectoryEntry->OffsetToDirectory); + + LangResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(LangResourceDirectory+1); + NumberOfLangDirectoryEntries = LangResourceDirectory->NumberOfNamedEntries + + LangResourceDirectory->NumberOfIdEntries; + LangDirectoryIndex = 0; + for (LangDirectoryIndex=0; + LangDirectoryIndex<NumberOfLangDirectoryEntries; + LangDirectoryIndex++, LangResourceDirectoryEntry++ + ) { + if (ResourceIdPathLength > 2) { + ReturnThisResource = LdrpCompareResourceNames_U( ResourceIdPath[ 2 ], + TopResourceDirectory, + LangResourceDirectoryEntry + ) == 0; + } + else { + ReturnThisResource = TRUE; + } + if (ReturnThisResource) { + if (LangResourceDirectoryEntry->DataIsDirectory) { + return STATUS_INVALID_IMAGE_FORMAT; + } + + if (LangResourceDirectoryEntry->NameIsString) { + ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) + ((PCHAR)TopResourceDirectory + LangResourceDirectoryEntry->NameOffset); + + LangResourceNameOrId = (ULONG)ResourceNameString; + } + else { + LangResourceNameOrId = (ULONG)LangResourceDirectoryEntry->Id; + } + + ResourceDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY) + ((PCHAR)TopResourceDirectory + LangResourceDirectoryEntry->OffsetToData); + + ResourceInfo = &Resources[ ResourceIndex++ ]; + if (ResourceIndex <= MaxResourceIndex) { + ResourceInfo->Path[ 0 ].NameOrId = TypeResourceNameOrId; + ResourceInfo->Path[ 1 ].NameOrId = NameResourceNameOrId; + ResourceInfo->Path[ 2 ].NameOrId = LangResourceNameOrId; + ResourceInfo->Data = (PVOID)((ULONG)DllHandle + ResourceDataEntry->OffsetToData); + ResourceInfo->Size = ResourceDataEntry->Size; + ResourceInfo->Reserved = 0; + } + else { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + } + } + } + } + } + } + + *NumberOfResources = ResourceIndex; + return Status; +} |