2010-06-16 14:20:27 +00:00
/*
* build . cpp
*
* This file is a part of NSIS .
*
2021-01-01 20:27:52 +00:00
* Copyright ( C ) 1999 - 2021 Nullsoft and Contributors
2010-06-16 14:20:27 +00:00
*
* 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 .
*
* Unicode support added by Jim Park - - 08 / 07 / 2007
*/
# include "tchar.h"
# include "Platform.h"
# include <stdio.h>
# include "exehead/config.h"
# include <nsis-version.h>
# include "build.h"
# include "util.h"
# include "fileform.h"
# include "writer.h"
# include "crc32.h"
# include "manifest.h"
# include "icon.h"
2017-04-25 13:58:43 +00:00
# include "utf.h" // For NStream
2021-06-25 20:44:37 +00:00
# include "BinInterop.h"
2010-06-16 14:20:27 +00:00
# include "exehead/api.h"
# include "exehead/resource.h"
# include <stdexcept>
# include "ResourceEditor.h"
# include "DialogTemplate.h"
# include "ResourceVersionInfo.h"
# include "tstring.h"
2012-10-13 01:47:50 +00:00
# include <stdio.h>
# include <stdarg.h>
2010-06-16 14:20:27 +00:00
# ifndef _WIN32
# include <locale.h>
# include <unistd.h>
# include <limits.h>
# include <stdlib.h>
# endif
# include <cassert> // for assert
# define RET_UNLESS_OK( function_rc ) do { \
int rc = ( function_rc ) ; \
if ( rc ! = PS_OK ) \
return rc ; \
} while ( false )
using namespace std ;
namespace { // begin anonymous namespace
bool isSimpleChar ( TCHAR ch )
{
return ( ch = = _T ( ' . ' ) ) | | ( ch = = _T ( ' _ ' ) ) | | ( ch > = _T ( ' 0 ' ) & & ch < = _T ( ' 9 ' ) ) | | ( ch > = _T ( ' A ' ) & & ch < = _T ( ' Z ' ) ) | | ( ch > = _T ( ' a ' ) & & ch < = _T ( ' z ' ) ) ;
}
} // end of anonymous namespace
2013-03-14 18:00:00 +00:00
namespace MakensisAPI {
2014-06-11 22:01:38 +00:00
# ifdef _WIN64
const TCHAR * SigintEventNameFmt = _T ( " makensis win32 sigint event %Iu " ) ; // %u is the notify HWND, this is to make sure we abort the correct instance
# else
const TCHAR * SigintEventNameFmt = _T ( " makensis win32 sigint event %u " ) ;
# endif
2013-03-14 18:00:00 +00:00
const TCHAR * SigintEventNameLegacy = _T ( " makensis win32 signint event " ) ; // "sigNint" typo is part of the API now and cannot be changed
}
2018-06-04 14:49:21 +00:00
const WORD DefaultPEDllCharacteristics = IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE | IMAGE_DLLCHARACTERISTICS_NO_SEH | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE ; //forums.winamp.com/showthread.php?t=344755
2010-06-16 14:20:27 +00:00
void CEXEBuild : : define ( const TCHAR * p , const TCHAR * v )
{
definedlist . add ( p , v ) ;
}
CEXEBuild : : ~ CEXEBuild ( )
{
free_loaded_icon ( installer_icon ) ;
free_loaded_icon ( uninstaller_icon ) ;
delete [ ] m_exehead ;
int nlt = lang_tables . getlen ( ) / sizeof ( LanguageTable ) ;
LanguageTable * nla = ( LanguageTable * ) lang_tables . get ( ) ;
2018-10-24 19:01:00 +00:00
for ( int i = 0 ; i < nlt ; i + + )
2010-06-16 14:20:27 +00:00
DeleteLangTable ( nla + i ) ;
2011-06-09 20:05:18 +00:00
2021-08-18 13:53:50 +00:00
if ( postbuild_cmds ) postbuild_cmds - > delete_all ( ) ;
if ( postubuild_cmds ) postubuild_cmds - > delete_all ( ) ;
2010-06-16 14:20:27 +00:00
}
2017-09-01 23:06:48 +00:00
CEXEBuild : : CEXEBuild ( signed char pponly , bool warnaserror ) :
2014-06-22 18:50:54 +00:00
preprocessonly ( pponly ) ,
2014-06-19 19:06:49 +00:00
m_exehead ( 0 ) ,
2014-06-22 18:50:54 +00:00
m_exehead_size ( 0 )
2010-06-16 14:20:27 +00:00
{
2014-06-15 19:12:12 +00:00
set_verbosity ( 3 ) ;
2017-09-01 23:06:48 +00:00
if ( warnaserror ) diagstate . set_warning_as_error ( ) ;
2010-06-16 14:20:27 +00:00
2014-06-15 19:12:12 +00:00
curlinereader = 0 ;
2014-06-19 19:06:49 +00:00
curfilename = 0 , linecnt = 0 ;
2010-06-16 14:20:27 +00:00
cur_ifblock = NULL ;
last_line_had_slash = 0 ;
inside_comment = false ;
multiple_entries_instruction = 0 ;
build_include_depth = 0 ;
has_called_write_output = false ;
ns_func . add ( _T ( " " ) , 0 ) ; // make sure offset 0 is special on these (i.e. never used by a label)
ns_label . add ( _T ( " " ) , 0 ) ;
definedlist . add ( _T ( " NSIS_VERSION " ) , NSIS_VERSION ) ;
2011-12-15 20:07:37 +00:00
definedlist . add ( _T ( " NSIS_PACKEDVERSION " ) , NSIS_PACKEDVERSION ) ;
2010-06-16 14:20:27 +00:00
2020-08-10 22:26:36 +00:00
m_target_type = TARGET_X86UNICODE ;
2014-02-08 00:13:52 +00:00
# ifdef _WIN32
2017-05-14 16:16:30 +00:00
if ( sizeof ( void * ) > 4 ) m_target_type = TARGET_AMD64 ; // BUGBUG: scons 'TARGET_ARCH' should specify the default
2018-06-03 21:00:53 +00:00
# endif
# ifdef _M_ARM64
m_target_type = TARGET_ARM64 ; // BUGBUG: scons 'TARGET_ARCH' should specify the default
2014-02-08 00:13:52 +00:00
# endif
build_unicode = TARGET_X86ANSI ! = m_target_type ;
build_lockedunicodetarget = false ;
2010-06-16 14:20:27 +00:00
// automatically generated header file containing all defines
# include <nsis-defines.h>
// no longer optional
definedlist . add ( _T ( " NSIS_SUPPORT_STANDARD_PREDEFINES " ) ) ;
definedlist . add ( _T ( " NSIS_SUPPORT_NAMED_USERVARS " ) ) ;
definedlist . add ( _T ( " NSIS_SUPPORT_LANG_IN_STRINGS " ) ) ;
# ifdef _WIN32
definedlist . add ( _T ( " NSIS_WIN32_MAKENSIS " ) ) ;
# endif
2012-02-28 22:40:43 +00:00
# ifdef _UNICODE
definedlist . add ( _T ( " NSIS_UNICODE_MAKENSIS " ) ) ; // This define might go away once makensis.exe is always unicode
# endif
2013-09-06 23:48:59 +00:00
if ( sizeof ( void * ) > 4 ) definedlist . add ( _T ( " NSIS_MAKENSIS64 " ) ) ;
2010-06-16 14:20:27 +00:00
2014-04-05 16:50:11 +00:00
db_opt_save = db_opt_save_u = db_full_size = db_full_size_u = 0 ;
db_comp_save = db_comp_save_u = 0 ;
2010-06-16 14:20:27 +00:00
// Added by Amir Szekely 31st July 2002
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
compressor = & zlib_compressor ;
# endif
build_compressor_set = false ;
build_compressor_final = false ;
build_compress_whole = false ;
build_compress = 1 ;
build_compress_level = 9 ;
build_compress_dict_size = 1 < < 23 ;
cur_entries = & build_entries ;
cur_instruction_entry_map = & build_instruction_entry_map ;
cur_datablock = & build_datablock ;
cur_datablock_cache = & build_datablock_cache ;
cur_functions = & build_functions ;
cur_labels = & build_labels ;
cur_sections = & build_sections ;
cur_header = & build_header ;
cur_strlist = & build_strlist ;
cur_langtables = & build_langtables ;
cur_ctlcolors = & build_ctlcolors ;
cur_pages = & build_pages ;
cur_page = 0 ;
cur_page_type = - 1 ;
build_filebuflen = 32 < < 20 ; // 32mb
sectiongroup_open_cnt = 0 ;
build_cursection_isfunc = 0 ;
build_cursection = NULL ;
// init public data.
2011-06-09 20:05:18 +00:00
build_packname [ 0 ] = build_packcmd [ 0 ] = build_output_filename [ 0 ] = 0 ;
2021-08-18 13:53:50 +00:00
postbuild_cmds = postubuild_cmds = NULL ;
2010-06-16 14:20:27 +00:00
// Added by ramon 23 May 2003
build_allowskipfiles = 1 ;
// Added by ramon 6 jun 2003
# ifdef NSIS_SUPPORT_VERSION_INFO
2011-07-29 22:11:00 +00:00
version_fixedflags = 0 ;
2010-06-16 14:20:27 +00:00
# endif
build_overwrite = build_last_overwrite = 0 ;
build_crcchk = 1 ;
build_datesave = 1 ;
build_optimize_datablock = 1 ;
memset ( & build_header , - 1 , sizeof ( build_header ) ) ;
build_header . install_reg_rootkey = 0 ;
build_header . flags = CH_FLAGS_NO_ROOT_DIR ;
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
build_header . lb_bg = RGB ( 0 , 0 , 0 ) ;
build_header . lb_fg = RGB ( 0 , 255 , 0 ) ;
# endif
# ifdef NSIS_CONFIG_LICENSEPAGE
build_header . license_bg = - COLOR_BTNFACE ;
# endif
build_header . install_directory_ptr = 0 ;
build_header . install_directory_auto_append = 0 ;
build_header . install_reg_key_ptr = 0 ;
build_header . install_reg_value_ptr = 0 ;
# ifdef NSIS_CONFIG_COMPONENTPAGE
memset ( build_header . install_types , 0 , sizeof ( build_header . install_types ) ) ;
# endif
memset ( & build_header . blocks , 0 , sizeof ( build_header . blocks ) ) ;
uninstall_mode = 0 ;
uninstall_size_full = 0 ;
uninstall_size = - 1 ;
memset ( & build_uninst , - 1 , sizeof ( build_uninst ) ) ;
build_header . install_reg_rootkey = 0 ;
build_uninst . flags = 0 ;
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
build_uninst . lb_bg = RGB ( 0 , 0 , 0 ) ;
build_uninst . lb_fg = RGB ( 0 , 255 , 0 ) ;
# endif
# ifdef NSIS_CONFIG_LICENSEPAGE
build_uninst . license_bg = - COLOR_BTNFACE ;
# endif
build_uninst . install_directory_ptr = 0 ;
build_uninst . install_directory_auto_append = 0 ;
build_uninst . install_reg_key_ptr = 0 ;
build_uninst . install_reg_value_ptr = 0 ;
# ifdef NSIS_CONFIG_COMPONENTPAGE
memset ( build_uninst . install_types , 0 , sizeof ( build_uninst . install_types ) ) ;
# endif
memset ( & build_uninst . blocks , 0 , sizeof ( build_uninst . blocks ) ) ;
uninstaller_writes_used = 0 ;
2013-03-07 21:25:35 +00:00
build_strlist . addemptystring ( ) ;
ubuild_strlist . addemptystring ( ) ;
2010-06-16 14:20:27 +00:00
build_langstring_num = 0 ;
ubuild_langstring_num = 0 ;
build_font [ 0 ] = 0 ;
build_font_size = 0 ;
m_unicon_size = 0 ;
branding_image_found = false ;
no_space_texts = false ;
2011-11-13 17:31:14 +00:00
m_currentmacroname = NULL ;
2010-06-16 14:20:27 +00:00
# ifdef NSIS_CONFIG_PLUGIN_SUPPORT
build_plugin_unload = 0 ;
2012-10-13 01:47:50 +00:00
m_pPlugins = 0 ;
2010-06-16 14:20:27 +00:00
# endif
last_used_lang = NSIS_DEFAULT_LANG ;
res_editor = 0 ;
2018-06-04 14:49:21 +00:00
PEDllCharacteristics = DefaultPEDllCharacteristics ;
2015-07-27 20:41:17 +00:00
PESubsysVerMaj = PESubsysVerMin = ( WORD ) - 1 ;
2018-05-14 19:07:17 +00:00
manifest_flags = manifest : : flags_default ;
2010-06-16 14:20:27 +00:00
manifest_comctl = manifest : : comctl_old ;
2015-08-07 00:13:36 +00:00
manifest_exec_level = manifest : : exec_level_admin ;
2012-09-20 18:42:21 +00:00
manifest_dpiaware = manifest : : dpiaware_notset ;
2019-08-16 19:07:02 +00:00
manifest_lpaware = manifest : : lpaware_notset ;
2012-09-20 10:18:40 +00:00
manifest_sosl . setdefault ( ) ;
2010-06-16 14:20:27 +00:00
enable_last_page_cancel = 0 ;
uenable_last_page_cancel = 0 ;
license_res_id = IDD_LICENSE ;
disable_window_icon = 0 ;
notify_hwnd = 0 ;
# ifdef NSIS_SUPPORT_BGBG
bg_default_font . lfHeight = 40 ;
bg_default_font . lfWidth = 0 ;
bg_default_font . lfEscapement = 0 ;
bg_default_font . lfOrientation = 0 ;
bg_default_font . lfWeight = FW_BOLD ;
bg_default_font . lfItalic = TRUE ;
bg_default_font . lfUnderline = FALSE ;
bg_default_font . lfStrikeOut = FALSE ;
bg_default_font . lfCharSet = DEFAULT_CHARSET ;
bg_default_font . lfOutPrecision = OUT_DEFAULT_PRECIS ;
bg_default_font . lfClipPrecision = CLIP_DEFAULT_PRECIS ;
bg_default_font . lfQuality = DEFAULT_QUALITY ;
bg_default_font . lfPitchAndFamily = DEFAULT_PITCH ;
2014-05-20 17:26:33 +00:00
my_strncpy ( bg_default_font . lfFaceName , _T ( " Times New Roman " ) , LF_FACESIZE ) ;
2010-06-16 14:20:27 +00:00
memcpy ( & bg_font , & bg_default_font , sizeof ( LOGFONT ) ) ;
# endif
defcodepage_set = false ;
uDefCodePage = CP_ACP ;
InitLangTables ( ) ;
// Register static user variables $0, $1 and so on
2013-03-27 02:50:27 +00:00
// with ONE of reference count, to avoid warning on these vars
2010-06-16 14:20:27 +00:00
TCHAR Aux [ 3 ] ;
int i ;
for ( i = 0 ; i < 10 ; i + + ) // 0 - 9
{
wsprintf ( Aux , _T ( " %d " ) , i ) ;
m_UserVarNames . add ( Aux , 1 ) ;
}
for ( i = 0 ; i < 10 ; i + + ) // 10 - 19
{
wsprintf ( Aux , _T ( " R%d " ) , i ) ;
m_UserVarNames . add ( Aux , 1 ) ;
}
m_UserVarNames . add ( _T ( " CMDLINE " ) , 1 ) ; // 20 everything before here doesn't have trailing slash removal
m_UserVarNames . add ( _T ( " INSTDIR " ) , 1 ) ; // 21
m_UserVarNames . add ( _T ( " OUTDIR " ) , 1 ) ; // 22
m_UserVarNames . add ( _T ( " EXEDIR " ) , 1 ) ; // 23
m_UserVarNames . add ( _T ( " LANGUAGE " ) , 1 ) ; // 24
m_UserVarNames . add ( _T ( " TEMP " ) , - 1 ) ; // 25
m_UserVarNames . add ( _T ( " PLUGINSDIR " ) , - 1 ) ; // 26
m_UserVarNames . add ( _T ( " EXEPATH " ) , - 1 ) ; // 27
m_UserVarNames . add ( _T ( " EXEFILE " ) , - 1 ) ; // 28
m_UserVarNames . add ( _T ( " HWNDPARENT " ) , - 1 ) ; // 29
m_UserVarNames . add ( _T ( " _CLICK " ) , - 1 ) ; // 30
2018-11-27 22:36:58 +00:00
m_UserVarNames . add ( _T ( " _OUTDIR " ) , 1 ) ; // 31 Note: nsDialogs also uses this
2010-06-16 14:20:27 +00:00
m_iBaseVarsNum = m_UserVarNames . getnum ( ) ;
m_ShellConstants . add ( _T ( " WINDIR " ) , CSIDL_WINDOWS , CSIDL_WINDOWS ) ;
m_ShellConstants . add ( _T ( " SYSDIR " ) , CSIDL_SYSTEM , CSIDL_SYSTEM ) ;
m_ShellConstants . add ( _T ( " SMPROGRAMS " ) , CSIDL_PROGRAMS , CSIDL_COMMON_PROGRAMS ) ;
m_ShellConstants . add ( _T ( " SMSTARTUP " ) , CSIDL_STARTUP , CSIDL_COMMON_STARTUP ) ;
m_ShellConstants . add ( _T ( " DESKTOP " ) , CSIDL_DESKTOPDIRECTORY , CSIDL_COMMON_DESKTOPDIRECTORY ) ;
m_ShellConstants . add ( _T ( " STARTMENU " ) , CSIDL_STARTMENU , CSIDL_COMMON_STARTMENU ) ;
m_ShellConstants . add ( _T ( " QUICKLAUNCH " ) , CSIDL_APPDATA , CSIDL_APPDATA ) ;
m_ShellConstants . add ( _T ( " DOCUMENTS " ) , CSIDL_PERSONAL , CSIDL_COMMON_DOCUMENTS ) ;
m_ShellConstants . add ( _T ( " SENDTO " ) , CSIDL_SENDTO , CSIDL_SENDTO ) ;
m_ShellConstants . add ( _T ( " RECENT " ) , CSIDL_RECENT , CSIDL_RECENT ) ;
m_ShellConstants . add ( _T ( " FAVORITES " ) , CSIDL_FAVORITES , CSIDL_COMMON_FAVORITES ) ;
m_ShellConstants . add ( _T ( " MUSIC " ) , CSIDL_MYMUSIC , CSIDL_COMMON_MUSIC ) ;
m_ShellConstants . add ( _T ( " PICTURES " ) , CSIDL_MYPICTURES , CSIDL_COMMON_PICTURES ) ;
m_ShellConstants . add ( _T ( " VIDEOS " ) , CSIDL_MYVIDEO , CSIDL_COMMON_VIDEO ) ;
m_ShellConstants . add ( _T ( " NETHOOD " ) , CSIDL_NETHOOD , CSIDL_NETHOOD ) ;
m_ShellConstants . add ( _T ( " FONTS " ) , CSIDL_FONTS , CSIDL_FONTS ) ;
m_ShellConstants . add ( _T ( " TEMPLATES " ) , CSIDL_TEMPLATES , CSIDL_COMMON_TEMPLATES ) ;
2017-06-23 12:59:44 +00:00
m_ShellConstants . add ( _T ( " APPDATA " ) , CSIDL_APPDATA , CSIDL_COMMON_APPDATA ) ; // Note: There is no all-users roaming appdata folder.
2017-06-23 01:11:30 +00:00
m_ShellConstants . add ( _T ( " LOCALAPPDATA " ) , CSIDL_LOCAL_APPDATA , CSIDL_COMMON_APPDATA ) ;
2010-06-16 14:20:27 +00:00
m_ShellConstants . add ( _T ( " PRINTHOOD " ) , CSIDL_PRINTHOOD , CSIDL_PRINTHOOD ) ;
//m_ShellConstants.add(_T("ALTSTARTUP"), CSIDL_ALTSTARTUP, CSIDL_COMMON_ALTSTARTUP);
m_ShellConstants . add ( _T ( " INTERNET_CACHE " ) , CSIDL_INTERNET_CACHE , CSIDL_INTERNET_CACHE ) ;
m_ShellConstants . add ( _T ( " COOKIES " ) , CSIDL_COOKIES , CSIDL_COOKIES ) ;
m_ShellConstants . add ( _T ( " HISTORY " ) , CSIDL_HISTORY , CSIDL_HISTORY ) ;
m_ShellConstants . add ( _T ( " PROFILE " ) , CSIDL_PROFILE , CSIDL_PROFILE ) ;
m_ShellConstants . add ( _T ( " ADMINTOOLS " ) , CSIDL_ADMINTOOLS , CSIDL_COMMON_ADMINTOOLS ) ;
m_ShellConstants . add ( _T ( " RESOURCES " ) , CSIDL_RESOURCES , CSIDL_RESOURCES ) ;
m_ShellConstants . add ( _T ( " RESOURCES_LOCALIZED " ) , CSIDL_RESOURCES_LOCALIZED , CSIDL_RESOURCES_LOCALIZED ) ;
m_ShellConstants . add ( _T ( " CDBURN_AREA " ) , CSIDL_CDBURN_AREA , CSIDL_CDBURN_AREA ) ;
2021-08-26 12:57:34 +00:00
// Contants that are not affected by SetShellVarContext
m_ShellConstants . add ( _T ( " USERAPPDATA " ) , CSIDL_APPDATA , CSIDL_APPDATA ) ;
m_ShellConstants . add ( _T ( " USERLOCALAPPDATA " ) , CSIDL_LOCAL_APPDATA , CSIDL_LOCAL_APPDATA ) ;
m_ShellConstants . add ( _T ( " USERTEMPLATES " ) , CSIDL_TEMPLATES , CSIDL_TEMPLATES ) ;
m_ShellConstants . add ( _T ( " USERSTARTMENU " ) , CSIDL_STARTMENU , CSIDL_STARTMENU ) ;
m_ShellConstants . add ( _T ( " USERSMPROGRAMS " ) , CSIDL_PROGRAMS , CSIDL_PROGRAMS ) ;
m_ShellConstants . add ( _T ( " USERDESKTOP " ) , CSIDL_DESKTOPDIRECTORY , CSIDL_DESKTOPDIRECTORY ) ;
m_ShellConstants . add ( _T ( " COMMONLOCALAPPDATA " ) , CSIDL_COMMON_APPDATA , CSIDL_COMMON_APPDATA ) ;
m_ShellConstants . add ( _T ( " COMMONPROGRAMDATA " ) , CSIDL_COMMON_APPDATA , CSIDL_COMMON_APPDATA ) ; // a.k.a. %ProgramData%
m_ShellConstants . add ( _T ( " COMMONTEMPLATES " ) , CSIDL_COMMON_TEMPLATES , CSIDL_COMMON_TEMPLATES ) ;
m_ShellConstants . add ( _T ( " COMMONSTARTMENU " ) , CSIDL_COMMON_STARTMENU , CSIDL_COMMON_STARTMENU ) ;
m_ShellConstants . add ( _T ( " COMMONSMPROGRAMS " ) , CSIDL_COMMON_PROGRAMS , CSIDL_COMMON_PROGRAMS ) ;
m_ShellConstants . add ( _T ( " COMMONDESKTOP " ) , CSIDL_COMMON_DESKTOPDIRECTORY , CSIDL_COMMON_DESKTOPDIRECTORY ) ;
2013-03-07 21:25:35 +00:00
// PROGRAMFILES&COMMONFILES does a registry lookup and the required string offsets are filled in later.
2017-06-04 22:48:13 +00:00
// We do this later because the unicode mode has to be locked when we call add_string...
2013-03-07 21:25:35 +00:00
m_ShellConstants . add ( _T ( " PROGRAMFILES " ) , 0 , 0 ) ;
m_ShellConstants . add ( _T ( " PROGRAMFILES32 " ) , 0 , 0 ) ;
m_ShellConstants . add ( _T ( " PROGRAMFILES64 " ) , 0 , 0 ) ;
m_ShellConstants . add ( _T ( " COMMONFILES " ) , 0 , 0 ) ;
m_ShellConstants . add ( _T ( " COMMONFILES32 " ) , 0 , 0 ) ;
m_ShellConstants . add ( _T ( " COMMONFILES64 " ) , 0 , 0 ) ;
2010-06-16 14:20:27 +00:00
set_uninstall_mode ( 0 ) ;
set_code_type_predefines ( ) ;
}
void CEXEBuild : : initialize ( const TCHAR * makensis_path )
{
tstring nsis_dir ;
const TCHAR * dir = _tgetenv ( _T ( " NSISDIR " ) ) ;
if ( dir ) nsis_dir = dir ;
else {
# ifndef NSIS_CONFIG_CONST_DATA_PATH
nsis_dir = get_dir_name ( get_executable_dir ( makensis_path ) ) ;
# else
2016-03-28 05:52:12 +00:00
nsis_dir = _T ( PREFIX_DATA ) ;
2010-06-16 14:20:27 +00:00
# endif
}
definedlist . add ( _T ( " NSISDIR " ) , nsis_dir . c_str ( ) ) ;
tstring includes_dir = nsis_dir ;
includes_dir + = PLATFORM_PATH_SEPARATOR_STR _T ( " Include " ) ;
include_dirs . add ( includes_dir . c_str ( ) , 0 ) ;
stubs_dir = nsis_dir ;
stubs_dir + = PLATFORM_PATH_SEPARATOR_STR _T ( " Stubs " ) ;
2014-02-08 00:13:52 +00:00
if ( set_compressor ( _T ( " zlib " ) , false ) ! = PS_OK | | set_target_architecture_data ( ) ! = PS_OK )
2010-06-16 14:20:27 +00:00
{
throw runtime_error ( " error setting default stub " ) ;
}
tstring uninst = stubs_dir + PLATFORM_PATH_SEPARATOR_STR + _T ( " uninst " ) ;
uninstaller_icon = load_icon_file ( uninst . c_str ( ) ) ;
2019-02-02 20:25:07 +00:00
changed_target = false ;
2010-06-16 14:20:27 +00:00
}
int CEXEBuild : : getcurdbsize ( ) { return cur_datablock - > getlen ( ) ; }
2013-03-07 21:25:35 +00:00
void CEXEBuild : : init_shellconstantvalues ( )
{
static bool done = false ;
2013-12-08 14:34:38 +00:00
if ( done ) return ; else done = true ;
2013-03-07 21:25:35 +00:00
2017-03-22 00:46:25 +00:00
const int orgunmode = uninstall_mode , t64 = is_target_64bit ( ) , reg = 0x80 , r32 = t64 ? 0xC0 : reg , r64 = r32 ^ 0x40 ;
2013-12-08 14:34:38 +00:00
set_uninstall_mode ( 0 ) ;
2013-03-07 21:25:35 +00:00
// Note: The order matters because some of the strings are preprocessed and cf must be <= 0x40
unsigned int pf = add_asciistring ( _T ( " ProgramFilesDir " ) , 0 ) ;
unsigned int cf = add_asciistring ( _T ( " CommonFilesDir " ) , 0 ) ;
2017-03-22 00:46:25 +00:00
unsigned int pf_def = add_asciistring ( _T ( " C: \\ Program Files " ) ) ; // Ultimate fallback
// TODO: 64-bit targets could use CSIDL_PROGRAM_FILES+CSIDL_PROGRAM_FILESX86?
m_ShellConstants . set_values ( _T ( " PROGRAMFILES " ) , reg | pf , pf_def ) ;
unsigned int pf_var = add_asciistring ( _T ( " $PROGRAMFILES " ) ) ; // Fallback for the 32/64 specific constants if the WOW registry view fails
m_ShellConstants . set_values ( _T ( " PROGRAMFILES32 " ) , r32 | pf , reg ! = r32 ? pf_var : pf_def ) ;
m_ShellConstants . set_values ( _T ( " PROGRAMFILES64 " ) , r64 | pf , reg ! = r64 ? pf_var : pf_def ) ;
2013-03-07 21:25:35 +00:00
unsigned int cf_def = add_asciistring ( _T ( " $PROGRAMFILES \\ Common Files " ) ) ;
2017-03-22 00:46:25 +00:00
m_ShellConstants . set_values ( _T ( " COMMONFILES " ) , reg | cf , cf_def ) ;
unsigned int cf_var = add_asciistring ( _T ( " $COMMONFILES " ) ) ;
m_ShellConstants . set_values ( _T ( " COMMONFILES32 " ) , r32 | cf , reg ! = r32 ? cf_var : cf_def ) ;
m_ShellConstants . set_values ( _T ( " COMMONFILES64 " ) , r64 | cf , reg ! = r64 ? cf_var : cf_def ) ;
2013-03-07 21:25:35 +00:00
2017-03-22 00:46:25 +00:00
if ( ( pf > = 0x40 | | pf_def > = 0xFF | | pf_var > 0xFF ) // BUGBUG: pf_def should be ">"?
| | ( cf > 0x40 | | cf_def > 0xFF | | cf_var > 0xFF ) )
2013-03-07 21:25:35 +00:00
{
// see Source\exehead\util.c for implementation details
// basically, it knows it needs to get folders from the registry when the 0x80 is on
2014-03-09 23:23:19 +00:00
const char * msg = " Internal compiler error: too many strings added to strings block before adding shell constants! " ;
2015-09-17 14:30:07 +00:00
ERROR_MSG ( _T ( " % " ) NPRIns , msg ) ;
2014-03-09 23:23:19 +00:00
throw out_of_range ( msg ) ;
2013-03-07 21:25:35 +00:00
}
set_uninstall_mode ( 1 ) ;
unsigned int unpf = add_asciistring ( _T ( " ProgramFilesDir " ) , 0 ) ;
unsigned int uncf = add_asciistring ( _T ( " CommonFilesDir " ) , 0 ) ;
unsigned int unpf_def = add_asciistring ( _T ( " C: \\ Program Files " ) ) ;
2017-03-22 00:46:25 +00:00
unsigned int unpf_var = add_asciistring ( _T ( " $PROGRAMFILES " ) ) ;
2013-03-07 21:25:35 +00:00
unsigned int uncf_def = add_asciistring ( _T ( " $PROGRAMFILES \\ Common Files " ) ) ;
2017-03-22 00:46:25 +00:00
unsigned int uncf_var = add_asciistring ( _T ( " $COMMONFILES " ) ) ;
2013-03-07 21:25:35 +00:00
set_uninstall_mode ( orgunmode ) ;
2017-03-22 00:46:25 +00:00
if ( unpf ! = pf | | unpf_def ! = pf_def | | unpf_var ! = pf_var
| | uncf ! = cf | | uncf_def ! = cf_def | | uncf_var ! = cf_var )
2013-03-07 21:25:35 +00:00
{
2014-03-09 23:23:19 +00:00
const char * msg = " Internal compiler error: installer's shell constants are different than uninstallers! " ;
2015-09-17 14:30:07 +00:00
ERROR_MSG ( _T ( " % " ) NPRIns , msg ) ;
2014-03-09 23:23:19 +00:00
throw out_of_range ( msg ) ;
2013-03-07 21:25:35 +00:00
}
}
2010-06-16 14:20:27 +00:00
// returns offset in stringblock
2013-03-07 21:25:35 +00:00
int CEXEBuild : : add_string ( const TCHAR * string , int process /*=1*/ , UINT codepage /*=-2*/ )
2010-06-16 14:20:27 +00:00
{
if ( ! string | | ! * string ) return 0 ;
2013-03-07 21:25:35 +00:00
build_lockedunicodetarget = true ;
init_shellconstantvalues ( ) ;
2013-12-08 14:34:38 +00:00
if ( ( UINT ) - 2 = = codepage )
2013-03-07 21:25:35 +00:00
{
2013-05-04 13:32:47 +00:00
codepage = curlinereader ? curlinereader - > StreamEncoding ( ) . GetCodepage ( ) : CP_UTF8 ;
2013-03-07 21:25:35 +00:00
// If the current source file is Unicode we have to pick a real codepage for ANSI!
2015-09-18 23:16:34 +00:00
// It might not be the correct codepage but it's the best we can do.
2013-03-07 21:25:35 +00:00
// Not using CP_ACP to avoid heisenbugs when compiled on a different system.
if ( NStreamEncoding : : IsUnicodeCodepage ( codepage ) ) codepage = 1252 ;
}
if ( * string = = _T ( ' $ ' ) & & * ( string + 1 ) = = _T ( ' ( ' ) )
{
2010-06-16 14:20:27 +00:00
int idx = 0 ;
TCHAR * cp = _tcsdup ( string + 2 ) ;
TCHAR * p = _tcschr ( cp , _T ( ' ) ' ) ) ;
if ( p & & p [ 1 ] = = _T ( ' \0 ' ) ) { // if string is only a language str identifier
* p = 0 ;
idx = DefineLangString ( cp , process ) ;
}
free ( cp ) ;
if ( idx < 0 ) return idx ;
}
2013-03-07 21:25:35 +00:00
int i ;
if ( process )
{
2013-03-10 22:26:27 +00:00
ExpandoString < TCHAR , NSIS_MAX_STRLEN * 4 > buf ;
// NOTE: It is impossible to know how much preprocessing will increase the size, we have to guess
buf . Reserve ( _tcsclen ( string ) * 2 ) ;
2013-12-08 14:34:38 +00:00
preprocess_string ( buf , string , codepage ) ; // BUGBUG: This could overflow buf
2013-03-07 21:25:35 +00:00
i = cur_strlist - > add ( buf , ( WORD ) codepage , true ) ;
}
else
i = cur_strlist - > add ( string , ( WORD ) codepage , false ) ;
return i ;
}
2010-06-16 14:20:27 +00:00
2013-03-07 21:25:35 +00:00
int CEXEBuild : : add_asciistring ( const TCHAR * string , int process /*=1*/ )
{
return add_string ( string , process , 1252 ) ;
2010-06-16 14:20:27 +00:00
}
int CEXEBuild : : add_intstring ( const int i ) // returns offset in stringblock
{
2013-03-07 21:25:35 +00:00
TCHAR buf [ 32 ] ;
wsprintf ( buf , _T ( " %d " ) , i ) ;
return add_asciistring ( buf , false ) ;
2010-06-16 14:20:27 +00:00
}
# ifdef _UNICODE
char * convert_processed_string_to_ansi ( char * out , const TCHAR * in , WORD codepage )
{
const TCHAR * p = in ;
for ( ; ; )
{
_TUCHAR i = ( _TUCHAR ) * p + + ;
2011-09-23 17:36:30 +00:00
if ( NS_IS_CODE ( i ) ) // Note: this includes '\0'
2010-06-16 14:20:27 +00:00
{
// convert all character up to, and including this code
2014-02-11 01:34:11 +00:00
int c = ( int ) ( p - in ) , cb = WideCharToMultiByte ( codepage , 0 , in , c , out , c * 2 , NULL , NULL ) ;
2013-03-07 21:25:35 +00:00
if ( ! cb & & i ) return 0 ;
2010-06-16 14:20:27 +00:00
out + = cb ;
if ( i = = _T ( ' \0 ' ) )
break ;
else if ( i = = NS_SKIP_CODE )
2014-05-13 15:51:45 +00:00
// BUGBUG: Shouldn't the escaped code be converted from wchar_t to codepage as well?
2010-06-16 14:20:27 +00:00
* out + + = ( char ) * in + + ; // simply copy escaped code (01..04)
else
{
WORD w = * p + + ; // special NSIS code is following by a WORD we need to output unchanged
* out + + = LOBYTE ( w ) ;
* out + + = HIBYTE ( w ) ;
}
in = p ;
}
}
return out ;
}
# endif
// based on Dave Laundon's code
int CEXEBuild : : preprocess_string ( TCHAR * out , const TCHAR * in , WORD codepage /*=CP_ACP*/ )
{
const TCHAR * p = in ;
while ( * p )
{
const TCHAR * np ;
# ifdef _UNICODE
np = CharNext ( p ) ;
# else
np = CharNextExA ( codepage , p , 0 ) ;
# endif
if ( np - p > 1 ) // multibyte TCHAR
{
2014-02-11 01:34:11 +00:00
size_t len = np - p ;
while ( len - - )
2010-06-16 14:20:27 +00:00
{
_TUCHAR i = ( _TUCHAR ) * p + + ;
if ( NS_IS_CODE ( i ) ) {
* out + + = ( TCHAR ) NS_SKIP_CODE ;
}
* out + + = ( TCHAR ) i ;
}
continue ;
}
_TUCHAR i = ( _TUCHAR ) * p ;
p = np ; // increment p.
// Test for characters extending into the variable codes
if ( NS_IS_CODE ( i ) ) {
* out + + = ( TCHAR ) NS_SKIP_CODE ;
// out does get the NS_CODE as well because of
// "*out++=(TCHAR)i" at the end.
}
else if ( i = = _T ( ' $ ' ) )
{
if ( * p = = _T ( ' $ ' ) )
p + + ; // Can simply convert $$ to $ now
else
{
// starts with a $ but not $$.
2014-06-15 13:58:04 +00:00
bool bProceced = false ;
2015-09-17 14:30:07 +00:00
if ( * p )
2014-06-15 13:58:04 +00:00
{
const TCHAR * pUserVarName = p ;
while ( isSimpleChar ( * pUserVarName ) )
pUserVarName + + ;
while ( pUserVarName > p )
2010-06-16 14:20:27 +00:00
{
2015-09-17 14:30:07 +00:00
if ( m_ShellConstants . get ( p , truncate_cast ( int , ( size_t ) ( pUserVarName - p ) ) ) > = 0 )
2014-06-15 13:58:04 +00:00
break ; // Woops it's a shell constant
2010-06-16 14:20:27 +00:00
2015-09-17 14:30:07 +00:00
int idxUserVar = m_UserVarNames . get ( p , truncate_cast ( int , ( size_t ) ( pUserVarName - p ) ) ) ;
2014-06-15 13:58:04 +00:00
if ( idxUserVar > = 0 )
2010-06-16 14:20:27 +00:00
{
2014-06-15 13:58:04 +00:00
// Well, using variables inside string formating doens't mean
// using the variable, because it will be always an empty string
// which is also memory wasting
// So the line below must be commented !??
//m_UserVarNames.inc_reference(idxUserVar);
* out + + = ( TCHAR ) NS_VAR_CODE ; // Named user variable;
WORD w = FIX_ENDIAN_INT16 ( CODE_SHORT ( idxUserVar ) ) ;
unsigned int w4 = sizeof ( TCHAR ) > 2 ? FIX_ENDIAN_INT32 ( CODE_SHORT ( idxUserVar ) ) : w ; // Maybe this is too much endian fixing?
if ( sizeof ( TCHAR ) < 2 ) * ( ( WORD * ) out ) = w , out + = 2 ; else * out = ( TCHAR ) w4 , out + + ;
p + = pUserVarName - p ; // zip past the user var string.
bProceced = true ;
break ;
2010-06-16 14:20:27 +00:00
}
2014-06-15 13:58:04 +00:00
pUserVarName - - ;
}
} // if ( *p )
if ( ! bProceced & & * p )
{
const TCHAR * pShellConstName = p ;
while ( isSimpleChar ( * pShellConstName ) )
pShellConstName + + ;
while ( pShellConstName > p )
2010-06-16 14:20:27 +00:00
{
2014-06-15 13:58:04 +00:00
// Look for the identifier in the shell constants list of strings.
2015-09-17 14:30:07 +00:00
int idxConst = m_ShellConstants . get ( ( TCHAR * ) p , truncate_cast ( int , ( size_t ) ( pShellConstName - p ) ) ) ;
2010-06-16 14:20:27 +00:00
2014-06-15 13:58:04 +00:00
// If found...
if ( idxConst > = 0 )
2010-06-16 14:20:27 +00:00
{
2014-06-15 13:58:04 +00:00
init_shellconstantvalues ( ) ;
int CSIDL_Value_current = m_ShellConstants . get_value1 ( idxConst ) ;
int CSIDL_Value_all = m_ShellConstants . get_value2 ( idxConst ) ;
* out + + = ( TCHAR ) NS_SHELL_CODE ; // Constant code identifier
2010-06-16 14:20:27 +00:00
# ifdef _UNICODE
2014-06-15 13:58:04 +00:00
* out + + = MAKEWORD ( CSIDL_Value_current , CSIDL_Value_all ) ;
2010-06-16 14:20:27 +00:00
# else
2014-06-15 13:58:04 +00:00
* out + + = ( TCHAR ) CSIDL_Value_current ;
* out + + = ( TCHAR ) CSIDL_Value_all ;
2010-06-16 14:20:27 +00:00
# endif
2014-06-15 13:58:04 +00:00
p = pShellConstName ; // zip past the shell constant string.
bProceced = true ;
break ;
2010-06-16 14:20:27 +00:00
}
2014-06-15 13:58:04 +00:00
// We are looking from the longest identifier first and work
// smaller.
pShellConstName - - ;
2010-06-16 14:20:27 +00:00
}
2014-06-15 13:58:04 +00:00
}
if ( ! bProceced & & * p = = _T ( ' ( ' ) )
{
int idx = - 1 ;
TCHAR * cp = _tcsdup ( p + 1 ) ; // JP: Bad... should avoid memory alloc.
TCHAR * pos = _tcschr ( cp , _T ( ' ) ' ) ) ;
if ( pos )
2010-06-16 14:20:27 +00:00
{
2014-06-15 13:58:04 +00:00
* pos = 0 ;
idx = DefineLangString ( cp ) ;
if ( idx < 0 )
2010-06-16 14:20:27 +00:00
{
2014-06-15 13:58:04 +00:00
* out + + = ( TCHAR ) NS_LANG_CODE ; // Next word is lang-string Identifier
WORD w = FIX_ENDIAN_INT16 ( CODE_SHORT ( - idx - 1 ) ) ;
unsigned int w4 = sizeof ( TCHAR ) > 2 ? FIX_ENDIAN_INT32 ( CODE_SHORT ( - idx - 1 ) ) : w ; // Maybe this is too much endian fixing?
if ( sizeof ( TCHAR ) < 2 ) * ( ( WORD * ) out ) = w , out + = 2 ; else * out = ( TCHAR ) w4 , out + + ;
p + = _tcslen ( cp ) + 2 ;
bProceced = true ;
2010-06-16 14:20:27 +00:00
}
}
2014-06-15 13:58:04 +00:00
free ( cp ) ;
}
if ( bProceced )
continue ; // outermost while
else
{
TCHAR tbuf [ 64 ] , cBracket = _T ( ' \0 ' ) ;
bool bDoWarning = true ;
2010-06-16 14:20:27 +00:00
2014-06-15 13:58:04 +00:00
if ( * p = = _T ( ' [ ' ) ) cBracket = _T ( ' ] ' ) ;
else if ( * p = = _T ( ' ( ' ) ) cBracket = _T ( ' ) ' ) ;
else if ( * p = = _T ( ' { ' ) ) cBracket = _T ( ' } ' ) ;
2010-06-16 14:20:27 +00:00
2014-06-15 13:58:04 +00:00
my_strncpy ( tbuf , p , COUNTOF ( tbuf ) ) ;
2010-06-16 14:20:27 +00:00
2014-06-15 13:58:04 +00:00
if ( cBracket ! = 0 )
{
if ( _tcschr ( tbuf , cBracket ) ) ( _tcschr ( tbuf , cBracket ) + 1 ) [ 0 ] = 0 ;
if ( tbuf [ 0 ] = = _T ( ' { ' ) & & tbuf [ _tcslen ( tbuf ) - 1 ] = = _T ( ' } ' ) )
2010-06-16 14:20:27 +00:00
{
2014-06-15 13:58:04 +00:00
TCHAR * tstIfDefine = _tcsdup ( tbuf + 1 ) ;
tstIfDefine [ _tcslen ( tstIfDefine ) - 1 ] = _T ( ' \0 ' ) ;
bDoWarning = definedlist . find ( tstIfDefine ) = = NULL ;
// If it's a defined identifier, then don't warn.
2010-06-16 14:20:27 +00:00
}
}
2014-06-15 13:58:04 +00:00
else
{
if ( _tcsstr ( tbuf , _T ( " " ) ) ) _tcsstr ( tbuf , _T ( " " ) ) [ 0 ] = 0 ;
}
if ( bDoWarning )
2017-04-25 13:09:41 +00:00
warning_fl ( DW_VAR_IGNORED_UNKNOWN , _T ( " unknown variable/constant \" % " ) NPRIs _T ( " \" detected, ignoring " ) , tbuf ) ;
2014-06-15 13:58:04 +00:00
i = _T ( ' $ ' ) ; // redundant since i is already '$' and has not changed.
}
2010-06-16 14:20:27 +00:00
} // else
} // else if (i == _T('$'))
* out + + = ( TCHAR ) i ;
} // outside while
* out = 0 ;
return 0 ;
}
// what it does is, when you pass it the offset of the last item added, it will determine if
// that data is already present in the datablock, and if so, reference it instead (and shorten
// the datablock as necessary). Reduces overhead if you want to add files to a couple places.
// Woo, an optimizing installer generator, now we're styling.
int CEXEBuild : : datablock_optimize ( int start_offset , int first_int )
{
int this_len = cur_datablock - > getlen ( ) - start_offset ;
cached_db_size this_size = { first_int , start_offset } ;
this - > cur_datablock_cache - > add ( & this_size , sizeof ( cached_db_size ) ) ;
if ( ! this - > build_optimize_datablock | | this_len < ( int ) sizeof ( int ) )
return start_offset ;
2014-06-20 18:36:05 +00:00
# ifdef DEBUG
assert ( dynamic_cast < MMapBuf * > ( cur_datablock ) ) ;
# endif
MMapBuf * db = static_cast < MMapBuf * > ( cur_datablock ) ;
2010-06-16 14:20:27 +00:00
db - > setro ( TRUE ) ;
cached_db_size * db_sizes = ( cached_db_size * ) this - > cur_datablock_cache - > get ( ) ;
int db_sizes_num = this - > cur_datablock_cache - > getlen ( ) / sizeof ( cached_db_size ) ;
db_sizes_num - - ; // don't compare with the one we just added
for ( int i = 0 ; i < db_sizes_num ; i + + )
{
if ( db_sizes [ i ] . first_int = = first_int )
{
int pos = db_sizes [ i ] . start_offset ;
int left = this_len ;
while ( left > 0 )
{
int l = min ( left , build_filebuflen ) ;
void * newstuff = db - > get ( start_offset + this_len - left , l ) ;
void * oldstuff = db - > getmore ( pos + this_len - left , l ) ;
int res = memcmp ( newstuff , oldstuff , l ) ;
db - > release ( oldstuff , l ) ;
db - > release ( ) ;
2014-03-30 03:25:52 +00:00
if ( res ) break ;
2010-06-16 14:20:27 +00:00
left - = l ;
}
if ( ! left )
{
db_opt_save + = this_len ;
db - > resize ( max ( start_offset , pos + this_len ) ) ;
db - > setro ( FALSE ) ;
this - > cur_datablock_cache - > resize ( cur_datablock_cache - > getlen ( ) - sizeof ( cached_db_size ) ) ;
return pos ;
}
}
}
db - > setro ( FALSE ) ;
return start_offset ;
}
2014-03-30 03:25:52 +00:00
bool CEXEBuild : : datablock_finddata ( IMMap & mmap , int mmstart , int size , int * ofs )
{
const int first_int = size ;
size & = ~ 0x80000000 ;
2014-06-20 18:36:05 +00:00
# ifdef DEBUG
assert ( dynamic_cast < MMapBuf * > ( cur_datablock ) ) ;
# endif
MMapBuf * db = static_cast < MMapBuf * > ( cur_datablock ) ;
2014-03-30 03:25:52 +00:00
cached_db_size * db_sizes = ( cached_db_size * ) this - > cur_datablock_cache - > get ( ) ;
int db_sizes_num = this - > cur_datablock_cache - > getlen ( ) / sizeof ( cached_db_size ) ;
for ( int i = 0 ; i < db_sizes_num ; i + + )
{
if ( db_sizes [ i ] . first_int ! = first_int ) continue ;
int left = size , oldpos = db_sizes [ i ] . start_offset ;
while ( left > 0 )
{
int cbCmp = min ( left , build_filebuflen ) ;
void * newstuff = mmap . get ( mmstart + size - left , cbCmp ) ;
void * oldstuff = db - > get ( sizeof ( int ) + oldpos + size - left , cbCmp ) ;
int res = memcmp ( newstuff , oldstuff , cbCmp ) ;
mmap . release ( ) , db - > release ( ) ;
if ( res ) break ;
left - = cbCmp ;
}
if ( ! left )
{
if ( ofs ) * ofs = oldpos ;
return true ;
}
}
return false ;
}
2010-06-16 14:20:27 +00:00
int CEXEBuild : : add_db_data ( IMMap * mmap ) // returns offset
{
build_compressor_set = true ;
int done = 0 ;
if ( ! mmap )
{
ERROR_MSG ( _T ( " Error: add_db_data() called with invalid mapped file \n " ) ) ;
return - 1 ;
}
int length = mmap - > getsize ( ) ;
if ( length < 0 )
{
ERROR_MSG ( _T ( " Error: add_db_data() called with length=%d \n " ) , length ) ;
return - 1 ;
}
// Jim Park: This kind of stuff looks scary and it is. cur_datablock is
// most likely to point to a MMapBuf type right now so it works.
MMapBuf * db = ( MMapBuf * ) this - > cur_datablock ;
int st = db - > getlen ( ) ;
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
if ( length & & ! build_compress_whole & & build_compress )
{
// grow datablock so that there is room to compress into
int bufferlen = length + 1024 + length / 4 ; // give a nice 25% extra space
2014-03-31 17:34:58 +00:00
if ( st + bufferlen + ( signed ) sizeof ( int ) < 0 ) // we've hit a signed integer overflow (file is over 1.6 GB)
bufferlen = INT_MAX - st - sizeof ( int ) ; // so maximize compressor room and hope the file compresses well
2010-06-16 14:20:27 +00:00
db - > resize ( st + bufferlen + sizeof ( int ) ) ;
int n = compressor - > Init ( build_compress_level , build_compress_dict_size ) ;
if ( n ! = C_OK )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Internal compiler error #12345: deflateInit() failed(% " ) NPRIs _T ( " [%d]). \n " ) , compressor - > GetErrStr ( n ) , n ) ;
2010-06-16 14:20:27 +00:00
extern void quit ( ) ; quit ( ) ;
}
int avail_in = length ;
int avail_out = bufferlen ;
int ret ;
while ( avail_in > 0 )
{
int in_len = min ( this - > build_filebuflen , avail_in ) ;
int out_len = min ( this - > build_filebuflen , avail_out ) ;
compressor - > SetNextIn ( ( char * ) mmap - > get ( length - avail_in , in_len ) , in_len ) ;
compressor - > SetNextOut ( ( char * ) db - > get ( st + sizeof ( int ) + bufferlen - avail_out , out_len ) , out_len ) ;
if ( ( ret = compressor - > Compress ( 0 ) ) < 0 )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: add_db_data() - compress() failed(% " ) NPRIs _T ( " [%d]) \n " ) , compressor - > GetErrStr ( ret ) , ret ) ;
2010-06-16 14:20:27 +00:00
return - 1 ;
}
mmap - > release ( ) ;
db - > flush ( out_len ) ;
db - > release ( ) ;
avail_in - = in_len - compressor - > GetAvailIn ( ) ;
avail_out - = out_len - compressor - > GetAvailOut ( ) ;
if ( ! avail_out )
// not enough space in the output buffer - no compression is better
break ;
}
// if not enough space in the output buffer - no compression is better
if ( avail_out )
{
char * out ;
char a ;
compressor - > SetNextIn ( & a , 0 ) ;
do
{
int out_len = min ( build_filebuflen , avail_out ) ;
out = ( char * ) db - > get ( st + sizeof ( int ) + bufferlen - avail_out , out_len ) ;
compressor - > SetNextOut ( out , out_len ) ;
if ( ( ret = compressor - > Compress ( C_FINISH ) ) < 0 )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: add_db_data() - compress() failed(% " ) NPRIs _T ( " [%d]) \n " ) , compressor - > GetErrStr ( ret ) , ret ) ;
2010-06-16 14:20:27 +00:00
return - 1 ;
}
db - > flush ( out_len ) ;
db - > release ( ) ;
avail_out - = out_len - compressor - > GetAvailOut ( ) ;
}
while ( compressor - > GetNextOut ( ) - out > 0 & & avail_out > 0 ) ;
compressor - > End ( ) ;
int used = bufferlen - avail_out ;
// never store compressed if output buffer is full (compression increased the size...)
if ( avail_out & & ( build_compress = = 2 | | used < length ) )
{
done = 1 ;
db - > resize ( st + used + sizeof ( int ) ) ;
* ( int * ) db - > get ( st , sizeof ( int ) ) = FIX_ENDIAN_INT32 ( used | 0x80000000 ) ;
db - > release ( ) ;
int nst = datablock_optimize ( st , used | 0x80000000 ) ;
if ( nst = = st ) db_comp_save + = length - used ;
else st = nst ;
}
}
else
compressor - > End ( ) ;
}
# endif // NSIS_CONFIG_COMPRESSION_SUPPORT
if ( ! done )
{
2014-03-30 03:25:52 +00:00
// Adding the same file twice can push cur_datablock over the limit
// because datablock_optimize() happens too late. Let's try to find a dupe early.
2014-03-31 17:34:58 +00:00
if ( this - > build_optimize_datablock & & st + length < 0 )
2014-03-30 03:25:52 +00:00
{
int oldst ;
2014-03-31 17:34:58 +00:00
if ( datablock_finddata ( * mmap , 0 , length , & oldst ) )
2014-04-05 16:50:11 +00:00
return ( db_full_size + = length , db_opt_save + = length , oldst ) ;
2014-03-30 03:25:52 +00:00
}
db - > resize ( st + sizeof ( int ) + length ) ;
2010-06-16 14:20:27 +00:00
int * plen = ( int * ) db - > get ( st , sizeof ( int ) ) ;
* plen = FIX_ENDIAN_INT32 ( length ) ;
db - > release ( ) ;
int left = length ;
while ( left > 0 )
{
int l = min ( build_filebuflen , left ) ;
int * p = ( int * ) db - > get ( st + sizeof ( int ) + length - left , l ) ;
memcpy ( p , mmap - > get ( length - left , l ) , l ) ;
db - > flush ( l ) ;
db - > release ( ) ;
mmap - > release ( ) ;
left - = l ;
}
st = datablock_optimize ( st , length ) ;
}
db_full_size + = length + sizeof ( int ) ;
return st ;
}
int CEXEBuild : : add_db_data ( const char * data , int length ) // returns offset
{
MMapFake fakemap ;
fakemap . set ( data , length ) ;
return add_db_data ( & fakemap ) ;
}
int CEXEBuild : : add_data ( const char * data , int length , IGrowBuf * dblock ) // returns offset
{
build_compressor_set = true ;
int done = 0 ;
if ( length < 0 )
{
ERROR_MSG ( _T ( " Error: add_data() called with length=%d \n " ) , length ) ;
return - 1 ;
}
int st = dblock - > getlen ( ) ;
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
if ( ! build_compress_whole & & build_compress )
{
// grow datablock so that there is room to compress into
int bufferlen = length + 1024 + length / 4 ; // give a nice 25% extra space
dblock - > resize ( st + bufferlen + sizeof ( int ) ) ;
int n = compressor - > Init ( build_compress_level , build_compress_dict_size ) ;
if ( n ! = C_OK )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Internal compiler error #12345: deflateInit() failed(% " ) NPRIs _T ( " [%d]). \n " ) , compressor - > GetErrStr ( n ) , n ) ;
2010-06-16 14:20:27 +00:00
extern void quit ( ) ; quit ( ) ;
}
compressor - > SetNextIn ( ( char * ) data , length ) ;
compressor - > SetNextOut ( ( char * ) dblock - > get ( ) + st + sizeof ( int ) , bufferlen ) ;
compressor - > Compress ( C_FINISH ) ;
int used = bufferlen - compressor - > GetAvailOut ( ) ;
// never store compressed if output buffer is full
if ( compressor - > GetAvailOut ( ) & & ( build_compress = = 2 | | used < length ) )
{
done = 1 ;
dblock - > resize ( st + used + sizeof ( int ) ) ;
* ( ( int * ) ( ( char * ) dblock - > get ( ) + st ) ) = FIX_ENDIAN_INT32 ( used | 0x80000000 ) ;
}
compressor - > End ( ) ;
}
# endif // NSIS_CONFIG_COMPRESSION_SUPPORT
if ( ! done )
{
dblock - > resize ( st ) ;
int rl = FIX_ENDIAN_INT32 ( length ) ;
dblock - > add ( & rl , sizeof ( int ) ) ;
dblock - > add ( data , length ) ;
}
return st ;
}
int CEXEBuild : : add_label ( const TCHAR * name )
{
if ( ! build_cursection )
{
ERROR_MSG ( _T ( " Error: Label declaration not valid outside of function/section \n " ) ) ;
return PS_ERROR ;
}
if ( ( name [ 0 ] > = _T ( ' 0 ' ) & & name [ 0 ] < = _T ( ' 9 ' ) ) | | name [ 0 ] = = _T ( ' - ' ) | | name [ 0 ] = = _T ( ' ' ) | | name [ 0 ] = = _T ( ' : ' ) )
{
ERROR_MSG ( _T ( " Error: labels must not begin with 0-9, -, :, or a space. \n " ) ) ;
return PS_ERROR ;
}
int cs = build_cursection - > code ;
int ce = cs + build_cursection - > code_size ;
TCHAR * p = _tcsdup ( name ) ;
if ( p [ _tcslen ( p ) - 1 ] = = _T ( ' : ' ) ) p [ _tcslen ( p ) - 1 ] = 0 ;
int offs = ns_label . add ( p , 0 ) ;
free ( p ) ;
int n = cur_labels - > getlen ( ) / sizeof ( section ) ;
// Check to see if the label already exists.
if ( n )
{
section * t = ( section * ) cur_labels - > get ( ) ;
while ( n - - )
{
// Labels beginning with '.' are global and can be jumped to from any function or section.
if ( ( * name = = _T ( ' . ' ) | | ( t - > code > = cs & & t - > code < = ce ) ) & &
t - > name_ptr = = offs )
{
2013-12-08 14:34:38 +00:00
if ( * name = = _T ( ' . ' ) ) ERROR_MSG ( _T ( " Error: global label \" % " ) NPRIs _T ( " \" already declared \n " ) , name ) ;
2010-06-16 14:20:27 +00:00
else
{
const TCHAR * szType = _T ( " section " ) ;
if ( build_cursection_isfunc )
szType = _T ( " function " ) ;
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: label \" % " ) NPRIs _T ( " \" already declared in % " ) NPRIs _T ( " \n " ) , name , szType ) ;
2010-06-16 14:20:27 +00:00
}
return PS_ERROR ;
}
t + + ;
}
}
section s = { 0 } ;
s . name_ptr = offs ;
s . code = ce ;
cur_labels - > add ( & s , sizeof ( s ) ) ;
return PS_OK ;
}
int CEXEBuild : : add_function ( const TCHAR * funname )
{
if ( build_cursection_isfunc )
{
ERROR_MSG ( _T ( " Error: Function open when creating function (use FunctionEnd first) \n " ) ) ;
return PS_ERROR ;
}
if ( build_cursection )
{
ERROR_MSG ( _T ( " Error: Section open when creating function (use SectionEnd first) \n " ) ) ;
return PS_ERROR ;
}
if ( cur_page )
{
ERROR_MSG ( _T ( " Error: PageEx open when creating function (use PageExEnd first) \n " ) ) ;
return PS_ERROR ;
}
if ( ! funname [ 0 ] )
{
ERROR_MSG ( _T ( " Error: Function must have a name \n " ) ) ;
return PS_ERROR ;
}
set_uninstall_mode ( ! _tcsnicmp ( funname , _T ( " un. " ) , 3 ) ) ;
// ns_func contains all the function names defined.
int addr = ns_func . add ( funname , 0 ) ;
2015-09-17 14:30:07 +00:00
int n = cur_functions - > getlen ( ) / sizeof ( section ) , x ;
2010-06-16 14:20:27 +00:00
section * tmp = ( section * ) cur_functions - > get ( ) ;
for ( x = 0 ; x < n ; x + + )
{
if ( tmp [ x ] . name_ptr = = addr )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: Function named \" % " ) NPRIs _T ( " \" already exists. \n " ) , funname ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
}
cur_functions - > resize ( ( n + 1 ) * sizeof ( section ) ) ;
build_cursection = ( ( section * ) cur_functions - > get ( ) ) + n ;
build_cursection_isfunc = 1 ;
build_cursection - > name_ptr = addr ;
build_cursection - > code = cur_entries - > getlen ( ) / sizeof ( entry ) ;
build_cursection - > code_size = 0 ;
build_cursection - > install_types = 0 ;
build_cursection - > flags = 0 ;
build_cursection - > size_kb = 0 ;
memset ( build_cursection - > name , 0 , sizeof ( build_cursection - > name ) ) ;
if ( uninstall_mode )
set_code_type_predefines ( funname + 3 ) ;
else
set_code_type_predefines ( funname ) ;
return PS_OK ;
}
int CEXEBuild : : function_end ( )
{
if ( ! build_cursection_isfunc )
{
ERROR_MSG ( _T ( " Error: No function open, FunctionEnd called \n " ) ) ;
return PS_ERROR ;
}
// add ret.
add_entry_direct ( EW_RET ) ;
build_cursection_isfunc = 0 ;
build_cursection = NULL ;
set_uninstall_mode ( 0 ) ;
set_code_type_predefines ( ) ;
return PS_OK ;
}
int CEXEBuild : : section_add_flags ( int flags )
{
if ( ! build_cursection | | build_cursection_isfunc )
{
ERROR_MSG ( _T ( " Error: can't modify flags when no section is open \n " ) ) ;
return PS_ERROR ;
}
build_cursection - > flags | = flags ;
return PS_OK ;
}
int CEXEBuild : : section_add_install_type ( int inst_type )
{
if ( ! build_cursection | | build_cursection_isfunc )
{
ERROR_MSG ( _T ( " Error: can't modify flags when no section is open \n " ) ) ;
return PS_ERROR ;
}
if ( build_cursection - > install_types = = ~ 0 )
build_cursection - > install_types = 0 ;
build_cursection - > install_types | = inst_type ;
return PS_OK ;
}
void CEXEBuild : : section_add_size_kb ( int kb )
{
if ( build_cursection )
{
build_cursection - > size_kb + = kb ;
}
}
int CEXEBuild : : section_end ( )
{
if ( build_cursection_isfunc )
{
ERROR_MSG ( _T ( " Error: SectionEnd specified in function (not section) \n " ) ) ;
return PS_ERROR ;
}
if ( ! build_cursection )
{
ERROR_MSG ( _T ( " Error: SectionEnd specified and no sections open \n " ) ) ;
return PS_ERROR ;
}
add_entry_direct ( EW_RET ) ;
build_cursection - > code_size - - ;
build_cursection = NULL ;
if ( ! sectiongroup_open_cnt )
set_uninstall_mode ( 0 ) ;
set_code_type_predefines ( ) ;
return PS_OK ;
}
int CEXEBuild : : add_section ( const TCHAR * secname , const TCHAR * defname , int expand /*=0*/ )
{
if ( build_cursection_isfunc )
{
ERROR_MSG ( _T ( " Error: Section can't create section (already in function, use FunctionEnd first) \n " ) ) ;
return PS_ERROR ;
}
if ( cur_page ) {
ERROR_MSG ( _T ( " Error: PageEx already open, call PageExEnd first \n " ) ) ;
return PS_ERROR ;
}
if ( build_cursection )
{
ERROR_MSG ( _T ( " Error: Section already open, call SectionEnd first \n " ) ) ;
return PS_ERROR ;
}
section new_section ;
new_section . flags = SF_SELECTED ;
new_section . flags | = expand ? SF_EXPAND : 0 ;
new_section . code_size = 0 ;
new_section . size_kb = 0 ;
TCHAR * name = ( TCHAR * ) secname ;
2010-06-16 16:01:40 +00:00
if ( name [ 0 ] = = _T ( ' \x1F ' ) ) // SectionGroup/SectionGroupEnd
2010-06-16 14:20:27 +00:00
{
2010-06-16 16:01:40 +00:00
if ( name [ 1 ] )
2010-06-16 14:20:27 +00:00
{
new_section . flags | = SF_SECGRP ;
name + + ;
}
else
new_section . flags | = SF_SECGRPEND ;
}
2010-06-16 16:01:40 +00:00
int hidden = ( name [ 0 ] = = _T ( ' - ' ) ) ;
if ( hidden )
name + + ;
2010-06-16 14:20:27 +00:00
if ( name [ 0 ] = = _T ( ' ! ' ) )
{
name + + ;
new_section . flags | = SF_BOLD ;
}
int old_uninstall_mode = uninstall_mode ;
set_uninstall_mode ( 0 ) ;
if ( ! _tcsnicmp ( name , _T ( " un. " ) , 3 ) )
{
set_uninstall_mode ( 1 ) ;
name + = 3 ;
}
if ( ! _tcsicmp ( name , _T ( " uninstall " ) ) )
{
set_uninstall_mode ( 1 ) ;
}
if ( ( new_section . flags & SF_SECGRPEND ) & & sectiongroup_open_cnt & & old_uninstall_mode )
{
set_uninstall_mode ( 1 ) ;
}
if ( sectiongroup_open_cnt )
{
if ( uninstall_mode ! = old_uninstall_mode )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: Can't create % " ) NPRIs _T ( " section in % " ) NPRIs _T ( " section group (use SectionGroupEnd first) \n " ) , uninstall_mode ? _T ( " uninstaller " ) : _T ( " installer " ) , old_uninstall_mode ? _T ( " uninstaller " ) : _T ( " installer " ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
}
new_section . code = cur_entries - > getlen ( ) / sizeof ( entry ) ;
2010-06-16 16:01:40 +00:00
new_section . install_types = ( ! hidden & & * name ) ? 0 : ~ 0 ;
new_section . name_ptr = hidden ? 0 : add_string ( name ) ;
2010-06-16 14:20:27 +00:00
memset ( & new_section . name , 0 , sizeof ( new_section . name ) ) ;
cur_sections - > add ( & new_section , sizeof ( section ) ) ;
build_cursection = ( section * ) cur_sections - > get ( ) + cur_header - > blocks [ NB_SECTIONS ] . num ;
if ( defname [ 0 ] )
{
TCHAR buf [ 1024 ] ;
wsprintf ( buf , _T ( " %d " ) , cur_header - > blocks [ NB_SECTIONS ] . num ) ;
if ( definedlist . add ( defname , buf ) )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: \" % " ) NPRIs _T ( " \" already defined, can't assign section index! \n " ) , defname ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
}
cur_header - > blocks [ NB_SECTIONS ] . num + + ;
if ( new_section . flags & ( SF_SECGRP | SF_SECGRPEND ) )
{
add_entry_direct ( EW_RET ) ;
build_cursection - > code_size = 0 ;
build_cursection = 0 ;
if ( new_section . flags & SF_SECGRPEND )
{
sectiongroup_open_cnt - - ;
if ( sectiongroup_open_cnt < 0 )
{
ERROR_MSG ( _T ( " SectionGroupEnd: no SectionGroups are open \n " ) ) ;
return PS_ERROR ;
}
if ( ! sectiongroup_open_cnt )
{
set_uninstall_mode ( 0 ) ;
}
}
else
sectiongroup_open_cnt + + ;
}
set_code_type_predefines ( name ) ;
return PS_OK ;
}
int CEXEBuild : : add_entry ( const entry * ent )
{
if ( ! build_cursection & & ! uninstall_mode )
{
ERROR_MSG ( _T ( " Error: Can't add entry, no section or function is open! \n " ) ) ;
return PS_ERROR ;
}
cur_entries - > add ( ent , sizeof ( entry ) ) ;
cur_instruction_entry_map - > add ( & multiple_entries_instruction , sizeof ( int ) ) ;
build_cursection - > code_size + + ;
cur_header - > blocks [ NB_ENTRIES ] . num + + ;
multiple_entries_instruction = 1 ;
return PS_OK ;
}
int CEXEBuild : : add_entry_direct ( int which , int o0 , int o1 , int o2 , int o3 , int o4 , int o5 /*o#=0*/ )
{
entry ent ;
ent . which = which ;
ent . offsets [ 0 ] = o0 ;
ent . offsets [ 1 ] = o1 ;
ent . offsets [ 2 ] = o2 ;
ent . offsets [ 3 ] = o3 ;
ent . offsets [ 4 ] = o4 ;
ent . offsets [ 5 ] = o5 ;
return add_entry ( & ent ) ;
}
int CEXEBuild : : resolve_jump_int ( const TCHAR * fn , int * a , int offs , int start , int end )
{
if ( * a > 0 )
{
TCHAR * lname = ( TCHAR * ) ns_label . get ( ) + * a ;
if ( lname [ 0 ] = = _T ( ' - ' ) | | lname [ 0 ] = = _T ( ' + ' ) )
{
int jump = _ttoi ( lname ) ;
int * skip_map = ( int * ) cur_instruction_entry_map - > get ( ) ;
int maxoffs = cur_instruction_entry_map - > getlen ( ) / ( int ) sizeof ( int ) ;
int direction = 1 ;
if ( jump < 0 )
direction = - 1 ;
for ( ; jump ! = 0 ; jump - = direction )
{
offs + = direction ;
if ( offs > = 0 & & offs < maxoffs )
{
while ( skip_map [ offs ] )
{
offs + = direction ;
}
}
}
* a = offs + 1 ;
}
else
{
section * s = ( section * ) cur_labels - > get ( ) ;
int n = cur_labels - > getlen ( ) / sizeof ( section ) ;
while ( n - - > 0 )
{
if ( ( * lname = = _T ( ' . ' ) | | ( s - > code > = start & & s - > code < = end ) ) & & s - > name_ptr = = * a )
{
* a = s - > code + 1 ; // jumps are to the absolute position, +1 (to differentiate between no jump, and jumping to offset 0)
s - > flags + + ;
if ( * lname = = _T ( ' . ' ) )
{
// bug #2593369 - mark functions with used global labels as used
// XXX this puts another hole in function reference counting
// a recursive function, for example, will never be optimized
int nf = cur_functions - > getlen ( ) / sizeof ( section ) ;
section * func = ( section * ) cur_functions - > get ( ) ;
while ( nf - - > 0 )
{
int fstart = func - > code ;
int fend = func - > code + func - > code_size ;
if ( s - > code > = fstart & & s - > code < = fend )
{
func - > flags + + ;
break ;
}
func + + ;
}
}
return 0 ;
}
s + + ;
}
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: could not resolve label \" % " ) NPRIs _T ( " \" in % " ) NPRIs _T ( " \n " ) , lname , fn ) ;
2010-06-16 14:20:27 +00:00
return 1 ;
}
}
else if ( * a < 0 ) // to jump to a user variable target, -variable_index-1 is already stored.
{
}
// otherwise, *a is 0, which means no jump and we also leave it intact
return 0 ;
}
int CEXEBuild : : resolve_call_int ( const TCHAR * fn , const TCHAR * str , int fptr , int * ofs )
{
if ( fptr < 0 ) return 0 ;
int nf = cur_functions - > getlen ( ) / sizeof ( section ) ;
section * sec = ( section * ) cur_functions - > get ( ) ;
while ( nf - - > 0 )
{
if ( sec - > name_ptr > 0 & & sec - > name_ptr = = fptr )
{
ofs [ 0 ] = sec - > code ;
sec - > flags + + ;
return 0 ;
}
sec + + ;
}
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: resolving % " ) NPRIs _T ( " function \" % " ) NPRIs _T ( " \" in % " ) NPRIs _T ( " \n " ) , str , ( TCHAR * ) ns_func . get ( ) + fptr , fn ) ;
2010-06-16 14:20:27 +00:00
ERROR_MSG ( _T ( " Note: uninstall functions must begin with \" un. \" , and install functions must not \n " ) ) ;
return 1 ;
}
int CEXEBuild : : resolve_instruction ( const TCHAR * fn , const TCHAR * str , entry * w , int offs , int start , int end )
{
if ( w - > which = = EW_NOP )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 0 ] , offs , start , end ) ) return 1 ;
}
# ifdef NSIS_SUPPORT_MESSAGEBOX
else if ( w - > which = = EW_MESSAGEBOX )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 3 ] , offs , start , end ) ) return 1 ;
if ( resolve_jump_int ( fn , & w - > offsets [ 5 ] , offs , start , end ) ) return 1 ;
}
# endif
else if ( w - > which = = EW_IFFILEEXISTS )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 1 ] , offs , start , end ) ) return 1 ;
if ( resolve_jump_int ( fn , & w - > offsets [ 2 ] , offs , start , end ) ) return 1 ;
}
else if ( w - > which = = EW_IFFLAG )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 0 ] , offs , start , end ) ) return 1 ;
if ( resolve_jump_int ( fn , & w - > offsets [ 1 ] , offs , start , end ) ) return 1 ;
}
# ifdef NSIS_SUPPORT_STROPTS
else if ( w - > which = = EW_STRCMP )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 2 ] , offs , start , end ) ) return 1 ;
if ( resolve_jump_int ( fn , & w - > offsets [ 3 ] , offs , start , end ) ) return 1 ;
}
# endif
# ifdef NSIS_SUPPORT_INTOPTS
else if ( w - > which = = EW_INTCMP )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 2 ] , offs , start , end ) ) return 1 ;
if ( resolve_jump_int ( fn , & w - > offsets [ 3 ] , offs , start , end ) ) return 1 ;
if ( resolve_jump_int ( fn , & w - > offsets [ 4 ] , offs , start , end ) ) return 1 ;
}
# endif
# ifdef NSIS_SUPPORT_HWNDS
else if ( w - > which = = EW_ISWINDOW )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 1 ] , offs , start , end ) ) return 1 ;
if ( resolve_jump_int ( fn , & w - > offsets [ 2 ] , offs , start , end ) ) return 1 ;
}
# endif
else if ( w - > which = = EW_CALL )
{
if ( w - > offsets [ 0 ] > = 0 & & w - > offsets [ 1 ] ) // get as jump
{
if ( resolve_jump_int ( fn , & w - > offsets [ 0 ] , offs , start , end ) ) return 1 ;
}
else
{
if ( w - > offsets [ 0 ] > = 0 & & resolve_call_int ( fn , str , w - > offsets [ 0 ] , w - > offsets ) ) return 1 ;
// if w->offsets[0] >= 0, EW_CALL requires that it 1-based.
// otherwise, if < 0, it needs an increment anyway (since it
// was encoded with a -2 base, to prevent it looking like an
// empty string "")
w - > offsets [ 0 ] + + ;
}
}
# ifdef NSIS_SUPPORT_STROPTS
else if ( w - > which = = EW_GETFUNCTIONADDR )
{
if ( w - > offsets [ 1 ] < 0 )
{
ERROR_MSG ( _T ( " Error: GetFunctionAddress requires a real function to get address of. \n " ) ) ;
return 1 ;
}
if ( resolve_call_int ( fn , str , w - > offsets [ 1 ] , & w - > offsets [ 1 ] ) ) return 1 ;
w - > which = EW_ASSIGNVAR ;
w - > offsets [ 1 ] = add_intstring ( w - > offsets [ 1 ] + 1 ) ; // +1 here to make 1-based.
}
else if ( w - > which = = EW_GETLABELADDR )
{
if ( resolve_jump_int ( fn , & w - > offsets [ 1 ] , offs , start , end ) ) return 1 ;
w - > which = EW_ASSIGNVAR ;
w - > offsets [ 1 ] = add_intstring ( w - > offsets [ 1 ] ) ;
}
# endif
return 0 ;
}
int CEXEBuild : : resolve_coderefs ( const TCHAR * str )
{
// resolve jumps&calls
{
section * sec = ( section * ) cur_functions - > get ( ) ;
int l = cur_functions - > getlen ( ) / sizeof ( section ) ;
entry * w = ( entry * ) cur_entries - > get ( ) ;
while ( l - - > 0 )
{
int x ;
for ( x = sec - > code ; x < sec - > code + sec - > code_size ; x + + )
{
TCHAR fname [ 1024 ] ;
2013-12-08 14:34:38 +00:00
wsprintf ( fname , _T ( " function \" % " ) NPRIs _T ( " \" " ) , ns_func . get ( ) + sec - > name_ptr ) ;
2010-06-16 14:20:27 +00:00
if ( resolve_instruction ( fname , str , w + x , x , sec - > code , sec - > code + sec - > code_size ) ) return 1 ;
}
sec + + ;
}
int cnt = 0 ;
sec = ( section * ) cur_sections - > get ( ) ;
l = cur_sections - > getlen ( ) / sizeof ( section ) ;
while ( l - - > 0 )
{
int x = sec - > name_ptr ;
TCHAR fname [ 1024 ] ;
2013-03-07 21:25:35 +00:00
tstring section_name ;
2010-06-16 14:20:27 +00:00
if ( x < 0 )
{
// lang string
section_name = _T ( " $(lang string) " ) ;
}
else
{
// normal string
2013-03-07 21:25:35 +00:00
cur_strlist - > get ( x , section_name ) ;
2010-06-16 14:20:27 +00:00
}
2013-12-08 14:34:38 +00:00
if ( x ) wsprintf ( fname , _T ( " % " ) NPRIs _T ( " section \" % " ) NPRIs _T ( " \" (%d) " ) , str , section_name . c_str ( ) , cnt ) ;
else wsprintf ( fname , _T ( " unnamed % " ) NPRIs _T ( " section (%d) " ) , str , cnt ) ;
2010-06-16 14:20:27 +00:00
for ( x = sec - > code ; x < sec - > code + sec - > code_size ; x + + )
{
if ( resolve_instruction ( fname , str , w + x , x , sec - > code , sec - > code + sec - > code_size ) )
return 1 ;
}
sec + + ;
cnt + + ;
}
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
# ifdef NSIS_SUPPORT_CODECALLBACKS
if ( cur_pages - > getlen ( ) ) {
page * p = ( page * ) cur_pages - > get ( ) ;
int i = 0 ;
while ( i < cur_header - > blocks [ NB_PAGES ] . num ) {
TCHAR pagestr [ 1024 ] ;
2013-12-08 14:34:38 +00:00
wsprintf ( pagestr , _T ( " % " ) NPRIs _T ( " pages " ) , str ) ;
2010-06-16 14:20:27 +00:00
if ( resolve_call_int ( pagestr , p - > dlg_id ? _T ( " pre-page " ) : _T ( " create-page " ) , p - > prefunc , & p - > prefunc ) ) return 1 ;
if ( resolve_call_int ( pagestr , _T ( " show-page " ) , p - > showfunc , & p - > showfunc ) ) return 1 ;
if ( resolve_call_int ( pagestr , _T ( " leave-page " ) , p - > leavefunc , & p - > leavefunc ) ) return 1 ;
p + + ;
i + + ;
}
}
# endif
# endif
}
# ifdef NSIS_SUPPORT_CODECALLBACKS
// resolve callbacks
{
struct {
const TCHAR * name ;
int * p ;
} callbacks [ ] = {
2013-12-08 14:34:38 +00:00
{ _T ( " % " ) NPRIs _T ( " .onInit " ) , & cur_header - > code_onInit } ,
{ _T ( " % " ) NPRIs _T ( " .on% " ) NPRIs _T ( " InstSuccess " ) , & cur_header - > code_onInstSuccess } ,
{ _T ( " % " ) NPRIs _T ( " .on% " ) NPRIs _T ( " InstFailed " ) , & cur_header - > code_onInstFailed } ,
{ _T ( " % " ) NPRIs _T ( " .onUserAbort " ) , & cur_header - > code_onUserAbort } ,
{ _T ( " % " ) NPRIs _T ( " .onVerifyInstDir " ) , & cur_header - > code_onVerifyInstDir } ,
2010-06-16 14:20:27 +00:00
# ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
2013-12-08 14:34:38 +00:00
{ _T ( " % " ) NPRIs _T ( " .onGUIInit " ) , & cur_header - > code_onGUIInit } ,
{ _T ( " % " ) NPRIs _T ( " .onGUIEnd " ) , & cur_header - > code_onGUIEnd } ,
{ _T ( " % " ) NPRIs _T ( " .onMouseOverSection " ) , & cur_header - > code_onMouseOverSection } ,
2010-06-16 14:20:27 +00:00
# endif //NSIS_CONFIG_ENHANCEDUI_SUPPORT
# ifdef NSIS_CONFIG_COMPONENTPAGE
2013-12-08 14:34:38 +00:00
{ _T ( " % " ) NPRIs _T ( " .onSelChange " ) , & cur_header - > code_onSelChange } ,
2010-06-16 14:20:27 +00:00
# endif //NSIS_CONFIG_COMPONENTPAGE
# ifdef NSIS_SUPPORT_REBOOT
2013-12-08 14:34:38 +00:00
{ _T ( " % " ) NPRIs _T ( " .onRebootFailed " ) , & cur_header - > code_onRebootFailed } ,
2010-06-16 14:20:27 +00:00
# endif //NSIS_SUPPORT_REBOOT
{ 0 , 0 }
} ;
for ( int i = 0 ; callbacks [ i ] . name ; i + + ) {
const TCHAR * un = uninstall_mode ? _T ( " un " ) : _T ( " " ) ;
TCHAR fname [ 1024 ] ;
wsprintf ( fname , callbacks [ i ] . name , un , un ) ;
TCHAR cbstr [ 1024 ] ;
2013-12-08 14:34:38 +00:00
wsprintf ( cbstr , _T ( " % " ) NPRIs _T ( " callback " ) , str ) ;
2010-06-16 14:20:27 +00:00
TCHAR cbstr2 [ 1024 ] ;
2013-12-08 14:34:38 +00:00
wsprintf ( cbstr2 , _T ( " % " ) NPRIs _T ( " .callbacks " ) , un ) ;
2010-06-16 14:20:27 +00:00
if ( resolve_call_int ( cbstr , cbstr2 , ns_func . find ( fname , 0 ) , callbacks [ i ] . p ) )
return PS_ERROR ;
}
}
# endif //NSIS_SUPPORT_CODECALLBACKS
// optimize unused functions
{
section * sec = ( section * ) cur_functions - > get ( ) ;
int l = cur_functions - > getlen ( ) / sizeof ( section ) ;
entry * w = ( entry * ) cur_entries - > get ( ) ;
while ( l - - > 0 )
{
if ( sec - > name_ptr )
{
if ( ! sec - > flags )
{
if ( sec - > code_size > 0 )
{
2017-04-25 13:09:41 +00:00
warning ( DW_UNUSED_FUNCTION , _T ( " % " ) NPRIs _T ( " function \" % " ) NPRIs _T ( " \" not referenced - zeroing code (%d-%d) out \n " ) , str ,
2010-06-16 14:20:27 +00:00
ns_func . get ( ) + sec - > name_ptr ,
sec - > code , sec - > code + sec - > code_size ) ;
memset ( w + sec - > code , 0 , sec - > code_size * sizeof ( entry ) ) ;
}
}
}
sec + + ;
}
}
// give warnings on unused labels
{
section * t = ( section * ) cur_labels - > get ( ) ;
int n = cur_labels - > getlen ( ) / sizeof ( section ) ;
while ( n - - > 0 )
{
if ( ! t - > flags )
{
TCHAR * n = ( TCHAR * ) ns_label . get ( ) + t - > name_ptr ;
2017-04-25 13:09:41 +00:00
if ( * n = = _T ( ' . ' ) ) warning ( DW_UNUSED_GLOBALLABEL , _T ( " global label \" % " ) NPRIs _T ( " \" not used " ) , n ) ;
else warning ( DW_UNUSED_LABEL , _T ( " label \" % " ) NPRIs _T ( " \" not used " ) , n ) ;
2010-06-16 14:20:27 +00:00
}
t + + ;
}
}
return 0 ;
}
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
int CEXEBuild : : add_page ( int type )
{
page pg = {
0 ,
0 ,
# ifdef NSIS_SUPPORT_CODECALLBACKS
- 1 ,
- 1 ,
- 1 ,
# endif
0 ,
} ;
# ifndef NSIS_CONFIG_LICENSEPAGE
if ( type = = PAGE_LICENSE )
{
2021-08-18 13:53:50 +00:00
ERROR_MSG ( _T ( " Error: can't add % " ) NPRIns _T ( " page, % " ) NPRIns _T ( " not defined. \n " ) , " license " , " NSIS_CONFIG_LICENSEPAGE " ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
# endif
# ifndef NSIS_CONFIG_COMPONENTPAGE
if ( type = = PAGE_COMPONENTS )
{
2021-08-18 13:53:50 +00:00
ERROR_MSG ( _T ( " Error: can't add % " ) NPRIns _T ( " page, % " ) NPRIns _T ( " not defined. \n " ) , " components " , " NSIS_CONFIG_COMPONENTPAGE " ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
# endif
# ifndef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( type = = PAGE_COMPONENTS )
{
2021-08-18 13:53:50 +00:00
ERROR_MSG ( _T ( " Error: can't add % " ) NPRIns _T ( " page, % " ) NPRIns _T ( " not defined. \n " ) , " uninstConfirm " , " NSIS_CONFIG_UNINSTALL_SUPPORT " ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
# endif
struct {
int wndproc_id ;
int dlg_id ;
const TCHAR * name ;
} ids [ ] = {
{ PWP_CUSTOM , 0 , _T ( " custom " ) } , // custom
# ifdef NSIS_CONFIG_LICENSEPAGE
{ PWP_LICENSE , IDD_LICENSE , _T ( " license " ) } , // license
# else
{ 0 , IDD_LICENSE , _T ( " license " ) } , // license
# endif
# ifdef NSIS_CONFIG_COMPONENTPAGE
{ PWP_SELCOM , IDD_SELCOM , _T ( " components " ) } , // components
# else
{ 0 , IDD_SELCOM , _T ( " components " ) } , // components
# endif
{ PWP_DIR , IDD_DIR , _T ( " directory " ) } , // directory
{ PWP_INSTFILES , IDD_INSTFILES , _T ( " instfiles " ) } , // instfiles
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
{ PWP_UNINST , IDD_UNINST , _T ( " uninstConfirm " ) } , // uninstConfirm
# else
{ 0 , IDD_UNINST , _T ( " uninstConfirm " ) } , // uninstConfirm
# endif
{ PWP_COMPLETED , - 1 , NULL } // completed
} ;
pg . wndproc_id = ids [ type ] . wndproc_id ;
pg . dlg_id = ids [ type ] . dlg_id ;
cur_pages - > add ( & pg , sizeof ( page ) ) ;
cur_page = ( page * ) cur_pages - > get ( ) + cur_header - > blocks [ NB_PAGES ] . num + + ;
cur_page_type = type ;
set_code_type_predefines ( ids [ type ] . name ) ;
return PS_OK ;
}
int CEXEBuild : : page_end ( )
{
cur_page = 0 ;
set_code_type_predefines ( ) ;
return PS_OK ;
}
# endif
# ifdef NSIS_SUPPORT_VERSION_INFO
int CEXEBuild : : AddVersionInfo ( )
{
GrowBuf VerInfoStream ;
2011-07-29 22:11:00 +00:00
// Should probably check for (4 & version_fixedflags) here, but VIProductVersion without VIAddVersionKey
// fails silently, so VIFileVersion does the same...
2010-06-16 14:20:27 +00:00
if ( rVersionInfo . GetStringTablesCount ( ) > 0 )
{
2011-07-29 22:11:00 +00:00
if ( ! ( 1 & version_fixedflags ) )
2010-06-16 14:20:27 +00:00
{
ERROR_MSG ( _T ( " Error: VIProductVersion is required when other version information functions are used. \n " ) ) ;
return PS_ERROR ;
}
else
{
2011-07-29 22:11:00 +00:00
if ( ! ( 2 & version_fixedflags ) )
2010-06-16 14:20:27 +00:00
{
2011-07-29 22:11:00 +00:00
// This error string should match the one used by the TOK_VI_SETFILEVERSION handler
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: invalid % " ) NPRIs _T ( " format, should be X.X.X.X \n " ) , _T ( " VIProductVersion " ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
try
{
init_res_editor ( ) ;
for ( int i = 0 ; i < rVersionInfo . GetStringTablesCount ( ) ; i + + )
{
LANGID lang_id = rVersionInfo . GetLangID ( i ) ;
int code_page = rVersionInfo . GetCodePage ( i ) ;
2011-07-29 22:11:00 +00:00
const TCHAR * lang_name = GetLangNameAndCPForVersionResource ( lang_id , NULL , false ) ;
2010-06-16 14:20:27 +00:00
2011-07-29 22:11:00 +00:00
const TCHAR * recverkeys =
_T ( " FileVersion \0 " )
_T ( " FileDescription \0 " )
_T ( " LegalCopyright \0 " ) ;
for ( ; ; )
{
if ( ! * recverkeys ) break ;
if ( ! rVersionInfo . FindKey ( lang_id , code_page , recverkeys ) )
2017-04-25 13:09:41 +00:00
warning ( DW_VI_MISSINGSTDKEY , _T ( " Generating version information for language \" %04d-% " ) NPRIs _T ( " \" without standard key \" % " ) NPRIs _T ( " \" " ) , lang_id , lang_name , recverkeys ) ;
2011-07-29 22:11:00 +00:00
recverkeys + = _tcsclen ( recverkeys ) + 1 ;
}
2010-06-16 14:20:27 +00:00
rVersionInfo . ExportToStream ( VerInfoStream , i ) ;
res_editor - > UpdateResource ( RT_VERSION , 1 , lang_id , ( BYTE * ) VerInfoStream . get ( ) , VerInfoStream . getlen ( ) ) ;
}
}
catch ( exception & err ) {
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error adding version information: % " ) NPRIs _T ( " \n " ) , CtoTStrParam ( err . what ( ) ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
}
}
return PS_OK ;
}
# endif // NSIS_SUPPORT_VERSION_INFO
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
int CEXEBuild : : ProcessPages ( )
{
SCRIPT_MSG ( _T ( " Processing pages... " ) ) ;
int license_normal = 0 ;
int license_fsrb = 0 ;
int license_fscb = 0 ;
int selcom = 0 ;
2012-09-08 02:50:09 +00:00
int dir = 0 ;
2010-06-16 14:20:27 +00:00
int uninstconfirm = 0 ;
int instlog = 0 , instlog_used ;
int main = 0 ;
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
again :
# endif
instlog_used = 0 ;
# ifdef NSIS_CONFIG_SILENT_SUPPORT
if ( ( cur_header - > flags & ( CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG ) ) = = 0 )
# endif
{
main + + ;
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
# define LS(inst, uninst) (uninstall_mode ? uninst : inst)
# else
# define LS(inst, uninst) inst
# endif
DefineInnerLangString ( NLF_BRANDING ) ;
if ( ! cur_pages - > getlen ( ) ) {
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( uninstall_mode ) {
if ( HasUserDefined ( NLF_UNINST_TEXT ) ) {
add_page ( PAGE_UNINSTCONFIRM ) ;
page_end ( ) ;
}
add_page ( PAGE_INSTFILES ) ;
page_end ( ) ;
add_page ( PAGE_COMPLETED ) ;
page_end ( ) ;
}
else
# endif
{
# ifdef NSIS_CONFIG_LICENSEPAGE
if ( HasUserDefined ( NLF_LICENSE_TEXT ) & & HasUserDefined ( NLF_LICENSE_DATA ) ) {
add_page ( PAGE_LICENSE ) ;
page_end ( ) ;
}
# endif
# ifdef NSIS_CONFIG_COMPONENTPAGE
if ( HasUserDefined ( NLF_COMP_TEXT ) ) {
add_page ( PAGE_COMPONENTS ) ;
page_end ( ) ;
}
# endif
if ( HasUserDefined ( NLF_DIR_TEXT ) ) {
add_page ( PAGE_DIRECTORY ) ;
page_end ( ) ;
}
add_page ( PAGE_INSTFILES ) ;
page_end ( ) ;
add_page ( PAGE_COMPLETED ) ;
page_end ( ) ;
}
}
// start processing the pages
{
int i = 0 ;
page * p = ( page * ) cur_pages - > get ( ) ;
for ( i = 0 ; i < cur_header - > blocks [ NB_PAGES ] . num ; i + + , p + + ) {
page * pp = 0 ;
if ( i ) {
pp = p - 1 ;
// set back button
p - > flags | = PF_BACK_SHOW ;
if ( pp - > wndproc_id ! = PWP_COMPLETED & & p - > wndproc_id ! = PWP_COMPLETED & & p - > wndproc_id ! = PWP_INSTFILES )
p - > flags | = PF_BACK_ENABLE ;
if ( ! p - > back )
p - > back = DefineInnerLangString ( NLF_BTN_BACK ) ;
// set previous page's next button
if ( ! pp - > next ) {
int str = 0 ;
# ifdef NSIS_CONFIG_LICENSEPAGE
if ( pp - > wndproc_id = = PWP_LICENSE & & ( ! ( pp - > flags & PF_LICENSE_FORCE_SELECTION ) | | HasUserDefined ( NLF_BTN_LICENSE ) ) )
str = NLF_BTN_LICENSE ;
else
# endif
if ( p - > wndproc_id = = PWP_INSTFILES )
str = LS ( NLF_BTN_INSTALL , NLF_BTN_UNINSTALL ) ;
else
str = NLF_BTN_NEXT ;
pp - > next = DefineInnerLangString ( str ) ;
}
// set previous page's click next text
if ( ! pp - > clicknext ) {
int str = 0 ;
if ( p - > wndproc_id = = PWP_INSTFILES )
str = LS ( NLF_CLICK_INSTALL , NLF_CLICK_UNINSTALL ) ;
else
str = NLF_CLICK_NEXT ;
pp - > clicknext = DefineInnerLangString ( str ) ;
}
}
// enable next button
if ( p - > wndproc_id ! = PWP_INSTFILES )
p - > flags | = PF_NEXT_ENABLE ;
// set cancel button
if ( ! p - > cancel )
p - > cancel = DefineInnerLangString ( NLF_BTN_CANCEL ) ;
if ( p - > wndproc_id ! = PWP_INSTFILES & & p - > wndproc_id ! = PWP_COMPLETED )
p - > flags | = PF_CANCEL_ENABLE ;
// set caption
struct {
int caption ;
int ucaption ;
} captions [ ] = {
# ifdef NSIS_CONFIG_LICENSEPAGE
{ NLF_SUBCAPTION_LICENSE , NLF_SUBCAPTION_LICENSE } ,
# endif
# ifdef NSIS_CONFIG_COMPONENTPAGE
{ NLF_SUBCAPTION_OPTIONS , NLF_SUBCAPTION_OPTIONS } ,
# endif
{ NLF_SUBCAPTION_DIR , NLF_SUBCAPTION_DIR } ,
{ NLF_SUBCAPTION_INSTFILES , NLF_USUBCAPTION_INSTFILES } ,
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
{ NLF_USUBCAPTION_CONFIRM , NLF_USUBCAPTION_CONFIRM } ,
# endif
{ NLF_SUBCAPTION_COMPLETED , NLF_USUBCAPTION_COMPLETED }
} ;
if ( ! p - > caption & & p - > wndproc_id ! = PWP_CUSTOM ) {
p - > caption = DefineInnerLangString ( LS ( captions [ p - > wndproc_id ] . caption , captions [ p - > wndproc_id ] . ucaption ) ) ;
}
// set texts
switch ( p - > dlg_id ) {
# ifdef NSIS_CONFIG_LICENSEPAGE
case IDD_LICENSE :
case IDD_LICENSE_FSRB :
case IDD_LICENSE_FSCB :
{
if ( ! ( p - > flags & PF_PAGE_EX ) )
p - > dlg_id = license_res_id ;
if ( ! ( p - > flags & ( PF_LICENSE_FORCE_SELECTION | PF_LICENSE_NO_FORCE_SELECTION ) ) )
p - > dlg_id = license_res_id ;
p - > flags | = PF_NO_NEXT_FOCUS ;
if ( ! p - > parms [ 1 ] )
p - > parms [ 1 ] = DefineInnerLangString ( NLF_LICENSE_DATA , 0 ) ;
if ( p - > dlg_id = = IDD_LICENSE ) {
if ( ! p - > parms [ 0 ] )
p - > parms [ 0 ] = DefineInnerLangString ( LS ( NLF_LICENSE_TEXT , NLF_ULICENSE_TEXT ) ) ;
license_normal + + ;
}
else if ( p - > dlg_id = = IDD_LICENSE_FSCB ) {
p - > flags | = PF_LICENSE_FORCE_SELECTION ;
if ( ! p - > parms [ 0 ] )
p - > parms [ 0 ] = DefineInnerLangString ( LS ( NLF_LICENSE_TEXT_FSCB , NLF_ULICENSE_TEXT_FSCB ) ) ;
if ( ! p - > parms [ 2 ] )
p - > parms [ 2 ] = DefineInnerLangString ( NLF_BTN_LICENSE_AGREE ) ;
license_fscb + + ;
}
else if ( p - > dlg_id = = IDD_LICENSE_FSRB ) {
p - > flags | = PF_LICENSE_FORCE_SELECTION ;
if ( ! p - > parms [ 0 ] )
p - > parms [ 0 ] = DefineInnerLangString ( LS ( NLF_LICENSE_TEXT_FSRB , NLF_ULICENSE_TEXT_FSRB ) ) ;
if ( ! p - > parms [ 2 ] )
p - > parms [ 2 ] = DefineInnerLangString ( NLF_BTN_LICENSE_AGREE ) ;
if ( ! p - > parms [ 3 ] )
p - > parms [ 3 ] = DefineInnerLangString ( NLF_BTN_LICENSE_DISAGREE ) ;
license_fsrb + + ;
}
break ;
}
# endif
# ifdef NSIS_CONFIG_COMPONENTPAGE
case IDD_SELCOM :
{
if ( ! p - > parms [ 0 ] )
p - > parms [ 0 ] = DefineInnerLangString ( LS ( NLF_COMP_TEXT , NLF_UCOMP_TEXT ) ) ;
if ( ! p - > parms [ 1 ] )
p - > parms [ 1 ] = DefineInnerLangString ( LS ( NLF_COMP_SUBTEXT1 , NLF_UCOMP_SUBTEXT1 ) ) ;
if ( ! p - > parms [ 2 ] )
p - > parms [ 2 ] = DefineInnerLangString ( LS ( NLF_COMP_SUBTEXT2 , NLF_UCOMP_SUBTEXT2 ) ) ;
if ( ! p - > parms [ 3 ] & & ! uninstall_mode & & HasUserDefined ( NLF_COMP_SUBTEXT1 ) )
p - > parms [ 3 ] = p - > parms [ 1 ] ;
if ( ! p - > parms [ 4 ] & & ! uninstall_mode & & HasUserDefined ( NLF_COMP_SUBTEXT2 ) )
p - > parms [ 4 ] = p - > parms [ 2 ] ;
else if ( ! p - > parms [ 4 ] )
p - > parms [ 4 ] = DefineInnerLangString ( LS ( NLF_COMP_SUBTEXT1_NO_INST_TYPES , NLF_UCOMP_SUBTEXT1_NO_INST_TYPES ) ) ;
DefineInnerLangString ( NLF_SPACE_REQ ) ;
DefineInnerLangString ( NLF_BYTE ) ;
DefineInnerLangString ( NLF_KILO ) ;
DefineInnerLangString ( NLF_MEGA ) ;
DefineInnerLangString ( NLF_GIGA ) ;
selcom + + ;
break ;
}
# endif
case IDD_DIR :
{
if ( ! p - > parms [ 0 ] )
p - > parms [ 0 ] = DefineInnerLangString ( LS ( NLF_DIR_TEXT , NLF_UDIR_TEXT ) ) ;
if ( ! p - > parms [ 1 ] )
p - > parms [ 1 ] = DefineInnerLangString ( LS ( NLF_DIR_SUBTEXT , NLF_UDIR_SUBTEXT ) ) ;
if ( ! p - > parms [ 2 ] )
p - > parms [ 2 ] = DefineInnerLangString ( NLF_BTN_BROWSE ) ;
if ( ! p - > parms [ 3 ] )
p - > parms [ 3 ] = DefineInnerLangString ( LS ( NLF_DIR_BROWSETEXT , NLF_UDIR_BROWSETEXT ) ) ;
if ( ! p - > parms [ 4 ] )
p - > parms [ 4 ] = m_UserVarNames . get ( _T ( " INSTDIR " ) ) ;
else
p - > parms [ 4 ] - - ;
DefineInnerLangString ( NLF_SPACE_AVAIL ) ;
DefineInnerLangString ( NLF_SPACE_REQ ) ;
DefineInnerLangString ( NLF_BYTE ) ;
DefineInnerLangString ( NLF_KILO ) ;
DefineInnerLangString ( NLF_MEGA ) ;
DefineInnerLangString ( NLF_GIGA ) ;
# ifdef NSIS_CONFIG_LOG
DefineInnerLangString ( NLF_LOG_INSTALL_PROCESS ) ;
# endif
dir + + ;
break ;
}
case IDD_INSTFILES :
{
if ( ! p - > parms [ 1 ] )
p - > parms [ 1 ] = DefineInnerLangString ( NLF_BTN_DETAILS ) ;
if ( ! p - > parms [ 2 ] )
p - > parms [ 2 ] = DefineInnerLangString ( NLF_COMPLETED ) ;
DefineInnerLangString ( NLF_COPY_DETAILS ) ;
instlog + + ;
instlog_used + + ;
break ;
}
case IDD_UNINST :
{
if ( ! p - > parms [ 0 ] )
p - > parms [ 0 ] = DefineInnerLangString ( NLF_UNINST_TEXT ) ;
if ( ! p - > parms [ 1 ] )
p - > parms [ 1 ] = DefineInnerLangString ( NLF_UNINST_SUBTEXT ) ;
if ( ! p - > parms [ 4 ] )
p - > parms [ 4 ] = m_UserVarNames . get ( _T ( " INSTDIR " ) ) ;
else
p - > parms [ 4 ] - - ;
uninstconfirm + + ;
break ;
}
}
p - > flags & = ~ PF_PAGE_EX ;
}
p - - ;
if ( ! p - > next )
p - > next = DefineInnerLangString ( NLF_BTN_CLOSE ) ;
if ( p - > wndproc_id = = PWP_COMPLETED )
( p - 1 ) - > next = DefineInnerLangString ( NLF_BTN_CLOSE ) ;
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( uninstall_mode ) {
if ( ! uenable_last_page_cancel & & instlog_used )
p - > flags & = ~ PF_CANCEL_ENABLE ;
}
else
# endif
{
if ( ! enable_last_page_cancel & & instlog_used )
p - > flags & = ~ PF_CANCEL_ENABLE ;
}
if ( ! instlog_used ) {
2017-04-25 13:09:41 +00:00
warning ( DW_INSTFILESPAGE_NOT_USED , _T ( " % " ) NPRIs _T ( " age instfiles not used, no sections will be executed! " ) , uninstall_mode ? _T ( " Uninstall p " ) : _T ( " P " ) ) ;
2010-06-16 14:20:27 +00:00
}
}
}
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( ! uninstall_mode ) {
set_uninstall_mode ( 1 ) ;
goto again ;
}
else
set_uninstall_mode ( 0 ) ;
# endif //NSIS_CONFIG_UNINSTALL_SUPPORT
SCRIPT_MSG ( _T ( " Done! \n " ) ) ;
# define REMOVE_ICON(id) if (disable_window_icon) { \
BYTE * dlg = res_editor - > GetResource ( RT_DIALOG , id , NSIS_DEFAULT_LANG ) ; \
if ( dlg ) { \
CDialogTemplate dt ( dlg , build_unicode , uDefCodePage ) ; \
res_editor - > FreeResource ( dlg ) ; \
if ( dt . RemoveItem ( IDC_ULICON ) ) { \
DialogItemTemplate * text = dt . GetItem ( IDC_INTROTEXT ) ; \
DialogItemTemplate * prog = dt . GetItem ( IDC_PROGRESS ) ; \
if ( text ) { \
text - > sWidth + = text - > sX ; \
text - > sX = 0 ; \
} \
if ( prog ) { \
prog - > sWidth + = prog - > sX ; \
prog - > sX = 0 ; \
} \
\
DWORD dwSize ; \
dlg = dt . Save ( dwSize ) ; \
res_editor - > UpdateResource ( RT_DIALOG , id , NSIS_DEFAULT_LANG , dlg , dwSize ) ; \
2014-08-05 13:53:20 +00:00
dt . FreeSavedTemplate ( dlg ) ; \
2010-06-16 14:20:27 +00:00
} \
} \
}
try {
SCRIPT_MSG ( _T ( " Removing unused resources... " ) ) ;
init_res_editor ( ) ;
# ifdef NSIS_CONFIG_LICENSEPAGE
if ( ! license_normal ) {
res_editor - > UpdateResource ( RT_DIALOG , IDD_LICENSE , NSIS_DEFAULT_LANG , 0 , 0 ) ;
}
else REMOVE_ICON ( IDD_LICENSE ) ;
if ( ! license_fsrb ) {
res_editor - > UpdateResource ( RT_DIALOG , IDD_LICENSE_FSRB , NSIS_DEFAULT_LANG , 0 , 0 ) ;
}
else REMOVE_ICON ( IDD_LICENSE_FSRB ) ;
if ( ! license_fscb ) {
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 - > 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 - > UpdateResource ( RT_DIALOG , IDD_DIR , NSIS_DEFAULT_LANG , 0 , 0 ) ;
}
else REMOVE_ICON ( IDD_DIR ) ;
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( ! uninstconfirm ) {
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 - > UpdateResource ( RT_DIALOG , IDD_INSTFILES , NSIS_DEFAULT_LANG , 0 , 0 ) ;
}
else REMOVE_ICON ( IDD_INSTFILES ) ;
if ( ! main ) {
res_editor - > UpdateResource ( RT_DIALOG , IDD_INST , NSIS_DEFAULT_LANG , 0 , 0 ) ;
if ( ! build_compress_whole & & ! build_crcchk )
res_editor - > UpdateResource ( RT_DIALOG , IDD_VERIFY , NSIS_DEFAULT_LANG , 0 , 0 ) ;
}
SCRIPT_MSG ( _T ( " Done! \n " ) ) ;
}
catch ( exception & err ) {
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " \n Error: % " ) NPRIs _T ( " \n " ) , CtoTStrParam ( err . what ( ) ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
return PS_OK ;
}
# endif // NSIS_CONFIG_VISIBLE_SUPPORT
# ifdef NSIS_CONFIG_COMPONENTPAGE
void CEXEBuild : : PrepareInstTypes ( )
{
if ( ! ( cur_header - > flags & CH_FLAGS_NO_CUSTOM ) )
cur_header - > install_types [ NSIS_MAX_INST_TYPES ] = DefineInnerLangString ( NLF_COMP_CUSTOM ) ;
// set insttype list for RO sections that didn't use SectionIn
int i = cur_header - > blocks [ NB_SECTIONS ] . num ;
section * sections = ( section * ) cur_sections - > get ( ) ;
while ( i - - )
{
if ( sections [ i ] . flags & SF_RO & & ! sections [ i ] . install_types )
sections [ i ] . install_types = ~ 0 ;
}
// set selection to first insttype
if ( cur_header - > install_types [ 0 ] )
{
int i = cur_header - > blocks [ NB_SECTIONS ] . num ;
section * sections = ( section * ) cur_sections - > get ( ) ;
// if /o was used abort since the user did his manual choice
while ( i - - )
if ( ( sections [ i ] . flags & SF_SELECTED ) = = 0 )
return ;
i = cur_header - > blocks [ NB_SECTIONS ] . num ;
while ( i - - )
if ( ( sections [ i ] . install_types & 1 ) = = 0 )
sections [ i ] . flags & = ~ SF_SELECTED ;
}
}
# endif
void CEXEBuild : : AddStandardStrings ( )
{
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( uninstall_mode )
{
2016-03-11 19:32:21 +00:00
cur_header - > str_uninstchild = add_asciistring ( _T ( " $TEMP \\ Un_$1.exe " ) ) ;
cur_header - > str_uninstcmd = add_asciistring ( _T ( " \" $TEMP \\ Un_$1.exe \" $0 _?=$INSTDIR \\ " ) ) ;
2010-06-16 14:20:27 +00:00
}
# endif //NSIS_CONFIG_UNINSTALL_SUPPORT
# ifdef NSIS_SUPPORT_MOVEONREBOOT
2014-05-19 22:03:09 +00:00
cur_header - > str_wininit = is_target_64bit ( ) ? 0 : add_asciistring ( _T ( " $WINDIR \\ wininit.ini " ) ) ;
2010-06-16 14:20:27 +00:00
# endif //NSIS_SUPPORT_MOVEONREBOOT
}
2015-09-18 15:55:56 +00:00
writer_target_info CEXEBuild : : mk_writer_target_info ( ) { return writer_target_info ( build_unicode , is_target_64bit ( ) ) ; }
2010-06-16 14:20:27 +00:00
void CEXEBuild : : PrepareHeaders ( IGrowBuf * hdrbuf )
{
2015-09-18 15:55:56 +00:00
const writer_target_info ti = mk_writer_target_info ( ) ;
const unsigned int cbHdr = get_header_size ( ) ;
2010-06-16 14:20:27 +00:00
GrowBuf blocks_buf ;
2015-09-18 15:55:56 +00:00
growbuf_writer_sink sink ( & blocks_buf , ti ) ;
2010-06-16 14:20:27 +00:00
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
2015-09-18 15:55:56 +00:00
cur_header - > blocks [ NB_PAGES ] . offset = cbHdr + blocks_buf . getlen ( ) ;
2010-06-16 14:20:27 +00:00
page_writer : : write_block ( cur_pages , & sink ) ;
# endif
2015-09-18 15:55:56 +00:00
cur_header - > blocks [ NB_SECTIONS ] . offset = cbHdr + blocks_buf . getlen ( ) ;
2010-06-16 14:20:27 +00:00
section_writer : : write_block ( cur_sections , & sink ) ;
2015-09-18 15:55:56 +00:00
cur_header - > blocks [ NB_ENTRIES ] . offset = cbHdr + blocks_buf . getlen ( ) ;
2010-06-16 14:20:27 +00:00
entry_writer : : write_block ( cur_entries , & sink ) ;
2015-09-18 15:55:56 +00:00
cur_header - > blocks [ NB_STRINGS ] . offset = cbHdr + blocks_buf . getlen ( ) ;
2013-03-07 21:25:35 +00:00
blocks_buf . add ( cur_strlist - > getstorageptr ( ) , cur_strlist - > gettotalsize ( ) ) ;
2010-06-16 14:20:27 +00:00
2015-09-18 15:55:56 +00:00
cur_header - > blocks [ NB_LANGTABLES ] . offset = cbHdr + blocks_buf . getlen ( ) ;
2010-06-16 14:20:27 +00:00
lang_table_writer : : write_block ( cur_langtables , & sink , cur_header - > langtable_size ) ;
2015-09-18 15:55:56 +00:00
cur_header - > blocks [ NB_CTLCOLORS ] . offset = cbHdr + blocks_buf . getlen ( ) ;
ctlcolors_writer : : write_block ( cur_ctlcolors , & sink ) ;
2010-06-16 14:20:27 +00:00
# ifdef NSIS_SUPPORT_BGBG
if ( cur_header - > bg_color1 ! = - 1 )
{
bg_font . lfFaceName [ LF_FACESIZE - 1 ] = 0 ;
2015-09-18 15:55:56 +00:00
cur_header - > blocks [ NB_BGFONT ] . offset = cbHdr + blocks_buf . getlen ( ) ;
2010-06-16 14:20:27 +00:00
LOGFONT_writer w ( & sink ) ;
w . write ( & bg_font ) ;
}
# endif
2015-09-18 15:55:56 +00:00
growbuf_writer_sink sink2 ( hdrbuf , ti ) ;
2010-06-16 14:20:27 +00:00
header_writer header ( & sink2 ) ;
2015-09-18 15:55:56 +00:00
header . write ( cur_header , ti ) ;
2010-06-16 14:20:27 +00:00
sink2 . write_growbuf ( & blocks_buf ) ;
}
int CEXEBuild : : SetVarsSection ( )
{
try {
init_res_editor ( ) ;
VerifyDeclaredUserVarRefs ( & m_UserVarNames ) ;
int MaxUserVars = m_UserVarNames . getnum ( ) ;
2013-12-08 23:48:13 +00:00
int stringSize = NSIS_MAX_STRLEN * ( build_unicode ? 2 : 1 ) ;
2012-09-06 22:43:31 +00:00
if ( ! res_editor - > SetPESectionVirtualSize ( NSIS_VARS_SECTION , MaxUserVars * stringSize ) )
2010-06-16 14:20:27 +00:00
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Internal compiler error #12346: invalid exehead cannot find section \" % " ) NPRIs _T ( " \" ! \n " ) , _T ( NSIS_VARS_SECTION ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
}
catch ( exception & err ) {
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " \n Error: % " ) NPRIs _T ( " \n " ) , CtoTStrParam ( err . what ( ) ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
return PS_OK ;
}
int CEXEBuild : : SetManifest ( )
{
try {
init_res_editor ( ) ;
2019-08-17 20:13:07 +00:00
manifest : : SPECIFICATION spec = { ( manifest : : flags ) manifest_flags , manifest_dpiaware , manifest_dpiawareness . c_str ( ) , manifest_lpaware , & manifest_sosl , manifest_maxversiontested . c_str ( ) } ;
2019-06-06 00:42:08 +00:00
string manifest = manifest : : generate ( manifest_comctl , manifest_exec_level , spec ) ;
2010-06-16 14:20:27 +00:00
if ( manifest = = " " )
return PS_OK ;
2019-08-16 19:07:02 +00:00
if ( ! build_unicode & & manifest_lpaware > = manifest : : lpaware_true )
throw std : : runtime_error ( " Incompatible option " ) ;
2019-02-10 20:45:40 +00:00
// TODO: Ideally we should allow this but we must be sure that the manifest is custom and not a manifest from the stub
//if (res_editor->ResourceExists(MAKEINTRESOURCE(24), 1, CResourceEditor::ANYLANGID))
// return PS_OK; // Allow user to completely override the manifest with PEAddResource
2010-06-16 14:20:27 +00:00
// Saved directly as binary into the exe.
2019-06-06 00:42:08 +00:00
res_editor - > UpdateResource ( MAKEINTRESOURCE ( 24 ) , 1 , NSIS_DEFAULT_LANG , ( LPBYTE ) const_cast < char * > ( manifest . c_str ( ) ) , ( DWORD ) manifest . length ( ) ) ;
2010-06-16 14:20:27 +00:00
}
catch ( exception & err ) {
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error setting manifest: % " ) NPRIs _T ( " \n " ) , CtoTStrParam ( err . what ( ) ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
return PS_OK ;
}
int CEXEBuild : : UpdatePEHeader ( )
{
try {
PIMAGE_NT_HEADERS headers = CResourceEditor : : GetNTHeaders ( m_exehead ) ;
// workaround for bug #2697027, #2725883, #2803097
2015-10-01 17:32:56 +00:00
* GetCommonMemberFromPEOptHdr ( headers - > OptionalHeader , MajorImageVersion ) = FIX_ENDIAN_INT16 ( 6 ) ;
* GetCommonMemberFromPEOptHdr ( headers - > OptionalHeader , MinorImageVersion ) = FIX_ENDIAN_INT16 ( 0 ) ;
2015-07-27 20:41:17 +00:00
// Override SubsystemVersion?
if ( PESubsysVerMaj ! = ( WORD ) - 1 )
{
2015-10-01 17:32:56 +00:00
* GetCommonMemberFromPEOptHdr ( headers - > OptionalHeader , MajorSubsystemVersion ) = FIX_ENDIAN_INT16 ( PESubsysVerMaj ) ;
* GetCommonMemberFromPEOptHdr ( headers - > OptionalHeader , MinorSubsystemVersion ) = FIX_ENDIAN_INT16 ( PESubsysVerMin ) ;
2015-07-27 20:41:17 +00:00
}
2014-08-15 19:15:06 +00:00
// DllCharacteristics
2018-06-04 14:49:21 +00:00
* GetCommonMemberFromPEOptHdr ( headers - > OptionalHeader , DllCharacteristics ) = FIX_ENDIAN_INT16 ( PEDllCharacteristics ) ;
2010-06-16 14:20:27 +00:00
} catch ( std : : runtime_error & err ) {
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error updating PE headers: % " ) NPRIs _T ( " \n " ) , CtoTStrParam ( err . what ( ) ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
return PS_OK ;
}
2010-06-16 15:07:05 +00:00
void CEXEBuild : : set_default_output_filename ( const tstring & filename )
{
2010-06-17 15:56:42 +00:00
if ( build_output_filename [ 0 ] = = 0 )
2014-05-20 17:26:33 +00:00
my_strncpy ( build_output_filename , filename . c_str ( ) , COUNTOF ( build_output_filename ) ) ;
2010-06-16 15:07:05 +00:00
}
2010-06-16 14:20:27 +00:00
int CEXEBuild : : check_write_output_errors ( ) const
{
if ( has_called_write_output )
{
ERROR_MSG ( _T ( " Error (write_output): write_output already called, can't continue \n " ) ) ;
return PS_ERROR ;
}
if ( ! build_output_filename [ 0 ] )
{
ERROR_MSG ( _T ( " Error: invalid script: never had OutFile command \n " ) ) ;
return PS_ERROR ;
}
if ( ! build_sections . getlen ( ) )
{
ERROR_MSG ( _T ( " Error: invalid script: no sections specified \n " ) ) ;
return PS_ERROR ;
}
if ( ! build_entries . getlen ( ) )
{
ERROR_MSG ( _T ( " Error: invalid script: no entries specified \n " ) ) ;
return PS_ERROR ;
}
if ( build_cursection )
{
ERROR_MSG ( _T ( " Error: Section left open at EOF \n " ) ) ;
return PS_ERROR ;
}
if ( sectiongroup_open_cnt )
{
ERROR_MSG ( _T ( " Error: SectionGroup left open at EOF \n " ) ) ;
return PS_ERROR ;
}
if ( cur_page )
{
ERROR_MSG ( _T ( " Error: PageEx left open at EOF \n " ) ) ;
return PS_ERROR ;
}
// deal with functions, for both install and uninstall modes.
if ( build_cursection_isfunc )
{
ERROR_MSG ( _T ( " Error: Function left open at EOF \n " ) ) ;
return PS_ERROR ;
}
return PS_OK ;
}
int CEXEBuild : : prepare_uninstaller ( ) {
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( ubuild_entries . getlen ( ) )
{
if ( ! uninstaller_writes_used )
{
2017-04-25 13:09:41 +00:00
warning ( DW_UNCODE_WITHOUT_UNEXE , _T ( " Uninstaller script code found but WriteUninstaller never used - no uninstaller will be created. " ) ) ;
2010-06-16 14:20:27 +00:00
return PS_OK ;
}
build_uninst . flags | = build_header . flags & ( CH_FLAGS_PROGRESS_COLORED | CH_FLAGS_NO_ROOT_DIR ) ;
set_uninstall_mode ( 1 ) ;
DefineInnerLangString ( NLF_UCAPTION ) ;
if ( resolve_coderefs ( _T ( " uninstall " ) ) )
return PS_ERROR ;
# ifdef NSIS_CONFIG_COMPONENTPAGE
// set sections to the first insttype
PrepareInstTypes ( ) ;
# endif
// Add standard strings to string table
AddStandardStrings ( ) ;
set_uninstall_mode ( 0 ) ;
}
else if ( uninstaller_writes_used )
{
ERROR_MSG ( _T ( " Error: no Uninstall section specified, but WriteUninstaller used %d time(s) \n " ) , uninstaller_writes_used ) ;
return PS_ERROR ;
}
# endif //NSIS_CONFIG_UNINSTALL_SUPPORT
return PS_OK ;
}
int CEXEBuild : : pack_exe_header ( )
{
if ( ! ( build_packname [ 0 ] & & build_packcmd [ 0 ] ) ) {
// header not asked to be packed
return PS_OK ;
}
// write out exe header, pack, read back in, and
// update the header info
2021-08-18 13:53:50 +00:00
if ( m_exehead_size ! = write_octets_to_file ( build_packname , m_exehead , m_exehead_size ) )
2010-06-16 14:20:27 +00:00
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: writing temporary file \" % " ) NPRIs _T ( " \" for pack \n " ) , build_packname ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
2014-08-07 12:31:51 +00:00
int ec = sane_system ( build_packcmd ) ;
if ( ec = = - 1 )
2010-06-16 14:20:27 +00:00
{
_tremove ( build_packname ) ;
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: calling packer on \" % " ) NPRIs _T ( " \" \n " ) , build_packname ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
2014-08-07 12:31:51 +00:00
if ( ec ! = 0 )
2017-04-25 13:09:41 +00:00
warning ( DW_PACKHDR_RETNONZERO , _T ( " Packer returned %d, \" % " ) NPRIs _T ( " \" might still be unpacked \n " ) , ec , build_packname ) ;
2010-06-16 14:20:27 +00:00
int result = update_exehead ( build_packname ) ;
_tremove ( build_packname ) ;
if ( result ! = PS_OK )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: reading temporary file \" % " ) NPRIs _T ( " \" after pack \n " ) , build_packname ) ;
2010-06-16 14:20:27 +00:00
return result ;
}
return PS_OK ;
}
int CEXEBuild : : write_output ( void )
{
# ifndef NSIS_CONFIG_CRC_SUPPORT
build_crcchk = 0 ;
# endif
RET_UNLESS_OK ( check_write_output_errors ( ) ) ;
has_called_write_output = true ;
2019-02-02 20:25:07 +00:00
if ( ! changed_target & & ! build_unicode )
warning ( DW_GENERIC_DEPRECATED , _T ( " ANSI targets are deprecated " ) ) ;
2010-06-16 14:20:27 +00:00
# ifdef NSIS_CONFIG_PLUGIN_SUPPORT
RET_UNLESS_OK ( add_plugins_dir_initializer ( ) ) ;
# endif //NSIS_CONFIG_PLUGIN_SUPPORT
# ifdef NSIS_SUPPORT_VERSION_INFO
RET_UNLESS_OK ( AddVersionInfo ( ) ) ;
# endif //NSIS_SUPPORT_VERSION_INFO
RET_UNLESS_OK ( prepare_uninstaller ( ) ) ;
DefineInnerLangString ( NLF_CAPTION ) ;
if ( resolve_coderefs ( _T ( " install " ) ) )
return PS_ERROR ;
# ifdef NSIS_CONFIG_COMPONENTPAGE
// set sections to the first insttype
PrepareInstTypes ( ) ;
# endif
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
RET_UNLESS_OK ( ProcessPages ( ) ) ;
# endif //NSIS_CONFIG_VISIBLE_SUPPORT
// Generate language tables
RET_UNLESS_OK ( GenerateLangTables ( ) ) ;
// Setup user variables PE section
RET_UNLESS_OK ( SetVarsSection ( ) ) ;
// Set XML manifest
RET_UNLESS_OK ( SetManifest ( ) ) ;
// Add standard strings to string table
AddStandardStrings ( ) ;
try {
// Load icon from exe, if needed
if ( installer_icon . empty ( ) )
{
init_res_editor ( ) ;
installer_icon = load_icon_res ( res_editor , IDI_ICON2 ) ;
}
// Set icon
2019-02-10 20:45:40 +00:00
set_main_icon ( res_editor , IDI_ICON2 , installer_icon , uninstaller_icon ) ;
2010-06-16 14:20:27 +00:00
// Save all changes to the exe header
close_res_editor ( ) ;
}
catch ( exception & err ) {
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " \n Error: % " ) NPRIs _T ( " \n " ) , CtoTStrParam ( err . what ( ) ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
// Final PE touch-ups
RET_UNLESS_OK ( UpdatePEHeader ( ) ) ;
RET_UNLESS_OK ( pack_exe_header ( ) ) ;
build_optimize_datablock = 0 ;
int data_block_size_before_uninst = build_datablock . getlen ( ) ;
RET_UNLESS_OK ( uninstall_generate ( ) ) ;
2020-04-20 17:21:04 +00:00
unsigned char limit = 0 ; // Limit the number of retries in case the host has some kind of bug
retry_output :
2010-06-16 14:20:27 +00:00
{
2016-02-16 18:01:53 +00:00
tstring full_path = get_full_path ( build_output_filename ) , fnamebuf = get_file_name ( build_output_filename ) ;
2013-03-14 18:00:00 +00:00
notify ( MakensisAPI : : NOTIFY_OUTPUT , full_path . c_str ( ) ) ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " \n Output: \" % " ) NPRIs _T ( " \" \n " ) , full_path . c_str ( ) ) ;
2016-02-16 18:01:53 +00:00
const TCHAR * fname = fnamebuf . c_str ( ) ;
2016-02-16 14:35:20 +00:00
// Warn when special compatibility names are used. See also: http://github.com/wixtoolset/wix4/commit/3f4341b8ac4d13dffb1d6ba773d48ccc0ab07cf8
2016-03-17 21:36:06 +00:00
if ( ! _tcsicmp ( fname , _T ( " setup.exe " ) ) )
2016-02-16 14:35:20 +00:00
{
const bool orgdispwarn = display_warnings ;
display_warnings = false ; // Don't display warning inline in the middle of our statistics output.
2017-04-25 13:09:41 +00:00
warning ( DW_INSECURE_OUTFILENAME , _T ( " Insecure filename \" % " ) NPRIs _T ( " \" , Windows will unsafely load compatibility shims into the process. " ) , fname ) ;
2016-02-16 14:35:20 +00:00
display_warnings = orgdispwarn ;
}
2010-06-16 14:20:27 +00:00
}
2012-03-01 21:06:14 +00:00
FILE * fp = FOPEN ( build_output_filename , ( " w+b " ) ) ;
2010-06-16 14:20:27 +00:00
if ( ! fp )
{
ERROR_MSG ( _T ( " Can't open output file \n " ) ) ;
2020-04-20 17:21:04 +00:00
if ( + + limit & & prompt_for_output_path ( build_output_filename , COUNTOF ( CEXEBuild : : build_output_filename ) ) ) goto retry_output ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
if ( fwrite ( m_exehead , 1 , m_exehead_size , fp ) ! = m_exehead_size )
{
ERROR_MSG ( _T ( " Error: can't write %d bytes to output \n " ) , m_exehead_size ) ;
fclose ( fp ) ;
return PS_ERROR ;
}
2020-04-20 17:21:04 +00:00
crc32_t crc = 0 ;
2010-06-16 14:20:27 +00:00
# ifdef NSIS_CONFIG_CRC_SUPPORT
# ifdef NSIS_CONFIG_CRC_ANAL
2014-02-08 00:13:52 +00:00
crc = CRC32 ( crc , m_exehead , ( DWORD ) m_exehead_size ) ;
2010-06-16 14:20:27 +00:00
# else
2014-02-08 00:13:52 +00:00
crc = CRC32 ( crc , m_exehead + 512 , ( DWORD ) m_exehead_size - 512 ) ;
2010-06-16 14:20:27 +00:00
# endif
# endif
firstheader fh = { 0 , } ;
fh . nsinst [ 0 ] = FH_INT1 ;
fh . nsinst [ 1 ] = FH_INT2 ;
fh . nsinst [ 2 ] = FH_INT3 ;
# ifdef NSIS_CONFIG_CRC_SUPPORT
fh . flags = ( build_crcchk ? ( build_crcchk = = 2 ? FH_FLAGS_FORCE_CRC : 0 ) : FH_FLAGS_NO_CRC ) ;
# else
fh . flags = 0 ;
# endif
# ifdef NSIS_CONFIG_SILENT_SUPPORT
if ( build_header . flags & ( CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG ) ) fh . flags | = FH_FLAGS_SILENT ;
# endif
fh . siginfo = FH_SIG ;
int installinfo_compressed ;
int fd_start = 0 ;
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
if ( build_compress_whole )
{
int n = compressor - > Init ( build_compress_level , build_compress_dict_size ) ;
if ( n ! = C_OK )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Internal compiler error #12345: deflateInit() failed(% " ) NPRIs _T ( " [%d]). \n " ) , compressor - > GetErrStr ( n ) , n ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
}
# endif
{
GrowBuf ihd ;
{
GrowBuf hdrcomp ;
PrepareHeaders ( & hdrcomp ) ;
if ( add_data ( ( char * ) hdrcomp . get ( ) , hdrcomp . getlen ( ) , & ihd ) < 0 )
return PS_ERROR ;
fh . length_of_header = hdrcomp . getlen ( ) ;
installinfo_compressed = ihd . getlen ( ) ;
}
if ( ! build_compress_whole )
fh . length_of_all_following_data = ihd . getlen ( ) + build_datablock . getlen ( ) + ( int ) sizeof ( firstheader ) + ( build_crcchk ? sizeof ( crc32_t ) : 0 ) ;
else
fd_start = ftell ( fp ) ;
try
{
2015-09-18 15:55:56 +00:00
file_writer_sink sink ( fp , mk_writer_target_info ( ) ) ;
2010-06-16 14:20:27 +00:00
firstheader_writer w ( & sink ) ;
w . write ( & fh ) ;
}
catch ( . . . )
{
ERROR_MSG ( _T ( " Error: can't write %d bytes to output \n " ) , sizeof ( fh ) ) ;
fclose ( fp ) ;
return PS_ERROR ;
}
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
if ( build_compress_whole ) {
if ( deflateToFile ( fp , ( char * ) ihd . get ( ) , ihd . getlen ( ) ) )
{
fclose ( fp ) ;
return PS_ERROR ;
}
}
else
# endif
{
if ( fwrite ( ihd . get ( ) , 1 , ihd . getlen ( ) , fp ) ! = ( unsigned int ) ihd . getlen ( ) )
{
ERROR_MSG ( _T ( " Error: can't write %d bytes to output \n " ) , ihd . getlen ( ) ) ;
fclose ( fp ) ;
return PS_ERROR ;
}
# ifdef NSIS_CONFIG_CRC_SUPPORT
crc_writer_sink crc_sink ( ( crc32_t * ) & crc ) ;
firstheader_writer w ( & crc_sink ) ;
w . write ( & fh ) ;
crc = CRC32 ( crc , ( unsigned char * ) ihd . get ( ) , ihd . getlen ( ) ) ;
# endif
}
}
INFO_MSG ( _T ( " Install: " ) ) ;
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
int np = build_header . blocks [ NB_PAGES ] . num ;
2013-12-08 15:41:47 +00:00
if ( PAGE_COMPLETED ! = PAGE_INSTFILES & & np ) - - np ; // Special page not part of count
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d page% " ) NPRIs _T ( " (%d bytes), " ) , np , np = = 1 ? _T ( " " ) : _T ( " s " ) , np * sizeof ( page ) ) ;
2010-06-16 14:20:27 +00:00
# endif
2021-09-04 01:13:22 +00:00
# define IsRequiredSection(s) ( (!(s).name_ptr && ((s).flags & SF_SELECTED)) || (((s).flags & (SF_RO|SF_SELECTED)) == (SF_RO|SF_SELECTED)))
2010-06-16 14:20:27 +00:00
{
2021-09-04 01:06:30 +00:00
int ns = build_sections . getlen ( ) / sizeof ( section ) , x ;
2010-06-16 14:20:27 +00:00
section * s = ( section * ) build_sections . get ( ) ;
2012-11-12 21:24:37 +00:00
unsigned int req = 0 ;
2021-09-04 01:06:30 +00:00
for ( x = 0 ; x < ns ; x + + ) if ( IsRequiredSection ( s [ x ] ) ) + + req ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d section% " ) NPRIs , ns , ns = = 1 ? _T ( " " ) : _T ( " s " ) ) ;
2021-09-04 01:06:30 +00:00
if ( req ) INFO_MSG ( _T ( " (%u required) " ) , req ) ;
2010-06-16 14:20:27 +00:00
INFO_MSG ( _T ( " (%d bytes), " ) , build_sections . getlen ( ) ) ;
}
int ne = build_header . blocks [ NB_ENTRIES ] . num ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d instruction% " ) NPRIs _T ( " (%d bytes), " ) , ne , ne = = 1 ? _T ( " " ) : _T ( " s " ) , ne * sizeof ( entry ) ) ;
2010-06-16 14:20:27 +00:00
int ns = build_strlist . getnum ( ) ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d string% " ) NPRIs _T ( " (%d bytes), " ) , ns , ns = = 1 ? _T ( " " ) : _T ( " s " ) , build_strlist . gettotalsize ( ) ) ;
2010-06-16 14:20:27 +00:00
int nlt = build_header . blocks [ NB_LANGTABLES ] . num ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d language table% " ) NPRIs _T ( " (%d bytes). \n " ) , nlt , nlt = = 1 ? _T ( " " ) : _T ( " s " ) , build_langtables . getlen ( ) ) ;
2010-06-16 14:20:27 +00:00
if ( ubuild_entries . getlen ( ) )
{
INFO_MSG ( _T ( " Uninstall: " ) ) ;
# ifdef NSIS_CONFIG_VISIBLE_SUPPORT
np = build_uninst . blocks [ NB_PAGES ] . num ;
2013-12-08 15:41:47 +00:00
if ( PAGE_COMPLETED ! = PAGE_INSTFILES & & np ) - - np ; // Special page not part of count
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d page% " ) NPRIs _T ( " (%d bytes), " ) , np , np = = 1 ? _T ( " " ) : _T ( " s " ) , ubuild_pages . getlen ( ) ) ;
2010-06-16 14:20:27 +00:00
# endif
{
2021-09-04 01:06:30 +00:00
int ns = ubuild_sections . getlen ( ) / sizeof ( section ) , x ;
2010-06-16 14:20:27 +00:00
section * s = ( section * ) ubuild_sections . get ( ) ;
2012-11-12 21:24:37 +00:00
unsigned int req = 0 ;
2021-09-04 01:06:30 +00:00
for ( x = 0 ; x < ns ; x + + ) if ( IsRequiredSection ( s [ x ] ) ) + + req ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d section% " ) NPRIs , ns , ns = = 1 ? _T ( " " ) : _T ( " s " ) ) ;
2021-09-04 01:06:30 +00:00
if ( req ) INFO_MSG ( _T ( " (%u required) " ) , req ) ;
2010-06-16 14:20:27 +00:00
INFO_MSG ( _T ( " (%d bytes), " ) , ubuild_sections . getlen ( ) ) ;
}
ne = build_uninst . blocks [ NB_ENTRIES ] . num ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d instruction% " ) NPRIs _T ( " (%d bytes), " ) , ne , ne = = 1 ? _T ( " " ) : _T ( " s " ) , ubuild_entries . getlen ( ) ) ;
2010-06-16 14:20:27 +00:00
ns = ubuild_strlist . getnum ( ) ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d string% " ) NPRIs _T ( " (%d bytes), " ) , ns , ns = = 1 ? _T ( " " ) : _T ( " s " ) , ubuild_strlist . gettotalsize ( ) ) ;
2010-06-16 14:20:27 +00:00
nlt = build_uninst . blocks [ NB_LANGTABLES ] . num ;
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " %d language table% " ) NPRIs _T ( " (%d bytes). \n " ) , nlt , nlt = = 1 ? _T ( " " ) : _T ( " s " ) , ubuild_langtables . getlen ( ) ) ;
2010-06-16 14:20:27 +00:00
}
if ( db_opt_save )
{
2014-05-19 22:03:09 +00:00
size_t total_out_size_estimate =
2014-03-31 17:34:58 +00:00
m_exehead_size + sizeof ( fh ) + build_datablock . getlen ( ) + ( build_crcchk ? sizeof ( crc32_t ) : 0 ) ;
int pc = ( int ) ( ( db_opt_save * 1000 ) / ( db_opt_save + total_out_size_estimate ) ) ;
2014-04-05 16:50:11 +00:00
FriendlySize fs ( db_opt_save ) ;
INFO_MSG ( _T ( " Datablock optimizer saved %u% " ) NPRIs _T ( " (~%d.%d%%). \n " ) ,
fs . UInt ( ) , fs . Scale ( ) , pc / 10 , pc % 10 ) ;
2010-06-16 14:20:27 +00:00
}
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
2013-12-08 14:34:38 +00:00
INFO_MSG ( _T ( " \n Using % " ) NPRIs _T ( " % " ) NPRIs _T ( " compression. \n \n " ) , compressor - > GetName ( ) , build_compress_whole ? _T ( " (compress whole) " ) : _T ( " " ) ) ;
2010-06-16 14:20:27 +00:00
# endif
2014-02-08 00:13:52 +00:00
unsigned int total_usize = ( unsigned int ) m_exehead_original_size ;
2010-06-16 14:20:27 +00:00
2012-11-12 21:24:37 +00:00
INFO_MSG ( _T ( " EXE header size: %10u / %u bytes \n " ) , m_exehead_size , m_exehead_original_size ) ;
2010-06-16 14:20:27 +00:00
if ( build_compress_whole ) {
INFO_MSG ( _T ( " Install code: (%d bytes) \n " ) ,
sizeof ( fh ) + fh . length_of_header ) ;
}
else {
INFO_MSG ( _T ( " Install code: %10d / %d bytes \n " ) ,
sizeof ( fh ) + installinfo_compressed ,
sizeof ( fh ) + fh . length_of_header ) ;
}
total_usize + = sizeof ( fh ) + fh . length_of_header ;
{
2014-04-05 16:50:11 +00:00
unsigned int dbsize ;
UINT64 dbsizeu ;
2010-06-16 14:20:27 +00:00
dbsize = build_datablock . getlen ( ) ;
2012-11-12 21:24:37 +00:00
if ( uninstall_size > 0 ) dbsize - = uninstall_size ;
2010-06-16 14:20:27 +00:00
if ( build_compress_whole ) {
2012-11-12 21:24:37 +00:00
dbsizeu = dbsize ;
2014-04-05 16:50:11 +00:00
INFO_MSG ( _T ( " Install data: (%u bytes) \n " ) , dbsize ) ; // dbsize==dbsizeu and is easy to print
2010-06-16 14:20:27 +00:00
}
else {
dbsizeu = db_full_size - uninstall_size_full ;
2014-04-05 16:50:11 +00:00
FriendlySize us ( dbsizeu , GFSF_BYTESIFPOSSIBLE ) ; // uncompressed installer size
FriendlySize cs ( dbsize , GFSF_BYTESIFPOSSIBLE | ( us . UInt ( ) = = dbsizeu ? GFSF_HIDEBYTESCALE : 0 ) ) ; // compressed installer size
INFO_MSG ( _T ( " Install data: %10u% " ) NPRIs _T ( " / %u% " ) NPRIs _T ( " \n " ) ,
cs . UInt ( ) , cs . Scale ( ) , us . UInt ( ) , us . Scale ( ) ) ; // "123 / 456 bytes" or "123 KiB / 456 MiB"
2010-06-16 14:20:27 +00:00
}
2014-04-05 16:50:11 +00:00
UINT future = ( build_crcchk ? sizeof ( int ) : 0 ) + ( uninstall_size > 0 ? uninstall_size_full : 0 ) ;
UINT maxsize = ( ~ ( UINT ) 0 ) - ( total_usize + future ) , totsizadd = dbsizeu < maxsize ? ( UINT ) dbsizeu : maxsize ;
total_usize + = totsizadd ; // Might not be accurate, it is more important to not overflow the additions coming up
2010-06-16 14:20:27 +00:00
}
if ( uninstall_size > = 0 )
{
if ( build_compress_whole )
INFO_MSG ( _T ( " Uninstall code+data: (%d bytes) \n " ) , uninstall_size_full ) ;
else
INFO_MSG ( _T ( " Uninstall code+data: %6d / %d bytes \n " ) , uninstall_size , uninstall_size_full ) ;
2012-11-12 21:24:37 +00:00
total_usize + = uninstall_size_full ;
2010-06-16 14:20:27 +00:00
}
if ( build_compress_whole ) {
INFO_MSG ( _T ( " Compressed data: " ) ) ;
}
if ( build_datablock . getlen ( ) )
{
build_datablock . setro ( TRUE ) ;
int dbl = build_datablock . getlen ( ) ;
int left = dbl ;
while ( left > 0 )
{
int l = min ( build_filebuflen , left ) ;
char * dbptr = ( char * ) build_datablock . get ( dbl - left , l ) ;
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
if ( build_compress_whole )
{
if ( deflateToFile ( fp , dbptr , l ) )
{
fclose ( fp ) ;
return PS_ERROR ;
}
}
else
# endif
{
# ifdef NSIS_CONFIG_CRC_SUPPORT
crc = CRC32 ( crc , ( unsigned char * ) dbptr , l ) ;
# endif
if ( ( int ) fwrite ( dbptr , 1 , l , fp ) ! = l )
{
ERROR_MSG ( _T ( " Error: can't write %d bytes to output \n " ) , l ) ;
fclose ( fp ) ;
return PS_ERROR ;
}
fflush ( fp ) ;
}
build_datablock . release ( ) ;
left - = l ;
}
build_datablock . setro ( FALSE ) ;
build_datablock . clear ( ) ;
}
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
if ( build_compress_whole )
{
if ( deflateToFile ( fp , NULL , 0 ) )
{
fclose ( fp ) ;
return PS_ERROR ;
}
compressor - > End ( ) ;
unsigned fend = ftell ( fp ) ;
fh . length_of_all_following_data = ftell ( fp ) - fd_start + ( build_crcchk ? sizeof ( crc32_t ) : 0 ) ;
INFO_MSG (
_T ( " %10d / %d bytes \n " ) ,
ftell ( fp ) - fd_start ,
data_block_size_before_uninst + fh . length_of_header + sizeof ( firstheader ) + uninstall_size_full
) ;
fseek ( fp , fd_start , SEEK_SET ) ;
try
{
2015-09-18 15:55:56 +00:00
file_writer_sink sink ( fp , mk_writer_target_info ( ) ) ;
2010-06-16 14:20:27 +00:00
firstheader_writer w ( & sink ) ;
w . write ( & fh ) ;
}
catch ( . . . )
{
ERROR_MSG ( _T ( " Error: can't write %d bytes to output \n " ) , sizeof ( fh ) ) ;
fclose ( fp ) ;
return PS_ERROR ;
}
# ifdef NSIS_CONFIG_CRC_SUPPORT
if ( build_crcchk )
{
// check rest of CRC
fseek ( fp , fd_start , SEEK_SET ) ;
for ( ; ; )
{
char buf [ 32768 ] ;
2014-02-08 00:13:52 +00:00
unsigned int l = ( unsigned int ) fread ( buf , 1 , sizeof ( buf ) , fp ) ;
2010-06-16 14:20:27 +00:00
if ( ! l ) break ;
crc = CRC32 ( crc , ( unsigned char * ) buf , l ) ;
}
}
# endif
fseek ( fp , fend , SEEK_SET ) ; // reset eof flag
}
# endif
if ( build_crcchk )
{
total_usize + = sizeof ( int ) ;
int rcrc = FIX_ENDIAN_INT32 ( crc ) ;
if ( fwrite ( & rcrc , 1 , sizeof ( crc32_t ) , fp ) ! = sizeof ( crc32_t ) )
{
ERROR_MSG ( _T ( " Error: can't write %d bytes to output \n " ) , sizeof ( crc32_t ) ) ;
fclose ( fp ) ;
return PS_ERROR ;
}
INFO_MSG ( _T ( " CRC (0x%08X): 4 / 4 bytes \n " ) , crc ) ;
}
INFO_MSG ( _T ( " \n " ) ) ;
{
2014-04-05 16:50:11 +00:00
long fileend = ftell ( fp ) ;
UINT pc = ( UINT ) ( ( ( UINT64 ) fileend * 1000 ) / ( total_usize ) ) ;
2010-06-16 14:20:27 +00:00
INFO_MSG ( _T ( " Total size: %10u / %u bytes (%u.%u%%) \n " ) ,
2014-04-05 16:50:11 +00:00
fileend , total_usize , pc / 10 , pc % 10 ) ;
2010-06-16 14:20:27 +00:00
}
fclose ( fp ) ;
2018-10-24 19:01:00 +00:00
RET_UNLESS_OK ( run_postbuild_cmds ( postbuild_cmds , build_output_filename , _T ( " Finalize " ) ) ) ;
2010-06-16 14:20:27 +00:00
print_warnings ( ) ;
return PS_OK ;
}
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
int CEXEBuild : : deflateToFile ( FILE * fp , char * buf , int len ) // len==0 to flush
{
build_compressor_set = true ;
char obuf [ 65536 ] ;
bool flush = false ;
compressor - > SetNextIn ( buf , len ) ;
if ( ! buf | | ! len )
{
char a ;
compressor - > SetNextIn ( & a , 0 ) ;
flush = C_FINISH ;
}
for ( ; ; )
{
compressor - > SetNextOut ( obuf , sizeof ( obuf ) ) ;
int ret = compressor - > Compress ( flush ) ;
if ( ret < 0 & & ( ret ! = - 1 | | ! flush ) )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: deflateToFile: deflate() failed(% " ) NPRIs _T ( " [%d]) \n " ) , compressor - > GetErrStr ( ret ) , ret ) ;
2010-06-16 14:20:27 +00:00
return 1 ;
}
2014-02-11 01:34:11 +00:00
size_t l = compressor - > GetNextOut ( ) - obuf ;
2010-06-16 14:20:27 +00:00
if ( l )
{
2014-02-11 01:34:11 +00:00
if ( fwrite ( obuf , 1 , l , fp ) ! = l )
2010-06-16 14:20:27 +00:00
{
2014-02-11 01:34:11 +00:00
ERROR_MSG ( _T ( " Error: deflateToFile fwrite(%lu) failed \n " ) , ( unsigned long ) l ) ;
2010-06-16 14:20:27 +00:00
return 1 ;
}
fflush ( fp ) ;
}
if ( ! compressor - > GetAvailIn ( ) & & ( ! flush | | ! l ) ) break ;
}
return 0 ;
}
# endif
int CEXEBuild : : uninstall_generate ( )
{
# ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if ( ubuild_entries . getlen ( ) & & uninstaller_writes_used )
{
SCRIPT_MSG ( _T ( " Generating uninstaller... " ) ) ;
2021-08-18 13:53:50 +00:00
const int start_offset = postubuild_cmds ? truncate_cast ( int , m_exehead_size ) : 0 ;
entry * ent = ( entry * ) build_entries . get ( ) ;
if ( ! ent ) return PS_ERROR ; // Check this early
MMapBuf udata ;
2010-06-16 14:20:27 +00:00
firstheader fh = { 0 , } ;
GrowBuf uhd ;
{
2021-08-18 13:53:50 +00:00
GrowBuf udata_exehead ;
2010-06-16 14:20:27 +00:00
set_uninstall_mode ( 1 ) ;
2021-08-18 13:53:50 +00:00
PrepareHeaders ( & udata_exehead ) ;
2010-06-16 14:20:27 +00:00
2021-08-18 13:53:50 +00:00
fh . length_of_header = udata_exehead . getlen ( ) ;
int err = add_data ( ( char * ) udata_exehead . get ( ) , udata_exehead . getlen ( ) , & uhd ) ;
2010-06-16 14:20:27 +00:00
set_uninstall_mode ( 0 ) ;
if ( err < 0 ) return PS_ERROR ;
}
crc32_t crc = 0 ;
2021-08-18 13:53:50 +00:00
# ifdef NSIS_CONFIG_CRC_SUPPORT
bool calc_crc = true ;
# else
bool calc_crc = false ;
# endif
2010-06-16 14:20:27 +00:00
// Get offsets of icons to replace for uninstall
// Also makes sure that the icons are there and in the right size.
LPBYTE unicon_data = generate_uninstall_icon_data ( installer_icon , uninstaller_icon , m_unicon_size ) ;
if ( generate_unicons_offsets ( m_exehead , m_exehead_size , unicon_data , IDI_ICON2 ) = = 0 )
{
delete [ ] unicon_data ;
return PS_ERROR ;
}
int uns = uninstaller_writes_used ;
int uninstdata_offset = build_datablock . getlen ( ) ;
2021-08-18 13:53:50 +00:00
for ( int ents = build_header . blocks [ NB_ENTRIES ] . num ; ents - - ; ent + + )
2010-06-16 14:20:27 +00:00
{
if ( ent - > which = = EW_WRITEUNINSTALLER )
{
ent - > offsets [ 1 ] = uninstdata_offset ;
2021-08-18 13:53:50 +00:00
ent - > offsets [ 2 ] = start_offset ? 0 : ( int ) m_unicon_size ;
if ( ! - - uns )
2010-06-16 14:20:27 +00:00
break ;
}
}
2021-08-18 13:53:50 +00:00
if ( ! start_offset & & add_db_data ( ( char * ) unicon_data , m_unicon_size ) < 0 )
2010-06-16 14:20:27 +00:00
{
delete [ ] unicon_data ;
return PS_ERROR ;
}
2021-08-18 13:53:50 +00:00
if ( start_offset | | calc_crc )
2010-06-16 14:20:27 +00:00
{
2021-08-18 13:53:50 +00:00
// create the uninstaller
2010-06-16 14:20:27 +00:00
LPBYTE uninst_header = ( LPBYTE ) malloc ( m_exehead_size ) ;
if ( ! uninst_header )
2021-08-18 13:53:50 +00:00
{
delete [ ] unicon_data ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
2021-08-18 13:53:50 +00:00
}
2010-06-16 14:20:27 +00:00
memcpy ( uninst_header , m_exehead , m_exehead_size ) ;
// patch the icons
LPBYTE seeker = unicon_data ;
while ( * seeker ) {
DWORD dwSize = FIX_ENDIAN_INT32 ( * ( LPDWORD ) seeker ) ;
seeker + = sizeof ( DWORD ) ;
DWORD dwOffset = FIX_ENDIAN_INT32 ( * ( LPDWORD ) seeker ) ;
seeker + = sizeof ( DWORD ) ;
memcpy ( uninst_header + dwOffset , seeker , dwSize ) ;
seeker + = dwSize ;
}
2021-08-18 13:53:50 +00:00
if ( calc_crc )
{
# ifdef NSIS_CONFIG_CRC_SUPPORT
2010-06-16 14:20:27 +00:00
# ifdef NSIS_CONFIG_CRC_ANAL
2021-08-18 13:53:50 +00:00
crc = CRC32 ( crc , uninst_header , ( DWORD ) m_exehead_size ) ;
2010-06-16 14:20:27 +00:00
# else
2021-08-18 13:53:50 +00:00
crc = CRC32 ( crc , uninst_header + 512 , ( DWORD ) m_exehead_size - 512 ) ;
# endif
2010-06-16 14:20:27 +00:00
# endif
2021-08-18 13:53:50 +00:00
}
// write the exehead
if ( start_offset )
udata . add ( ( char * ) uninst_header , truncate_cast ( int , m_exehead_size ) ) ;
2010-06-16 14:20:27 +00:00
free ( uninst_header ) ;
}
2021-08-18 13:53:50 +00:00
delete [ ] unicon_data ;
2010-06-16 14:20:27 +00:00
fh . nsinst [ 0 ] = FH_INT1 ;
fh . nsinst [ 1 ] = FH_INT2 ;
fh . nsinst [ 2 ] = FH_INT3 ;
fh . flags = FH_FLAGS_UNINSTALL ;
# ifdef NSIS_CONFIG_CRC_SUPPORT
fh . flags | = ( build_crcchk ? ( build_crcchk = = 2 ? FH_FLAGS_FORCE_CRC : 0 ) : FH_FLAGS_NO_CRC ) ;
# endif
# ifdef NSIS_CONFIG_SILENT_SUPPORT
if ( build_uninst . flags & ( CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG ) ) fh . flags | = FH_FLAGS_SILENT ;
# endif
fh . siginfo = FH_SIG ;
fh . length_of_all_following_data =
uhd . getlen ( ) + ubuild_datablock . getlen ( ) + ( int ) sizeof ( firstheader ) + ( build_crcchk ? sizeof ( crc32_t ) : 0 ) ;
{
2015-09-18 15:55:56 +00:00
growbuf_writer_sink sink ( & udata , mk_writer_target_info ( ) ) ;
2010-06-16 14:20:27 +00:00
firstheader_writer w ( & sink ) ;
w . write ( & fh ) ;
}
ubuild_datablock . setro ( TRUE ) ;
# ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
if ( build_compress_whole ) {
// compress uninstaller too
{
char obuf [ 65536 ] ;
int n = compressor - > Init ( build_compress_level , build_compress_dict_size ) ;
if ( n ! = C_OK )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Internal compiler error #12345: deflateInit() failed(% " ) NPRIs _T ( " [%d]). \n " ) , compressor - > GetErrStr ( n ) , n ) ;
2010-06-16 14:20:27 +00:00
extern void quit ( ) ; quit ( ) ;
}
compressor - > SetNextIn ( ( char * ) uhd . get ( ) , uhd . getlen ( ) ) ;
while ( compressor - > GetAvailIn ( ) )
{
compressor - > SetNextOut ( obuf , sizeof ( obuf ) ) ;
compressor - > Compress ( 0 ) ;
if ( compressor - > GetNextOut ( ) - obuf > 0 )
{
2015-09-17 14:30:07 +00:00
udata . add ( obuf , truncate_cast ( int , ( size_t ) ( compressor - > GetNextOut ( ) - obuf ) ) ) ;
2010-06-16 14:20:27 +00:00
}
}
int avail_in = ubuild_datablock . getlen ( ) ;
int in_pos = 0 ;
while ( avail_in > 0 ) {
int l = min ( avail_in , build_filebuflen ) ;
char * p = ( char * ) ubuild_datablock . get ( in_pos , l ) ;
compressor - > SetNextIn ( p , l ) ;
while ( compressor - > GetAvailIn ( ) )
{
compressor - > SetNextOut ( obuf , sizeof ( obuf ) ) ;
compressor - > Compress ( 0 ) ;
if ( compressor - > GetNextOut ( ) - obuf > 0 )
2015-09-17 14:30:07 +00:00
udata . add ( obuf , truncate_cast ( int , ( size_t ) ( compressor - > GetNextOut ( ) - obuf ) ) ) ;
2010-06-16 14:20:27 +00:00
}
ubuild_datablock . release ( ) ;
avail_in - = l ;
in_pos + = l ;
}
for ( ; ; )
{
compressor - > SetNextOut ( obuf , sizeof ( obuf ) ) ;
compressor - > Compress ( C_FINISH ) ;
if ( compressor - > GetNextOut ( ) - obuf > 0 )
2015-09-17 14:30:07 +00:00
udata . add ( obuf , truncate_cast ( int , ( size_t ) ( compressor - > GetNextOut ( ) - obuf ) ) ) ;
2010-06-16 14:20:27 +00:00
else break ;
}
compressor - > End ( ) ;
}
2021-08-18 13:53:50 +00:00
firstheader * ufh = ( firstheader * ) udata . get ( start_offset , sizeof ( firstheader ) ) ;
ufh - > length_of_all_following_data = FIX_ENDIAN_INT32 ( ( udata . getlen ( ) - start_offset ) + ( build_crcchk ? sizeof ( crc32_t ) : 0 ) ) ;
2010-06-16 14:20:27 +00:00
udata . release ( ) ;
}
else
# endif //NSIS_CONFIG_COMPRESSION_SUPPORT
{
udata . add ( uhd . get ( ) , uhd . getlen ( ) ) ;
int st = udata . getlen ( ) ;
int length = ubuild_datablock . getlen ( ) ;
int left = length ;
udata . resize ( st + left ) ;
while ( left > 0 )
{
int l = min ( build_filebuflen , left ) ;
void * p = ubuild_datablock . get ( length - left , l ) ;
memcpy ( udata . get ( st + length - left , l ) , p , l ) ;
udata . flush ( l ) ;
udata . release ( ) ;
ubuild_datablock . release ( ) ;
left - = l ;
}
}
ubuild_datablock . clear ( ) ;
udata . setro ( TRUE ) ;
# ifdef NSIS_CONFIG_CRC_SUPPORT
if ( build_crcchk )
{
int pos = 0 ;
2021-08-18 13:53:50 +00:00
int left = udata . getlen ( ) - start_offset ;
2010-06-16 14:20:27 +00:00
while ( left > 0 )
{
int l = min ( build_filebuflen , left ) ;
2021-08-18 13:53:50 +00:00
crc = CRC32 ( crc , ( unsigned char * ) udata . get ( pos + start_offset , l ) , l ) ;
2010-06-16 14:20:27 +00:00
udata . release ( ) ;
pos + = l ;
left - = l ;
}
udata . setro ( FALSE ) ;
FIX_ENDIAN_INT32_INPLACE ( crc ) ;
udata . add ( & crc , sizeof ( crc ) ) ;
udata . setro ( TRUE ) ;
}
# endif
2021-08-18 13:53:50 +00:00
if ( start_offset )
{
TCHAR * fpath ;
unsigned long in_len ;
if ( ! ( fpath = create_tempfile_path ( ) ) )
{
ERROR_MSG ( _T ( " Error: can't get temporary path \n " ) ) ;
return PS_ERROR ;
}
size_t ret_size = write_octets_to_file ( fpath , ( unsigned char * ) udata . get ( 0 , udata . getlen ( ) ) , udata . getlen ( ) ) ;
udata . release ( ) ;
if ( ( size_t ) udata . getlen ( ) ! = ret_size )
{
ERROR_MSG ( _T ( " Error: can't write %d bytes to output \n " ) , udata . getlen ( ) ) ;
free ( fpath ) ;
return PS_ERROR ;
}
if ( PS_OK ! = run_postbuild_cmds ( postubuild_cmds , fpath , _T ( " UninstFinalize " ) ) )
{
free ( fpath ) ;
return PS_ERROR ;
}
BYTE * in_buf = alloc_and_read_file ( fpath , in_len ) ;
_tremove ( fpath ) ;
free ( fpath ) ;
if ( ! in_buf )
{
ERROR_MSG ( _T ( " Error: can't read %d bytes from input \n " ) , in_len ) ;
return PS_ERROR ;
}
MMapBuf udata_in ;
udata_in . add ( in_buf , in_len ) ;
free ( in_buf ) ;
2010-06-16 14:20:27 +00:00
2021-08-18 13:53:50 +00:00
if ( add_db_data ( & udata_in ) < 0 )
return PS_ERROR ;
uninstall_size_full = udata_in . getlen ( ) ;
udata_in . clear ( ) ;
}
else
{
if ( add_db_data ( & udata ) < 0 )
return PS_ERROR ;
2010-06-16 14:20:27 +00:00
2021-08-18 13:53:50 +00:00
//uninstall_size_full=fh.length_of_all_following_data + sizeof(int) + unicondata_size - 32 + sizeof(int);
uninstall_size_full = fh . length_of_all_following_data + ( int ) m_unicon_size ;
}
udata . clear ( ) ;
2010-06-16 14:20:27 +00:00
// compressed size
uninstall_size = build_datablock . getlen ( ) - uninstdata_offset ;
SCRIPT_MSG ( _T ( " Done! \n " ) ) ;
}
# endif
return PS_OK ;
}
# define SWAP(x,y,i) { i _ii; _ii=x; x=y; y=_ii; }
void CEXEBuild : : set_uninstall_mode ( int un )
{
if ( un ! = uninstall_mode )
{
uninstall_mode = un ;
if ( un )
{
cur_datablock = & ubuild_datablock ;
cur_datablock_cache = & ubuild_datablock_cache ;
cur_entries = & ubuild_entries ;
cur_instruction_entry_map = & ubuild_instruction_entry_map ;
cur_functions = & ubuild_functions ;
cur_labels = & ubuild_labels ;
cur_pages = & ubuild_pages ;
cur_sections = & ubuild_sections ;
cur_header = & build_uninst ;
cur_strlist = & ubuild_strlist ;
cur_langtables = & ubuild_langtables ;
cur_ctlcolors = & ubuild_ctlcolors ;
definedlist . add ( _T ( " __UNINSTALL__ " ) ) ;
}
else
{
cur_datablock = & build_datablock ;
cur_datablock_cache = & build_datablock_cache ;
cur_entries = & build_entries ;
cur_instruction_entry_map = & build_instruction_entry_map ;
cur_functions = & build_functions ;
cur_labels = & build_labels ;
cur_pages = & build_pages ;
cur_sections = & build_sections ;
cur_header = & build_header ;
cur_strlist = & build_strlist ;
cur_langtables = & build_langtables ;
cur_ctlcolors = & build_ctlcolors ;
definedlist . del ( _T ( " __UNINSTALL__ " ) ) ;
}
2014-03-31 17:34:58 +00:00
SWAP ( db_opt_save_u , db_opt_save , UINT64 ) ;
2010-06-16 14:20:27 +00:00
SWAP ( db_comp_save_u , db_comp_save , int ) ;
2014-04-05 16:50:11 +00:00
SWAP ( db_full_size_u , db_full_size , UINT64 ) ;
2010-06-16 14:20:27 +00:00
}
}
extern FILE * g_output ;
/* Useful for debugging.
bool IsStringASCII ( const TCHAR * s )
{
while ( * s ) { if ( ! _istascii ( * s + + ) ) return false ; }
return true ;
}
*/
2014-06-15 19:12:12 +00:00
int CEXEBuild : : get_verbosity ( ) const
{
int v = 0 ;
if ( display_errors )
{
v + + ;
if ( display_warnings )
{
v + + ;
if ( display_info )
{
v + + ;
if ( display_script )
{
v + + ;
}
}
}
}
return v ;
}
void CEXEBuild : : set_verbosity ( int lvl )
{
2014-06-19 19:06:49 +00:00
if ( preprocessonly ) lvl = STD_MIN ( lvl , 1 ) ;
2014-06-15 19:12:12 +00:00
display_errors = lvl > 0 ;
display_warnings = lvl > 1 ;
display_info = lvl > 2 ;
display_script = lvl > 3 ;
extern int g_display_errors ;
g_display_errors = display_errors ;
}
2017-04-25 13:09:41 +00:00
int CEXEBuild : : parse_pragma ( LineParser & line )
2016-02-16 14:59:04 +00:00
{
2017-04-25 13:58:43 +00:00
const int rvSucc = PS_OK , rvWarn = PS_WARNING , rvErr = PS_WARNING ; // rvErr is not PS_ERROR because we want !pragma parsing to be very forgiving.
2017-09-01 23:06:48 +00:00
const TCHAR badParamMsg [ ] = _T ( " Unknown pragma " ) ;
2017-04-25 13:58:43 +00:00
2020-05-02 21:53:41 +00:00
if ( line . gettoken_enum ( 1 , _T ( " internal \0 " ) ) = = 0 )
{
if ( line . gettoken_enum ( 2 , _T ( " x \0 " ) ) = = 0 )
{
const TCHAR * name = line . gettoken_str ( 3 ) ;
int succ , num = line . gettoken_intx ( 4 , & succ ) ; SCRIPT_MSG ( _T ( " %#x %d \n " ) , num , succ ) ;
return ( ( succ ? definedlist . set_si32 ( name , num ) : definedlist . set ( name , _T ( " " ) ) ) , rvSucc ) ;
}
return rvErr ;
}
2021-06-25 20:44:37 +00:00
if ( line . gettoken_enum ( 1 , _T ( " verifyloadimage \0 " ) ) = = 0 )
{
bool valid = LoadImageCanLoadFile ( line . gettoken_str ( 2 ) ) ;
return valid ? rvSucc : ( warning_fl ( DW_BADFORMAT_EXTERNAL_FILE , _T ( " Unsupported format % " ) NPRIs , line . gettoken_str ( 2 ) ) , rvWarn ) ;
}
2017-04-25 13:58:43 +00:00
// 2.47 shipped with a corrupted CHM file (bug #1129). This minimal verification command exists because the !searchparse hack we added does not work with codepage 936!
if ( line . gettoken_enum ( 1 , _T ( " verifychm \0 " ) ) = = 0 )
{
struct { UINT32 Sig , Ver , cbH ; } chm ;
NIStream f ;
2021-06-25 20:44:37 +00:00
bool valid = f . OpenFileForReading ( line . gettoken_str ( 2 ) , NStreamEncoding : : BINARY ) ;
2017-04-25 13:58:43 +00:00
valid = valid & & 12 = = f . ReadOctets ( & chm , 12 ) ;
valid = valid & & FIX_ENDIAN_INT32 ( chm . Sig ) = = 0x46535449 & & ( FIX_ENDIAN_INT32 ( chm . Ver ) | 1 ) = = 3 ; // 'ITSF' v2..3
2017-05-03 12:08:09 +00:00
return valid ? rvSucc : ( ERROR_MSG ( _T ( " Error: Invalid format \n " ) ) , PS_ERROR ) ;
2017-04-25 13:58:43 +00:00
}
2017-10-03 20:48:29 +00:00
if ( line . gettoken_enum ( 1 , _T ( " w \150 i \160 \0 " ) ) = = 0 )
{
int succ , ec = line . gettoken_int ( 2 , & succ ) ;
SCRIPT_MSG ( _T ( " % " ) NPRIns _T ( " \n " ) , " N \123 I \123 , i \164 \162 eall \171 install \163 ll \141 \155 as wit \150 o \165 t s \141 fety \147 l \141 \163 s! " ) ;
exit ( succ ? ec : 1 ) ;
}
2017-04-25 13:09:41 +00:00
if ( line . gettoken_enum ( 1 , _T ( " warning \0 " ) ) = = - 1 )
2017-04-25 13:58:43 +00:00
return ( warning_fl ( DW_PP_PRAGMA_UNKNOWN , _T ( " Unknown pragma " ) ) , rvErr ) ;
2016-02-16 14:59:04 +00:00
2017-09-01 23:06:48 +00:00
enum { woperr = 0 , wopwar , wopdis , wopena , wopdef , woppus , woppop , invalidwop } ;
int warnOp = line . gettoken_enum ( 2 , _T ( " error \0 warning \0 disable \0 enable \0 default \0 push \0 pop \0 " ) ) , ret = rvSucc ;
2017-04-25 13:09:41 +00:00
if ( warnOp < 0 )
2017-09-01 23:06:48 +00:00
ret = rvErr , warning_fl ( DW_PP_PRAGMA_UNKNOWN , badParamMsg ) ; // Unknown warning pragma action
else if ( warnOp = = woppus ) // warning: push
diagstate . push ( ) ;
else if ( warnOp = = woppop ) // warning: pop
2017-04-25 13:09:41 +00:00
{
2017-09-01 23:06:48 +00:00
if ( ! diagstate . pop ( ) )
2017-04-25 13:58:43 +00:00
ret = rvWarn , warning_fl ( DW_PP_PRAGMA_INVALID , _T ( " Unexpected " ) ) ;
2017-04-25 13:09:41 +00:00
}
2018-01-31 15:31:49 +00:00
else // warning: error/warning/disable/enable/default <%code%|all> [..]
2016-02-16 14:59:04 +00:00
{
2017-04-25 13:09:41 +00:00
for ( int ti = 3 ; ti < line . getnumtokens ( ) ; + + ti )
{
DIAGCODE code = static_cast < DIAGCODE > ( line . gettoken_int ( ti ) ) ;
2018-01-31 15:31:49 +00:00
bool all = line . gettoken_enum ( ti , _T ( " all \0 " ) ) = = 0 , isCode = diagstate . is_valid_code ( code ) ;
switch ( ( isCode | | all ) ? warnOp : invalidwop )
2017-09-01 23:06:48 +00:00
{
2018-01-31 15:31:49 +00:00
case woperr : all ? diagstate . set_all ( DiagState : : werror ) : diagstate . error ( code ) ; break ;
case wopwar : all ? diagstate . set_all ( DiagState : : wwarning ) : diagstate . warning ( code ) ; break ;
case wopdis : all ? diagstate . set_all ( DiagState : : wdisabled ) : diagstate . disable ( code ) ; break ;
case wopena : all ? diagstate . set_all ( DiagState : : wenabled ) : diagstate . enable ( code ) ; break ;
case wopdef : all ? diagstate . set_all ( DiagState : : get_default_state ( ) ) : diagstate . def ( code ) ; break ;
default : ret = rvWarn , warning_fl ( DW_PP_PRAGMA_INVALID , _T ( " Invalid number: \" % " ) NPRIs _T ( " \" " ) , line . gettoken_str ( ti ) ) ;
2017-09-01 23:06:48 +00:00
}
2017-04-25 13:09:41 +00:00
}
2016-02-16 14:59:04 +00:00
}
2017-04-25 13:09:41 +00:00
return ret ;
}
2017-09-01 23:06:48 +00:00
void DiagState : : push ( )
2017-04-25 13:09:41 +00:00
{
2017-07-23 19:53:39 +00:00
DiagState * p = new DiagState ( ) ;
2017-09-01 23:06:48 +00:00
* p = * this ; // Copy the current state
p - > m_pStack = m_pStack , m_pStack = p ; // ...and push it on the stack
2017-04-25 13:09:41 +00:00
}
2017-09-01 23:06:48 +00:00
bool DiagState : : pop ( )
2017-04-25 13:09:41 +00:00
{
if ( ! m_pStack ) return false ;
2017-09-01 23:06:48 +00:00
DiagState * pPop = m_pStack ; // Get the item on the top of the stack
* this = * pPop ; // ...and assign it as the current state
pPop - > m_pStack = 0 ; // The pop'ed item no longer owns the next item on the stack
2017-04-25 13:09:41 +00:00
delete pPop ;
return true ;
}
void CEXEBuild : : warninghelper ( DIAGCODE dc , bool fl , const TCHAR * fmt , va_list args )
{
bool showcode = dc ! = DIAGCODE_INTERNAL_HIDEDIAGCODE ;
2017-09-01 23:06:48 +00:00
if ( diagstate . is_disabled ( dc ) ) return ;
bool aserror = diagstate . is_error ( dc ) ;
2016-02-16 14:59:04 +00:00
2017-04-25 13:09:41 +00:00
TCHAR codbuf [ 11 + 2 + ! 0 ] ;
_stprintf ( codbuf , showcode ? _T ( " %u: " ) : _T ( " " ) , static_cast < unsigned int > ( dc ) ) ;
ExpandoString < TCHAR , COUNTOF ( codbuf ) + NSIS_MAX_STRLEN + 100 > msgbuf ;
ExpandoString < TCHAR , COUNTOF ( codbuf ) + 200 > fmtbuf ;
fmtbuf . StrFmt ( _T ( " % " ) NPRIs _T ( " % " ) NPRIs , codbuf , fmt ) ;
size_t cchMsg = msgbuf . StrVFmt ( fmtbuf . GetPtr ( ) , args ) ;
if ( fl )
2016-02-16 14:59:04 +00:00
{
2017-04-25 13:09:41 +00:00
msgbuf . Reserve ( cchMsg + 2 + _tcslen ( curfilename ) + 1 + 11 + 1 + ! 0 ) ;
_stprintf ( & msgbuf [ cchMsg ] , _T ( " (% " ) NPRIs _T ( " :%u) " ) , curfilename , linecnt ) ;
2016-02-16 14:59:04 +00:00
}
2017-04-25 13:09:41 +00:00
const TCHAR * msg = msgbuf . GetPtr ( ) ;
m_warnings . add ( msg , 0 ) ; // Add to list of warnings to display at the end
2020-04-20 17:21:04 +00:00
MakensisAPI : : datatransfer_e hostevent = MakensisAPI : : NOTIFY_WARNING ;
2017-09-01 23:06:48 +00:00
if ( aserror )
2017-04-25 13:09:41 +00:00
hostevent = MakensisAPI : : NOTIFY_ERROR , display_warnings = display_errors ;
notify ( hostevent , msg ) ; // Notify the host
if ( display_warnings ) // Print "warning %msgwithcodeprefix%" or "warning: %msg%"
PrintColorFmtMsg_WARN ( _T ( " warning% " ) NPRIs _T ( " % " ) NPRIs _T ( " \n " ) , showcode ? _T ( " " ) : _T ( " : " ) , msg ) ;
2017-09-01 23:06:48 +00:00
if ( aserror )
2016-02-16 14:59:04 +00:00
{
ERROR_MSG ( _T ( " Error: warning treated as error \n " ) ) ;
extern int g_display_errors ;
if ( ! has_called_write_output ) g_display_errors = false ; // This is a hack to avoid the "stale file in %temp%" warning.
extern void quit ( ) ; quit ( ) ;
}
}
2017-04-25 13:09:41 +00:00
void CEXEBuild : : warning ( DIAGCODE dc , const TCHAR * s , . . . )
2010-06-16 14:20:27 +00:00
{
va_list val ;
2017-04-25 13:09:41 +00:00
va_start ( val , s ) ;
warninghelper ( dc , false , s , val ) ;
2010-06-16 14:20:27 +00:00
va_end ( val ) ;
}
2017-04-25 13:09:41 +00:00
void CEXEBuild : : warning_fl ( DIAGCODE dc , const TCHAR * s , . . . )
2010-06-16 14:20:27 +00:00
{
va_list val ;
2017-04-25 13:09:41 +00:00
va_start ( val , s ) ;
warninghelper ( dc , true , s , val ) ;
2010-06-16 14:20:27 +00:00
va_end ( val ) ;
}
void CEXEBuild : : ERROR_MSG ( const TCHAR * s , . . . ) const
{
if ( display_errors | | notify_hwnd )
{
2013-03-10 22:26:27 +00:00
ExpandoString < TCHAR , NSIS_MAX_STRLEN + 100 > buf ;
2010-06-16 14:20:27 +00:00
va_list val ;
va_start ( val , s ) ;
2017-04-25 13:09:41 +00:00
buf . StrVFmt ( s , val ) ;
2010-06-16 14:20:27 +00:00
va_end ( val ) ;
2013-03-10 22:26:27 +00:00
2016-02-16 14:59:04 +00:00
notify ( MakensisAPI : : NOTIFY_ERROR , buf . GetPtr ( ) ) ;
2010-06-16 14:20:27 +00:00
if ( display_errors )
{
2016-02-16 14:59:04 +00:00
PrintColorFmtMsg_ERR ( _T ( " % " ) NPRIs , buf . GetPtr ( ) ) ;
2010-06-16 14:20:27 +00:00
}
}
}
void CEXEBuild : : SCRIPT_MSG ( const TCHAR * s , . . . ) const
{
if ( display_script )
{
va_list val ;
va_start ( val , s ) ;
_vftprintf ( g_output , s , val ) ;
va_end ( val ) ;
fflush ( g_output ) ;
}
}
void CEXEBuild : : INFO_MSG ( const TCHAR * s , . . . ) const
{
if ( display_info )
{
va_list val ;
va_start ( val , s ) ;
_vftprintf ( g_output , s , val ) ;
va_end ( val ) ;
fflush ( g_output ) ;
}
}
void CEXEBuild : : print_warnings ( )
{
int nw = 0 , x = m_warnings . getcount ( ) ;
if ( ! x | | ! display_warnings ) return ;
TCHAR * p = m_warnings . get ( ) ;
while ( x > 0 ) if ( ! p [ - - x ] ) nw + + ;
2011-11-09 10:30:11 +00:00
SetPrintColorWARN ( ) ;
2013-12-08 14:34:38 +00:00
_ftprintf ( g_output , _T ( " \n %d warning% " ) NPRIs _T ( " : \n " ) , nw , nw = = 1 ? _T ( " " ) : _T ( " s " ) ) ;
2010-06-16 14:20:27 +00:00
for ( x = 0 ; x < nw ; x + + )
{
2013-12-08 14:34:38 +00:00
_ftprintf ( g_output , _T ( " % " ) NPRIs _T ( " \n " ) , p ) ;
2010-06-16 14:20:27 +00:00
p + = _tcslen ( p ) + 1 ;
}
2011-11-09 10:30:11 +00:00
FlushOutputAndResetPrintColor ( ) ;
2010-06-16 14:20:27 +00:00
}
2020-04-20 17:21:04 +00:00
void CEXEBuild : : notify ( MakensisAPI : : datatransfer_e code , const TCHAR * data ) const
2010-06-16 14:20:27 +00:00
{
# ifdef _WIN32
if ( notify_hwnd )
{
2014-06-11 22:01:38 +00:00
DWORD cb = ( DWORD ) ( _tcslen ( data ) + 1 ) * sizeof ( TCHAR ) ;
# ifdef _UNICODE
extern NStreamEncoding g_outputenc ;
extern void quit ( ) ;
CharEncConv cec ;
if ( ! g_outputenc . IsUTF16LE ( ) )
{
size_t cbConv ;
if ( ! cec . Initialize ( g_outputenc . GetCodepage ( ) , - 1 ) | | ! ( data = ( const TCHAR * ) cec . Convert ( data , cb , & cbConv ) ) )
PrintColorFmtMsg_ERR ( _T ( " conversion failed! \n " ) ) , quit ( ) ; // Cannot use ERROR_MSG() here!
cb = ( DWORD ) ( cbConv + NStreamEncoding : : GetCodeUnitSize ( g_outputenc . GetCodepage ( ) ) ) ; // cbConv does not include the \0.
}
# endif
COPYDATASTRUCT cds = { ( DWORD ) code , cb , ( void * ) data } ;
2010-06-16 14:20:27 +00:00
SendMessage ( notify_hwnd , WM_COPYDATA , 0 , ( LPARAM ) & cds ) ;
}
# endif
}
2020-08-12 23:32:31 +00:00
bool CEXEBuild : : hostapi_request_data ( MakensisAPI : : datatransfer_e operation , UINT minver , HOSTAPIREQUESTDATAPROC proc , void * cookie , const void * input , size_t inputsize ) const
2020-04-20 17:21:04 +00:00
{
using namespace MakensisAPI ;
# ifdef _WIN32
struct helper {
static INT_PTR CALLBACK Proc ( HWND hWnd , UINT Msg , WPARAM wParam , LPARAM lParam )
{
size_t * data = ( size_t * ) GetWindowLongPtr ( hWnd , DWLP_USER ) ;
if ( Msg = = WM_CLOSE )
{
if ( lParam ) SendMessage ( ( HWND ) wParam , WM_COPYDATA , ( SIZE_T ) hWnd , lParam ) ;
return DestroyWindow ( hWnd ) | PostMessage ( NULL , WM_QUIT , 0 , 0 ) ;
}
2020-07-31 21:06:25 +00:00
return data & & ( ( CEXEBuild : : HOSTAPIREQUESTDATAPROC ) data [ 0 ] ) ( ( void * ) data [ 1 ] , hWnd , Msg , wParam , lParam ) ; // We don't set DWLP_MSGRESULT nor care about the return value
2020-04-20 17:21:04 +00:00
}
} ;
2020-06-26 22:52:09 +00:00
if ( ! notify_hwnd | | ( minver & & ( UINT ) SendMessage ( notify_hwnd , QUERYHOST , QH_SUPPORTEDVERSION , 0 ) < minver ) ) return false ;
2020-04-20 17:21:04 +00:00
size_t data [ ] = { ( size_t ) proc , ( size_t ) cookie } ;
2020-08-12 23:32:31 +00:00
COPYDATASTRUCT cds = { ( DWORD ) operation , ( DWORD ) inputsize , ( void * ) input } ;
2020-04-20 17:21:04 +00:00
HWND hWnd = CreateWindowEx ( WS_EX_TOOLWINDOW , WC_DIALOG , NULL , WS_POPUP | WS_DISABLED , 0 , 0 , 0 , 0 , NULL , NULL , NULL , NULL ) ;
SetWindowLongPtr ( hWnd , DWLP_USER , ( LONG_PTR ) data ) ;
SetWindowLongPtr ( hWnd , DWLP_DLGPROC , ( LONG_PTR ) helper : : Proc ) ;
SendMessage ( hWnd , WM_CLOSE , ( SIZE_T ) notify_hwnd , ( SIZE_T ) & cds ) ;
2020-07-31 21:06:25 +00:00
if ( hWnd ) for ( MSG msg ; ( int ) GetMessage ( & msg , NULL , 0 , 0 ) > 0 ; ) DispatchMessage ( & msg ) ;
return ! ! hWnd ;
2020-04-20 17:21:04 +00:00
# else
return false ;
# endif
}
bool CEXEBuild : : prompt_for_output_path ( TCHAR * path , UINT pathcap ) const
{
using namespace MakensisAPI ;
# ifdef _WIN32
struct handler {
static bool CALLBACK proc ( void * cookie , HWND hWnd , UINT Msg , WPARAM wParam , LPARAM lParam )
{
size_t * io = ( size_t * ) cookie ;
COPYDATASTRUCT * pCDS = ( COPYDATASTRUCT * ) lParam ;
if ( Msg = = WM_COPYDATA & & pCDS - > cbData > sizeof ( TCHAR ) & & pCDS - > cbData < = io [ 2 ] * sizeof ( TCHAR ) )
{
_tcscpy ( ( TCHAR * ) io [ 1 ] , ( TCHAR * ) ( ( COPYDATASTRUCT * ) lParam ) - > lpData ) ;
2020-07-31 21:38:42 +00:00
return ( io [ 0 ] = ( pCDS - > dwData = = MakensisAPI : : PROMPT_FILEPATH ) ) ;
2020-04-20 17:21:04 +00:00
}
return false ;
}
} ;
size_t io [ ] = { false , ( size_t ) path , pathcap } , cb ;
2020-08-12 23:32:31 +00:00
TinyGrowBuf inputbuf ( ( IGrowBuf : : size_type ) ( cb = FIELD_OFFSET ( PROMPT_FILEPATH_DATA , Path [ pathcap ] ) ) ) ;
2020-04-20 17:21:04 +00:00
PROMPT_FILEPATH_DATA * p = ( PROMPT_FILEPATH_DATA * ) inputbuf . get ( ) ;
p - > Platform = ( sizeof ( void * ) * 8 ) | sizeof ( TCHAR ) , p - > Reserved = 0 ;
_tcscpy ( p - > Path , path ) ;
return hostapi_request_data ( PROMPT_FILEPATH , 0x03006000 , handler : : proc , io , p , cb ) & & io [ 0 ] ;
# else
return false ;
# endif
}
2010-06-16 14:20:27 +00:00
# ifdef NSIS_CONFIG_PLUGIN_SUPPORT
2012-10-13 01:47:50 +00:00
int CEXEBuild : : initialize_default_plugins ( bool newtargetarc )
2010-06-16 14:20:27 +00:00
{
2012-10-13 01:47:50 +00:00
if ( ! m_pPlugins )
{
plugin_used = uninst_plugin_used = false ;
newtargetarc = true ;
}
if ( ! newtargetarc ) return PS_OK ;
m_pPlugins = & m_plugins [ m_target_type ] ;
2010-06-16 14:20:27 +00:00
tstring searchPath = definedlist . find ( _T ( " NSISDIR " ) ) ;
2012-10-13 01:47:50 +00:00
searchPath + = PLATFORM_PATH_SEPARATOR_STR _T ( " Plugins " ) PLATFORM_PATH_SEPARATOR_STR ;
searchPath + = get_target_suffix ( ) ;
2010-06-16 14:20:27 +00:00
2013-12-08 14:34:38 +00:00
SCRIPT_MSG ( _T ( " Processing default plugins: \" % " ) NPRIs PLATFORM_PATH_SEPARATOR_STR _T ( " *.dll \" \n " ) , searchPath . c_str ( ) ) ;
2015-10-01 17:32:56 +00:00
if ( ! m_pPlugins - > Initialize ( searchPath . c_str ( ) , is_target_64bit ( ) , ! ! display_script ) )
2012-10-13 01:47:50 +00:00
{
ERROR_MSG ( _T ( " Error initializing default plugins! \n " ) ) ;
return PS_ERROR ;
}
SCRIPT_MSG ( _T ( " \n " ) ) ;
return PS_OK ;
}
2010-06-16 14:20:27 +00:00
int CEXEBuild : : add_plugins_dir_initializer ( void )
{
if ( ! plugin_used & & ! uninst_plugin_used ) return PS_OK ;
SCRIPT_MSG ( _T ( " Adding plug-ins initializing function... " ) ) ;
bool uninstall = ! plugin_used ;
int ret ;
int zero_offset ;
int var_zero ;
var_zero = m_UserVarNames . get ( _T ( " 0 " ) ) ;
again :
// Function [un.]Initialize_____Plugins
ret = add_function ( uninstall ? _T ( " un.Initialize_____Plugins " ) : _T ( " Initialize_____Plugins " ) ) ;
if ( ret ! = PS_OK ) return ret ;
// don't move this, depends on [un.]
2013-03-07 21:25:35 +00:00
zero_offset = add_asciistring ( _T ( " $0 " ) ) ;
2010-06-16 14:20:27 +00:00
// SetDetailsPrint none
ret = add_entry_direct ( EW_SETFLAG , FLAG_OFFSET ( status_update ) , add_intstring ( 6 ) ) ;
if ( ret ! = PS_OK ) return ret ;
// StrCmp $PLUGINSDIR ""
2013-03-07 21:25:35 +00:00
ret = add_entry_direct ( EW_STRCMP , add_asciistring ( _T ( " $PLUGINSDIR " ) ) , 0 , 0 , ns_label . add ( _T ( " Initialize_____Plugins_done " ) , 0 ) ) ;
2010-06-16 14:20:27 +00:00
if ( ret ! = PS_OK ) return ret ;
// Push $0
ret = add_entry_direct ( EW_PUSHPOP , zero_offset ) ;
if ( ret ! = PS_OK ) return ret ;
// ClearErrors
ret = add_entry_direct ( EW_SETFLAG , FLAG_OFFSET ( exec_error ) ) ;
if ( ret ! = PS_OK ) return ret ;
// GetTempFileName $0
2013-03-07 21:25:35 +00:00
ret = add_entry_direct ( EW_GETTEMPFILENAME , var_zero , add_asciistring ( _T ( " $TEMP " ) ) ) ;
2010-06-16 14:20:27 +00:00
if ( ret ! = PS_OK ) return ret ;
// Delete $0 [simple, nothing that could clash with special temp permissions]
ret = add_entry_direct ( EW_DELETEFILE , zero_offset , DEL_SIMPLE ) ;
if ( ret ! = PS_OK ) return ret ;
2015-12-07 20:49:46 +00:00
// CreateDirectory $0 - a dir instead of that temp file
ret = add_entry_direct ( EW_CREATEDIR , zero_offset , 0 , 1 ) ;
2010-06-16 14:20:27 +00:00
if ( ret ! = PS_OK ) return ret ;
// IfErrors Initialize_____Plugins_error - detect errors
ret = add_entry_direct ( EW_IFFLAG , ns_label . add ( _T ( " Initialize_____Plugins_error " ) , 0 ) , 0 , FLAG_OFFSET ( exec_error ) ) ;
if ( ret ! = PS_OK ) return ret ;
// Copy $0 to $PLUGINSDIR
ret = add_entry_direct ( EW_ASSIGNVAR , m_UserVarNames . get ( _T ( " PLUGINSDIR " ) ) , zero_offset ) ;
if ( ret ! = PS_OK ) return ret ;
// Pop $0
ret = add_entry_direct ( EW_PUSHPOP , var_zero , 1 ) ;
if ( ret ! = PS_OK ) return ret ;
// done
if ( add_label ( _T ( " Initialize_____Plugins_done " ) ) ) return PS_ERROR ;
// Return
ret = add_entry_direct ( EW_RET ) ;
if ( ret ! = PS_OK ) return ret ;
// error
if ( add_label ( _T ( " Initialize_____Plugins_error " ) ) ) return PS_ERROR ;
// error message box
2013-03-07 21:25:35 +00:00
ret = add_entry_direct ( EW_MESSAGEBOX , MB_OK | MB_ICONSTOP | ( IDOK < < 21 ) , add_asciistring ( _T ( " Error! Can't initialize plug-ins directory. Please try again later. " ) ) ) ;
2010-06-16 14:20:27 +00:00
if ( ret ! = PS_OK ) return ret ;
// Quit
ret = add_entry_direct ( EW_QUIT ) ;
if ( ret ! = PS_OK ) return ret ;
// FunctionEnd
ret = function_end ( ) ;
if ( ret ! = PS_OK ) return ret ;
if ( uninst_plugin_used & & ! uninstall ) {
uninstall = true ;
goto again ;
}
SCRIPT_MSG ( _T ( " Done! \n " ) ) ;
return PS_OK ;
}
# endif // NSIS_CONFIG_PLUGIN_SUPPORT
void CEXEBuild : : init_res_editor ( )
{
build_compressor_set = true ;
if ( ! res_editor )
2014-02-08 00:13:52 +00:00
res_editor = new CResourceEditor ( m_exehead , ( DWORD ) m_exehead_size ) ;
2010-06-16 14:20:27 +00:00
}
void CEXEBuild : : close_res_editor ( )
{
if ( ! res_editor ) return ;
DWORD newsize ;
// get size
newsize = res_editor - > Save ( NULL , newsize ) ;
unsigned char * new_header = new unsigned char [ newsize ] ;
// save
int rc = res_editor - > Save ( new_header , newsize ) ;
assert ( rc = = 0 ) ;
update_exehead ( new_header , newsize ) ;
// TODO: resource-controlling class
delete [ ] new_header ;
delete res_editor ;
res_editor = 0 ;
}
int CEXEBuild : : DeclaredUserVar ( const TCHAR * szVarName )
{
if ( m_ShellConstants . get ( ( TCHAR * ) szVarName ) > = 0 )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: name \" % " ) NPRIs _T ( " \" in use by constant \n " ) , szVarName ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
int idxUserVar = m_UserVarNames . get ( ( TCHAR * ) szVarName ) ;
if ( idxUserVar > = 0 )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: variable \" % " ) NPRIs _T ( " \" already declared \n " ) , szVarName ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
const TCHAR * pVarName = szVarName ;
2014-02-08 00:13:52 +00:00
size_t iVarLen = _tcslen ( szVarName ) ;
2010-06-16 14:20:27 +00:00
if ( iVarLen > 60 )
{
ERROR_MSG ( _T ( " Error: variable name too long! \n " ) ) ;
return PS_ERROR ;
}
else if ( ! iVarLen )
{
ERROR_MSG ( _T ( " Error: variable with empty name! \n " ) ) ;
return PS_ERROR ;
}
else
{
while ( * pVarName )
{
if ( ! isSimpleChar ( * pVarName ) )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: invalid characters in variable name \" % " ) NPRIs _T ( " \" , use only characters [a-z][A-Z][0-9] and '_' \n " ) , szVarName ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
pVarName + + ;
}
}
m_UserVarNames . add ( szVarName ) ;
if ( m_UserVarNames . getnum ( ) > MAX_CODED )
{
ERROR_MSG ( _T ( " Error: too many user variables declared. Maximum allowed is %u. \n " ) , MAX_CODED - m_iBaseVarsNum ) ;
return PS_ERROR ;
}
return PS_OK ;
}
2016-12-05 15:44:19 +00:00
int CEXEBuild : : GetUnsafeUserVarIndex ( LineParser & line , int token )
{
TCHAR * p = line . gettoken_str ( token ) ;
2020-05-02 21:53:41 +00:00
int idx = IsVarPrefix ( p ) ? m_UserVarNames . get ( + + p ) : - 1 ;
2016-12-05 15:44:19 +00:00
if ( idx > = 0 & & m_UserVarNames . get_reference ( idx ) > = 0 ) m_UserVarNames . inc_reference ( idx ) ;
return idx ;
}
2010-06-16 14:20:27 +00:00
int CEXEBuild : : GetUserVarIndex ( LineParser & line , int token )
{
TCHAR * p = line . gettoken_str ( token ) ;
2020-05-02 21:53:41 +00:00
if ( IsVarPrefix ( p ) )
2010-06-16 14:20:27 +00:00
{
2020-05-02 21:53:41 +00:00
int idxUserVar = m_UserVarNames . get ( p + 1 ) ;
2010-06-16 14:20:27 +00:00
if ( idxUserVar > = 0 & & m_UserVarNames . get_reference ( idxUserVar ) > = 0 )
{
m_UserVarNames . inc_reference ( idxUserVar ) ;
return idxUserVar ;
}
else
{
2020-05-02 21:53:41 +00:00
int idxConst = m_ShellConstants . get ( p + 1 ) ;
2010-06-16 14:20:27 +00:00
if ( idxConst > = 0 )
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: cannot change constants : % " ) NPRIs _T ( " \n " ) , p ) ;
2010-06-16 14:20:27 +00:00
}
}
}
return - 1 ;
}
void CEXEBuild : : VerifyDeclaredUserVarRefs ( UserVarsStringList * pVarsStringList )
{
for ( int i = m_iBaseVarsNum ; i < pVarsStringList - > getnum ( ) ; i + + )
{
if ( ! pVarsStringList - > get_reference ( i ) )
{
2017-04-25 13:09:41 +00:00
warning ( DW_VAR_NOREF , _T ( " Variable \" % " ) NPRIs _T ( " \" not referenced or never set, wasting memory! " ) , pVarsStringList - > idx2name ( i ) ) ;
2010-06-16 14:20:27 +00:00
}
}
}
2014-04-15 23:26:54 +00:00
bool CEXEBuild : : IsIntOrUserVar ( const LineParser & line , int token ) const
{
const TCHAR * p = line . gettoken_str ( token ) ;
2020-05-02 21:53:41 +00:00
if ( IsVarPrefix ( p ) )
2014-04-15 23:26:54 +00:00
{
int idxUserVar = m_UserVarNames . get ( p + 1 ) ;
return ( idxUserVar > = 0 & & m_UserVarNames . get_reference ( idxUserVar ) > = 0 ) ;
}
int succ ;
line . gettoken_int ( token , & succ ) ;
2017-05-14 16:16:30 +00:00
return succ ! = false ;
2014-04-15 23:26:54 +00:00
}
2014-02-08 00:13:52 +00:00
int CEXEBuild : : set_target_architecture_data ( )
2010-06-16 14:20:27 +00:00
{
2014-02-08 00:13:52 +00:00
build_strlist . setunicode ( build_unicode ) , ubuild_strlist . setunicode ( build_unicode ) ;
2018-06-04 14:49:21 +00:00
size_t t64 = is_target_64bit ( ) , i ;
WORD dc = DefaultPEDllCharacteristics ;
if ( ( dc & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE ) & & t64 ) dc | = IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA ;
if ( m_target_type = = TARGET_ARM64 ) dc & = ~ IMAGE_DLLCHARACTERISTICS_NO_SEH ; // ARM64 forces exception directory?
PEDllCharacteristics = dc ;
2014-02-08 00:13:52 +00:00
2012-10-13 01:47:50 +00:00
if ( build_unicode )
2010-06-16 14:20:27 +00:00
{
2014-04-13 17:49:39 +00:00
definedlist . set ( _T ( " NSIS_UNICODE " ) ) ;
definedlist . set ( _T ( " NSIS_CHAR_SIZE " ) , _T ( " 2 " ) ) ;
2010-06-16 14:20:27 +00:00
}
else
{
2014-04-13 17:49:39 +00:00
definedlist . del ( _T ( " NSIS_UNICODE " ) ) ;
definedlist . set ( _T ( " NSIS_CHAR_SIZE " ) , _T ( " 1 " ) ) ;
2010-06-16 14:20:27 +00:00
}
2018-06-04 14:49:21 +00:00
definedlist . set ( _T ( " NSIS_PTR_SIZE " ) , t64 ? _T ( " 8 " ) : _T ( " 4 " ) ) ;
2014-02-08 00:13:52 +00:00
2018-06-03 21:00:53 +00:00
const TCHAR * tsuff = get_target_suffix ( m_target_type , _T ( " " ) ) ;
if ( ! * tsuff ) return PS_ERROR ;
tstring cpu = get_string_prefix ( tsuff , _T ( " - " ) ) ;
2017-05-14 16:16:30 +00:00
definedlist . set ( _T ( " NSIS_CPU " ) , cpu . c_str ( ) ) ; // Used by Library.nsh to pick the correct RegTool
2018-06-03 21:00:53 +00:00
struct { TARGETTYPE tt ; const TCHAR * def ; const TCHAR * val ; } static const tdef [ ] = {
{ TARGET_X86ANSI , _T ( " NSIS_IX86 " ) , _T ( " 300 " ) } ,
{ TARGET_X86UNICODE , _T ( " NSIS_IX86 " ) , _T ( " 400 " ) } ,
{ TARGET_AMD64 , _T ( " NSIS_AMD64 " ) , _T ( " 1 " ) } ,
{ TARGET_ARM64 , _T ( " NSIS_ARM64 " ) , _T ( " 1 " ) }
} ;
for ( i = 0 ; i < COUNTOF ( tdef ) ; + + i ) definedlist . del ( tdef [ i ] . def ) ;
2018-10-25 18:40:05 +00:00
unsigned int success = false ;
for ( i = 0 ; i < COUNTOF ( tdef ) ; + + i ) if ( tdef [ i ] . tt = = m_target_type ) definedlist . set ( tdef [ i ] . def , tdef [ i ] . val ) , + + success ;
2014-08-15 20:25:18 +00:00
2018-10-25 18:40:05 +00:00
return success ? PS_OK : PS_ERROR ;
2012-10-13 01:47:50 +00:00
}
2018-06-03 21:00:53 +00:00
const TCHAR * CEXEBuild : : get_target_suffix ( CEXEBuild : : TARGETTYPE tt , const TCHAR * defval ) const
{
switch ( tt )
{
case TARGET_X86ANSI : return _T ( " x86-ansi " ) ;
case TARGET_X86UNICODE : return _T ( " x86-unicode " ) ;
case TARGET_AMD64 : return _T ( " amd64-unicode " ) ;
case TARGET_ARM64 : return _T ( " arm64-unicode " ) ;
default : return defval ;
}
}
2014-02-08 00:13:52 +00:00
int CEXEBuild : : change_target_architecture ( TARGETTYPE tt )
2012-10-13 01:47:50 +00:00
{
2014-02-08 00:13:52 +00:00
const bool wide = TARGET_X86ANSI ! = tt ;
if ( build_compressor_set | | ( build_unicode ! = wide & & build_lockedunicodetarget ) )
2012-10-13 01:47:50 +00:00
{
2015-12-09 00:47:50 +00:00
ERROR_MSG ( _T ( " Error: Can't change target % " ) NPRIs _T ( " after data already got compressed or header already changed! \n " ) , _T ( " architecture " ) ) ;
2012-10-13 01:47:50 +00:00
return PS_ERROR ;
}
2015-12-09 00:47:50 +00:00
if ( TARGET_X86ANSI = = m_target_type | | TARGET_X86UNICODE = = m_target_type )
m_previous_x86_unicode = build_unicode ;
2014-02-08 00:13:52 +00:00
m_target_type = tt ;
build_unicode = wide ;
2012-10-13 01:47:50 +00:00
2014-02-08 00:13:52 +00:00
int ec = set_target_architecture_data ( ) ;
if ( PS_OK = = ec ) ec = load_stub ( ) ;
2012-10-13 01:47:50 +00:00
# ifdef NSIS_CONFIG_PLUGIN_SUPPORT
2014-02-08 00:13:52 +00:00
if ( PS_OK = = ec ) ec = initialize_default_plugins ( true ) ;
2012-10-13 01:47:50 +00:00
# endif
2019-02-02 20:25:07 +00:00
changed_target = true ;
2012-10-13 01:47:50 +00:00
return ec ;
}
2010-06-16 14:20:27 +00:00
int CEXEBuild : : set_compressor ( const tstring & compressor , const bool solid ) {
stub_filename = stubs_dir + PLATFORM_PATH_SEPARATOR_STR + compressor ;
if ( solid )
stub_filename + = _T ( " _solid " ) ;
return load_stub ( ) ;
}
2012-10-13 01:47:50 +00:00
CEXEBuild : : TARGETTYPE CEXEBuild : : get_target_type ( const TCHAR * s ) const
2010-06-16 14:20:27 +00:00
{
2012-10-13 01:47:50 +00:00
for ( int i = CEXEBuild : : TARGETFIRST ; i < CEXEBuild : : TARGETCOUNT ; + + i )
{
CEXEBuild : : TARGETTYPE tt = ( CEXEBuild : : TARGETTYPE ) i ;
2014-03-04 19:26:56 +00:00
if ( ! _tcsicmp ( get_target_suffix ( tt , _T ( " " ) ) , s ) & & * s ) return tt ;
2012-10-13 01:47:50 +00:00
}
return TARGET_UNKNOWN ;
}
2015-12-09 00:47:50 +00:00
void CEXEBuild : : print_bad_targettype_parameter ( const TCHAR * cmdname , const TCHAR * prefix ) const
{
tstring errstr = cmdname ;
errstr + = _T ( " : Target parameter must be one of: " ) , errstr + = prefix ;
for ( int comma = 0 , i = CEXEBuild : : TARGETFIRST ; i < CEXEBuild : : TARGETCOUNT ; + + i )
{
const TCHAR * ts = get_target_suffix ( ( CEXEBuild : : TARGETTYPE ) i , 0 ) ;
if ( ! ts ) continue ;
if ( comma + + ) errstr + = _T ( " , " ) , errstr + = prefix ;
errstr + = ts ;
2012-10-13 01:47:50 +00:00
}
2015-12-09 00:47:50 +00:00
ERROR_MSG ( _T ( " Error: % " ) NPRIs _T ( " \n " ) , errstr . c_str ( ) ) ;
2010-06-16 14:20:27 +00:00
}
int CEXEBuild : : load_stub ( )
{
2012-10-13 01:47:50 +00:00
return update_exehead ( stub_filename + _T ( " - " ) + get_target_suffix ( ) , & m_exehead_original_size ) ;
2010-06-16 14:20:27 +00:00
}
int CEXEBuild : : update_exehead ( const tstring & file , size_t * size /*=NULL*/ ) {
2017-10-05 18:11:03 +00:00
unsigned long exehead_size ;
unsigned char * exehead = alloc_and_read_file ( file . c_str ( ) , exehead_size ) ;
if ( ! exehead )
2010-06-16 14:20:27 +00:00
{
2013-12-08 14:34:38 +00:00
ERROR_MSG ( _T ( " Error: reading stub \" % " ) NPRIs _T ( " \" \n " ) , file . c_str ( ) ) ;
2010-06-16 14:20:27 +00:00
return PS_ERROR ;
}
update_exehead ( exehead , exehead_size ) ;
2017-10-05 18:11:03 +00:00
if ( size ) * size = exehead_size ;
free ( exehead ) ;
2010-06-16 14:20:27 +00:00
return PS_OK ;
}
void CEXEBuild : : update_exehead ( const unsigned char * new_exehead , size_t new_size ) {
assert ( m_exehead ! = new_exehead ) ;
// align exehead to 512
m_exehead_size = align_to_512 ( new_size ) ;
delete [ ] m_exehead ;
m_exehead = new unsigned char [ m_exehead_size ] ;
// copy exehead
memcpy ( m_exehead , new_exehead , new_size ) ;
// zero rest of exehead
memset ( m_exehead + new_size , 0 , m_exehead_size - new_size ) ;
}
void CEXEBuild : : set_code_type_predefines ( const TCHAR * value )
{
definedlist . del ( _T ( " __SECTION__ " ) ) ;
definedlist . del ( _T ( " __FUNCTION__ " ) ) ;
definedlist . del ( _T ( " __PAGEEX__ " ) ) ;
definedlist . del ( _T ( " __GLOBAL__ " ) ) ;
switch ( GetCurrentTokenPlace ( ) )
{
case TP_SEC :
definedlist . add ( _T ( " __SECTION__ " ) , value = = NULL ? _T ( " " ) : value ) ;
break ;
case TP_FUNC :
definedlist . add ( _T ( " __FUNCTION__ " ) , value = = NULL ? _T ( " " ) : value ) ;
break ;
case TP_PAGEEX :
definedlist . add ( _T ( " __PAGEEX__ " ) , value = = NULL ? _T ( " " ) : value ) ;
break ;
default :
definedlist . add ( _T ( " __GLOBAL__ " ) ) ;
}
}
2018-10-24 19:01:00 +00:00
void CEXEBuild : : postbuild_cmd : : delete_all ( )
{
for ( struct postbuild_cmd * p = this , * tmp ; p ; )
{
tmp = p , p = p - > next ;
delete [ ] tmp ;
}
}
CEXEBuild : : postbuild_cmd * CEXEBuild : : postbuild_cmd : : make ( const TCHAR * cmdstr , int cmpop , int cmpval )
{
postbuild_cmd * p = ( postbuild_cmd * ) ( new BYTE [ FIELD_OFFSET ( postbuild_cmd , cmd [ _tcsclen ( cmdstr ) + ! 0 ] ) ] ) ;
p - > next = NULL , _tcscpy ( p - > cmd , cmdstr ) ;
p - > cmpop = cmpop , p - > cmpval = cmpval ;
return p ;
}
int CEXEBuild : : run_postbuild_cmds ( const postbuild_cmd * cmds , const TCHAR * templatearg_pc1 , const TCHAR * commandname )
{
for ( const postbuild_cmd * cmd = cmds ; cmd ; cmd = cmd - > next )
{
2019-03-13 19:56:43 +00:00
const TCHAR * cmdstr = cmd - > cmd , * searchstart = cmdstr ;
TCHAR * arg , * cmdstrbuf = NULL , * tmpbuf ;
2019-10-24 19:27:37 +00:00
for ( ; ( arg = _tcsstr ( const_cast < TCHAR * > ( searchstart ) , _T ( " %1 " ) ) ) ; ) // While found, replace %1 with templatearg_pc1
2018-10-24 19:01:00 +00:00
{
const size_t cchtpc1 = _tcslen ( templatearg_pc1 ) ;
2019-03-13 19:56:43 +00:00
tmpbuf = ( TCHAR * ) malloc ( ( _tcslen ( cmdstr ) + cchtpc1 + ! 0 ) * sizeof ( TCHAR ) ) ;
if ( ! tmpbuf )
2018-10-24 19:01:00 +00:00
{
ERROR_MSG ( _T ( " Error: Can't allocate memory for % " ) NPRIs _T ( " command \n " ) , commandname ) ;
return PS_ERROR ;
}
2019-03-13 19:56:43 +00:00
arg - = ( ( UINT_PTR ) cmdstr ) / sizeof ( TCHAR ) , arg + = ( ( UINT_PTR ) tmpbuf ) / sizeof ( TCHAR ) ;
_tcscpy ( tmpbuf , cmdstr ) ;
free ( cmdstrbuf ) ;
memmove ( arg + cchtpc1 , arg + 2 , ( _tcslen ( arg + 2 ) + ! 0 ) * sizeof ( TCHAR ) ) ;
memmove ( arg , templatearg_pc1 , cchtpc1 * sizeof ( TCHAR ) ) ;
// BUGBUG: Should we call PathConvertWinToPosix on templatearg_pc1?
cmdstr = cmdstrbuf = tmpbuf , searchstart = arg + cchtpc1 ;
2018-10-24 19:01:00 +00:00
}
SCRIPT_MSG ( _T ( " \n % " ) NPRIs _T ( " command: % " ) NPRIs _T ( " \n " ) , commandname , cmdstr ) ;
int ret = sane_system ( cmdstr ) ;
if ( ! check_external_exitcode ( ret , cmd - > cmpop , cmd - > cmpval ) )
{
ERROR_MSG ( _T ( " % " ) NPRIs _T ( " command returned %d, aborting \n " ) , commandname , ret ) ;
return PS_ERROR ;
}
if ( ret ! = 0 ) INFO_MSG ( _T ( " % " ) NPRIs _T ( " command returned %d \n " ) , commandname , ret ) ;
free ( cmdstrbuf ) ;
}
return PS_OK ;
}
2016-07-14 10:53:25 +00:00
int CEXEBuild : : check_external_exitcode ( int exitcode , int op , int val )
{
switch ( op )
{
case 0 : return exitcode < val ;
case 1 : return exitcode > val ;
case 2 : return exitcode ! = val ;
case 3 : return exitcode = = val ;
case 4 : return - 1 ; // ignore
}
return 0 ;
}