2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/misc/resource.c
5 * PURPOSE: Boot Library Resource Functions
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
13 /* DATA VARIABLES ************************************************************/
17 PVOID ResRootDirectory
;
19 PVOID ResPeImageBasePrimary
;
20 PVOID ResPeImageEndPrimary
;
21 PVOID ResRootDirectoryPrimary
;
22 ULONG_PTR ResRootDirectoryPrimaryOffset
;
23 ULONG_PTR ResRootDirectoryOffset
;
24 ULONG_PTR ResRootDirectoryFallbackOffset
;
25 PVOID ResPeImageBaseFallback
;
26 PVOID ResPeImageEndFallback
;
27 PVOID ResRootDirectoryFallback
;
29 BOOLEAN ResLoadedFontFiles
;
30 PVOID ResMuiImageBase
;
31 ULONG_PTR ResMuiImageSize
;
35 /* FUNCTIONS *****************************************************************/
44 /* Check if we're using the primary (MUI) or fallback resources */
47 /* Use the primary ones */
48 ResRootDirectory
= ResRootDirectoryPrimary
;
49 ResRootDirectoryOffset
= ResRootDirectoryPrimaryOffset
;
50 ResPeImageBase
= ResPeImageBasePrimary
;
51 ResPeImageEnd
= ResPeImageEndPrimary
;
53 /* Register the locale with the display */
54 Status
= BlpDisplayRegisterLocale(ResLocale
);
57 /* Check if that failed, or if we're using fallback */
58 if (!(Primary
) || !(NT_SUCCESS(Status
)))
60 /* Set the fallback pointers */
61 ResRootDirectory
= ResRootDirectoryFallback
;
62 ResRootDirectoryOffset
= ResRootDirectoryFallbackOffset
;
63 ResPeImageBase
= ResPeImageBaseFallback
;
64 ResPeImageEnd
= ResPeImageEndFallback
;
66 /* Register the fallback (America baby!) locale */
67 Status
= BlpDisplayRegisterLocale(L
"en-US");
68 if (!NT_SUCCESS(Status
))
70 /* Fallback to text mode (yes, this is the API...) */
71 return BlDisplaySetScreenResolution();
75 /* No fonts loaded -- return failure code */
76 ResLoadedFontFiles
= FALSE
;
80 PIMAGE_RESOURCE_DIRECTORY_ENTRY
81 ResFindDirectoryEntry (
82 _In_ PIMAGE_RESOURCE_DIRECTORY Directory
,
85 _In_ ULONG_PTR SectionStart
88 PIMAGE_RESOURCE_DIRECTORY_ENTRY EntryTable
, IdEntryTable
;
91 PIMAGE_RESOURCE_DIRECTORY_STRING NameString
;
93 /* Are we looking by ID or name? */
96 /* By ID, so were we passed a name? */
99 /* That doesn't make sense */
105 /* By name, but we weren't given one. Also bad. */
109 /* Get the table of names */
110 EntryTable
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(Directory
+ 1);
112 /* Check if we are doing ID lookup instead */
115 /* The IDs come after the names */
116 IdEntryTable
= &EntryTable
[Directory
->NumberOfNamedEntries
];
119 for (i
= 0; i
< Directory
->NumberOfIdEntries
; i
++)
121 /* Check if the ID matches, or if the wildcard is being used*/
122 if ((IdEntryTable
[i
].Id
== *Id
) || (*Id
== 0xFFFF))
124 /* Return a pointer to the data */
125 return (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(SectionStart
+ IdEntryTable
[i
].OffsetToDirectory
);
129 /* ID was not found */
133 /* Searching by name, so parse them */
134 for (i
= 0; i
< Directory
->NumberOfNamedEntries
; i
++)
136 /* Get the name itself and count its length */
137 NameString
= (PIMAGE_RESOURCE_DIRECTORY_STRING
)(SectionStart
+ EntryTable
[i
].NameOffset
);
138 NameLength
= wcslen(Name
);
140 /* If the length matches, compare the bytes */
141 if ((NameLength
== NameString
->Length
) &&
142 (RtlCompareMemory(NameString
->NameString
, Name
, NameLength
) == NameLength
))
144 /* They both match, so this is our entry. Return it */
145 return (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(SectionStart
+ EntryTable
[i
].OffsetToDirectory
);
149 /* Name was not found */
154 ResFindDataEntryFromImage (
155 _In_opt_ PVOID ImageBase
,
156 _In_opt_ ULONG ImageSize
,
157 _In_ USHORT DirectoryId
,
158 _In_ PUSHORT EntryId
,
160 _Out_ PIMAGE_RESOURCE_DATA_ENTRY
*DataEntryOut
,
161 _Out_ PVOID
* ResourceOut
165 PIMAGE_SECTION_HEADER ResourceSection
;
166 PIMAGE_RESOURCE_DIRECTORY ResourceDir
, RootDir
;
167 PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry
;
168 PIMAGE_RESOURCE_DATA_ENTRY DataEntry
;
169 PVOID Data
, DataEnd
, ImageEnd
;
170 BOOLEAN UseFallbackDirectory
;
172 /* Assume nothing found */
173 UseFallbackDirectory
= TRUE
;
174 Status
= STATUS_NOT_FOUND
;
176 /* Are we looking at a particular image? */
179 /* Then make sure we know its size */
185 /* Find the resource section for it */
186 ResourceSection
= BlImgFindSection(ImageBase
, ImageSize
);
187 if (!ResourceSection
)
189 return STATUS_INVALID_IMAGE_FORMAT
;
192 /* Remember how big the image is, and find the resource directory */
193 ImageEnd
= (PVOID
)((ULONG_PTR
)ImageBase
+ ImageSize
);
194 RootDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG_PTR
)ImageBase
+
195 ResourceSection
->VirtualAddress
);
196 if ((PVOID
)RootDir
< ImageBase
)
198 /* It's out of bounds, so bail out */
199 return STATUS_INVALID_PARAMETER
;
202 /* We have a valid directory, don't use fallback for now */
203 UseFallbackDirectory
= FALSE
;
207 /* We are using the current library settings instead */
208 ImageBase
= ResPeImageBase
;
209 RootDir
= ResRootDirectory
;
210 ImageEnd
= ResPeImageEnd
;
213 /* If we don't have a resource directory, there's nothing to find */
219 /* Try two loops, once for primary, once for fallback */
222 /* Find the directory first */
223 ResourceDir
= (PIMAGE_RESOURCE_DIRECTORY
)ResFindDirectoryEntry(RootDir
,
232 /* We didn't find it -- is it time to use the fallback? */
233 if (UseFallbackDirectory
)
235 /* Were were not using the fallback already? */
236 if (RootDir
!= ResRootDirectoryFallback
)
238 /* Then attempt with the fallback instead*/
239 RootDir
= ResRootDirectoryFallback
;
240 ImageBase
= ResPeImageBaseFallback
;
241 ImageEnd
= ResPeImageEndFallback
;
243 /* Making sure we have one... */
251 /* Otherwise, return failure here */
255 /* Now that we are in the right directory, lookup the resource */
256 ResourceDir
= (PIMAGE_RESOURCE_DIRECTORY
)ResFindDirectoryEntry(ResourceDir
,
265 /* The entry is right after */
266 DirEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResourceDir
+ 1);
267 if ((PVOID
)DirEntry
< (PVOID
)ResourceDir
)
269 return STATUS_INVALID_PARAMETER
;
272 /* Get the data entry for it */
273 DataEntry
= (PIMAGE_RESOURCE_DATA_ENTRY
)((ULONG_PTR
)RootDir
+
274 DirEntry
->OffsetToData
);
276 /* Check if the data entry is out of bounds */
277 if (((PVOID
)DataEntry
< ImageBase
) || ((PVOID
)DataEntry
> ImageEnd
))
279 return STATUS_INVALID_PARAMETER
;
282 /* Finally read the data offset */
283 Data
= (PVOID
)((ULONG_PTR
)ImageBase
+ DataEntry
->OffsetToData
);
285 /* Check if the data is out of bounds */
286 if (((PVOID
)Data
< ImageBase
) || ((PVOID
)Data
> ImageEnd
))
288 return STATUS_INVALID_PARAMETER
;
291 /* Make sure the data end isn't out of bounds either */
292 DataEnd
= (PVOID
)((ULONG_PTR
)Data
+ DataEntry
->Size
);
293 if (((PVOID
)DataEnd
< ImageBase
) || ((PVOID
)DataEnd
> ImageEnd
))
295 return STATUS_INVALID_PARAMETER
;
298 /* We finally made it. Return the entry and the raw data */
299 *DataEntryOut
= DataEntry
;
301 return STATUS_SUCCESS
;
310 PIMAGE_RESOURCE_DATA_ENTRY HtmlDataEntry
;
316 /* Look for an RT_HTML resource called BOOTMGR.XSL */
317 Status
= ResFindDataEntryFromImage(NULL
,
323 (PVOID
*)&Stylesheet
);
324 if (!NT_SUCCESS(Status
))
329 /* Check for Unicode BOM */
330 if (*Stylesheet
== 0xFEFF)
332 /* Overwrite it, and NULL-terminate */
333 RtlMoveMemory(Stylesheet
,
335 HtmlDataEntry
->Size
- sizeof(WCHAR
));
336 Stylesheet
[(HtmlDataEntry
->Size
/ sizeof(WCHAR
)) - 1] = UNICODE_NULL
;
338 else if (Stylesheet
[(HtmlDataEntry
->Size
/ sizeof(WCHAR
)) - 1] != UNICODE_NULL
)
340 /* If it's not NULL-terminated, fail */
349 BlResourceFindMessage (
354 PIMAGE_RESOURCE_DIRECTORY ResourceDir
;
355 PIMAGE_RESOURCE_DATA_ENTRY DataEntry
;
356 PMESSAGE_RESOURCE_DATA MsgData
;
357 PMESSAGE_RESOURCE_ENTRY MsgEntry
;
363 /* Bail out if there's no resource directory */
365 if (!ResRootDirectory
)
370 /* Check if we've loaded fonts already */
371 if (!ResLoadedFontFiles
)
373 /* Nope, load them now */
374 Status
= BfLoadDeferredFontFiles();
375 if (!NT_SUCCESS(Status
))
377 /* We failed to load fonts, fallback to fallback locale */
378 Status
= ResSelectLocale(FALSE
);
379 if (NT_SUCCESS(Status
))
382 Status
= BfLoadDeferredFontFiles();
383 if (!NT_SUCCESS(Status
))
385 /* Still didn't work -- fallback to text mode */
386 EfiPrintf(L
"Font loading failed, falling back to text mode\r\n");
387 Status
= BlDisplaySetScreenResolution();
388 if (!NT_SUCCESS(Status
))
390 /* That didn't work either. F*ck it. */
397 /* Now we have a resource directory, and fonts are loaded */
398 NT_ASSERT(ResRootDirectory
!= NULL
);
399 ResLoadedFontFiles
= TRUE
;
402 /* Go look for RT_MESSAGETABLE */
404 ResourceDir
= (PIMAGE_RESOURCE_DIRECTORY
)ResFindDirectoryEntry(ResRootDirectory
,
407 (ULONG_PTR
)ResRootDirectory
);
413 /* Go look for the first directory in the table */
415 ResourceDir
= (PIMAGE_RESOURCE_DIRECTORY
)ResFindDirectoryEntry(ResourceDir
,
418 (ULONG_PTR
)ResRootDirectory
);
424 /* Go look for any language entry in the table */
426 DataEntry
= (PIMAGE_RESOURCE_DATA_ENTRY
)ResFindDirectoryEntry(ResourceDir
,
429 (ULONG_PTR
)ResRootDirectory
);
435 /* Get the message data*/
436 MsgData
= (PMESSAGE_RESOURCE_DATA
)((ULONG_PTR
)ResRootDirectory
+
437 DataEntry
->OffsetToData
-
438 ResRootDirectoryOffset
);
440 /* Loop through the message blocks */
441 for (j
= 0; j
< MsgData
->NumberOfBlocks
; j
++)
443 /* Check if the ID is within this range */
444 if ((MsgId
>= MsgData
->Blocks
[j
].LowId
) &&
445 (MsgId
<= MsgData
->Blocks
[j
].HighId
))
447 /* Get the first entry */
448 MsgEntry
= (PMESSAGE_RESOURCE_ENTRY
)((ULONG_PTR
)MsgData
+
449 MsgData
->Blocks
[j
].OffsetToEntries
);
451 /* Loop till we find the right one */
452 for (i
= MsgId
- MsgData
->Blocks
[j
].LowId
; i
; --i
)
454 MsgEntry
= (PMESSAGE_RESOURCE_ENTRY
)((ULONG_PTR
)MsgEntry
+
458 /* Find where this message ends */
459 MsgEnd
= (PVOID
)((ULONG_PTR
)MsgEntry
+ MsgEntry
->Length
);
461 /* Now make sure that the message is within bounds */
462 if ((MsgEnd
>= (PVOID
)MsgEntry
) &&
463 ((PVOID
)MsgEntry
>= ResPeImageBase
) &&
464 (MsgEnd
<= ResPeImageEnd
))
466 /* If so, read the text associated with it */
467 Message
= (PWCHAR
)MsgEntry
->Text
;
473 /* Return the text, if one was found */
478 BlpResourceInitialize (
483 PIMAGE_SECTION_HEADER ResourceSection
;
485 ULONG ImageSize
, VRes
, HRes
;
488 /* Default to using fallback */
491 /* Initialize all globals */
494 ResRootDirectoryPrimary
= 0;
495 ResRootDirectoryPrimaryOffset
= 0;
496 ResPeImageBasePrimary
= 0;
497 ResPeImageEndPrimary
= 0;
498 ResRootDirectoryFallback
= 0;
499 ResRootDirectoryFallbackOffset
= 0;
500 ResPeImageBaseFallback
= 0;
501 ResPeImageEndFallback
= 0;
502 ResRootDirectory
= 0;
503 ResRootDirectoryOffset
= 0;
506 ResLoadedFontFiles
= 0;
508 /* Check if we had allocated a locale already */
511 /* Free it and reset */
512 BlMmFreeHeap(ResLocale
);
516 /* Get our base address and size*/
517 Status
= BlGetApplicationBaseAndSize(&ImageBase
, &ImageSize
);
518 if (!NT_SUCCESS(Status
))
523 /* Find our resource section */
524 ResourceSection
= BlImgFindSection(ImageBase
, ImageSize
);
527 /* The resource section will be our fallback. Save down its details */
528 ResRootDirectoryFallbackOffset
= ResourceSection
->VirtualAddress
;
529 ResPeImageBaseFallback
= ImageBase
;
530 ResPeImageEndFallback
= (PVOID
)((ULONG_PTR
)ImageBase
+ ImageSize
);
531 ResRootDirectoryFallback
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG_PTR
)ImageBase
+
532 ResRootDirectoryFallbackOffset
);
535 /* Get the current screen resolution and check if we're in graphics mode */
536 Status
= BlDisplayGetScreenResolution(&HRes
, &VRes
);
537 if ((NT_SUCCESS(Status
)) && ((HRes
!= 640) || (VRes
!= 200)))
539 /* We are... we should load MUI data */
540 Status
= STATUS_NOT_IMPLEMENTED
;//ResInitializeMuiResources();
541 if (NT_SUCCESS(Status
))
543 /* And not rely on the fallback */
548 /* Load the locale resources */
549 return ResSelectLocale(UsePrimary
);