diff --git a/Docs/src/attributes.but b/Docs/src/attributes.but index e5566d42..0b43b0ff 100644 --- a/Docs/src/attributes.but +++ b/Docs/src/attributes.but @@ -360,6 +360,7 @@ Adds \cw{file} as a resource to the installer and uninstaller. \cw{restype} spec \c PEAddResource "myimage.bmp" "#2" "#1337" \c PEAddResource "mybonus.ico" "#Icon" "#200" \c PEAddResource "myimage.png" "PNG" "#1234" +\c PEAddResource "res://$%WINDIR%/Explorer.exe/#Icon/#101" "#Icon" "#1337" \S2{aperemoveresource} PERemoveResource diff --git a/Docs/src/history.but b/Docs/src/history.but index 3c827735..cb68d4e9 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -20,6 +20,8 @@ Released on ???? ??th, 20?? \b Added /LAUNCH compiler switch +\b PEAddResource now supports the res:// protocol + \H{v3.07} 3.07 Released on July 24th, 2021 diff --git a/Source/BinInterop.cpp b/Source/BinInterop.cpp index 75fccac1..d50ae9b0 100644 --- a/Source/BinInterop.cpp +++ b/Source/BinInterop.cpp @@ -29,6 +29,33 @@ #define HE2BE32 BE2HE32 const size_t invalid_res_id = ~(size_t)0; +signed char GetExeType(const void*pData, size_t Size) // Returns 'P', 'N', 'L', -'E' or '\0' +{ + char *filedata = (char*) pData, type = '\0'; + PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER) filedata; + if (Size > sizeof(*pIDH) && (pIDH->e_magic == 0x5A4D) | (pIDH->e_magic == 0x4D5A)) + { + type = -'E'; // Basic DOS EXE + UINT32 nho = LE2HE32(pIDH->e_lfanew); + if (Size > nho + 4 && MKPTR(BYTE*, pIDH, nho)[1] == 'E') + { + if (pIDH->e_magic == IMAGE_DOS_SIGNATURE && MKPTR(PIMAGE_NT_HEADERS, pIDH, nho)->Signature == IMAGE_NT_SIGNATURE) + type = 'P'; + else if (MKPTR(BYTE*, pIDH, nho)[0] == 'L' || MKPTR(BYTE*, pIDH, nho)[0] == 'N') + type = MKPTR(BYTE*, pIDH, nho)[0]; + } + } + return type; +} + +signed char GetExeType(const TCHAR*filepath) +{ + FILEVIEW map; + char *filedata = create_file_view_readonly(filepath, map), type = '\0'; + if (filedata) type = GetExeType(filedata, map.size), close_file_view(map); + return type; +} + FILE* MSTLB_fopen(const TCHAR*filepath, size_t*pResId) { size_t resid = invalid_res_id; // MSDN:"By default, the type library is extracted from the first resource of type ITypeLib" diff --git a/Source/BinInterop.h b/Source/BinInterop.h index 29a7d6b0..e135d941 100644 --- a/Source/BinInterop.h +++ b/Source/BinInterop.h @@ -22,6 +22,9 @@ #include "tchar.h" #include // FILE* +signed char GetExeType(const void*pData, size_t Size); +signed char GetExeType(const TCHAR*filepath); + FILE* MSTLB_fopen(const TCHAR*filepath, size_t*pResId = 0); bool GetTLBVersion(const TCHAR *filepath, DWORD &high, DWORD &low); diff --git a/Source/ResourceEditor.cpp b/Source/ResourceEditor.cpp index f2abc74e..bafb7034 100644 --- a/Source/ResourceEditor.cpp +++ b/Source/ResourceEditor.cpp @@ -167,14 +167,68 @@ LANGID CResourceEditor::ParseResourceTypeNameLangString(const TCHAR**Type, const return ParseResourceLangString(Lang); } -template static WORD GetDependentType(T Type) -{ +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); + size_t pathend = 0, typestart = 0, namestart = 0, i, cch; + if (lowercase(tstring(proto)).compare(_T("res://")) != 0) + return path; + for (Url += prefix, i = 0; Url[i]; ++i) + if (Url[i] == '/') + typestart = namestart, namestart = i; + const TCHAR*pS = Url; + if (namestart > 2 && (buf = (TCHAR*) malloc((cch = ++i) * sizeof(*Url)))) { + if (pS[0] == '/') ++pS; + ch = S7ChLwr(pS[0]); + if (ch >= 'a' && ch <= 'z' && (pS[1] == ':' || pS[1] == '|') && IsAgnosticPathSeparator(pS[2])) { // IEBlog:"File URIs in Windows" says %3A is not a drive delimiter. + if (Url[0] == '/') ++skip; // "res:///C:/.." => "res://C:/.." (Even on POSIX so that our FOPEN can do "c:/.." => "/c/..") + pipe = (UINT)(size_t) ((pS + 1) - (Url + skip)); + } + typestart -= skip, namestart -= skip; + const TCHAR *rt = buf + typestart + 1, *rn = buf + namestart + 1, *rl = _T("Any"); + my_strncpy(buf, Url + skip, cch); + buf[typestart] = buf[namestart] = '\0'; // Note: Type and Name are not decoded. + if (pipe) buf[pipe] = ':'; // "res://C|/.." => "res://C:/.." (The | replacement is technically a file:// legacy feature but we support it for res:// as well) + for (pD = buf, pS = pD;; ++pS, ++pD) { + if ((ch = *pS) == '%') { // Deal with percent-encoding + if (*++pS != '%') { + TCHAR hex[3] = { pS[0], pS[0] ? pS[1] : '\0', '\0' }; + ch = ChIsHex(pS[0]) && ChIsHex(pS[1]) ? (TCHAR) _tcstol(hex, 0, 16) : 0; + if (ch) ++pS; else ++bad; + } + } + if (!(*pD = (mswin && ch == '/') ? '\\' : ch)) break; // Convert path if needed and stop at the end. + } + Lang = CResourceEditor::ParseResourceTypeNameLangString(&rt, &rn, rl); + if (!bad && Lang != CResourceEditor::INVALIDLANGID) + path = buf, Type = rt, Name = rn; + } + if (!path) free(buf); + return path; +} + +template static WORD GetDependentType(T Type) { if (!IS_INTRESOURCE((size_t) Type)) return 0; if (MAKEINTRESOURCE((size_t) Type) == RT_GROUP_ICON) return (WORD)(size_t) RT_ICON; if (MAKEINTRESOURCE((size_t) Type) == RT_GROUP_CURSOR) return (WORD)(size_t) RT_CURSOR; return 0; } +template static WORD IsIcoCurSingleImageType(T Type) { + WORD t = IS_INTRESOURCE((size_t) Type) ? (WORD)(size_t) Type : 0; + return t == (WORD)(size_t) RT_ICON || t == (WORD)(size_t) RT_CURSOR; +} + +template static WORD IsIcoCurGroupType(T Type) { + return IsIcoCurSingleImageType(GetDependentType(Type)); +} + +template static WORD IsIcoCurType(T Type) { + return IsIcoCurSingleImageType(Type) || IsIcoCurGroupType(Type); +} + ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // CResourceEditor @@ -191,6 +245,9 @@ CResourceEditor::CResourceEditor(void* pbPE, int iSize, bool bKeepData /*=true*/ m_iSize = iSize; m_bKeepData = bKeepData; + assert(!EditorSupportsStringNames()); + assert(!EditorSupportsCursorPng()); + // Get NT headers m_ntHeaders = GetNTHeaders(m_pbPE); @@ -240,6 +297,13 @@ CResourceDataEntry* CResourceEditor::FindResource(const WINWCHAR* Type, const WI return pRDE ? pRDE->GetDataEntry() : 0; } +template static void UpdateManipulationType(CResourceEditor::TYPEMANIPULATION &Manip, const T* szType, const void*Data, size_t Size) { + WORD dependenttype = GetDependentType(szType); + if (Manip == CResourceEditor::TM_AUTO) + if (IsIcoCurSingleImageType(dependenttype) && IsICOCURFile(Data, Size)) + Manip = CResourceEditor::TM_ICONFILE; +} + // Adds/Replaces/Removes a simple resource. // If lpData is 0 UpdateResource removes the resource. bool CResourceEditor::UpdateResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize, TYPEMANIPULATION Manip) { @@ -263,18 +327,19 @@ bool CResourceEditor::UpdateResourceW(const WINWCHAR* szType, WINWCHAR* szName, } bool deleteoperation = !lpData, success = true, handlecomplexicon = false; + UpdateManipulationType(Manip, szType, lpData, dwSize); WORD dependenttype = GetDependentType(szType); if (dependenttype && Manip != TM_RAW) { - if (Manip == TM_AUTO && ((size_t) szType == (size_t) RT_GROUP_ICON || (size_t) szType == (size_t) RT_GROUP_CURSOR)) - Manip = TM_ICON; + if (Manip == TM_AUTO && IsIcoCurSingleImageType(dependenttype)) + Manip = TM_ICON; // A non-TM_ICONFILE operation that is probably going to fail if (Manip & TM_ICON) - handlecomplexicon = true; + handlecomplexicon = true; // Group and images if (handlecomplexicon && !deleteoperation) if (Manip == TM_AUTO || (Manip & TM_ICONRSRC)) - return false; // It is impossible to add a resource icon from a plain data buffer because it doesn't use offsets for the images + return false; // It is impossible to add a icon from a resource-based plain data buffer because it doesn't use offsets for the images if ((size_t) szType == (size_t) RT_GROUP_ICON && (size_t) szName == (size_t) IDI_ICON2) return false; // The main icon is special, don't allow high-level RT_GROUP_ICON updates to touch RT_ICON. @@ -398,10 +463,6 @@ bool CResourceEditor::UpdateResourceT(const TCHAR* szType, WORD szName, LANGID w BYTE *data = alloc_and_read_file(Data, size); if (!data) return false; - WORD dependenttype = GetDependentType(szType); - if (Manip == TM_AUTO) - if (dependenttype && IsICOCURFile(data, size)) - Manip = TM_ICONFILE; result = UpdateResourceT(szType, szName, wLanguage, data, size, Manip); free(data); return result; @@ -741,10 +802,11 @@ static WORD FindFreeIconImageId(CResourceEditor& re, WORD ImgType) { return 0; } +typedef struct { BYTE Width, Height, Palette, Reserved; WORD Planes, BPP; UINT32 Size, Offset; } FILEICOGROUPENTRY; +typedef struct { BYTE Width, Height, Palette, Reserved; WORD Planes, BPP, SizeLo, SizeHi, Id; } RSRCICOGROUPENTRY; +typedef struct { WORD Width, Height; WORD Planes, BPP, SizeLo, SizeHi, Id; } RSRCCURGROUPENTRY; //msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx + bool CResourceEditor::AddExtraIconFromFile(const WINWCHAR* Type, WINWCHAR* Name, LANGID LangId, BYTE* Data, DWORD Size) { - typedef struct { BYTE Width, Height, Palette, Reserved; WORD Planes, BPP; UINT32 Size, Offset; } FILEICOGROUPENTRY; - typedef struct { BYTE Width, Height, Palette, Reserved; WORD Planes, BPP, SizeLo, SizeHi, Id; } RSRCICOGROUPENTRY; - typedef struct { WORD Width, Height; WORD Planes, BPP, SizeLo, SizeHi, Id; } RSRCCURGROUPENTRY; //msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx assert(sizeof(RSRCICOGROUPENTRY) == 12+2 && sizeof(FILEICOGROUPENTRY) == 12+4); assert(sizeof(RSRCICOGROUPENTRY) == sizeof(RSRCCURGROUPENTRY)); @@ -767,6 +829,7 @@ bool CResourceEditor::AddExtraIconFromFile(const WINWCHAR* Type, WINWCHAR* Name, BYTE *pImg = (BYTE*) (((char*) Data) + FIX_ENDIAN_INT32(pSrcFGE[i].Offset)), *pCursor = 0; if (isCursor) { // We must prepend the hotspot to the image data and change the group entry + assert(!EditorSupportsCursorPng()); GENERICIMAGEINFO info; if (/*!IsPNGFile(pImg, imgSize, &info) &&*/ !GetDIBHeaderInfo(pImg, imgSize, info)) // Are PNG cursor images allowed? goto fail; @@ -800,6 +863,128 @@ 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; + TCHAR *resproto = ParseResProtocolAlloc(File, srctype, srcname, srclang); + if (resproto) { + File = resproto; + } + + FILEVIEW map; + size_t datasize; + char *filedata = create_file_view_readonly(File, map), *data = 0, *dataalloc = 0; + if (filedata) { + if (resproto) { + 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 = 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 && siz != DWORD(-1)) { + data = filedata + ofs, datasize = siz; // Raw resource data + } + } + } + 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); + return success; +} + +CResourceDataEntry* CResourceEditor::FindIcoCurDataEntry(WORD Type, WORD Id, LANGID PrefLang) { + 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) { + CResourceDirectoryEntry*pLangDir = FindResourceLanguageDirEntryW(szType, szName, wLanguage); + if (!pLangDir) + return 0; + CResourceDataEntry*pRDE = pLangDir->GetDataEntry(); + BYTE*pSH = pRDE->GetData(), cbRGE = 14, cbFGE = 16, *pResData; + DWORD succ = false, i, cbRes, failed = false; + if (pRDE->GetSize() < 6) // Must at least have a ICO file header + return 0; + WORD imgResType, count, *pFirstRGE = (WORD*) GetFirstICOCURGroupEntry(pSH, &imgResType, &count), *pRGE; + if (!pFirstRGE) + return 0; + + WORD *pDH = 0, isCursor = imgResType == (size_t) RT_CURSOR; + DWORD imgsOfs = 6 + (count * cbFGE), cbTot = imgsOfs, cbImages = 0, grpsOfs = 6; + + // 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); + if (pRDE && pRDE->GetData()) cbImages += ((FILEICOGROUPENTRY*)pRGE)->Size; else count = 0; + } + // Build the .ICO file + GENERICIMAGEINFO ii; + 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); + 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 + DWORD cbImgFromGrp = FIX_ENDIAN_INT32(pFGE->Size), cbImg = cbImgFromGrp; + if (isCursor) { + pFGE->Width = (BYTE) FIX_ENDIAN_INT16(pRGE[0]), pFGE->Height = (BYTE) FIX_ENDIAN_INT16(pRGE[1]); + if (cbRes >= 4+12) { + assert(!EditorSupportsCursorPng()); + pFGE->Planes = ((WORD*)pResData)[0], pFGE->BPP = ((WORD*)pResData)[0], cbImg -= 4; // Hotspot + DWORD cbBMH = GetDIBHeaderInfo(pResData += 4, cbRes - 4, ii), cd = ii.BPP * ii.Planes; + pFGE->Palette = cbBMH && cd < 8 ? (BYTE)(1 << cd) : 0; // devblogs.microsoft.com/oldnewthing/20101018-00/?p=12513 says only for depths < 8! + pFGE->Reserved = 0; + } + else + ++failed; + } + if (cbImg <= cbRes) { + memcpy((char*)pDH + imgsOfs, pResData, cbImg); + pFGE->Size = FIX_ENDIAN_INT32(cbImg); + imgsOfs += cbImg, grpsOfs += cbFGE; + } + else + ++failed; + } + } + cbData = cbTot; + if (!count || failed) + free(pDH), pDH = 0; + return (BYTE*) pDH; +} + +BYTE* CResourceEditor::ExtractIcoCurT(const TCHAR* szType, WORD szName, LANGID wLanguage, size_t&cbData) { + assert(!EditorSupportsStringNames() && sizeof(szName)); +#if defined(_WIN32) && defined(_UNICODE) + return ExtractIcoCurW((WINWCHAR*)szType, MAKEINTRESOURCEWINW(szName), wLanguage, cbData); +#else + WINWCHAR* szwType = ResStringToUnicode(szType); + BYTE* result = ExtractIcoCurW(szwType, MAKEINTRESOURCEWINW(szName), wLanguage, cbData); + FreeUnicodeResString(szwType); + return result; +#endif +} + + ////////////////////////////////////////////////////////////////////// // Private Methods ////////////////////////////////////////////////////////////////////// diff --git a/Source/ResourceEditor.h b/Source/ResourceEditor.h index 1a8b8f6a..fdea39e7 100644 --- a/Source/ResourceEditor.h +++ b/Source/ResourceEditor.h @@ -129,6 +129,11 @@ public: // On POSIX+Unicode GetResource(RT_VERSION,..) is not TCHAR nor WINWCHAR, it is WCHAR/UINT16 (MAKEINTRESOURCEW). // If it passes IS_INTRESOURCE we must allow it. // Use TCHAR* for real strings. If you need to pass in a WINWCHAR*, make GetResourceW public... + template bool UpdateResourceFromExternal(const T*Type, WORD Name, LANGID Lang, const TCHAR*File, TYPEMANIPULATION Manip = TM_AUTO) + { + if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return false; } + return UpdateResourceFromExternalT((const TCHAR*) Type, Name, Lang, File, Manip); + } template bool UpdateResource(const T*Type, WORD Name, LANGID Lang, BYTE*Data, DWORD Size, TYPEMANIPULATION Manip = TM_RAW) { if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return false; } @@ -169,7 +174,13 @@ public: if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return NULL; } return GetFirstResourceT((const TCHAR*) Type, cbData); } + template BYTE* ExtractIcoCur(const T*Type, WORD Name, LANGID Lang, size_t&cbData) + { + if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return NULL; } + return ExtractIcoCurT((const TCHAR*) Type, Name, Lang, cbData); + } + 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); bool DeleteResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage, TYPEMANIPULATION Manip = TM_RAW); @@ -178,6 +189,7 @@ 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); void FreeResource(BYTE* pbResource); // The section name must be in ASCII. @@ -200,6 +212,7 @@ public: static LANGID ParseResourceLangString(const TCHAR*String); static LANGID ParseResourceTypeNameLangString(const TCHAR**Type, const TCHAR**Name, const TCHAR*Lang); static bool EditorSupportsStringNames() { return false; } // UpdateResource/GetResource do not support string names (yet) + static bool EditorSupportsCursorPng() { return false; } private: bool UpdateResourceW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize, TYPEMANIPULATION Manip = TM_RAW); @@ -207,12 +220,14 @@ 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); 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); BYTE* DupData(CResourceDataEntry*pDE); // Free with FreeResource CResourceDirectory* ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan); diff --git a/Source/script.cpp b/Source/script.cpp index 7e63da11..f3c4e41e 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -2255,7 +2255,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) case TOK_PEADDRESOURCE: { init_res_editor(); - int tokidx = 1, ovr = 0, rep = 0; + int tokidx = 1, ovr = 0, rep = 0, result = PS_ERROR; if (!_tcsicmp(line.gettoken_str(tokidx), _T("/OVERWRITE"))) // Update the resource even if it exists ++ovr, ++tokidx; else if (!_tcsicmp(line.gettoken_str(tokidx), _T("/REPLACE"))) // Only update existing resource @@ -2275,15 +2275,10 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) ERROR_MSG(_T("Error: Resource %") NPRIns _T("\n"), rep ? ("does not exist") : ("already exists")); return PS_ERROR; } - int result = PS_ERROR; - if (FILE*f = FOPEN(line.gettoken_str(tokidx+0), ("rb"))) + if (res_editor->UpdateResourceFromExternal(rt, rn, rl, line.gettoken_str(tokidx+0), CResourceEditor::TM_AUTO)) { - if (res_editor->UpdateResource(rt, rn, rl, f, CResourceEditor::TM_AUTO)) - { - SCRIPT_MSG(_T("PEAddResource: %") NPRIs _T("=%") NPRIs _T("\n"), make_friendly_resource_path(rt, rnraw, rl).c_str(), line.gettoken_str(tokidx+0)); - result = PS_OK; - } - fclose(f); + SCRIPT_MSG(_T("PEAddResource: %") NPRIs _T("=%") NPRIs _T("\n"), make_friendly_resource_path(rt, rnraw, rl).c_str(), line.gettoken_str(tokidx+0)); + result = PS_OK; } return result; } diff --git a/Source/util.cpp b/Source/util.cpp index dfedb3ed..6d427b69 100644 --- a/Source/util.cpp +++ b/Source/util.cpp @@ -61,12 +61,16 @@ extern FILE *g_output, *g_errout; #ifdef _WIN32 -static char* CreateMappedFileView(LPCTSTR Path, DWORD FAccess, DWORD FShare, DWORD FMode, DWORD PProtect, DWORD MAccess) +bool GetFileSize64(HANDLE hFile, ULARGE_INTEGER &uli); +static char* CreateMappedFileView(LPCTSTR Path, DWORD FAccess, DWORD FShare, DWORD FMode, DWORD PProtect, DWORD MAccess, size_t &FSize) { - char *pView = NULL, restoreGLE = false; + char *pView = NULL, restoreGLE = false, validSize; HANDLE hFile = CreateFile(Path, FAccess, FShare, NULL, FMode, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) return pView; - HANDLE hMap = CreateFileMapping(hFile, NULL, PProtect, 0, 0, NULL); + ULARGE_INTEGER fs; + validSize = GetFileSize64(hFile, fs) && sizeof(size_t) >= 8 || !fs.HighPart; + FSize = sizeof(size_t) >= 8 ? (size_t) fs.QuadPart : fs.LowPart; + HANDLE hMap = validSize ? CreateFileMapping(hFile, NULL, PProtect, 0, 0, NULL) : INVALID_HANDLE_VALUE; if (hMap != INVALID_HANDLE_VALUE) { CloseHandle(hFile); @@ -702,15 +706,15 @@ void close_file_view(FILEVIEW&mmfv) #ifdef _WIN32 if (mmfv.base) UnmapViewOfFile(mmfv.base); #else - if (mmfv.base) munmap(mmfv.base, mmfv.internal); + if (mmfv.base) munmap(mmfv.base, mmfv.size); #endif } char* create_file_view_readonly(const TCHAR *filepath, FILEVIEW&mmfv) { #ifdef _WIN32 - return mmfv.base = CreateMappedFileView(filepath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, PAGE_READONLY, FILE_MAP_READ); + return mmfv.base = CreateMappedFileView(filepath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, PAGE_READONLY, FILE_MAP_READ, mmfv.size); #else - return mmfv.base = CreateMappedFileView(filepath, "rb", PROT_READ, MAP_SHARED, mmfv.internal); + return mmfv.base = CreateMappedFileView(filepath, "rb", PROT_READ, MAP_SHARED, mmfv.size); #endif } diff --git a/Source/util.h b/Source/util.h index 51ea3c0c..831a03be 100644 --- a/Source/util.h +++ b/Source/util.h @@ -36,6 +36,7 @@ extern double my_wtof(const wchar_t *str); extern size_t my_strncpy(TCHAR*Dest, const TCHAR*Src, size_t cchMax); template bool strtrycpy(T*Dest, const T*Src, size_t cchCap) { size_t c = my_strncpy(Dest, Src, cchCap); return c < cchCap && !Src[c]; } size_t my_strftime(TCHAR *s, size_t max, const TCHAR *fmt, const struct tm *tm); +template bool ChIsHex(T c) { return (c >= '0' && c <= '9') || ((c|32) >= 'a' && (c|32) <= 'f'); } // Adds the bitmap in filename using resource editor re as id id. // If width or height are specified it will also make sure the bitmap is in that size @@ -283,7 +284,7 @@ const UINT64 invalid_file_size64 = ~ (UINT64) 0; BYTE* alloc_and_read_file(FILE *f, unsigned long &size); BYTE* alloc_and_read_file(const TCHAR *filepath, unsigned long &size); -typedef struct { char*base; size_t internal; } FILEVIEW; +typedef struct { char*base; size_t size; } FILEVIEW; void close_file_view(FILEVIEW&mmfv); char* create_file_view_readonly(const TCHAR *filepath, FILEVIEW&mmfv); @@ -390,5 +391,10 @@ RM_DEFINE_FREEFUNC(my_convert_free); // Platform detection inline bool Platform_IsBigEndian() { return FIX_ENDIAN_INT16(0x00ff) != 0x00ff; } unsigned char Platform_SupportsUTF8Conversion(); +#ifdef _WIN32 +#define Platform_IsWindows() ( !0 ) +#else +#define Platform_IsWindows() ( 0 ) +#endif #endif //_UTIL_H_