:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / 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  * PROGRAMMERS:     Eric Kohl (ekohl@rz-online.de)
8  */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ddk/ntddk.h>
13
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS ****************************************************************/
18
19 NTSTATUS STDCALL
20 LdrAccessResource(IN  PVOID BaseAddress,
21                   IN  PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
22                   OUT PVOID *Resource OPTIONAL,
23                   OUT PULONG Size OPTIONAL)
24 {
25    PIMAGE_SECTION_HEADER Section;
26    PIMAGE_NT_HEADERS NtHeader;
27    ULONG SectionRva;
28    ULONG SectionVa;
29    ULONG DataSize;
30    ULONG Offset = 0;
31    ULONG Data;
32
33    Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
34                                                TRUE,
35                                                IMAGE_DIRECTORY_ENTRY_RESOURCE,
36                                                &DataSize);
37    if (Data == 0)
38         return STATUS_RESOURCE_DATA_NOT_FOUND;
39
40    if ((ULONG)BaseAddress & 1)
41      {
42         /* loaded as ordinary file */
43         NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
44         Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
45         Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
46         if (Section == NULL)
47           {
48              return STATUS_RESOURCE_DATA_NOT_FOUND;
49           }
50
51         if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
52           {
53              SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
54              SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
55              Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
56           }
57      }
58
59    if (Resource)
60      {
61         *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
62      }
63
64    if (Size)
65      {
66         *Size = ResourceDataEntry->Size;
67      }
68
69    return STATUS_SUCCESS;
70 }
71
72
73 NTSTATUS STDCALL
74 LdrFindResource_U(PVOID BaseAddress,
75                   PLDR_RESOURCE_INFO ResourceInfo,
76                   ULONG Level,
77                   PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
78 {
79    PIMAGE_RESOURCE_DIRECTORY ResDir;
80    PIMAGE_RESOURCE_DIRECTORY ResBase;
81    PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
82    NTSTATUS Status = STATUS_SUCCESS;
83    ULONG EntryCount;
84    PWCHAR ws;
85    ULONG i;
86    ULONG Id;
87
88    DPRINT ("LdrFindResource_U()\n");
89
90    /* Get the pointer to the resource directory */
91    ResDir = (PIMAGE_RESOURCE_DIRECTORY)
92         RtlImageDirectoryEntryToData (BaseAddress,
93                                       TRUE,
94                                       IMAGE_DIRECTORY_ENTRY_RESOURCE,
95                                       &i);
96    if (ResDir == NULL)
97      {
98         return STATUS_RESOURCE_DATA_NOT_FOUND;
99      }
100
101    DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
102
103    ResBase = ResDir;
104
105    /* Let's go into resource tree */
106    for (i = 0; i < Level; i++)
107      {
108         DPRINT("ResDir: %x\n", (ULONG)ResDir);
109         Id = ((PULONG)ResourceInfo)[i];
110         EntryCount = ResDir->NumberOfNamedEntries;
111         ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
112         DPRINT("ResEntry %x\n", (ULONG)ResEntry);
113         if (Id & 0xFFFF0000)
114           {
115              /* Resource name is a unicode string */
116              for (; EntryCount--; ResEntry++)
117                {
118                   /* Scan entries for equal name */
119                   if (ResEntry->Name & 0x80000000)
120                     {
121                        ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
122                        if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
123                            wcslen((PWCHAR)Id) == (int)*ws )
124                          {
125                             goto found;
126                          }
127                     }
128                }
129           }
130         else
131           {
132              /* We use ID number instead of string */
133              ResEntry += EntryCount;
134              EntryCount = ResDir->NumberOfIdEntries;
135              for (; EntryCount--; ResEntry++)
136                {
137                   /* Scan entries for equal name */
138                   if (ResEntry->Name == Id)
139                     {
140                      DPRINT("ID entry found %x\n", Id);
141                      goto found;
142                     }
143                }
144           }
145         DPRINT("Error %lu\n", i);
146
147           switch (i)
148           {
149              case 0:
150                 return STATUS_RESOURCE_TYPE_NOT_FOUND;
151
152              case 1:
153                 return STATUS_RESOURCE_NAME_NOT_FOUND;
154
155              case 2:
156                 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
157                   {
158                      /* Use the first available language */
159                      ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
160                      break;
161                   }
162                 return STATUS_RESOURCE_LANG_NOT_FOUND;
163
164              case 3:
165                 return STATUS_RESOURCE_DATA_NOT_FOUND;
166
167              default:
168                 return STATUS_INVALID_PARAMETER;
169           }
170 found:;
171         ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
172                 (ResEntry->OffsetToData & 0x7FFFFFFF));
173      }
174    DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
175
176    if (ResourceDataEntry)
177      {
178         *ResourceDataEntry = (PVOID)ResDir;
179      }
180
181   return Status;
182 }
183
184 /* EOF */