mirror of
https://github.com/GerbilSoft/rom-properties.git
synced 2025-06-18 11:35:38 -04:00
[libromdata] EXE: Load icons from Windows 1.x/2.x executables.
Windows 1.x/2.x does not have RT_GROUP_ICON. For NE executables, check for RT_GROUP_ICON, and use it if found. Otherwise, check for RT_ICON and use that if found. IResourceReader: Add a function has_resource_type() to check if the executable has any resources of the specified type. [librptexture] ICO: Handle RT_ICON and RT_CURSOR as Windows 1.x/2.x. TODO: Check the header to verify?
This commit is contained in:
parent
8f762b7c78
commit
22da0c2e21
@ -394,7 +394,26 @@ rp_image_const_ptr EXEPrivate::loadSpecificIcon(int iconindex)
|
||||
int ret = loadResourceReader();
|
||||
if (ret != 0 || !rsrcReader) {
|
||||
// No resources available.
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
uint16_t type = RT_GROUP_ICON;
|
||||
if (exeType == ExeType::NE || exeType == ExeType::COM_NE) {
|
||||
// Windows 1.x/2.x executables don't have RT_GROUP_ICON,
|
||||
// but do have RT_ICON. If this is Win16, check for
|
||||
// RT_GROUP_ICON first, then try RT_ICON.
|
||||
// NOTE: Can't simply check based on if it's a 1.x/2.x
|
||||
// executable because some EXEs converted to 3.x will
|
||||
// still show up as 1.x/2.x.
|
||||
if (rsrcReader->has_resource_type(RT_GROUP_ICON)) {
|
||||
// We have RT_GROUP_ICON.
|
||||
} else if (rsrcReader->has_resource_type(RT_ICON)) {
|
||||
// We have RT_ICON.
|
||||
type = RT_ICON;
|
||||
} else {
|
||||
// No icons...
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Get the resource ID.
|
||||
@ -417,7 +436,7 @@ rp_image_const_ptr EXEPrivate::loadSpecificIcon(int iconindex)
|
||||
}
|
||||
|
||||
// Attempt to load the default icon.
|
||||
unique_ptr<ICO> ico(new ICO(rsrcReader, RT_GROUP_ICON, resID, -1));
|
||||
unique_ptr<ICO> ico(new ICO(rsrcReader, type, resID, -1));
|
||||
if (!ico->isValid()) {
|
||||
// Unable to load the default icon.
|
||||
return {};
|
||||
|
@ -838,4 +838,19 @@ int NEResourceReader::lookup_resource_ID(int type, int index)
|
||||
return type_dir[index].id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we have any resources of the specified type?
|
||||
* @param type [in] Resource type ID
|
||||
* @return True if we have these resources; false if we don't.
|
||||
*/
|
||||
bool NEResourceReader::has_resource_type(int type)
|
||||
{
|
||||
// NOTE: Type and resource IDs have the high bit set for integers.
|
||||
// We're only supporting integer IDs, so set the high bits here.
|
||||
type |= 0x8000;
|
||||
|
||||
RP_D(const NEResourceReader);
|
||||
return (d->res_types.find(type) != d->res_types.end());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -126,6 +126,13 @@ public:
|
||||
* @return Resource ID, or negative POSIX error code on error.
|
||||
*/
|
||||
int lookup_resource_ID(int type, int index) final;
|
||||
|
||||
/**
|
||||
* Do we have any resources of the specified type?
|
||||
* @param type [in] Resource type ID
|
||||
* @return True if we have these resources; false if we don't.
|
||||
*/
|
||||
bool has_resource_type(int type) final;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -892,4 +892,15 @@ int PEResourceReader::lookup_resource_ID(int type, int index)
|
||||
return type_dir->at(index).id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we have any resources of the specified type?
|
||||
* @param type [in] Resource type ID
|
||||
* @return True if we have these resources; false if we don't.
|
||||
*/
|
||||
bool PEResourceReader::has_resource_type(int type)
|
||||
{
|
||||
RP_D(PEResourceReader);
|
||||
return (d->getTypeDir(type) != nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -127,6 +127,13 @@ public:
|
||||
* @return Resource ID, or negative POSIX error code on error.
|
||||
*/
|
||||
int lookup_resource_ID(int type, int index) final;
|
||||
|
||||
/**
|
||||
* Do we have any resources of the specified type?
|
||||
* @param type [in] Resource type ID
|
||||
* @return True if we have these resources; false if we don't.
|
||||
*/
|
||||
bool has_resource_type(int type) final;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -129,6 +129,13 @@ public:
|
||||
* @return Resource ID, or negative POSIX error code on error.
|
||||
*/
|
||||
virtual int lookup_resource_ID(int type, int index) = 0;
|
||||
|
||||
/**
|
||||
* Do we have any resources of the specified type?
|
||||
* @param type [in] Resource type ID
|
||||
* @return True if we have these resources; false if we don't.
|
||||
*/
|
||||
virtual bool has_resource_type(int type) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IResourceReader> IResourceReaderPtr;
|
||||
|
@ -63,9 +63,13 @@ public:
|
||||
Icon_Win3 = 2,
|
||||
Cursor_Win3 = 3,
|
||||
|
||||
// Win1.x resources (RT_ICON, RT_CURSOR)
|
||||
IconRes_Win1 = 4,
|
||||
CursorRes_Win1 = 5,
|
||||
|
||||
// Win3.x resources (RT_GROUP_ICON, RT_GROUP_CURSOR)
|
||||
IconRes_Win3 = 4,
|
||||
CursorRes_Win3 = 5,
|
||||
IconRes_Win3 = 6,
|
||||
CursorRes_Win3 = 7,
|
||||
|
||||
Max
|
||||
};
|
||||
@ -85,7 +89,7 @@ public:
|
||||
*/
|
||||
inline bool isResource(void) const
|
||||
{
|
||||
return (iconType >= IconType::IconRes_Win3) && (iconType <= IconType::CursorRes_Win3);
|
||||
return (iconType >= IconType::IconRes_Win1) && (iconType <= IconType::CursorRes_Win3);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,8 +99,10 @@ public:
|
||||
inline uint16_t imageResType(void) const
|
||||
{
|
||||
switch (iconType) {
|
||||
case IconType::IconRes_Win1:
|
||||
case IconType::IconRes_Win3:
|
||||
return RT_ICON;
|
||||
case IconType::CursorRes_Win1:
|
||||
case IconType::CursorRes_Win3:
|
||||
return RT_CURSOR;
|
||||
default:
|
||||
@ -265,15 +271,28 @@ ICOPrivate::ICOPrivate(ICO *q, const IResourceReaderPtr &resReader, uint16_t typ
|
||||
memset(&icoHeader, 0, sizeof(icoHeader));
|
||||
|
||||
// Determine the icon type here.
|
||||
assert(type == RT_GROUP_ICON || type == RT_GROUP_CURSOR);
|
||||
if (type == RT_GROUP_ICON) {
|
||||
iconType = IconType::IconRes_Win3;
|
||||
} else if (type == RT_GROUP_CURSOR) {
|
||||
iconType = IconType::CursorRes_Win3;
|
||||
} else {
|
||||
// Unrecognized?
|
||||
dir.v = nullptr;
|
||||
return;
|
||||
assert(type == RT_ICON || type == RT_CURSOR || type == RT_GROUP_ICON || type == RT_GROUP_CURSOR);
|
||||
switch (type) {
|
||||
default:
|
||||
assert(!"Unsupported resource type");
|
||||
dir.v = nullptr;
|
||||
return;
|
||||
|
||||
// NOTE: Assuming individual icon/cursor is Windows 1.x/2.x format.
|
||||
// TODO: Check the header to verify?
|
||||
case RT_ICON:
|
||||
iconType = IconType::IconRes_Win1;
|
||||
break;
|
||||
case RT_CURSOR:
|
||||
iconType = IconType::CursorRes_Win1;
|
||||
break;
|
||||
|
||||
case RT_GROUP_ICON:
|
||||
iconType = IconType::IconRes_Win3;
|
||||
break;
|
||||
case RT_GROUP_CURSOR:
|
||||
iconType = IconType::CursorRes_Win3;
|
||||
break;
|
||||
}
|
||||
|
||||
// Initialize the icon directory union.
|
||||
@ -314,7 +333,7 @@ int ICOPrivate::loadIconDirectory_Win3(void)
|
||||
|
||||
// Open the RT_GROUP_ICON / RT_GROUP_CURSOR resource.
|
||||
auto &res = *(dir.res);
|
||||
IRpFilePtr f_icondir = res.resReader->open(res.type, res.id, res.lang);
|
||||
IRpFilePtr f_icondir = res.resReader->open(rt, res.id, res.lang);
|
||||
if (!f_icondir) {
|
||||
// Unable to open the RT_GROUP_ICON / RT_GROUP_CURSOR.
|
||||
return -ENOENT;
|
||||
@ -502,7 +521,26 @@ rp_image_const_ptr ICOPrivate::loadImage_Win1(void)
|
||||
// Load the icon data.
|
||||
rp::uvector<uint8_t> icon_data;
|
||||
icon_data.resize(icon_size * 2);
|
||||
size_t size = file->seekAndRead(sizeof(icoHeader.win1), icon_data.data(), icon_size * 2);
|
||||
|
||||
// Is this from a file or a resource?
|
||||
size_t size;
|
||||
const uint16_t rt = imageResType();
|
||||
if (rt != 0) {
|
||||
// Open the resource.
|
||||
const auto &res = *(dir.res);
|
||||
IRpFilePtr f_icon = res.resReader->open(rt, res.id, res.lang);
|
||||
if (!f_icon) {
|
||||
// Unable to open the resource.
|
||||
return {};
|
||||
}
|
||||
|
||||
// Read from the resource.
|
||||
size = f_icon->seekAndRead(sizeof(icoHeader.win1), icon_data.data(), icon_size * 2);
|
||||
} else {
|
||||
// Read from the file.
|
||||
size = file->seekAndRead(sizeof(icoHeader.win1), icon_data.data(), icon_size * 2);
|
||||
}
|
||||
|
||||
if (size != icon_size * 2) {
|
||||
// Seek and/or read error.
|
||||
return {};
|
||||
@ -873,6 +911,8 @@ rp_image_const_ptr ICOPrivate::loadImage(void)
|
||||
|
||||
case IconType::Icon_Win1:
|
||||
case IconType::Cursor_Win1:
|
||||
case IconType::IconRes_Win1:
|
||||
case IconType::CursorRes_Win1:
|
||||
// Windows 1.0 icon or cursor
|
||||
return loadImage_Win1();
|
||||
|
||||
@ -918,7 +958,7 @@ ICO::ICO(const IRpFilePtr &file)
|
||||
* NOTE: Check isValid() to determine if this is a valid ROM.
|
||||
*
|
||||
* @param resReader [in] IResourceReader
|
||||
* @param type [in] Resource type ID (RT_GROUP_ICON or RT_GROUP_CURSOR)
|
||||
* @param type [in] Resource type ID
|
||||
* @param id [in] Resource ID (-1 for "first entry")
|
||||
* @param lang [in] Language ID (-1 for "first entry")
|
||||
*/
|
||||
@ -946,7 +986,7 @@ void ICO::init(bool res)
|
||||
const auto &res = *(d->dir.res);
|
||||
IRpFilePtr f_icondir = res.resReader->open(res.type, res.id, res.lang);
|
||||
if (!f_icondir) {
|
||||
// Unable to open the RT_GROUP_ICON / RT_GROUP_CURSOR.
|
||||
// Unable to open the icon or cursor.
|
||||
d->file.reset();
|
||||
delete d->dir.res;
|
||||
d->dir.res = nullptr;
|
||||
@ -1059,6 +1099,8 @@ void ICO::init(bool res)
|
||||
|
||||
case ICOPrivate::IconType::Icon_Win1:
|
||||
case ICOPrivate::IconType::Cursor_Win1:
|
||||
case ICOPrivate::IconType::IconRes_Win1:
|
||||
case ICOPrivate::IconType::CursorRes_Win1:
|
||||
d->dimensions[0] = le16_to_cpu(d->icoHeader.win1.width);
|
||||
d->dimensions[1] = le16_to_cpu(d->icoHeader.win1.height);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user