1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Test for LdrEnumResources
5  * PROGRAMMER:      Timo Kreuzer
6  */
7 
8 #include "precomp.h"
9 
10 typedef struct _TEST_RESOURCES
11 {
12     IMAGE_RESOURCE_DIRECTORY TypeDirectory;
13     IMAGE_RESOURCE_DIRECTORY_ENTRY TypeEntries[2];
14     IMAGE_RESOURCE_DIRECTORY Name1Directory;
15     IMAGE_RESOURCE_DIRECTORY_ENTRY Name1Entries[2];
16     IMAGE_RESOURCE_DIRECTORY Name2Directory;
17     IMAGE_RESOURCE_DIRECTORY_ENTRY Name2Entries[2];
18     IMAGE_RESOURCE_DIRECTORY Lang1Directory;
19     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang1Entries[2];
20     IMAGE_RESOURCE_DIRECTORY Lang2Directory;
21     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang2Entries[2];
22     IMAGE_RESOURCE_DIRECTORY Lang3Directory;
23     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang3Entries[2];
24     IMAGE_RESOURCE_DIRECTORY Lang4Directory;
25     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang4Entries[2];
26     IMAGE_RESOURCE_DATA_ENTRY DataEntries[8];
27     IMAGE_RESOURCE_DIRECTORY_STRING Name1String;
28     ULONG StringIndex;
29     WCHAR StringBuffer[20];
30 } TEST_RESOURCES, *PTEST_RESOURCES;
31 
32 typedef struct _TEST_IMAGE
33 {
34     IMAGE_DOS_HEADER DosHeader;
35     IMAGE_NT_HEADERS NtHeaders;
36     IMAGE_SECTION_HEADER SectionHeaders[1];
37     TEST_RESOURCES Resources;
38 } TEST_IMAGE, *PTEST_IMAGE;
39 
40 static
41 VOID
42 InitializeResourceDirectory(
43     PIMAGE_RESOURCE_DIRECTORY ResourceDirectory,
44     USHORT NumberOfNamedEntries,
45     USHORT NumberOfIdEntries)
46 {
47     ResourceDirectory->Characteristics = 0;
48     ResourceDirectory->TimeDateStamp = 0;
49     ResourceDirectory->MajorVersion = 0;
50     ResourceDirectory->MinorVersion = 0;
51     ResourceDirectory->NumberOfNamedEntries = NumberOfNamedEntries;
52     ResourceDirectory->NumberOfIdEntries = NumberOfIdEntries;
53 }
54 
55 static
56 VOID
57 InitializeNamedEntry(
58     PTEST_RESOURCES Resource,
59     PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry,
60     PWCHAR Name,
61     PVOID Data)
62 {
63     DirEntry->Name = Resource->StringIndex * 2 + FIELD_OFFSET(TEST_RESOURCES, StringBuffer);
64     DirEntry->NameIsString = 1;
65     DirEntry->OffsetToData = (PUCHAR)Data - (PUCHAR)Resource;
66     if (DirEntry < Resource->Lang1Entries)
67         DirEntry->DataIsDirectory = 1;
68     Resource->StringBuffer[Resource->StringIndex] = wcslen(Name);
69     wcscpy(&Resource->StringBuffer[Resource->StringIndex + 1], Name);
70     Resource->StringIndex += Resource->StringBuffer[Resource->StringIndex] * 2 + 1;
71 }
72 
73 static
74 VOID
75 InitializeIdEntry(
76     PTEST_RESOURCES Resource,
77     PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry,
78     USHORT Id,
79     PVOID Data)
80 {
81     DirEntry->Name = Id;
82     DirEntry->NameIsString = 0;
83     DirEntry->OffsetToData = (PUCHAR)Data - (PUCHAR)Resource;
84     if (DirEntry < Resource->Lang1Entries)
85         DirEntry->DataIsDirectory = 1;
86 }
87 
88 static
89 VOID
90 InitializeDataEntry(
91     PVOID ImageBase,
92     PIMAGE_RESOURCE_DATA_ENTRY DataEntry,
93     PVOID Data,
94     ULONG Size)
95 {
96 
97     DataEntry->OffsetToData = (PUCHAR)Data - (PUCHAR)ImageBase;
98     DataEntry->Size = Size;
99     DataEntry->CodePage = 0;
100     DataEntry->Reserved = 0;
101 }
102 
103 static
104 VOID
105 InitializeTestResource(
106     PVOID ImageBase,
107     PTEST_RESOURCES Resource)
108 {
109 
110     memset(Resource->StringBuffer, 0, sizeof(Resource->StringBuffer));
111     Resource->StringIndex = 0;
112 
113     InitializeResourceDirectory(&Resource->TypeDirectory, 0, 2);
114     InitializeIdEntry(Resource, &Resource->TypeEntries[0], 1, &Resource->Name1Directory);
115     InitializeIdEntry(Resource, &Resource->TypeEntries[1], 2, &Resource->Name2Directory);
116 
117     InitializeResourceDirectory(&Resource->Name1Directory, 1, 1);
118     InitializeNamedEntry(Resource, &Resource->Name1Entries[0], L"TEST", &Resource->Lang1Directory);
119     InitializeIdEntry(Resource, &Resource->Name1Entries[1], 7, &Resource->Lang2Directory);
120 
121     InitializeResourceDirectory(&Resource->Name2Directory, 2, 0);
122     InitializeNamedEntry(Resource, &Resource->Name2Entries[0], L"LOL", &Resource->Lang3Directory);
123     InitializeNamedEntry(Resource, &Resource->Name2Entries[1], L"xD", &Resource->Lang4Directory);
124 
125     InitializeResourceDirectory(&Resource->Lang1Directory, 0, 2);
126     InitializeIdEntry(Resource, &Resource->Lang1Entries[0], 0x409, &Resource->DataEntries[0]);
127     InitializeIdEntry(Resource, &Resource->Lang1Entries[1], 0x407, &Resource->DataEntries[1]);
128 
129     InitializeResourceDirectory(&Resource->Lang2Directory, 0, 2);
130     InitializeIdEntry(Resource, &Resource->Lang2Entries[0], 0x408, &Resource->DataEntries[2]);
131     InitializeIdEntry(Resource, &Resource->Lang2Entries[1], 0x406, &Resource->DataEntries[3]);
132 
133     InitializeResourceDirectory(&Resource->Lang3Directory, 0, 2);
134     InitializeIdEntry(Resource, &Resource->Lang3Entries[0], 0x405, &Resource->DataEntries[4]);
135     InitializeIdEntry(Resource, &Resource->Lang3Entries[1], 0x403, &Resource->DataEntries[5]);
136 
137     InitializeResourceDirectory(&Resource->Lang4Directory, 0, 2);
138     InitializeIdEntry(Resource, &Resource->Lang4Entries[0], 0x402, &Resource->DataEntries[6]);
139     InitializeIdEntry(Resource, &Resource->Lang4Entries[1], 0x404, &Resource->DataEntries[7]);
140 
141     InitializeDataEntry(ImageBase, &Resource->DataEntries[0], Resource->StringBuffer + 0, 2);
142     InitializeDataEntry(ImageBase, &Resource->DataEntries[1], Resource->StringBuffer + 2, 4);
143     InitializeDataEntry(ImageBase, &Resource->DataEntries[2], Resource->StringBuffer + 4, 6);
144     InitializeDataEntry(ImageBase, &Resource->DataEntries[3], Resource->StringBuffer + 6, 8);
145     InitializeDataEntry(ImageBase, &Resource->DataEntries[4], Resource->StringBuffer + 8, 10);
146     InitializeDataEntry(ImageBase, &Resource->DataEntries[5], Resource->StringBuffer + 10, 12);
147     InitializeDataEntry(ImageBase, &Resource->DataEntries[6], Resource->StringBuffer + 12, 14);
148     InitializeDataEntry(ImageBase, &Resource->DataEntries[7], Resource->StringBuffer + 14, 16);
149 
150 }
151 
152 VOID
153 InitializeTestImage(
154     PTEST_IMAGE TestImage)
155 {
156     PIMAGE_DATA_DIRECTORY ResourceDirectory;
157 
158     TestImage->DosHeader.e_magic = IMAGE_DOS_SIGNATURE;
159     TestImage->DosHeader.e_lfanew = sizeof(IMAGE_DOS_HEADER);
160 
161     TestImage->NtHeaders.Signature = IMAGE_NT_SIGNATURE;
162 
163     TestImage->NtHeaders.FileHeader.Machine = IMAGE_FILE_MACHINE_I386;
164     TestImage->NtHeaders.FileHeader.NumberOfSections = 1;
165     TestImage->NtHeaders.FileHeader.TimeDateStamp = 0;
166     TestImage->NtHeaders.FileHeader.PointerToSymbolTable = 0;
167     TestImage->NtHeaders.FileHeader.NumberOfSymbols = 0;
168     TestImage->NtHeaders.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
169     TestImage->NtHeaders.FileHeader.Characteristics = 0;
170 
171     TestImage->NtHeaders.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
172     TestImage->NtHeaders.OptionalHeader.ImageBase = (DWORD_PTR)TestImage;
173     TestImage->NtHeaders.OptionalHeader.SizeOfImage = sizeof(TEST_IMAGE);
174     TestImage->NtHeaders.OptionalHeader.SizeOfHeaders = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS);
175 
176     ResourceDirectory = &TestImage->NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
177     ResourceDirectory->VirtualAddress = FIELD_OFFSET(TEST_IMAGE, Resources);
178     ResourceDirectory->Size = sizeof(TEST_RESOURCES);
179 
180     strcpy((char*)TestImage->SectionHeaders[0].Name, ".rsrc");
181     TestImage->SectionHeaders[0].Misc.VirtualSize = sizeof(TEST_IMAGE);
182     TestImage->SectionHeaders[0].VirtualAddress = FIELD_OFFSET(TEST_IMAGE, Resources);
183     TestImage->SectionHeaders[0].SizeOfRawData = sizeof(TEST_IMAGE);
184     TestImage->SectionHeaders[0].PointerToRawData = FIELD_OFFSET(TEST_IMAGE, Resources);
185     TestImage->SectionHeaders[0].PointerToRelocations = 0;
186     TestImage->SectionHeaders[0].PointerToLinenumbers = 0;
187     TestImage->SectionHeaders[0].NumberOfRelocations = 0;
188     TestImage->SectionHeaders[0].NumberOfLinenumbers = 0;
189     TestImage->SectionHeaders[0].Characteristics = 0;
190 
191     InitializeTestResource(TestImage, &TestImage->Resources);
192 }
193 
194 #define ok_nwstr(str1, str2, count) \
195     ok(wcsncmp((PWCHAR)str1, (PWCHAR)str2, count) == 0, \
196        "string is wrong, expected: '%S', got '%S'\n", str1, str2); \
197 
198 #define ok_enumres(_Res, _Type, _Name, _Lang, _Data, _Size) \
199     ok_dec((_Res)->Type, _Type); \
200     if ((ULONG_PTR)(_Name) > 0xFFFF) \
201     { \
202         ok_dec(*(WORD*)((_Res)->Name), wcslen((PWCHAR)(_Name))); \
203         ok_nwstr((PWCHAR)((_Res)->Name + 2), (PWCHAR)_Name, *(WORD*)((_Res)->Name)); \
204     } \
205     else \
206     { \
207         ok_dec((_Res)->Name, (ULONG_PTR)_Name); \
208     } \
209     ok_hex((_Res)->Language, _Lang); \
210     ok_ptr((PVOID)(_Res)->Data, _Data); \
211     ok_dec((_Res)->Size, _Size); \
212     ok_dec((_Res)->Reserved, 0);
213 
214 static
215 void
216 Test_Data(PTEST_IMAGE TestImage)
217 {
218     LDR_RESOURCE_INFO ResourceInfo;
219     LDR_ENUM_RESOURCE_INFO EnumRes[8];
220     ULONG ResourceCount;
221     NTSTATUS Status;
222 
223     InitializeTestImage(TestImage);
224 
225     memset(EnumRes, 0xcc, sizeof(EnumRes));
226 
227     ResourceInfo.Type = 1;
228     ResourceInfo.Name = 1;
229     ResourceInfo.Language = 0x408;
230     ResourceCount = 8;
231     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, EnumRes);
232     ok_hex(Status, STATUS_SUCCESS);
233     ok_dec(ResourceCount, 8);
234 
235     ok_ptr((PVOID)EnumRes[0].Data, TestImage->Resources.StringBuffer);
236     ok_dec(EnumRes[0].Size, 2);
237 
238     ok_enumres(&EnumRes[0], 1, L"TEST", 0x409, TestImage->Resources.StringBuffer, 2)
239     ok_enumres(&EnumRes[1], 1, L"TEST", 0x407, TestImage->Resources.StringBuffer + 2, 4)
240     ok_enumres(&EnumRes[2], 1, 7, 0x408, TestImage->Resources.StringBuffer + 4, 6)
241     ok_enumres(&EnumRes[3], 1, 7, 0x406, TestImage->Resources.StringBuffer + 6, 8)
242     ok_enumres(&EnumRes[4], 2, L"LOL", 0x405, TestImage->Resources.StringBuffer + 8, 10)
243     ok_enumres(&EnumRes[5], 2, L"LOL", 0x403, TestImage->Resources.StringBuffer + 10, 12)
244     ok_enumres(&EnumRes[6], 2, L"xD", 0x402, TestImage->Resources.StringBuffer + 12, 14)
245     ok_enumres(&EnumRes[7], 2, L"xD", 0x404, TestImage->Resources.StringBuffer + 14, 16)
246 
247     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, EnumRes);
248     ok_hex(Status, STATUS_SUCCESS);
249     ok_dec(ResourceCount, 4);
250 
251 }
252 
253 
254 static
255 void
256 Test_Parameters(PTEST_IMAGE TestImage)
257 {
258     LDR_RESOURCE_INFO ResourceInfo;
259     LDR_ENUM_RESOURCE_INFO Resources[8];
260     ULONG ResourceCount;
261     NTSTATUS Status;
262 
263     InitializeTestImage(TestImage);
264 
265     ResourceInfo.Type = 6;
266     ResourceInfo.Name = 1;
267     ResourceInfo.Language = 0x409;
268 
269     ResourceCount = 8;
270     Status = LdrEnumResources(TestImage, &ResourceInfo, 3, &ResourceCount, Resources);
271     ok_hex(Status, STATUS_SUCCESS);
272     ok_dec(ResourceCount, 0);
273 
274     ResourceInfo.Type = 1;
275     ResourceInfo.Name = 7;
276     ResourceInfo.Language = 0x406;
277     ResourceCount = 8;
278     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, Resources);
279     ok_hex(Status,  STATUS_SUCCESS);
280     ok_dec(ResourceCount, 8);
281 
282     ResourceCount = 8;
283     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, Resources);
284     ok_hex(Status, STATUS_SUCCESS);
285     ok_dec(ResourceCount, 4);
286 
287     ResourceCount = 8;
288     Status = LdrEnumResources(TestImage, &ResourceInfo, 2, &ResourceCount, Resources);
289     ok_hex(Status, STATUS_SUCCESS);
290     ok_dec(ResourceCount, 2);
291 
292     ResourceCount = 8;
293     Status = LdrEnumResources(TestImage, &ResourceInfo, 3, &ResourceCount, Resources);
294     ok_hex(Status, STATUS_SUCCESS);
295     ok_dec(ResourceCount, 1);
296 
297     ResourceCount = 8;
298     Status = LdrEnumResources(TestImage, &ResourceInfo, 99, &ResourceCount, Resources);
299     ok_hex(Status, STATUS_SUCCESS);
300     ok_dec(ResourceCount, 1);
301 
302     ResourceCount = 0;
303     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, Resources);
304     ok_hex(Status,  STATUS_INFO_LENGTH_MISMATCH);
305     ok_dec(ResourceCount, 8);
306 
307     ResourceCount = 7;
308     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, Resources);
309     ok_hex(Status,  STATUS_INFO_LENGTH_MISMATCH);
310     ok_dec(ResourceCount, 8);
311 
312     ResourceCount = 8;
313     Status = LdrEnumResources(NULL, &ResourceInfo, 1, &ResourceCount, Resources);
314     ok_hex(Status, STATUS_RESOURCE_DATA_NOT_FOUND);
315     ok_dec(ResourceCount, 0);
316 
317     ResourceCount = 8;
318     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, NULL);
319     ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH);
320     ok_dec(ResourceCount, 4);
321 
322     ResourceCount = 8;
323     _SEH2_TRY
324     {
325         Status = LdrEnumResources(NULL, NULL, 0, NULL, NULL);
326     }
327     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
328     {
329         Status = 0xDeadC0de;
330     }
331     _SEH2_END
332     ok_hex(Status, 0xDeadC0de);
333 
334     ResourceCount = 42;
335     _SEH2_TRY
336     {
337         Status = LdrEnumResources(TestImage, &ResourceInfo, 1, NULL, Resources);
338     }
339     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
340     {
341         Status = 0xDeadC0de;
342     }
343     _SEH2_END
344     ok_hex(Status, 0xDeadC0de);
345     ok_dec(ResourceCount, 42);
346 
347     ResourceCount = 8;
348     Status = LdrEnumResources(TestImage + 2, &ResourceInfo, 1, &ResourceCount, NULL);
349     ok_hex(Status,  STATUS_RESOURCE_DATA_NOT_FOUND);
350     ok_dec(ResourceCount, 0);
351 
352     TestImage->Resources.TypeEntries[0].DataIsDirectory = 0;
353     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, NULL);
354     ok_hex(Status,  STATUS_INVALID_IMAGE_FORMAT);
355     ok_dec(ResourceCount, 0);
356 
357 }
358 
359 START_TEST(LdrEnumResources)
360 {
361     TEST_IMAGE TestImage;
362 
363     Test_Parameters(&TestImage);
364     Test_Data(&TestImage);
365 
366 }
367