2007-11-09 18:29:18 +00:00
/*
2019-09-11 23:36:32 +00:00
Copyright ( C ) 2002 Robert Rainwater < rrainwater @ yahoo . com >
2021-01-01 20:27:52 +00:00
Copyright ( C ) 2002 - 2021 Nullsoft and Contributors
2007-11-09 18:29:18 +00:00
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 <windows.h>
# include <commctrl.h>
# include <winnt.h>
2009-02-04 14:08:31 +00:00
# include <nsis/pluginapi.h> // nsis plugin
2007-11-09 18:29:18 +00:00
2015-10-30 03:55:30 +00:00
# if defined(_MSC_VER) && !defined(GetVersion)
# if _MSC_VER >= 1500
FORCEINLINE DWORD NoDepr_GetVersion ( ) { __pragma ( warning ( push ) ) __pragma ( warning ( disable : 4996 ) ) DWORD r = GetVersion ( ) ; __pragma ( warning ( pop ) ) return r ; }
# define GetVersion NoDepr_GetVersion
# endif //~ _MSC_VER >= 1500
# endif //~ _MSC_VER
2019-09-11 23:36:32 +00:00
# define TAB_REPLACE _T(" ")
# define TAB_REPLACE_SIZE (sizeof(TAB_REPLACE) - sizeof(_T("")))
# define TAB_REPLACE_CCH (TAB_REPLACE_SIZE / sizeof(_T("")))
enum { MODE_IGNOREOUTPUT = 0 , MODE_LINES = 1 , MODE_STACK = 2 } ;
2007-11-09 18:29:18 +00:00
2015-10-30 03:55:30 +00:00
# define LOOPTIMEOUT 100
HWND g_hwndParent ;
HWND g_hwndList ;
2019-09-11 23:36:32 +00:00
HINSTANCE g_hInst ;
2007-11-09 18:29:18 +00:00
void ExecScript ( BOOL log ) ;
2010-03-24 17:22:56 +00:00
TCHAR * my_strstr ( TCHAR * a , TCHAR * b ) ;
unsigned int my_atoi ( TCHAR * s ) ;
2012-10-13 01:47:50 +00:00
int WINAPI AsExeWinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPTSTR lpCmdLine , int nCmdShow ) ;
2007-11-09 18:29:18 +00:00
2010-03-24 17:22:56 +00:00
void __declspec ( dllexport ) Exec ( HWND hwndParent , int string_size , TCHAR * variables , stack_t * * stacktop ) {
2019-09-11 23:36:32 +00:00
g_hwndParent = hwndParent ;
2007-11-09 18:29:18 +00:00
EXDLL_INIT ( ) ;
2019-09-11 23:36:32 +00:00
ExecScript ( MODE_IGNOREOUTPUT ) ;
2007-11-09 18:29:18 +00:00
}
2010-03-24 17:22:56 +00:00
void __declspec ( dllexport ) ExecToLog ( HWND hwndParent , int string_size , TCHAR * variables , stack_t * * stacktop ) {
2019-09-11 23:36:32 +00:00
g_hwndParent = hwndParent ;
2007-11-09 18:29:18 +00:00
EXDLL_INIT ( ) ;
2019-09-11 23:36:32 +00:00
ExecScript ( MODE_LINES ) ;
2007-11-09 18:29:18 +00:00
}
2010-03-24 17:22:56 +00:00
void __declspec ( dllexport ) ExecToStack ( HWND hwndParent , int string_size , TCHAR * variables , stack_t * * stacktop ) {
2019-09-11 23:36:32 +00:00
g_hwndParent = hwndParent ;
2007-11-09 18:29:18 +00:00
EXDLL_INIT ( ) ;
2019-09-11 23:36:32 +00:00
ExecScript ( MODE_STACK ) ;
2007-11-09 18:29:18 +00:00
}
2012-10-13 01:47:50 +00:00
BOOL WINAPI DllMain ( HINSTANCE hInst , ULONG ul_reason_for_call , LPVOID lpReserved ) {
2007-11-09 18:29:18 +00:00
g_hInst = hInst ;
return TRUE ;
}
2019-09-15 17:10:26 +00:00
static BOOL IsLeadSurrogateUTF16 ( unsigned short c ) { return c > = 0xd800 & & c < = 0xdbff ; }
static BOOL IsTrailSurrogateUTF16 ( unsigned short c ) { return c > = 0xdc00 & & c < = 0xdfff ; }
static PWSTR MyCharNext ( PCWSTR p )
{
2019-10-07 18:01:16 +00:00
// Note: This is wrong for surrogate pair combining characters but CharNextW does
// not support surrogate pairs correctly so we have to manually handle the pairs.
2019-09-15 17:10:26 +00:00
if ( ! p [ 0 ] ) return ( PWSTR ) p ;
if ( IsLeadSurrogateUTF16 ( p [ 0 ] ) & & IsTrailSurrogateUTF16 ( p [ 1 ] ) ) return ( PWSTR ) p + 2 ; // Current is a surrogate pair, we incorrectly assume that it is not followed by combining characters.
if ( IsLeadSurrogateUTF16 ( p [ 1 ] ) & & IsTrailSurrogateUTF16 ( p [ 2 ] ) ) return ( PWSTR ) p + 1 ; // Next is a surrogate pair, we incorrectly assume that it is not a combining character for the current character.
return ( CharNextW ) ( p ) ;
2019-09-11 23:36:32 +00:00
}
2019-09-15 17:10:26 +00:00
# define CharNextW MyCharNext
2019-09-11 23:36:32 +00:00
static void TruncateStringUTF16LE ( LPWSTR Buffer , SIZE_T Length , LPCWSTR Overflow , SIZE_T lenOver ) {
if ( Length ) {
LPWSTR p = & Buffer [ Length - 1 ] ;
UINT stripBaseCharIfCuttingCombining = TRUE ;
// CharNextW is buggy on XP&2003 but we don't care enough to call GetStringTypeW (http://archives.miloush.net/michkap/archive/2005/01/30/363420.html)
if ( stripBaseCharIfCuttingCombining & & lenOver ) {
WCHAR buf [ ] = { * p , Overflow [ 0 ] , lenOver > 1 ? Overflow [ 1 ] : L ' ' , L ' \0 ' } ;
for ( ; ; ) {
BOOL comb = CharNextW ( buf ) > buf + 1 ;
if ( ! comb | | p < Buffer ) break ;
* ( ( WORD * ) ( ( BYTE * ) & buf [ 1 ] ) ) = * ( ( WORD * ) ( ( BYTE * ) & buf [ 0 ] ) ) ;
buf [ 0 ] = * p ;
* p - - = L ' \0 ' ;
}
}
if ( IsLeadSurrogateUTF16 ( * p ) ) {
* p = L ' \0 ' ; // Avoid incomplete pair
}
}
}
static void TruncateStringMB ( UINT Codepage , LPSTR Buffer , SIZE_T Length , unsigned short OverflowCh ) {
if ( Length ) {
CHAR * p = & Buffer [ Length - 1 ] , buf [ ] = { * p , ' ' , ' ' , ' \0 ' } ;
if ( CharNextExA ( Codepage , buf , 0 ) > buf + 1 ) { // Remove incomplete DBCS character?
* p = ' \0 ' ;
}
}
}
2007-11-09 18:29:18 +00:00
2019-03-04 22:15:41 +00:00
static BOOL IsWOW64 ( ) {
# ifdef _WIN64
return FALSE ;
# else
typedef BOOL ( WINAPI * ISWOW64PROCESS ) ( HANDLE , BOOL * ) ;
ISWOW64PROCESS pfIsWow64Process ;
typedef BOOL ( WINAPI * ISWOW64PROCESS2 ) ( HANDLE , USHORT * , USHORT * ) ;
ISWOW64PROCESS2 pfIsWow64Process2 ;
HANDLE hProcess = GetCurrentProcess ( ) ;
HMODULE hK32 = GetModuleHandleA ( " KERNEL32 " ) ;
UINT_PTR retval ;
USHORT appmach , image_file_machine_unknown = 0 ;
CHAR funcnam [ 16 ]
# if defined(_MSC_VER) && (_MSC_VER-0 <= 1400)
= " IsWow64Process2 " ; // MOVSD * 4
# else
; lstrcpyA ( funcnam , " IsWow64Process2 " ) ;
# endif
pfIsWow64Process2 = ( ISWOW64PROCESS2 ) GetProcAddress ( hK32 , funcnam ) ;
if ( pfIsWow64Process2 & & pfIsWow64Process2 ( hProcess , & appmach , NULL ) ) {
retval = image_file_machine_unknown ! = appmach ;
}
else {
BOOL wow64 ;
pfIsWow64Process = ( ISWOW64PROCESS ) GetProcAddress ( hK32 , ( funcnam [ 14 ] = ' \0 ' , funcnam ) ) ;
retval = ( UINT_PTR ) pfIsWow64Process ;
if ( pfIsWow64Process & & ( retval = pfIsWow64Process ( hProcess , & wow64 ) ) ) {
retval = wow64 ;
2008-02-16 18:30:47 +00:00
}
}
2019-03-04 22:15:41 +00:00
return ( BOOL ) ( UINT ) retval ;
# endif
2008-02-16 18:30:47 +00:00
}
2019-09-15 17:10:26 +00:00
// Tim Kosse's LogMessage
# ifdef UNICODE
static void LogMessage ( const TCHAR * pStr , BOOL bOEM ) {
# else
static void LogMessage ( TCHAR * pStr , BOOL bOEM ) {
# endif
LVITEM item ;
int nItemCount ;
if ( ! g_hwndList ) return ;
//if (!*pStr) return;
# ifndef UNICODE
if ( bOEM = = TRUE ) OemToCharBuff ( pStr , pStr , lstrlen ( pStr ) ) ;
# endif
nItemCount = ( int ) SendMessage ( g_hwndList , LVM_GETITEMCOUNT , 0 , 0 ) ;
item . mask = LVIF_TEXT ;
item . pszText = ( TCHAR * ) pStr ;
item . cchTextMax = 0 ;
item . iItem = nItemCount , item . iSubItem = 0 ;
ListView_InsertItem ( g_hwndList , & item ) ;
ListView_EnsureVisible ( g_hwndList , item . iItem , 0 ) ;
}
2010-05-19 15:21:34 +00:00
2019-09-11 23:36:32 +00:00
void ExecScript ( int mode ) {
TCHAR szRet [ 128 ] ;
TCHAR meDLLPath [ MAX_PATH ] ;
TCHAR * g_exec , * executor ;
2010-03-24 17:22:56 +00:00
TCHAR * pExec ;
2019-09-11 23:36:32 +00:00
int ignoreData = mode = = MODE_IGNOREOUTPUT ;
int logMode = mode = = MODE_LINES , stackMode = mode = = MODE_STACK ;
unsigned int to , tabExpandLength = logMode ? TAB_REPLACE_CCH : 0 , codepage ;
2020-08-22 16:24:14 +00:00
BOOL bOEM , forceNarrowInput = FALSE ;
2007-11-09 18:29:18 +00:00
2019-09-11 23:36:32 +00:00
* szRet = _T ( ' \0 ' ) ;
2008-02-16 21:46:52 +00:00
if ( ! IsWOW64 ( ) ) {
2010-03-24 17:22:56 +00:00
TCHAR * p ;
2008-02-16 18:30:47 +00:00
int nComSpecSize ;
2007-11-09 18:29:18 +00:00
2008-02-16 18:30:47 +00:00
nComSpecSize = GetModuleFileName ( g_hInst , meDLLPath , MAX_PATH ) + 2 ; // 2 chars for quotes
2019-09-11 23:36:32 +00:00
g_exec = ( TCHAR * ) GlobalAlloc ( GPTR , sizeof ( TCHAR ) * ( g_stringsize + nComSpecSize + 2 ) ) ; // 1 for space, 1 for null
2008-02-16 18:30:47 +00:00
p = meDLLPath + nComSpecSize - 2 ; // point p at null char of meDLLPath
2010-03-24 17:22:56 +00:00
* g_exec = _T ( ' " ' ) ;
2008-02-16 18:30:47 +00:00
executor = g_exec + 1 ;
2007-11-09 18:29:18 +00:00
2010-03-24 17:22:56 +00:00
// Look for the last '\' in path.
2008-02-16 18:30:47 +00:00
do
2007-11-09 18:29:18 +00:00
{
2010-03-24 17:22:56 +00:00
if ( * p = = _T ( ' \\ ' ) )
2008-02-16 18:30:47 +00:00
break ;
p = CharPrev ( meDLLPath , p ) ;
}
while ( p > meDLLPath ) ;
if ( p = = meDLLPath )
{
// bad path
2010-03-24 17:22:56 +00:00
pushstring ( _T ( " error " ) ) ;
2008-02-16 18:30:47 +00:00
GlobalFree ( g_exec ) ;
return ;
2007-11-09 18:29:18 +00:00
}
2008-02-16 18:30:47 +00:00
* p = 0 ;
2010-03-24 17:22:56 +00:00
GetTempFileName ( meDLLPath , _T ( " ns " ) , 0 , executor ) ; // executor = new temp file name in module path.
* p = _T ( ' \\ ' ) ;
if ( CopyFile ( meDLLPath , executor , FALSE ) ) // copy current DLL to temp file in module path.
2008-02-16 18:30:47 +00:00
{
HANDLE hFile , hMapping ;
LPBYTE pMapView ;
PIMAGE_NT_HEADERS pNTHeaders ;
hFile = CreateFile ( executor , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
hMapping = CreateFileMapping ( hFile , NULL , PAGE_READWRITE , 0 , 0 , NULL ) ;
pMapView = MapViewOfFile ( hMapping , FILE_MAP_WRITE , 0 , 0 , 0 ) ;
if ( pMapView )
{
pNTHeaders = ( PIMAGE_NT_HEADERS ) ( pMapView + ( ( PIMAGE_DOS_HEADER ) pMapView ) - > e_lfanew ) ;
2010-03-24 17:22:56 +00:00
// Turning the copied DLL into a stripped down executable.
2008-02-16 18:30:47 +00:00
pNTHeaders - > FileHeader . Characteristics = IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE ;
2010-03-24 17:22:56 +00:00
// Windows character-mode user interface (CUI) subsystem.
2008-02-16 18:30:47 +00:00
pNTHeaders - > OptionalHeader . Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI ;
2010-03-29 14:24:47 +00:00
// g_hInst is assumed to be the very base of the DLL in memory.
// WinMain will have the address of the WinMain function in memory.
// Getting the difference gets you the relative location of the
// WinMain function.
2014-02-08 00:13:52 +00:00
pNTHeaders - > OptionalHeader . AddressOfEntryPoint = ( DWORD ) ( ( DWORD_PTR ) AsExeWinMain - ( DWORD_PTR ) g_hInst ) ;
2008-02-16 18:30:47 +00:00
UnmapViewOfFile ( pMapView ) ;
}
CloseHandle ( hMapping ) ;
CloseHandle ( hFile ) ;
}
2010-03-24 17:22:56 +00:00
lstrcat ( g_exec , _T ( " \" " ) ) ;
2008-02-16 18:30:47 +00:00
// add space
pExec = g_exec + lstrlen ( g_exec ) ;
2010-03-24 17:22:56 +00:00
* pExec = _T ( ' ' ) ;
2008-02-16 18:30:47 +00:00
pExec + + ;
} else {
executor = NULL ;
2019-09-11 23:36:32 +00:00
g_exec = ( TCHAR * ) GlobalAlloc ( GPTR , sizeof ( TCHAR ) * ( g_stringsize + 1 ) ) ; // 1 for NULL
2008-02-16 18:30:47 +00:00
pExec = g_exec ;
}
2007-11-09 18:29:18 +00:00
2019-09-11 23:36:32 +00:00
to = 0 ; // default is no timeout
bOEM = FALSE ; // default is no OEM->ANSI conversion
2007-11-09 18:29:18 +00:00
g_hwndList = NULL ;
2010-03-24 17:22:56 +00:00
// g_hwndParent = the caller, usually NSIS installer.
if ( g_hwndParent ) // The window class name for dialog boxes is "#32770"
2019-09-11 23:36:32 +00:00
g_hwndList = FindWindowEx ( FindWindowEx ( g_hwndParent , NULL , _T ( " #32770 " ) , NULL ) , NULL , _T ( " SysListView32 " ) , NULL ) ;
2010-03-24 17:22:56 +00:00
// g_exec is the complete command to run: It has the copy of this DLL turned
// into an executable right now.
2007-11-09 18:29:18 +00:00
params :
2010-03-24 17:22:56 +00:00
// Get the command I need to run from the NSIS stack.
2007-11-09 18:29:18 +00:00
popstring ( pExec ) ;
2010-03-24 17:22:56 +00:00
if ( my_strstr ( pExec , _T ( " /TIMEOUT= " ) ) = = pExec ) {
TCHAR * szTimeout = pExec + 9 ;
2019-09-11 23:36:32 +00:00
to = my_atoi ( szTimeout ) ;
2007-11-09 18:29:18 +00:00
* pExec = 0 ;
goto params ;
}
2010-03-24 17:22:56 +00:00
if ( ! lstrcmpi ( pExec , _T ( " /OEM " ) ) ) {
2020-08-22 16:24:14 +00:00
bOEM = forceNarrowInput = TRUE ;
* pExec = 0 ;
goto params ;
}
if ( ! lstrcmpi ( pExec , _T ( " /MBCS " ) ) ) {
forceNarrowInput = TRUE ;
2007-11-09 18:29:18 +00:00
* pExec = 0 ;
goto params ;
}
if ( ! pExec [ 0 ] )
{
2010-03-24 17:22:56 +00:00
pushstring ( _T ( " error " ) ) ;
2010-05-28 14:09:08 +00:00
if ( pExec - 2 > = g_exec )
* ( pExec - 2 ) = _T ( ' \0 ' ) ; // skip space and quote
2008-02-16 18:30:47 +00:00
if ( executor ) DeleteFile ( executor ) ;
2007-11-09 18:29:18 +00:00
GlobalFree ( g_exec ) ;
return ;
}
2010-03-24 17:22:56 +00:00
// Got all the params off the stack.
2007-11-09 18:29:18 +00:00
{
2019-09-11 23:36:32 +00:00
STARTUPINFO si = { sizeof ( si ) , } ;
SECURITY_ATTRIBUTES sa = { sizeof ( sa ) , } ;
SECURITY_DESCRIPTOR sd = { 0 , } ;
PROCESS_INFORMATION pi ;
2015-10-30 03:55:30 +00:00
const BOOL isNT = sizeof ( void * ) > 4 | | ( GetVersion ( ) < 0x80000000 ) ;
2019-09-11 23:36:32 +00:00
HANDLE newstdout = 0 , read_stdout = 0 ;
HANDLE newstdin = 0 , read_stdin = 0 ;
2020-08-22 16:24:14 +00:00
int utfSource = sizeof ( TCHAR ) > 1 & & ! forceNarrowInput ? - 1 : FALSE , utfOutput = sizeof ( TCHAR ) > 1 ;
2019-09-11 23:36:32 +00:00
DWORD cbRead , dwLastOutput ;
DWORD dwExit = 0 , waitResult = WAIT_TIMEOUT ;
static BYTE bufSrc [ 1024 ] ;
BYTE * pSrc ;
SIZE_T cbSrcTot = sizeof ( bufSrc ) , cbSrc = 0 , cbSrcFree ;
TCHAR * bufOutput = 0 , * pNewAlloc , * pD ;
SIZE_T cchAlloc , cbAlloc , cchFree ;
2019-10-24 19:27:37 +00:00
# ifndef _MSC_VER // Avoid GCC "may be used uninitialized in this function" warnings
pD = NULL ;
cchAlloc = 0 ;
# endif
2019-09-15 17:10:26 +00:00
pi . hProcess = pi . hThread = NULL ;
2019-09-11 23:36:32 +00:00
codepage = bOEM ? CP_OEMCP : CP_ACP ;
if ( ! ignoreData ) {
cbAlloc = stackMode ? ( g_stringsize * sizeof ( TCHAR ) ) : sizeof ( bufSrc ) * 4 , cchAlloc = cbAlloc / sizeof ( TCHAR ) ;
pD = bufOutput = GlobalAlloc ( GPTR , cbAlloc + sizeof ( TCHAR ) ) ; // Include "hidden" space for a \0
if ( ! bufOutput ) {
2010-03-24 17:22:56 +00:00
lstrcpy ( szRet , _T ( " error " ) ) ;
2007-11-09 18:29:18 +00:00
goto done ;
}
2019-09-11 23:36:32 +00:00
* bufOutput = _T ( ' \0 ' ) ;
2007-11-09 18:29:18 +00:00
}
2019-09-11 23:36:32 +00:00
sa . bInheritHandle = TRUE ;
2015-10-30 03:55:30 +00:00
sa . lpSecurityDescriptor = NULL ;
if ( isNT ) {
2019-09-11 23:36:32 +00:00
InitializeSecurityDescriptor ( & sd , SECURITY_DESCRIPTOR_REVISION ) ;
SetSecurityDescriptorDacl ( & sd , TRUE , NULL , FALSE ) ;
2007-11-09 18:29:18 +00:00
sa . lpSecurityDescriptor = & sd ;
}
2015-10-30 03:55:30 +00:00
2019-09-11 23:36:32 +00:00
if ( ! CreatePipe ( & read_stdout , & newstdout , & sa , 0 ) ) {
2010-03-24 17:22:56 +00:00
lstrcpy ( szRet , _T ( " error " ) ) ;
2007-11-09 18:29:18 +00:00
goto done ;
}
2019-09-11 23:36:32 +00:00
if ( ! CreatePipe ( & read_stdin , & newstdin , & sa , 0 ) ) {
2010-03-24 17:22:56 +00:00
lstrcpy ( szRet , _T ( " error " ) ) ;
2007-11-09 18:29:18 +00:00
goto done ;
}
2019-09-11 23:36:32 +00:00
GetStartupInfo ( & si ) ; // Why?
2007-11-09 18:29:18 +00:00
si . dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW ;
si . wShowWindow = SW_HIDE ;
2008-02-16 18:30:47 +00:00
si . hStdInput = newstdin ;
2007-11-09 18:29:18 +00:00
si . hStdOutput = newstdout ;
si . hStdError = newstdout ;
2019-09-11 23:36:32 +00:00
if ( ! CreateProcess ( NULL , g_exec , NULL , NULL , TRUE , CREATE_NEW_CONSOLE , NULL , NULL , & si , & pi ) ) {
2010-03-24 17:22:56 +00:00
lstrcpy ( szRet , _T ( " error " ) ) ;
2007-11-09 18:29:18 +00:00
goto done ;
}
2019-09-11 23:36:32 +00:00
// Now I'm talking with an executable copy of myself.
2007-11-09 18:29:18 +00:00
dwLastOutput = GetTickCount ( ) ;
2019-09-11 23:36:32 +00:00
for ( ; ; ) {
TCHAR bufCh [ 2 ] ;
waitForProcess :
waitResult = WaitForSingleObject ( pi . hProcess , 0 ) ;
GetExitCodeProcess ( pi . hProcess , & dwExit ) ;
readMore :
PeekNamedPipe ( read_stdout , 0 , 0 , 0 , & cbRead , NULL ) ;
if ( ! cbRead ) {
if ( waitResult = = WAIT_OBJECT_0 ) {
break ; // No data in the pipe and process ended, we are done
}
if ( to & & GetTickCount ( ) > dwLastOutput + to ) {
TerminateProcess ( pi . hProcess , - 1 ) ;
lstrcpy ( szRet , _T ( " timeout " ) ) ;
}
else {
Sleep ( LOOPTIMEOUT ) ;
}
continue ;
}
2007-11-09 18:29:18 +00:00
2019-09-11 23:36:32 +00:00
dwLastOutput = GetTickCount ( ) ;
2019-10-07 18:01:16 +00:00
ReadFile ( read_stdout , bufSrc + cbSrc , ( DWORD ) ( cbSrcFree = cbSrcTot - cbSrc ) , & cbRead , NULL ) ;
2019-09-11 23:36:32 +00:00
cbSrcFree - = cbRead , cbSrc = cbSrcTot - cbSrcFree ;
pSrc = bufSrc ;
if ( utfSource < 0 & & cbSrc ) { // Simple UTF-16LE detection
# ifdef UNICODE
2019-10-07 18:01:16 +00:00
utfSource = IsTextUnicode ( pSrc , ( UINT ) ( cbSrc & ~ 1 ) , NULL ) ! = FALSE ;
2010-05-19 15:21:34 +00:00
# else
2019-09-11 23:36:32 +00:00
utfSource = ( cbSrc > = 3 & & pSrc [ 0 ] & & ! pSrc [ 1 ] ) | | ( cbSrc > 4 & & pSrc [ 2 ] & & ! pSrc [ 3 ] ) ; // Lame latin-only test
utfSource | = ( cbSrc > 3 & & pSrc [ 0 ] = = 0xFF & & pSrc [ 1 ] = = 0xFE & & ( pSrc [ 2 ] | pSrc [ 3 ] ) ) ; // Lame BOM test
2010-05-19 15:21:34 +00:00
# endif
2019-09-11 23:36:32 +00:00
}
if ( ignoreData ) {
cbSrc = 0 ; // Overwrite the whole buffer every read
continue ;
}
if ( ! cbRead ) {
continue ; // No new data, read more before trying to parse
}
parseLines :
cchFree = cchAlloc - ( pD - bufOutput ) ;
for ( ; ; ) {
DWORD cbSrcChar = 1 , cchDstChar , i ;
* pD = _T ( ' \0 ' ) ; // Terminate output buffer because we can unexpectedly run out of data
if ( ! cbSrc ) {
goto readMore ;
}
if ( utfSource ) { // UTF-16LE --> ?:
if ( cbSrc < 2 ) {
goto readMore ;
2010-03-29 14:24:47 +00:00
}
2019-09-11 23:36:32 +00:00
if ( utfOutput ) { // UTF-16LE --> UTF-16LE:
bufCh [ 0 ] = ( ( TCHAR * ) pSrc ) [ 0 ] , cbSrcChar = sizeof ( WCHAR ) , cchDstChar = 1 ; // We only care about certain ASCII characters so we don't bother dealing with surrogate pairs.
}
else { // UTF-16LE --> DBCS
// TODO: This is tricky because we need the complete base character (or surrogate pair) and all the trailing combining characters for a grapheme in the buffer before we can call WideCharToMultiByte.
utfOutput = FALSE ; // For now we just treat it as DBCS
continue ;
}
}
else { // DBCS --> ?:
if ( utfOutput ) { // DBCS --> UTF-16LE:
2019-09-15 17:10:26 +00:00
BOOL isMb = IsDBCSLeadByteEx ( codepage , ( ( CHAR * ) pSrc ) [ 0 ] ) ;
2019-09-11 23:36:32 +00:00
if ( isMb & & cbSrc < + + cbSrcChar ) {
goto readMore ;
2010-05-19 15:18:54 +00:00
}
2019-10-24 19:27:37 +00:00
cchDstChar = MultiByteToWideChar ( codepage , 0 , ( CHAR * ) pSrc , cbSrcChar , ( WCHAR * ) bufCh , 2 ) ;
2019-09-11 23:36:32 +00:00
}
else { // DBCS --> DBCS:
bufCh [ 0 ] = ( ( CHAR * ) pSrc ) [ 0 ] , cchDstChar = 1 ; // Note: OEM codepage will be converted by LogMessage
}
}
if ( bufCh [ 0 ] = = _T ( ' \t ' ) & & tabExpandLength ) { // Expand tab to spaces?
if ( cchFree < tabExpandLength ) {
goto resizeOutputBuffer ;
}
lstrcpy ( pD , TAB_REPLACE ) ;
pD + = tabExpandLength , cchFree - = tabExpandLength ;
}
else if ( bufCh [ 0 ] = = _T ( ' \r ' ) & & logMode ) {
// Eating it
}
else if ( bufCh [ 0 ] = = _T ( ' \n ' ) & & logMode ) {
LogMessage ( bufOutput , bOEM ) ; // Output has already been \0 terminated
* ( pD = bufOutput ) = _T ( ' \0 ' ) , cchFree = cchAlloc ;
}
else {
if ( cchFree < cchDstChar ) {
SIZE_T cchOrgOffset ;
resizeOutputBuffer :
if ( stackMode ) {
ignoreData = TRUE ; // Buffer was already maximum for the NSIS stack, we cannot handle more data
if ( utfOutput )
TruncateStringUTF16LE ( ( LPWSTR ) bufOutput , pD - bufOutput , ( LPCWSTR ) bufCh , cchDstChar ) ;
2007-11-09 18:29:18 +00:00
else
2019-09-11 23:36:32 +00:00
TruncateStringMB ( codepage , ( LPSTR ) bufOutput , pD - bufOutput , bufCh [ 0 ] ) ;
goto waitForProcess ;
2007-11-09 18:29:18 +00:00
}
2019-09-11 23:36:32 +00:00
cchAlloc + = 1024 , cbAlloc = cchAlloc / sizeof ( TCHAR ) ;
2019-09-15 17:10:26 +00:00
pNewAlloc = GlobalReAlloc ( bufOutput , cbAlloc + sizeof ( TCHAR ) , GPTR | GMEM_MOVEABLE ) ; // Include "hidden" space for a \0
2019-09-11 23:36:32 +00:00
if ( ! pNewAlloc ) {
lstrcpy ( szRet , _T ( " error " ) ) ;
ignoreData = TRUE ;
goto waitForProcess ;
2007-11-09 18:29:18 +00:00
}
2019-09-11 23:36:32 +00:00
cchOrgOffset = pD - bufOutput ;
* ( pD = ( bufOutput = pNewAlloc ) + cchOrgOffset ) = _T ( ' \0 ' ) ;
goto parseLines ;
}
for ( i = 0 ; i < cchDstChar ; + + i ) {
* pD + + = bufCh [ i ] , - - cchFree ;
2007-11-09 18:29:18 +00:00
}
}
2019-09-11 23:36:32 +00:00
pSrc + = cbSrcChar , cbSrc - = cbSrcChar ;
2007-11-09 18:29:18 +00:00
}
}
2019-09-11 23:36:32 +00:00
2007-11-09 18:29:18 +00:00
done :
2019-09-11 23:36:32 +00:00
if ( stackMode ) pushstring ( bufOutput ) ;
if ( logMode & & * bufOutput ) LogMessage ( bufOutput , bOEM ) ; // Write remaining output
if ( dwExit = = STATUS_ILLEGAL_INSTRUCTION )
2010-03-24 17:22:56 +00:00
lstrcpy ( szRet , _T ( " error " ) ) ;
if ( ! szRet [ 0 ] ) wsprintf ( szRet , _T ( " %d " ) , dwExit ) ;
2007-11-09 18:29:18 +00:00
pushstring ( szRet ) ;
CloseHandle ( pi . hThread ) ;
CloseHandle ( pi . hProcess ) ;
CloseHandle ( newstdout ) ;
CloseHandle ( read_stdout ) ;
2008-02-16 18:30:47 +00:00
CloseHandle ( newstdin ) ;
2007-11-09 18:29:18 +00:00
CloseHandle ( read_stdin ) ;
2010-05-28 14:09:08 +00:00
if ( pExec - 2 > = g_exec )
* ( pExec - 2 ) = _T ( ' \0 ' ) ; // skip space and quote
2019-09-11 23:36:32 +00:00
if ( executor )
DeleteFile ( executor ) ;
2007-11-09 18:29:18 +00:00
GlobalFree ( g_exec ) ;
2019-09-11 23:36:32 +00:00
if ( bufOutput )
GlobalFree ( bufOutput ) ;
2007-11-09 18:29:18 +00:00
}
}
2010-03-24 17:22:56 +00:00
TCHAR * my_strstr ( TCHAR * a , TCHAR * b )
2007-11-09 18:29:18 +00:00
{
int l = lstrlen ( b ) ;
while ( lstrlen ( a ) > = l )
{
2010-03-24 17:22:56 +00:00
TCHAR c = a [ l ] ;
2007-11-09 18:29:18 +00:00
a [ l ] = 0 ;
if ( ! lstrcmpi ( a , b ) )
{
a [ l ] = c ;
return a ;
}
a [ l ] = c ;
a = CharNext ( a ) ;
}
return NULL ;
}
2010-03-24 17:22:56 +00:00
unsigned int my_atoi ( TCHAR * s ) {
2007-11-09 18:29:18 +00:00
unsigned int v = 0 ;
2010-03-24 17:22:56 +00:00
if ( * s = = _T ( ' 0 ' ) & & ( s [ 1 ] = = _T ( ' x ' ) | | s [ 1 ] = = _T ( ' X ' ) ) ) {
2007-11-09 18:29:18 +00:00
s + = 2 ;
for ( ; ; ) {
int c = * s + + ;
2010-03-24 17:22:56 +00:00
if ( c > = _T ( ' 0 ' ) & & c < = _T ( ' 9 ' ) ) c - = _T ( ' 0 ' ) ;
else if ( c > = _T ( ' a ' ) & & c < = _T ( ' f ' ) ) c - = _T ( ' a ' ) - 10 ;
else if ( c > = _T ( ' A ' ) & & c < = _T ( ' F ' ) ) c - = _T ( ' A ' ) - 10 ;
2007-11-09 18:29:18 +00:00
else break ;
v < < = 4 ;
v + = c ;
}
}
2010-03-24 17:22:56 +00:00
else if ( * s = = _T ( ' 0 ' ) & & s [ 1 ] < = _T ( ' 7 ' ) & & s [ 1 ] > = _T ( ' 0 ' ) ) {
2007-11-09 18:29:18 +00:00
s + + ;
for ( ; ; ) {
int c = * s + + ;
2010-03-24 17:22:56 +00:00
if ( c > = _T ( ' 0 ' ) & & c < = _T ( ' 7 ' ) ) c - = _T ( ' 0 ' ) ;
2007-11-09 18:29:18 +00:00
else break ;
v < < = 3 ;
v + = c ;
}
}
else {
for ( ; ; ) {
2010-03-24 17:22:56 +00:00
int c = * s + + - _T ( ' 0 ' ) ;
2007-11-09 18:29:18 +00:00
if ( c < 0 | | c > 9 ) break ;
v * = 10 ;
v + = c ;
}
}
return ( int ) v ;
}
2012-10-13 01:47:50 +00:00
int WINAPI AsExeWinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPTSTR lpCmdLine , int nCmdShow )
2007-11-09 18:29:18 +00:00
{
DWORD Ret ;
STARTUPINFO si = { 0 } ;
PROCESS_INFORMATION pi = { 0 } ;
2012-10-13 01:47:50 +00:00
TCHAR command_line [ 1024 ] ; //BUGBUG
2010-03-24 17:22:56 +00:00
TCHAR seekchar = _T ( ' ' ) ;
TCHAR * cmdline ;
2007-11-09 18:29:18 +00:00
si . cb = sizeof ( si ) ;
// Make child process use this app's standard files. Not needed because the handles
// we created when executing this process were inheritable.
//si.dwFlags = STARTF_USESTDHANDLES;
//si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
//si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
//si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
lstrcpyn ( command_line , GetCommandLine ( ) , 1024 ) ;
cmdline = command_line ;
2010-03-24 17:22:56 +00:00
if ( * cmdline = = _T ( ' \" ' ) ) seekchar = * cmdline + + ;
2007-11-09 18:29:18 +00:00
while ( * cmdline & & * cmdline ! = seekchar ) cmdline = CharNext ( cmdline ) ;
cmdline = CharNext ( cmdline ) ;
// skip any spaces before the arguments
2010-03-24 17:22:56 +00:00
while ( * cmdline & & * cmdline = = _T ( ' ' ) ) cmdline + + ;
2007-11-09 18:29:18 +00:00
Ret = CreateProcess ( NULL , cmdline ,
NULL , NULL ,
TRUE , 0 ,
NULL , NULL ,
& si , & pi
) ;
if ( Ret )
{
2007-11-09 18:42:03 +00:00
WaitForSingleObject ( pi . hProcess , INFINITE ) ;
GetExitCodeProcess ( pi . hProcess , & Ret ) ;
2007-11-09 18:29:18 +00:00
CloseHandle ( pi . hProcess ) ;
CloseHandle ( pi . hThread ) ;
ExitProcess ( Ret ) ;
}
else
{
ExitProcess ( STATUS_ILLEGAL_INSTRUCTION ) ;
}
return 0 ; // dummy
}