#include <os/os.h>
#include <os/pe.h>
#include <wchar.h>
#include <stdlib.h>
#include <errno.h>
static const IMAGE_RESOURCE_DIRECTORY_ENTRY* resFindItem(dword base,
const IMAGE_RESOURCE_DIRECTORY* dir, const word* ids)
{
const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
int i;
entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*) (dir + 1);
for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++)
{
if (entry[i].u.Id == ids[0] || ids[0] == 0)
{
ids++;
if (entry[i].u2.s.DataIsDirectory)
{
//wprintf(L"%x: Directory: offset to directory = %x\n",
//entry[i].u.Id, entry[i].u2.s.OffsetToDirectory);
dir = (const IMAGE_RESOURCE_DIRECTORY*) (base + entry[i].u2.s.OffsetToDirectory);
return resFindItem(base, dir, ids);
}
else
{
//wprintf(L"%x: Resource: offset to data = %x\n",
//entry[i].u.Id, entry[i].u2.OffsetToData);
return entry + i;
}
}
}
//wprintf(L"%x: Not found\n", ids[0]);
sysSetErrno(ENOTFOUND);
return NULL;
}
//! Finds a resource in the specified module.
/*!
* \param base The base address of the module where the resource is to be
* found. Use _info.base for the current module, or another base address if
* a different module is to be used.
*
* \param type A pre-defined or numeric user-defined resource type.
* Pre-defined resource types are:
* - RT_CURSOR A cursor at a specific resolution and colour depth
* - RT_BITMAP A bitmap
* - RT_ICON An icon at a specific resolution and colour depth
* - RT_MENU A menu definition
* - RT_DIALOG A dialog box definition
* - RT_STRING A block of up to 16 strings (use resLoadString() to load a
* specific string)
* - RT_FONTDIR A list of fonts
* - RT_FONT A font with a specific typeface, weight, size and attributes
* - RT_ACCEL A list of keyboard accelerators
* - RT_RCDATA Arbitrary binary data
* - RT_MSGTABLE A table of error messages
* - RT_GROUP_CURSOR A group of cursors which describe the same image but at
* different resolutions and colour depths
* - RT_GROUP_ICON A group of icons which describe the same image but at
* different resolutions and colour depths
* - RT_VERSION A version information block
* \param id The numeric identifier of the resource to be loaded.
* \param language The ID of the specific language of the resource to
* be loaded. Passing NULL for this parameter specifies the default
* language for the process.
*
* \note The Möbius only supports numeric resource IDs; string IDs (such
* as those used in Microsoft Windows) are not supported.
*
* \return A pointer to the start of the resource within the specified module,
* or NULL if the resource could not be found.
* Since the resource is contained within the image of the module in
* memory, it is read-only (or it conforms to the attributes of the
* PE section that contains it). There is also no corresponding function
* to free a loaded resource; all resources are freed when the process
* terminates.
*/
const void* resFind(dword base, word type, word id, word language)
{
word ids[4] = { type, id, language, 0 };
const IMAGE_DOS_HEADER* dos_head;
const IMAGE_PE_HEADERS* header;
const IMAGE_RESOURCE_DIRECTORY *dir;
const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
const IMAGE_RESOURCE_DATA_ENTRY *data;
if (!base)
return NULL;
dos_head = (const IMAGE_DOS_HEADER*) base;
header = (const IMAGE_PE_HEADERS*) ((char *) dos_head + dos_head->e_lfanew);
dir = (const IMAGE_RESOURCE_DIRECTORY*)
(base + header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
if ((dword) dir <= base)
{
sysSetErrno(ENOTFOUND);
return NULL;
}
entry = resFindItem((dword) dir, dir, ids);
if (entry)
{
//wprintf(L"entry->OffsetToData = %x\n", entry->OffsetToData);
data = (const IMAGE_RESOURCE_DATA_ENTRY*) ((byte*) dir + entry->u2.OffsetToData);
//wprintf(L"data->OffsetToData = %x\n", data->OffsetToData);
return (const void*) (base + data->OffsetToData);
}
else
return NULL;
}
//! Loads a string from the specified module.
/*!
* \param base The base address of the module where the resource is to be
* found. Use _info.base for the current module, or another base address if
* a different module is to be used.
* \param id The numeric identifier of the string to be loaded.
* \param str String buffer to receive the loaded string.
* \param str_max Size, in characters, of the buffer pointed to by str.
*
* \return \p true if the string was found and loaded successfully; false
* otherwise.
* \note Due to a limitation of the PE resource file format, it is not
* possible to distinguish between a zero-length string and a not-present
* string if there are any strings within the same block of 16.
*/
bool resLoadString(dword base, word id, wchar_t* str, size_t str_max)
{
const wchar_t* buf;
word i;
buf = resFind(base, RT_STRING, (word) ((id >> 4) + 1), 0);
if (buf)
{
id &= 15;
for (i = 0; i < id; i++)
{
//wprintf(L"%x\t%s\n", buf[0], buf + 1);
buf += buf[0] + 1;
}
wcsncpy(str, buf + 1, min((word) buf[0], str_max));
return true;
}
else
return false;
}