update for HEAD-2003091401
[reactos.git] / lib / ntdll / ldr / res.c
1 /* $Id$
2  * 
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  */
11
12 /*
13  * TODO:
14  *  - any comments ??
15  */
16
17 /* INCLUDES *****************************************************************/
18
19 #include <reactos/config.h>
20 #include <ddk/ntddk.h>
21 #include <windows.h>
22 #include <string.h>
23 #include <wchar.h>
24 #include <ntdll/ldr.h>
25 #include <ntos/minmax.h>
26
27 #define NDEBUG
28 #include <ntdll/ntdll.h>
29
30 /* PROTOTYPES ****************************************************************/
31
32
33
34 /* FUNCTIONS *****************************************************************/
35
36 /*
37         Status = LdrFindResource_U (hModule,
38                                     &ResourceInfo,
39                                     RESOURCE_DATA_LEVEL,
40                                     &ResourceDataEntry);
41  */
42 NTSTATUS STDCALL
43 LdrFindResource_U(PVOID BaseAddress,
44                   PLDR_RESOURCE_INFO ResourceInfo,
45                   ULONG Level,
46                   PIMAGE_RESOURCE_DATA_ENTRY* ResourceDataEntry)
47 {
48     PIMAGE_RESOURCE_DIRECTORY ResDir;
49     PIMAGE_RESOURCE_DIRECTORY ResBase;
50     PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
51     NTSTATUS Status = STATUS_SUCCESS;
52     ULONG EntryCount;
53     PWCHAR ws;
54     ULONG i;
55     ULONG Id;
56
57     //DPRINT("LdrFindResource_U()\n");
58     DPRINT("LdrFindResource_U(%08x, %08x, %d, %08x)\n", BaseAddress, ResourceInfo, Level, ResourceDataEntry);
59
60     /* Get the pointer to the resource directory */
61     ResDir = (PIMAGE_RESOURCE_DIRECTORY)RtlImageDirectoryEntryToData(BaseAddress,
62                       TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &i);
63     if (ResDir == NULL) {
64         return STATUS_RESOURCE_DATA_NOT_FOUND;
65     }
66
67     DPRINT("ResourceDirectory: %x  Size: %d\n", (ULONG)ResDir, (int)i);
68
69     ResBase = ResDir;
70
71     /* Let's go into resource tree */
72     for (i = 0; i < Level; i++) {
73         DPRINT("ResDir: %x  Level: %d\n", (ULONG)ResDir, i);
74
75         Id = ((PULONG)ResourceInfo)[i];
76 //      ResourceInfo.Type = (ULONG)lpType;
77 //      ResourceInfo.Name = (ULONG)lpName;
78 //      ResourceInfo.Language = (ULONG)wLanguage;
79
80         EntryCount = ResDir->NumberOfNamedEntries;
81         DPRINT("    Id: %d  NumberOfNamedEntries: %d\n", Id, EntryCount);
82         ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
83         //DPRINT("ResEntry %x\n", (ULONG)ResEntry);
84         if (Id & 0xFFFF0000) {
85             /* Resource name is a unicode string */
86             DPRINT("ResEntry %x - Resource name is a unicode string\n", (ULONG)ResEntry);
87             DPRINT("EntryCount %d\n", (ULONG)EntryCount);
88             for (; EntryCount--; ResEntry++) {
89                 /* Scan entries for equal name */
90                 if (ResEntry->Name & 0x80000000) {
91                     ws = (PWCHAR)((ULONG)ResBase + (ResEntry->Name & 0x7FFFFFFF));
92                     if (!_wcsnicmp((PWCHAR)Id, ws + 1, *ws) &&
93                           wcslen((PWCHAR)Id) == (int)*ws) {
94                         goto found;
95                     }
96                 }
97             }
98         } else {
99             /* We use ID number instead of string */
100             DPRINT("ResEntry %x - Resource ID number instead of string\n", (ULONG)ResEntry);
101             DPRINT("EntryCount %d\n", (ULONG)EntryCount);
102             ResEntry += EntryCount;
103             EntryCount = ResDir->NumberOfIdEntries;
104             DPRINT("EntryCount %d\n", (ULONG)EntryCount);
105             for (; EntryCount--; ResEntry++) {
106                 /* Scan entries for equal name */
107                 DPRINT("EntryCount %d  ResEntry %x\n", (ULONG)EntryCount, ResEntry);
108                 DPRINT("ResEntry->Name %x  Id %x\n", (ULONG)ResEntry->Name, Id);
109                 if (ResEntry->Name == Id) {
110                     DPRINT("ID entry found %x\n", Id);
111                     goto found;
112                 }
113             }
114         }
115
116         //DPRINT("Error %lu\n", i);
117
118         switch (i) {
119         case 0:
120             DPRINT("Error %lu - STATUS_RESOURCE_TYPE_NOT_FOUND\n", i);
121             return STATUS_RESOURCE_TYPE_NOT_FOUND;
122         case 1:
123             DPRINT("Error %lu - STATUS_RESOURCE_NAME_NOT_FOUND\n", i);
124             return STATUS_RESOURCE_NAME_NOT_FOUND;
125         case 2:
126             if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries) {
127                 /* Use the first available language */
128                 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
129                 break;
130             }
131             DPRINT("Error %lu - STATUS_RESOURCE_LANG_NOT_FOUND\n", i);
132             return STATUS_RESOURCE_LANG_NOT_FOUND;
133          case 3:
134             DPRINT("Error %lu - STATUS_RESOURCE_DATA_NOT_FOUND\n", i);
135             return STATUS_RESOURCE_DATA_NOT_FOUND;
136          default:
137             DPRINT("Error %lu - STATUS_INVALID_PARAMETER\n", i);
138             return STATUS_INVALID_PARAMETER;
139         }
140 found:;
141         ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
142                      (ResEntry->OffsetToData & 0x7FFFFFFF));
143     }
144     DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
145
146     if (ResourceDataEntry) {
147         *ResourceDataEntry = (PVOID)ResDir;
148     }
149     return Status;
150 }
151
152
153 /*
154  * @implemented
155  */
156 NTSTATUS STDCALL
157 LdrAccessResource(IN  PVOID BaseAddress,
158                   IN  PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
159                   OUT PVOID* Resource OPTIONAL,
160                   OUT PULONG Size OPTIONAL)
161 {
162     PIMAGE_SECTION_HEADER Section;
163     PIMAGE_NT_HEADERS NtHeader;
164     ULONG SectionRva;
165     ULONG SectionVa;
166     ULONG DataSize;
167     ULONG Offset = 0;
168     ULONG Data;
169
170     if(!ResourceDataEntry)
171         return STATUS_RESOURCE_DATA_NOT_FOUND;
172
173     Data = (ULONG)RtlImageDirectoryEntryToData(BaseAddress,
174                            TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &DataSize);
175     if (Data == 0) {
176         return STATUS_RESOURCE_DATA_NOT_FOUND;
177     }
178     if ((ULONG)BaseAddress & 1) {
179         /* loaded as ordinary file */
180         NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
181         Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
182         Section = RtlImageRvaToSection(NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
183         if (Section == NULL) {
184             return STATUS_RESOURCE_DATA_NOT_FOUND;
185         }
186         if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData) {
187             SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
188             SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
189             Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
190         }
191     }
192     if (Resource) {
193         *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
194     }
195     if (Size) {
196         *Size = ResourceDataEntry->Size;
197     }
198     return STATUS_SUCCESS;
199 }
200
201
202 /*
203  * @implemented
204  */
205 NTSTATUS STDCALL
206 LdrFindResourceDirectory_U(IN PVOID BaseAddress,
207                            WCHAR** name,
208                            DWORD level,
209                            OUT PVOID* addr)
210 {
211     PIMAGE_RESOURCE_DIRECTORY ResDir;
212     PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
213     ULONG EntryCount;
214     ULONG i;
215     NTSTATUS Status = STATUS_SUCCESS;
216     WCHAR* ws;
217
218     /* Get the pointer to the resource directory */
219     ResDir = (PIMAGE_RESOURCE_DIRECTORY)
220     RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &i);
221     if (ResDir == NULL) {
222         return STATUS_RESOURCE_DATA_NOT_FOUND;
223     }
224
225     /* Let's go into resource tree */
226     for (i = 0; i < level; i++, name++) {
227         EntryCount = ResDir->NumberOfNamedEntries;
228         ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
229         if ((ULONG)(*name) & 0xFFFF0000) {
230             /* Resource name is a unicode string */
231             for (; EntryCount--; ResEntry++) {
232                 /* Scan entries for equal name */
233                 if (ResEntry->Name & 0x80000000) {
234                     ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
235                     if (!wcsncmp(*name, ws + 1, *ws) && wcslen(*name) == (int)*ws) {
236                         goto found;
237                     }
238                 }
239             }
240         } else {
241             /* We use ID number instead of string */
242             ResEntry += EntryCount;
243             EntryCount = ResDir->NumberOfIdEntries;
244             for (; EntryCount--; ResEntry++) {
245                 /* Scan entries for equal name */
246                 if (ResEntry->Name == (ULONG)(*name))
247                     goto found;
248             }
249         }
250         switch (i) {
251         case 0:
252             return STATUS_RESOURCE_TYPE_NOT_FOUND;
253         case 1:
254             return STATUS_RESOURCE_NAME_NOT_FOUND;
255         case 2:
256             Status = STATUS_RESOURCE_LANG_NOT_FOUND;
257             /* Just use first language entry */
258             if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries) {
259                 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
260                 break;
261             }
262             return Status;
263         case 3:
264             return STATUS_RESOURCE_DATA_NOT_FOUND;
265         default:
266             return STATUS_INVALID_PARAMETER;
267         }
268 found:;
269         ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
270     }
271     if (addr) {
272         *addr = (PVOID)ResDir;
273     }
274     return Status;
275 }
276
277 /* EOF */