mirror of
https://github.com/GerbilSoft/rom-properties.git
synced 2025-06-18 19:45:41 -04:00
[libromdata] EXE: Add icon thumbnailing using librptexture's ICO class.
Uses the first icon in the first available language. New function loadResourceReader() which ensures rsrcReader is loaded. [librptexture] ICO: Fix resource loading issues: - Use the correct resource file pointer, not this->file. - Add IconRes_Win3 and CursorRes_Win3 cases where appropriate. - Ensure d->iconType doesn't get overwritten after it's set by the ICOPrivate constructor for resources. FIXME: VBoxWindowsAdditions.exe's PNG icon loads fine, but the 128x128 "regular" icon is corrupted.
This commit is contained in:
parent
9994c2df94
commit
f5be3c81a4
@ -16,9 +16,14 @@ using namespace LibRpBase;
|
||||
using namespace LibRpFile;
|
||||
using namespace LibRpText;
|
||||
|
||||
// Windows icon handler
|
||||
#include "librptexture/fileformat/ICO.hpp"
|
||||
using namespace LibRpTexture;
|
||||
|
||||
// C++ STL classes
|
||||
using std::array;
|
||||
using std::string;
|
||||
using std::unique_ptr;
|
||||
using std::vector;
|
||||
|
||||
// EXE data
|
||||
@ -96,6 +101,37 @@ EXEPrivate::EXEPrivate(const IRpFilePtr &file)
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the resource reader is loaded.
|
||||
* @return 0 on success; negative POSIX error code on error.
|
||||
*/
|
||||
int EXEPrivate::loadResourceReader(void)
|
||||
{
|
||||
if (rsrcReader) {
|
||||
// Resource reader is already loaded.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = -1;
|
||||
switch (exeType) {
|
||||
default:
|
||||
// Unable to load resources from this type of executable.
|
||||
return -ENOENT;
|
||||
|
||||
case EXEPrivate::ExeType::NE:
|
||||
case EXEPrivate::ExeType::COM_NE:
|
||||
ret = loadNEResourceTable();
|
||||
break;
|
||||
|
||||
case EXEPrivate::ExeType::PE:
|
||||
case EXEPrivate::ExeType::PE32PLUS:
|
||||
ret = loadPEResourceTypes();
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add VS_VERSION_INFO fields.
|
||||
*
|
||||
@ -342,6 +378,38 @@ void EXEPrivate::addFields_VS_VERSION_INFO(const VS_FIXEDFILEINFO *pVsFfi, const
|
||||
fields.addField_listData("StringFileInfo", ¶ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the icon.
|
||||
* @return Icon, or nullptr on error.
|
||||
*/
|
||||
rp_image_const_ptr EXEPrivate::loadIcon(void)
|
||||
{
|
||||
if (img_icon) {
|
||||
// Icon has already been loaded.
|
||||
return img_icon;
|
||||
} else if (!this->isValid || static_cast<int>(this->exeType) < 0) {
|
||||
// Can't load the icon.
|
||||
return {};
|
||||
}
|
||||
|
||||
// Make sure the the resource reader is loaded.
|
||||
int ret = loadResourceReader();
|
||||
if (ret != 0 || !rsrcReader) {
|
||||
// No resources available.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Attempt to load the default icon.
|
||||
unique_ptr<ICO> ico(new ICO(rsrcReader, RT_GROUP_ICON, -1, -1));
|
||||
if (!ico->isValid()) {
|
||||
// Unable to load the default icon.
|
||||
return {};
|
||||
}
|
||||
|
||||
// Return the icon's image.
|
||||
return ico->image();
|
||||
}
|
||||
|
||||
/** MZ-specific **/
|
||||
|
||||
/**
|
||||
@ -936,6 +1004,92 @@ const char *EXE::systemName(unsigned int type) const
|
||||
return C_("EXE", "Unknown EXE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bitfield of image types this class can retrieve.
|
||||
* @return Bitfield of supported image types. (ImageTypesBF)
|
||||
*/
|
||||
uint32_t EXE::supportedImageTypes_static(void)
|
||||
{
|
||||
return IMGBF_INT_ICON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bitfield of image types this object can retrieve.
|
||||
* @return Bitfield of supported image types. (ImageTypesBF)
|
||||
*/
|
||||
uint32_t EXE::supportedImageTypes(void) const
|
||||
{
|
||||
return supportedImageTypes_static();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all available image sizes for the specified image type.
|
||||
* @param imageType Image type.
|
||||
* @return Vector of available image sizes, or empty vector if no images are available.
|
||||
*/
|
||||
vector<RomData::ImageSizeDef> EXE::supportedImageSizes_static(ImageType imageType)
|
||||
{
|
||||
ASSERT_supportedImageSizes(imageType);
|
||||
|
||||
switch (imageType) {
|
||||
case IMG_INT_ICON:
|
||||
// Assuming 32x32.
|
||||
return {{nullptr, 32, 32, 0}};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Unsupported image type.
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all available image sizes for the specified image type.
|
||||
* @param imageType Image type.
|
||||
* @return Vector of available image sizes, or empty vector if no images are available.
|
||||
*/
|
||||
vector<RomData::ImageSizeDef> EXE::supportedImageSizes(ImageType imageType) const
|
||||
{
|
||||
ASSERT_supportedImageSizes(imageType);
|
||||
|
||||
switch (imageType) {
|
||||
case IMG_INT_ICON:
|
||||
// Assuming 32x32.
|
||||
// TODO: Load the icon and check?
|
||||
return {{nullptr, 32, 32, 0}};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Unsupported image type.
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image processing flags.
|
||||
*
|
||||
* These specify post-processing operations for images,
|
||||
* e.g. applying transparency masks.
|
||||
*
|
||||
* @param imageType Image type.
|
||||
* @return Bitfield of ImageProcessingBF operations to perform.
|
||||
*/
|
||||
uint32_t EXE::imgpf(ImageType imageType) const
|
||||
{
|
||||
ASSERT_imgpf(imageType);
|
||||
|
||||
uint32_t ret = 0;
|
||||
switch (imageType) {
|
||||
case IMG_INT_ICON:
|
||||
// TODO: Use nearest-neighbor for < 64x64.
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load field data.
|
||||
* Called by RomData::fields() if the field data hasn't been loaded yet.
|
||||
@ -1047,23 +1201,7 @@ int EXE::loadMetaData(void)
|
||||
|
||||
// We can parse fields for NE (Win16) and PE (Win32) executables,
|
||||
// if they have a resource section.
|
||||
int ret = -1;
|
||||
switch (d->exeType) {
|
||||
default:
|
||||
// Cannot load any metadata...
|
||||
return 0;
|
||||
|
||||
case EXEPrivate::ExeType::NE:
|
||||
case EXEPrivate::ExeType::COM_NE:
|
||||
ret = d->loadNEResourceTable();
|
||||
break;
|
||||
|
||||
case EXEPrivate::ExeType::PE:
|
||||
case EXEPrivate::ExeType::PE32PLUS:
|
||||
ret = d->loadPEResourceTypes();
|
||||
break;
|
||||
}
|
||||
|
||||
int ret = d->loadResourceReader();
|
||||
if (ret != 0 || !d->rsrcReader) {
|
||||
// No resources available.
|
||||
return 0;
|
||||
@ -1164,6 +1302,26 @@ bool EXE::hasDangerousPermissions(void) const
|
||||
#endif /* ENABLE_XML */
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an internal image.
|
||||
* Called by RomData::image().
|
||||
* @param imageType [in] Image type to load.
|
||||
* @param pImage [out] Reference to rp_image_const_ptr to store the image in.
|
||||
* @return 0 on success; negative POSIX error code on error.
|
||||
*/
|
||||
int EXE::loadInternalImage(ImageType imageType, rp_image_const_ptr &pImage)
|
||||
{
|
||||
ASSERT_loadInternalImage(imageType, pImage);
|
||||
RP_D(EXE);
|
||||
ROMDATA_loadInternalImage_single(
|
||||
IMG_INT_ICON, // ourImageType
|
||||
d->file, // file
|
||||
d->isValid, // isValid
|
||||
d->exeType, // romType
|
||||
d->img_icon, // imgCache
|
||||
d->loadIcon); // func
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for "viewed" achievements.
|
||||
*
|
||||
|
@ -2,7 +2,7 @@
|
||||
* ROM Properties Page shell extension. (libromdata) *
|
||||
* EXE.hpp: DOS/Windows executable reader. *
|
||||
* *
|
||||
* Copyright (c) 2016-2023 by David Korth. *
|
||||
* Copyright (c) 2016-2025 by David Korth. *
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later *
|
||||
***************************************************************************/
|
||||
|
||||
@ -15,6 +15,9 @@ namespace LibRomData {
|
||||
ROMDATA_DECL_BEGIN(EXE)
|
||||
ROMDATA_DECL_DANGEROUS()
|
||||
ROMDATA_DECL_METADATA()
|
||||
ROMDATA_DECL_IMGSUPPORT()
|
||||
ROMDATA_DECL_IMGPF()
|
||||
ROMDATA_DECL_IMGINT()
|
||||
ROMDATA_DECL_VIEWED_ACHIEVEMENTS()
|
||||
ROMDATA_DECL_END()
|
||||
|
||||
|
@ -102,6 +102,12 @@ public:
|
||||
// Resource reader
|
||||
IResourceReaderPtr rsrcReader;
|
||||
|
||||
/**
|
||||
* Make sure the resource reader is loaded.
|
||||
* @return 0 on success; negative POSIX error code on error.
|
||||
*/
|
||||
int loadResourceReader(void);
|
||||
|
||||
/**
|
||||
* Add VS_VERSION_INFO fields.
|
||||
*
|
||||
@ -113,6 +119,15 @@ public:
|
||||
*/
|
||||
void addFields_VS_VERSION_INFO(const VS_FIXEDFILEINFO *pVsFfi, const IResourceReader::StringFileInfo *pVsSfi);
|
||||
|
||||
// Icon
|
||||
LibRpTexture::rp_image_ptr img_icon;
|
||||
|
||||
/**
|
||||
* Load the icon.
|
||||
* @return Icon, or nullptr on error.
|
||||
*/
|
||||
LibRpTexture::rp_image_const_ptr loadIcon(void);
|
||||
|
||||
/** MZ-specific **/
|
||||
|
||||
/**
|
||||
|
@ -322,7 +322,7 @@ int ICOPrivate::loadIconDirectory_Win3(void)
|
||||
const size_t fullsize = count * sizeof(GRPICONDIRENTRY);
|
||||
auto &iconDirectory = res.iconDirectory;
|
||||
iconDirectory.resize(count);
|
||||
size_t size = file->seekAndRead(sizeof(GRPICONDIR), iconDirectory.data(), fullsize);
|
||||
size_t size = f_icondir->seekAndRead(sizeof(GRPICONDIR), iconDirectory.data(), fullsize);
|
||||
if (size != fullsize) {
|
||||
// Seek and/or read error.
|
||||
iconDirectory.clear();
|
||||
@ -341,7 +341,7 @@ int ICOPrivate::loadIconDirectory_Win3(void)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
size_t size = file->read(p, sizeof(*p));
|
||||
size_t size = f_icon->read(p, sizeof(*p));
|
||||
if (size != sizeof(*p)) {
|
||||
// Short read.
|
||||
iconDirectory.clear();
|
||||
@ -877,6 +877,8 @@ rp_image_const_ptr ICOPrivate::loadImage(void)
|
||||
|
||||
case IconType::Icon_Win3:
|
||||
case IconType::Cursor_Win3:
|
||||
case IconType::IconRes_Win3:
|
||||
case IconType::CursorRes_Win3:
|
||||
// Windows 3.x icon or cursor
|
||||
return loadImage_Win3();
|
||||
}
|
||||
@ -949,6 +951,7 @@ void ICO::init(bool res)
|
||||
d->dir.res = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = f_icondir->read(&d->icoHeader, sizeof(d->icoHeader));
|
||||
if (size != sizeof(d->icoHeader)) {
|
||||
d->file.reset();
|
||||
@ -966,6 +969,8 @@ void ICO::init(bool res)
|
||||
}
|
||||
|
||||
// Determine the icon type.
|
||||
// NOTE: d->iconType is already set if loading from a Windows resource.
|
||||
// Only set it if it's still ICOPrivate::IconType::Unknown.
|
||||
switch (le16_to_cpu(d->icoHeader.win1.format)) {
|
||||
default:
|
||||
// Not recognized...
|
||||
@ -987,12 +992,16 @@ void ICO::init(bool res)
|
||||
}
|
||||
return;
|
||||
case ICO_WIN3_TYPE_ICON:
|
||||
d->iconType = ICOPrivate::IconType::Icon_Win3;
|
||||
if (d->iconType == ICOPrivate::IconType::Unknown) {
|
||||
d->iconType = ICOPrivate::IconType::Icon_Win3;
|
||||
}
|
||||
d->mimeType = "image/vnd.microsoft.icon";
|
||||
d->textureFormatName = "Windows 3.x Icon";
|
||||
break;
|
||||
case ICO_WIN3_TYPE_CURSOR:
|
||||
d->iconType = ICOPrivate::IconType::Cursor_Win3;
|
||||
if (d->iconType == ICOPrivate::IconType::Unknown) {
|
||||
d->iconType = ICOPrivate::IconType::Cursor_Win3;
|
||||
}
|
||||
d->mimeType = "image/vnd.microsoft.cursor";
|
||||
d->textureFormatName = "Windows 3.x Icon";
|
||||
break;
|
||||
@ -1015,7 +1024,9 @@ void ICO::init(bool res)
|
||||
case ICO_WIN1_FORMAT_ICON_DIB:
|
||||
case ICO_WIN1_FORMAT_ICON_DDB:
|
||||
case ICO_WIN1_FORMAT_ICON_BOTH:
|
||||
d->iconType = ICOPrivate::IconType::Icon_Win1;
|
||||
if (d->iconType == ICOPrivate::IconType::Unknown) {
|
||||
d->iconType = ICOPrivate::IconType::Icon_Win1;
|
||||
}
|
||||
// TODO: Different MIME type for Windows 1.x?
|
||||
d->mimeType = "image/vnd.microsoft.icon";
|
||||
d->textureFormatName = "Windows 1.x Icon";
|
||||
@ -1024,7 +1035,9 @@ void ICO::init(bool res)
|
||||
case ICO_WIN1_FORMAT_CURSOR_DIB:
|
||||
case ICO_WIN1_FORMAT_CURSOR_DDB:
|
||||
case ICO_WIN1_FORMAT_CURSOR_BOTH:
|
||||
d->iconType = ICOPrivate::IconType::Cursor_Win1;
|
||||
if (d->iconType == ICOPrivate::IconType::Unknown) {
|
||||
d->iconType = ICOPrivate::IconType::Cursor_Win1;
|
||||
}
|
||||
// TODO: Different MIME type for Windows 1.x?
|
||||
d->mimeType = "image/vnd.microsoft.cursor";
|
||||
d->textureFormatName = "Windows 1.x Cursor";
|
||||
@ -1051,7 +1064,8 @@ void ICO::init(bool res)
|
||||
|
||||
case ICOPrivate::IconType::Icon_Win3:
|
||||
case ICOPrivate::IconType::Cursor_Win3:
|
||||
// TODO: Need to check BITMAPINFOHEADER, BITMAPCOREHEADER, or PNG header.
|
||||
case ICOPrivate::IconType::IconRes_Win3:
|
||||
case ICOPrivate::IconType::CursorRes_Win3:
|
||||
if (!d->dir.ico->pBestIcon) {
|
||||
// No "best" icon...
|
||||
d->file.reset();
|
||||
|
Loading…
Reference in New Issue
Block a user