mirror of
https://github.com/GerbilSoft/rom-properties.git
synced 2025-06-18 19:45:41 -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();
|
int ret = loadResourceReader();
|
||||||
if (ret != 0 || !rsrcReader) {
|
if (ret != 0 || !rsrcReader) {
|
||||||
// No resources available.
|
// 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.
|
// Get the resource ID.
|
||||||
@ -417,7 +436,7 @@ rp_image_const_ptr EXEPrivate::loadSpecificIcon(int iconindex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to load the default icon.
|
// 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()) {
|
if (!ico->isValid()) {
|
||||||
// Unable to load the default icon.
|
// Unable to load the default icon.
|
||||||
return {};
|
return {};
|
||||||
|
@ -838,4 +838,19 @@ int NEResourceReader::lookup_resource_ID(int type, int index)
|
|||||||
return type_dir[index].id;
|
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.
|
* @return Resource ID, or negative POSIX error code on error.
|
||||||
*/
|
*/
|
||||||
int lookup_resource_ID(int type, int index) final;
|
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;
|
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.
|
* @return Resource ID, or negative POSIX error code on error.
|
||||||
*/
|
*/
|
||||||
int lookup_resource_ID(int type, int index) final;
|
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.
|
* @return Resource ID, or negative POSIX error code on error.
|
||||||
*/
|
*/
|
||||||
virtual int lookup_resource_ID(int type, int index) = 0;
|
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;
|
typedef std::shared_ptr<IResourceReader> IResourceReaderPtr;
|
||||||
|
@ -63,9 +63,13 @@ public:
|
|||||||
Icon_Win3 = 2,
|
Icon_Win3 = 2,
|
||||||
Cursor_Win3 = 3,
|
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)
|
// Win3.x resources (RT_GROUP_ICON, RT_GROUP_CURSOR)
|
||||||
IconRes_Win3 = 4,
|
IconRes_Win3 = 6,
|
||||||
CursorRes_Win3 = 5,
|
CursorRes_Win3 = 7,
|
||||||
|
|
||||||
Max
|
Max
|
||||||
};
|
};
|
||||||
@ -85,7 +89,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline bool isResource(void) const
|
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
|
inline uint16_t imageResType(void) const
|
||||||
{
|
{
|
||||||
switch (iconType) {
|
switch (iconType) {
|
||||||
|
case IconType::IconRes_Win1:
|
||||||
case IconType::IconRes_Win3:
|
case IconType::IconRes_Win3:
|
||||||
return RT_ICON;
|
return RT_ICON;
|
||||||
|
case IconType::CursorRes_Win1:
|
||||||
case IconType::CursorRes_Win3:
|
case IconType::CursorRes_Win3:
|
||||||
return RT_CURSOR;
|
return RT_CURSOR;
|
||||||
default:
|
default:
|
||||||
@ -265,15 +271,28 @@ ICOPrivate::ICOPrivate(ICO *q, const IResourceReaderPtr &resReader, uint16_t typ
|
|||||||
memset(&icoHeader, 0, sizeof(icoHeader));
|
memset(&icoHeader, 0, sizeof(icoHeader));
|
||||||
|
|
||||||
// Determine the icon type here.
|
// Determine the icon type here.
|
||||||
assert(type == RT_GROUP_ICON || type == RT_GROUP_CURSOR);
|
assert(type == RT_ICON || type == RT_CURSOR || type == RT_GROUP_ICON || type == RT_GROUP_CURSOR);
|
||||||
if (type == RT_GROUP_ICON) {
|
switch (type) {
|
||||||
iconType = IconType::IconRes_Win3;
|
default:
|
||||||
} else if (type == RT_GROUP_CURSOR) {
|
assert(!"Unsupported resource type");
|
||||||
iconType = IconType::CursorRes_Win3;
|
dir.v = nullptr;
|
||||||
} else {
|
return;
|
||||||
// Unrecognized?
|
|
||||||
dir.v = nullptr;
|
// NOTE: Assuming individual icon/cursor is Windows 1.x/2.x format.
|
||||||
return;
|
// 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.
|
// Initialize the icon directory union.
|
||||||
@ -314,7 +333,7 @@ int ICOPrivate::loadIconDirectory_Win3(void)
|
|||||||
|
|
||||||
// Open the RT_GROUP_ICON / RT_GROUP_CURSOR resource.
|
// Open the RT_GROUP_ICON / RT_GROUP_CURSOR resource.
|
||||||
auto &res = *(dir.res);
|
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) {
|
if (!f_icondir) {
|
||||||
// Unable to open the RT_GROUP_ICON / RT_GROUP_CURSOR.
|
// Unable to open the RT_GROUP_ICON / RT_GROUP_CURSOR.
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
@ -502,7 +521,26 @@ rp_image_const_ptr ICOPrivate::loadImage_Win1(void)
|
|||||||
// Load the icon data.
|
// Load the icon data.
|
||||||
rp::uvector<uint8_t> icon_data;
|
rp::uvector<uint8_t> icon_data;
|
||||||
icon_data.resize(icon_size * 2);
|
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) {
|
if (size != icon_size * 2) {
|
||||||
// Seek and/or read error.
|
// Seek and/or read error.
|
||||||
return {};
|
return {};
|
||||||
@ -873,6 +911,8 @@ rp_image_const_ptr ICOPrivate::loadImage(void)
|
|||||||
|
|
||||||
case IconType::Icon_Win1:
|
case IconType::Icon_Win1:
|
||||||
case IconType::Cursor_Win1:
|
case IconType::Cursor_Win1:
|
||||||
|
case IconType::IconRes_Win1:
|
||||||
|
case IconType::CursorRes_Win1:
|
||||||
// Windows 1.0 icon or cursor
|
// Windows 1.0 icon or cursor
|
||||||
return loadImage_Win1();
|
return loadImage_Win1();
|
||||||
|
|
||||||
@ -918,7 +958,7 @@ ICO::ICO(const IRpFilePtr &file)
|
|||||||
* NOTE: Check isValid() to determine if this is a valid ROM.
|
* NOTE: Check isValid() to determine if this is a valid ROM.
|
||||||
*
|
*
|
||||||
* @param resReader [in] IResourceReader
|
* @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 id [in] Resource ID (-1 for "first entry")
|
||||||
* @param lang [in] Language 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);
|
const auto &res = *(d->dir.res);
|
||||||
IRpFilePtr f_icondir = res.resReader->open(res.type, res.id, res.lang);
|
IRpFilePtr f_icondir = res.resReader->open(res.type, res.id, res.lang);
|
||||||
if (!f_icondir) {
|
if (!f_icondir) {
|
||||||
// Unable to open the RT_GROUP_ICON / RT_GROUP_CURSOR.
|
// Unable to open the icon or cursor.
|
||||||
d->file.reset();
|
d->file.reset();
|
||||||
delete d->dir.res;
|
delete d->dir.res;
|
||||||
d->dir.res = nullptr;
|
d->dir.res = nullptr;
|
||||||
@ -1059,6 +1099,8 @@ void ICO::init(bool res)
|
|||||||
|
|
||||||
case ICOPrivate::IconType::Icon_Win1:
|
case ICOPrivate::IconType::Icon_Win1:
|
||||||
case ICOPrivate::IconType::Cursor_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[0] = le16_to_cpu(d->icoHeader.win1.width);
|
||||||
d->dimensions[1] = le16_to_cpu(d->icoHeader.win1.height);
|
d->dimensions[1] = le16_to_cpu(d->icoHeader.win1.height);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user