NSIS/Source/build.cpp
anders_k 7cc150c464 MakeNSIS can now generate Unicode or Ansi installers based on a script attribute. SCons generates both Ansi and Unicode stubs and plugins.
The official plugins are now stored in architecture specific subdirectories under NSIS\Plugins. !AddPluginDir also gained a new (optional) architecture flag because MakeNSIS now stores separate plugin information for each target architecture. Storing plugins in the root of the Plugins directory is no longer supported.

MinGW does not implement the unicode CRT startup functions so the entry point functions and linker parameters had to be changed. The unicode tools use the ansi entry point and a small helper function that calls into the real code: _tmain has full argc+argv emulation while wWinMain does not pass the command line parameters. The stubs do not use any CRT functions and have no CRT or unicode helper code, they call our entry point directly.



git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6269 212acab6-be3b-0410-9dea-997c60f758d6
2012-10-13 01:47:50 +00:00

3783 lines
108 KiB
C++

/*
* build.cpp
*
* This file is a part of NSIS.
*
* Copyright (C) 1999-2009 Nullsoft and Contributors
*
* Licensed under the zlib/libpng license (the "License");
* you may not use this file except in compliance with the License.
*
* Licence details can be found in the file COPYING.
*
* This software is provided 'as-is', without any express or implied
* warranty.
*
* 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"
#include "exehead/api.h"
#include "exehead/resource.h"
#include <stdexcept>
#include "ResourceEditor.h"
#include "DialogTemplate.h"
#include "ResourceVersionInfo.h"
#include "tstring.h"
#include <stdio.h>
#include <stdarg.h>
#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
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();
for (int i = 0; i < nlt; i++) {
DeleteLangTable(nla+i);
}
for (;postbuild_cmds;)
{
struct postbuild_cmd * tmp = postbuild_cmds;
postbuild_cmds = postbuild_cmds->next;
delete [] tmp;
}
}
CEXEBuild::CEXEBuild() :
m_exehead(0),
m_exehead_size(0)
{
linecnt = 0;
fp = 0;
curfilename = 0;
curfile_unicode = FALSE;
display_info=1;
display_script=1;
display_errors=1;
display_warnings=1;
cur_ifblock=NULL;
last_line_had_slash=0;
inside_comment=false;
multiple_entries_instruction=0;
build_include_depth=0;
#ifndef _UNICODE
build_include_isutf8=false;
#endif
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);
#ifdef NSIS_PACKEDVERSION
definedlist.add(_T("NSIS_PACKEDVERSION"), NSIS_PACKEDVERSION);
#endif
build_unicode=false;
m_target_type=TARGET_X86ANSI;
// 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
#ifdef _UNICODE
definedlist.add(_T("NSIS_UNICODE_MAKENSIS")); // This define might go away once makensis.exe is always unicode
#endif
db_opt_save=db_comp_save=db_full_size=db_opt_save_u=db_comp_save_u=db_full_size_u=0;
// 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.
build_packname[0]=build_packcmd[0]=build_output_filename[0]=0;
postbuild_cmds=NULL;
// Added by ramon 23 May 2003
build_allowskipfiles=1;
// Added by ramon 6 jun 2003
#ifdef NSIS_SUPPORT_VERSION_INFO
version_fixedflags=0;
#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;
build_strlist.add(_T(""), CP_ACP, false, build_unicode);
ubuild_strlist.add(_T(""), CP_ACP, false, build_unicode);
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;
m_currentmacroname=NULL;
#ifdef NSIS_CONFIG_PLUGIN_SUPPORT
build_plugin_unload=0;
m_pPlugins=0;
#endif
last_used_lang=NSIS_DEFAULT_LANG;
res_editor=0;
manifest_comctl = manifest::comctl_old;
manifest_exec_level = manifest::exec_level_none;
manifest_dpiaware = manifest::dpiaware_notset;
manifest_sosl.setdefault();
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;
_tcsnccpy(bg_default_font.lfFaceName,_T("Times New Roman"),LF_FACESIZE);
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
// with ONE of reference count, to avoid warning on this vars
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
m_UserVarNames.add(_T("_OUTDIR"),1); // 31
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);
m_ShellConstants.add(_T("APPDATA"), CSIDL_APPDATA, CSIDL_COMMON_APPDATA);
m_ShellConstants.add(_T("LOCALAPPDATA"), CSIDL_LOCAL_APPDATA, CSIDL_LOCAL_APPDATA);
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);
unsigned int program_files = add_string(_T("ProgramFilesDir"), 0);
unsigned int program_files_def = add_string(_T("C:\\Program Files"));
if ((program_files >= 0x40) || (program_files_def >= 0xFF))
{
// see Source\exehead\util.c for implementation details
// basically, it knows it needs to get folders from the registry when the 0x80 is on
ERROR_MSG(_T("Internal compiler error: too many strings added to strings block before adding shell constants!\n"));
throw out_of_range("Internal compiler error: too many strings added to strings block before adding shell constants!");
}
m_ShellConstants.add(_T("PROGRAMFILES"), 0x80 | program_files, program_files_def);
unsigned int program_files64_def = add_string(_T("$PROGRAMFILES"));
if (program_files64_def > 0xFF)
{
ERROR_MSG(_T("Internal compiler error: too many strings added to strings block before adding shell constants!\n"));
throw out_of_range("Internal compiler error: too many strings added to strings block before adding shell constants!");
}
m_ShellConstants.add(_T("PROGRAMFILES32"), 0x80 | program_files, program_files_def);
m_ShellConstants.add(_T("PROGRAMFILES64"), 0xC0 | program_files, program_files64_def);
unsigned int common_files = add_string(_T("CommonFilesDir"), 0);
unsigned int common_files_def = add_string(_T("$PROGRAMFILES\\Common Files"));
if ((common_files > 0x40) || (common_files_def > 0xFF))
{
ERROR_MSG(_T("Internal compiler error: too many strings added to strings block before adding shell constants!\n"));
throw out_of_range("Internal compiler error: too many strings added to strings block before adding shell constants!");
}
m_ShellConstants.add(_T("COMMONFILES"), 0x80 | common_files, common_files_def);
unsigned int common_files64_def = add_string(_T("$COMMONFILES"));
if (common_files64_def > 0xFF)
{
ERROR_MSG(_T("Internal compiler error: too many strings added to strings block before adding shell constants!\n"));
throw out_of_range("Internal compiler error: too many strings added to strings block before adding shell constants!");
}
m_ShellConstants.add(_T("COMMONFILES32"), 0x80 | common_files, common_files_def);
m_ShellConstants.add(_T("COMMONFILES64"), 0xC0 | common_files, common_files64_def);
set_uninstall_mode(1);
unsigned int uprogram_files = add_string(_T("ProgramFilesDir"), 0);
unsigned int uprogram_files_def = add_string(_T("C:\\Program Files"));
unsigned int uprogram_files64_def = add_string(_T("$PROGRAMFILES"));
unsigned int ucommon_files = add_string(_T("CommonFilesDir"), 0);
unsigned int ucommon_files_def = add_string(_T("$PROGRAMFILES\\Common Files"));
unsigned int ucommon_files64_def = add_string(_T("$COMMONFILES"));
if (uprogram_files != program_files
|| uprogram_files_def != program_files_def
|| uprogram_files64_def != program_files64_def
|| ucommon_files != common_files
|| ucommon_files_def != common_files_def
|| ucommon_files64_def != common_files64_def)
{
ERROR_MSG(_T("Internal compiler error: installer's shell constants are different than uninstallers!\n"));
throw out_of_range("Internal compiler error: installer's shell constants are different than uninstallers!");
}
set_uninstall_mode(0);
set_code_type_predefines();
set_target_architecture_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
nsis_dir = PREFIX_DATA;
#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");
if (set_compressor(_T("zlib"), false) != PS_OK)
{
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());
}
int CEXEBuild::getcurdbsize() { return cur_datablock->getlen(); }
// returns offset in stringblock
int CEXEBuild::add_string(const TCHAR *string, int process/*=1*/, WORD codepage/*=CP_ACP*/)
{
if (!string || !*string) return 0;
if (*string == _T('$') && *(string+1) == _T('(')) {
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;
}
if (!process) return cur_strlist->add(string, codepage, false, build_unicode);
TCHAR buf[NSIS_MAX_STRLEN*4];
preprocess_string(buf,string,codepage);
return cur_strlist->add(buf,codepage, true, build_unicode);
}
int CEXEBuild::add_intstring(const int i) // returns offset in stringblock
{
TCHAR i_str[32];
wsprintf(i_str, _T("%d"), i);
return add_string(i_str);
}
#ifdef _UNICODE
char* convert_processed_string_to_ansi(char *out, const TCHAR *in, WORD codepage)
{
const TCHAR *p=in;
for (;;)
{
_TUCHAR i = (_TUCHAR)*p++;
if (NS_IS_CODE(i)) // Note: this includes '\0'
{
// convert all character up to, and including this code
int cb = WideCharToMultiByte(codepage, 0, in, p-in, out, (p-in)*2, NULL, NULL);
out += cb;
if (i == _T('\0'))
break;
else if (i == NS_SKIP_CODE)
*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
{
int l = np - p;
while (l--)
{
_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 $$.
{ // block - why do we need this extra {?
bool bProceced=false;
if ( *p )
{
const TCHAR *pUserVarName = p;
while (isSimpleChar(*pUserVarName))
pUserVarName++;
while (pUserVarName > p)
{
if (m_ShellConstants.get((TCHAR*)p, pUserVarName-p) >= 0)
break; // Woops it's a shell constant
// Jim Park: The following line could be a source of bugs for
// variables where one variable name is a prefix of another
// variable name. For example, if you are searching for
// variable 'UserVar', you can get 'UserVariable' instead.
// Suggest that we do:
// TCHAR varname[NSIS_MAX_STRLEN];
// _tcsncpy(varname, p, pUserVarName-p);
// int idxUserVar = m_UserVarNames.get(varname);
int idxUserVar = m_UserVarNames.get((TCHAR*)p, pUserVarName-p);
if (idxUserVar >= 0)
{
// Well, using variables inside string formating doens't mean
// using the variable, beacuse 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));
memcpy(out, &w, sizeof(WORD));
out += sizeof(WORD)/sizeof(TCHAR);
p += pUserVarName-p; // zip past the user var string.
bProceced = true;
break;
}
pUserVarName--;
}
}// if ( *p )
if (!bProceced && *p)
{
const TCHAR *pShellConstName = p;
while (isSimpleChar(*pShellConstName))
pShellConstName++;
while (pShellConstName > p)
{
// Look for the identifier in the shell constants list of strings.
int idxConst = m_ShellConstants.get((TCHAR*)p, pShellConstName - p);
// If found...
if (idxConst >= 0)
{
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
#ifdef _UNICODE
*out++=MAKEWORD(CSIDL_Value_current, CSIDL_Value_all);
#else
*out++=(TCHAR)CSIDL_Value_current;
*out++=(TCHAR)CSIDL_Value_all;
#endif
p = pShellConstName; // zip past the shell constant string.
bProceced = true;
break;
}
// We are looking from the longest identifier first and work
// smaller.
pShellConstName--;
}
}
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)
{
*pos = 0;
idx = DefineLangString(cp);
if (idx < 0)
{
*out++ = (TCHAR)NS_LANG_CODE; // Next word is lang-string Identifier
WORD w = FIX_ENDIAN_INT16(CODE_SHORT(-idx-1));
memcpy(out, &w, sizeof(WORD));
out += sizeof(WORD)/sizeof(TCHAR);
p += _tcslen(cp) + 2;
bProceced = true;
}
}
free(cp);
}
if ( bProceced )
continue; // outermost while
else
{
TCHAR tbuf[64];
TCHAR cBracket = _T('\0');
bool bDoWarning = true;
if ( *p == _T('[') )
cBracket = _T(']');
else if ( *p == _T('(') )
cBracket = _T(')');
else if ( *p == _T('{') )
cBracket = _T('}');
_tcsnccpy(tbuf,p,63);
tbuf[63]=0;
if ( cBracket != 0 )
{
if (_tcschr(tbuf,cBracket)) (_tcschr(tbuf,cBracket)+1)[0]=0;
if ( tbuf[0] == _T('{') && tbuf[_tcslen(tbuf)-1] == _T('}') )
{
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.
}
}
else
{
if (_tcsstr(tbuf,_T(" "))) _tcsstr(tbuf,_T(" "))[0]=0;
}
if ( bDoWarning )
warning_fl(_T("unknown variable/constant \"%s\" detected, ignoring"),tbuf);
i = _T('$'); // redundant since i is already '$' and has
// not changed.
}
} // block
} // 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;
MMapBuf *db = (MMapBuf *) cur_datablock;
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();
if (res)
{
break;
}
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;
}
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
if (st+bufferlen+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
db->resize(st + bufferlen + sizeof(int));
int n = compressor->Init(build_compress_level, build_compress_dict_size);
if (n != C_OK)
{
ERROR_MSG(_T("Internal compiler error #12345: deflateInit() failed(%s [%d]).\n"), compressor->GetErrStr(n), n);
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)
{
ERROR_MSG(_T("Error: add_db_data() - compress() failed(%s [%d])\n"), compressor->GetErrStr(ret), ret);
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)
{
ERROR_MSG(_T("Error: add_db_data() - compress() failed(%s [%d])\n"), compressor->GetErrStr(ret), ret);
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)
{
db->resize(st + length + sizeof(int));
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)
{
ERROR_MSG(_T("Internal compiler error #12345: deflateInit() failed(%s [%d]).\n"), compressor->GetErrStr(n), n);
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)
{
if (*name == _T('.')) ERROR_MSG(_T("Error: global label \"%s\" already declared\n"),name);
else
{
const TCHAR *szType = _T("section");
if (build_cursection_isfunc)
szType = _T("function");
ERROR_MSG(_T("Error: label \"%s\" already declared in %s\n"),name,szType);
}
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);
int x;
int n=cur_functions->getlen()/sizeof(section);
section *tmp=(section*)cur_functions->get();
for (x = 0; x < n; x ++)
{
if (tmp[x].name_ptr == addr)
{
ERROR_MSG(_T("Error: Function named \"%s\" already exists.\n"),funname);
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;
if (name[0] == _T('\x1F')) // SectionGroup/SectionGroupEnd
{
if (name[1])
{
new_section.flags |= SF_SECGRP;
name++;
}
else
new_section.flags |= SF_SECGRPEND;
}
int hidden = (name[0] == _T('-'));
if (hidden)
name++;
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)
{
ERROR_MSG(_T("Error: Can't create %s section in %s section group (use SectionGroupEnd first)\n"), uninstall_mode ? _T("uninstaller") : _T("installer"), old_uninstall_mode ? _T("uninstaller") : _T("installer"));
return PS_ERROR;
}
}
new_section.code = cur_entries->getlen() / sizeof(entry);
new_section.install_types = (!hidden && *name) ? 0 : ~0;
new_section.name_ptr = hidden ? 0 : add_string(name);
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))
{
ERROR_MSG(_T("Error: \"%s\" already defined, can't assign section index!\n"), defname);
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++;
}
ERROR_MSG(_T("Error: could not resolve label \"%s\" in %s\n"),lname,fn);
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++;
}
ERROR_MSG(_T("Error: resolving %s function \"%s\" in %s\n"),str,(TCHAR*)ns_func.get()+fptr,fn);
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];
wsprintf(fname,_T("function \"%s\""),ns_func.get()+sec->name_ptr);
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];
const TCHAR *section_name;
if (x < 0)
{
// lang string
section_name = _T("$(lang string)");
}
else
{
// normal string
section_name = cur_strlist->getTchar() + x;
}
if (x) wsprintf(fname,_T("%s section \"%s\" (%d)"),str,section_name,cnt);
else wsprintf(fname,_T("unnamed %s section (%d)"),str,cnt);
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];
wsprintf(pagestr, _T("%s pages"), str);
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[] = {
{_T("%s.onInit"), &cur_header->code_onInit},
{_T("%s.on%sInstSuccess"), &cur_header->code_onInstSuccess},
{_T("%s.on%sInstFailed"), &cur_header->code_onInstFailed},
{_T("%s.onUserAbort"), &cur_header->code_onUserAbort},
{_T("%s.onVerifyInstDir"), &cur_header->code_onVerifyInstDir},
#ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
{_T("%s.onGUIInit"), &cur_header->code_onGUIInit},
{_T("%s.onGUIEnd"), &cur_header->code_onGUIEnd},
{_T("%s.onMouseOverSection"), &cur_header->code_onMouseOverSection},
#endif//NSIS_CONFIG_ENHANCEDUI_SUPPORT
#ifdef NSIS_CONFIG_COMPONENTPAGE
{_T("%s.onSelChange"), &cur_header->code_onSelChange},
#endif//NSIS_CONFIG_COMPONENTPAGE
#ifdef NSIS_SUPPORT_REBOOT
{_T("%s.onRebootFailed"), &cur_header->code_onRebootFailed},
#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];
wsprintf(cbstr, _T("%s callback"), str);
TCHAR cbstr2[1024];
wsprintf(cbstr2, _T("%s.callbacks"), un);
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)
{
warning(_T("%s function \"%s\" not referenced - zeroing code (%d-%d) out\n"),str,
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;
if (*n == _T('.')) warning(_T("global label \"%s\" not used"),n);
else warning(_T("label \"%s\" not used"),n);
}
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)
{
ERROR_MSG(_T("Error: can't add license page, NSIS_CONFIG_LICENSEPAGE not defined.\n"));
return PS_ERROR;
}
#endif
#ifndef NSIS_CONFIG_COMPONENTPAGE
if (type == PAGE_COMPONENTS)
{
ERROR_MSG(_T("Error: can't add components page, NSIS_CONFIG_COMPONENTPAGE not defined.\n"));
return PS_ERROR;
}
#endif
#ifndef NSIS_CONFIG_UNINSTALL_SUPPORT
if (type == PAGE_COMPONENTS)
{
ERROR_MSG(_T("Error: can't add uninstConfirm page, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n"));
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;
// Should probably check for (4 & version_fixedflags) here, but VIProductVersion without VIAddVersionKey
// fails silently, so VIFileVersion does the same...
if ( rVersionInfo.GetStringTablesCount() > 0 )
{
if ( !(1 & version_fixedflags) )
{
ERROR_MSG(_T("Error: VIProductVersion is required when other version information functions are used.\n"));
return PS_ERROR;
}
else
{
if ( !(2 & version_fixedflags) )
{
// This error string should match the one used by the TOK_VI_SETFILEVERSION handler
ERROR_MSG(_T("Error: invalid %s format, should be X.X.X.X\n"),_T("VIProductVersion"));
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);
const TCHAR *lang_name = GetLangNameAndCPForVersionResource(lang_id, NULL, false);
const TCHAR *recverkeys =
_T("FileVersion\0")
_T("FileDescription\0")
_T("LegalCopyright\0");
for(;;)
{
if ( !*recverkeys ) break;
if ( !rVersionInfo.FindKey(lang_id, code_page, recverkeys) )
warning(_T("Generating version information for language \"%04d-%s\" without standard key \"%s\""), lang_id, lang_name, recverkeys);
recverkeys += _tcsclen(recverkeys) + 1;
}
rVersionInfo.ExportToStream(VerInfoStream, i);
res_editor->UpdateResource(RT_VERSION, 1, lang_id, (BYTE*)VerInfoStream.get(), VerInfoStream.getlen());
}
}
catch (exception& err) {
ERROR_MSG(_T("Error adding version information: %s\n"), CtoTStrParam(err.what()));
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;
int dir=0;
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) {
warning(_T("%sage instfiles not used, no sections will be executed!"), uninstall_mode ? _T("Uninstall p") : _T("P"));
}
}
}
#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); \
delete [] dlg; \
} \
} \
}
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) {
ERROR_MSG(_T("\nError: %s\n"), CtoTStrParam(err.what()));
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)
{
cur_header->str_uninstchild = add_string(_T("$TEMP\\$1u_.exe"));
cur_header->str_uninstcmd = add_string(_T("\"$TEMP\\$1u_.exe\" $0 _?=$INSTDIR\\"));
}
#endif//NSIS_CONFIG_UNINSTALL_SUPPORT
#ifdef NSIS_SUPPORT_MOVEONREBOOT
cur_header->str_wininit = add_string(_T("$WINDIR\\wininit.ini"));
#endif//NSIS_SUPPORT_MOVEONREBOOT
}
void CEXEBuild::PrepareHeaders(IGrowBuf *hdrbuf)
{
GrowBuf blocks_buf;
growbuf_writer_sink sink(&blocks_buf, build_unicode);
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
cur_header->blocks[NB_PAGES].offset = sizeof(header) + blocks_buf.getlen();
page_writer::write_block(cur_pages, &sink);
#endif
cur_header->blocks[NB_SECTIONS].offset = sizeof(header) + blocks_buf.getlen();
section_writer::write_block(cur_sections, &sink);
cur_header->blocks[NB_ENTRIES].offset = sizeof(header) + blocks_buf.getlen();
entry_writer::write_block(cur_entries, &sink);
cur_header->blocks[NB_STRINGS].offset = sizeof(header) + blocks_buf.getlen();
#ifdef _UNICODE
if (!build_unicode)
blocks_buf.add(cur_strlist->getAnsi(), cur_strlist->getcount());
else
#endif
blocks_buf.add(cur_strlist->getTchar(), cur_strlist->getcount()*sizeof(TCHAR));
cur_header->blocks[NB_LANGTABLES].offset = sizeof(header) + blocks_buf.getlen();
lang_table_writer::write_block(cur_langtables, &sink, cur_header->langtable_size);
cur_header->blocks[NB_CTLCOLORS].offset = sizeof(header) + blocks_buf.getlen();
ctlcolors_writer::write_block(cur_ctlcolors, &sink);
#ifdef NSIS_SUPPORT_BGBG
if (cur_header->bg_color1 != -1)
{
bg_font.lfFaceName[LF_FACESIZE-1] = 0;
cur_header->blocks[NB_BGFONT].offset = sizeof(header) + blocks_buf.getlen();
LOGFONT_writer w(&sink);
w.write(&bg_font);
}
#endif
growbuf_writer_sink sink2(hdrbuf, build_unicode);
header_writer header(&sink2);
header.write(cur_header);
sink2.write_growbuf(&blocks_buf);
}
int CEXEBuild::SetVarsSection()
{
try {
init_res_editor();
VerifyDeclaredUserVarRefs(&m_UserVarNames);
int MaxUserVars = m_UserVarNames.getnum();
int stringSize = NSIS_MAX_STRLEN*(build_unicode?sizeof(TCHAR):sizeof(char));
if (!res_editor->SetPESectionVirtualSize(NSIS_VARS_SECTION, MaxUserVars * stringSize))
{
ERROR_MSG(_T("Internal compiler error #12346: invalid exehead cannot find section \"%s\"!\n"), _T(NSIS_VARS_SECTION));
return PS_ERROR;
}
}
catch (exception& err) {
ERROR_MSG(_T("\nError: %s\n"), CtoTStrParam(err.what()));
return PS_ERROR;
}
return PS_OK;
}
int CEXEBuild::SetManifest()
{
try {
init_res_editor();
// This should stay ANSI
string manifest = manifest::generate(manifest_comctl, manifest_exec_level, manifest_dpiaware, manifest_sosl);
if (manifest == "")
return PS_OK;
// Saved directly as binary into the exe.
res_editor->UpdateResource(MAKEINTRESOURCE(24), 1, NSIS_DEFAULT_LANG, (LPBYTE) manifest.c_str(), manifest.length());
}
catch (exception& err) {
ERROR_MSG(_T("Error setting manifest: %s\n"), CtoTStrParam(err.what()));
return PS_ERROR;
}
return PS_OK;
}
int CEXEBuild::UpdatePEHeader()
{
try {
PIMAGE_NT_HEADERS headers = CResourceEditor::GetNTHeaders(m_exehead);
// workaround for bug #2697027, #2725883, #2803097
headers->OptionalHeader.MajorImageVersion = 6;
headers->OptionalHeader.MinorImageVersion = 0;
// terminal services aware
headers->OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
} catch (std::runtime_error& err) {
ERROR_MSG(_T("Error updating PE headers: %s\n"), CtoTStrParam(err.what()));
return PS_ERROR;
}
return PS_OK;
}
void CEXEBuild::set_default_output_filename(const tstring& filename)
{
if (build_output_filename[0] == 0)
_tcsnccpy(build_output_filename,filename.c_str(),1024-1);
}
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)
{
warning(_T("Uninstaller script code found but WriteUninstaller never used - no uninstaller will be created."));
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
FILE *tmpfile=FOPEN(build_packname,("wb"));
if (!tmpfile)
{
ERROR_MSG(_T("Error: writing temporary file \"%s\" for pack\n"),build_packname);
return PS_ERROR;
}
fwrite(m_exehead,1,m_exehead_size,tmpfile);
fclose(tmpfile);
if (sane_system(build_packcmd) == -1)
{
_tremove(build_packname);
ERROR_MSG(_T("Error: calling packer on \"%s\"\n"),build_packname);
return PS_ERROR;
}
int result = update_exehead(build_packname);
_tremove(build_packname);
if (result != PS_OK)
{
ERROR_MSG(_T("Error: reading temporary file \"%s\" after pack\n"),build_packname);
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;
#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
set_icon(res_editor, IDI_ICON2, installer_icon, uninstaller_icon);
// Save all changes to the exe header
close_res_editor();
}
catch (exception& err) {
ERROR_MSG(_T("\nError: %s\n"), CtoTStrParam(err.what()));
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() );
crc32_t crc=0;
{
tstring full_path = get_full_path(build_output_filename);
notify(MAKENSIS_NOTIFY_OUTPUT, full_path.c_str());
INFO_MSG(_T("\nOutput: \"%s\"\n"), full_path.c_str());
}
FILE *fp = FOPEN(build_output_filename,("w+b"));
if (!fp)
{
ERROR_MSG(_T("Can't open output file\n"));
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;
}
#ifdef NSIS_CONFIG_CRC_SUPPORT
#ifdef NSIS_CONFIG_CRC_ANAL
crc=CRC32(crc,m_exehead,m_exehead_size);
#else
crc=CRC32(crc,m_exehead+512,m_exehead_size-512);
#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)
{
ERROR_MSG(_T("Internal compiler error #12345: deflateInit() failed(%s [%d]).\n"), compressor->GetErrStr(n), n);
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
{
file_writer_sink sink(fp);
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;
INFO_MSG(_T("%d page%s (%d bytes), "),np,np==1?_T(""):_T("s"),np*sizeof(page));
#endif
{
int ns=build_sections.getlen()/sizeof(section);
section *s=(section*)build_sections.get();
int x;
int req=0;
for (x = 1; x < ns; x ++)
{
if (!s[x].name_ptr || s[x].flags & SF_RO) req++;
}
INFO_MSG(_T("%d section%s"),ns,ns==1?_T(""):_T("s"));
if (req)
{
INFO_MSG(_T(" (%d required)"),req);
}
INFO_MSG(_T(" (%d bytes), "), build_sections.getlen());
}
int ne=build_header.blocks[NB_ENTRIES].num;
INFO_MSG(_T("%d instruction%s (%d bytes), "),ne,ne==1?_T(""):_T("s"),ne*sizeof(entry));
int ns=build_strlist.getnum();
INFO_MSG(_T("%d string%s (%d bytes), "),ns,ns==1?_T(""):_T("s"),build_strlist.getcount()*(build_unicode ? sizeof(CHAR) : sizeof(TCHAR)));
int nlt=build_header.blocks[NB_LANGTABLES].num;
INFO_MSG(_T("%d language table%s (%d bytes).\n"),nlt,nlt==1?_T(""):_T("s"),build_langtables.getlen());
if (ubuild_entries.getlen())
{
INFO_MSG(_T("Uninstall: "));
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
np=build_uninst.blocks[NB_PAGES].num;
INFO_MSG(_T("%d page%s (%d bytes), \n"),np,np==1?_T(""):_T("s"),ubuild_pages.getlen());
#endif
{
int ns=ubuild_sections.getlen()/sizeof(section);
section *s=(section*)ubuild_sections.get();
int x;
int req=0;
for (x = 1; x < ns; x ++)
{
if (!s[x].name_ptr || s[x].flags & SF_RO) req++;
}
INFO_MSG(_T("%d section%s"),ns,ns==1?_T(""):_T("s"));
if (req)
{
INFO_MSG(_T(" (%d required)"),req);
}
INFO_MSG(_T(" (%d bytes), "), ubuild_sections.getlen());
}
ne=build_uninst.blocks[NB_ENTRIES].num;
INFO_MSG(_T("%d instruction%s (%d bytes), "),ne,ne==1?_T(""):_T("s"),ubuild_entries.getlen());
ns=ubuild_strlist.getnum();
INFO_MSG(_T("%d string%s (%d bytes), "),ns,ns==1?_T(""):_T("s"),ubuild_strlist.getcount()*(build_unicode ? sizeof(CHAR) : sizeof(TCHAR)));
nlt=build_uninst.blocks[NB_LANGTABLES].num;
INFO_MSG(_T("%d language table%s (%d bytes).\n"),nlt,nlt==1?_T(""):_T("s"),ubuild_langtables.getlen());
}
if (db_opt_save)
{
int total_out_size_estimate=
m_exehead_size+sizeof(fh)+build_datablock.getlen()+(build_crcchk?sizeof(crc32_t):0);
int pc=(int)(((INT64)db_opt_save*1000)/(db_opt_save+total_out_size_estimate));
INFO_MSG(_T("Datablock optimizer saved %d bytes (~%d.%d%%).\n"),db_opt_save,
pc/10,pc%10);
}
#ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
INFO_MSG(_T("\nUsing %s%s compression.\n\n"), compressor->GetName(), build_compress_whole?_T(" (compress whole)"):_T(""));
#endif
unsigned int total_usize=m_exehead_original_size;
INFO_MSG(_T("EXE header size: %10d / %d bytes\n"),m_exehead_size,m_exehead_original_size);
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;
{
int dbsize, dbsizeu;
dbsize = build_datablock.getlen();
if (uninstall_size>0) dbsize-=uninstall_size;
if (build_compress_whole) {
dbsizeu=dbsize;
INFO_MSG(_T("Install data: (%d bytes)\n"),dbsizeu);
}
else {
dbsizeu = db_full_size - uninstall_size_full;
INFO_MSG(_T("Install data: %10d / %d bytes\n"),dbsize,dbsizeu);
}
total_usize+=dbsizeu;
}
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);
total_usize+=uninstall_size_full;
}
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
{
file_writer_sink sink(fp);
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];
int l=fread(buf,1,sizeof(buf),fp);
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"));
{
UINT pc=(UINT)(((UINT64)ftell(fp)*1000)/(total_usize));
INFO_MSG(_T("Total size: %10u / %u bytes (%u.%u%%)\n"),
ftell(fp),total_usize,pc/10,pc%10);
}
fclose(fp);
if (postbuild_cmds)
{
for (struct postbuild_cmd *cmd=postbuild_cmds; cmd; cmd = cmd->next)
{
LPTSTR cmdstr = cmd->cmd, cmdstrbuf = NULL;
LPTSTR arg = _tcsstr(cmdstr, _T("%1"));
if (arg) // if found, replace %1 by build_output_filename
{
const UINT cchbldoutfile = _tcslen(build_output_filename);
cmdstrbuf = (LPTSTR) malloc( (_tcslen(cmdstr) + cchbldoutfile + 1)*sizeof(TCHAR) );
if (!cmdstrbuf)
{
ERROR_MSG(_T("Error: can't allocate memory for finalize command\n"));
return PS_ERROR;
}
arg -= (UINT_PTR)cmdstr, arg += (UINT_PTR)cmdstrbuf;
_tcscpy(cmdstrbuf,cmdstr);
cmdstr = cmdstrbuf;
memmove(arg+cchbldoutfile, arg+2, (_tcslen(arg+2)+1)*sizeof(TCHAR));
memmove(arg, build_output_filename, cchbldoutfile*sizeof(TCHAR));
}
SCRIPT_MSG(_T("\nFinalize command: %s\n"),cmdstr);
#ifdef _WIN32
int ret=sane_system(cmdstr);
#else
PATH_CONVERT(cmdstr);
int ret=system(cmdstr);
#endif
if (ret != 0)
INFO_MSG(_T("Finalize command returned %d\n"),ret);
free(cmdstrbuf);
}
}
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))
{
ERROR_MSG(_T("Error: deflateToFile: deflate() failed(%s [%d])\n"), compressor->GetErrStr(ret), ret);
return 1;
}
int l=compressor->GetNextOut()-obuf;
if (l)
{
if (fwrite(obuf,1,l,fp) != (unsigned)l)
{
ERROR_MSG(_T("Error: deflateToFile fwrite(%d) failed\n"),l);
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... "));
firstheader fh={0,};
GrowBuf uhd;
{
GrowBuf udata;
set_uninstall_mode(1);
PrepareHeaders(&udata);
fh.length_of_header=udata.getlen();
int err=add_data((char*)udata.get(),udata.getlen(),&uhd);
set_uninstall_mode(0);
if (err < 0) return PS_ERROR;
}
crc32_t crc=0;
// 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;
}
entry *ent = (entry *) build_entries.get();
if (!ent)
{
delete [] unicon_data;
return PS_ERROR;
}
int ents = build_header.blocks[NB_ENTRIES].num;
int uns = uninstaller_writes_used;
int uninstdata_offset = build_datablock.getlen();
while (ents--)
{
if (ent->which == EW_WRITEUNINSTALLER)
{
ent->offsets[1] = uninstdata_offset;
ent->offsets[2] = m_unicon_size;
uns--;
if (!uns)
break;
}
ent++;
}
if (add_db_data((char *)unicon_data,m_unicon_size) < 0)
{
delete [] unicon_data;
return PS_ERROR;
}
#ifdef NSIS_CONFIG_CRC_SUPPORT
{
// "create" the uninstaller
LPBYTE uninst_header = (LPBYTE) malloc(m_exehead_size);
if (!uninst_header)
return PS_ERROR;
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;
}
delete [] unicon_data;
#ifdef NSIS_CONFIG_CRC_ANAL
crc=CRC32(crc, uninst_header, m_exehead_size);
#else
crc=CRC32(crc, uninst_header + 512, m_exehead_size - 512);
#endif
free(uninst_header);
}
#endif
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);
MMapBuf udata;
{
growbuf_writer_sink sink(&udata, build_unicode);
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)
{
ERROR_MSG(_T("Internal compiler error #12345: deflateInit() failed(%s [%d]).\n"), compressor->GetErrStr(n), n);
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)
{
udata.add(obuf, compressor->GetNextOut() - obuf);
}
}
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)
udata.add(obuf, compressor->GetNextOut() - obuf);
}
ubuild_datablock.release();
avail_in -= l;
in_pos += l;
}
for (;;)
{
compressor->SetNextOut(obuf, sizeof(obuf));
compressor->Compress(C_FINISH);
if (compressor->GetNextOut() - obuf > 0)
udata.add(obuf, compressor->GetNextOut() - obuf);
else break;
}
compressor->End();
}
firstheader *_fh=(firstheader *)udata.get(0, sizeof(firstheader));
_fh->length_of_all_following_data=FIX_ENDIAN_INT32(udata.getlen()+(build_crcchk?sizeof(crc32_t):0));
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;
int left = udata.getlen();
while (left > 0)
{
int l = min(build_filebuflen, left);
crc = CRC32(crc, (unsigned char *) udata.get(pos, l), l);
udata.release();
pos += l;
left -= l;
}
udata.setro(FALSE);
FIX_ENDIAN_INT32_INPLACE(crc);
udata.add(&crc, sizeof(crc));
udata.setro(TRUE);
}
#endif
if (add_db_data(&udata) < 0)
return PS_ERROR;
udata.clear();
//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+m_unicon_size;
// 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__"));
}
SWAP(db_opt_save_u,db_opt_save,int);
SWAP(db_comp_save_u,db_comp_save,int);
SWAP(db_full_size_u,db_full_size,int);
}
}
extern FILE *g_output;
/* Useful for debugging.
bool IsStringASCII(const TCHAR* s)
{
while (*s) { if (!_istascii(*s++)) return false; }
return true;
}
*/
void CEXEBuild::warning(const TCHAR *s, ...)
{
TCHAR buf[NSIS_MAX_STRLEN*10];
va_list val;
va_start(val,s);
#ifdef _WIN32
_vstprintf(buf,s,val);
#else
_vsntprintf(buf,NSIS_MAX_STRLEN*10,s,val);
#endif
va_end(val);
m_warnings.add(buf,0);
notify(MAKENSIS_NOTIFY_WARNING,buf);
if (display_warnings)
{
PrintColorFmtMsg_WARN(_T("warning: %s\n"),buf);
}
}
void CEXEBuild::warning_fl(const TCHAR *s, ...)
{
TCHAR buf[NSIS_MAX_STRLEN*10];
va_list val;
va_start(val,s);
#ifdef _WIN32
_vstprintf(buf,s,val);
#else
_vsntprintf(buf,NSIS_MAX_STRLEN*10,s,val);
#endif
va_end(val);
_stprintf(buf+_tcslen(buf),_T(" (%s:%d)"),curfilename,linecnt);
m_warnings.add(buf,0);
notify(MAKENSIS_NOTIFY_WARNING,buf);
if (display_warnings)
{
PrintColorFmtMsg_WARN(_T("warning: %s\n"),buf);
}
}
void CEXEBuild::ERROR_MSG(const TCHAR *s, ...) const
{
if (display_errors || notify_hwnd)
{
TCHAR buf[NSIS_MAX_STRLEN*10];
va_list val;
va_start(val,s);
#ifdef _WIN32
_vstprintf(buf,s,val);
#else
_vsntprintf(buf,NSIS_MAX_STRLEN*10,s,val);
#endif
va_end(val);
notify(MAKENSIS_NOTIFY_ERROR,buf);
if (display_errors)
{
PrintColorFmtMsg_ERR(_T("%s"),buf);
}
}
}
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++;
SetPrintColorWARN();
_ftprintf(g_output,_T("\n%d warning%s:\n"),nw,nw==1?_T(""):_T("s"));
for (x = 0; x < nw; x ++)
{
_ftprintf(g_output,_T(" %s\n"),p);
p+=_tcslen(p)+1;
}
FlushOutputAndResetPrintColor();
}
void CEXEBuild::notify(notify_e code, const TCHAR *data) const
{
#ifdef _WIN32
if (notify_hwnd)
{
COPYDATASTRUCT cds = {(DWORD)code, (_tcslen(data)+1)*sizeof(TCHAR), (void *) data};
SendMessage(notify_hwnd, WM_COPYDATA, 0, (LPARAM)&cds);
}
#endif
}
#ifdef NSIS_CONFIG_PLUGIN_SUPPORT
int CEXEBuild::initialize_default_plugins(bool newtargetarc)
{
if (!m_pPlugins)
{
plugin_used = uninst_plugin_used = false;
newtargetarc = true;
}
if (!newtargetarc) return PS_OK;
m_pPlugins = &m_plugins[m_target_type];
tstring searchPath = definedlist.find(_T("NSISDIR"));
searchPath += PLATFORM_PATH_SEPARATOR_STR _T("Plugins") PLATFORM_PATH_SEPARATOR_STR;
searchPath += get_target_suffix();
SCRIPT_MSG(_T("Processing default plugins: \"%s") PLATFORM_PATH_SEPARATOR_STR _T("*.dll\"\n"), searchPath.c_str());
if (!m_pPlugins->Initialize(searchPath.c_str(), !!display_script))
{
ERROR_MSG(_T("Error initializing default plugins!\n"));
return PS_ERROR;
}
SCRIPT_MSG(_T("\n"));
return PS_OK;
}
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.]
zero_offset=add_string(_T("$0"));
// SetDetailsPrint none
ret=add_entry_direct(EW_SETFLAG, FLAG_OFFSET(status_update), add_intstring(6));
if (ret != PS_OK) return ret;
// StrCmp $PLUGINSDIR ""
ret=add_entry_direct(EW_STRCMP, add_string(_T("$PLUGINSDIR")), 0, 0, ns_label.add(_T("Initialize_____Plugins_done"),0));
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
ret=add_entry_direct(EW_GETTEMPFILENAME, var_zero, add_string(_T("$TEMP")));
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;
// CraeteDirectory $0 - a dir instead of that temp file
ret=add_entry_direct(EW_CREATEDIR, zero_offset);
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
ret=add_entry_direct(EW_MESSAGEBOX, MB_OK|MB_ICONSTOP|(IDOK<<21), add_string(_T("Error! Can't initialize plug-ins directory. Please try again later.")));
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)
res_editor = new CResourceEditor(m_exehead, m_exehead_size);
}
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)
{
ERROR_MSG(_T("Error: name \"%s\" in use by constant\n"), szVarName);
return PS_ERROR;
}
int idxUserVar = m_UserVarNames.get((TCHAR*)szVarName);
if (idxUserVar >= 0)
{
ERROR_MSG(_T("Error: variable \"%s\" already declared\n"), szVarName);
return PS_ERROR;
}
const TCHAR *pVarName = szVarName;
int iVarLen = _tcslen(szVarName);
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))
{
ERROR_MSG(_T("Error: invalid characters in variable name \"%s\", use only characters [a-z][A-Z][0-9] and '_'\n"), szVarName);
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;
}
int CEXEBuild::GetUserVarIndex(LineParser &line, int token)
{
TCHAR *p = line.gettoken_str(token);
if ( *p == _T('$') && *(p+1) )
{
int idxUserVar = m_UserVarNames.get((TCHAR *)p+1);
if (idxUserVar >= 0 && m_UserVarNames.get_reference(idxUserVar) >= 0)
{
m_UserVarNames.inc_reference(idxUserVar);
return idxUserVar;
}
else
{
int idxConst = m_ShellConstants.get((TCHAR *)p+1);
if (idxConst >= 0)
{
ERROR_MSG(_T("Error: cannot change constants : %s\n"), p);
}
}
}
return -1;
}
void CEXEBuild::VerifyDeclaredUserVarRefs(UserVarsStringList *pVarsStringList)
{
for (int i = m_iBaseVarsNum; i < pVarsStringList->getnum(); i++)
{
if (!pVarsStringList->get_reference(i))
{
warning(_T("Variable \"%s\" not referenced or never set, wasting memory!"), pVarsStringList->idx2name(i));
}
}
}
void CEXEBuild::set_target_architecture_predefines()
{
definedlist.del(_T("NSIS_UNICODE"));
definedlist.del(_T("NSIS_CHAR_SIZE"));
if (build_unicode)
{
definedlist.add(_T("NSIS_UNICODE"));
definedlist.add(_T("NSIS_CHAR_SIZE"), _T("2"));
}
else
{
definedlist.add(_T("NSIS_CHAR_SIZE"), _T("1"));
}
}
int CEXEBuild::change_target_architecture()
{
if (build_compressor_set)
{
ERROR_MSG(_T("Error: Can't change target architecture after data already got compressed!\n"));
return PS_ERROR;
}
m_target_type = build_unicode ? TARGET_X86UNICODE : TARGET_X86ANSI;
set_target_architecture_predefines();
int ec = load_stub();
#ifdef NSIS_CONFIG_PLUGIN_SUPPORT
if (PS_OK==ec) ec = initialize_default_plugins(true);
#endif
return ec;
}
#ifdef _UNICODE
int CEXEBuild::set_target_charset(bool unicode)
{
build_unicode = unicode;
return change_target_architecture();
}
#endif
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();
}
CEXEBuild::TARGETTYPE CEXEBuild::get_target_type(const TCHAR*s) const
{
for(int i = CEXEBuild::TARGETFIRST; i < CEXEBuild::TARGETCOUNT; ++i)
{
CEXEBuild::TARGETTYPE tt = (CEXEBuild::TARGETTYPE) i;
if (!_tcsicmp(get_target_suffix(tt),s)) return tt;
}
return TARGET_UNKNOWN;
}
const TCHAR* CEXEBuild::get_target_suffix(CEXEBuild::TARGETTYPE tt) const
{
switch(tt)
{
case TARGET_X86ANSI :return _T("x86-ansi");
case TARGET_X86UNICODE:return _T("x86-unicode");
default:return _T("?");
}
}
int CEXEBuild::load_stub()
{
return update_exehead(stub_filename+_T("-")+get_target_suffix(), &m_exehead_original_size);
}
int CEXEBuild::update_exehead(const tstring& file, size_t *size/*=NULL*/) {
FILE *tmpfile = FOPEN(file.c_str(), ("rb"));
if (!tmpfile)
{
ERROR_MSG(_T("Error: opening stub \"%s\"\n"), file.c_str());
return PS_ERROR;
}
fseek(tmpfile, 0, SEEK_END);
size_t exehead_size = ftell(tmpfile);
unsigned char *exehead = new unsigned char[exehead_size];
fseek(tmpfile, 0, SEEK_SET);
if (fread(exehead, 1, exehead_size, tmpfile) != exehead_size)
{
ERROR_MSG(_T("Error: reading stub \"%s\"\n"), file.c_str());
fclose(tmpfile);
delete [] exehead;
return PS_ERROR;
}
fclose(tmpfile);
update_exehead(exehead, exehead_size);
if (size)
*size = exehead_size;
delete [] exehead;
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__"));
}
}