[CMAKE]: Simplify makefiles.
[reactos.git] / lib / rtl / res.c
1 /*
2 * PE file resources
3 *
4 * Copyright 1995 Thomas Sandford
5 * Copyright 1996 Martin von Loewis
6 * Copyright 2003 Alexandre Julliard
7 * Copyright 1993 Robert J. Amstadt
8 * Copyright 1997 Marcus Meissner
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /* INCLUDES *****************************************************************/
26
27 #include <rtl.h>
28
29 #define NDEBUG
30 #include <debug.h>
31
32 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
33 ULONG level, void **ret, int want_dir );
34
35 /* FUNCTIONS ****************************************************************/
36
37 int page_fault(ULONG ExceptionCode)
38 {
39 if (ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
40 ExceptionCode == EXCEPTION_PRIV_INSTRUCTION)
41 return EXCEPTION_EXECUTE_HANDLER;
42 return EXCEPTION_CONTINUE_SEARCH;
43 }
44
45 /**********************************************************************
46 * is_data_file_module
47 *
48 * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
49 */
50 static int is_data_file_module( PVOID BaseAddress )
51 {
52 return (ULONG_PTR)BaseAddress & 1;
53 }
54
55
56 /**********************************************************************
57 * push_language
58 *
59 * push a language in the list of languages to try
60 */
61 int push_language( USHORT *list, ULONG pos, WORD lang )
62 {
63 ULONG i;
64 for (i = 0; i < pos; i++) if (list[i] == lang) return pos;
65 list[pos++] = lang;
66 return pos;
67 }
68
69
70 /**********************************************************************
71 * find_first_entry
72 *
73 * Find the first suitable entry in a resource directory
74 */
75 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
76 void *root, int want_dir )
77 {
78 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
79 int pos;
80
81 for (pos = 0; pos < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; pos++)
82 {
83 if (!entry[pos].DataIsDirectory == !want_dir)
84 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].OffsetToDirectory);
85 }
86 return NULL;
87 }
88
89
90 /**********************************************************************
91 * find_entry_by_id
92 *
93 * Find an entry by id in a resource directory
94 */
95 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
96 WORD id, void *root, int want_dir )
97 {
98 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
99 int min, max, pos;
100
101 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
102 min = dir->NumberOfNamedEntries;
103 max = min + dir->NumberOfIdEntries - 1;
104 while (min <= max)
105 {
106 pos = (min + max) / 2;
107 if (entry[pos].Id == id)
108 {
109 if (!entry[pos].DataIsDirectory == !want_dir)
110 {
111 DPRINT("root %p dir %p id %04x ret %p\n",
112 root, dir, id, (const char*)root + entry[pos].OffsetToDirectory);
113 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].OffsetToDirectory);
114 }
115 break;
116 }
117 if (entry[pos].Id > id) max = pos - 1;
118 else min = pos + 1;
119 }
120 DPRINT("root %p dir %p id %04x not found\n", root, dir, id );
121 return NULL;
122 }
123
124
125 /**********************************************************************
126 * find_entry_by_name
127 *
128 * Find an entry by name in a resource directory
129 */
130 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
131 LPCWSTR name, void *root,
132 int want_dir )
133 {
134 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
135 const IMAGE_RESOURCE_DIR_STRING_U *str;
136 int min, max, res, pos, namelen;
137
138 if (!((ULONG_PTR)name & 0xFFFF0000)) return find_entry_by_id( dir, (ULONG_PTR)name & 0xFFFF, root, want_dir );
139 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
140 namelen = wcslen(name);
141 min = 0;
142 max = dir->NumberOfNamedEntries - 1;
143 while (min <= max)
144 {
145 pos = (min + max) / 2;
146 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const char *)root + entry[pos].NameOffset);
147 res = _wcsnicmp( name, str->NameString, str->Length );
148 if (!res && namelen == str->Length)
149 {
150 if (!entry[pos].DataIsDirectory == !want_dir)
151 {
152 DPRINT("root %p dir %p name %ws ret %p\n",
153 root, dir, name, (const char*)root + entry[pos].OffsetToDirectory);
154 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].OffsetToDirectory);
155 }
156 break;
157 }
158 if (res < 0) max = pos - 1;
159 else min = pos + 1;
160 }
161 DPRINT("root %p dir %p name %ws not found\n", root, dir, name);
162 return NULL;
163 }
164
165 #ifdef __i386__
166 NTSTATUS NTAPI LdrpAccessResource( PVOID BaseAddress, IMAGE_RESOURCE_DATA_ENTRY *entry,
167 void **ptr, ULONG *size )
168 #else
169 static NTSTATUS LdrpAccessResource( PVOID BaseAddress, IMAGE_RESOURCE_DATA_ENTRY *entry,
170 void **ptr, ULONG *size )
171 #endif
172 {
173 NTSTATUS status = STATUS_SUCCESS;
174
175 _SEH2_TRY
176 {
177 ULONG dirsize;
178
179 if (!RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &dirsize ))
180 status = STATUS_RESOURCE_DATA_NOT_FOUND;
181 else
182 {
183 if (ptr)
184 {
185 if (is_data_file_module(BaseAddress))
186 {
187 PVOID mod = (PVOID)((ULONG_PTR)BaseAddress & ~1);
188 *ptr = RtlImageRvaToVa( RtlImageNtHeader(mod), mod, entry->OffsetToData, NULL );
189 }
190 else *ptr = (char *)BaseAddress + entry->OffsetToData;
191 }
192 if (size) *size = entry->Size;
193 }
194 }
195 _SEH2_EXCEPT(page_fault(_SEH2_GetExceptionCode()))
196 {
197 status = _SEH2_GetExceptionCode();
198 }
199 _SEH2_END;
200 return status;
201 }
202
203
204 /*
205 * @implemented
206 */
207 NTSTATUS NTAPI
208 LdrFindResource_U(PVOID BaseAddress,
209 PLDR_RESOURCE_INFO ResourceInfo,
210 ULONG Level,
211 PIMAGE_RESOURCE_DATA_ENTRY* ResourceDataEntry)
212 {
213 void *res;
214 NTSTATUS status = STATUS_SUCCESS;
215
216 _SEH2_TRY
217 {
218 if (ResourceInfo)
219 {
220 DPRINT( "module %p type %ws name %ws lang %04lx level %ld\n",
221 BaseAddress, (LPCWSTR)ResourceInfo->Type,
222 Level > 1 ? (LPCWSTR)ResourceInfo->Name : L"",
223 Level > 2 ? ResourceInfo->Language : 0, Level );
224 }
225
226 status = find_entry( BaseAddress, ResourceInfo, Level, &res, FALSE );
227 if (status == STATUS_SUCCESS) *ResourceDataEntry = res;
228 }
229 _SEH2_EXCEPT(page_fault(_SEH2_GetExceptionCode()))
230 {
231 status = _SEH2_GetExceptionCode();
232 }
233 _SEH2_END;
234 return status;
235 }
236
237 #ifndef __i386__
238 /*
239 * @implemented
240 */
241 NTSTATUS NTAPI
242 LdrAccessResource(IN PVOID BaseAddress,
243 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
244 OUT PVOID* Resource OPTIONAL,
245 OUT PULONG Size OPTIONAL)
246 {
247 return LdrpAccessResource( BaseAddress, ResourceDataEntry, Resource, Size );
248 }
249 #endif
250
251 /*
252 * @implemented
253 */
254 NTSTATUS NTAPI
255 LdrFindResourceDirectory_U(IN PVOID BaseAddress,
256 IN PLDR_RESOURCE_INFO info,
257 IN ULONG level,
258 OUT PIMAGE_RESOURCE_DIRECTORY* addr)
259 {
260 void *res;
261 NTSTATUS status = STATUS_SUCCESS;
262
263 _SEH2_TRY
264 {
265 if (info)
266 {
267 DPRINT( "module %p type %ws name %ws lang %04lx level %ld\n",
268 BaseAddress, (LPCWSTR)info->Type,
269 level > 1 ? (LPCWSTR)info->Name : L"",
270 level > 2 ? info->Language : 0, level );
271 }
272
273 status = find_entry( BaseAddress, info, level, &res, TRUE );
274 if (status == STATUS_SUCCESS) *addr = res;
275 }
276 _SEH2_EXCEPT(page_fault(_SEH2_GetExceptionCode()))
277 {
278 status = _SEH2_GetExceptionCode();
279 }
280 _SEH2_END;
281 return status;
282 }
283
284
285 /*
286 * @unimplemented
287 */
288 NTSTATUS NTAPI
289 LdrEnumResources(IN PVOID BaseAddress,
290 IN PLDR_RESOURCE_INFO ResourceInfo,
291 IN ULONG Level,
292 IN OUT PULONG ResourceCount,
293 OUT PVOID Resources OPTIONAL)
294 {
295 UNIMPLEMENTED;
296 return STATUS_NOT_IMPLEMENTED;
297 }