/*++ 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;iNumberOfNamedEntries;i++) { ++FoundDirectory; } // // Search for matching ID. // for (i=0;iNumberOfIdEntries;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); }