winemenubuilder: Handle icons disguised as executables and better validate icon streams.
For some applications the shortcut's icon points to a .exe file which in fact contains a .ico file. This means open_icon() cannot rely on the file extension. Also reject icon streams that don't actually contain a valid icon and use the next source as a fallback.
This commit is contained in:
parent
d4b9ac46a0
commit
520dcb4c23
|
@ -964,20 +964,32 @@ end:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT write_native_icon(IStream *iconStream, const char *icon_name, LPCWSTR szFileName)
|
static HRESULT validate_ico(IStream **ppStream, ICONDIRENTRY **ppIconDirEntries, int *numEntries)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = read_ico_direntries(*ppStream, ppIconDirEntries, numEntries);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (*numEntries)
|
||||||
|
return hr;
|
||||||
|
HeapFree(GetProcessHeap(), 0, *ppIconDirEntries);
|
||||||
|
*ppIconDirEntries = NULL;
|
||||||
|
}
|
||||||
|
IStream_Release(*ppStream);
|
||||||
|
*ppStream = NULL;
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT write_native_icon(IStream *iconStream, ICONDIRENTRY *pIconDirEntry,
|
||||||
|
int numEntries, const char *icon_name, LPCWSTR szFileName)
|
||||||
{
|
{
|
||||||
ICONDIRENTRY *pIconDirEntry = NULL;
|
|
||||||
int numEntries;
|
|
||||||
int nMax = 0, nMaxBits = 0;
|
int nMax = 0, nMaxBits = 0;
|
||||||
int nIndex = 0;
|
int nIndex = 0;
|
||||||
int i;
|
int i;
|
||||||
LARGE_INTEGER position;
|
LARGE_INTEGER position;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
hr = read_ico_direntries(iconStream, &pIconDirEntry, &numEntries);
|
|
||||||
if (FAILED(hr))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
for (i = 0; i < numEntries; i++)
|
for (i = 0; i < numEntries; i++)
|
||||||
{
|
{
|
||||||
WINE_TRACE("[%d]: %d x %d @ %d\n", i, pIconDirEntry[i].bWidth, pIconDirEntry[i].bHeight, pIconDirEntry[i].wBitCount);
|
WINE_TRACE("[%d]: %d x %d @ %d\n", i, pIconDirEntry[i].bWidth, pIconDirEntry[i].bHeight, pIconDirEntry[i].wBitCount);
|
||||||
|
@ -1069,7 +1081,7 @@ static HRESULT open_default_icon(IStream **ppStream)
|
||||||
return open_module_icon(user32W, -(INT_PTR)IDI_WINLOGO, ppStream);
|
return open_module_icon(user32W, -(INT_PTR)IDI_WINLOGO, ppStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppStream)
|
static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppStream, ICONDIRENTRY **ppIconDirEntries, int *numEntries)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
@ -1084,16 +1096,25 @@ static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppSt
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static const WCHAR dot_icoW[] = {'.','i','c','o',0};
|
/* This might be a raw .ico file */
|
||||||
int len = strlenW(filename);
|
|
||||||
if (len >= 4 && strcmpiW(&filename[len - 4], dot_icoW) == 0)
|
|
||||||
hr = SHCreateStreamOnFileW(filename, STGM_READ, ppStream);
|
hr = SHCreateStreamOnFileW(filename, STGM_READ, ppStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
hr = open_file_type_icon(filename, ppStream);
|
hr = open_file_type_icon(filename, ppStream);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
|
||||||
|
}
|
||||||
if (FAILED(hr) && !bWait)
|
if (FAILED(hr) && !bWait)
|
||||||
|
{
|
||||||
hr = open_default_icon(ppStream);
|
hr = open_default_icon(ppStream);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
|
||||||
|
}
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1147,11 +1168,10 @@ static inline int size_to_slot(int size)
|
||||||
|
|
||||||
#define CLASSIC_SLOT 3
|
#define CLASSIC_SLOT 3
|
||||||
|
|
||||||
static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR icoPathW,
|
static HRESULT platform_write_icon(IStream *icoStream, ICONDIRENTRY *pIconDirEntry,
|
||||||
|
int numEntries, int exeIndex, LPCWSTR icoPathW,
|
||||||
const char *destFilename, char **nativeIdentifier)
|
const char *destFilename, char **nativeIdentifier)
|
||||||
{
|
{
|
||||||
ICONDIRENTRY *iconDirEntries = NULL;
|
|
||||||
int numEntries;
|
|
||||||
struct {
|
struct {
|
||||||
int index;
|
int index;
|
||||||
int maxBits;
|
int maxBits;
|
||||||
|
@ -1164,9 +1184,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
|
||||||
LARGE_INTEGER zero;
|
LARGE_INTEGER zero;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
hr = read_ico_direntries(icoStream, &iconDirEntries, &numEntries);
|
|
||||||
if (FAILED(hr))
|
|
||||||
goto end;
|
|
||||||
for (i = 0; i < ICNS_SLOTS; i++)
|
for (i = 0; i < ICNS_SLOTS; i++)
|
||||||
{
|
{
|
||||||
best[i].index = -1;
|
best[i].index = -1;
|
||||||
|
@ -1254,7 +1271,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
HeapFree(GetProcessHeap(), 0, iconDirEntries);
|
|
||||||
HeapFree(GetProcessHeap(), 0, icnsPath);
|
HeapFree(GetProcessHeap(), 0, icnsPath);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -1279,20 +1295,15 @@ static void refresh_icon_cache(const char *iconsDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR icoPathW,
|
static HRESULT platform_write_icon(IStream *icoStream, ICONDIRENTRY *iconDirEntries,
|
||||||
|
int numEntries, int exeIndex, LPCWSTR icoPathW,
|
||||||
const char *destFilename, char **nativeIdentifier)
|
const char *destFilename, char **nativeIdentifier)
|
||||||
{
|
{
|
||||||
ICONDIRENTRY *iconDirEntries = NULL;
|
|
||||||
int numEntries;
|
|
||||||
int i;
|
int i;
|
||||||
char *iconsDir = NULL;
|
char *iconsDir = NULL;
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
LARGE_INTEGER zero;
|
LARGE_INTEGER zero;
|
||||||
|
|
||||||
hr = read_ico_direntries(icoStream, &iconDirEntries, &numEntries);
|
|
||||||
if (FAILED(hr))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (destFilename)
|
if (destFilename)
|
||||||
*nativeIdentifier = heap_printf("%s", destFilename);
|
*nativeIdentifier = heap_printf("%s", destFilename);
|
||||||
else
|
else
|
||||||
|
@ -1372,7 +1383,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
|
||||||
refresh_icon_cache(iconsDir);
|
refresh_icon_cache(iconsDir);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
HeapFree(GetProcessHeap(), 0, iconDirEntries);
|
|
||||||
HeapFree(GetProcessHeap(), 0, iconsDir);
|
HeapFree(GetProcessHeap(), 0, iconsDir);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -1382,24 +1392,27 @@ end:
|
||||||
static char *extract_icon(LPCWSTR icoPathW, int index, const char *destFilename, BOOL bWait)
|
static char *extract_icon(LPCWSTR icoPathW, int index, const char *destFilename, BOOL bWait)
|
||||||
{
|
{
|
||||||
IStream *stream = NULL;
|
IStream *stream = NULL;
|
||||||
|
ICONDIRENTRY *pIconDirEntries = NULL;
|
||||||
|
int numEntries;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
char *nativeIdentifier = NULL;
|
char *nativeIdentifier = NULL;
|
||||||
|
|
||||||
WINE_TRACE("path=[%s] index=%d destFilename=[%s]\n", wine_dbgstr_w(icoPathW), index, wine_dbgstr_a(destFilename));
|
WINE_TRACE("path=[%s] index=%d destFilename=[%s]\n", wine_dbgstr_w(icoPathW), index, wine_dbgstr_a(destFilename));
|
||||||
|
|
||||||
hr = open_icon(icoPathW, index, bWait, &stream);
|
hr = open_icon(icoPathW, index, bWait, &stream, &pIconDirEntries, &numEntries);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
WINE_WARN("opening icon %s index %d failed, hr=0x%08X\n", wine_dbgstr_w(icoPathW), index, hr);
|
WINE_WARN("opening icon %s index %d failed, hr=0x%08X\n", wine_dbgstr_w(icoPathW), index, hr);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
hr = platform_write_icon(stream, index, icoPathW, destFilename, &nativeIdentifier);
|
hr = platform_write_icon(stream, pIconDirEntries, numEntries, index, icoPathW, destFilename, &nativeIdentifier);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
WINE_WARN("writing icon failed, error 0x%08X\n", hr);
|
WINE_WARN("writing icon failed, error 0x%08X\n", hr);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (stream)
|
if (stream)
|
||||||
IStream_Release(stream);
|
IStream_Release(stream);
|
||||||
|
HeapFree(GetProcessHeap(), 0, pIconDirEntries);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
HeapFree(GetProcessHeap(), 0, nativeIdentifier);
|
HeapFree(GetProcessHeap(), 0, nativeIdentifier);
|
||||||
|
@ -3472,6 +3485,8 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath)
|
||||||
WCHAR szIconPath[MAX_PATH];
|
WCHAR szIconPath[MAX_PATH];
|
||||||
int iconId;
|
int iconId;
|
||||||
IStream *stream = NULL;
|
IStream *stream = NULL;
|
||||||
|
ICONDIRENTRY *pIconDirEntries = NULL;
|
||||||
|
int numEntries;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
utf8lnkPath = wchars_to_utf8_chars(lnkPath);
|
utf8lnkPath = wchars_to_utf8_chars(lnkPath);
|
||||||
|
@ -3533,15 +3548,15 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath)
|
||||||
|
|
||||||
if (szIconPath[0])
|
if (szIconPath[0])
|
||||||
{
|
{
|
||||||
hr = open_icon(szIconPath, iconId, FALSE, &stream);
|
hr = open_icon(szIconPath, iconId, FALSE, &stream, &pIconDirEntries, &numEntries);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
hr = write_native_icon(stream, utf8OutputPath, NULL);
|
hr = write_native_icon(stream, pIconDirEntries, numEntries, utf8OutputPath, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hr = open_icon(szPath, iconId, FALSE, &stream);
|
hr = open_icon(szPath, iconId, FALSE, &stream, &pIconDirEntries, &numEntries);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
hr = write_native_icon(stream, utf8OutputPath, NULL);
|
hr = write_native_icon(stream, pIconDirEntries, numEntries, utf8OutputPath, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
@ -3554,6 +3569,7 @@ end:
|
||||||
IPersistFile_Release(persistFile);
|
IPersistFile_Release(persistFile);
|
||||||
if (stream != NULL)
|
if (stream != NULL)
|
||||||
IStream_Release(stream);
|
IStream_Release(stream);
|
||||||
|
HeapFree(GetProcessHeap(), 0, pIconDirEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WCHAR *next_token( LPWSTR *p )
|
static WCHAR *next_token( LPWSTR *p )
|
||||||
|
|
Loading…
Reference in New Issue