From 64a0f32e524c50271442e39fa0bdd6e9d6f8d6f4 Mon Sep 17 00:00:00 2001 From: wizou Date: Mon, 12 Apr 2010 16:00:17 +0000 Subject: [PATCH] more simple TCHARs fixes git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6047 212acab6-be3b-0410-9dea-997c60f758d6 --- Contrib/Library/LibraryLocal/LibraryLocal.cpp | 2 +- Contrib/Library/RegTool/RegTool.c | 748 +++--- Contrib/Library/RegTool/SConscript | 3 +- Contrib/MakeLangId/SConscript | 3 +- Contrib/Makensisw/SConscript | 5 +- Contrib/Makensisw/makensisw.cpp | 22 +- Contrib/Makensisw/noclib.cpp | 72 - Contrib/Makensisw/noclib.h | 33 - Contrib/Makensisw/toolbar.cpp | 7 +- Contrib/Makensisw/update.cpp | 9 +- Contrib/Makensisw/utils.cpp | 26 +- Contrib/Makensisw/version.cpp | 5 +- Contrib/UIs/SConscript | 3 +- Contrib/zip2exe/main.cpp | 25 +- Contrib/zip2exe/zlib/ioapi.h | 2 +- Docs/src/build.but | 2 +- SCons/Tools/mstoolkit.py | 2 +- SConstruct | 16 +- Source/DialogTemplate.cpp | 2 +- Source/Plugins.cpp | 8 +- Source/ResourceEditor.cpp | 2151 ++++++++--------- Source/ResourceEditor.h | 22 +- Source/ResourceVersionInfo.cpp | 8 +- Source/Tests/winchar.cpp | 31 +- Source/build.cpp | 28 +- Source/exehead/exec.c | 6 +- Source/exehead/fileform.h | 1 - Source/icon.cpp | 22 +- Source/lang.cpp | 10 +- Source/script.cpp | 20 +- Source/strlist.cpp | 409 ++-- Source/strlist.h | 4 +- Source/tstring.h | 19 +- Source/util.cpp | 6 +- Source/winchar.cpp | 31 +- Source/winchar.h | 4 +- Source/writer.cpp | 22 +- Source/writer.h | 3 +- 38 files changed, 1831 insertions(+), 1961 deletions(-) delete mode 100644 Contrib/Makensisw/noclib.cpp delete mode 100644 Contrib/Makensisw/noclib.h diff --git a/Contrib/Library/LibraryLocal/LibraryLocal.cpp b/Contrib/Library/LibraryLocal/LibraryLocal.cpp index b1d99fbf..3ffff7c8 100644 --- a/Contrib/Library/LibraryLocal/LibraryLocal.cpp +++ b/Contrib/Library/LibraryLocal/LibraryLocal.cpp @@ -47,7 +47,7 @@ int GetTLBVersion(tstring& filepath, DWORD& high, DWORD & low) hr = LoadTypeLib(fullpath, &typeLib); #else // If built without UNICODE, we still need to convert this string to a Unicode string. - WCHAR *ole_filename = winchar_fromansi(fullpath); + WCHAR *ole_filename = winchar_fromTchar(fullpath); hr = LoadTypeLib(ole_filename, &typeLib); #endif diff --git a/Contrib/Library/RegTool/RegTool.c b/Contrib/Library/RegTool/RegTool.c index 70178120..69b90080 100644 --- a/Contrib/Library/RegTool/RegTool.c +++ b/Contrib/Library/RegTool/RegTool.c @@ -1,368 +1,380 @@ -#include -#include - -#ifndef _CRT_STRINGIZE -#define __CRT_STRINGIZE(_Value) #_Value -#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) -#endif /* _CRT_STRINGIZE */ - -#define STR_SIZE 1024 - -void RegFile(TCHAR cmd, TCHAR *file, int x64); -void RegDll(TCHAR *file); -void RegTypeLib(TCHAR *file); -void DeleteFileOnReboot(TCHAR *pszFile); - -int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) -{ - TCHAR *cmdline; - TCHAR seekchar = _T(' '); - - cmdline = GetCommandLine(); - if (*cmdline == _T('\"')) - seekchar = *cmdline++; - - while (*cmdline && *cmdline != seekchar) - cmdline = CharNext(cmdline); - cmdline = CharNext(cmdline); - while (*cmdline == _T(' ')) - cmdline++; - - if (*cmdline++ != _T('/')) - { - ExitProcess(1); - return 0; - } - - if (*cmdline == _T('S')) - { - HKEY rootkey; - - if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NSIS.Library.RegTool.v3"), 0, KEY_READ, &rootkey))) - { - TCHAR keyname[STR_SIZE]; - - while (RegEnumKey(rootkey, 0, keyname, STR_SIZE) == ERROR_SUCCESS) - { - HKEY key; - - if (SUCCEEDED(RegOpenKeyEx(rootkey, keyname, 0, KEY_READ, &key))) - { - DWORD t, count, l = sizeof(DWORD); - - if (SUCCEEDED(RegQueryValueEx(key, _T("count"), NULL, &t, (LPBYTE) &count, &l)) && t == REG_DWORD) - { - DWORD j; - TCHAR valname[128], mode[3], file[STR_SIZE]; - - for (j = 1; j <= count; j++) - { - wsprintf(valname, _T("%u.mode"), j); - l = sizeof(mode); - if (FAILED(RegQueryValueEx(key, valname, NULL, &t, (LPBYTE) mode, &l)) || t != REG_SZ) - continue; - - wsprintf(valname, _T("%u.file"), j); - l = (lstrlen(file)+1)*sizeof(TCHAR); - if (FAILED(RegQueryValueEx(key, valname, NULL, &t, (LPBYTE) file, &l)) || t != REG_SZ) - continue; - - // JP: Note, if this mode[1] is used as anything but a boolean later on, - // we'll need to consider the next line carefully. - RegFile(mode[0], file, mode[1] == 'X'); - } - } - - RegCloseKey(key); - RegDeleteKey(rootkey, keyname); - } - } - - RegCloseKey(rootkey); - RegDeleteKey(HKEY_LOCAL_MACHINE, _T("Software\\NSIS.Library.RegTool.v3")); - } - - { - TCHAR file[STR_SIZE]; - if (GetModuleFileName(GetModuleHandle(NULL), file, STR_SIZE)) - { - DeleteFileOnReboot(file); - } - } - } - else - { - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); - OleInitialize(NULL); - - if (*cmdline == _T('D')) - { - RegDll(cmdline + 1); - } - else if (*cmdline == _T('T')) - { - RegTypeLib(cmdline + 1); - } - - OleUninitialize(); - SetErrorMode(0); - } - - ExitProcess(0); - return 0; -} - -void SafeWow64EnableWow64FsRedirection(BOOL Wow64FsEnableRedirection) -{ - HMODULE kernel = GetModuleHandle(_T("kernel32")); - if (kernel) - { - FARPROC proc = GetProcAddress(kernel, "Wow64EnableWow64FsRedirection"); - if (proc) - { - typedef BOOL (WINAPI *Wow64EnableWow64FsRedirectionPtr)(BOOL); - Wow64EnableWow64FsRedirectionPtr Wow64EnableWow64FsRedirectionFunc = - (Wow64EnableWow64FsRedirectionPtr) proc; - - Wow64EnableWow64FsRedirectionFunc(Wow64FsEnableRedirection); - } - } -} - -void RegFile(TCHAR cmd, TCHAR *file, int x64) -{ - TCHAR self[STR_SIZE]; - TCHAR cmdline[STR_SIZE]; - - int ready = 0; - - if (!*file || (cmd != _T('D') && cmd != _T('T') && cmd != _T('E'))) - return; - - if (cmd == _T('E')) - { - wsprintf(cmdline, _T("\"%s\" /regserver"), file); - ready++; - } - else if (!x64) - { - if (GetModuleFileName(GetModuleHandle(NULL), self, STR_SIZE)) - { - wsprintf(cmdline, _T("\"%s\" /%c%s"), self, cmd, file); - ready++; - } - } - else - { - if (GetSystemDirectory(self, STR_SIZE)) - { - wsprintf(cmdline, _T("\"%s\\regsvr32.exe\" /s \"%s\""), self, file); - ready++; - - SafeWow64EnableWow64FsRedirection(FALSE); - } - } - - if (ready) - { - PROCESS_INFORMATION pi; - STARTUPINFO si = { sizeof(STARTUPINFO) }; - - if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) - { - CloseHandle(pi.hThread); - - WaitForSingleObject(pi.hProcess, INFINITE); - - CloseHandle(pi.hProcess); - } - - if (x64) - { - SafeWow64EnableWow64FsRedirection(TRUE); - } - } -} - -void RegDll(TCHAR *file) -{ - HMODULE mod = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (mod) - { - FARPROC regfunc = GetProcAddress(mod, "DllRegisterServer"); - if (regfunc) - regfunc(); - FreeLibrary(mod); - } -} - -void RegTypeLib(TCHAR *file) -{ - WCHAR wfile[STR_SIZE]; - - if (MultiByteToWideChar(CP_ACP, 0, file, -1, wfile, STR_SIZE) != 0) - { - ITypeLib* tlib; - if (SUCCEEDED(LoadTypeLib(wfile, &tlib))) { - RegisterTypeLib(tlib, wfile, NULL); - tlib->lpVtbl->Release(tlib); - } - } -} - -char *mystrstriA(char *a, const char *b) -{ - int l = lstrlenA(b); - while (lstrlenA(a) >= l) - { - char c = a[l]; - a[l] = 0; - if (!lstrcmpiA(a, b)) - { - a[l] = c; - return a; - } - a[l] = c; - a = CharNextA(a); - } - return NULL; -} - -void mini_memcpy(void *out, const void *in, int len) -{ - char *c_out=(char*)out; - char *c_in=(char *)in; - while (len-- > 0) - { - *c_out++=*c_in++; - } -} - -HANDLE myOpenFile(const TCHAR *fn, DWORD da, DWORD cd) -{ - int attr = GetFileAttributes(fn); - return CreateFile( - fn, - da, - FILE_SHARE_READ, - NULL, - cd, - attr == INVALID_FILE_ATTRIBUTES ? 0 : attr, - NULL - ); -} - -/** Modifies the wininit.ini file to rename / delete a file. - * - * @param prevName The previous / current name of the file. - * @param newName The new name to move the file to. If NULL, the current file - * will be deleted. - */ -void RenameViaWininit(const TCHAR* prevName, const TCHAR* newName) -{ - static char szRenameLine[1024]; - static TCHAR wininit[1024]; - static TCHAR tmpbuf[1024]; - - int cchRenameLine; - LPCSTR szRenameSec = "[Rename]\r\n"; // rename section marker - HANDLE hfile; - DWORD dwFileSize; - DWORD dwBytes; - DWORD dwRenameLinePos; - char *pszWinInit; // Contains the file contents of wininit.ini - - int spn; // length of the short path name in TCHARs. - - lstrcpy(tmpbuf, _T("NUL")); - - if (newName) { - // create the file if it's not already there to prevent GetShortPathName from failing - CloseHandle(myOpenFile(newName,0,CREATE_NEW)); - spn = GetShortPathName(newName,tmpbuf,1024); - if (!spn || spn > 1024) - return; - } - // wininit is used as a temporary here - spn = GetShortPathName(prevName,wininit,1024); - if (!spn || spn > 1024) - return; - cchRenameLine = wsprintfA(szRenameLine, "%s=%s\r\n", tmpbuf, wininit); - // Get the path to the wininit.ini file. - GetWindowsDirectory(wininit, 1024-16); - lstrcat(wininit, _T("\\wininit.ini")); - - hfile = myOpenFile(wininit, GENERIC_READ | GENERIC_WRITE, OPEN_ALWAYS); - - if (hfile != INVALID_HANDLE_VALUE) - { - // We are now working on the Windows wininit file - dwFileSize = GetFileSize(hfile, NULL); - pszWinInit = (char*) GlobalAlloc(GPTR, dwFileSize + cchRenameLine + 10); - - if (pszWinInit != NULL) - { - if (ReadFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL) && dwFileSize == dwBytes) - { - // Look for the rename section in the current file. - LPSTR pszRenameSecInFile = mystrstriA(pszWinInit, szRenameSec); - if (pszRenameSecInFile == NULL) - { - // No rename section. So we add it to the end of file. - lstrcpyA(pszWinInit+dwFileSize, szRenameSec); - dwFileSize += 10; - dwRenameLinePos = dwFileSize; - } - else - { - // There is a rename section, but is there another section after it? - char *pszFirstRenameLine = pszRenameSecInFile+10; - char *pszNextSec = mystrstriA(pszFirstRenameLine,"\n["); - if (pszNextSec) - { - TCHAR *p = ++pszNextSec; - while (p < pszWinInit + dwFileSize) { - p[cchRenameLine] = *p; - p++; - } - - dwRenameLinePos = pszNextSec - pszWinInit; - } - // rename section is last, stick item at end of file - else dwRenameLinePos = dwFileSize; - } - - mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine); - dwFileSize += cchRenameLine; - - SetFilePointer(hfile, 0, NULL, FILE_BEGIN); - WriteFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL); - - GlobalFree(pszWinInit); - } - } - - CloseHandle(hfile); - } -} - -void DeleteFileOnReboot(TCHAR *pszFile) -{ - BOOL fOk = 0; - HMODULE hLib=GetModuleHandle(_T("KERNEL32.dll")); - if (hLib) - { - typedef BOOL (WINAPI *mfea_t)(LPCTSTR lpExistingFileName,LPCTSTR lpNewFileName,DWORD dwFlags); - mfea_t mfea; - mfea=(mfea_t) GetProcAddress(hLib,_CRT_STRINGIZE(MoveFileEx)); - if (mfea) - { - fOk=mfea(pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); - } - } - - if (!fOk) - { - RenameViaWininit(pszFile, NULL); - } -} +#include +#include + +#ifndef _CRT_STRINGIZE +#define __CRT_STRINGIZE(_Value) #_Value +#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) +#endif /* _CRT_STRINGIZE */ + +#define STR_SIZE 1024 + +void RegFile(TCHAR cmd, TCHAR *file, int x64); +void RegDll(TCHAR *file); +void RegTypeLib(TCHAR *file); +void DeleteFileOnReboot(TCHAR *pszFile); + +int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) +{ + TCHAR *cmdline; + TCHAR seekchar = _T(' '); + + cmdline = GetCommandLine(); + if (*cmdline == _T('\"')) + seekchar = *cmdline++; + + while (*cmdline && *cmdline != seekchar) + cmdline = CharNext(cmdline); + cmdline = CharNext(cmdline); + while (*cmdline == _T(' ')) + cmdline++; + + if (*cmdline++ != _T('/')) + { + ExitProcess(1); + return 0; + } + + if (*cmdline == _T('S')) + { + HKEY rootkey; + TCHAR *keyname, *file; // These are turned into heap memory to avoid _chkstk + keyname = (TCHAR*) GlobalAlloc(GPTR, STR_SIZE*sizeof(TCHAR)); + file = (TCHAR*) GlobalAlloc(GPTR, STR_SIZE*sizeof(TCHAR)); + + if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NSIS.Library.RegTool.v3"), 0, KEY_READ, &rootkey))) + { + while (RegEnumKey(rootkey, 0, keyname, STR_SIZE) == ERROR_SUCCESS) + { + HKEY key; + + if (SUCCEEDED(RegOpenKeyEx(rootkey, keyname, 0, KEY_READ, &key))) + { + DWORD t, count, l = sizeof(DWORD); + + if (SUCCEEDED(RegQueryValueEx(key, _T("count"), NULL, &t, (LPBYTE) &count, &l)) && t == REG_DWORD) + { + DWORD j; + TCHAR valname[128], mode[3]; + + for (j = 1; j <= count; j++) + { + wsprintf(valname, _T("%u.mode"), j); + l = sizeof(mode); + if (FAILED(RegQueryValueEx(key, valname, NULL, &t, (LPBYTE) mode, &l)) || t != REG_SZ) + continue; + + wsprintf(valname, _T("%u.file"), j); + l = (lstrlen(file)+1)*sizeof(TCHAR); + if (FAILED(RegQueryValueEx(key, valname, NULL, &t, (LPBYTE) file, &l)) || t != REG_SZ) + continue; + + // JP: Note, if this mode[1] is used as anything but a boolean later on, + // we'll need to consider the next line carefully. + RegFile(mode[0], file, mode[1] == 'X'); + } + } + + RegCloseKey(key); + RegDeleteKey(rootkey, keyname); + } + } + + RegCloseKey(rootkey); + RegDeleteKey(HKEY_LOCAL_MACHINE, _T("Software\\NSIS.Library.RegTool.v3")); + } + + { + if (GetModuleFileName(GetModuleHandle(NULL), file, STR_SIZE)) + { + DeleteFileOnReboot(file); + } + } + GlobalFree(keyname); + GlobalFree(file); + } + else + { + SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + OleInitialize(NULL); + + if (*cmdline == _T('D')) + { + RegDll(cmdline + 1); + } + else if (*cmdline == _T('T')) + { + RegTypeLib(cmdline + 1); + } + + OleUninitialize(); + SetErrorMode(0); + } + + ExitProcess(0); + return 0; +} + +void SafeWow64EnableWow64FsRedirection(BOOL Wow64FsEnableRedirection) +{ + HMODULE kernel = GetModuleHandle(_T("kernel32")); + if (kernel) + { + FARPROC proc = GetProcAddress(kernel, "Wow64EnableWow64FsRedirection"); + if (proc) + { + typedef BOOL (WINAPI *Wow64EnableWow64FsRedirectionPtr)(BOOL); + Wow64EnableWow64FsRedirectionPtr Wow64EnableWow64FsRedirectionFunc = + (Wow64EnableWow64FsRedirectionPtr) proc; + + Wow64EnableWow64FsRedirectionFunc(Wow64FsEnableRedirection); + } + } +} + +void RegFile(TCHAR cmd, TCHAR *file, int x64) +{ + TCHAR* self; // These are turned into heap memory to avoid _chkstk + TCHAR* cmdline; + + int ready = 0; + + if (!*file || (cmd != _T('D') && cmd != _T('T') && cmd != _T('E'))) + return; + + self = (TCHAR*) GlobalAlloc(GPTR, sizeof(TCHAR)*STR_SIZE); + cmdline = (TCHAR*) GlobalAlloc(GPTR, sizeof(TCHAR)*STR_SIZE); + + if (cmd == _T('E')) + { + wsprintf(cmdline, _T("\"%s\" /regserver"), file); + ready++; + } + else if (!x64) + { + if (GetModuleFileName(GetModuleHandle(NULL), self, STR_SIZE)) + { + wsprintf(cmdline, _T("\"%s\" /%c%s"), self, cmd, file); + ready++; + } + } + else + { + if (GetSystemDirectory(self, STR_SIZE)) + { + wsprintf(cmdline, _T("\"%s\\regsvr32.exe\" /s \"%s\""), self, file); + ready++; + + SafeWow64EnableWow64FsRedirection(FALSE); + } + } + + if (ready) + { + PROCESS_INFORMATION pi; + STARTUPINFO si = { sizeof(STARTUPINFO) }; + + if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + CloseHandle(pi.hThread); + + WaitForSingleObject(pi.hProcess, INFINITE); + + CloseHandle(pi.hProcess); + } + + if (x64) + { + SafeWow64EnableWow64FsRedirection(TRUE); + } + } + + GlobalFree(self); + GlobalFree(cmdline); +} + +void RegDll(TCHAR *file) +{ + HMODULE mod = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (mod) + { + FARPROC regfunc = GetProcAddress(mod, "DllRegisterServer"); + if (regfunc) + regfunc(); + FreeLibrary(mod); + } +} + +void RegTypeLib(TCHAR *file) +{ +#ifdef _UNICODE + WCHAR* wfile = file; +#else + WCHAR wfile[STR_SIZE]; + if (MultiByteToWideChar(CP_ACP, 0, file, -1, wfile, STR_SIZE) == 0) + return; +#endif + { + ITypeLib* tlib; + if (SUCCEEDED(LoadTypeLib(wfile, &tlib))) { + RegisterTypeLib(tlib, wfile, NULL); + tlib->lpVtbl->Release(tlib); + } + } +} + +char *mystrstriA(char *a, const char *b) +{ + int l = lstrlenA(b); + while (lstrlenA(a) >= l) + { + char c = a[l]; + a[l] = 0; + if (!lstrcmpiA(a, b)) + { + a[l] = c; + return a; + } + a[l] = c; + a = CharNextA(a); + } + return NULL; +} + +void mini_memcpy(void *out, const void *in, int len) +{ + char *c_out=(char*)out; + char *c_in=(char *)in; + while (len-- > 0) + { + *c_out++=*c_in++; + } +} + +HANDLE myOpenFile(const TCHAR *fn, DWORD da, DWORD cd) +{ + int attr = GetFileAttributes(fn); + return CreateFile( + fn, + da, + FILE_SHARE_READ, + NULL, + cd, + attr == INVALID_FILE_ATTRIBUTES ? 0 : attr, + NULL + ); +} + +/** Modifies the wininit.ini file to rename / delete a file. + * + * @param prevName The previous / current name of the file. + * @param newName The new name to move the file to. If NULL, the current file + * will be deleted. + */ +void RenameViaWininit(const TCHAR* prevName, const TCHAR* newName) +{ + static char szRenameLine[1024]; + static TCHAR wininit[1024]; + static TCHAR tmpbuf[1024]; + + int cchRenameLine; + LPCSTR szRenameSec = "[Rename]\r\n"; // rename section marker + HANDLE hfile; + DWORD dwFileSize; + DWORD dwBytes; + DWORD dwRenameLinePos; + char *pszWinInit; // Contains the file contents of wininit.ini + + int spn; // length of the short path name in TCHARs. + + lstrcpy(tmpbuf, _T("NUL")); + + if (newName) { + // create the file if it's not already there to prevent GetShortPathName from failing + CloseHandle(myOpenFile(newName,0,CREATE_NEW)); + spn = GetShortPathName(newName,tmpbuf,1024); + if (!spn || spn > 1024) + return; + } + // wininit is used as a temporary here + spn = GetShortPathName(prevName,wininit,1024); + if (!spn || spn > 1024) + return; + cchRenameLine = wsprintfA(szRenameLine, "%s=%s\r\n", tmpbuf, wininit); + // Get the path to the wininit.ini file. + GetWindowsDirectory(wininit, 1024-16); + lstrcat(wininit, _T("\\wininit.ini")); + + hfile = myOpenFile(wininit, GENERIC_READ | GENERIC_WRITE, OPEN_ALWAYS); + + if (hfile != INVALID_HANDLE_VALUE) + { + // We are now working on the Windows wininit file + dwFileSize = GetFileSize(hfile, NULL); + pszWinInit = (char*) GlobalAlloc(GPTR, dwFileSize + cchRenameLine + 10); + + if (pszWinInit != NULL) + { + if (ReadFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL) && dwFileSize == dwBytes) + { + // Look for the rename section in the current file. + LPSTR pszRenameSecInFile = mystrstriA(pszWinInit, szRenameSec); + if (pszRenameSecInFile == NULL) + { + // No rename section. So we add it to the end of file. + lstrcpyA(pszWinInit+dwFileSize, szRenameSec); + dwFileSize += 10; + dwRenameLinePos = dwFileSize; + } + else + { + // There is a rename section, but is there another section after it? + char *pszFirstRenameLine = pszRenameSecInFile+10; + char *pszNextSec = mystrstriA(pszFirstRenameLine,"\n["); + if (pszNextSec) + { + char *p = ++pszNextSec; + while (p < pszWinInit + dwFileSize) { + p[cchRenameLine] = *p; + p++; + } + + dwRenameLinePos = pszNextSec - pszWinInit; + } + // rename section is last, stick item at end of file + else dwRenameLinePos = dwFileSize; + } + + mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine); + dwFileSize += cchRenameLine; + + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); + WriteFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL); + + GlobalFree(pszWinInit); + } + } + + CloseHandle(hfile); + } +} + +void DeleteFileOnReboot(TCHAR *pszFile) +{ + BOOL fOk = 0; + HMODULE hLib=GetModuleHandle(_T("KERNEL32.dll")); + if (hLib) + { + typedef BOOL (WINAPI *mfea_t)(LPCTSTR lpExistingFileName,LPCTSTR lpNewFileName,DWORD dwFlags); + mfea_t mfea; + mfea=(mfea_t) GetProcAddress(hLib,_CRT_STRINGIZE(MoveFileEx)); + if (mfea) + { + fOk=mfea(pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); + } + } + + if (!fOk) + { + RenameViaWininit(pszFile, NULL); + } +} diff --git a/Contrib/Library/RegTool/SConscript b/Contrib/Library/RegTool/SConscript index d40a0f6d..5704c8b9 100644 --- a/Contrib/Library/RegTool/SConscript +++ b/Contrib/Library/RegTool/SConscript @@ -13,5 +13,6 @@ libs = Split(""" """) Import('BuildUtil') +Import('_tWinMain') -BuildUtil(target, files, libs, entry = 'WinMain', nodeflib = True, file_name = 'RegTool.bin') +BuildUtil(target, files, libs, entry = _tWinMain, nodeflib = True, file_name = 'RegTool.bin') diff --git a/Contrib/MakeLangId/SConscript b/Contrib/MakeLangId/SConscript index 122629d9..66c1f2b5 100644 --- a/Contrib/MakeLangId/SConscript +++ b/Contrib/MakeLangId/SConscript @@ -19,6 +19,7 @@ libs = Split(""" """) Import('BuildUtil') +Import('_tWinMain') -BuildUtil(target, files, libs, res = res, resources = resources, entry = 'WinMain') +BuildUtil(target, files, libs, res = res, resources = resources, entry = _tWinMain) diff --git a/Contrib/Makensisw/SConscript b/Contrib/Makensisw/SConscript index 401fab81..5c1541bf 100644 --- a/Contrib/Makensisw/SConscript +++ b/Contrib/Makensisw/SConscript @@ -2,7 +2,6 @@ target = 'makensisw' files = Split(""" makensisw.cpp - noclib.cpp toolbar.cpp utils.cpp version.cpp @@ -34,6 +33,7 @@ libs = Split(""" user32 gdi32 shell32 + shlwapi comdlg32 comctl32 wsock32 @@ -45,6 +45,7 @@ docs = Split(""" """) Import('BuildUtil') +Import('_tWinMain') BuildUtil( target, @@ -52,7 +53,7 @@ BuildUtil( libs, res = res, resources = resources, - entry = 'WinMain', + entry = _tWinMain, defines = ['RELEASE=2.3'], docs = docs, root_util = True diff --git a/Contrib/Makensisw/makensisw.cpp b/Contrib/Makensisw/makensisw.cpp index d95d8327..267daa38 100644 --- a/Contrib/Makensisw/makensisw.cpp +++ b/Contrib/Makensisw/makensisw.cpp @@ -24,9 +24,9 @@ #include "makensisw.h" #include +#include #include #include "resource.h" -#include "noclib.h" #include "toolbar.h" #include "update.h" @@ -41,9 +41,9 @@ int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, TCHAR *cmdParam, int int status; HACCEL haccel; - my_memset(&g_sdata,0,sizeof(NSCRIPTDATA)); - my_memset(&g_resize,0,sizeof(NRESIZEDATA)); - my_memset(&g_find,0,sizeof(NFINDREPLACE)); + memset(&g_sdata,0,sizeof(NSCRIPTDATA)); + memset(&g_resize,0,sizeof(NRESIZEDATA)); + memset(&g_find,0,sizeof(NFINDREPLACE)); g_sdata.hInstance=GetModuleHandle(0); g_sdata.symbols = NULL; g_sdata.sigint_event = CreateEvent(NULL, FALSE, FALSE, _T("makensis win32 signint event")); @@ -130,10 +130,10 @@ void ProcessCommandLine() if (argc > 1) { for (i = 1; i < argc; i++) { - if (!lstrncmpi(argv[i], _T("/XSetCompressor "), lstrlen(_T("/XSetCompressor ")))) + if (!StrCmpNI(argv[i], _T("/XSetCompressor "), lstrlen(_T("/XSetCompressor ")))) { TCHAR *p = argv[i] + lstrlen(_T("/XSetCompressor ")); - if(!lstrncmpi(p,_T("/FINAL "), lstrlen(_T("/FINAL ")))) + if(!StrCmpNI(p,_T("/FINAL "), lstrlen(_T("/FINAL ")))) { p += lstrlen(_T("/FINAL ")); } @@ -481,7 +481,7 @@ BOOL CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { if (g_sdata.input_script) { TCHAR str[MAX_PATH],*str2; lstrcpy(str,g_sdata.input_script); - str2=my_strrchr(str,_T('\\')); + str2=_tcsrchr(str,_T('\\')); if(str2!=NULL) *(str2+1)=0; ShellExecute(g_sdata.hwnd,_T("open"),str,NULL,NULL,SW_SHOWNORMAL); } @@ -656,7 +656,7 @@ BOOL CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { case IDM_FIND: { if (!g_find.uFindReplaceMsg) g_find.uFindReplaceMsg = RegisterWindowMessage(FINDMSGSTRING); - my_memset(&g_find.fr, 0, sizeof(FINDREPLACE)); + memset(&g_find.fr, 0, sizeof(FINDREPLACE)); g_find.fr.lStructSize = sizeof(FINDREPLACE); g_find.fr.hwndOwner = hwndDlg; g_find.fr.Flags = FR_NOUPDOWN; @@ -743,7 +743,7 @@ DWORD WINAPI MakeNSISProc(LPVOID p) { PostMessage(g_sdata.hwnd,WM_MAKENSIS_PROCESSCOMPLETE,0,0); return 1; } - char szBuf[1024]; + TCHAR szBuf[1024]; DWORD dwRead = 1; DWORD dwExit = !STILL_ACTIVE; while (dwExit == STILL_ACTIVE || dwRead) { @@ -986,7 +986,7 @@ BOOL CALLBACK SettingsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) if(n > 0) { TCHAR *buf = (TCHAR *)GlobalAlloc(GPTR, (n+1)*sizeof(TCHAR)); SendDlgItemMessage(hwndDlg, IDC_SYMBOL, WM_GETTEXT, n+1, (LPARAM)buf); - if(my_strstr(buf,_T(" ")) || my_strstr(buf,_T("\t"))) { + if(_tcsstr(buf,_T(" ")) || _tcsstr(buf,_T("\t"))) { MessageBox(hwndDlg,SYMBOLSERROR,_T("Error"),MB_OK|MB_ICONSTOP); GlobalFree(buf); break; @@ -1028,7 +1028,7 @@ BOOL CALLBACK SettingsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) if(n > 0) { TCHAR *buf = (TCHAR *)GlobalAlloc(GPTR, (n+1)*sizeof(TCHAR)); SendDlgItemMessage(hwndDlg, IDC_SYMBOLS, LB_GETTEXT, (WPARAM)index, (LPARAM)buf); - TCHAR *p = my_strstr(buf,_T("=")); + TCHAR *p = _tcsstr(buf,_T("=")); if(p) { SendDlgItemMessage(hwndDlg, IDC_VALUE, WM_SETTEXT, 0, (LPARAM)(p+1)); *p=0; diff --git a/Contrib/Makensisw/noclib.cpp b/Contrib/Makensisw/noclib.cpp deleted file mode 100644 index b4621667..00000000 --- a/Contrib/Makensisw/noclib.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - Copyright (c) 2002 Robert Rainwater - Contributors: Justin Frankel, Fritz Elfert, and Amir Szekely - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - -*/ -#include -#include "noclib.h" - -// kickik's clib methods -char *my_strrchr(const char *string, int c) { - for (int i=lstrlen(string); i>=0; i--) - if (string[i]==c) return (char*)&string[i]; - return 0; -} - -char *my_strstr(char *i, char *s) { - if (lstrlen(i)>=lstrlen(s)) while (i[lstrlen(s)-1]) { - int l=lstrlen(s)+1; - char *ii=i; - char *is=s; - while (--l>0) { - if (*ii != *is) break; - ii++; - is++; - } - if (l==0) return i; - i++; - } - return NULL; -} - -void *my_memset(void *dest, int c, size_t count) { - for (size_t i=0; i 0) && (*s1) && (*s2) && (*(s1) == *(s2))) chars--, s1++, s2++; - if ((chars == 0) || (*s1 == *s2)) return 0; - return (*s1 - *s2); -} - -int lstrncmpi(char *s1, const char *s2, int chars) -{ - while (chars-- && *s1 && *s2) - { - char ss1=*s1++; - char ss2=*s2++; - if (ss1>='a' && ss1 <= 'z') ss1+='A'-'a'; - if (ss2>='a' && ss2 <= 'z') ss2+='A'-'a'; - if (ss1 != ss2) return ss1-ss2; - } - return 0; -} diff --git a/Contrib/Makensisw/noclib.h b/Contrib/Makensisw/noclib.h deleted file mode 100644 index 51686b01..00000000 --- a/Contrib/Makensisw/noclib.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (c) 2002 Robert Rainwater - Contributors: Justin Frankel, Fritz Elfert, and Amir Szekely - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - -*/ -#ifndef NOCLIB_H -#define NOCLIB_H - -// kickik's clib methods -char *my_strstr(char *i, char *s); -char *my_strrchr(const char *string, int c); -void *my_memset(void *dest, int c, size_t count); - -// iceman_k's clib methods -int lstrncmp(char *s1, const char *s2, int chars); -int lstrncmpi(char *s1, const char *s2, int chars); -#endif diff --git a/Contrib/Makensisw/toolbar.cpp b/Contrib/Makensisw/toolbar.cpp index 13b1c36c..dbf3fc96 100644 --- a/Contrib/Makensisw/toolbar.cpp +++ b/Contrib/Makensisw/toolbar.cpp @@ -25,7 +25,6 @@ #include "makensisw.h" #include "resource.h" -#include "noclib.h" #include "toolbar.h" #include "../ExDLL/nsis_tchar.h" @@ -133,7 +132,7 @@ void UpdateToolBarCompressorButton() TCHAR temp[64]; // increased to 64. Hit limit 08/20/2007 -- Jim Park. TOOLINFO ti; - my_memset(&ti, 0, sizeof(TOOLINFO)); + memset(&ti, 0, sizeof(TOOLINFO)); if(g_sdata.compressor >= COMPRESSOR_SCRIPT && g_sdata.compressor <= COMPRESSOR_BEST) { iBitmap = compressor_bitmaps[(int)g_sdata.compressor]; @@ -146,7 +145,7 @@ void UpdateToolBarCompressorButton() IDS_COMPRESSOR, temp, COUNTOF(temp)); - my_memset(szBuffer, 0, sizeof(szBuffer)); + memset(szBuffer, 0, sizeof(szBuffer)); lstrcat(szBuffer,temp); lstrcat(szBuffer,_T(" [")); LoadString(g_sdata.hInstance, @@ -174,7 +173,7 @@ void AddToolBarButtonTooltip(int id, int iString) TCHAR szBuffer[64]; RECT rect; - my_memset(&ti, 0, sizeof(TOOLINFO)); + memset(&ti, 0, sizeof(TOOLINFO)); SendMessage(g_toolbar.hwnd, TB_GETITEMRECT, id, (LPARAM) (LPRECT) &rect); diff --git a/Contrib/Makensisw/update.cpp b/Contrib/Makensisw/update.cpp index f509d3b2..7070ac3f 100644 --- a/Contrib/Makensisw/update.cpp +++ b/Contrib/Makensisw/update.cpp @@ -2,7 +2,6 @@ #include "makensisw.h" #include "update.h" -#include "noclib.h" #include "jnetlib/httpget.h" #include "../ExDLL/nsis_tchar.h" @@ -62,14 +61,14 @@ DWORD CALLBACK UpdateThread(LPVOID v) { if (getProxyInfo(pbuf)) { - p=my_strstr(pbuf,"http="); + p=strstr(pbuf,"http="); if (!p) p=pbuf; else { p+=5; } - char *tp=my_strstr(p,";"); + char *tp=strstr(p,";"); if (tp) *tp=0; - char *p2=my_strstr(p,"="); + char *p2=strstr(p,"="); if (p2) p=0; // we found the wrong proxy } @@ -140,7 +139,7 @@ DWORD CALLBACK UpdateThread(LPVOID v) { void Update() { DWORD dwThreadId; - if (my_strstr(g_sdata.brandingv,_T("cvs"))) + if (_tcsstr(g_sdata.brandingv,_T("cvs"))) { MessageBox(g_sdata.hwnd,_T("Cannot check for new version of nightly builds. To update, download a new nightly build."),_T("NSIS Update"),MB_OK|MB_ICONSTOP); return; diff --git a/Contrib/Makensisw/utils.cpp b/Contrib/Makensisw/utils.cpp index 6f978d1d..c289271c 100644 --- a/Contrib/Makensisw/utils.cpp +++ b/Contrib/Makensisw/utils.cpp @@ -25,7 +25,7 @@ #include "makensisw.h" #include "resource.h" #include "toolbar.h" -#include "noclib.h" +#include #ifdef _countof #define COUNTOF _countof @@ -60,13 +60,13 @@ int SetArgv(const TCHAR *cmdLine, int *argc, TCHAR ***argv) } } - argSpaceSize = size * sizeof(TCHAR *) + lstrlen(cmdLine) + 1; + argSpaceSize = size * sizeof(TCHAR *) + (lstrlen(cmdLine) + 1) * sizeof(TCHAR); argSpace = (TCHAR *) GlobalAlloc(GMEM_FIXED, argSpaceSize); if (!argSpace) return 0; *argv = (TCHAR **) argSpace; - argSpace += size * sizeof(TCHAR *); + argSpace = (TCHAR *) ((*argv)+size); size--; p = cmdLine; @@ -241,13 +241,13 @@ void SetCompressorStats() DWORD len = lstrlen(TOTAL_SIZE_COMPRESSOR_STAT); lstrcat(g_sdata.compressor_stats,buf); - if(!lstrncmp(buf,TOTAL_SIZE_COMPRESSOR_STAT,len)) { + if(!StrCmpN(buf,TOTAL_SIZE_COMPRESSOR_STAT,len)) { break; } } else { DWORD len = lstrlen(EXE_HEADER_COMPRESSOR_STAT); - if(!lstrncmp(buf,EXE_HEADER_COMPRESSOR_STAT,len)) { + if(!StrCmpN(buf,EXE_HEADER_COMPRESSOR_STAT,len)) { found = true; lstrcpy(g_sdata.compressor_stats,_T("\n\n")); lstrcat(g_sdata.compressor_stats,buf); @@ -622,7 +622,7 @@ int InitBranding() { void InitTooltips(HWND h) { if (h == NULL) return; - my_memset(&g_tip,0,sizeof(NTOOLTIP)); + memset(&g_tip,0,sizeof(NTOOLTIP)); g_tip.tip_p = h; INITCOMMONCONTROLSEX icx; icx.dwSize = sizeof(icx); @@ -668,7 +668,7 @@ LRESULT CALLBACK TipHookProc(int nCode, WPARAM wParam, LPARAM lParam) { void ShowDocs() { TCHAR pathf[MAX_PATH],*path; GetModuleFileName(NULL,pathf,sizeof(pathf)); - path=my_strrchr(pathf,_T('\\')); + path=_tcsrchr(pathf,_T('\\')); if(path!=NULL) *path=0; lstrcat(pathf,LOCALDOCS); if ((int)ShellExecute(g_sdata.hwnd,_T("open"),pathf,NULL,NULL,SW_SHOWNORMAL)<=32) @@ -749,7 +749,7 @@ void PushMRUFile(TCHAR* fname) return; } - my_memset(full_file_name,0,sizeof(full_file_name)); + memset(full_file_name,0,sizeof(full_file_name)); rv = GetFullPathName(fname,COUNTOF(full_file_name),full_file_name,NULL); if (rv == 0) { return; @@ -783,19 +783,19 @@ void BuildMRUMenus() for(i = 0; i < MRU_LIST_SIZE; i++) { if(g_mru_list[i][0]) { - my_memset(buf,0,sizeof(buf)); - my_memset(&mii, 0, sizeof(mii)); + memset(buf,0,sizeof(buf)); + memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; mii.wID = IDM_MRU_FILE+i; mii.fType = MFT_STRING; wsprintf(buf, _T("&%d "), i + 1); if(lstrlen(g_mru_list[i]) > MRU_DISPLAY_LENGTH) { - TCHAR *p = my_strrchr(g_mru_list[i],_T('\\')); + TCHAR *p = _tcsrchr(g_mru_list[i],_T('\\')); if(p) { p++; if(lstrlen(p) > MRU_DISPLAY_LENGTH - 7) { - my_memset(buf2,0,sizeof(buf2)); + memset(buf2,0,sizeof(buf2)); lstrcpyn(buf2,p,MRU_DISPLAY_LENGTH - 9); lstrcat(buf2,_T("...")); @@ -833,7 +833,7 @@ void BuildMRUMenus() } hMenu = g_sdata.toolsSubmenu; - my_memset(&mii, 0, sizeof(mii)); + memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE; diff --git a/Contrib/Makensisw/version.cpp b/Contrib/Makensisw/version.cpp index 0597ace9..c74f796d 100644 --- a/Contrib/Makensisw/version.cpp +++ b/Contrib/Makensisw/version.cpp @@ -21,11 +21,12 @@ Unicode support by Jim Park -- 08/17/2007 */ +#include "makensisw.h" #define REALSTR(x) #x #define STR(x) REALSTR(x) #ifdef RELEASE - const char *NSISW_VERSION = "MakeNSISW " STR(RELEASE) " (NSIS Compiler Interface)"; + const TCHAR *NSISW_VERSION = _T("MakeNSISW ") _T(STR(RELEASE)) _T(" (NSIS Compiler Interface)"); #else - const char *NSISW_VERSION = "MakeNSISW " __DATE__; + const TCHAR *NSISW_VERSION = _T("MakeNSISW ") __TDATE__; #endif diff --git a/Contrib/UIs/SConscript b/Contrib/UIs/SConscript index 2e598ab7..c08f3bad 100644 --- a/Contrib/UIs/SConscript +++ b/Contrib/UIs/SConscript @@ -18,9 +18,10 @@ libs = Split(""" """) Import('BuildUtil env') +Import('_tWinMain') code = env.Object(code) for ui in uis: - ui = BuildUtil(ui, [code], libs, entry = 'WinMain', res = ui + '.rc', contrib = True, path = 'UIs') + ui = BuildUtil(ui, [code], libs, entry = _tWinMain, res = ui + '.rc', contrib = True, path = 'UIs') env.Alias('UIs', ui) diff --git a/Contrib/zip2exe/main.cpp b/Contrib/zip2exe/main.cpp index dd7e75c1..1bb1f81b 100644 --- a/Contrib/zip2exe/main.cpp +++ b/Contrib/zip2exe/main.cpp @@ -188,17 +188,30 @@ int tempzip_make(HWND hwndDlg, TCHAR *fn) int nf=0, nkb=0; g_extracting=1; do { - TCHAR filename[MAX_PATH]; + char filenameA[MAX_PATH]; unz_file_info info; - unzGetCurrentFileInfo(f,&info,filename,sizeof(filename),NULL,0,NULL,0); + // ZREAD uses byte size, not TCHAR length. + unzGetCurrentFileInfo(f,&info,filenameA,sizeof(filenameA),NULL,0,NULL,0); // was zip created on MS-DOS/Windows? if ((info.version & 0xFF00) == 0) { - OemToCharBuff(filename, filename, strlen(filename)); + OemToCharBuffA(filenameA, filenameA, strlen(filenameA)); } +#ifdef _UNICODE + TCHAR filename[MAX_PATH]; + if (MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filename, MAX_PATH) == 0) + { + if (f) unzClose(f); + MessageBox(hwndDlg,_T("Error converting filename to Unicode"), g_errcaption, MB_OK|MB_ICONSTOP); + return 1; + } +#else + char* filename = filenameA; +#endif + if (filename[0] && filename[_tcsclen(filename)-1] != _T('\\') && filename[_tcsclen(filename)-1] != _T('/')) @@ -485,7 +498,11 @@ void makeEXE(HWND hwndDlg) TCHAR buf[2048]; GetTempPath(MAX_PATH,buf); GetTempFileName(buf,_T("zne"),0,nsifilename); - FILE *fp=fopen(nsifilename,_T("w")); +#ifdef _UNICODE + FILE *fp=_tfopen(nsifilename,_T("w, ccs=UNICODE")); // generate a Unicode .NSI file +#else + FILE *fp=_tfopen(nsifilename,_T("w")); +#endif if (!fp) { MessageBox(hwndDlg,_T("Error writing .NSI file"),g_errcaption,MB_OK|MB_ICONSTOP); diff --git a/Contrib/zip2exe/zlib/ioapi.h b/Contrib/zip2exe/zlib/ioapi.h index 351d230e..218a9380 100644 --- a/Contrib/zip2exe/zlib/ioapi.h +++ b/Contrib/zip2exe/zlib/ioapi.h @@ -11,7 +11,7 @@ #ifndef _ZLIBIOAPI_H #define _ZLIBIOAPI_H -#include "../../ExDLL/nsis_tchar.h" +#include #define ZLIB_FILEFUNC_SEEK_CUR (1) diff --git a/Docs/src/build.but b/Docs/src/build.but index 1b918488..f2eaa551 100644 --- a/Docs/src/build.but +++ b/Docs/src/build.but @@ -94,7 +94,7 @@ To compile the documentation as a CHM file, hhc.exe must be in the PATH. It is a To build NSIS Menu, install \W{http://www.wxwidgets.org/}{wxWidgets 2.8}, create an environment variable named \c{WXWIN} containing the path to the installation directory of wxWidgets, run \c{Contrib\\NSIS Menu\\wx\\wxbuild.bat} and build NSIS as usual. -\\Important notes for Microsoft Visual C++ 6.0 users:\\ The latest \W{http://www.microsoft.com/msdownload/platformsdk/sdkupdate/}{Platform SDK} must be installed before building. Because of flaws in the libraries distributed with Microsoft Visual C++ 6.0, not installing the Platform SDK will result in crashes when using the \R{copyfiles}{CopyFiles} command. See \W{http://forums.winamp.com/showthread.php?s=&threadid=131964}{this forum topic} for more information. Installing the \W{http://msdn.microsoft.com/vstudio/aa718349.aspx}{Processor Pack} is highly recommended xto decrease the size of the installer overhead. +\\Important notes for Microsoft Visual C++ 6.0 users:\\ The latest \W{http://www.microsoft.com/msdownload/platformsdk/sdkupdate/}{Platform SDK} must be installed before building. Because of flaws in the libraries distributed with Microsoft Visual C++ 6.0, not installing the Platform SDK will result in crashes when using the \R{copyfiles}{CopyFiles} command. See \W{http://forums.winamp.com/showthread.php?s=&threadid=131964}{this forum topic} for more information. Installing the \W{http://msdn.microsoft.com/vstudio/aa718349.aspx}{Processor Pack} is highly recommended to decrease the size of the installer overhead. \H{build_posix} Building on POSIX diff --git a/SCons/Tools/mstoolkit.py b/SCons/Tools/mstoolkit.py index 1b7eaa5f..c2c92766 100644 --- a/SCons/Tools/mstoolkit.py +++ b/SCons/Tools/mstoolkit.py @@ -338,7 +338,7 @@ def generate(env): env['REGSVRFLAGS'] = '/s ' env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS $TARGET' - env['MSVS_VERSION'] = '8.0' + env['MSVS_VERSION'] = '7.1' def exists(env): diff --git a/SConstruct b/SConstruct index e0080f48..6d5b1dc2 100644 --- a/SConstruct +++ b/SConstruct @@ -185,11 +185,13 @@ if 'NSIS_CONFIG_CONST_DATA_PATH' in defenv['NSIS_CPPDEFINES']: # Need this early for the config header files to be placed in if defenv['UNICODE']: + _tWinMain = 'wWinMain' if defenv['DEBUG']: defenv.Replace(BUILD_PREFIX = 'build/udebug') else: defenv.Replace(BUILD_PREFIX = 'build/urelease') else: + _tWinMain = 'WinMain' if defenv['DEBUG']: defenv.Replace(BUILD_PREFIX = 'build/debug') else: @@ -454,7 +456,7 @@ def build_installer(target, source, env): AlwaysBuild(cmd) # Comment out the following if you want to see the installation directory # after the build is finished. - AlwaysBuild(env.AddPostAction(cmd, Delete('$INSTDISTDIR'))) + #AlwaysBuild(env.AddPostAction(cmd, Delete('$INSTDISTDIR'))) env.Alias('dist-installer', cmd) installer_target = defenv.Command('nsis-${VERSION}-setup${DISTSUFFIX}.exe', @@ -474,15 +476,9 @@ defenv.Alias('dist', ['dist-zip', 'dist-installer']) for d in doc: if d in defenv['SKIPDOC']: continue - if defenv['UNICODE']: - defenv.DistributeDoc('Unicode/' + d) - else: - defenv.DistributeDoc(d) + defenv.DistributeDoc(d) -if defenv['UNICODE']: - defenv.DistributeConf('Unicode/nsisconf.nsh') -else: - defenv.DistributeConf('nsisconf.nsh') +defenv.DistributeConf('nsisconf.nsh') ###################################################################### ####### Stubs ### @@ -678,7 +674,7 @@ for util in utils: path = 'Contrib/' + util build_dir = '$BUILD_PREFIX/' + util - exports = {'BuildUtil' : BuildUtil, 'BuildUtilEnv' : BuildUtilEnv, 'env' : util_env} + exports = {'BuildUtil' : BuildUtil, 'BuildUtilEnv' : BuildUtilEnv, 'env' : util_env, '_tWinMain' : _tWinMain} defenv.SConscript(dirs = path, build_dir = build_dir, duplicate = False, exports = exports) diff --git a/Source/DialogTemplate.cpp b/Source/DialogTemplate.cpp index cbb9a98a..546398df 100644 --- a/Source/DialogTemplate.cpp +++ b/Source/DialogTemplate.cpp @@ -292,7 +292,7 @@ void CDialogTemplate::SetFont(TCHAR* szFaceName, WORD wFontSize) { m_bCharset = DEFAULT_CHARSET; m_dwStyle |= DS_SETFONT; if (m_szFont) delete [] m_szFont; - m_szFont = winchar_fromansi(szFaceName, m_uCodePage); + m_szFont = winchar_fromTchar(szFaceName, m_uCodePage); m_sFontSize = wFontSize; } diff --git a/Source/Plugins.cpp b/Source/Plugins.cpp index cc0dfb82..3596367c 100644 --- a/Source/Plugins.cpp +++ b/Source/Plugins.cpp @@ -59,7 +59,7 @@ void Plugins::FindCommands(const tstring &path, bool displayInfo) struct NSISException : public std::runtime_error { - NSISException(const string& msg) : std::runtime_error(msg) {} + NSISException(const tstring& msg) : std::runtime_error(string(TtoCString(msg))) {} }; namespace { @@ -82,7 +82,7 @@ void read_file(const tstring& filename, vector& data) { ifstream file(filename.c_str(), ios::binary); if (!file) { - throw NSISException("Can't open file '" + filename + "'"); + throw NSISException(_T("Can't open file '") + filename + _T("'")); } // get the file size @@ -93,7 +93,7 @@ void read_file(const tstring& filename, vector& data) { file.read(reinterpret_cast(&data[0]), filesize); if (size_t(file.tellg()) != filesize) { // ifstream::eof doesn't return true here - throw NSISException("Couldn't read entire file '" + filename + "'"); + throw NSISException(_T("Couldn't read entire file '") + filename + _T("'")); } } } @@ -139,7 +139,7 @@ void Plugins::GetExports(const tstring &pathToDll, bool displayInfo) for (DWORD j = 0; j < FIX_ENDIAN_INT32(exports->NumberOfNames); j++) { const string name = string((char*)exports + FIX_ENDIAN_INT32(names[j]) - ExportDirVA); - const tstring signature = dllName + _T("::") + name; + const tstring signature = dllName + _T("::") + tstring(CtoTString(name)); const tstring lcsig = lowercase(signature); m_command_to_path[lcsig] = pathToDll; m_command_lowercase_to_command[lcsig] = signature; diff --git a/Source/ResourceEditor.cpp b/Source/ResourceEditor.cpp index d4a515e4..c095ea56 100644 --- a/Source/ResourceEditor.cpp +++ b/Source/ResourceEditor.cpp @@ -1,1086 +1,1065 @@ -/* - * ResourceEditor.cpp - * - * This file is a part of NSIS. - * - * Copyright (C) 2002-2009 Amir Szekely - * - * Licensed under the zlib/libpng license (the "License"); - * you may not use this file except in compliance with the License. - * - * Licence details can be found in the file COPYING. - * - * This software is provided 'as-is', without any express or implied - * warranty. - * - * Reviewed for Unicode support by Jim Park -- 08/21/2007 - */ - -#include "ResourceEditor.h" -#include "util.h" -#include "winchar.h" -#include -#include "tchar.h" -using namespace std; - -////////////////////////////////////////////////////////////////////// -// Utilities -////////////////////////////////////////////////////////////////////// - -#define ALIGN(dwToAlign, dwAlignOn) dwToAlign = (dwToAlign%dwAlignOn == 0) ? dwToAlign : dwToAlign - (dwToAlign%dwAlignOn) + dwAlignOn -#define RALIGN(dwToAlign, dwAlignOn) ((dwToAlign%dwAlignOn == 0) ? dwToAlign : dwToAlign - (dwToAlign%dwAlignOn) + dwAlignOn) - -static inline DWORD ConvertEndianness(DWORD d) { - return FIX_ENDIAN_INT32(d); -} - -static inline WORD ConvertEndianness(WORD w) { - return FIX_ENDIAN_INT16(w); -} - -PIMAGE_NT_HEADERS CResourceEditor::GetNTHeaders(BYTE* pbPE) { - // Get dos header - PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) pbPE; - if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) - throw runtime_error("PE file contains invalid DOS header"); - - // Get NT headers - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(pbPE + ConvertEndianness((DWORD)dosHeader->e_lfanew)); - if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) - throw runtime_error("PE file missing NT signature"); - - // Make sure this is a supported PE format - if (ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && - ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) - throw runtime_error("Unsupported PE format"); - - return ntHeaders; -} - -PRESOURCE_DIRECTORY CResourceEditor::GetResourceDirectory( - BYTE* pbPE, - DWORD dwSize, - PIMAGE_NT_HEADERS ntHeaders, - DWORD *pdwResSecVA /*=NULL*/, - DWORD *pdwSectionIndex /*=NULL*/ -) { - PIMAGE_DATA_DIRECTORY dataDirectory = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory); - DWORD dwNumberOfRvaAndSizes = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, NumberOfRvaAndSizes); - - if (ConvertEndianness(dwNumberOfRvaAndSizes) <= IMAGE_DIRECTORY_ENTRY_RESOURCE) - throw runtime_error("No resource section found"); - // Get resource section virtual address - DWORD dwResSecVA = ConvertEndianness(dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); - // Pointer to the sections headers array - PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(ntHeaders); - - DWORD dwSectionIndex = (DWORD) -1; - - // Find resource section index in the array - for (int i = 0; i < ConvertEndianness(ntHeaders->FileHeader.NumberOfSections); i++) { - if (dwResSecVA == ConvertEndianness(sectionHeadersArray[i].VirtualAddress)) { - // Remember resource section index - dwSectionIndex = i; - // Check for invalid resource section pointer - if (!sectionHeadersArray[i].PointerToRawData) - throw runtime_error("Invalid resource section pointer"); - - break; - } - - // Invalid section pointer (goes beyond the PE image) - if (ConvertEndianness(sectionHeadersArray[i].PointerToRawData) > dwSize) - throw runtime_error("Invalid section pointer"); - } - - // No resource section... - if (dwSectionIndex == (DWORD) -1) - throw runtime_error("PE file doesn't contain any resource section"); - - // Return extra parameters - if (pdwSectionIndex) - *pdwSectionIndex = dwSectionIndex; - if (pdwResSecVA) - *pdwResSecVA = dwResSecVA; - - // Pointer to section data, the first resource directory - DWORD dwResSecPtr = ConvertEndianness(sectionHeadersArray[dwSectionIndex].PointerToRawData); - return PRESOURCE_DIRECTORY(pbPE + dwResSecPtr); -} - -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// CResourceEditor -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResourceEditor::CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData /*=true*/) { - // Copy the data pointer - m_pbPE = pbPE; - m_iSize = iSize; - m_bKeepData = bKeepData; - - // Get NT headers - m_ntHeaders = GetNTHeaders(m_pbPE); - - // No check sum support yet... - DWORD* pdwCheckSum = GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, CheckSum); - if (*pdwCheckSum) - { - // clear checksum (should be [re]calculated after all changes done) - pdwCheckSum = 0; - //throw runtime_error("CResourceEditor doesn't yet support check sum"); - } - - // Get resource section virtual address, resource section index and pointer to resource directory - PRESOURCE_DIRECTORY rdRoot = GetResourceDirectory(m_pbPE, iSize, m_ntHeaders, &m_dwResourceSectionVA, &m_dwResourceSectionIndex); - - // Scan the resource directory - m_cResDir = ScanDirectory(rdRoot, rdRoot); -} - -CResourceEditor::~CResourceEditor() { - if (m_cResDir) { - m_cResDir->Destroy(); - delete m_cResDir; - } -} - -////////////////////////////////////////////////////////////////////// -// Methods -////////////////////////////////////////////////////////////////////// - -// Adds/Replaces/Removes a resource. -// If lpData is 0 UpdateResource removes the resource. -bool CResourceEditor::UpdateResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { - CResourceDirectory* nameDir = 0; - CResourceDirectory* langDir = 0; - CResourceDataEntry* data = 0; - IMAGE_RESOURCE_DIRECTORY rd = {0, /*time(0),*/}; - int iTypeIdx = -1, iNameIdx = -1, iLangIdx = -1; - - iTypeIdx = m_cResDir->Find(szType); - if (iTypeIdx > -1) { - nameDir = m_cResDir->GetEntry(iTypeIdx)->GetSubDirectory(); - iNameIdx = nameDir->Find(szName); - if (iNameIdx > -1) { - langDir = nameDir->GetEntry(iNameIdx)->GetSubDirectory(); - iLangIdx = langDir->Find(wLanguage); - if (iLangIdx > -1) { - data = langDir->GetEntry(iLangIdx)->GetDataEntry(); - } - } - } - - if (lpData) { - // Replace/Add the resource - if (data) { - data->SetData(lpData, dwSize); - return true; - } - - if (!nameDir) { - // Type doesn't yet exist - nameDir = new CResourceDirectory(&rd); - m_cResDir->AddEntry(new CResourceDirectoryEntry(szType, nameDir)); - } - if (!langDir) { - // Name doesn't yet exist - langDir = new CResourceDirectory(&rd); - nameDir->AddEntry(new CResourceDirectoryEntry(szName, langDir)); - } - if (!data) { - // Language doesn't yet exist, hence data nither - data = new CResourceDataEntry(lpData, dwSize); - langDir->AddEntry(new CResourceDirectoryEntry(MAKEINTRESOURCEW(wLanguage), data)); - } - } - else if (data) { - // Delete the resource - delete data; - langDir->RemoveEntry(iLangIdx); - // Delete directories holding the resource if empty - if (!langDir->CountEntries()) { - delete langDir; - nameDir->RemoveEntry(iNameIdx); - if (!nameDir->CountEntries()) { - delete nameDir; - m_cResDir->RemoveEntry(iTypeIdx); - } - } - } - else return false; - return true; -} - -static WCHAR* ResStringToUnicode(const char *szString) { - if (IS_INTRESOURCE(szString)) - return MAKEINTRESOURCEW((ULONG_PTR)szString); - else - return winchar_fromansi(szString); -} - -static void FreeUnicodeResString(WCHAR* szwString) { - if (!IS_INTRESOURCE(szwString)) - delete [] szwString; -} - -bool CResourceEditor::UpdateResourceW(WORD szType, WCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { - return UpdateResourceW(MAKEINTRESOURCEW(szType), szName, wLanguage, lpData, dwSize); -} - -bool CResourceEditor::UpdateResourceW(WCHAR* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { - return UpdateResourceW(szType, MAKEINTRESOURCEW(szName), wLanguage, lpData, dwSize); -} - -bool CResourceEditor::UpdateResourceA(char* szType, char* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { - WCHAR* szwType = ResStringToUnicode(szType); - WCHAR* szwName = ResStringToUnicode(szName); - - bool result = UpdateResourceW(szwType, szwName, wLanguage, lpData, dwSize); - - FreeUnicodeResString(szwType); - FreeUnicodeResString(szwName); - - return result; -} - -bool CResourceEditor::UpdateResourceA(WORD szType, char* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { - return UpdateResourceA(MAKEINTRESOURCE(szType), szName, wLanguage, lpData, dwSize); -} - -bool CResourceEditor::UpdateResourceA(char* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { - return UpdateResourceA(szType, MAKEINTRESOURCE(szName), wLanguage, lpData, dwSize); -} - -bool CResourceEditor::UpdateResource(WORD szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { - return UpdateResourceW(MAKEINTRESOURCEW(szType), MAKEINTRESOURCEW(szName), wLanguage, lpData, dwSize); -} - -// Returns a copy of the requested resource -// Returns 0 if the requested resource can't be found -BYTE* CResourceEditor::GetResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage) { - if (!m_bKeepData) - throw runtime_error("Can't GetResource() when bKeepData is false"); - - CResourceDirectory* nameDir = 0; - CResourceDirectory* langDir = 0; - CResourceDataEntry* data = 0; - - int i = m_cResDir->Find(szType); - if (i > -1) { - nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); - i = nameDir->Find(szName); - if (i > -1) { - langDir = nameDir->GetEntry(i)->GetSubDirectory(); - i = 0; - if (wLanguage) - i = langDir->Find(wLanguage); - if (i > -1) { - data = langDir->GetEntry(i)->GetDataEntry(); - } - } - } - - if (data) { - BYTE* toReturn = new BYTE[data->GetSize()]; - CopyMemory(toReturn, data->GetData(), data->GetSize()); - return toReturn; - } - else - return NULL; -} - -BYTE* CResourceEditor::GetResourceA(char* szType, char* szName, LANGID wLanguage) { - WCHAR* szwType = ResStringToUnicode(szType); - WCHAR* szwName = ResStringToUnicode(szName); - - BYTE* result = GetResourceW(szwType, szwName, wLanguage); - - FreeUnicodeResString(szwType); - FreeUnicodeResString(szwName); - - return result; -} - -// Returns the size of the requested resource -// Returns -1 if the requested resource can't be found -int CResourceEditor::GetResourceSizeW(WCHAR* szType, WCHAR* szName, LANGID wLanguage) { - CResourceDirectory* nameDir = 0; - CResourceDirectory* langDir = 0; - CResourceDataEntry* data = 0; - - int i = m_cResDir->Find(szType); - if (i > -1) { - nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); - i = nameDir->Find(szName); - if (i > -1) { - langDir = nameDir->GetEntry(i)->GetSubDirectory(); - i = 0; - if (wLanguage) - i = langDir->Find(wLanguage); - if (i > -1) { - data = langDir->GetEntry(i)->GetDataEntry(); - } - } - } - - if (data) - return (int) data->GetSize(); - else - return -1; -} - -int CResourceEditor::GetResourceSizeA(char* szType, char* szName, LANGID wLanguage) { - WCHAR* szwType = ResStringToUnicode(szType); - WCHAR* szwName = ResStringToUnicode(szName); - - int result = GetResourceSizeW(szwType, szwName, wLanguage); - - FreeUnicodeResString(szwType); - FreeUnicodeResString(szwName); - - return result; -} - -// Returns the offset of the requested resource in the original PE -// Returns -1 if the requested resource can't be found -DWORD CResourceEditor::GetResourceOffsetW(WCHAR* szType, WCHAR* szName, LANGID wLanguage) { - CResourceDirectory* nameDir = 0; - CResourceDirectory* langDir = 0; - CResourceDataEntry* data = 0; - - int i = m_cResDir->Find(szType); - if (i > -1) { - nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); - i = nameDir->Find(szName); - if (i > -1) { - langDir = nameDir->GetEntry(i)->GetSubDirectory(); - i = 0; - if (wLanguage) - i = langDir->Find(wLanguage); - if (i > -1) { - data = langDir->GetEntry(i)->GetDataEntry(); - } - } - } - - if (data) - return data->GetOffset(); - else - return DWORD(-1); -} - -DWORD CResourceEditor::GetResourceOffsetA(char* szType, char* szName, LANGID wLanguage) { - WCHAR* szwType = ResStringToUnicode(szType); - WCHAR* szwName = ResStringToUnicode(szName); - - DWORD result = GetResourceOffsetW(szwType, szwName, wLanguage); - - FreeUnicodeResString(szwType); - FreeUnicodeResString(szwName); - - return result; -} - -void CResourceEditor::FreeResource(BYTE* pbResource) -{ - if (pbResource) - delete [] pbResource; -} - -// Saves the edited PE into a buffer and returns it. -DWORD CResourceEditor::Save(BYTE* pbBuf, DWORD &dwSize) { - if (!m_bKeepData) - throw runtime_error("Can't Save() when bKeepData is false"); - - unsigned int i; - DWORD dwReqSize; - - DWORD dwFileAlign = ConvertEndianness(m_ntHeaders->OptionalHeader.FileAlignment); - DWORD dwSecAlign = ConvertEndianness(m_ntHeaders->OptionalHeader.SectionAlignment); - - DWORD dwRsrcSize = m_cResDir->GetSize(); // Size of new resource section - DWORD dwRsrcSizeAligned = RALIGN(dwRsrcSize, dwFileAlign); // Align it to FileAlignment - - // Calculate the total new PE size - DWORD dwOldRsrcSize = ConvertEndianness(IMAGE_FIRST_SECTION(m_ntHeaders)[m_dwResourceSectionIndex].SizeOfRawData); - dwReqSize = m_iSize - dwOldRsrcSize + dwRsrcSizeAligned; - - if (!pbBuf || dwSize < dwReqSize) - return dwReqSize; - - // Use buffer - BYTE* pbNewPE = pbBuf; - dwSize = dwReqSize; - // Fill buffer with zeros - ZeroMemory(pbNewPE, dwSize); - - BYTE* seeker = pbNewPE; - BYTE* oldSeeker = m_pbPE; - - PIMAGE_SECTION_HEADER old_sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders); - - DWORD dwHeaderSize = ConvertEndianness(old_sectionHeadersArray[m_dwResourceSectionIndex].PointerToRawData); - WORD wNumberOfSections = ConvertEndianness(m_ntHeaders->FileHeader.NumberOfSections); - - // Copy everything until the resource section (including headers and everything that might come after them) - // We don't use SizeOfHeaders because sometimes (using VC6) it can extend beyond the first section - // or (Borland) there could be some more information between the headers and the first section. - CopyMemory(seeker, oldSeeker, dwHeaderSize); - - // Skip the headers and whatever comes after them - seeker += dwHeaderSize; - oldSeeker += dwHeaderSize; - - // Get new nt headers pointer - PIMAGE_NT_HEADERS ntHeaders = GetNTHeaders(pbNewPE); - // Get a pointer to the new section headers - PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(ntHeaders); - - // Skip the resource section in the old PE seeker. - oldSeeker += dwOldRsrcSize; - - // Save the old virtual size of the resource section - DWORD dwNewVirtualSize = RALIGN(dwRsrcSize, dwSecAlign); - DWORD dwOldVirtualSize = ConvertEndianness(sectionHeadersArray[m_dwResourceSectionIndex].Misc.VirtualSize); - ALIGN(dwOldVirtualSize, dwSecAlign); - DWORD dwVAAdjustment = dwNewVirtualSize - dwOldVirtualSize; - - // Set the new size of the resource section (size aligned to FileAlignment) - sectionHeadersArray[m_dwResourceSectionIndex].SizeOfRawData = ConvertEndianness(dwRsrcSizeAligned); - // Set the virtual size as well (in memory) - sectionHeadersArray[m_dwResourceSectionIndex].Misc.VirtualSize = ConvertEndianness(dwRsrcSize); - (*GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory))[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = ConvertEndianness(dwRsrcSize); - - // Set the new virtual size of the image - DWORD* pdwSizeOfImage = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, SizeOfImage); - *pdwSizeOfImage = AlignVA(*GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, SizeOfHeaders)); - for (i = 0; i < wNumberOfSections; i++) { - DWORD dwSecSize = ConvertEndianness(sectionHeadersArray[i].Misc.VirtualSize); - *pdwSizeOfImage = AlignVA(AdjustVA(*pdwSizeOfImage, dwSecSize)); - } - - // Set the new AddressOfEntryPoint if needed - DWORD* pdwAddressOfEntryPoint = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, AddressOfEntryPoint); - if (ConvertEndianness(*pdwAddressOfEntryPoint) > m_dwResourceSectionVA) - *pdwAddressOfEntryPoint = AdjustVA(*pdwAddressOfEntryPoint, dwVAAdjustment); - - // Set the new BaseOfCode if needed - DWORD* pdwBaseOfCode = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, BaseOfCode); - if (ConvertEndianness(*pdwBaseOfCode) > m_dwResourceSectionVA) - *pdwBaseOfCode = AdjustVA(*pdwBaseOfCode, dwVAAdjustment); - - // Set the new BaseOfData if needed - if (ntHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - DWORD* pdwBaseOfData = &((PIMAGE_OPTIONAL_HEADER32)&ntHeaders->OptionalHeader)->BaseOfData; - if (ConvertEndianness(*pdwBaseOfData) > m_dwResourceSectionVA) - *pdwBaseOfData = AdjustVA(*pdwBaseOfData, dwVAAdjustment); - } - - // Refresh the headers of the sections that come after the resource section, and the data directory - DWORD dwNumberOfRvaAndSizes = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, NumberOfRvaAndSizes); - PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory); - for (i = m_dwResourceSectionIndex + 1; i < wNumberOfSections; i++) { - if (sectionHeadersArray[i].PointerToRawData) { - AdjustVA(sectionHeadersArray[i].PointerToRawData, dwRsrcSizeAligned - dwOldRsrcSize); - } - - // We must find the right data directory entry before we change the virtual address - unsigned int uDataDirIdx = 0; - for (unsigned int j = 0; j < ConvertEndianness(dwNumberOfRvaAndSizes); j++) - if (pDataDirectory[j].VirtualAddress == sectionHeadersArray[i].VirtualAddress) - uDataDirIdx = j; - - sectionHeadersArray[i].VirtualAddress = AdjustVA(sectionHeadersArray[i].VirtualAddress, dwVAAdjustment); - - // Change the virtual address in the data directory too - if (uDataDirIdx) - pDataDirectory[uDataDirIdx].VirtualAddress = sectionHeadersArray[i].VirtualAddress; - } - - // Write the resource section - WriteRsrcSec(seeker); - // Advance the pointer - seeker += dwRsrcSizeAligned; - - // Copy everything that comes after the resource section (other sections and tacked data) - DWORD dwLeft = m_iSize - (oldSeeker - m_pbPE); - if (dwLeft) - CopyMemory(seeker, oldSeeker, dwLeft); - - seeker += dwLeft; - oldSeeker += dwLeft; - - /********************************************************** - * To add checksum to the header use MapFileAndCheckSum - **********************************************************/ - - // From now on, we are working on the new PE - // Freeing the old PE memory is up to the user - m_pbPE = pbNewPE; - m_iSize = dwSize; - m_ntHeaders = ntHeaders; - // We just wrote the resource section according to m_cResDir, so we don't need to rescan - // m_dwResourceSectionIndex and m_dwResourceSectionVA have also been left unchanged as - // we didn't move the resources section - - return 0; -} - -// This function scans exe sections and after find a match with given name -// increments it's virtual size (auto fixes image size based on section alignment, etc) -// Jim Park: The section name must be ASCII code. Do not TCHAR this stuff. -bool CResourceEditor::AddExtraVirtualSize2PESection(const char* pszSectionName, int addsize) -{ - PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders); - - // Refresh the headers of the sections that come after the resource section, and the data directory - for (int i = 0; i < ConvertEndianness(m_ntHeaders->FileHeader.NumberOfSections); i++) { - if (!strcmp((LPCSTR)sectionHeadersArray[i].Name, pszSectionName)) { - sectionHeadersArray[i].Misc.VirtualSize = AlignVA(AdjustVA(sectionHeadersArray[i].Misc.VirtualSize, addsize)); - - sectionHeadersArray[i].Characteristics &= ConvertEndianness((DWORD) ~IMAGE_SCN_MEM_DISCARDABLE); - - // now fix any section after - for (int k = i + 1; k < ConvertEndianness(m_ntHeaders->FileHeader.NumberOfSections); k++, i++) { - DWORD dwLastSecVA = ConvertEndianness(sectionHeadersArray[i].VirtualAddress); - DWORD dwLastSecSize = ConvertEndianness(sectionHeadersArray[i].Misc.VirtualSize); - DWORD dwSecVA = AlignVA(ConvertEndianness(dwLastSecVA + dwLastSecSize)); - - sectionHeadersArray[k].VirtualAddress = dwSecVA; - - if (m_dwResourceSectionIndex == (DWORD) k) - { - // fix the resources virtual address if it changed - PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, DataDirectory); - pDataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = dwSecVA; - m_dwResourceSectionVA = ConvertEndianness(dwSecVA); - } - } - - return true; - } - } - - return false; -} - -////////////////////////////////////////////////////////////////////// -// Private Methods -////////////////////////////////////////////////////////////////////// - -// This function scans a give resource directory and return a CResourceDirectory object -// rdRoot must point to the root directory of the resource section -CResourceDirectory* CResourceEditor::ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan) { - // Create CResourceDirectory from rdToScan - CResourceDirectory* rdc = new CResourceDirectory(PIMAGE_RESOURCE_DIRECTORY(rdToScan)); - WCHAR* szName; - PIMAGE_RESOURCE_DATA_ENTRY rde = NULL; - - // Go through all entries of this resource directory - int entries = ConvertEndianness(rdToScan->Header.NumberOfNamedEntries); - entries += ConvertEndianness(rdToScan->Header.NumberOfIdEntries); - - for (int i = 0; i < entries; i++) { - MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rd = rdToScan->Entries[i]; - rd.UOffset.OffsetToData = ConvertEndianness(rd.UOffset.OffsetToData); - rd.UName.Name = ConvertEndianness(rd.UName.Name); - - // If this entry points to data entry get a pointer to it - if (!rd.UOffset.DirectoryOffset.DataIsDirectory) - rde = PIMAGE_RESOURCE_DATA_ENTRY(rd.UOffset.OffsetToData + (BYTE*)rdRoot); - - // If this entry has a name, translate it from Unicode - if (rd.UName.NameString.NameIsString) { - PIMAGE_RESOURCE_DIR_STRING_U rds = PIMAGE_RESOURCE_DIR_STRING_U(rd.UName.NameString.NameOffset + (char*)rdRoot); - - size_t nameSize = ConvertEndianness(rds->Length); - szName = new WCHAR[nameSize+1]; - winchar_strncpy(szName, rds->NameString, nameSize); - szName[nameSize] = 0; - } - // Else, set the name to this entry's id - else - szName = MAKEINTRESOURCEW(ConvertEndianness(rdToScan->Entries[i].UName.Id)); - - if (rd.UOffset.DirectoryOffset.DataIsDirectory) - { - rdc->AddEntry( - new CResourceDirectoryEntry( - szName, - ScanDirectory( - rdRoot, - PRESOURCE_DIRECTORY(rd.UOffset.DirectoryOffset.OffsetToDirectory + (LPBYTE)rdRoot) - ) - ) - ); - } - else - { - LPBYTE pbData = (LPBYTE)rdRoot + ConvertEndianness(rde->OffsetToData) - m_dwResourceSectionVA; - DWORD dwOffset = DWORD(pbData - m_pbPE); - - if (m_bKeepData) - { - if (dwOffset > DWORD(m_iSize)) - { - throw runtime_error("Invalid resource entry data pointer, possibly compressed resources"); - } - } - else - { - pbData = m_pbPE; // dummy pointer to "nothing" - } - - rdc->AddEntry( - new CResourceDirectoryEntry( - szName, - new CResourceDataEntry( - pbData, - ConvertEndianness(rde->Size), - ConvertEndianness(rde->CodePage), - dwOffset - ) - ) - ); - } - - // Delete the dynamicly allocated name if it is a name and not an id - if (!IS_INTRESOURCE(szName)) - delete [] szName; - } - - return rdc; -} - -// This function writes into a given place in memory (pbRsrcSec) the edited resource section -void CResourceEditor::WriteRsrcSec(BYTE* pbRsrcSec) { - BYTE* seeker = pbRsrcSec; - - queue qDirs; // Used to scan the tree by level - queue qDataEntries; // Used for writing the data entries - queue qDataEntries2; // Used for writing raw resources data - queue qStrings; // Used for writing resources' names - - qDirs.push(m_cResDir); - - while (!qDirs.empty()) { - CResourceDirectory* crd = qDirs.front(); - - IMAGE_RESOURCE_DIRECTORY rdDir = crd->GetInfo(); - - rdDir.NumberOfNamedEntries = ConvertEndianness(rdDir.NumberOfNamedEntries); - rdDir.NumberOfIdEntries = ConvertEndianness(rdDir.NumberOfIdEntries); - - CopyMemory(seeker, &rdDir, sizeof(IMAGE_RESOURCE_DIRECTORY)); - crd->m_ulWrittenAt = (ULONG_PTR)(seeker); - seeker += sizeof(IMAGE_RESOURCE_DIRECTORY); - - for (int i = 0; i < crd->CountEntries(); i++) { - if (crd->GetEntry(i)->HasName()) - qStrings.push(crd->GetEntry(i)); - if (crd->GetEntry(i)->IsDataDirectory()) - qDirs.push(crd->GetEntry(i)->GetSubDirectory()); - else { - qDataEntries.push(crd->GetEntry(i)->GetDataEntry()); - qDataEntries2.push(crd->GetEntry(i)->GetDataEntry()); - } - - MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rDirE; - ZeroMemory(&rDirE, sizeof(rDirE)); - rDirE.UOffset.DirectoryOffset.DataIsDirectory = crd->GetEntry(i)->IsDataDirectory(); - rDirE.UName.Id = crd->GetEntry(i)->HasName() ? 0 : crd->GetEntry(i)->GetId(); - rDirE.UName.Id = ConvertEndianness(rDirE.UName.Id); - rDirE.UName.NameString.NameIsString = (crd->GetEntry(i)->HasName()) ? 1 : 0; - - CopyMemory(seeker, &rDirE, sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY)); - crd->GetEntry(i)->m_ulWrittenAt = (ULONG_PTR)(seeker); - seeker += sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY); - } - qDirs.pop(); - } - - /* - * Write IMAGE_RESOURCE_DATA_ENTRYs. - */ - while (!qDataEntries.empty()) { - CResourceDataEntry* cRDataE = qDataEntries.front(); - IMAGE_RESOURCE_DATA_ENTRY rDataE = {0,}; - rDataE.CodePage = ConvertEndianness(cRDataE->GetCodePage()); - rDataE.Size = ConvertEndianness(cRDataE->GetSize()); - - CopyMemory(seeker, &rDataE, sizeof(IMAGE_RESOURCE_DATA_ENTRY)); - cRDataE->m_ulWrittenAt = (ULONG_PTR)(seeker); - seeker += sizeof(IMAGE_RESOURCE_DATA_ENTRY); - - qDataEntries.pop(); - } - - /* - * Write strings - */ - while (!qStrings.empty()) { - CResourceDirectoryEntry* cRDirE = qStrings.front(); - - PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY(cRDirE->m_ulWrittenAt)->UName.NameString.NameOffset = ConvertEndianness((DWORD) (seeker - pbRsrcSec)); - - WCHAR* szName = cRDirE->GetName(); - WORD iLen = winchar_strlen(szName) + 1; - - *(WORD*)seeker = ConvertEndianness(iLen); - CopyMemory(seeker + sizeof(WORD), szName, iLen*sizeof(WCHAR)); - - seeker += RALIGN(iLen * sizeof(WCHAR) + sizeof(WORD), 4); - - delete [] szName; - - qStrings.pop(); - } - - /* - * Write raw resource data and set offsets in IMAGE_RESOURCE_DATA_ENTRYs. - */ - while (!qDataEntries2.empty()) { - CResourceDataEntry* cRDataE = qDataEntries2.front(); - CopyMemory(seeker, cRDataE->GetData(), cRDataE->GetSize()); - PIMAGE_RESOURCE_DATA_ENTRY(cRDataE->m_ulWrittenAt)->OffsetToData = ConvertEndianness((DWORD)(seeker - pbRsrcSec) + m_dwResourceSectionVA); - - seeker += RALIGN(cRDataE->GetSize(), 8); - - qDataEntries2.pop(); - } - - /* - * Set all of the directory entries offsets. - */ - SetOffsets(m_cResDir, (ULONG_PTR)(pbRsrcSec)); -} - -// Sets the offsets in directory entries -void CResourceEditor::SetOffsets(CResourceDirectory* resDir, ULONG_PTR newResDirAt) { - for (int i = 0; i < resDir->CountEntries(); i++) { - PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY rde = PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY(resDir->GetEntry(i)->m_ulWrittenAt); - if (resDir->GetEntry(i)->IsDataDirectory()) { - rde->UOffset.DirectoryOffset.DataIsDirectory = 1; - rde->UOffset.DirectoryOffset.OffsetToDirectory = resDir->GetEntry(i)->GetSubDirectory()->m_ulWrittenAt - newResDirAt; - rde->UOffset.OffsetToData = ConvertEndianness(rde->UOffset.OffsetToData); - SetOffsets(resDir->GetEntry(i)->GetSubDirectory(), newResDirAt); - } - else { - rde->UOffset.OffsetToData = ConvertEndianness((DWORD)(resDir->GetEntry(i)->GetDataEntry()->m_ulWrittenAt - newResDirAt)); - } - } -} - -// Adjusts a virtual address by a specific amount -DWORD CResourceEditor::AdjustVA(DWORD dwVirtualAddress, DWORD dwAdjustment) { - dwVirtualAddress = ConvertEndianness(dwVirtualAddress); - dwVirtualAddress += dwAdjustment; - dwVirtualAddress = ConvertEndianness(dwVirtualAddress); - - return dwVirtualAddress; -} - -// Aligns a virtual address to the section alignment -DWORD CResourceEditor::AlignVA(DWORD dwVirtualAddress) { - DWORD dwSectionAlignment = *GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, SectionAlignment); - DWORD dwAlignment = ConvertEndianness(dwSectionAlignment); - - dwVirtualAddress = ConvertEndianness(dwVirtualAddress); - dwVirtualAddress = RALIGN(dwVirtualAddress, dwAlignment); - dwVirtualAddress = ConvertEndianness(dwVirtualAddress); - - return dwVirtualAddress; -} - -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// CResourceDirectory -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResourceDirectory::CResourceDirectory(PIMAGE_RESOURCE_DIRECTORY prd) { - m_rdDir = *prd; - m_rdDir.NumberOfIdEntries = 0; - m_rdDir.NumberOfNamedEntries = 0; -} - -CResourceDirectory::~CResourceDirectory() { -} - -////////////////////////////////////////////////////////////////////// -// Methods -////////////////////////////////////////////////////////////////////// - -IMAGE_RESOURCE_DIRECTORY CResourceDirectory::GetInfo() { - return m_rdDir; -} - -CResourceDirectoryEntry* CResourceDirectory::GetEntry(unsigned int i) { - if (m_vEntries.size() < i) - return 0; - return m_vEntries[i]; -} - -// This function inserts a new directory entry -// It also keeps the directory entries sorted -void CResourceDirectory::AddEntry(CResourceDirectoryEntry* entry) { - int i = 0; - if (entry->HasName()) { - WCHAR* szEntName = entry->GetName(); - for (i = 0; i < m_rdDir.NumberOfNamedEntries; i++) { - WCHAR* szName = m_vEntries[i]->GetName(); - int cmp = winchar_strcmp(szName, szEntName); - delete [] szName; - if (cmp == 0) { - delete [] szEntName; - return; - } - if (cmp > 0) - break; - } - delete [] szEntName; - m_rdDir.NumberOfNamedEntries++; - } - else { - for (i = m_rdDir.NumberOfNamedEntries; i < m_rdDir.NumberOfNamedEntries+m_rdDir.NumberOfIdEntries; i++) { - if (m_vEntries[i]->GetId() == entry->GetId()) - return; - if (m_vEntries[i]->GetId() > entry->GetId()) - break; - } - m_rdDir.NumberOfIdEntries++; - } - m_vEntries.insert(m_vEntries.begin() + i, entry); -} - -void CResourceDirectory::RemoveEntry(int i) { - if (m_vEntries[i]->HasName()) - m_rdDir.NumberOfNamedEntries--; - else - m_rdDir.NumberOfIdEntries--; - delete m_vEntries[i]; - m_vEntries.erase(m_vEntries.begin() + i); -} - -int CResourceDirectory::CountEntries() { - return m_vEntries.size(); -} - -// Returns the index of a directory entry with the specified name -// Name can be a string or an id -// Returns -1 if can not be found -int CResourceDirectory::Find(WCHAR* szName) { - if (IS_INTRESOURCE(szName)) - return Find((WORD) (ULONG_PTR) szName); - else - if (szName[0] == L'#') - return Find(WORD(winchar_stoi(szName + 1))); - - for (unsigned int i = 0; i < m_vEntries.size(); i++) { - if (!m_vEntries[i]->HasName()) - continue; - - WCHAR* szEntName = m_vEntries[i]->GetName(); - int cmp = winchar_strcmp(szName, szEntName); - delete [] szEntName; - - if (!cmp) - return i; - } - - return -1; -} - -// Returns the index of a directory entry with the specified id -// Returns -1 if can not be found -int CResourceDirectory::Find(WORD wId) { - for (unsigned int i = 0; i < m_vEntries.size(); i++) { - if (m_vEntries[i]->HasName()) - continue; - - if (wId == m_vEntries[i]->GetId()) - return i; - } - - return -1; -} - -// Get the size of this resource directory (including all of its children) -DWORD CResourceDirectory::GetSize() { - DWORD dwSize = sizeof(IMAGE_RESOURCE_DIRECTORY); - for (unsigned int i = 0; i < m_vEntries.size(); i++) { - dwSize += sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY); - if (m_vEntries[i]->HasName()) - dwSize += sizeof(IMAGE_RESOURCE_DIR_STRING_U) + (m_vEntries[i]->GetNameLength()+1)*sizeof(WCHAR); - if (m_vEntries[i]->IsDataDirectory()) - dwSize += m_vEntries[i]->GetSubDirectory()->GetSize(); - else { - DWORD dwAligned = m_vEntries[i]->GetDataEntry()->GetSize(); - ALIGN(dwAligned, 8); - dwSize += sizeof(IMAGE_RESOURCE_DATA_ENTRY) + dwAligned; - } - } - return dwSize; -} - -// Destroys this directory and all of its children -void CResourceDirectory::Destroy() { - for (unsigned int i = 0; i < m_vEntries.size(); i++) { - if (m_vEntries[i]->IsDataDirectory()) { - m_vEntries[i]->GetSubDirectory()->Destroy(); - delete m_vEntries[i]->GetSubDirectory(); - } - else - delete m_vEntries[i]->GetDataEntry(); - } -} - -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// CResourceDirectoryEntry -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResourceDirectoryEntry::CResourceDirectoryEntry(WCHAR* szName, CResourceDirectory* rdSubDir) { - if (IS_INTRESOURCE(szName)) { - m_bHasName = false; - m_szName = 0; - m_wId = (WORD) (ULONG_PTR) szName; - } - else { - m_bHasName = true; - m_szName = winchar_strdup(szName); - } - m_bIsDataDirectory = true; - m_rdSubDir = rdSubDir; -} - -CResourceDirectoryEntry::CResourceDirectoryEntry(WCHAR* szName, CResourceDataEntry* rdeData) { - if (IS_INTRESOURCE(szName)) { - m_bHasName = false; - m_szName = 0; - m_wId = (WORD) (ULONG_PTR) szName; - } - else { - m_bHasName = true; - m_szName = winchar_strdup(szName); - } - m_bIsDataDirectory = false; - m_rdeData = rdeData; -} - -CResourceDirectoryEntry::~CResourceDirectoryEntry() { - if (m_szName && m_bHasName) - delete [] m_szName; -} - -////////////////////////////////////////////////////////////////////// -// Methods -////////////////////////////////////////////////////////////////////// - -bool CResourceDirectoryEntry::HasName() { - return m_bHasName; -} - -// Don't forget to free the memory used by the string after usage! -WCHAR* CResourceDirectoryEntry::GetName() { - if (!m_bHasName) - return 0; - return winchar_strdup(m_szName); -} - -int CResourceDirectoryEntry::GetNameLength() { - return winchar_strlen(m_szName); -} - -WORD CResourceDirectoryEntry::GetId() { - if (m_bHasName) - return 0; - return m_wId; -} - -bool CResourceDirectoryEntry::IsDataDirectory() { - return m_bIsDataDirectory; -} - -CResourceDirectory* CResourceDirectoryEntry::GetSubDirectory() { - if (!m_bIsDataDirectory) - return NULL; - return m_rdSubDir; -} - -CResourceDataEntry* CResourceDirectoryEntry::GetDataEntry() { - if (m_bIsDataDirectory) - return NULL; - return m_rdeData; -} - -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// CResourceDataEntry -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResourceDataEntry::CResourceDataEntry(BYTE* pbData, DWORD dwSize, DWORD dwCodePage, DWORD dwOffset) { - m_pbData = 0; - SetData(pbData, dwSize, dwCodePage); - m_dwOffset = dwOffset; -} - -CResourceDataEntry::~CResourceDataEntry() { - if (m_pbData) - delete [] m_pbData; -} - -////////////////////////////////////////////////////////////////////// -// Methods -////////////////////////////////////////////////////////////////////// - -// 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() { - return m_pbData; -} - -void CResourceDataEntry::SetData(BYTE* pbData, DWORD dwSize) { - SetData(pbData, dwSize, m_dwCodePage); -} - -void CResourceDataEntry::SetData(BYTE* pbData, DWORD dwSize, DWORD dwCodePage) { - if (m_pbData) delete [] m_pbData; - m_pbData = new BYTE[dwSize]; - CopyMemory(m_pbData, pbData, dwSize); - m_dwSize = dwSize; - m_dwCodePage = dwCodePage; - m_dwOffset = DWORD(-1); // unset -} - -DWORD CResourceDataEntry::GetSize() { - return m_dwSize; -} - -DWORD CResourceDataEntry::GetCodePage() { - return m_dwCodePage; -} - -DWORD CResourceDataEntry::GetOffset() { - return m_dwOffset; -} +/* + * ResourceEditor.cpp + * + * This file is a part of NSIS. + * + * Copyright (C) 2002-2009 Amir Szekely + * + * Licensed under the zlib/libpng license (the "License"); + * you may not use this file except in compliance with the License. + * + * Licence details can be found in the file COPYING. + * + * This software is provided 'as-is', without any express or implied + * warranty. + * + * Reviewed for Unicode support by Jim Park -- 08/21/2007 + */ + +#include "ResourceEditor.h" +#include "util.h" +#include "winchar.h" +#include +#include "tchar.h" +using namespace std; + +////////////////////////////////////////////////////////////////////// +// Utilities +////////////////////////////////////////////////////////////////////// + +#define ALIGN(dwToAlign, dwAlignOn) dwToAlign = (dwToAlign%dwAlignOn == 0) ? dwToAlign : dwToAlign - (dwToAlign%dwAlignOn) + dwAlignOn +#define RALIGN(dwToAlign, dwAlignOn) ((dwToAlign%dwAlignOn == 0) ? dwToAlign : dwToAlign - (dwToAlign%dwAlignOn) + dwAlignOn) + +static inline DWORD ConvertEndianness(DWORD d) { + return FIX_ENDIAN_INT32(d); +} + +static inline WORD ConvertEndianness(WORD w) { + return FIX_ENDIAN_INT16(w); +} + +PIMAGE_NT_HEADERS CResourceEditor::GetNTHeaders(BYTE* pbPE) { + // Get dos header + PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) pbPE; + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) + throw runtime_error("PE file contains invalid DOS header"); + + // Get NT headers + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(pbPE + ConvertEndianness((DWORD)dosHeader->e_lfanew)); + if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) + throw runtime_error("PE file missing NT signature"); + + // Make sure this is a supported PE format + if (ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && + ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) + throw runtime_error("Unsupported PE format"); + + return ntHeaders; +} + +PRESOURCE_DIRECTORY CResourceEditor::GetResourceDirectory( + BYTE* pbPE, + DWORD dwSize, + PIMAGE_NT_HEADERS ntHeaders, + DWORD *pdwResSecVA /*=NULL*/, + DWORD *pdwSectionIndex /*=NULL*/ +) { + PIMAGE_DATA_DIRECTORY dataDirectory = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory); + DWORD dwNumberOfRvaAndSizes = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, NumberOfRvaAndSizes); + + if (ConvertEndianness(dwNumberOfRvaAndSizes) <= IMAGE_DIRECTORY_ENTRY_RESOURCE) + throw runtime_error("No resource section found"); + // Get resource section virtual address + DWORD dwResSecVA = ConvertEndianness(dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); + // Pointer to the sections headers array + PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(ntHeaders); + + DWORD dwSectionIndex = (DWORD) -1; + + // Find resource section index in the array + for (int i = 0; i < ConvertEndianness(ntHeaders->FileHeader.NumberOfSections); i++) { + if (dwResSecVA == ConvertEndianness(sectionHeadersArray[i].VirtualAddress)) { + // Remember resource section index + dwSectionIndex = i; + // Check for invalid resource section pointer + if (!sectionHeadersArray[i].PointerToRawData) + throw runtime_error("Invalid resource section pointer"); + + break; + } + + // Invalid section pointer (goes beyond the PE image) + if (ConvertEndianness(sectionHeadersArray[i].PointerToRawData) > dwSize) + throw runtime_error("Invalid section pointer"); + } + + // No resource section... + if (dwSectionIndex == (DWORD) -1) + throw runtime_error("PE file doesn't contain any resource section"); + + // Return extra parameters + if (pdwSectionIndex) + *pdwSectionIndex = dwSectionIndex; + if (pdwResSecVA) + *pdwResSecVA = dwResSecVA; + + // Pointer to section data, the first resource directory + DWORD dwResSecPtr = ConvertEndianness(sectionHeadersArray[dwSectionIndex].PointerToRawData); + return PRESOURCE_DIRECTORY(pbPE + dwResSecPtr); +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// CResourceEditor +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResourceEditor::CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData /*=true*/) { + // Copy the data pointer + m_pbPE = pbPE; + m_iSize = iSize; + m_bKeepData = bKeepData; + + // Get NT headers + m_ntHeaders = GetNTHeaders(m_pbPE); + + // No check sum support yet... + DWORD* pdwCheckSum = GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, CheckSum); + if (*pdwCheckSum) + { + // clear checksum (should be [re]calculated after all changes done) + pdwCheckSum = 0; + //throw runtime_error("CResourceEditor doesn't yet support check sum"); + } + + // Get resource section virtual address, resource section index and pointer to resource directory + PRESOURCE_DIRECTORY rdRoot = GetResourceDirectory(m_pbPE, iSize, m_ntHeaders, &m_dwResourceSectionVA, &m_dwResourceSectionIndex); + + // Scan the resource directory + m_cResDir = ScanDirectory(rdRoot, rdRoot); +} + +CResourceEditor::~CResourceEditor() { + if (m_cResDir) { + m_cResDir->Destroy(); + delete m_cResDir; + } +} + +////////////////////////////////////////////////////////////////////// +// Methods +////////////////////////////////////////////////////////////////////// + +// Adds/Replaces/Removes a resource. +// If lpData is 0 UpdateResource removes the resource. +bool CResourceEditor::UpdateResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { + CResourceDirectory* nameDir = 0; + CResourceDirectory* langDir = 0; + CResourceDataEntry* data = 0; + IMAGE_RESOURCE_DIRECTORY rd = {0, /*time(0),*/}; + int iTypeIdx = -1, iNameIdx = -1, iLangIdx = -1; + + iTypeIdx = m_cResDir->Find(szType); + if (iTypeIdx > -1) { + nameDir = m_cResDir->GetEntry(iTypeIdx)->GetSubDirectory(); + iNameIdx = nameDir->Find(szName); + if (iNameIdx > -1) { + langDir = nameDir->GetEntry(iNameIdx)->GetSubDirectory(); + iLangIdx = langDir->Find(wLanguage); + if (iLangIdx > -1) { + data = langDir->GetEntry(iLangIdx)->GetDataEntry(); + } + } + } + + if (lpData) { + // Replace/Add the resource + if (data) { + data->SetData(lpData, dwSize); + return true; + } + + if (!nameDir) { + // Type doesn't yet exist + nameDir = new CResourceDirectory(&rd); + m_cResDir->AddEntry(new CResourceDirectoryEntry(szType, nameDir)); + } + if (!langDir) { + // Name doesn't yet exist + langDir = new CResourceDirectory(&rd); + nameDir->AddEntry(new CResourceDirectoryEntry(szName, langDir)); + } + if (!data) { + // Language doesn't yet exist, hence data nither + data = new CResourceDataEntry(lpData, dwSize); + langDir->AddEntry(new CResourceDirectoryEntry(MAKEINTRESOURCEW(wLanguage), data)); + } + } + else if (data) { + // Delete the resource + delete data; + langDir->RemoveEntry(iLangIdx); + // Delete directories holding the resource if empty + if (!langDir->CountEntries()) { + delete langDir; + nameDir->RemoveEntry(iNameIdx); + if (!nameDir->CountEntries()) { + delete nameDir; + m_cResDir->RemoveEntry(iTypeIdx); + } + } + } + else return false; + return true; +} + +#ifndef _UNICODE +static WCHAR* ResStringToUnicode(const char *szString) { + if (IS_INTRESOURCE(szString)) + return MAKEINTRESOURCEW((ULONG_PTR)szString); + else + return winchar_fromTchar(szString); +} +#endif + +static void FreeUnicodeResString(WCHAR* szwString) { + if (!IS_INTRESOURCE(szwString)) + delete [] szwString; +} + + +bool CResourceEditor::UpdateResource(TCHAR* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { +#ifdef _UNICODE + return UpdateResourceW(szType, MAKEINTRESOURCEW(szName), wLanguage, lpData, dwSize); +#else + WCHAR* szwType = ResStringToUnicode(szType); + bool result = UpdateResourceW(szwType, MAKEINTRESOURCEW(szName), wLanguage, lpData, dwSize); + FreeUnicodeResString(szwType); + return result; +#endif +} + +// Returns a copy of the requested resource +// Returns 0 if the requested resource can't be found +BYTE* CResourceEditor::GetResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage) { + if (!m_bKeepData) + throw runtime_error("Can't GetResource() when bKeepData is false"); + + CResourceDirectory* nameDir = 0; + CResourceDirectory* langDir = 0; + CResourceDataEntry* data = 0; + + int i = m_cResDir->Find(szType); + if (i > -1) { + nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); + i = nameDir->Find(szName); + if (i > -1) { + langDir = nameDir->GetEntry(i)->GetSubDirectory(); + i = 0; + if (wLanguage) + i = langDir->Find(wLanguage); + if (i > -1) { + data = langDir->GetEntry(i)->GetDataEntry(); + } + } + } + + if (data) { + BYTE* toReturn = new BYTE[data->GetSize()]; + CopyMemory(toReturn, data->GetData(), data->GetSize()); + return toReturn; + } + else + return NULL; +} + +BYTE* CResourceEditor::GetResource(TCHAR* szType, WORD szName, LANGID wLanguage) { +#ifdef _UNICODE + return GetResourceW(szType, MAKEINTRESOURCEW(szName), wLanguage); +#else + WCHAR* szwType = ResStringToUnicode(szType); + BYTE* result = GetResourceW(szwType, MAKEINTRESOURCEW(szName), wLanguage); + FreeUnicodeResString(szwType); + return result; +#endif +} + +// Returns the size of the requested resource +// Returns -1 if the requested resource can't be found +int CResourceEditor::GetResourceSizeW(WCHAR* szType, WCHAR* szName, LANGID wLanguage) { + CResourceDirectory* nameDir = 0; + CResourceDirectory* langDir = 0; + CResourceDataEntry* data = 0; + + int i = m_cResDir->Find(szType); + if (i > -1) { + nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); + i = nameDir->Find(szName); + if (i > -1) { + langDir = nameDir->GetEntry(i)->GetSubDirectory(); + i = 0; + if (wLanguage) + i = langDir->Find(wLanguage); + if (i > -1) { + data = langDir->GetEntry(i)->GetDataEntry(); + } + } + } + + if (data) + return (int) data->GetSize(); + else + return -1; +} + +int CResourceEditor::GetResourceSize(TCHAR* szType, WORD szName, LANGID wLanguage) { +#ifdef _UNICODE + return GetResourceSizeW(szType, MAKEINTRESOURCEW(szName), wLanguage); +#else + WCHAR* szwType = ResStringToUnicode(szType); + int result = GetResourceSizeW(szwType, MAKEINTRESOURCEW(szName), wLanguage); + FreeUnicodeResString(szwType); + return result; +#endif +} + +// Returns the offset of the requested resource in the original PE +// Returns -1 if the requested resource can't be found +DWORD CResourceEditor::GetResourceOffsetW(WCHAR* szType, WCHAR* szName, LANGID wLanguage) { + CResourceDirectory* nameDir = 0; + CResourceDirectory* langDir = 0; + CResourceDataEntry* data = 0; + + int i = m_cResDir->Find(szType); + if (i > -1) { + nameDir = m_cResDir->GetEntry(i)->GetSubDirectory(); + i = nameDir->Find(szName); + if (i > -1) { + langDir = nameDir->GetEntry(i)->GetSubDirectory(); + i = 0; + if (wLanguage) + i = langDir->Find(wLanguage); + if (i > -1) { + data = langDir->GetEntry(i)->GetDataEntry(); + } + } + } + + if (data) + return data->GetOffset(); + else + return DWORD(-1); +} + +DWORD CResourceEditor::GetResourceOffset(TCHAR* szType, WORD szName, LANGID wLanguage) { +#ifdef _UNICODE + return GetResourceOffsetW(szType, MAKEINTRESOURCEW(szName), wLanguage); +#else + WCHAR* szwType = ResStringToUnicode(szType); + DWORD result = GetResourceOffsetW(szwType, MAKEINTRESOURCEW(szName), wLanguage); + FreeUnicodeResString(szwType); + return result; +#endif +} + +void CResourceEditor::FreeResource(BYTE* pbResource) +{ + if (pbResource) + delete [] pbResource; +} + +// Saves the edited PE into a buffer and returns it. +DWORD CResourceEditor::Save(BYTE* pbBuf, DWORD &dwSize) { + if (!m_bKeepData) + throw runtime_error("Can't Save() when bKeepData is false"); + + unsigned int i; + DWORD dwReqSize; + + DWORD dwFileAlign = ConvertEndianness(m_ntHeaders->OptionalHeader.FileAlignment); + DWORD dwSecAlign = ConvertEndianness(m_ntHeaders->OptionalHeader.SectionAlignment); + + DWORD dwRsrcSize = m_cResDir->GetSize(); // Size of new resource section + DWORD dwRsrcSizeAligned = RALIGN(dwRsrcSize, dwFileAlign); // Align it to FileAlignment + + // Calculate the total new PE size + DWORD dwOldRsrcSize = ConvertEndianness(IMAGE_FIRST_SECTION(m_ntHeaders)[m_dwResourceSectionIndex].SizeOfRawData); + dwReqSize = m_iSize - dwOldRsrcSize + dwRsrcSizeAligned; + + if (!pbBuf || dwSize < dwReqSize) + return dwReqSize; + + // Use buffer + BYTE* pbNewPE = pbBuf; + dwSize = dwReqSize; + // Fill buffer with zeros + ZeroMemory(pbNewPE, dwSize); + + BYTE* seeker = pbNewPE; + BYTE* oldSeeker = m_pbPE; + + PIMAGE_SECTION_HEADER old_sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders); + + DWORD dwHeaderSize = ConvertEndianness(old_sectionHeadersArray[m_dwResourceSectionIndex].PointerToRawData); + WORD wNumberOfSections = ConvertEndianness(m_ntHeaders->FileHeader.NumberOfSections); + + // Copy everything until the resource section (including headers and everything that might come after them) + // We don't use SizeOfHeaders because sometimes (using VC6) it can extend beyond the first section + // or (Borland) there could be some more information between the headers and the first section. + CopyMemory(seeker, oldSeeker, dwHeaderSize); + + // Skip the headers and whatever comes after them + seeker += dwHeaderSize; + oldSeeker += dwHeaderSize; + + // Get new nt headers pointer + PIMAGE_NT_HEADERS ntHeaders = GetNTHeaders(pbNewPE); + // Get a pointer to the new section headers + PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(ntHeaders); + + // Skip the resource section in the old PE seeker. + oldSeeker += dwOldRsrcSize; + + // Save the old virtual size of the resource section + DWORD dwNewVirtualSize = RALIGN(dwRsrcSize, dwSecAlign); + DWORD dwOldVirtualSize = ConvertEndianness(sectionHeadersArray[m_dwResourceSectionIndex].Misc.VirtualSize); + ALIGN(dwOldVirtualSize, dwSecAlign); + DWORD dwVAAdjustment = dwNewVirtualSize - dwOldVirtualSize; + + // Set the new size of the resource section (size aligned to FileAlignment) + sectionHeadersArray[m_dwResourceSectionIndex].SizeOfRawData = ConvertEndianness(dwRsrcSizeAligned); + // Set the virtual size as well (in memory) + sectionHeadersArray[m_dwResourceSectionIndex].Misc.VirtualSize = ConvertEndianness(dwRsrcSize); + (*GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory))[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = ConvertEndianness(dwRsrcSize); + + // Set the new virtual size of the image + DWORD* pdwSizeOfImage = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, SizeOfImage); + *pdwSizeOfImage = AlignVA(*GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, SizeOfHeaders)); + for (i = 0; i < wNumberOfSections; i++) { + DWORD dwSecSize = ConvertEndianness(sectionHeadersArray[i].Misc.VirtualSize); + *pdwSizeOfImage = AlignVA(AdjustVA(*pdwSizeOfImage, dwSecSize)); + } + + // Set the new AddressOfEntryPoint if needed + DWORD* pdwAddressOfEntryPoint = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, AddressOfEntryPoint); + if (ConvertEndianness(*pdwAddressOfEntryPoint) > m_dwResourceSectionVA) + *pdwAddressOfEntryPoint = AdjustVA(*pdwAddressOfEntryPoint, dwVAAdjustment); + + // Set the new BaseOfCode if needed + DWORD* pdwBaseOfCode = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, BaseOfCode); + if (ConvertEndianness(*pdwBaseOfCode) > m_dwResourceSectionVA) + *pdwBaseOfCode = AdjustVA(*pdwBaseOfCode, dwVAAdjustment); + + // Set the new BaseOfData if needed + if (ntHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + DWORD* pdwBaseOfData = &((PIMAGE_OPTIONAL_HEADER32)&ntHeaders->OptionalHeader)->BaseOfData; + if (ConvertEndianness(*pdwBaseOfData) > m_dwResourceSectionVA) + *pdwBaseOfData = AdjustVA(*pdwBaseOfData, dwVAAdjustment); + } + + // Refresh the headers of the sections that come after the resource section, and the data directory + DWORD dwNumberOfRvaAndSizes = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, NumberOfRvaAndSizes); + PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory); + for (i = m_dwResourceSectionIndex + 1; i < wNumberOfSections; i++) { + if (sectionHeadersArray[i].PointerToRawData) { + AdjustVA(sectionHeadersArray[i].PointerToRawData, dwRsrcSizeAligned - dwOldRsrcSize); + } + + // We must find the right data directory entry before we change the virtual address + unsigned int uDataDirIdx = 0; + for (unsigned int j = 0; j < ConvertEndianness(dwNumberOfRvaAndSizes); j++) + if (pDataDirectory[j].VirtualAddress == sectionHeadersArray[i].VirtualAddress) + uDataDirIdx = j; + + sectionHeadersArray[i].VirtualAddress = AdjustVA(sectionHeadersArray[i].VirtualAddress, dwVAAdjustment); + + // Change the virtual address in the data directory too + if (uDataDirIdx) + pDataDirectory[uDataDirIdx].VirtualAddress = sectionHeadersArray[i].VirtualAddress; + } + + // Write the resource section + WriteRsrcSec(seeker); + // Advance the pointer + seeker += dwRsrcSizeAligned; + + // Copy everything that comes after the resource section (other sections and tacked data) + DWORD dwLeft = m_iSize - (oldSeeker - m_pbPE); + if (dwLeft) + CopyMemory(seeker, oldSeeker, dwLeft); + + seeker += dwLeft; + oldSeeker += dwLeft; + + /********************************************************** + * To add checksum to the header use MapFileAndCheckSum + **********************************************************/ + + // From now on, we are working on the new PE + // Freeing the old PE memory is up to the user + m_pbPE = pbNewPE; + m_iSize = dwSize; + m_ntHeaders = ntHeaders; + // We just wrote the resource section according to m_cResDir, so we don't need to rescan + // m_dwResourceSectionIndex and m_dwResourceSectionVA have also been left unchanged as + // we didn't move the resources section + + return 0; +} + +// This function scans exe sections and after find a match with given name +// increments it's virtual size (auto fixes image size based on section alignment, etc) +// Jim Park: The section name must be ASCII code. Do not TCHAR this stuff. +bool CResourceEditor::AddExtraVirtualSize2PESection(const char* pszSectionName, int addsize) +{ + PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders); + + // Refresh the headers of the sections that come after the resource section, and the data directory + for (int i = 0; i < ConvertEndianness(m_ntHeaders->FileHeader.NumberOfSections); i++) { + if (!strcmp((LPCSTR)sectionHeadersArray[i].Name, pszSectionName)) { + sectionHeadersArray[i].Misc.VirtualSize = AlignVA(AdjustVA(sectionHeadersArray[i].Misc.VirtualSize, addsize)); + + sectionHeadersArray[i].Characteristics &= ConvertEndianness((DWORD) ~IMAGE_SCN_MEM_DISCARDABLE); + + // now fix any section after + for (int k = i + 1; k < ConvertEndianness(m_ntHeaders->FileHeader.NumberOfSections); k++, i++) { + DWORD dwLastSecVA = ConvertEndianness(sectionHeadersArray[i].VirtualAddress); + DWORD dwLastSecSize = ConvertEndianness(sectionHeadersArray[i].Misc.VirtualSize); + DWORD dwSecVA = AlignVA(ConvertEndianness(dwLastSecVA + dwLastSecSize)); + + sectionHeadersArray[k].VirtualAddress = dwSecVA; + + if (m_dwResourceSectionIndex == (DWORD) k) + { + // fix the resources virtual address if it changed + PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, DataDirectory); + pDataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = dwSecVA; + m_dwResourceSectionVA = ConvertEndianness(dwSecVA); + } + } + + return true; + } + } + + return false; +} + +////////////////////////////////////////////////////////////////////// +// Private Methods +////////////////////////////////////////////////////////////////////// + +// This function scans a give resource directory and return a CResourceDirectory object +// rdRoot must point to the root directory of the resource section +CResourceDirectory* CResourceEditor::ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan) { + // Create CResourceDirectory from rdToScan + CResourceDirectory* rdc = new CResourceDirectory(PIMAGE_RESOURCE_DIRECTORY(rdToScan)); + WCHAR* szName; + PIMAGE_RESOURCE_DATA_ENTRY rde = NULL; + + // Go through all entries of this resource directory + int entries = ConvertEndianness(rdToScan->Header.NumberOfNamedEntries); + entries += ConvertEndianness(rdToScan->Header.NumberOfIdEntries); + + for (int i = 0; i < entries; i++) { + MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rd = rdToScan->Entries[i]; + rd.UOffset.OffsetToData = ConvertEndianness(rd.UOffset.OffsetToData); + rd.UName.Name = ConvertEndianness(rd.UName.Name); + + // If this entry points to data entry get a pointer to it + if (!rd.UOffset.DirectoryOffset.DataIsDirectory) + rde = PIMAGE_RESOURCE_DATA_ENTRY(rd.UOffset.OffsetToData + (BYTE*)rdRoot); + + // If this entry has a name, translate it from Unicode + if (rd.UName.NameString.NameIsString) { + PIMAGE_RESOURCE_DIR_STRING_U rds = PIMAGE_RESOURCE_DIR_STRING_U(rd.UName.NameString.NameOffset + (char*)rdRoot); + + size_t nameSize = ConvertEndianness(rds->Length); + szName = new WCHAR[nameSize+1]; + winchar_strncpy(szName, rds->NameString, nameSize); + szName[nameSize] = 0; + } + // Else, set the name to this entry's id + else + szName = MAKEINTRESOURCEW(ConvertEndianness(rdToScan->Entries[i].UName.Id)); + + if (rd.UOffset.DirectoryOffset.DataIsDirectory) + { + rdc->AddEntry( + new CResourceDirectoryEntry( + szName, + ScanDirectory( + rdRoot, + PRESOURCE_DIRECTORY(rd.UOffset.DirectoryOffset.OffsetToDirectory + (LPBYTE)rdRoot) + ) + ) + ); + } + else + { + LPBYTE pbData = (LPBYTE)rdRoot + ConvertEndianness(rde->OffsetToData) - m_dwResourceSectionVA; + DWORD dwOffset = DWORD(pbData - m_pbPE); + + if (m_bKeepData) + { + if (dwOffset > DWORD(m_iSize)) + { + throw runtime_error("Invalid resource entry data pointer, possibly compressed resources"); + } + } + else + { + pbData = m_pbPE; // dummy pointer to "nothing" + } + + rdc->AddEntry( + new CResourceDirectoryEntry( + szName, + new CResourceDataEntry( + pbData, + ConvertEndianness(rde->Size), + ConvertEndianness(rde->CodePage), + dwOffset + ) + ) + ); + } + + // Delete the dynamicly allocated name if it is a name and not an id + if (!IS_INTRESOURCE(szName)) + delete [] szName; + } + + return rdc; +} + +// This function writes into a given place in memory (pbRsrcSec) the edited resource section +void CResourceEditor::WriteRsrcSec(BYTE* pbRsrcSec) { + BYTE* seeker = pbRsrcSec; + + queue qDirs; // Used to scan the tree by level + queue qDataEntries; // Used for writing the data entries + queue qDataEntries2; // Used for writing raw resources data + queue qStrings; // Used for writing resources' names + + qDirs.push(m_cResDir); + + while (!qDirs.empty()) { + CResourceDirectory* crd = qDirs.front(); + + IMAGE_RESOURCE_DIRECTORY rdDir = crd->GetInfo(); + + rdDir.NumberOfNamedEntries = ConvertEndianness(rdDir.NumberOfNamedEntries); + rdDir.NumberOfIdEntries = ConvertEndianness(rdDir.NumberOfIdEntries); + + CopyMemory(seeker, &rdDir, sizeof(IMAGE_RESOURCE_DIRECTORY)); + crd->m_ulWrittenAt = (ULONG_PTR)(seeker); + seeker += sizeof(IMAGE_RESOURCE_DIRECTORY); + + for (int i = 0; i < crd->CountEntries(); i++) { + if (crd->GetEntry(i)->HasName()) + qStrings.push(crd->GetEntry(i)); + if (crd->GetEntry(i)->IsDataDirectory()) + qDirs.push(crd->GetEntry(i)->GetSubDirectory()); + else { + qDataEntries.push(crd->GetEntry(i)->GetDataEntry()); + qDataEntries2.push(crd->GetEntry(i)->GetDataEntry()); + } + + MY_IMAGE_RESOURCE_DIRECTORY_ENTRY rDirE; + ZeroMemory(&rDirE, sizeof(rDirE)); + rDirE.UOffset.DirectoryOffset.DataIsDirectory = crd->GetEntry(i)->IsDataDirectory(); + rDirE.UName.Id = crd->GetEntry(i)->HasName() ? 0 : crd->GetEntry(i)->GetId(); + rDirE.UName.Id = ConvertEndianness(rDirE.UName.Id); + rDirE.UName.NameString.NameIsString = (crd->GetEntry(i)->HasName()) ? 1 : 0; + + CopyMemory(seeker, &rDirE, sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY)); + crd->GetEntry(i)->m_ulWrittenAt = (ULONG_PTR)(seeker); + seeker += sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY); + } + qDirs.pop(); + } + + /* + * Write IMAGE_RESOURCE_DATA_ENTRYs. + */ + while (!qDataEntries.empty()) { + CResourceDataEntry* cRDataE = qDataEntries.front(); + IMAGE_RESOURCE_DATA_ENTRY rDataE = {0,}; + rDataE.CodePage = ConvertEndianness(cRDataE->GetCodePage()); + rDataE.Size = ConvertEndianness(cRDataE->GetSize()); + + CopyMemory(seeker, &rDataE, sizeof(IMAGE_RESOURCE_DATA_ENTRY)); + cRDataE->m_ulWrittenAt = (ULONG_PTR)(seeker); + seeker += sizeof(IMAGE_RESOURCE_DATA_ENTRY); + + qDataEntries.pop(); + } + + /* + * Write strings + */ + while (!qStrings.empty()) { + CResourceDirectoryEntry* cRDirE = qStrings.front(); + + PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY(cRDirE->m_ulWrittenAt)->UName.NameString.NameOffset = ConvertEndianness((DWORD) (seeker - pbRsrcSec)); + + WCHAR* szName = cRDirE->GetName(); + WORD iLen = winchar_strlen(szName) + 1; + + *(WORD*)seeker = ConvertEndianness(iLen); + CopyMemory(seeker + sizeof(WORD), szName, iLen*sizeof(WCHAR)); + + seeker += RALIGN(iLen * sizeof(WCHAR) + sizeof(WORD), 4); + + delete [] szName; + + qStrings.pop(); + } + + /* + * Write raw resource data and set offsets in IMAGE_RESOURCE_DATA_ENTRYs. + */ + while (!qDataEntries2.empty()) { + CResourceDataEntry* cRDataE = qDataEntries2.front(); + CopyMemory(seeker, cRDataE->GetData(), cRDataE->GetSize()); + PIMAGE_RESOURCE_DATA_ENTRY(cRDataE->m_ulWrittenAt)->OffsetToData = ConvertEndianness((DWORD)(seeker - pbRsrcSec) + m_dwResourceSectionVA); + + seeker += RALIGN(cRDataE->GetSize(), 8); + + qDataEntries2.pop(); + } + + /* + * Set all of the directory entries offsets. + */ + SetOffsets(m_cResDir, (ULONG_PTR)(pbRsrcSec)); +} + +// Sets the offsets in directory entries +void CResourceEditor::SetOffsets(CResourceDirectory* resDir, ULONG_PTR newResDirAt) { + for (int i = 0; i < resDir->CountEntries(); i++) { + PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY rde = PMY_IMAGE_RESOURCE_DIRECTORY_ENTRY(resDir->GetEntry(i)->m_ulWrittenAt); + if (resDir->GetEntry(i)->IsDataDirectory()) { + rde->UOffset.DirectoryOffset.DataIsDirectory = 1; + rde->UOffset.DirectoryOffset.OffsetToDirectory = resDir->GetEntry(i)->GetSubDirectory()->m_ulWrittenAt - newResDirAt; + rde->UOffset.OffsetToData = ConvertEndianness(rde->UOffset.OffsetToData); + SetOffsets(resDir->GetEntry(i)->GetSubDirectory(), newResDirAt); + } + else { + rde->UOffset.OffsetToData = ConvertEndianness((DWORD)(resDir->GetEntry(i)->GetDataEntry()->m_ulWrittenAt - newResDirAt)); + } + } +} + +// Adjusts a virtual address by a specific amount +DWORD CResourceEditor::AdjustVA(DWORD dwVirtualAddress, DWORD dwAdjustment) { + dwVirtualAddress = ConvertEndianness(dwVirtualAddress); + dwVirtualAddress += dwAdjustment; + dwVirtualAddress = ConvertEndianness(dwVirtualAddress); + + return dwVirtualAddress; +} + +// Aligns a virtual address to the section alignment +DWORD CResourceEditor::AlignVA(DWORD dwVirtualAddress) { + DWORD dwSectionAlignment = *GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, SectionAlignment); + DWORD dwAlignment = ConvertEndianness(dwSectionAlignment); + + dwVirtualAddress = ConvertEndianness(dwVirtualAddress); + dwVirtualAddress = RALIGN(dwVirtualAddress, dwAlignment); + dwVirtualAddress = ConvertEndianness(dwVirtualAddress); + + return dwVirtualAddress; +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// CResourceDirectory +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResourceDirectory::CResourceDirectory(PIMAGE_RESOURCE_DIRECTORY prd) { + m_rdDir = *prd; + m_rdDir.NumberOfIdEntries = 0; + m_rdDir.NumberOfNamedEntries = 0; +} + +CResourceDirectory::~CResourceDirectory() { +} + +////////////////////////////////////////////////////////////////////// +// Methods +////////////////////////////////////////////////////////////////////// + +IMAGE_RESOURCE_DIRECTORY CResourceDirectory::GetInfo() { + return m_rdDir; +} + +CResourceDirectoryEntry* CResourceDirectory::GetEntry(unsigned int i) { + if (m_vEntries.size() < i) + return 0; + return m_vEntries[i]; +} + +// This function inserts a new directory entry +// It also keeps the directory entries sorted +void CResourceDirectory::AddEntry(CResourceDirectoryEntry* entry) { + int i = 0; + if (entry->HasName()) { + WCHAR* szEntName = entry->GetName(); + for (i = 0; i < m_rdDir.NumberOfNamedEntries; i++) { + WCHAR* szName = m_vEntries[i]->GetName(); + int cmp = winchar_strcmp(szName, szEntName); + delete [] szName; + if (cmp == 0) { + delete [] szEntName; + return; + } + if (cmp > 0) + break; + } + delete [] szEntName; + m_rdDir.NumberOfNamedEntries++; + } + else { + for (i = m_rdDir.NumberOfNamedEntries; i < m_rdDir.NumberOfNamedEntries+m_rdDir.NumberOfIdEntries; i++) { + if (m_vEntries[i]->GetId() == entry->GetId()) + return; + if (m_vEntries[i]->GetId() > entry->GetId()) + break; + } + m_rdDir.NumberOfIdEntries++; + } + m_vEntries.insert(m_vEntries.begin() + i, entry); +} + +void CResourceDirectory::RemoveEntry(int i) { + if (m_vEntries[i]->HasName()) + m_rdDir.NumberOfNamedEntries--; + else + m_rdDir.NumberOfIdEntries--; + delete m_vEntries[i]; + m_vEntries.erase(m_vEntries.begin() + i); +} + +int CResourceDirectory::CountEntries() { + return m_vEntries.size(); +} + +// Returns the index of a directory entry with the specified name +// Name can be a string or an id +// Returns -1 if can not be found +int CResourceDirectory::Find(WCHAR* szName) { + if (IS_INTRESOURCE(szName)) + return Find((WORD) (ULONG_PTR) szName); + else + if (szName[0] == L'#') + return Find(WORD(_wtoi(szName + 1))); + + for (unsigned int i = 0; i < m_vEntries.size(); i++) { + if (!m_vEntries[i]->HasName()) + continue; + + WCHAR* szEntName = m_vEntries[i]->GetName(); + int cmp = winchar_strcmp(szName, szEntName); + delete [] szEntName; + + if (!cmp) + return i; + } + + return -1; +} + +// Returns the index of a directory entry with the specified id +// Returns -1 if can not be found +int CResourceDirectory::Find(WORD wId) { + for (unsigned int i = 0; i < m_vEntries.size(); i++) { + if (m_vEntries[i]->HasName()) + continue; + + if (wId == m_vEntries[i]->GetId()) + return i; + } + + return -1; +} + +// Get the size of this resource directory (including all of its children) +DWORD CResourceDirectory::GetSize() { + DWORD dwSize = sizeof(IMAGE_RESOURCE_DIRECTORY); + for (unsigned int i = 0; i < m_vEntries.size(); i++) { + dwSize += sizeof(MY_IMAGE_RESOURCE_DIRECTORY_ENTRY); + if (m_vEntries[i]->HasName()) + dwSize += sizeof(IMAGE_RESOURCE_DIR_STRING_U) + (m_vEntries[i]->GetNameLength()+1)*sizeof(WCHAR); + if (m_vEntries[i]->IsDataDirectory()) + dwSize += m_vEntries[i]->GetSubDirectory()->GetSize(); + else { + DWORD dwAligned = m_vEntries[i]->GetDataEntry()->GetSize(); + ALIGN(dwAligned, 8); + dwSize += sizeof(IMAGE_RESOURCE_DATA_ENTRY) + dwAligned; + } + } + return dwSize; +} + +// Destroys this directory and all of its children +void CResourceDirectory::Destroy() { + for (unsigned int i = 0; i < m_vEntries.size(); i++) { + if (m_vEntries[i]->IsDataDirectory()) { + m_vEntries[i]->GetSubDirectory()->Destroy(); + delete m_vEntries[i]->GetSubDirectory(); + } + else + delete m_vEntries[i]->GetDataEntry(); + } +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// CResourceDirectoryEntry +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResourceDirectoryEntry::CResourceDirectoryEntry(WCHAR* szName, CResourceDirectory* rdSubDir) { + if (IS_INTRESOURCE(szName)) { + m_bHasName = false; + m_szName = 0; + m_wId = (WORD) (ULONG_PTR) szName; + } + else { + m_bHasName = true; + m_szName = winchar_strdup(szName); + } + m_bIsDataDirectory = true; + m_rdSubDir = rdSubDir; +} + +CResourceDirectoryEntry::CResourceDirectoryEntry(WCHAR* szName, CResourceDataEntry* rdeData) { + if (IS_INTRESOURCE(szName)) { + m_bHasName = false; + m_szName = 0; + m_wId = (WORD) (ULONG_PTR) szName; + } + else { + m_bHasName = true; + m_szName = winchar_strdup(szName); + } + m_bIsDataDirectory = false; + m_rdeData = rdeData; +} + +CResourceDirectoryEntry::~CResourceDirectoryEntry() { + if (m_szName && m_bHasName) + delete [] m_szName; +} + +////////////////////////////////////////////////////////////////////// +// Methods +////////////////////////////////////////////////////////////////////// + +bool CResourceDirectoryEntry::HasName() { + return m_bHasName; +} + +// Don't forget to free the memory used by the string after usage! +WCHAR* CResourceDirectoryEntry::GetName() { + if (!m_bHasName) + return 0; + return winchar_strdup(m_szName); +} + +int CResourceDirectoryEntry::GetNameLength() { + return winchar_strlen(m_szName); +} + +WORD CResourceDirectoryEntry::GetId() { + if (m_bHasName) + return 0; + return m_wId; +} + +bool CResourceDirectoryEntry::IsDataDirectory() { + return m_bIsDataDirectory; +} + +CResourceDirectory* CResourceDirectoryEntry::GetSubDirectory() { + if (!m_bIsDataDirectory) + return NULL; + return m_rdSubDir; +} + +CResourceDataEntry* CResourceDirectoryEntry::GetDataEntry() { + if (m_bIsDataDirectory) + return NULL; + return m_rdeData; +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// CResourceDataEntry +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResourceDataEntry::CResourceDataEntry(BYTE* pbData, DWORD dwSize, DWORD dwCodePage, DWORD dwOffset) { + m_pbData = 0; + SetData(pbData, dwSize, dwCodePage); + m_dwOffset = dwOffset; +} + +CResourceDataEntry::~CResourceDataEntry() { + if (m_pbData) + delete [] m_pbData; +} + +////////////////////////////////////////////////////////////////////// +// Methods +////////////////////////////////////////////////////////////////////// + +// 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() { + return m_pbData; +} + +void CResourceDataEntry::SetData(BYTE* pbData, DWORD dwSize) { + SetData(pbData, dwSize, m_dwCodePage); +} + +void CResourceDataEntry::SetData(BYTE* pbData, DWORD dwSize, DWORD dwCodePage) { + if (m_pbData) delete [] m_pbData; + m_pbData = new BYTE[dwSize]; + CopyMemory(m_pbData, pbData, dwSize); + m_dwSize = dwSize; + m_dwCodePage = dwCodePage; + m_dwOffset = DWORD(-1); // unset +} + +DWORD CResourceDataEntry::GetSize() { + return m_dwSize; +} + +DWORD CResourceDataEntry::GetCodePage() { + return m_dwCodePage; +} + +DWORD CResourceDataEntry::GetOffset() { + return m_dwOffset; +} diff --git a/Source/ResourceEditor.h b/Source/ResourceEditor.h index 352d9e04..c45127e4 100644 --- a/Source/ResourceEditor.h +++ b/Source/ResourceEditor.h @@ -114,19 +114,10 @@ public: CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData = true); virtual ~CResourceEditor(); - bool UpdateResource(WORD szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); - bool UpdateResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); - bool UpdateResourceW(WORD szType, WCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); - bool UpdateResourceW(WCHAR* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); - bool UpdateResourceA(char* szType, char* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); - bool UpdateResourceA(WORD szType, char* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); - bool UpdateResourceA(char* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); - BYTE* GetResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage); - BYTE* GetResourceA(char* szType, char* szName, LANGID wLanguage); - int GetResourceSizeW(WCHAR* szType, WCHAR* szName, LANGID wLanguage); - int GetResourceSizeA(char* szType, char* szName, LANGID wLanguage); - DWORD GetResourceOffsetW(WCHAR* szType, WCHAR* szName, LANGID wLanguage); - DWORD GetResourceOffsetA(char* szType, char* szName, LANGID wLanguage); + bool UpdateResource (TCHAR* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); + BYTE* GetResource (TCHAR* szType, WORD szName, LANGID wLanguage); + int GetResourceSize (TCHAR* szType, WORD szName, LANGID wLanguage); + DWORD GetResourceOffset(TCHAR* szType, WORD szName, LANGID wLanguage); void FreeResource(BYTE* pbResource); // The section name must be in ASCII. @@ -143,6 +134,11 @@ public: DWORD *pdwResSecVA = NULL, DWORD *pdwSectionIndex = NULL ); +private: + bool UpdateResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); + BYTE* GetResourceW(WCHAR* szType, WCHAR* szName, LANGID wLanguage); + int GetResourceSizeW(WCHAR* szType, WCHAR* szName, LANGID wLanguage); + DWORD GetResourceOffsetW(WCHAR* szType, WCHAR* szName, LANGID wLanguage); private: BYTE* m_pbPE; diff --git a/Source/ResourceVersionInfo.cpp b/Source/ResourceVersionInfo.cpp index 82ce7cfe..65a5860f 100644 --- a/Source/ResourceVersionInfo.cpp +++ b/Source/ResourceVersionInfo.cpp @@ -57,7 +57,7 @@ CVersionStrigList::~CVersionStrigList() int CVersionStrigList::add(LANGID langid, int codepage) { TCHAR Buff[10]; - sprintf(Buff, _T("%04x"), langid); + _stprintf(Buff, _T("%04x"), langid); int pos = SortedStringListND::add(Buff); if (pos == -1) return false; ((struct version_string_list*)gr.get())[pos].pChildStrings = new DefineList; @@ -87,7 +87,7 @@ DefineList* CVersionStrigList::get_strings(int idx) int CVersionStrigList::find(LANGID lang_id, int codepage) { TCHAR Buff[10]; - sprintf(Buff, _T("%04x"), lang_id); + _stprintf(Buff, _T("%04x"), lang_id); return SortedStringListND::find(Buff); } @@ -218,8 +218,8 @@ void CResourceVersionInfo::ExportToStream(GrowBuf &strm, int Index) PadStream (stringInfoStream); p = stringInfoStream.getlen(); - KeyName = winchar_fromansi(pChildStrings->getname(i), codepage); - KeyValue = winchar_fromansi(pChildStrings->getvalue(i), codepage); + KeyName = winchar_fromTchar(pChildStrings->getname(i), codepage); + KeyValue = winchar_fromTchar(pChildStrings->getvalue(i), codepage); SaveVersionHeader (stringInfoStream, 0, WORD(winchar_strlen(KeyValue) + 1), 1, KeyName, (void*)KeyValue); delete [] KeyName; delete [] KeyValue; diff --git a/Source/Tests/winchar.cpp b/Source/Tests/winchar.cpp index 1ba44c70..5da4665b 100644 --- a/Source/Tests/winchar.cpp +++ b/Source/Tests/winchar.cpp @@ -11,35 +11,24 @@ class WinCharTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( WinCharTest ); - CPPUNIT_TEST( testFromAnsi ); - CPPUNIT_TEST( testToAnsi ); + CPPUNIT_TEST( testFromTchar ); CPPUNIT_TEST( testStrCpy ); CPPUNIT_TEST( testStrNCpy ); CPPUNIT_TEST( testStrLen ); CPPUNIT_TEST( testStrCmp ); CPPUNIT_TEST( testStrDup ); - CPPUNIT_TEST( testStoi ); CPPUNIT_TEST_SUITE_END(); public: - void testFromAnsi() { + void testFromTchar() { WCHAR test[] = { _x('t'), _x('e'), _x('s'), _x('t'), 0 }; - WCHAR *dyn = winchar_fromansi("test"); + WCHAR *dyn = winchar_fromTchar("test"); CPPUNIT_ASSERT_EQUAL( 0, memcmp(test, dyn, 5) ); delete [] dyn; } - void testToAnsi() { - WCHAR test[] = { _x('t'), _x('e'), _x('s'), _x('t'), 0 }; - char *dyn = winchar_toansi(test); - - CPPUNIT_ASSERT_EQUAL( 0, strcmp("test", dyn) ); - - delete [] dyn; - } - void testStrCpy() { WCHAR a[] = { _x('t'), _x('e'), _x('s'), _x('t'), 0 }; WCHAR b[5]; @@ -111,20 +100,6 @@ public: delete [] b; } - void testStoi() { - srand(time(0)); - - for (int i = 0; i < 1000; i++) - { - int r = rand(); - char s[128]; - sprintf(s, "%d", r); - WCHAR *ws = winchar_fromansi(s); - CPPUNIT_ASSERT_EQUAL( r, winchar_stoi(ws) ); - delete [] ws; - } - } - }; CPPUNIT_TEST_SUITE_REGISTRATION( WinCharTest ); diff --git a/Source/build.cpp b/Source/build.cpp index 98e275db..d4e7c0c8 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -1733,7 +1733,7 @@ int CEXEBuild::AddVersionInfo() warning(_T("Generating version information for language \"%04d-%s\" without standard key \"LegalCopyright\""), lang_id, lang_name); rVersionInfo.ExportToStream(VerInfoStream, i); - res_editor->UpdateResourceA(RT_VERSION, 1, lang_id, (BYTE*)VerInfoStream.get(), VerInfoStream.getlen()); + res_editor->UpdateResource(RT_VERSION, 1, lang_id, (BYTE*)VerInfoStream.get(), VerInfoStream.getlen()); } } catch (exception& err) { @@ -2073,7 +2073,7 @@ again: SCRIPT_MSG(_T("Done!\n")); #define REMOVE_ICON(id) if (disable_window_icon) { \ - BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(id), NSIS_DEFAULT_LANG); \ + BYTE* dlg = res_editor->GetResource(RT_DIALOG, id, NSIS_DEFAULT_LANG); \ if (dlg) { \ CDialogTemplate dt(dlg,uDefCodePage); \ res_editor->FreeResource(dlg); \ @@ -2091,7 +2091,7 @@ again: \ DWORD dwSize; \ dlg = dt.Save(dwSize); \ - res_editor->UpdateResourceA(RT_DIALOG, MAKEINTRESOURCE(id), NSIS_DEFAULT_LANG, dlg, dwSize); \ + res_editor->UpdateResource(RT_DIALOG, id, NSIS_DEFAULT_LANG, dlg, dwSize); \ delete [] dlg; \ } \ } \ @@ -2102,43 +2102,43 @@ again: init_res_editor(); #ifdef NSIS_CONFIG_LICENSEPAGE if (!license_normal) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_LICENSE, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_LICENSE, NSIS_DEFAULT_LANG, 0, 0); } else REMOVE_ICON(IDD_LICENSE); if (!license_fsrb) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_LICENSE_FSRB, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_LICENSE_FSRB, NSIS_DEFAULT_LANG, 0, 0); } else REMOVE_ICON(IDD_LICENSE_FSRB); if (!license_fscb) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_LICENSE_FSCB, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_LICENSE_FSCB, NSIS_DEFAULT_LANG, 0, 0); } else REMOVE_ICON(IDD_LICENSE_FSCB); #endif // NSIS_CONFIG_LICENSEPAGE #ifdef NSIS_CONFIG_COMPONENTPAGE if (!selcom) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_SELCOM, NSIS_DEFAULT_LANG, 0, 0); - res_editor->UpdateResourceA(RT_BITMAP, IDB_BITMAP1, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_SELCOM, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_BITMAP, IDB_BITMAP1, NSIS_DEFAULT_LANG, 0, 0); } else REMOVE_ICON(IDD_SELCOM); #endif // NSIS_CONFIG_COMPONENTPAGE if (!dir) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_DIR, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_DIR, NSIS_DEFAULT_LANG, 0, 0); } else REMOVE_ICON(IDD_DIR); #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT if (!uninstconfirm) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_UNINST, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_UNINST, NSIS_DEFAULT_LANG, 0, 0); } else REMOVE_ICON(IDD_UNINST); #endif // NSIS_CONFIG_UNINSTALL_SUPPORT if (!instlog) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_INSTFILES, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_INSTFILES, NSIS_DEFAULT_LANG, 0, 0); } else REMOVE_ICON(IDD_INSTFILES); if (!main) { - res_editor->UpdateResourceA(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG, 0, 0); if (!build_compress_whole && !build_crcchk) - res_editor->UpdateResourceA(RT_DIALOG, IDD_VERIFY, NSIS_DEFAULT_LANG, 0, 0); + res_editor->UpdateResource(RT_DIALOG, IDD_VERIFY, NSIS_DEFAULT_LANG, 0, 0); } SCRIPT_MSG(_T("Done!\n")); @@ -2279,7 +2279,7 @@ int CEXEBuild::SetManifest() return PS_OK; // Saved directly as binary into the exe. - res_editor->UpdateResourceA(MAKEINTRESOURCE(24), MAKEINTRESOURCE(1), NSIS_DEFAULT_LANG, (LPBYTE) manifest.c_str(), manifest.length()); + res_editor->UpdateResource(MAKEINTRESOURCE(24), 1, NSIS_DEFAULT_LANG, (LPBYTE) manifest.c_str(), manifest.length()); } catch (exception& err) { ERROR_MSG(_T("Error setting manifest: %s\n"), CtoTString(err.what())); diff --git a/Source/exehead/exec.c b/Source/exehead/exec.c index 380b7e9e..d92f824f 100644 --- a/Source/exehead/exec.c +++ b/Source/exehead/exec.c @@ -1174,13 +1174,13 @@ static int NSISCALL ExecuteEntry(entry *entry_) break; case EW_READINISTR: { - DWORD errstr = CHAR4_TO_DWORD(_T('!'), _T('N'), _T('~'), 0); + TCHAR errstr[] = _T("!N~"); TCHAR *p=var0; TCHAR *buf0=GetStringFromParm(0x01); TCHAR *buf1=GetStringFromParm(0x12); TCHAR *buf2=GetStringFromParm(-0x23); - GetPrivateProfileString(buf0,buf1,(LPCTSTR)&errstr,p,NSIS_MAX_STRLEN-1,buf2); - if (*(DWORD*)p == errstr) + GetPrivateProfileString(buf0,buf1,errstr,p,NSIS_MAX_STRLEN-1,buf2); + if (lstrcmp(p, errstr) == 0) { exec_error++; p[0]=0; diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index 838943da..e4a05bec 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -272,7 +272,6 @@ enum { }; // nsis strings - typedef TCHAR NSIS_STRING[NSIS_MAX_STRLEN]; // Settings common to both installers and uninstallers diff --git a/Source/icon.cpp b/Source/icon.cpp index 7567c08d..1564f9b2 100644 --- a/Source/icon.cpp +++ b/Source/icon.cpp @@ -49,8 +49,8 @@ IconGroup load_icon_res(CResourceEditor* re, WORD id) IconGroupHeader* header; IconGroup result; - LPBYTE group = re->GetResourceA( - RT_GROUP_ICON, MAKEINTRESOURCE(id), NSIS_DEFAULT_LANG); + LPBYTE group = re->GetResource( + RT_GROUP_ICON, id, NSIS_DEFAULT_LANG); if (!group) throw runtime_error("can't find icon group"); @@ -69,7 +69,7 @@ IconGroup load_icon_res(CResourceEditor* re, WORD id) WORD rsrc_id = FIX_ENDIAN_INT16(entry->wRsrcId); - icon.data = re->GetResourceA(RT_ICON, MAKEINTRESOURCE(rsrc_id), NSIS_DEFAULT_LANG); + icon.data = re->GetResource(RT_ICON, rsrc_id, NSIS_DEFAULT_LANG); if (!icon.data) { @@ -276,17 +276,17 @@ void set_icon(CResourceEditor* re, WORD wIconId, IconGroup icon1, IconGroup icon size_t group_size = sizeof(IconGroupHeader) // header + order.size() * SIZEOF_RSRC_ICON_GROUP_ENTRY; // entries - re->UpdateResourceA(RT_GROUP_ICON, MAKEINTRESOURCE(wIconId), NSIS_DEFAULT_LANG, group1, group_size); + re->UpdateResource(RT_GROUP_ICON, wIconId, NSIS_DEFAULT_LANG, group1, group_size); // delete old icons unsigned i = 1; - while (re->UpdateResourceA(RT_ICON, MAKEINTRESOURCE(i++), NSIS_DEFAULT_LANG, 0, 0)); + while (re->UpdateResource(RT_ICON, i++, NSIS_DEFAULT_LANG, 0, 0)); // set new icons IconGroup::size_type order_index; for (order_index = 0; order_index < order.size(); order_index++) { - DWORD size_index = order[order_index].size_index; + WORD size_index = order[order_index].size_index; DWORD size = order[order_index].size; LPBYTE data = new BYTE[size]; memset(data, 0, size); @@ -297,7 +297,7 @@ void set_icon(CResourceEditor* re, WORD wIconId, IconGroup icon1, IconGroup icon memcpy(data, icon->data, FIX_ENDIAN_INT32(icon->meta.dwRawSize)); } - re->UpdateResourceA(RT_ICON, MAKEINTRESOURCE(size_index + 1), NSIS_DEFAULT_LANG, data, size); + re->UpdateResource(RT_ICON, size_index + 1, NSIS_DEFAULT_LANG, data, size); delete [] data; } @@ -375,7 +375,7 @@ int generate_unicons_offsets(LPBYTE exeHeader, size_t exeHeaderSize, LPBYTE unin LPBYTE seeker = uninstIconData; - offset = re.GetResourceOffsetA(RT_GROUP_ICON, MAKEINTRESOURCE(wIconId), NSIS_DEFAULT_LANG); + offset = re.GetResourceOffset(RT_GROUP_ICON, wIconId, NSIS_DEFAULT_LANG); size = FIX_ENDIAN_INT32(*(LPDWORD)seeker); seeker += sizeof(DWORD); @@ -388,14 +388,14 @@ int generate_unicons_offsets(LPBYTE exeHeader, size_t exeHeaderSize, LPBYTE unin while (*(LPDWORD)seeker) { - offset = re.GetResourceOffsetA(RT_ICON, MAKEINTRESOURCE(icon_index), NSIS_DEFAULT_LANG); + offset = re.GetResourceOffset(RT_ICON, icon_index, NSIS_DEFAULT_LANG); if (offset > exeHeaderSize) { - throw runtime_error(_T("invalid icon offset (possibly compressed icon)")); + throw runtime_error("invalid icon offset (possibly compressed icon)"); } - DWORD real_size = re.GetResourceSizeA(RT_ICON, MAKEINTRESOURCE(icon_index), NSIS_DEFAULT_LANG); + DWORD real_size = re.GetResourceSize(RT_ICON, icon_index, NSIS_DEFAULT_LANG); size = FIX_ENDIAN_INT32(*(LPDWORD)seeker); seeker += sizeof(DWORD); diff --git a/Source/lang.cpp b/Source/lang.cpp index 224608cd..93992382 100644 --- a/Source/lang.cpp +++ b/Source/lang.cpp @@ -286,7 +286,7 @@ int StringsArray::set(int idx, const TCHAR *str) int old = ((int*)offsets.get())[idx]; - ((int*)offsets.get())[idx] = strings.add(str, strlen(str) + 1); + ((int*)offsets.get())[idx] = strings.add(str, (_tcsclen(str)+1)*sizeof(TCHAR))/sizeof(TCHAR); return old; } @@ -696,14 +696,14 @@ int CEXEBuild::GenerateLangTables() { init_res_editor(); #define ADD_FONT(id) { \ - BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(id), NSIS_DEFAULT_LANG); \ + BYTE* dlg = res_editor->GetResource(RT_DIALOG, id, NSIS_DEFAULT_LANG); \ if (dlg) { \ CDialogTemplate td(dlg); \ res_editor->FreeResource(dlg); \ td.SetFont(build_font, (WORD) build_font_size); \ DWORD dwSize; \ dlg = td.Save(dwSize); \ - res_editor->UpdateResourceA(RT_DIALOG, MAKEINTRESOURCE(id), NSIS_DEFAULT_LANG, dlg, dwSize); \ + res_editor->UpdateResource(RT_DIALOG, id, NSIS_DEFAULT_LANG, dlg, dwSize); \ delete [] dlg; \ } \ } @@ -751,7 +751,7 @@ int CEXEBuild::GenerateLangTables() { init_res_editor(); #define ADD_FONT(id) { \ - BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(id), NSIS_DEFAULT_LANG); \ + BYTE* dlg = res_editor->GetResource(RT_DIALOG, id, NSIS_DEFAULT_LANG); \ if (dlg) { \ CDialogTemplate td(dlg,lt[i].nlf.m_uCodePage); \ res_editor->FreeResource(dlg); \ @@ -766,7 +766,7 @@ int CEXEBuild::GenerateLangTables() { } \ DWORD dwSize; \ dlg = td.Save(dwSize); \ - res_editor->UpdateResourceA(RT_DIALOG, MAKEINTRESOURCE(id+cur_offset), NSIS_DEFAULT_LANG, dlg, dwSize); \ + res_editor->UpdateResource(RT_DIALOG, id+cur_offset, NSIS_DEFAULT_LANG, dlg, dwSize); \ delete [] dlg; \ } \ } diff --git a/Source/script.cpp b/Source/script.cpp index 87b483ef..b5287418 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -2157,7 +2157,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) try { init_res_editor(); - BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INSTFILES), NSIS_DEFAULT_LANG); + BYTE* dlg = res_editor->GetResource(RT_DIALOG, IDD_INSTFILES, NSIS_DEFAULT_LANG); if (!dlg) throw runtime_error("IDD_INSTFILES doesn't exist!"); CDialogTemplate dt(dlg,uDefCodePage); free(dlg); @@ -2173,7 +2173,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) DWORD dwSize; dlg = dt.Save(dwSize); - res_editor->UpdateResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INSTFILES), NSIS_DEFAULT_LANG, dlg, dwSize); + res_editor->UpdateResource(RT_DIALOG, IDD_INSTFILES, NSIS_DEFAULT_LANG, dlg, dwSize); delete [] dlg; } catch (exception& err) { @@ -2452,9 +2452,9 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) init_res_editor(); // Search for required items - #define GET(x) dlg = uire->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(x), 0); if (!dlg) return PS_ERROR; CDialogTemplate UIDlg(dlg, uDefCodePage); - #define SEARCH(x) if (!UIDlg.GetItem(x)) {ERROR_MSG("Error: Can't find %s (%u) in the custom UI!\n", #x, x);delete [] dlg;delete uire;return PS_ERROR;} - #define SAVE(x) dwSize = UIDlg.GetSize(); res_editor->UpdateResourceA(RT_DIALOG, x, NSIS_DEFAULT_LANG, dlg, dwSize); delete [] dlg; + #define GET(x) dlg = uire->GetResource(RT_DIALOG, x, 0); if (!dlg) return PS_ERROR; CDialogTemplate UIDlg(dlg, uDefCodePage); + #define SEARCH(x) if (!UIDlg.GetItem(x)) {ERROR_MSG(_T("Error: Can't find %s (%u) in the custom UI!\n"), _T(#x), x);delete [] dlg;delete uire;return PS_ERROR;} + #define SAVE(x) dwSize = UIDlg.GetSize(); res_editor->UpdateResource(RT_DIALOG, x, NSIS_DEFAULT_LANG, dlg, dwSize); delete [] dlg; LPBYTE dlg = NULL; @@ -2570,7 +2570,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) padding = line.gettoken_int(3); init_res_editor(); - BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), NSIS_DEFAULT_LANG); + BYTE* dlg = res_editor->GetResource(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG); CDialogTemplate dt(dlg, uDefCodePage); @@ -2618,7 +2618,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) DWORD dwDlgSize; dlg = dt.Save(dwDlgSize); - res_editor->UpdateResourceA(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG, dlg, dwDlgSize); + res_editor->UpdateResource(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG, dlg, dwDlgSize); delete [] dlg; @@ -2846,7 +2846,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) for (;;) { TCHAR *p=str; *p=0; - fgets(str,MAX_LINELENGTH,fp); + _fgetts(str,MAX_LINELENGTH,fp); linecnt++; if (feof(fp)&&!str[0]) break; @@ -3668,7 +3668,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) if (trim) try { init_res_editor(); - BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), NSIS_DEFAULT_LANG); + BYTE* dlg = res_editor->GetResource(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG); CDialogTemplate td(dlg,uDefCodePage); free(dlg); @@ -3695,7 +3695,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) DWORD dwSize; dlg = td.Save(dwSize); - res_editor->UpdateResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), NSIS_DEFAULT_LANG, dlg, dwSize); + res_editor->UpdateResource(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG, dlg, dwSize); res_editor->FreeResource(dlg); } catch (exception& err) { diff --git a/Source/strlist.cpp b/Source/strlist.cpp index ffda8e56..64a9da9f 100644 --- a/Source/strlist.cpp +++ b/Source/strlist.cpp @@ -1,204 +1,205 @@ -/* - * strlist.cpp: Implementation of the StringList class. - * - * This file is a part of NSIS. - * - * Copyright (C) 1999-2009 Nullsoft and Contributors - * - * Licensed under the zlib/libpng license (the "License"); - * you may not use this file except in compliance with the License. - * - * Licence details can be found in the file COPYING. - * - * This software is provided 'as-is', without any express or implied - * warranty. - */ - -#include "strlist.h" - -int StringList::add(const TCHAR *str, int case_sensitive) -{ - int a=find(str,case_sensitive); - if (a >= 0 && case_sensitive!=-1) return a; - return gr.add(str,strlen(str)+1); -} - -// use 2 for case sensitive end-of-string matches too -int StringList::find(const TCHAR *str, int case_sensitive, int *idx/*=NULL*/) const // returns -1 if not found -{ - const TCHAR *s=get(); - int ml=getlen(); - int offs=0; - if (idx) *idx=0; - while (offs < ml) - { - if ((case_sensitive && !strcmp(s+offs,str)) || - (!case_sensitive && !stricmp(s+offs,str))) - { - return offs; - } - if (case_sensitive==2 && - strlen(str) < strlen(s+offs) && // check for end of string - !strcmp(s+offs+strlen(s+offs)-strlen(str),str)) - { - return offs+strlen(s+offs)-strlen(str); - } - offs+=strlen(s+offs)+1; - if (idx) (*idx)++; - } - return -1; -} - -void StringList::delbypos(int pos) -{ - TCHAR *s=(TCHAR*)gr.get(); - int len=strlen(s+pos)+1; - if (pos+len < gr.getlen()) memcpy(s+pos,s+pos+len,gr.getlen()-(pos+len)); - gr.resize(gr.getlen()-len); -} - -int StringList::idx2pos(int idx) const -{ - TCHAR *s=(TCHAR*)gr.get(); - int offs=0; - int cnt=0; - if (idx>=0) while (offs < gr.getlen()) - { - if (cnt++ == idx) return offs; - offs+=strlen(s+offs)+1; - } - return -1; -} - -int StringList::getnum() const -{ - TCHAR *s=(TCHAR*)gr.get(); - int ml=gr.getlen(); - int offs=0; - int idx=0; - while (offs < ml) - { - offs+=strlen(s+offs)+1; - idx++; - } - return idx; -} - -const TCHAR *StringList::get() const -{ - return (const TCHAR*)gr.get(); -} - -int StringList::getlen() const -{ - return gr.getlen(); -} - -// ========== -// DefineList -// ========== - -DefineList::~DefineList() -{ - struct define *s=(struct define*)gr.get(); - int num=gr.getlen()/sizeof(struct define); - - for (int i=0; i::add(name); - if (pos == -1) - { - return 1; - } - - TCHAR **newvalue=&(((struct define*)gr.get())[pos].value); - *newvalue=(TCHAR*)malloc(strlen(value)+1); - if (!(*newvalue)) - { - extern FILE *g_output; - extern int g_display_errors; - extern void quit(); - if (g_display_errors) - { - fprintf(g_output,_T("\nInternal compiler error #12345: GrowBuf realloc/malloc(%lu) failed.\n"),(unsigned long)strlen(value)+1); - fflush(g_output); - } - quit(); - } - strcpy(*newvalue,value); - return 0; -} - -TCHAR *DefineList::find(const TCHAR *name) -{ - int v=SortedStringList::find(name); - if (v==-1) - { - return NULL; - } - return ((struct define*)gr.get())[v].value; -} - -// returns 0 on success, 1 otherwise -int DefineList::del(const TCHAR *str) -{ - int pos=SortedStringList::find(str); - if (pos==-1) return 1; - - struct define *db=(struct define *)gr.get(); - free(db[pos].value); - delbypos(pos); - - return 0; -} - -int DefineList::getnum() -{ - return gr.getlen()/sizeof(define); -} - -TCHAR *DefineList::getname(int num) -{ - if ((unsigned int)getnum() <= (unsigned int)num) - return 0; - return ((struct define*)gr.get())[num].name; -} - -TCHAR *DefineList::getvalue(int num) -{ - if ((unsigned int)getnum() <= (unsigned int)num) - return 0; - return ((struct define*)gr.get())[num].value; -} - -// ============== -// FastStringList -// ============== - -int FastStringList::add(const TCHAR *name, int case_sensitive/*=0*/) -{ - int pos = SortedStringListND::add(name, case_sensitive); - if (pos == -1) return -1; - return ((struct string_t*)gr.get())[pos].name; -} - -TCHAR *FastStringList::get() const -{ - return (TCHAR*)strings.get(); -} - -int FastStringList::getlen() const -{ - return strings.getlen(); -} - -int FastStringList::getnum() const -{ - return gr.getlen()/sizeof(struct string_t); -} - +/* + * strlist.cpp: Implementation of the StringList class. + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2009 Nullsoft and Contributors + * + * Licensed under the zlib/libpng license (the "License"); + * you may not use this file except in compliance with the License. + * + * Licence details can be found in the file COPYING. + * + * This software is provided 'as-is', without any express or implied + * warranty. + */ + +#include "strlist.h" + +int StringList::add(const TCHAR *str, int case_sensitive) +{ + int a=find(str,case_sensitive); + if (a >= 0 && case_sensitive!=-1) return a; + return gr.add(str,(_tcsclen(str)+1)*sizeof(TCHAR))/sizeof(TCHAR); +} + +// use 2 for case sensitive end-of-string matches too +int StringList::find(const TCHAR *str, int case_sensitive, int *idx/*=NULL*/) const // returns -1 if not found +{ + const TCHAR *s=get(); + int ml=getlen(); + int offs=0; + if (idx) *idx=0; + while (offs < ml) + { + if ((case_sensitive && !_tcscmp(s+offs,str)) || + (!case_sensitive && !_tcsicmp(s+offs,str))) + { + return offs; + } + if (case_sensitive==2 && + _tcslen(str) < _tcslen(s+offs) && // check for end of string + !_tcscmp(s+offs+_tcslen(s+offs)-_tcslen(str),str)) + { + return offs+_tcslen(s+offs)-_tcslen(str); + } + offs+=_tcslen(s+offs)+1; + if (idx) (*idx)++; + } + return -1; +} + +void StringList::delbypos(int pos) +{ + TCHAR *s=(TCHAR*)gr.get(); + int len=_tcslen(s+pos)+1; + if (pos+len < gr.getlen()) memcpy(s+pos,s+pos+len,gr.getlen()-(pos+len)); + gr.resize(gr.getlen()-len); +} + +int StringList::idx2pos(int idx) const +{ + TCHAR *s=(TCHAR*)gr.get(); + int offs=0; + int cnt=0; + if (idx>=0) while (offs < gr.getlen()) + { + if (cnt++ == idx) return offs; + offs+=_tcslen(s+offs)+1; + } + return -1; +} + +int StringList::getnum() const +{ + TCHAR *s=(TCHAR*)gr.get(); + int ml=gr.getlen(); + int offs=0; + int idx=0; + while (offs < ml) + { + offs+=_tcslen(s+offs)+1; + idx++; + } + return idx; +} + +const TCHAR *StringList::get() const +{ + return (const TCHAR*)gr.get(); +} + +int StringList::getlen() const +{ + return gr.getlen(); +} + +// ========== +// DefineList +// ========== + +DefineList::~DefineList() +{ + struct define *s=(struct define*)gr.get(); + int num=gr.getlen()/sizeof(struct define); + + for (int i=0; i::add(name); + if (pos == -1) + { + return 1; + } + + TCHAR **newvalue=&(((struct define*)gr.get())[pos].value); + size_t size_in_bytes = (_tcslen(value) + 1) * sizeof(TCHAR); + *newvalue=(TCHAR*)malloc(size_in_bytes); + if (!(*newvalue)) + { + extern FILE *g_output; + extern int g_display_errors; + extern void quit(); + if (g_display_errors) + { + _ftprintf(g_output,_T("\nInternal compiler error #12345: GrowBuf realloc/malloc(%lu) failed.\n"), (unsigned long) size_in_bytes); + fflush(g_output); + } + quit(); + } + _tcscpy(*newvalue,value); + return 0; +} + +TCHAR *DefineList::find(const TCHAR *name) +{ + int v=SortedStringList::find(name); + if (v==-1) + { + return NULL; + } + return ((struct define*)gr.get())[v].value; +} + +// returns 0 on success, 1 otherwise +int DefineList::del(const TCHAR *str) +{ + int pos=SortedStringList::find(str); + if (pos==-1) return 1; + + struct define *db=(struct define *)gr.get(); + free(db[pos].value); + delbypos(pos); + + return 0; +} + +int DefineList::getnum() +{ + return gr.getlen()/sizeof(define); +} + +TCHAR *DefineList::getname(int num) +{ + if ((unsigned int)getnum() <= (unsigned int)num) + return 0; + return ((struct define*)gr.get())[num].name; +} + +TCHAR *DefineList::getvalue(int num) +{ + if ((unsigned int)getnum() <= (unsigned int)num) + return 0; + return ((struct define*)gr.get())[num].value; +} + +// ============== +// FastStringList +// ============== + +int FastStringList::add(const TCHAR *name, int case_sensitive/*=0*/) +{ + int pos = SortedStringListND::add(name, case_sensitive); + if (pos == -1) return -1; + return ((struct string_t*)gr.get())[pos].name; +} + +TCHAR *FastStringList::get() const +{ + return (TCHAR*)strings.get(); +} + +int FastStringList::getlen() const +{ + return strings.getlen(); +} + +int FastStringList::getnum() const +{ + return gr.getlen()/sizeof(struct string_t); +} + diff --git a/Source/strlist.h b/Source/strlist.h index ca38cee3..e61239d5 100644 --- a/Source/strlist.h +++ b/Source/strlist.h @@ -210,7 +210,7 @@ class SortedStringList if (case_sensitive) res=_tcscmp(str, data[nextpos].name); else - res=stricmp(str, data[nextpos].name); + res=_tcsicmp(str, data[nextpos].name); if (res==0) return returnbestpos ? -1 : nextpos; if (res<0) ul=nextpos; else ll=nextpos+1; @@ -302,7 +302,7 @@ class SortedStringListND // no delete - can be placed in GrowBuf if (pos==-1) return alwaysreturnpos ? where : -1; // Note that .name is set with the TCHAR* offset into m_strings. - newstruct.name=strings.add(name,strlen(name)+1); + newstruct.name=strings.add(name,(_tcsclen(name)+1)*sizeof(TCHAR))/sizeof(TCHAR); gr.add(&newstruct,sizeof(T)); T *s=(T*)gr.get(); diff --git a/Source/tstring.h b/Source/tstring.h index 95351671..d2bcedd1 100644 --- a/Source/tstring.h +++ b/Source/tstring.h @@ -19,6 +19,7 @@ #ifndef _TSTRING_ #define _TSTRING_ +#include "Platform.h" #include "tchar.h" #include @@ -28,9 +29,7 @@ typedef std::wstring tstring; typedef std::wofstream tofstream; typedef std::wifstream tifstream; // Use the following macros to open text files. -// #define FOPENTEXT(file, mode) _wfopen(file, mode ## L", ccs=Unicode") -FILE* FileOpenUnicodeText(const TCHAR* file, const TCHAR* mode); -#define FOPENTEXT(file, mode) FileOpenUnicodeText(file, mode) +#define FOPENTEXT(file, mode) _wfopen(file, mode) #else typedef std::string tstring; typedef std::ofstream tofstream; @@ -56,10 +55,16 @@ public: m_wStr = (wchar_t*) GlobalAlloc(GPTR, len*sizeof(wchar_t)); MultiByteToWideChar(CP_ACP, 0, str, -1, m_wStr, len); } + CtoTString(const std::string& str) + { + int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length()+1, NULL, 0); + m_wStr = (wchar_t*) GlobalAlloc(GPTR, len*sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length()+1, m_wStr, len); + } ~CtoTString() { GlobalFree(m_wStr); m_wStr = 0; } - operator const wchar_t* tstr() { return m_wStr; } + operator const wchar_t*() { return m_wStr; } private: wchar_t* m_wStr; @@ -76,6 +81,12 @@ public: m_cStr = (char*) GlobalAlloc(GPTR, len); WideCharToMultiByte(CP_ACP, 0, wStr, -1, m_cStr, len, 0, 0); } + TtoCString(const tstring& wStr) + { + int len = WideCharToMultiByte(CP_ACP, 0, wStr.c_str(), wStr.length()+1, NULL, 0, 0, 0); + m_cStr = (char*) GlobalAlloc(GPTR, len); + WideCharToMultiByte(CP_ACP, 0, wStr.c_str(), wStr.length()+1, m_cStr, len, 0, 0); + } ~TtoCString() { GlobalFree(m_cStr); m_cStr = 0; } diff --git a/Source/util.cpp b/Source/util.cpp index 18bfce9a..e9d79a4e 100644 --- a/Source/util.cpp +++ b/Source/util.cpp @@ -129,7 +129,7 @@ int update_bitmap(CResourceEditor* re, WORD id, const TCHAR* filename, int width } fclose(f); - re->UpdateResourceA(RT_BITMAP, MAKEINTRESOURCE(id), NSIS_DEFAULT_LANG, bitmap, dwSize); + re->UpdateResource(RT_BITMAP, id, NSIS_DEFAULT_LANG, bitmap, dwSize); free(bitmap); @@ -537,8 +537,8 @@ static bool GetDLLVersionUsingRE(const tstring& filepath, DWORD& high, DWORD & l try { CResourceEditor *dllre = new CResourceEditor(dll, len); - LPBYTE ver = dllre->GetResourceA(VS_FILE_INFO, MAKEINTRESOURCE(VS_VERSION_INFO), 0); - int versize = dllre->GetResourceSizeA(VS_FILE_INFO, MAKEINTRESOURCE(VS_VERSION_INFO), 0); + LPBYTE ver = dllre->GetResource(VS_FILE_INFO, VS_VERSION_INFO, 0); + int versize = dllre->GetResourceSize(VS_FILE_INFO, VS_VERSION_INFO, 0); if (ver) { diff --git a/Source/winchar.cpp b/Source/winchar.cpp index a8e54711..35c243cc 100644 --- a/Source/winchar.cpp +++ b/Source/winchar.cpp @@ -24,8 +24,11 @@ using std::runtime_error; -WCHAR *winchar_fromansi(const char* s, unsigned int codepage/*=CP_ACP*/) +WCHAR *winchar_fromTchar(const TCHAR* s, unsigned int codepage/*=CP_ACP*/) { +#ifdef _UNICODE + return _wcsdup(s); // codepage is not used in this mode +#else int l = MultiByteToWideChar(codepage, 0, s, -1, 0, 0); if (l == 0) throw runtime_error("Unicode conversion failed"); @@ -36,20 +39,7 @@ WCHAR *winchar_fromansi(const char* s, unsigned int codepage/*=CP_ACP*/) throw runtime_error("Unicode conversion failed"); return ws; -} - -char *winchar_toansi(const WCHAR* ws, unsigned int codepage/*=CP_ACP*/) -{ - int l = WideCharToMultiByte(codepage, 0, ws, -1, 0, 0, 0, 0); - if (l == 0) - throw runtime_error("Unicode conversion failed"); - - char *s = new char[l + 1]; - - if (WideCharToMultiByte(codepage, 0, ws, -1, s, l + 1, 0, 0) == 0) - throw runtime_error("Unicode conversion failed"); - - return s; +#endif } WCHAR *winchar_strcpy(WCHAR *ws1, const WCHAR *ws2) @@ -115,14 +105,3 @@ int winchar_strcmp(const WCHAR *ws1, const WCHAR *ws2) return diff; } - -int winchar_stoi(const WCHAR *ws) -{ - char *s = winchar_toansi(ws); - - int ret = atoi(s); - - delete [] s; - - return ret; -} diff --git a/Source/winchar.h b/Source/winchar.h index 3c400235..ed3f1f24 100644 --- a/Source/winchar.h +++ b/Source/winchar.h @@ -18,11 +18,9 @@ #include "Platform.h" -WCHAR *winchar_fromansi(const char* s, unsigned int codepage = CP_ACP); -char *winchar_toansi(const WCHAR* ws, unsigned int codepage = CP_ACP); +WCHAR *winchar_fromTchar(const TCHAR* s, unsigned int codepage = CP_ACP); WCHAR *winchar_strcpy(WCHAR *ws1, const WCHAR *ws2); WCHAR *winchar_strncpy(WCHAR *ws1, const WCHAR *ws2, size_t n); size_t winchar_strlen(const WCHAR *ws); WCHAR *winchar_strdup(const WCHAR *ws); int winchar_strcmp(const WCHAR *ws1, const WCHAR *ws2); -int winchar_stoi(const WCHAR *ws); diff --git a/Source/writer.cpp b/Source/writer.cpp index b81c9a6c..bb4fe929 100644 --- a/Source/writer.cpp +++ b/Source/writer.cpp @@ -50,19 +50,29 @@ void writer_sink::write_int_array(const int i[], const size_t len) } } -void writer_sink::write_string(const char *s) -{ - write_data(s, strlen(s) + 1); -} - // size in this case is the length of the string to write. -void writer_sink::write_string(const char *s, const size_t size) +void writer_sink::write_string(const TCHAR *s, size_t size) { +#ifdef _UNICODE + bool strEnd = false; + TCHAR ch; + for (; size ; size--) + { + if (!strEnd) + { + ch = *s++; + if (ch == _T('\0')) + strEnd = true; + } + write_short(ch); + } +#else char *wb = new char[size]; memset(wb, 0, size); strncpy(wb, s, size); write_data(wb, size); delete [] wb; +#endif } void writer_sink::write_growbuf(const IGrowBuf *b) diff --git a/Source/writer.h b/Source/writer.h index 294cc4fa..0f4a970e 100644 --- a/Source/writer.h +++ b/Source/writer.h @@ -34,8 +34,7 @@ public: virtual void write_short(const short s); virtual void write_int(const int i); virtual void write_int_array(const int i[], const size_t len); - virtual void write_string(const TCHAR *s); - virtual void write_string(const TCHAR *s, const size_t size); + virtual void write_string(const TCHAR *s, size_t size); virtual void write_growbuf(const IGrowBuf *b); virtual void write_data(const void *data, const size_t size) = 0;