3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/res.c
6 * PURPOSE: Resource access for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 * Robert Dickenson (robd@mok.lvcm.com)
10 * NOTES: Parts based on Wine code
11 * Copyright 1995 Thomas Sandford
12 * Copyright 1996 Martin von Loewis
13 * Copyright 2003 Alexandre Julliard
14 * Copyright 1993 Robert J. Amstadt
15 * Copyright 1995 Alexandre Julliard
16 * Copyright 1997 Marcus Meissner
24 /* INCLUDES *****************************************************************/
30 /* PROTOTYPES ****************************************************************/
34 /* FUNCTIONS *****************************************************************/
36 static PIMAGE_RESOURCE_DIRECTORY_ENTRY FASTCALL
37 FindEntryById(PIMAGE_RESOURCE_DIRECTORY ResDir
,
40 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
41 LONG low
, high
, mid
, result
;
43 /* We use ID number instead of string */
44 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1) + ResDir
->NumberOfNamedEntries
;
45 DPRINT("ResEntry %x - Resource ID number instead of string\n", (ULONG
)ResEntry
);
46 DPRINT("EntryCount %d\n", (ULONG
)ResDir
->NumberOfIdEntries
);
49 high
= ResDir
->NumberOfIdEntries
- 1;
51 while( low
<= high
) {
52 result
= Id
- ResEntry
[mid
].Name
;
54 return ResEntry
+ mid
;
67 PushLanguage(WORD
*list
, int pos
, WORD lang
)
71 for (i
= 0; i
< pos
; i
++) {
72 if (list
[i
] == lang
) {
83 Status = LdrFindResource_U (hModule,
89 LdrFindResource_U(PVOID BaseAddress
,
90 PLDR_RESOURCE_INFO ResourceInfo
,
92 PIMAGE_RESOURCE_DATA_ENTRY
* ResourceDataEntry
)
94 PIMAGE_RESOURCE_DIRECTORY ResDir
;
95 PIMAGE_RESOURCE_DIRECTORY ResBase
;
96 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
97 NTSTATUS Status
= STATUS_SUCCESS
;
101 LONG low
, high
, mid
, result
;
102 WORD list
[9]; /* list of languages to try */
104 LCID UserLCID
, SystemLCID
;
105 LANGID UserLangID
, SystemLangID
;
106 BOOLEAN MappedAsDataFile
;
108 MappedAsDataFile
= LdrMappedAsDataFile(&BaseAddress
);
109 DPRINT("LdrFindResource_U(%08x, %08x, %d, %08x)\n", BaseAddress
, ResourceInfo
, Level
, ResourceDataEntry
);
111 /* Get the pointer to the resource directory */
112 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)RtlImageDirectoryEntryToData(BaseAddress
,
113 ! MappedAsDataFile
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &i
);
114 if (ResDir
== NULL
) {
115 return STATUS_RESOURCE_DATA_NOT_FOUND
;
118 DPRINT("ResourceDirectory: %x Size: %d\n", (ULONG
)ResDir
, (int)i
);
122 /* Let's go into resource tree */
123 for (i
= 0; i
< (2 < Level
? 2 : Level
); i
++) {
124 DPRINT("ResDir: %x Level: %d\n", (ULONG
)ResDir
, i
);
126 Id
= ((PULONG
)ResourceInfo
)[i
];
128 if (Id
& 0xFFFF0000) {
129 /* Resource name is a unicode string */
130 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
131 DPRINT("ResEntry %x - Resource name is a unicode string\n", (ULONG
)ResEntry
);
132 DPRINT("EntryCount %d\n", (ULONG
)ResDir
->NumberOfNamedEntries
);
135 high
= ResDir
->NumberOfNamedEntries
- 1;
137 while( low
<= high
) {
138 /* Does we need check if it's named entry, think not */
139 ws
= (PWCHAR
)((ULONG
)ResBase
+ (ResEntry
[mid
].Name
& 0x7FFFFFFF));
140 result
= _wcsnicmp((PWCHAR
)Id
, ws
+ 1, *ws
);
141 /* Need double check for lexical & length */
143 result
= (wcslen((PWCHAR
)Id
) - (int)*ws
);
154 mid
= (low
+ high
)/2;
157 /* We use ID number instead of string */
158 ResEntry
= FindEntryById(ResDir
, Id
);
159 if (NULL
!= ResEntry
) goto found
;
164 DPRINT("Error %lu - STATUS_RESOURCE_TYPE_NOT_FOUND\n", i
);
165 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
167 DPRINT("Error %lu - STATUS_RESOURCE_NAME_NOT_FOUND\n", i
);
168 return STATUS_RESOURCE_NAME_NOT_FOUND
;
170 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
) {
171 /* Use the first available language */
172 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
175 DPRINT("Error %lu - STATUS_RESOURCE_LANG_NOT_FOUND\n", i
);
176 return STATUS_RESOURCE_LANG_NOT_FOUND
;
178 DPRINT("Error %lu - STATUS_RESOURCE_DATA_NOT_FOUND\n", i
);
179 return STATUS_RESOURCE_DATA_NOT_FOUND
;
181 DPRINT("Error %lu - STATUS_INVALID_PARAMETER\n", i
);
182 return STATUS_INVALID_PARAMETER
;
185 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResBase
+
186 (ResEntry
->OffsetToData
& 0x7FFFFFFF));
190 /* 1. specified language */
191 pos
= PushLanguage(list
, pos
, ResourceInfo
->Language
);
193 /* 2. specified language with neutral sublanguage */
194 pos
= PushLanguage(list
, pos
, MAKELANGID(PRIMARYLANGID(ResourceInfo
->Language
), SUBLANG_NEUTRAL
));
196 /* 3. neutral language with neutral sublanguage */
197 pos
= PushLanguage(list
, pos
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
));
199 /* if no explicitly specified language, try some defaults */
200 if (LANG_NEUTRAL
== PRIMARYLANGID(ResourceInfo
->Language
)) {
201 /* user defaults, unless SYS_DEFAULT sublanguage specified */
202 if (SUBLANG_SYS_DEFAULT
!= SUBLANGID(ResourceInfo
->Language
)) {
203 NtQueryDefaultLocale(TRUE
, &UserLCID
);
204 UserLangID
= LANGIDFROMLCID(UserLCID
);
206 /* 4. current thread locale language */
207 pos
= PushLanguage(list
, pos
, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale
));
209 /* 5. user locale language */
210 pos
= PushLanguage(list
, pos
, UserLangID
);
212 /* 6. user locale language with neutral sublanguage */
213 pos
= PushLanguage(list
, pos
, MAKELANGID(PRIMARYLANGID(UserLangID
),
217 /* now system defaults */
218 NtQueryDefaultLocale(FALSE
, &SystemLCID
);
219 SystemLangID
= LANGIDFROMLCID(SystemLCID
);
221 /* 7. system locale language */
222 pos
= PushLanguage(list
, pos
, SystemLangID
);
224 /* 8. system locale language with neutral sublanguage */
225 pos
= PushLanguage(list
, pos
, MAKELANGID(PRIMARYLANGID(SystemLangID
),
229 pos
= PushLanguage(list
, pos
, MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
));
233 for (j
= 0; NULL
== ResEntry
&& j
< pos
; j
++)
234 ResEntry
= FindEntryById(ResDir
, list
[j
]);
235 if (NULL
== ResEntry
) {
236 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
) {
237 /* Use the first available language */
238 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
240 DPRINT("Error - STATUS_RESOURCE_LANG_NOT_FOUND\n", i
);
241 return STATUS_RESOURCE_LANG_NOT_FOUND
;
244 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResBase
+
245 (ResEntry
->OffsetToData
& 0x7FFFFFFF));
247 DPRINT("Error - STATUS_INVALID_PARAMETER\n", i
);
248 return STATUS_INVALID_PARAMETER
;
251 DPRINT("ResourceDataEntry: %x\n", (ULONG
)ResDir
);
253 if (ResourceDataEntry
) {
254 *ResourceDataEntry
= (PVOID
)ResDir
;
264 LdrAccessResource(IN PVOID BaseAddress
,
265 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
,
266 OUT PVOID
* Resource OPTIONAL
,
267 OUT PULONG Size OPTIONAL
)
269 PIMAGE_SECTION_HEADER Section
;
270 PIMAGE_NT_HEADERS NtHeader
;
276 BOOLEAN MappedAsDataFile
;
278 if(!ResourceDataEntry
)
279 return STATUS_RESOURCE_DATA_NOT_FOUND
;
281 MappedAsDataFile
= LdrMappedAsDataFile(&BaseAddress
);
282 Data
= (ULONG
)RtlImageDirectoryEntryToData(BaseAddress
,
283 TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &DataSize
);
285 return STATUS_RESOURCE_DATA_NOT_FOUND
;
287 if (MappedAsDataFile
) {
288 /* loaded as ordinary file */
289 NtHeader
= RtlImageNtHeader(BaseAddress
);
290 Offset
= (ULONG
)BaseAddress
- Data
+ NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
291 Section
= RtlImageRvaToSection(NtHeader
, BaseAddress
, NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
);
292 if (Section
== NULL
) {
293 return STATUS_RESOURCE_DATA_NOT_FOUND
;
295 if (Section
->Misc
.VirtualSize
< ResourceDataEntry
->OffsetToData
) {
296 SectionRva
= RtlImageRvaToSection (NtHeader
, BaseAddress
, ResourceDataEntry
->OffsetToData
)->VirtualAddress
;
297 SectionVa
= RtlImageRvaToVa(NtHeader
, BaseAddress
, SectionRva
, NULL
);
298 Offset
= SectionRva
- SectionVa
+ Data
- Section
->VirtualAddress
;
302 *Resource
= (PVOID
)(ResourceDataEntry
->OffsetToData
- Offset
+ (ULONG
)BaseAddress
);
305 *Size
= ResourceDataEntry
->Size
;
307 return STATUS_SUCCESS
;
315 LdrFindResourceDirectory_U(IN PVOID BaseAddress
,
316 IN PLDR_RESOURCE_INFO info
,
318 OUT PIMAGE_RESOURCE_DIRECTORY
* addr
)
320 PIMAGE_RESOURCE_DIRECTORY ResDir
;
321 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
324 NTSTATUS Status
= STATUS_SUCCESS
;
326 PWCHAR
* name
= (PWCHAR
*) info
;
328 /* Get the pointer to the resource directory */
329 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
330 RtlImageDirectoryEntryToData(BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &i
);
331 if (ResDir
== NULL
) {
332 return STATUS_RESOURCE_DATA_NOT_FOUND
;
335 /* Let's go into resource tree */
336 for (i
= 0; i
< level
; i
++, name
++) {
337 EntryCount
= ResDir
->NumberOfNamedEntries
;
338 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
339 if ((ULONG
)(*name
) & 0xFFFF0000) {
340 /* Resource name is a unicode string */
341 for (; EntryCount
--; ResEntry
++) {
342 /* Scan entries for equal name */
343 if (ResEntry
->Name
& 0x80000000) {
344 ws
= (WCHAR
*)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
345 if (!wcsncmp(*name
, ws
+ 1, *ws
) && wcslen(*name
) == (int)*ws
) {
351 /* We use ID number instead of string */
352 ResEntry
+= EntryCount
;
353 EntryCount
= ResDir
->NumberOfIdEntries
;
354 for (; EntryCount
--; ResEntry
++) {
355 /* Scan entries for equal name */
356 if (ResEntry
->Name
== (ULONG
)(*name
))
362 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
364 return STATUS_RESOURCE_NAME_NOT_FOUND
;
366 Status
= STATUS_RESOURCE_LANG_NOT_FOUND
;
367 /* Just use first language entry */
368 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
) {
369 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
374 return STATUS_RESOURCE_DATA_NOT_FOUND
;
376 return STATUS_INVALID_PARAMETER
;
379 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResDir
+ ResEntry
->OffsetToData
);
382 *addr
= (PVOID
)ResDir
;