Merge 13159:13510 from trunk
[reactos.git] / reactos / ntoskrnl / ldr / resource.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ldr/resource.c
6 * PURPOSE: Resource loader
7 *
8 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS ****************************************************************/
18
19 /*
20 * @implemented
21 */
22 NTSTATUS STDCALL
23 LdrAccessResource(IN PVOID BaseAddress,
24 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
25 OUT PVOID *Resource OPTIONAL,
26 OUT PULONG Size OPTIONAL)
27 {
28 PIMAGE_SECTION_HEADER Section;
29 PIMAGE_NT_HEADERS NtHeader;
30 ULONG SectionRva;
31 ULONG SectionVa;
32 ULONG DataSize;
33 ULONG Offset = 0;
34 ULONG Data;
35
36 if(!ResourceDataEntry)
37 return STATUS_RESOURCE_DATA_NOT_FOUND;
38
39 Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
40 TRUE,
41 IMAGE_DIRECTORY_ENTRY_RESOURCE,
42 &DataSize);
43 if (Data == 0)
44 return STATUS_RESOURCE_DATA_NOT_FOUND;
45
46 if ((ULONG)BaseAddress & 1)
47 {
48 /* loaded as ordinary file */
49 NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
50 Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
51 Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
52 if (Section == NULL)
53 {
54 return STATUS_RESOURCE_DATA_NOT_FOUND;
55 }
56
57 if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
58 {
59 SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
60 SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
61 Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
62 }
63 }
64
65 if (Resource)
66 {
67 *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
68 }
69
70 if (Size)
71 {
72 *Size = ResourceDataEntry->Size;
73 }
74
75 return STATUS_SUCCESS;
76 }
77
78
79 /*
80 * @implemented
81 */
82 NTSTATUS STDCALL
83 LdrFindResource_U(PVOID BaseAddress,
84 PLDR_RESOURCE_INFO ResourceInfo,
85 ULONG Level,
86 PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
87 {
88 PIMAGE_RESOURCE_DIRECTORY ResDir;
89 PIMAGE_RESOURCE_DIRECTORY ResBase;
90 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
91 NTSTATUS Status = STATUS_SUCCESS;
92 ULONG EntryCount;
93 PWCHAR ws;
94 ULONG i;
95 ULONG Id;
96
97 DPRINT ("LdrFindResource_U()\n");
98
99 /* Get the pointer to the resource directory */
100 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
101 RtlImageDirectoryEntryToData (BaseAddress,
102 TRUE,
103 IMAGE_DIRECTORY_ENTRY_RESOURCE,
104 &i);
105 if (ResDir == NULL)
106 {
107 return STATUS_RESOURCE_DATA_NOT_FOUND;
108 }
109
110 DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
111
112 ResBase = ResDir;
113
114 /* Let's go into resource tree */
115 for (i = 0; i < Level; i++)
116 {
117 DPRINT("ResDir: %x\n", (ULONG)ResDir);
118 Id = ((PULONG)ResourceInfo)[i];
119 EntryCount = ResDir->NumberOfNamedEntries;
120 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
121 DPRINT("ResEntry %x\n", (ULONG)ResEntry);
122 if (Id & 0xFFFF0000)
123 {
124 /* Resource name is a unicode string */
125 for (; EntryCount--; ResEntry++)
126 {
127 /* Scan entries for equal name */
128 if (ResEntry->Name & 0x80000000)
129 {
130 ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
131 if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
132 wcslen((PWCHAR)Id) == (ULONG)*ws )
133 {
134 goto found;
135 }
136 }
137 }
138 }
139 else
140 {
141 /* We use ID number instead of string */
142 ResEntry += EntryCount;
143 EntryCount = ResDir->NumberOfIdEntries;
144 for (; EntryCount--; ResEntry++)
145 {
146 /* Scan entries for equal name */
147 if (ResEntry->Name == Id)
148 {
149 DPRINT("ID entry found %x\n", Id);
150 goto found;
151 }
152 }
153 }
154 DPRINT("Error %lu\n", i);
155
156 switch (i)
157 {
158 case 0:
159 return STATUS_RESOURCE_TYPE_NOT_FOUND;
160
161 case 1:
162 return STATUS_RESOURCE_NAME_NOT_FOUND;
163
164 case 2:
165 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
166 {
167 /* Use the first available language */
168 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
169 break;
170 }
171 return STATUS_RESOURCE_LANG_NOT_FOUND;
172
173 case 3:
174 return STATUS_RESOURCE_DATA_NOT_FOUND;
175
176 default:
177 return STATUS_INVALID_PARAMETER;
178 }
179 found:;
180 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
181 (ResEntry->OffsetToData & 0x7FFFFFFF));
182 }
183 DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
184
185 if (ResourceDataEntry)
186 {
187 *ResourceDataEntry = (PVOID)ResDir;
188 }
189
190 return Status;
191 }
192
193 /* STUBS */
194
195 /*
196 * @unimplemented
197 */
198 STDCALL
199 NTSTATUS
200 LdrFindResourceDirectory_U(
201 IN PVOID BaseAddress,
202 IN PLDR_RESOURCE_INFO ResourceInfo,
203 IN ULONG Level,
204 OUT PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory
205 )
206 {
207 UNIMPLEMENTED;
208 return STATUS_NOT_IMPLEMENTED;
209 }
210
211 /*
212 * @unimplemented
213 */
214 STDCALL
215 NTSTATUS
216 LdrEnumResources(
217 IN PVOID BaseAddress,
218 IN PLDR_RESOURCE_INFO ResourceInfo,
219 IN ULONG Level,
220 IN OUT PULONG ResourceCount,
221 OUT PVOID Resources OPTIONAL
222 )
223 {
224 UNIMPLEMENTED;
225 return STATUS_NOT_IMPLEMENTED;
226 }
227
228 /* EOF */