update for HEAD-2003091401
[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 /*
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 /* EOF */