Icon now supports the res:// protocol

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@7328 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2021-09-18 20:24:41 +00:00
parent cc431158fd
commit 167e53df8a
6 changed files with 266 additions and 127 deletions

View file

@ -30,6 +30,7 @@ using namespace std;
// Utilities
//////////////////////////////////////////////////////////////////////
#define FIRSTRESDIRSTRADDRESS ( (WINWCHAR*)(~(size_t)0) )
#define WCHARPTR2WINWCHARPTR(s) ( (WINWCHAR*) (s) ) // Only for WinSDK structs like IMAGE_RESOURCE_DIR_STRING_U where we cannot change the WCHAR type!
#define RALIGN(dwToAlign, dwAlignOn) ((dwToAlign%dwAlignOn == 0) ? dwToAlign : dwToAlign - (dwToAlign%dwAlignOn) + dwAlignOn)
#define ALIGN(dwToAlign, dwAlignOn) dwToAlign = RALIGN((dwToAlign), (dwAlignOn))
@ -37,6 +38,31 @@ using namespace std;
static inline DWORD ConvertEndianness(DWORD d) { return FIX_ENDIAN_INT32(d); }
static inline WORD ConvertEndianness(WORD w) { return FIX_ENDIAN_INT16(w); }
#if !(defined(_WIN32) && defined(_UNICODE))
static void FreeUnicodeResString(WINWCHAR* s) {
if (!IS_INTRESOURCE(s) && FIRSTRESDIRSTRADDRESS != (WINWCHAR*) s)
free(s);
}
static WINWCHAR* ResStringToUnicode(const char *s) {
if (IS_INTRESOURCE(s)) return MAKEINTRESOURCEWINW((ULONG_PTR)s);
if (FIRSTRESDIRSTRADDRESS == (WINWCHAR*) s) return (WINWCHAR*) s;
WINWCHAR *ws = WinWStrDupFromTChar(s);
if (!ws) throw std::runtime_error("Unicode conversion failed");
return ws;
}
#endif //~ !(_WIN32 && _UNICODE)
struct UTF16LEResString {
WINWCHAR *m_s;
operator WINWCHAR*() const { return m_s; }
#if defined(_WIN32) && defined(_UNICODE)
UTF16LEResString(const TCHAR*tstr) : m_s((WINWCHAR*) tstr) {}
#else
UTF16LEResString(const TCHAR*tstr) : m_s(ResStringToUnicode(tstr)) { }
~UTF16LEResString() { FreeUnicodeResString(m_s); }
#endif
};
PIMAGE_NT_HEADERS CResourceEditor::GetNTHeaders(BYTE* pbPE) {
// Get dos header
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) pbPE;
@ -140,12 +166,13 @@ const TCHAR* CResourceEditor::ParseResourceTypeString(const TCHAR*Str)
#include "exehead/resource.h" // IDI_ICON2
#include "exehead/config.h" // NSIS_DEFAULT_LANG
const TCHAR* CResourceEditor::ParseResourceNameString(const TCHAR*Str) {
const TCHAR* CResourceEditor::ParseResourceNameString(const TCHAR*Str, bool AllowFirst) {
if (Str[0] == _T('#'))
{
++Str;
if (!_tcsicmp(Str, _T("Version"))) return (TCHAR*) MAKEINTRESOURCE(1);
if (!_tcsicmp(Str, _T("Icon"))) return (TCHAR*) MAKEINTRESOURCE(IDI_ICON2);
if (AllowFirst && Str[0] == '?' && !Str[1]) return (TCHAR*) FIRSTRESDIRSTRADDRESS;
int succ, num = ParseSimpleInt(Str, &succ);
return succ && IS_INTRESOURCE(num) ? (TCHAR*) MAKEINTRESOURCE(num) : NULL;
}
@ -161,19 +188,26 @@ LANGID CResourceEditor::ParseResourceLangString(const TCHAR*Str) {
return succ ? num : INVALIDLANGID;
}
LANGID CResourceEditor::ParseResourceTypeNameLangString(const TCHAR**Type, const TCHAR**Name, const TCHAR*Lang) {
LANGID CResourceEditor::ParseResourceTypeNameLangString(const TCHAR**Type, const TCHAR**Name, const TCHAR*Lang, bool AllowFirst) {
if (!(*Type = ParseResourceTypeString(*Type))) return INVALIDLANGID;
if (!(*Name = ParseResourceNameString(*Name))) return INVALIDLANGID;
if (!(*Name = ParseResourceNameString(*Name, AllowFirst))) return INVALIDLANGID;
return ParseResourceLangString(Lang);
}
UINT CResourceEditor::IsResProtocol(const TCHAR*Url)
{
if ('r' == S7ChLwr(Url[0]) && 'e' == S7ChLwr(Url[1]) && 's' == S7ChLwr(Url[2]))
if (':' == Url[3] && '/' == Url[4] && '/' == Url[5])
return 6;
return 0;
}
static TCHAR* ParseResProtocolAlloc(const TCHAR*Url, const TCHAR*&Type, const TCHAR*&Name, LANGID&Lang) {
//msdn.microsoft.com/library/aa767740#res Protocol
TCHAR proto[42], *path = 0, *buf = 0, *pD, ch;
UINT prefix = 6, mswin = Platform_IsWindows(), bad = false, pipe = 0, skip = 0;
my_strncpy(proto, Url, prefix+!0);
TCHAR *path = 0, *buf = 0, *pD, ch;
UINT prefix, mswin = Platform_IsWindows(), bad = false, pipe = 0, skip = 0;
size_t typestart = 0, namestart = 0, i, cch;
if (lowercase(tstring(proto)).compare(_T("res://")) != 0)
if (!(prefix = CResourceEditor::IsResProtocol(Url)))
return path;
for (Url += prefix, i = 0; Url[i]; ++i)
if (Url[i] == '/')
@ -201,7 +235,7 @@ static TCHAR* ParseResProtocolAlloc(const TCHAR*Url, const TCHAR*&Type, const TC
}
if (!(*pD = (mswin && ch == '/') ? '\\' : ch)) break; // Convert path if needed and stop at the end.
}
Lang = CResourceEditor::ParseResourceTypeNameLangString(&rt, &rn, rl);
Lang = CResourceEditor::ParseResourceTypeNameLangString(&rt, &rn, rl, true);
if (!bad && Lang != CResourceEditor::INVALIDLANGID)
path = buf, Type = rt, Name = rn;
}
@ -275,26 +309,44 @@ CResourceEditor::~CResourceEditor() {
// Methods
//////////////////////////////////////////////////////////////////////
#define FINDRESOURCE_NAME_FIRSTITEM ( (WINWCHAR*)(~(size_t)0) )
bool CResourceEditor::CanOpen(const void*Data, size_t Size)
{
return 'P' == GetExeType(Data, Size); // We only understand PE, not NE/LE
}
CResourceDirectoryEntry* CResourceEditor::FindResourceLanguageDirEntryW(const WINWCHAR* Type, const WINWCHAR* Name, LANGID Language) {
int i = m_cResDir->Find(Type);
if (-1 != i) {
CResourceDirectory* pND = m_cResDir->GetEntry(i)->GetSubDirectory();
i = FINDRESOURCE_NAME_FIRSTITEM == Name ? 0 : pND->Find(Name);
if (-1 != i) {
CResourceDirectory* pLD = pND->GetEntry(i)->GetSubDirectory();
i = ANYLANGID == Language ? 0 : pLD->Find(Language);
if (-1 != i)
return pLD->GetEntry(i);
CResourceDataEntry* CResourceEditor::FindResourceW(const WINWCHAR*RT, const WINWCHAR*RN, LANGID RL, CResourceDirectoryEntry**ppTE, CResourceDirectoryEntry**ppNE, CResourceDirectoryEntry**ppLE) const {
int i = m_cResDir->Find(RT);
CResourceDirectoryEntry*pTDE = -1 != i ? m_cResDir->GetEntry(i) : 0, *pNDE, *pLDE;
if (pTDE) {
CResourceDirectory *pND = pTDE->GetSubDirectory();
i = FIRSTRESDIRSTRADDRESS == RN ? 0 : pND->Find(RN);
if ((pNDE = (-1 != i) ? pND->GetEntry(i) : 0)) {
CResourceDirectory *pLD = pNDE->GetSubDirectory();
i = ANYLANGID == RL ? 0 : pLD->Find(RL);
if ((pLDE = (-1 != i) ? pLD->GetEntry(i) : 0)) {
if (ppTE) *ppTE = pTDE;
if (ppNE) *ppNE = pNDE;
if (ppLE) *ppLE = pLDE;
return pLDE->GetDataEntry();
}
}
}
return 0;
}
CResourceDataEntry* CResourceEditor::FindResource(const WINWCHAR* Type, const WINWCHAR* Name, LANGID Language) {
CResourceDirectoryEntry*pRDE = FindResourceLanguageDirEntryW(Type, Name, Language);
return pRDE ? pRDE->GetDataEntry() : 0;
CResourceDataEntry* CResourceEditor::FindResourceT(const TCHAR*RT, const TCHAR*RN, LANGID RL, CResourceDirectoryEntry**ppTE, CResourceDirectoryEntry**ppNE, CResourceDirectoryEntry**ppLE) const {
return FindResourceW(UTF16LEResString(RT), UTF16LEResString(RN), RL, ppTE, ppNE, ppLE);
}
CResourceDirectoryEntry* CResourceEditor::FindResourceLanguageDirEntryW(const WINWCHAR* RT, const WINWCHAR* RN, LANGID RL) const {
CResourceDirectoryEntry*pLDE = 0;
FindResourceW(RT, RN, RL, 0, 0, &pLDE);
return pLDE;
}
CResourceDataEntry* CResourceEditor::FindResource(const WINWCHAR* RT, const WINWCHAR* RN, LANGID RL) const {
CResourceDirectoryEntry*pDE = FindResourceLanguageDirEntryW(RT, RN, RL);
return pDE ? pDE->GetDataEntry() : 0;
}
template<class T> static void UpdateManipulationType(CResourceEditor::TYPEMANIPULATION &Manip, const T* szType, const void*Data, size_t Size) {
@ -408,37 +460,13 @@ bool CResourceEditor::UpdateResourceW(const WINWCHAR* szType, WINWCHAR* szName,
return success;
}
#ifndef _UNICODE
static WINWCHAR* ResStringToUnicode(const char *szString) {
if (IS_INTRESOURCE(szString)) return MAKEINTRESOURCEWINW((ULONG_PTR)szString);
WINWCHAR *s = WinWStrDupFromTChar(szString);
if (!s) throw std::bad_alloc();
return s;
}
static void FreeUnicodeResString(WINWCHAR* szwString) {
if (!IS_INTRESOURCE(szwString)) free(szwString);
}
#else
#ifndef _WIN32
static WINWCHAR* ResStringToUnicode(const TCHAR *s) {
if (IS_INTRESOURCE(s)) return MAKEINTRESOURCEWINW((ULONG_PTR)s);
WCToUTF16LEHlpr cnv;
if (!cnv.Create(s)) throw std::runtime_error("Unicode conversion failed");
return (WINWCHAR*) cnv.Detach();
}
static void FreeUnicodeResString(WINWCHAR* s) {
if (!IS_INTRESOURCE(s)) free(s);
}
#endif // ~_WIN32
#endif // ~_UNICODE
CResourceDirectoryEntry* CResourceEditor::FindResourceLanguageDirEntryT(const TCHAR* Type, const TCHAR* Name, LANGID Language) {
assert(!EditorSupportsStringNames() && sizeof(Name));
CResourceDirectoryEntry* CResourceEditor::FindResourceLanguageDirEntryT(const TCHAR* RT, const TCHAR* RN, LANGID RL) const {
assert(!EditorSupportsStringNames() && sizeof(RN));
#if defined(_WIN32) && defined(_UNICODE)
return FindResourceLanguageDirEntryW((WINWCHAR*)Type, (WINWCHAR*)Name, Language);
return FindResourceLanguageDirEntryW((WINWCHAR*)RT, (WINWCHAR*)RN, RL);
#else
WINWCHAR* szwType = ResStringToUnicode(Type);
CResourceDirectoryEntry* result = FindResourceLanguageDirEntryW(szwType, (WINWCHAR*)Name, Language);
WINWCHAR* szwType = ResStringToUnicode(RT);
CResourceDirectoryEntry* result = FindResourceLanguageDirEntryW(szwType, (WINWCHAR*)RN, RL);
FreeUnicodeResString(szwType);
return result;
#endif
@ -550,7 +578,7 @@ DWORD CResourceEditor::GetResourceOffsetT(const TCHAR* szType, WORD szName, LANG
// Returns a copy of the resource data from the first resource of a specific type
BYTE* CResourceEditor::GetFirstResourceW(const WINWCHAR* szType, size_t&cbData) {
CResourceDataEntry *pDE = FindResource(szType, FINDRESOURCE_NAME_FIRSTITEM, ANYLANGID);
CResourceDataEntry *pDE = FindResource(szType, FIRSTRESDIRSTRADDRESS, ANYLANGID);
if (pDE)
{
cbData = pDE->GetSize();
@ -863,17 +891,28 @@ bool CResourceEditor::AddExtraIconFromFile(const WINWCHAR* Type, WINWCHAR* Name,
return !failed;
}
bool CResourceEditor::UpdateResourceFromExternalT(const TCHAR* Type, WORD Name, LANGID Lang, const TCHAR*File, TYPEMANIPULATION Manip)
{
bool success = false;
const TCHAR *srctype, *srcname;
LANGID srclang = 0;
TCHAR *resproto = ParseResProtocolAlloc(File, srctype, srcname, srclang);
template<class C, class P> static bool Contains(C&Map, P*p) {
return p && (SIZE_T) Map.base <= (SIZE_T) p && (SIZE_T) Map.base + Map.size > (SIZE_T) p;
}
void CResourceEditor::FreeExternal(EXTERNAL&X) {
assert(sizeof(FILEVIEW) <= sizeof(X.Map));
if (X.Data) {
FILEVIEW &map = *(FILEVIEW*) &X.Map;
if (!Contains(map, X.Data)) free(X.Data);
close_file_view(map);
free(X.FreeThis); // ParseResProtocolAlloc
}
}
// Maps a file into memory and locates a resource inside it, a manipulated from a resource inside it or the file itself. Free with FreeExternal.
const TCHAR* CResourceEditor::MapExternal(const TCHAR*File, TYPEMANIPULATION Manip, EXTERNAL&X) {
TCHAR *resproto = ParseResProtocolAlloc(File, X.RT, X.RN, X.RL);
if (resproto) {
File = resproto;
}
FILEVIEW map;
FILEVIEW &map = *(FILEVIEW*) &X.Map;
size_t datasize;
char *filedata = create_file_view_readonly(File, map), *data = 0, *dataalloc = 0;
if (filedata) {
@ -881,15 +920,17 @@ bool CResourceEditor::UpdateResourceFromExternalT(const TCHAR* Type, WORD Name,
signed char exetype = GetExeType(filedata, map.size);
if (exetype == 'P') {
CResourceEditor re(filedata, (int) map.size);
WORD ordsrcname = (WORD)(size_t) srcname;
if (!re.EditorSupportsStringNames() && !IS_INTRESOURCE(srcname)) {
assert(!"Unsupported name");
srclang = INVALIDLANGID;
DWORD ofs, siz = 0, firstname = X.RN == (TCHAR*) FIRSTRESDIRSTRADDRESS;
CResourceDirectoryEntry*pNRDE, *pLRDE;
CResourceDataEntry*pRE = re.FindResourceT(X.RT, X.RN, X.RL, 0, &pNRDE, &pLRDE);
if (pRE) {
const WINWCHAR *wrn = pNRDE->GetNameOrId();
if (firstname) X.RN = IS_INTRESOURCE(wrn) ? MAKEINTRESOURCE((size_t) wrn) : _T("");
X.RL = pLRDE->GetId();
ofs = pRE->GetOffset(), siz = pRE->GetSize();
}
DWORD ofs = re.GetResourceOffset(srctype, ordsrcname, srclang);
DWORD siz = re.GetResourceSize(srctype, ordsrcname, srclang);
if (IsIcoCurGroupType(srctype) && (Manip == TM_AUTO || (Manip & TM_ICON))) { // Must create a fake .ico file
data = dataalloc = (char*) re.ExtractIcoCur(srctype, ordsrcname, srclang, datasize), siz = 0;
if (siz && IsIcoCurGroupType(X.RT) && (Manip == TM_AUTO || (Manip & TM_ICON))) { // Must create a fake .ico file
data = dataalloc = (char*) re.ExtractIcoCur(*pRE, X.RL, datasize), siz = 0;
}
if (siz && siz != DWORD(-1)) {
data = filedata + ofs, datasize = siz; // Raw resource data
@ -899,26 +940,43 @@ bool CResourceEditor::UpdateResourceFromExternalT(const TCHAR* Type, WORD Name,
else {
data = filedata, datasize = map.size; // Just a normal file
}
if (data && (DWORD) datasize == datasize) {
success = this->UpdateResource(Type, Name, Lang, (BYTE*) data, (DWORD) datasize, Manip);
}
close_file_view(map);
}
free(dataalloc);
free(resproto);
X.Data = (BYTE*) data, X.cbData = datasize;
X.FreeThis = resproto;
if (data) return File;
FreeExternal(X);
return 0;
}
bool CResourceEditor::UpdateResourceFromExternalT(const TCHAR* Type, WORD Name, LANGID Lang, const TCHAR*File, TYPEMANIPULATION Manip) {
EXTERNAL x;
size_t &datasize = x.cbData;
bool success = false;
const TCHAR *parsedpath = MapExternal(File, Manip, x);
if (parsedpath) {
if ((DWORD) datasize == datasize) {
success = this->UpdateResource(Type, Name, Lang, (BYTE*) x.Data, (DWORD) datasize, Manip);
}
FreeExternal(x);
}
return success;
}
CResourceDataEntry* CResourceEditor::FindIcoCurDataEntry(WORD Type, WORD Id, LANGID PrefLang) {
CResourceDataEntry* CResourceEditor::FindIcoCurDataEntry(WORD Type, WORD Id, LANGID PrefLang) const {
CResourceDataEntry*pRDE = FindResource(MAKEINTRESOURCEWINW(Type), MAKEINTRESOURCEWINW(Id), PrefLang);
return pRDE ? pRDE : FindResource(MAKEINTRESOURCEWINW(Type), MAKEINTRESOURCEWINW(Id), ANYLANGID);
}
BYTE* CResourceEditor::ExtractIcoCurW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, size_t&cbData) {
BYTE* CResourceEditor::ExtractIcoCurW(const WINWCHAR* szType, const WINWCHAR* szName, LANGID wLanguage, size_t&cbData) const {
CResourceDirectoryEntry*pLangDir = FindResourceLanguageDirEntryW(szType, szName, wLanguage);
if (!pLangDir)
return 0;
CResourceDataEntry*pRDE = pLangDir->GetDataEntry();
return ExtractIcoCur(*pRDE, pLangDir->GetId(), cbData); // Uses the "real" LANGID
}
BYTE* CResourceEditor::ExtractIcoCur(const CResourceDataEntry&rde, LANGID ChildLang, size_t&cbData) const {
const CResourceDataEntry*pRDE = &rde;
BYTE*pSH = pRDE->GetData(), cbRGE = 14, cbFGE = 16, *pResData;
DWORD i, cbRes, failed = false;
if (pRDE->GetSize() < 6) // Must at least have a ICO file header
@ -932,7 +990,7 @@ BYTE* CResourceEditor::ExtractIcoCurW(const WINWCHAR* szType, WINWCHAR* szName,
// Get the size of all images
for (i = 0, pRGE = pFirstRGE; i < count; ++i, pRGE += cbRGE / sizeof(*pRGE)) {
pRDE = FindIcoCurDataEntry(imgResType, ((RSRCICOGROUPENTRY*)pRGE)->Id, wLanguage);
pRDE = FindIcoCurDataEntry(imgResType, ((RSRCICOGROUPENTRY*)pRGE)->Id, ChildLang);
if (pRDE && pRDE->GetData()) cbImages += FIX_ENDIAN_INT32(((FILEICOGROUPENTRY*)pRGE)->Size); else count = 0;
}
// Build the .ICO file
@ -940,7 +998,7 @@ BYTE* CResourceEditor::ExtractIcoCurW(const WINWCHAR* szType, WINWCHAR* szName,
if (count && (pDH = (WORD*) malloc(cbTot += cbImages))) {
pDH[0] = 0x0000, pDH[1] = FIX_ENDIAN_INT16(isCursor ? 2 : 1), pDH[2] = FIX_ENDIAN_INT16(count);
for (i = 0, pRGE = pFirstRGE; i < count; ++i, pRGE += cbRGE / sizeof(*pRGE)) {
pRDE = FindIcoCurDataEntry(imgResType, ((RSRCICOGROUPENTRY*)pRGE)->Id, wLanguage);
pRDE = FindIcoCurDataEntry(imgResType, ((RSRCICOGROUPENTRY*)pRGE)->Id, ChildLang);
pResData = pRDE->GetData(), cbRes = pRDE->GetSize();
FILEICOGROUPENTRY*pFGE = (FILEICOGROUPENTRY*) ((char*)pDH + grpsOfs);
memcpy(pFGE, pRGE, cbRGE), pFGE->Offset = FIX_ENDIAN_INT32(imgsOfs); // Initialize ICO group entry
@ -972,7 +1030,7 @@ BYTE* CResourceEditor::ExtractIcoCurW(const WINWCHAR* szType, WINWCHAR* szName,
return (BYTE*) pDH;
}
BYTE* CResourceEditor::ExtractIcoCurT(const TCHAR* szType, WORD szName, LANGID wLanguage, size_t&cbData) {
BYTE* CResourceEditor::ExtractIcoCurT(const TCHAR* szType, WORD szName, LANGID wLanguage, size_t&cbData) const {
assert(!EditorSupportsStringNames() && sizeof(szName));
#if defined(_WIN32) && defined(_UNICODE)
return ExtractIcoCurW((WINWCHAR*)szType, MAKEINTRESOURCEWINW(szName), wLanguage, cbData);
@ -1454,7 +1512,7 @@ CResourceDataEntry::~CResourceDataEntry() {
// To save memory this function doesn't give you a copy of the data
// Don't mess with the data returned from this function!
BYTE* CResourceDataEntry::GetData() {
BYTE* CResourceDataEntry::GetData() const {
return m_pbData;
}
@ -1471,14 +1529,14 @@ void CResourceDataEntry::SetData(BYTE* pbData, DWORD dwSize, DWORD dwCodePage) {
m_dwOffset = DWORD(-1); // unset
}
DWORD CResourceDataEntry::GetSize() {
DWORD CResourceDataEntry::GetSize() const {
return m_dwSize;
}
DWORD CResourceDataEntry::GetCodePage() {
DWORD CResourceDataEntry::GetCodePage() const {
return m_dwCodePage;
}
DWORD CResourceDataEntry::GetOffset() {
DWORD CResourceDataEntry::GetOffset() const {
return m_dwOffset;
}

View file

@ -180,6 +180,7 @@ public:
return ExtractIcoCurT((const TCHAR*) Type, Name, Lang, cbData);
}
CResourceDataEntry* FindResourceT(const TCHAR*RT, const TCHAR*RN, LANGID RL, CResourceDirectoryEntry**pTE, CResourceDirectoryEntry**pNE, CResourceDirectoryEntry**pLE) const;
bool UpdateResourceFromExternalT(const TCHAR* Type, WORD Name, LANGID Lang, const TCHAR*File, TYPEMANIPULATION Manip = TM_AUTO);
bool UpdateResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize, TYPEMANIPULATION Manip = TM_RAW);
bool UpdateResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage, FILE*Data, TYPEMANIPULATION Manip = TM_AUTO);
@ -189,7 +190,8 @@ public:
DWORD GetResourceOffsetT(const TCHAR* szType, WORD szName, LANGID wLanguage);
bool ResourceExistsT (const TCHAR* szType, WORD szName, LANGID wLanguage, LANGID*pFoundLanguage = 0);
BYTE* GetFirstResourceT (const TCHAR* szType, size_t&cbData);
BYTE* ExtractIcoCurT (const TCHAR* szType, WORD szName, LANGID wLanguage, size_t&cbData);
BYTE* ExtractIcoCurT (const TCHAR* szType, WORD szName, LANGID wLanguage, size_t&cbData) const;
BYTE* ExtractIcoCur(const CResourceDataEntry&rde, LANGID ChildLang, size_t&cbData) const;
void FreeResource(BYTE* pbResource);
// The section name must be in ASCII.
@ -208,9 +210,14 @@ public:
);
static const TCHAR* ParseResourceTypeString(const TCHAR*String);
static const TCHAR* ParseResourceNameString(const TCHAR*String);
static const TCHAR* ParseResourceNameString(const TCHAR*String, bool AllowFirst = false);
static LANGID ParseResourceLangString(const TCHAR*String);
static LANGID ParseResourceTypeNameLangString(const TCHAR**Type, const TCHAR**Name, const TCHAR*Lang);
static LANGID ParseResourceTypeNameLangString(const TCHAR**Type, const TCHAR**Name, const TCHAR*Lang, bool AllowFirst = false);
static bool CanOpen(const void*Data, size_t Size);
static UINT IsResProtocol(const TCHAR*Url);
typedef struct { BYTE*Data; size_t cbData, Map[2]; void*FreeThis; const TCHAR*RT, *RN; LANGID RL; } EXTERNAL;
static void FreeExternal(EXTERNAL&External);
static const TCHAR* MapExternal(const TCHAR*File, TYPEMANIPULATION Manip, EXTERNAL&External);
static bool EditorSupportsStringNames() { return false; } // UpdateResource/GetResource do not support string names (yet)
static bool EditorSupportsCursorPng() { return false; }
@ -220,14 +227,15 @@ private:
int GetResourceSizeW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
DWORD GetResourceOffsetW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
BYTE* GetFirstResourceW (const WINWCHAR* szType, size_t&cbData);
BYTE* ExtractIcoCurW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, size_t&cbData);
CResourceDataEntry* FindResource(const WINWCHAR* Type, const WINWCHAR* Name, LANGID Language);
CResourceDirectoryEntry* FindResourceLanguageDirEntryW(const WINWCHAR* Type, const WINWCHAR* Name, LANGID Language);
CResourceDirectoryEntry* FindResourceLanguageDirEntryT(const TCHAR* Type, const TCHAR* Name, LANGID Language);
BYTE* ExtractIcoCurW (const WINWCHAR* szType, const WINWCHAR* szName, LANGID wLanguage, size_t&cbData) const;
CResourceDataEntry* FindResource(const WINWCHAR*RT, const WINWCHAR*RN, LANGID RL) const;
CResourceDataEntry* FindResourceW(const WINWCHAR*RT, const WINWCHAR*RN, LANGID RL, CResourceDirectoryEntry**ppTE, CResourceDirectoryEntry**ppNE, CResourceDirectoryEntry**ppLE) const;
CResourceDirectoryEntry* FindResourceLanguageDirEntryW(const WINWCHAR* RT, const WINWCHAR* RN, LANGID RL) const;
CResourceDirectoryEntry* FindResourceLanguageDirEntryT(const TCHAR* RT, const TCHAR* RN, LANGID RL) const;
bool DeleteIconImages(const CResourceDirectoryEntry& LangDir);
bool DeleteIconImagesW(const WINWCHAR* OwnerType, WINWCHAR* Name, LANGID LangId);
bool AddExtraIconFromFile(const WINWCHAR* Type, WINWCHAR* Name, LANGID LangId, BYTE* Data, DWORD Size);
CResourceDataEntry* FindIcoCurDataEntry(WORD Type, WORD Id, LANGID PrefLang);
CResourceDataEntry* FindIcoCurDataEntry(WORD Type, WORD Id, LANGID PrefLang) const;
BYTE* DupData(CResourceDataEntry*pDE); // Free with FreeResource
CResourceDirectory* ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan);
@ -279,6 +287,7 @@ public:
CResourceDirectoryEntry(const WINWCHAR* szName, CResourceDataEntry* rdeData);
virtual ~CResourceDirectoryEntry();
const WINWCHAR* GetNameOrId() const { return HasName() ? GetName() : (WINWCHAR*)(size_t) GetId(); }
bool HasName() const;
const WINWCHAR* GetName() const;
int GetNameLength() const;
@ -306,13 +315,13 @@ public:
CResourceDataEntry(BYTE* pbData, DWORD dwSize, DWORD dwCodePage = 0, DWORD dwOffset = DWORD(-1));
~CResourceDataEntry();
BYTE* GetData();
BYTE* GetData() const;
void SetData(BYTE* pbData, DWORD dwSize);
void SetData(BYTE* pbData, DWORD dwSize, DWORD dwCodePage);
DWORD GetSize();
DWORD GetCodePage();
DWORD GetOffset();
DWORD GetSize() const;
DWORD GetCodePage() const;
DWORD GetOffset() const;
ULONG_PTR m_ulWrittenAt;

View file

@ -43,13 +43,9 @@ static bool is_valid_header(const void*headerdata)
return FIX_ENDIAN_INT16(pGH->wCount) != 0;
}
static FILE * open_icon(const TCHAR* filename, IconGroupHeader& igh)
template<class S> static WORD read_icon_header(S*f, IconGroupHeader& igh)
{
FILE* f = FOPEN(filename, ("rb"));
if (!f)
throw runtime_error("can't open file");
if (!fread(&igh, sizeof(IconGroupHeader), 1, f))
if (!freadall(&igh, sizeof(IconGroupHeader), f))
{
fclose(f);
throw runtime_error("unable to read header from file");
@ -57,6 +53,7 @@ static FILE * open_icon(const TCHAR* filename, IconGroupHeader& igh)
if (!is_valid_header(&igh))
{
igh.wType = igh.wCount = 0;
fclose(f);
throw runtime_error("invalid icon file");
}
@ -64,30 +61,31 @@ static FILE * open_icon(const TCHAR* filename, IconGroupHeader& igh)
FIX_ENDIAN_INT16_INPLACE(igh.wReserved);
FIX_ENDIAN_INT16_INPLACE(igh.wType);
FIX_ENDIAN_INT16_INPLACE(igh.wCount);
return f;
return igh.wCount;
}
void free_loaded_icon(IconGroup icon)
void free_loaded_icon(IconGroup&icon)
{
for (IconGroup::size_type i = 0; i < icon.size(); i++)
{
delete [] icon[i].data;
}
icon.clear();
}
IconGroup load_icon_res(CResourceEditor* re, WORD id)
IconGroup load_icon_res(CResourceEditor* re, const TCHAR*RT, WORD RN, LANGID RL)
{
IconGroupHeader* header;
IconGroup result;
LPBYTE group = re->GetResource(
RT_GROUP_ICON, id, NSIS_DEFAULT_LANG);
LPBYTE group = re->GetResource(RT, RN, RL);
if (!group)
throw runtime_error("can't find icon group");
header = (IconGroupHeader*) group;
// Note: To handle cursors, use CResourceEditor::ExtractIcoCur
if (MAKEINTRESOURCE((size_t) RT) != RT_GROUP_ICON)
throw runtime_error("unsupported type");
for (WORD i = 0; i < FIX_ENDIAN_INT16(header->wCount); i++)
{
Icon icon;
@ -99,9 +97,7 @@ IconGroup load_icon_res(CResourceEditor* re, WORD id)
memcpy(&icon.meta, &entry->header, sizeof(IconGroupEntry));
WORD rsrc_id = FIX_ENDIAN_INT16(entry->wRsrcId);
icon.data = re->GetResource(RT_ICON, rsrc_id, NSIS_DEFAULT_LANG);
icon.data = re->GetResource(RT_ICON, rsrc_id, RL);
if (!icon.data)
{
free_loaded_icon(result);
@ -115,13 +111,14 @@ IconGroup load_icon_res(CResourceEditor* re, WORD id)
return result;
}
IconGroup load_icon_file(const TCHAR* filename)
IconGroup load_icon_res(CResourceEditor* re, WORD id)
{
IconGroupHeader iconHeader;
IconGroup result;
return load_icon_res(re, RT_GROUP_ICON, id, NSIS_DEFAULT_LANG);
}
FILE *file = open_icon(filename, iconHeader);
MANAGE_WITH(file, fclose);
template<class S> static IconGroup load_iconimages_from_stream(const IconGroupHeader&iconHeader, S&file)
{
IconGroup result;
for (WORD i = 0; i < iconHeader.wCount; i++)
{
@ -129,7 +126,7 @@ IconGroup load_icon_file(const TCHAR* filename)
icon.index = i;
icon.data = NULL;
if (!fread(&icon.meta, sizeof(IconGroupEntry), 1, file))
if (!freadall(&icon.meta, sizeof(IconGroupEntry), file))
{
free_loaded_icon(result);
throw runtime_error("unable to read entry from file");
@ -143,8 +140,7 @@ IconGroup load_icon_file(const TCHAR* filename)
}
DWORD iconOffset;
if (!fread(&iconOffset, sizeof(DWORD), 1, file))
if (!freadall(&iconOffset, sizeof(DWORD), file))
{
free_loaded_icon(result);
throw runtime_error("unable to read offset from file");
@ -154,7 +150,6 @@ IconGroup load_icon_file(const TCHAR* filename)
fpos_t pos;
fgetpos(file, &pos);
if (fseek(file, iconOffset, SEEK_SET))
{
free_loaded_icon(result);
@ -162,14 +157,14 @@ IconGroup load_icon_file(const TCHAR* filename)
}
icon.data = new BYTE[size];
if (!fread(icon.data, size, 1, file))
if (!freadall(icon.data, size, file)) die:
{
free_loaded_icon(result);
throw runtime_error("unable to read icon from file");
}
fsetpos(file, &pos);
if (fsetpos(file, &pos))
goto die;
result.push_back(icon);
}
@ -177,6 +172,39 @@ IconGroup load_icon_file(const TCHAR* filename)
return result;
}
template<class S> static IconGroup load_icon_from_stream(S*file)
{
IconGroupHeader iconHeader;
read_icon_header(file, iconHeader);
return load_iconimages_from_stream(iconHeader, file);
}
IconGroup load_icon_file(const TCHAR* filename)
{
FILE* f = FOPEN(filename, ("rb"));
if (!f)
throw runtime_error("can't open file");
MANAGE_WITH(f, fclose);
return load_icon_from_stream(f);
}
IconGroup load_icon(const TCHAR* filename)
{
if (CResourceEditor::IsResProtocol(filename)) // Try opening embedded resource
{
CResourceEditor::EXTERNAL x;
if (CResourceEditor::MapExternal(filename, CResourceEditor::TM_ICON, x))
{
CStdFileStreamOnMemory stream(x.Data, x.cbData);
IconGroup icon = load_icon_from_stream(&stream);
CResourceEditor::FreeExternal(x);
return icon;
}
}
return load_icon_file(filename);
}
typedef struct
{
unsigned index1;

View file

@ -62,9 +62,10 @@ typedef struct
typedef std::vector<Icon> IconGroup;
IconGroup load_icon(const TCHAR* filename);
IconGroup load_icon_file(const TCHAR* filename);
IconGroup load_icon_res(CResourceEditor* re, WORD id);
void free_loaded_icon(IconGroup icon);
void free_loaded_icon(IconGroup&icon);
void set_main_icon(CResourceEditor* re, WORD wIconId, IconGroup icon1, IconGroup icon2);

View file

@ -1333,7 +1333,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
SCRIPT_MSG(_T("Icon: \"%") NPRIs _T("\"\n"),line.gettoken_str(1));
try {
free_loaded_icon(installer_icon);
installer_icon = load_icon_file(line.gettoken_str(1));
installer_icon = load_icon(line.gettoken_str(1));
}
catch (exception& err) {
ERROR_MSG(_T("Error while loading icon from \"%") NPRIs _T("\": %") NPRIs _T("\n"), line.gettoken_str(1), CtoTStrParam(err.what()));
@ -2593,7 +2593,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
SCRIPT_MSG(_T("UninstallIcon: \"%") NPRIs _T("\"\n"),line.gettoken_str(1));
try {
free_loaded_icon(uninstaller_icon);
uninstaller_icon = load_icon_file(line.gettoken_str(1));
uninstaller_icon = load_icon(line.gettoken_str(1));
}
catch (exception& err) {
ERROR_MSG(_T("Error while loading icon from \"%") NPRIs _T("\": %") NPRIs _T("\n"), line.gettoken_str(1), CtoTStrParam(err.what()));

View file

@ -29,8 +29,8 @@
# include <stdio.h>
# include <unistd.h>
#endif
#include <stdarg.h>
#include <stdio.h>
extern double my_wtof(const wchar_t *str);
extern size_t my_strncpy(TCHAR*Dest, const TCHAR*Src, size_t cchMax);
@ -109,6 +109,49 @@ public:
int sane_system(const TCHAR *command);
template<class S> static size_t freadall(void*b, size_t cb, S*s) { return cb == fread(b, 1, cb, s) ? cb : 0; }
template<class T, class S> static inline size_t freadpod(T&b, S*s) { return freadall(b, sizeof(T), s); }
struct CStdFileStreamOnMemory
{
typedef CStdFileStreamOnMemory S_t;
BYTE*m_Base;
size_t m_cb, m_pos;
template<class T> CStdFileStreamOnMemory(T*p, size_t cb) : m_Base((BYTE*)p), m_cb(cb), m_pos(0) {}
template<class V> static inline bool assignfp(fpos_t*p, V v)
{
if (sizeof(p) >= sizeof(v)) return (*(V*)p = v, true);
UINT t = (UINT) v;
return t == v && sizeof(p) >= sizeof(t) && assignfp(p, t);
}
template<class V> static inline void readfp(V&v, const fpos_t*p) { v = sizeof(p) >= sizeof(v) ? *(V*)p : *(UINT*)p; }
friend inline size_t fclose(S_t*s) { return 0; }
friend int fgetpos(S_t*s, fpos_t*pos) { return assignfp(pos, s->m_pos) ? 0 : 1; }
friend int fsetpos(S_t*s, const fpos_t*pos) { size_t v; readfp(v, pos); return v < s->m_cb ? (s->m_pos = v, 0) : 1; }
friend int fseek(S_t*s, long int offset, int origin)
{
if ((unsigned long) offset != (size_t) offset) return 1; // long int will usually fit in our size_t
size_t newpos, invalid = 0;
switch(origin)
{
case SEEK_SET: newpos = (size_t) offset, invalid = offset < 0; break;
case SEEK_CUR: newpos = s->m_pos + offset; break;
case SEEK_END: newpos = s->m_cb + offset; break;
default: ++invalid;
}
if (!(invalid += s->m_cb <= newpos)) s->m_pos = newpos;
return (int) invalid;
}
friend size_t fread(void*b, size_t e, size_t c, S_t*s)
{
size_t cb = e * c, endpos = s->m_pos + cb;
if (endpos < s->m_pos || cb < c) return 0; // EOF/Overflow
if (s->m_cb < endpos) cb = s->m_cb - s->m_pos; // EOF
memcpy(b, s->m_Base + s->m_pos, cb);
return (s->m_pos += cb, cb);
}
};
#define NSISRT_DEFINEGLOBALS() int g_display_errors=1; FILE *g_output=stdout, *g_errout=stderr
void PrintColorFmtErrMsg(const TCHAR *fmtstr, va_list args);
void PrintColorFmtMsg(unsigned int type, const TCHAR *fmtstr, va_list args);