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:
parent
cc431158fd
commit
167e53df8a
6 changed files with 266 additions and 127 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue