diff --git a/Source/build.cpp b/Source/build.cpp index 569353f9..78b95bd3 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -1,2912 +1,2912 @@ -/* - * 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 -#include "exehead/config.h" - -#include - -#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 - -#include "ResourceEditor.h" -#include "DialogTemplate.h" -#include "ResourceVersionInfo.h" -#include "tstring.h" - -#ifndef _WIN32 -# include -# include -# include -# include -# include -#endif - -#include // for assert - -#define RET_UNLESS_OK( function_rc ) do { \ - int rc = (function_rc); \ - if ( rc != PS_OK) \ - return rc; \ -} while (false) - -const LONG available_stub_variants[] = -{ - 0x00000000, // classic ANSI stub - 0x00050000 // Unicode stub for Windows 2000 and more recent (5.0+) -}; - -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); - } -} - -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; - - 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); - - target_minimal_OS=0; - build_unicode=false; - definedlist.add(_T("NSIS_CHAR_SIZE"), _T("1")); // this can change after a TargetMinimalOS instruction is found - - // automatically generated header file containing all defines -#include - - // 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 - - 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]=postbuild_cmd[0]=0; - - // Added by ramon 23 May 2003 - build_allowskipfiles=1; - - // Added by ramon 6 jun 2003 -#ifdef NSIS_SUPPORT_VERSION_INFO - version_product_v[0]=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; - -#ifdef NSIS_CONFIG_PLUGIN_SUPPORT - build_plugin_unload=0; - plugins_processed=0; -#endif - - last_used_lang=NSIS_DEFAULT_LANG; - - res_editor=0; - - manifest_comctl = manifest::comctl_old; - manifest_exec_level = manifest::exec_level_none; - - 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(); -} - -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 include '\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 (bufferlen < 0) // too much data... try allocating as much as possible - db->resize(max(st, 0x7fffffff)); - else - 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; - - // Is it a hidden section? - if (secname[0] == _T('-')) - { - if (secname[1]) - { - new_section.flags |= SF_SECGRP; - name++; - } - else - new_section.flags |= SF_SECGRPEND; - } - - 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 = *name ? 0 : ~0; - new_section.name_ptr = 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; - - if ( rVersionInfo.GetStringTablesCount() > 0 ) - { - if ( !version_product_v[0] ) - { - ERROR_MSG(_T("Error: VIProductVersion is required when other version information functions are used.\n")); - return PS_ERROR; - } - else - { - int imm, iml, ilm, ill; - if ( _stscanf(version_product_v, _T("%d.%d.%d.%d"), &imm, &iml, &ilm, &ill) != 4 ) - { - ERROR_MSG(_T("Error: invalid VIProductVersion format, should be X.X.X.X\n")); - return PS_ERROR; - } - rVersionInfo.SetFileVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); - rVersionInfo.SetProductVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); - - 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 = GetLangNameAndCP(lang_id); - - if ( !rVersionInfo.FindKey(lang_id, code_page, _T("FileVersion")) ) - warning(_T("Generating version information for language \"%04d-%s\" without standard key \"FileVersion\""), lang_id, lang_name); - if ( !rVersionInfo.FindKey(lang_id, code_page, _T("FileDescription")) ) - warning(_T("Generating version information for language \"%04d-%s\" without standard key \"FileDescription\""), lang_id, lang_name); - if ( !rVersionInfo.FindKey(lang_id, code_page, _T("LegalCopyright")) ) - warning(_T("Generating version information for language \"%04d-%s\" without standard key \"LegalCopyright\""), lang_id, lang_name); - - 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"), CtoTString(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, dir_used; - int uninstconfirm=0; - int instlog=0, instlog_used; - int main=0; - -#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT -again: -#endif - - dir_used = 0; - 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"), CtoTString(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(); - // -1 because the default size is 1 - int stringSize = NSIS_MAX_STRLEN*(build_unicode?sizeof(TCHAR):sizeof(char)); - if (!res_editor->AddExtraVirtualSize2PESection(NSIS_VARS_SECTION, (MaxUserVars - 1) * 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"), CtoTString(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); - - 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"), CtoTString(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"), CtoTString(err.what())); - return PS_ERROR; - } - - return PS_OK; -} - -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,_T("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"), CtoTString(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,_T("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_cmd[0]) - { - LPTSTR arg = _tcsstr(postbuild_cmd, _T("%1")); - if (arg) // if found, replace %1 by build_output_filename - { - memmove(arg+_tcslen(build_output_filename), arg+2, (_tcslen(arg+2)+1)*sizeof(TCHAR)); - memmove(arg, build_output_filename, _tcslen(build_output_filename)*sizeof(TCHAR)); - } - SCRIPT_MSG(_T("\nFinalize command: %s\n"),postbuild_cmd); +/* + * 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 +#include "exehead/config.h" + +#include + +#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 + +#include "ResourceEditor.h" +#include "DialogTemplate.h" +#include "ResourceVersionInfo.h" +#include "tstring.h" + +#ifndef _WIN32 +# include +# include +# include +# include +# include +#endif + +#include // for assert + +#define RET_UNLESS_OK( function_rc ) do { \ + int rc = (function_rc); \ + if ( rc != PS_OK) \ + return rc; \ +} while (false) + +const LONG available_stub_variants[] = +{ + 0x00000000, // classic ANSI stub + 0x00050000 // Unicode stub for Windows 2000 and more recent (5.0+) +}; + +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); + } +} + +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; + + 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); + + target_minimal_OS=0; + build_unicode=false; + definedlist.add(_T("NSIS_CHAR_SIZE"), _T("1")); // this can change after a TargetMinimalOS instruction is found + + // automatically generated header file containing all defines +#include + + // 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 + + 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]=postbuild_cmd[0]=0; + + // Added by ramon 23 May 2003 + build_allowskipfiles=1; + + // Added by ramon 6 jun 2003 +#ifdef NSIS_SUPPORT_VERSION_INFO + version_product_v[0]=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; + +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + build_plugin_unload=0; + plugins_processed=0; +#endif + + last_used_lang=NSIS_DEFAULT_LANG; + + res_editor=0; + + manifest_comctl = manifest::comctl_old; + manifest_exec_level = manifest::exec_level_none; + + 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(); +} + +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 include '\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 (bufferlen < 0) // too much data... try allocating as much as possible + db->resize(max(st, 0x7fffffff)); + else + 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; + + // Is it a hidden section? + if (secname[0] == _T('-')) + { + if (secname[1]) + { + new_section.flags |= SF_SECGRP; + name++; + } + else + new_section.flags |= SF_SECGRPEND; + } + + 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 = *name ? 0 : ~0; + new_section.name_ptr = 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; + + if ( rVersionInfo.GetStringTablesCount() > 0 ) + { + if ( !version_product_v[0] ) + { + ERROR_MSG(_T("Error: VIProductVersion is required when other version information functions are used.\n")); + return PS_ERROR; + } + else + { + int imm, iml, ilm, ill; + if ( _stscanf(version_product_v, _T("%d.%d.%d.%d"), &imm, &iml, &ilm, &ill) != 4 ) + { + ERROR_MSG(_T("Error: invalid VIProductVersion format, should be X.X.X.X\n")); + return PS_ERROR; + } + rVersionInfo.SetFileVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); + rVersionInfo.SetProductVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); + + 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 = GetLangNameAndCP(lang_id); + + if ( !rVersionInfo.FindKey(lang_id, code_page, _T("FileVersion")) ) + warning(_T("Generating version information for language \"%04d-%s\" without standard key \"FileVersion\""), lang_id, lang_name); + if ( !rVersionInfo.FindKey(lang_id, code_page, _T("FileDescription")) ) + warning(_T("Generating version information for language \"%04d-%s\" without standard key \"FileDescription\""), lang_id, lang_name); + if ( !rVersionInfo.FindKey(lang_id, code_page, _T("LegalCopyright")) ) + warning(_T("Generating version information for language \"%04d-%s\" without standard key \"LegalCopyright\""), lang_id, lang_name); + + 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"), CtoTString(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, dir_used; + int uninstconfirm=0; + int instlog=0, instlog_used; + int main=0; + +#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT +again: +#endif + + dir_used = 0; + 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"), CtoTString(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(); + // -1 because the default size is 1 + int stringSize = NSIS_MAX_STRLEN*(build_unicode?sizeof(TCHAR):sizeof(char)); + if (!res_editor->AddExtraVirtualSize2PESection(NSIS_VARS_SECTION, (MaxUserVars - 1) * 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"), CtoTString(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); + + 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"), CtoTString(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"), CtoTString(err.what())); + return PS_ERROR; + } + + return PS_OK; +} + +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,_T("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"), CtoTString(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,_T("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_cmd[0]) + { + LPTSTR arg = _tcsstr(postbuild_cmd, _T("%1")); + if (arg) // if found, replace %1 by build_output_filename + { + memmove(arg+_tcslen(build_output_filename), arg+2, (_tcslen(arg+2)+1)*sizeof(TCHAR)); + memmove(arg, build_output_filename, _tcslen(build_output_filename)*sizeof(TCHAR)); + } + SCRIPT_MSG(_T("\nFinalize command: %s\n"),postbuild_cmd); #ifdef _WIN32 int ret=sane_system(postbuild_cmd); #else @@ -2914,797 +2914,797 @@ int CEXEBuild::write_output(void) int ret=system(postbuild_cmd); #endif if (ret != 0) - INFO_MSG(_T("Finalize command returned %d\n"),ret); + INFO_MSG(_T("Finalize command returned %d\n"),ret); } - 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) - { - _ftprintf(g_output,_T("warning: %s\n"),buf); - fflush(g_output); - } -} - -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) - { - _ftprintf(g_output,_T("warning: %s\n"),buf); - fflush(g_output); - } -} - -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) - { - _ftprintf(g_output,_T("%s"),buf); - fflush(g_output); - } - } -} - -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++; - _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; - } - fflush(g_output); -} - -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 -} - -// Added by Ximon Eighteen 5th August 2002 -#ifdef NSIS_CONFIG_PLUGIN_SUPPORT -void CEXEBuild::build_plugin_table(void) -{ - if (plugins_processed) - return; - plugins_processed=1; - - plugin_used = false; - uninst_plugin_used = false; - tstring searchPath = definedlist.find(_T("NSISDIR")); - searchPath += PLATFORM_PATH_SEPARATOR_STR _T("Plugins"); - INFO_MSG(_T("Processing plugin dlls: \"%s") PLATFORM_PATH_SEPARATOR_STR _T("*.dll\"\n"),searchPath.c_str()); - m_plugins.FindCommands(searchPath, display_info?true:false); - INFO_MSG(_T("\n")); -} - -#define FLAG_OFFSET(flag) (FIELD_OFFSET(exec_flags_t, flag)/sizeof(int)) - -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)); - } - } -} - -#ifdef _UNICODE -int CEXEBuild::set_target_minimal_OS(int major, int minor) -{ - target_minimal_OS = MAKELONG(minor,major); - build_unicode = major>=5; - definedlist.del(_T("NSIS_UNICODE")); - definedlist.del(_T("NSIS_CHAR_SIZE")); - if (build_unicode) // update defines depending on target installer type - { - definedlist.add(_T("NSIS_UNICODE")); - definedlist.add(_T("NSIS_CHAR_SIZE"), _T("2")); - } - else - { - definedlist.add(_T("NSIS_CHAR_SIZE"), _T("1")); - } - return load_stub(); -} -#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(); -} - -tstring CEXEBuild::get_stub_variant_suffix() -{ - LONG variant = 0; - for (int index = 0; index < COUNTOF(available_stub_variants); index++) - { - if (target_minimal_OS >= available_stub_variants[index]) - variant = available_stub_variants[index]; - else - break; - } - if (variant == 0) - return tstring(); - TCHAR buf[32]; - _stprintf(buf, _T(".%d_%d"), HIWORD(variant), LOWORD(variant)); - return tstring(buf); -} - -int CEXEBuild::load_stub() -{ - return update_exehead(stub_filename+get_stub_variant_suffix(), &m_exehead_original_size); -} - -int CEXEBuild::update_exehead(const tstring& file, size_t *size/*=NULL*/) { - FILE *tmpfile = _tfopen(file.c_str(), _T("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__")); - } -} - + 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) + { + _ftprintf(g_output,_T("warning: %s\n"),buf); + fflush(g_output); + } +} + +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) + { + _ftprintf(g_output,_T("warning: %s\n"),buf); + fflush(g_output); + } +} + +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) + { + _ftprintf(g_output,_T("%s"),buf); + fflush(g_output); + } + } +} + +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++; + _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; + } + fflush(g_output); +} + +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 +} + +// Added by Ximon Eighteen 5th August 2002 +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT +void CEXEBuild::build_plugin_table(void) +{ + if (plugins_processed) + return; + plugins_processed=1; + + plugin_used = false; + uninst_plugin_used = false; + tstring searchPath = definedlist.find(_T("NSISDIR")); + searchPath += PLATFORM_PATH_SEPARATOR_STR _T("Plugins"); + INFO_MSG(_T("Processing plugin dlls: \"%s") PLATFORM_PATH_SEPARATOR_STR _T("*.dll\"\n"),searchPath.c_str()); + m_plugins.FindCommands(searchPath, display_info?true:false); + INFO_MSG(_T("\n")); +} + +#define FLAG_OFFSET(flag) (FIELD_OFFSET(exec_flags_t, flag)/sizeof(int)) + +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)); + } + } +} + +#ifdef _UNICODE +int CEXEBuild::set_target_minimal_OS(int major, int minor) +{ + target_minimal_OS = MAKELONG(minor,major); + build_unicode = major>=5; + definedlist.del(_T("NSIS_UNICODE")); + definedlist.del(_T("NSIS_CHAR_SIZE")); + if (build_unicode) // update defines depending on target installer type + { + definedlist.add(_T("NSIS_UNICODE")); + definedlist.add(_T("NSIS_CHAR_SIZE"), _T("2")); + } + else + { + definedlist.add(_T("NSIS_CHAR_SIZE"), _T("1")); + } + return load_stub(); +} +#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(); +} + +tstring CEXEBuild::get_stub_variant_suffix() +{ + LONG variant = 0; + for (int index = 0; index < COUNTOF(available_stub_variants); index++) + { + if (target_minimal_OS >= available_stub_variants[index]) + variant = available_stub_variants[index]; + else + break; + } + if (variant == 0) + return tstring(); + TCHAR buf[32]; + _stprintf(buf, _T(".%d_%d"), HIWORD(variant), LOWORD(variant)); + return tstring(buf); +} + +int CEXEBuild::load_stub() +{ + return update_exehead(stub_filename+get_stub_variant_suffix(), &m_exehead_original_size); +} + +int CEXEBuild::update_exehead(const tstring& file, size_t *size/*=NULL*/) { + FILE *tmpfile = _tfopen(file.c_str(), _T("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__")); + } +} +