/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
blres.c
Abstract:
Provides rudimentary resource support for the osloader and setupldr
Author:
John Vert (jvert) 12-Nov-1993
Revision History:
--*/
#include "bootlib.h"
PUCHAR BlpResourceDirectory = NULL;
PUCHAR BlpResourceFileOffset = NULL;
//
// private function prototypes
//
PIMAGE_RESOURCE_DIRECTORY
BlpFindDirectoryEntry(
IN PIMAGE_RESOURCE_DIRECTORY Directory,
IN ULONG Id,
IN PUCHAR SectionStart
);
ARC_STATUS
BlInitResources(
IN PCHAR StartCommand
)
/*++
Routine Description:
Opens the executable that was run and reads the section headers out of the
image to determine where the resource section is located in memory.
Arguments:
StartCommand - Supplies the command used to start the program (argv[0])
Return Value:
ESUCCESS if successful
ARC_STATUS if unsuccessful
--*/
{
CHAR DeviceName[80];
PCHAR FileName;
PCHAR p;
ULONG DeviceId;
ULONG FileId;
ARC_STATUS Status;
UCHAR LocalBuffer[(SECTOR_SIZE * 2) + 256];
PUCHAR LocalPointer;
ULONG Count;
PIMAGE_FILE_HEADER FileHeader;
PIMAGE_OPTIONAL_HEADER OptionalHeader;
PIMAGE_DATA_DIRECTORY ResourceDirectory;
PIMAGE_SECTION_HEADER SectionHeader;
ULONG NumberOfSections;
if (BlpResourceDirectory != NULL) {
//
// Already initialized, just return.
//
return(ESUCCESS);
}
//
// extract device name from the startup path
//
p=strrchr(StartCommand,')');
if (p==NULL) {
return(ENODEV);
}
strncpy(DeviceName, StartCommand, p-StartCommand+1);
DeviceName[p-StartCommand+1]='\0';
FileName = p+1;
//
// Open the device.
//
Status = ArcOpen(DeviceName, ArcOpenReadOnly, &DeviceId);
if (Status != ESUCCESS) {
return(Status);
}
//
// Open the file.
//
Status = BlOpen(DeviceId,
FileName,
ArcOpenReadOnly,
&FileId);
if (Status != ESUCCESS) {
ArcClose(DeviceId);
return(Status);
}
//
// Read the first two sectors of the image header from the file.
//
LocalPointer = ALIGN_BUFFER(LocalBuffer);
Status = BlRead(FileId, LocalPointer, SECTOR_SIZE*2, &Count);
BlClose(FileId);
ArcClose(DeviceId);
if (Status != ESUCCESS) {
return(Status);
}
FileHeader = (PIMAGE_FILE_HEADER)LocalPointer;
OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(LocalPointer + sizeof(IMAGE_FILE_HEADER));
#if defined(_PPC_)
//
// The PPC ROM format uses an NT optional header, so the data directory
// can be used to locate the resource section (if any). The base
// address of the resource directory is adjusted by the image base. We
// also need to adjust virtual addresses in the resource directory by
// this amount which is used as (BlpResourceDirectory -
// BlpResourceFileOffset).
//
ResourceDirectory = (OptionalHeader->DataDirectory +
IMAGE_DIRECTORY_ENTRY_RESOURCE);
if ((FileHeader->Machine == IMAGE_FILE_MACHINE_POWERPC) &&
ResourceDirectory->VirtualAddress && ResourceDirectory->Size) {
BlpResourceDirectory = OptionalHeader->ImageBase +
ResourceDirectory->VirtualAddress;
BlpResourceFileOffset = ResourceDirectory->VirtualAddress;
return(ESUCCESS);
}
#else
NumberOfSections = FileHeader->NumberOfSections;
SectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)OptionalHeader +
FileHeader->SizeOfOptionalHeader);
//
// Find .rsrc section
//
while (NumberOfSections) {
if (_stricmp(SectionHeader->Name, ".rsrc")==0) {
BlpResourceDirectory = (PUCHAR)SectionHeader->VirtualAddress;
BlpResourceFileOffset = (PUCHAR)SectionHeader->PointerToRawData;
if (FileHeader->Machine == IMAGE_FILE_MACHINE_POWERPC) {
BlpResourceDirectory += OptionalHeader->ImageBase;
}
return(ESUCCESS);
}
++SectionHeader;
--NumberOfSections;
}
#endif //
return(EBADF);
}
PCHAR
BlFindMessage(
IN ULONG Id
)
/*++
Routine Description:
Looks up a message resource in the given image. Note that this routine
ignores the Language ID. It is assumed that the osloader/setupldr only
has messages for one language.
Arguments:
Id - Supplies the message ID to look up.
Return Value:
PCHAR - pointer to the message string.
NULL - failure.
--*/
{
PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
PIMAGE_RESOURCE_DIRECTORY NextDirectory;
PMESSAGE_RESOURCE_DATA MessageData;
PMESSAGE_RESOURCE_BLOCK MessageBlock;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
ULONG NumberOfBlocks;
ULONG Index;
if (BlpResourceDirectory==NULL) {
return(NULL);
}
ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)BlpResourceDirectory;
//
// Search the directory. We are looking for the type RT_MESSAGETABLE (11)
//
NextDirectory = BlpFindDirectoryEntry(ResourceDirectory,
11,
(PUCHAR)ResourceDirectory);
if (NextDirectory==NULL) {
return(NULL);
}
//
// Find the next directory. Should only be one entry here (nameid == 1)
//
NextDirectory = BlpFindDirectoryEntry(NextDirectory,
1,
(PUCHAR)ResourceDirectory);
if (NextDirectory==NULL) {
return(NULL);
}
// Find the message table.
// If a dbcs locale is active, then we look for the appropriate
// message table first. Otherwise we just look for the first message table.
//
if(DbcsLangId) {
DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)BlpFindDirectoryEntry(
NextDirectory,
DbcsLangId,
(PUCHAR)ResourceDirectory
);
} else {
DataEntry = NULL;
}
if(!DataEntry) {
DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)BlpFindDirectoryEntry(
NextDirectory,
(ULONG)(-1),
(PUCHAR)ResourceDirectory
);
}
if(!DataEntry) {
return(NULL);
}
MessageData = (PMESSAGE_RESOURCE_DATA)(BlpResourceDirectory +
DataEntry->OffsetToData -
BlpResourceFileOffset);
NumberOfBlocks = MessageData->NumberOfBlocks;
MessageBlock = MessageData->Blocks;
while (NumberOfBlocks--) {
if ((Id >= MessageBlock->LowId) &&
(Id <= MessageBlock->HighId)) {
//
// The requested ID is within this block, scan forward until
// we find it.
//
MessageEntry = (PMESSAGE_RESOURCE_ENTRY)((PCHAR)MessageData + MessageBlock->OffsetToEntries);
Index = Id - MessageBlock->LowId;
while (Index--) {
MessageEntry = (PMESSAGE_RESOURCE_ENTRY)((PUCHAR)MessageEntry + MessageEntry->Length);
}
return(MessageEntry->Text);
}
//
// Check the next block for this ID.
//
MessageBlock++;
}
return(NULL);
}
PIMAGE_RESOURCE_DIRECTORY
BlpFindDirectoryEntry(
IN PIMAGE_RESOURCE_DIRECTORY Directory,
IN ULONG Id,
IN PUCHAR SectionStart
)
/*++
Routine Description:
Searches through a resource directory for the given ID. Ignores entries
with actual names, only searches for ID. If the given ID is -1, the
first entry is returned.
Arguments:
Directory - Supplies the resource directory to search.
Id - Supplies the ID to search for. -1 means return the first ID found.
SectionStart - Supplies a pointer to the start of the resource section.
Return Value:
Pointer to the found resource directory.
NULL for failure.
--*/
{
ULONG i;
PIMAGE_RESOURCE_DIRECTORY_ENTRY FoundDirectory;
FoundDirectory = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(Directory+1);
//
// Skip entries with names.
//
for (i=0;i<Directory->NumberOfNamedEntries;i++) {
++FoundDirectory;
}
//
// Search for matching ID.
//
for (i=0;i<Directory->NumberOfIdEntries;i++) {
if ((FoundDirectory->Name == Id) || (Id == (ULONG)-1)) {
//
// Found a match.
//
return((PIMAGE_RESOURCE_DIRECTORY)(SectionStart +
(FoundDirectory->OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY)));
}
++FoundDirectory;
}
return(NULL);
}