364 lines
9.0 KiB
C
364 lines
9.0 KiB
C
/*++
|
||
|
||
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);
|
||
}
|