home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Source / build.cpp < prev    next >
C/C++ Source or Header  |  2004-02-05  |  94KB  |  3,284 lines

  1. #include "Platform.h"
  2. #include <stdio.h>
  3. #include "exehead/config.h"
  4. #include "exehead/fileform.h"
  5.  
  6. #include "exedata.h"
  7.  
  8. #include "build.h"
  9. #include "util.h"
  10.  
  11. #include "exehead/resource.h"
  12. #include "ResourceEditor.h"
  13. #include "DialogTemplate.h"
  14. #include "ResourceVersionInfo.h"
  15. #include <Shlobj.h>
  16.  
  17. int MMapFile::m_iAllocationGranularity = 0;
  18.  
  19. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  20. DWORD WINAPI lzmaCompressThread(LPVOID lpParameter)
  21. {
  22.   CLZMA *Compressor = (CLZMA *) lpParameter;
  23.   if (!Compressor)
  24.     return 0;
  25.  
  26.   return Compressor->CompressReal();
  27. }
  28. #endif
  29.  
  30. bool isSimpleChar(char ch)
  31. {
  32.   return (ch == '.' ) || (ch == '_' ) || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
  33. }
  34.  
  35. void CEXEBuild::define(const char *p, const char *v)
  36. {
  37.   definedlist.add(p,v);
  38. }
  39.  
  40. CEXEBuild::~CEXEBuild()
  41. {
  42.   free(header_data_new);
  43.   free(m_unicon_data);
  44.   
  45.   int nlt = lang_tables.getlen() / sizeof(LanguageTable);
  46.   LanguageTable *nla = (LanguageTable*)lang_tables.get();
  47.  
  48.   for (int i = 0; i < nlt; i++) {
  49.     DeleteLangTable(nla+i);
  50.   }
  51. }
  52.  
  53. CEXEBuild::CEXEBuild()
  54. {
  55.   linecnt = 0;
  56.   fp = 0;
  57.   curfilename = 0;
  58.  
  59.   display_info=1;
  60.   display_script=1;
  61.   display_errors=1;
  62.   display_warnings=1;
  63.  
  64.   cur_ifblock=NULL;
  65.   last_line_had_slash=0;
  66.   inside_comment=false;
  67.  
  68.   build_include_depth=0;
  69.  
  70.   has_called_write_output=0;
  71.  
  72.   ns_func.add("",0); // make sure offset 0 is special on these (i.e. never used by a label)
  73.   ns_label.add("",0);
  74.  
  75.   header_data_new=(unsigned char*)malloc(zlib_exeheader_size);
  76.   exeheader_size_new=zlib_exeheader_size;
  77.   exeheader_size=zlib_exeheader_size;
  78.  
  79.   if (!header_data_new)
  80.   {
  81.     ERROR_MSG("Internal compiler error #12345: malloc(%d) failed\n",exeheader_size_new);
  82.     extern void quit(); quit();
  83.   }
  84.  
  85.   // Changed by Amir Szekely 31st July 2002
  86.   memcpy(header_data_new,zlib_header_data,zlib_exeheader_size);
  87.  
  88. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  89.   // Changed by Amir Szekely 11th July 2002
  90.   // No need to check for uninstaller icon if uninstall support is disabled.
  91.   if (unicondata_size != icondata_size)
  92.   {
  93.     ERROR_MSG("Internal compiler error #12345: installer,uninstaller icon size mismatch (%d,%d)\n",icondata_size,unicondata_size);
  94.     extern void quit(); quit();
  95.   }
  96. #endif // NSIS_CONFIG_UNINSTALL_SUPPORT
  97.  
  98.   extern const char *NSIS_VERSION;
  99.   definedlist.add("NSIS_VERSION", NSIS_VERSION);
  100.  
  101. #define intdef2str_(x) #x
  102. #define intdef2str(x) intdef2str_(x)
  103.   definedlist.add("NSIS_MAX_INST_TYPES", intdef2str(NSIS_MAX_INST_TYPES));
  104.   definedlist.add("NSIS_MAX_STRLEN", intdef2str(NSIS_MAX_STRLEN));
  105.   definedlist.add("NSIS_DEFAULT_LANG", intdef2str(NSIS_DEFAULT_LANG));
  106.   definedlist.add("NSIS_COMPRESS_BZIP2_LEVEL", intdef2str(NSIS_COMPRESS_BZIP2_LEVEL));
  107. #undef intdef2str
  108. #undef intdef2str_
  109. #ifdef NSIS_BZIP2_COMPRESS_WHOLE
  110.   definedlist.add("NSIS_BZIP2_COMPRESS_WHOLE");
  111. #endif
  112. #ifdef NSIS_COMPRESS_BZIP2_SMALLMODE
  113.   definedlist.add("NSIS_COMPRESS_BZIP2_SMALLMODE");
  114. #endif
  115. #ifdef NSIS_CONFIG_COMPONENTPAGE
  116.   definedlist.add("NSIS_CONFIG_COMPONENTPAGE");
  117. #endif
  118. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  119.   definedlist.add("NSIS_CONFIG_COMPRESSION_SUPPORT");
  120. #endif
  121. #ifdef NSIS_CONFIG_CRC_ANAL
  122.   definedlist.add("NSIS_CONFIG_CRC_ANAL");
  123. #endif
  124. #ifdef NSIS_CONFIG_CRC_SUPPORT
  125.   definedlist.add("NSIS_CONFIG_CRC_SUPPORT");
  126. #endif
  127. #ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
  128.   definedlist.add("NSIS_CONFIG_ENHANCEDUI_SUPPORT");
  129. #endif
  130. #ifdef NSIS_CONFIG_LICENSEPAGE
  131.   definedlist.add("NSIS_CONFIG_LICENSEPAGE");
  132. #endif
  133. #ifdef NSIS_CONFIG_LOG
  134.   definedlist.add("NSIS_CONFIG_LOG");
  135. #endif
  136. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  137.   definedlist.add("NSIS_CONFIG_PLUGIN_SUPPORT");
  138. #endif
  139. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  140.   definedlist.add("NSIS_CONFIG_SILENT_SUPPORT");
  141. #endif
  142. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  143.   definedlist.add("NSIS_CONFIG_UNINSTALL_SUPPORT");
  144. #endif
  145. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  146.   definedlist.add("NSIS_CONFIG_VISIBLE_SUPPORT");
  147. #endif
  148. #ifdef NSIS_SUPPORT_ACTIVEXREG
  149.   definedlist.add("NSIS_SUPPORT_ACTIVEXREG");
  150. #endif
  151. #ifdef NSIS_SUPPORT_BGBG
  152.   definedlist.add("NSIS_SUPPORT_BGBG");
  153. #endif
  154. #ifdef NSIS_SUPPORT_CODECALLBACKS
  155.   definedlist.add("NSIS_SUPPORT_CODECALLBACKS");
  156. #endif
  157. #ifdef NSIS_SUPPORT_COPYFILES
  158.   definedlist.add("NSIS_SUPPORT_COPYFILES");
  159. #endif
  160. #ifdef NSIS_SUPPORT_CREATESHORTCUT
  161.   definedlist.add("NSIS_SUPPORT_CREATESHORTCUT");
  162. #endif
  163. #ifdef NSIS_SUPPORT_DELETE
  164.   definedlist.add("NSIS_SUPPORT_DELETE");
  165. #endif
  166. #ifdef NSIS_SUPPORT_ENVIRONMENT
  167.   definedlist.add("NSIS_SUPPORT_ENVIRONMENT");
  168. #endif
  169. #ifdef NSIS_SUPPORT_EXECUTE
  170.   definedlist.add("NSIS_SUPPORT_EXECUTE");
  171. #endif
  172. #ifdef NSIS_SUPPORT_FILE
  173.   definedlist.add("NSIS_SUPPORT_FILE");
  174. #endif
  175. #ifdef NSIS_SUPPORT_FILEFUNCTIONS
  176.   definedlist.add("NSIS_SUPPORT_FILEFUNCTIONS");
  177. #endif
  178. #ifdef NSIS_SUPPORT_FINDFIRST
  179.   definedlist.add("NSIS_SUPPORT_FINDFIRST");
  180. #endif
  181. #ifdef NSIS_SUPPORT_FNUTIL
  182.   definedlist.add("NSIS_SUPPORT_FNUTIL");
  183. #endif
  184. #ifdef NSIS_SUPPORT_GETDLLVERSION
  185.   definedlist.add("NSIS_SUPPORT_GETDLLVERSION");
  186. #endif
  187. #ifdef NSIS_SUPPORT_GETFILETIME
  188.   definedlist.add("NSIS_SUPPORT_GETFILETIME");
  189. #endif
  190. #ifdef NSIS_SUPPORT_HWNDS
  191.   definedlist.add("NSIS_SUPPORT_HWNDS");
  192. #endif
  193. #ifdef NSIS_SUPPORT_INIFILES
  194.   definedlist.add("NSIS_SUPPORT_INIFILES");
  195. #endif
  196. #ifdef NSIS_SUPPORT_INTOPTS
  197.   definedlist.add("NSIS_SUPPORT_INTOPTS");
  198. #endif
  199. #ifdef NSIS_SUPPORT_MESSAGEBOX
  200.   definedlist.add("NSIS_SUPPORT_MESSAGEBOX");
  201. #endif
  202. #ifdef NSIS_SUPPORT_MOVEONREBOOT
  203.   definedlist.add("NSIS_SUPPORT_MOVEONREBOOT");
  204. #endif
  205. #ifdef NSIS_SUPPORT_REBOOT
  206.   definedlist.add("NSIS_SUPPORT_REBOOT");
  207. #endif
  208. #ifdef NSIS_SUPPORT_REGISTRYFUNCTIONS
  209.   definedlist.add("NSIS_SUPPORT_REGISTRYFUNCTIONS");
  210. #endif
  211. #ifdef NSIS_SUPPORT_RENAME
  212.   definedlist.add("NSIS_SUPPORT_RENAME");
  213. #endif
  214. #ifdef NSIS_SUPPORT_RMDIR
  215.   definedlist.add("NSIS_SUPPORT_RMDIR");
  216. #endif
  217. #ifdef NSIS_SUPPORT_SHELLEXECUTE
  218.   definedlist.add("NSIS_SUPPORT_SHELLEXECUTE");
  219. #endif
  220. #ifdef NSIS_SUPPORT_STACK
  221.   definedlist.add("NSIS_SUPPORT_STACK");
  222. #endif
  223. #ifdef NSIS_SUPPORT_STROPTS
  224.   definedlist.add("NSIS_SUPPORT_STROPTS");
  225. #endif
  226. #ifdef NSIS_ZLIB_COMPRESS_WHOLE
  227.   definedlist.add("NSIS_ZLIB_COMPRESS_WHOLE");
  228. #endif
  229.  
  230.   // Added by Amir Szekely 11th July 2002
  231.   // Coded by Robert Rainwater
  232.   {
  233.     char szNSISDir[NSIS_MAX_STRLEN],*fn2;
  234.     GetModuleFileName(NULL,szNSISDir,sizeof(szNSISDir)-sizeof("\\Include"));
  235.     fn2=strrchr(szNSISDir,'\\');
  236.     if(fn2!=NULL) *fn2=0;
  237.     definedlist.add("NSISDIR",(char*)szNSISDir);
  238.     lstrcat(szNSISDir, "\\Include");
  239.     include_dirs.add(szNSISDir,0);
  240.   }
  241.  
  242. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  243.   // Added by Sunil Kamath 11 June 2003
  244.   definedlist.add("NSIS_SUPPORT_STANDARD_PREDEFINES");
  245. #endif
  246.  
  247. // no more optional
  248. definedlist.add("NSIS_SUPPORT_NAMED_USERVARS");
  249.  
  250. #ifdef NSIS_SUPPORT_VERSION_INFO
  251.   definedlist.add("NSIS_SUPPORT_VERSION_INFO");
  252. #endif
  253.  
  254. // no more optional
  255. definedlist.add("NSIS_SUPPORT_LANG_IN_STRINGS");
  256.  
  257. #ifdef NSIS_FIX_DEFINES_IN_STRINGS
  258.   definedlist.add("NSIS_FIX_DEFINES_IN_STRINGS");
  259. #endif
  260.  
  261.   db_opt_save=db_comp_save=db_full_size=db_opt_save_u=db_comp_save_u=db_full_size_u=0;
  262.  
  263.   // Added by Amir Szekely 31st July 2002
  264. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  265.   compressor = &zlib_compressor;
  266. #endif
  267.   build_compressor_set = false;
  268.   build_compressor_final = false;
  269. #ifdef NSIS_ZLIB_COMPRESS_WHOLE
  270.   build_compress_whole = true;
  271. #else
  272.   build_compress_whole = false;
  273. #endif
  274.   build_compress=1;
  275.   build_compress_level=9;
  276.   build_compress_dict_size=1<<23;
  277.  
  278.   cur_entries=&build_entries;
  279.   cur_datablock=&build_datablock;
  280.   cur_functions=&build_functions;
  281.   cur_labels=&build_labels;
  282.   cur_sections=&build_sections;
  283.   cur_header=&build_header;
  284.   cur_strlist=&build_strlist;
  285.   cur_langtables=&build_langtables;
  286.   cur_ctlcolors=&build_ctlcolors;
  287.   cur_pages=&build_pages;
  288.   cur_page=0;
  289.   cur_page_type=-1;
  290.  
  291.   build_filebuflen=32<<20; // 32mb
  292.  
  293.   subsection_open_cnt=0;
  294.   build_cursection_isfunc=0;
  295.   build_cursection=NULL;
  296.   // init public data.
  297.   build_packname[0]=build_packcmd[0]=build_output_filename[0]=0;
  298.  
  299.   // Added by ramon 23 May 2003
  300.   build_allowskipfiles=1;
  301.  
  302.   // Added by ramon 6 jun 2003
  303. #ifdef NSIS_SUPPORT_VERSION_INFO
  304.   version_product_v[0]=0;
  305. #endif
  306.  
  307.   build_overwrite=build_last_overwrite=0;
  308.   build_crcchk=1;
  309.   build_datesave=1;
  310.   build_optimize_datablock=1;
  311.  
  312.   memset(&build_header,-1,sizeof(build_header));
  313.  
  314.   build_header.install_reg_rootkey=0;
  315.   build_header.flags=CH_FLAGS_NO_ROOT_DIR;
  316. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  317.   build_header.lb_bg=RGB(0,0,0);
  318.   build_header.lb_fg=RGB(0,255,0);
  319. #endif
  320. #ifdef NSIS_CONFIG_LICENSEPAGE
  321.   build_header.license_bg=-COLOR_BTNFACE;
  322. #endif
  323.   build_header.install_directory_ptr=0;
  324.   build_header.install_directory_auto_append=0;
  325.   build_header.install_reg_key_ptr=0;
  326.   build_header.install_reg_value_ptr=0;
  327. #ifdef NSIS_CONFIG_COMPONENTPAGE
  328.   memset(build_header.install_types,0,sizeof(build_header.install_types));
  329. #endif
  330.   memset(&build_header.blocks,0,sizeof(build_header.blocks));
  331.  
  332.   uninstall_mode=0;
  333.   uninstall_size_full=0;
  334.   uninstall_size=-1;
  335.  
  336.   memset(&build_uninst,-1,sizeof(build_uninst));
  337.  
  338.   build_header.install_reg_rootkey=0;
  339.   build_uninst.flags=0;
  340. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  341.   build_uninst.lb_bg=RGB(0,0,0);
  342.   build_uninst.lb_fg=RGB(0,255,0);
  343. #endif
  344. #ifdef NSIS_CONFIG_LICENSEPAGE
  345.   build_uninst.license_bg=-COLOR_BTNFACE;
  346. #endif
  347.   build_uninst.install_directory_ptr=0;
  348.   build_uninst.install_directory_auto_append=0;
  349.   build_uninst.install_reg_key_ptr=0;
  350.   build_uninst.install_reg_value_ptr=0;
  351. #ifdef NSIS_CONFIG_COMPONENTPAGE
  352.   memset(build_uninst.install_types,0,sizeof(build_uninst.install_types));
  353. #endif
  354.   memset(&build_uninst.blocks,0,sizeof(build_uninst.blocks));
  355.  
  356.   uninstaller_writes_used=0;
  357.  
  358.   build_strlist.add("",0);
  359.   ubuild_strlist.add("",0);
  360.  
  361.   build_langstring_num=0;
  362.   ubuild_langstring_num=0;
  363.  
  364.   build_font[0]=NULL;
  365.   build_font_size=0;
  366.  
  367.   m_unicon_data=(unsigned char *)malloc(unicondata_size+3*sizeof(DWORD));
  368.   memcpy(m_unicon_data+2*sizeof(DWORD),unicon_data+22,unicondata_size);
  369.   *(DWORD*)(m_unicon_data) = unicondata_size;
  370.   *(DWORD*)(m_unicon_data + sizeof(DWORD)) = 0;
  371.   *(DWORD*)(m_unicon_data + 2*sizeof(DWORD) + unicondata_size) = 0;
  372.   unicondata_size += 3*sizeof(DWORD);
  373.  
  374.   branding_image_found=false;
  375.  
  376.   no_space_texts=false;
  377.  
  378. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  379.   build_plugin_unload=0;
  380.   plugins_processed=0;
  381. #endif
  382.  
  383.   last_used_lang=MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  384.  
  385.   res_editor=0;
  386.  
  387.   enable_last_page_cancel=0;
  388.   uenable_last_page_cancel=0;
  389.  
  390.   license_res_id=IDD_LICENSE;
  391.  
  392.   disable_window_icon=0;
  393.  
  394.   notify_hwnd=0;
  395.  
  396.   defcodepage_set=false;
  397.   uDefCodePage=CP_ACP;
  398.  
  399.   InitLangTables();
  400.  
  401.   // Register static user variables $0, $1 and so on
  402.   // with ONE of reference count, to avoid warning on this vars
  403.   char Aux[3];
  404.   for ( int i = 0; i < 10; i++ )    // 0 - 9
  405.   {
  406.     sprintf(Aux, "%d", i);    
  407.     m_UserVarNames.add(Aux,1);
  408.   }
  409.   for ( i = 0; i < 10; i++ )        // 10 - 19
  410.   {
  411.     sprintf(Aux, "R%d", i);    
  412.     m_UserVarNames.add(Aux,1);
  413.   }
  414.   m_UserVarNames.add("CMDLINE",1);       // 20 everything before here doesn't have trailing slash removal
  415.   m_UserVarNames.add("INSTDIR",1);       // 21
  416.   m_UserVarNames.add("OUTDIR",1);        // 22
  417.   m_UserVarNames.add("EXEDIR",1);        // 23
  418.   m_UserVarNames.add("LANGUAGE",1);      // 24
  419.   m_UserVarNames.add("TEMP",-1);         // 25
  420.   m_UserVarNames.add("PLUGINSDIR",-1);   // 26
  421.   m_UserVarNames.add("HWNDPARENT",-1);   // 27
  422.   m_UserVarNames.add("_CLICK",-1);       // 28
  423.  
  424.   m_iBaseVarsNum = m_UserVarNames.getnum();
  425.  
  426.   m_ShellConstants.add("WINDIR",CSIDL_WINDOWS,CSIDL_WINDOWS);
  427.   m_ShellConstants.add("SYSDIR",CSIDL_SYSTEM,CSIDL_SYSTEM);
  428.   m_ShellConstants.add("PROGRAMFILES",CSIDL_PROGRAM_FILES, CSIDL_PROGRAM_FILES);
  429.   m_ShellConstants.add("SMPROGRAMS",CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS);
  430.   m_ShellConstants.add("SMSTARTUP",CSIDL_STARTUP, CSIDL_COMMON_STARTUP);
  431.   m_ShellConstants.add("DESKTOP",CSIDL_DESKTOPDIRECTORY, CSIDL_COMMON_DESKTOPDIRECTORY);
  432.   m_ShellConstants.add("STARTMENU",CSIDL_STARTMENU, CSIDL_COMMON_STARTMENU);
  433.   m_ShellConstants.add("QUICKLAUNCH", CSIDL_APPDATA, CSIDL_PRINTERS);
  434.   m_ShellConstants.add("COMMONFILES",CSIDL_PROGRAM_FILES_COMMON, CSIDL_PROGRAM_FILES_COMMON);
  435.   m_ShellConstants.add("DOCUMENTS",CSIDL_PERSONAL, CSIDL_COMMON_DOCUMENTS);
  436.   m_ShellConstants.add("SENDTO",CSIDL_SENDTO, CSIDL_SENDTO);
  437.   m_ShellConstants.add("RECENT",CSIDL_RECENT, CSIDL_RECENT);
  438.   m_ShellConstants.add("FAVORITES",CSIDL_FAVORITES, CSIDL_COMMON_FAVORITES);
  439.   m_ShellConstants.add("MUSIC",CSIDL_MYMUSIC, CSIDL_COMMON_MUSIC);
  440.   m_ShellConstants.add("PICTURES",CSIDL_MYPICTURES, CSIDL_COMMON_PICTURES);
  441.   m_ShellConstants.add("VIDEOS",CSIDL_MYVIDEO, CSIDL_COMMON_VIDEO);
  442.   m_ShellConstants.add("NETHOOD", CSIDL_NETHOOD, CSIDL_NETHOOD);
  443.   m_ShellConstants.add("FONTS", CSIDL_FONTS, CSIDL_FONTS);
  444.   m_ShellConstants.add("TEMPLATES", CSIDL_TEMPLATES, CSIDL_COMMON_TEMPLATES);
  445.   m_ShellConstants.add("APPDATA", CSIDL_APPDATA, CSIDL_COMMON_APPDATA);
  446.   m_ShellConstants.add("PRINTHOOD", CSIDL_PRINTHOOD, CSIDL_PRINTHOOD);
  447.   //m_ShellConstants.add("ALTSTARTUP", CSIDL_ALTSTARTUP, CSIDL_COMMON_ALTSTARTUP);
  448.   m_ShellConstants.add("INTERNET_CACHE", CSIDL_INTERNET_CACHE, CSIDL_INTERNET_CACHE);
  449.   m_ShellConstants.add("COOKIES", CSIDL_COOKIES, CSIDL_COOKIES);
  450.   m_ShellConstants.add("HISTORY", CSIDL_HISTORY, CSIDL_HISTORY);
  451.   m_ShellConstants.add("PROFILE", CSIDL_PROFILE, CSIDL_PROFILE);
  452.   m_ShellConstants.add("ADMINTOOLS", CSIDL_ADMINTOOLS, CSIDL_COMMON_ADMINTOOLS);
  453.   m_ShellConstants.add("RESOURCES", CSIDL_RESOURCES, CSIDL_RESOURCES);
  454.   m_ShellConstants.add("RESOURCES_LOCALIZED", CSIDL_RESOURCES_LOCALIZED, CSIDL_RESOURCES_LOCALIZED);
  455.   m_ShellConstants.add("CDBURN_AREA", CSIDL_CDBURN_AREA, CSIDL_CDBURN_AREA);
  456. }
  457.  
  458. int CEXEBuild::getcurdbsize() { return cur_datablock->getlen(); }
  459.  
  460. // returns offset in stringblock
  461. int CEXEBuild::add_string(const char *string, int process/*=1*/, WORD codepage/*=CP_ACP*/)
  462. {
  463.   if (!string || !*string) return 0;
  464.  
  465.   if (*string == '$' && *(string+1) == '(') {
  466.     int idx = 0;
  467.     char *cp = strdup(string+2);
  468.     char *p = strchr(cp, ')');
  469.     if (p && p[1] == '\0' ) { // if string is only a language str identifier
  470.       *p = 0;
  471.       idx = DefineLangString(cp, process);
  472.     }
  473.     free(cp);
  474.     if (idx < 0) return idx;
  475.   }
  476.  
  477.   if (!process) return cur_strlist->add(string,2);
  478.  
  479.   char buf[4096];
  480.   preprocess_string(buf,string,codepage);
  481.   return cur_strlist->add(buf,2);
  482. }
  483.  
  484. int CEXEBuild::add_intstring(const int i) // returns offset in stringblock
  485. {
  486.   char i_str[64];
  487.   wsprintf(i_str, "%d", i);
  488.   return add_string(i_str);
  489. }
  490.  
  491. // based on Dave Laundon's code
  492. int CEXEBuild::preprocess_string(char *out, const char *in, WORD codepage/*=CP_ACP*/)
  493. {
  494.   const char *p=in;
  495.   while (*p)
  496.   {
  497.     const char *np=CharNextExA(codepage, p, 0);
  498.     
  499.     if (np-p > 1) // multibyte char
  500.     {
  501.       int l=np-p;
  502.       while (l--)
  503.       {
  504.         int i = (unsigned char)*p++;
  505.         if (i >= NS_CODES_START) {
  506.           *out++ = (char)NS_SKIP_CODE;
  507.         }
  508.         *out++=i;
  509.       }
  510.       continue;
  511.     }
  512.     
  513.     int i = (unsigned char)*p;
  514.     
  515.     p=np;
  516.     
  517.     // Test for characters extending into the variable codes
  518.     if (i >= NS_CODES_START) {
  519.       *out++ = (char)NS_SKIP_CODE;
  520.     }
  521.     else if (i == '$')
  522.     {
  523.       if (*p == '$')
  524.         p++; // Can simply convert $$ to $ now
  525.       else
  526.       {
  527.         {
  528.           bool bProceced=false;
  529.           if ( *p )
  530.           {
  531.             const char *pUserVarName = p;
  532.             while (isSimpleChar(*pUserVarName))
  533.               pUserVarName++;
  534.  
  535.             while (pUserVarName > p)
  536.             {
  537.               if (m_ShellConstants.get((char*)p, pUserVarName-p) >= 0)
  538.                 break; // Upps it's a shell constant
  539.  
  540.               int idxUserVar = m_UserVarNames.get((char*)p, pUserVarName-p);
  541.               if (idxUserVar >= 0)
  542.               {
  543.                 // Well, using variables inside string formating doens't mean 
  544.                 // using the variable, beacuse it will be always an empty string
  545.                 // which is also memory wasting
  546.                 // So the line below must be commented !??
  547.                 //m_UserVarNames.inc_reference(idxUserVar);
  548.                 *out++ = (unsigned int) NS_VAR_CODE; // Named user variable;
  549.                 *(WORD*)out = CODE_SHORT(idxUserVar);
  550.                 out += sizeof(WORD);
  551.                 p += pUserVarName-p;
  552.                 bProceced = true;
  553.                 break;
  554.               }
  555.               pUserVarName--;
  556.             }
  557.           }
  558.           if (!bProceced && *p)
  559.           {
  560.             const char *pShellConstName = p;
  561.             while (isSimpleChar(*pShellConstName))
  562.               pShellConstName++;
  563.  
  564.             while (pShellConstName > p)
  565.             {
  566.               int idxConst = m_ShellConstants.get((char*)p, pShellConstName - p);
  567.               if (idxConst >= 0)
  568.               {
  569.                 int CSIDL_Value_current = m_ShellConstants.get_value1(idxConst);
  570.                 int CSIDL_Value_all = m_ShellConstants.get_value2(idxConst);
  571.                 *out++=(unsigned int)NS_SHELL_CODE; // Constant code identifier
  572.                 *out++=(char)CSIDL_Value_current;
  573.                 *out++=(char)CSIDL_Value_all;
  574.                 p = pShellConstName;
  575.                 bProceced = true;
  576.                 break;
  577.               }
  578.               pShellConstName--;
  579.             }
  580.           }
  581.           if ( !bProceced && *p == '(' )
  582.           {
  583.             int idx = -1;
  584.             char *cp = strdup(p+1);
  585.             char *pos = strchr(cp, ')');
  586.             if (pos) 
  587.             {
  588.               *pos = 0;
  589.               idx = DefineLangString(cp);
  590.               if (idx < 0)
  591.               {
  592.                 *out++ = (unsigned int)NS_LANG_CODE; // Next word is lang-string Identifier
  593.                 *(WORD*)out= CODE_SHORT(-idx-1);
  594.                 out += sizeof(WORD);
  595.                 p += strlen(cp) + 2;
  596.                 bProceced = true;
  597.               }
  598.             }
  599.             free(cp);              
  600.           }
  601.           if ( bProceced )
  602.             continue;
  603.           else
  604.           {
  605.             char tbuf[64];
  606.             char cBracket = '\0';
  607.             bool bDoWarning = true;
  608.  
  609.             if ( *p == '[' )
  610.               cBracket = ']';
  611.             else if ( *p == '(' )
  612.               cBracket = ')';
  613.             else if ( *p == '{' )
  614.               cBracket = '}';
  615.             
  616.             strncpy(tbuf,p,63);
  617.             tbuf[63]=0;
  618.             
  619.             if ( cBracket != 0 )
  620.             {
  621.               if (strchr(tbuf,cBracket)) (strchr(tbuf,cBracket)+1)[0]=0;
  622.               if ( tbuf[0] == '{' && tbuf[strlen(tbuf)-1] == '}' )
  623.               {
  624.                 char *tstIfDefine = strdup(tbuf+1);
  625.                 tstIfDefine[strlen(tstIfDefine)-1] = '\0';
  626.                 bDoWarning = definedlist.find(tstIfDefine) == NULL;
  627.               }
  628.             }
  629.             else
  630.             {
  631.               if (strstr(tbuf," ")) strstr(tbuf," ")[0]=0;
  632.             }
  633.             if ( bDoWarning )
  634.               warning_fl("unknown variable/constant \"%s\" detected, ignoring",tbuf);
  635.             i = '$';
  636.           }
  637.         }
  638.       }
  639.     }
  640.     *out++=i;
  641.   }
  642.   *out=0;
  643.   return 0;
  644. }
  645.  
  646. // what it does is, when you pass it the offset of the last item added, it will determine if
  647. // that data is already present in the datablock, and if so, reference it instead (and shorten
  648. // the datablock as necessary). Reduces overhead if you want to add files to a couple places.
  649. // Woo, an optimizing installer generator, now we're styling.
  650.  
  651. int CEXEBuild::datablock_optimize(int start_offset)
  652. {
  653.   int this_len = cur_datablock->getlen() - start_offset;
  654.   int pos = 0;
  655.  
  656.   if (!build_optimize_datablock || this_len < sizeof(int))
  657.     return start_offset;
  658.  
  659.   MMapBuf *db = (MMapBuf *) cur_datablock;
  660.   db->setro(TRUE);
  661.  
  662.   int first_int = *(int *) db->get(start_offset, sizeof(int));
  663.   db->release();
  664.  
  665.   while (pos < start_offset)
  666.   {
  667.     int this_int = *(int *) db->get(pos, sizeof(int));
  668.     db->release();
  669.  
  670.     if (this_int == first_int)
  671.     {
  672.       int left = this_len;
  673.       while (left > 0)
  674.       {
  675.         int l = min(left, build_filebuflen);
  676.         void *newstuff = db->get(start_offset + this_len - left, l);
  677.         void *oldstuff = db->getmore(pos + this_len - left, l);
  678.  
  679.         int res = memcmp(newstuff, oldstuff, l);
  680.  
  681.         db->release(oldstuff);
  682.         db->release();
  683.  
  684.         if (res)
  685.         {
  686.           break;
  687.         }
  688.  
  689.         left -= l;
  690.       }
  691.  
  692.       if (!left)
  693.       {
  694.         db_opt_save += this_len;
  695.         db->resize(max(start_offset, pos + this_len));
  696.         db->setro(FALSE);
  697.         return pos;
  698.       }
  699.     }
  700.  
  701.     pos += sizeof(int) + (this_int & 0x7fffffff);
  702.   }
  703.  
  704.   db->setro(FALSE);
  705.  
  706.   return start_offset;
  707. }
  708.  
  709. int CEXEBuild::add_db_data(IMMap *map) // returns offset
  710. {
  711.   build_compressor_set = true;
  712.  
  713.   int done = 0;
  714.  
  715.   if (!map)
  716.   {
  717.     ERROR_MSG("Error: add_db_data() called with invalid mapped file\n");
  718.     return -1;
  719.   }
  720.  
  721.   int length = map->getsize();
  722.  
  723.   if (length < 0)
  724.   {
  725.     ERROR_MSG("Error: add_db_data() called with length=%d\n", length);
  726.     return -1;
  727.   }
  728.  
  729.   MMapBuf *db = (MMapBuf *) cur_datablock;
  730.  
  731.   int st = db->getlen();
  732.  
  733. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  734.   if (length && !build_compress_whole && build_compress)
  735.   {
  736.     // grow datablock so that there is room to compress into
  737.     int bufferlen = length + 1024 + length / 4; // give a nice 25% extra space
  738.     db->resize(st + bufferlen + sizeof(int));
  739.  
  740.     int n;
  741.     if (compressor == &lzma_compressor)
  742.       n = ((CLZMA *) compressor)->Init(build_compress_level, build_compress_dict_size);
  743.     else
  744.       n = compressor->Init(build_compress_level);
  745.     if (n != C_OK)
  746.     {
  747.       ERROR_MSG("Internal compiler error #12345: deflateInit() failed(%d).\n", n);
  748.       extern void quit(); quit();
  749.     }
  750.  
  751.     int avail_in = length;
  752.     int avail_out = bufferlen;
  753.     int ret;
  754.     while (avail_in > 0)
  755.     {
  756.       int in_len = min(build_filebuflen, avail_in);
  757.       int out_len = min(build_filebuflen, avail_out);
  758.       
  759.       compressor->SetNextIn((char *) map->get(length - avail_in, in_len), in_len);
  760.       compressor->SetNextOut((char *) db->get(st + sizeof(int) + bufferlen - avail_out, out_len), out_len);
  761.       if ((ret = compressor->Compress(0)) < 0)
  762.       {
  763.         ERROR_MSG("Error: add_db_data() - compress() failed - %d\n", ret);
  764.         return -1;
  765.       }
  766.       map->release();
  767.       db->flush(out_len);
  768.       db->release();
  769.       avail_in -= in_len - compressor->GetAvailIn();
  770.       avail_out -= out_len - compressor->GetAvailOut();
  771.  
  772.       if (!avail_out)
  773.         // not enough space in the output buffer - no compression is better
  774.         break;
  775.     }
  776.  
  777.     // if not enough space in the output buffer - no compression is better
  778.     if (avail_out)
  779.     {
  780.       char *out;
  781.  
  782.       char a;
  783.       compressor->SetNextIn(&a,0);
  784.  
  785.       do
  786.       {
  787.         int out_len = min(build_filebuflen, avail_out);
  788.  
  789.         out = (char *) db->get(st + sizeof(int) + bufferlen - avail_out, out_len);
  790.  
  791.         compressor->SetNextOut(out, out_len);
  792.         if ((ret = compressor->Compress(C_FINISH)) < 0)
  793.         {
  794.           ERROR_MSG("Error: add_db_data() - compress() failed - %d\n", ret);
  795.           return -1;
  796.         }
  797.  
  798.         db->flush(out_len);
  799.         db->release();
  800.  
  801.         avail_out -= out_len - compressor->GetAvailOut();
  802.       }
  803.       while (compressor->GetNextOut() - out > 0 && avail_out > 0);
  804.  
  805.       compressor->End();
  806.  
  807.       int used = bufferlen - avail_out;
  808.  
  809.       // never store compressed if output buffer is full (compression increased the size...)
  810.       if (avail_out && (build_compress == 2 || used < length))
  811.       {
  812.         done=1;
  813.         db->resize(st + used + sizeof(int));
  814.  
  815.         *(int*)db->get(st, sizeof(int)) = used | 0x80000000;
  816.         db->release();
  817.  
  818.         int nst = datablock_optimize(st);
  819.         if (nst == st) db_comp_save += length - used;
  820.         else st = nst;
  821.       }
  822.     }
  823.     else
  824.       compressor->End();
  825.   }
  826. #endif // NSIS_CONFIG_COMPRESSION_SUPPORT
  827.  
  828.   if (!done)
  829.   {
  830.     db->resize(st + length + sizeof(int));
  831.     int *plen = (int *) db->get(st, sizeof(int));
  832.     *plen = length;
  833.     db->release();
  834.  
  835.     int left = length;
  836.     while (left > 0)
  837.     {
  838.       int l = min(build_filebuflen, left);
  839.       int *p = (int *) db->get(st + sizeof(int) + length - left, l);
  840.       memcpy(p, map->get(length - left, l), l);
  841.       db->flush(l);
  842.       db->release();
  843.       map->release();
  844.       left -= l;
  845.     }
  846.  
  847.     st = datablock_optimize(st);
  848.   }
  849.  
  850.   db_full_size += length + sizeof(int);
  851.  
  852.   return st;
  853. }
  854.  
  855. int CEXEBuild::add_db_data(const char *data, int length) // returns offset
  856. {
  857.   MMapFake fakemap;
  858.   fakemap.set(data, length);
  859.   return add_db_data(&fakemap);
  860. }
  861.  
  862. int CEXEBuild::add_data(const char *data, int length, IGrowBuf *dblock) // returns offset
  863. {
  864.   build_compressor_set=true;
  865.  
  866.   int done=0;
  867.  
  868.   if (length < 0)
  869.   {
  870.     ERROR_MSG("Error: add_data() called with length=%d\n",length);
  871.     return -1;
  872.   }
  873.  
  874.   int st=dblock->getlen();
  875.  
  876. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  877.   if (!build_compress_whole && build_compress)
  878.   {
  879.     // grow datablock so that there is room to compress into
  880.     int bufferlen=length+1024+length/4; // give a nice 25% extra space
  881.     dblock->resize(st+bufferlen+sizeof(int));
  882.  
  883.     int n;
  884.     if (compressor == &lzma_compressor)
  885.       n = ((CLZMA *) compressor)->Init(build_compress_level, build_compress_dict_size);
  886.     else
  887.       n = compressor->Init(build_compress_level);
  888.     if (n != C_OK)
  889.     {
  890.       ERROR_MSG("Internal compiler error #12345: deflateInit() failed(%d).\n",n);
  891.       extern void quit(); quit();
  892.     }
  893.  
  894.     compressor->SetNextIn((char*)data, length);
  895.     compressor->SetNextOut((char*)dblock->get() + st + sizeof(int), bufferlen);
  896.  
  897.     compressor->Compress(C_FINISH);
  898.  
  899.     int used=bufferlen-compressor->GetAvailOut();
  900.  
  901.     // never store compressed if output buffer is full
  902.     if (compressor->GetAvailOut() && (build_compress == 2 || used < length))
  903.     {
  904.       done=1;
  905.       dblock->resize(st+used+sizeof(int));
  906.  
  907.       *((int*)((char *)dblock->get()+st)) = used|0x80000000;
  908.     }
  909.     compressor->End();
  910.   }
  911. #endif // NSIS_CONFIG_COMPRESSION_SUPPORT
  912.  
  913.   if (!done)
  914.   {
  915.     dblock->resize(st);
  916.     dblock->add(&length,sizeof(int));
  917.     dblock->add(data,length);
  918.   }
  919.  
  920.   return st;
  921. }
  922.  
  923. int CEXEBuild::add_label(const char *name)
  924. {
  925.   if (!build_cursection)
  926.   {
  927.     ERROR_MSG("Error: Label declaration not valid outside of function/section\n");
  928.     return PS_ERROR;
  929.   }
  930.   if ((name[0] >= '0' && name[0] <= '9') || name[0] == '-' || name[0] == ' ' || name[0] == ':')
  931.   {
  932.     ERROR_MSG("Error: labels must not begin with 0-9, -, :, or a space.\n");
  933.     return PS_ERROR;
  934.   }
  935.  
  936.   int cs=build_cursection->code;
  937.   int ce=cs+build_cursection->code_size;
  938.  
  939.   char *p=strdup(name);
  940.   if (p[strlen(p)-1] == ':') p[strlen(p)-1]=0;
  941.   int offs=ns_label.add(p,0);
  942.   free(p);
  943.  
  944.   int n=cur_labels->getlen()/sizeof(section);
  945.   if (n)
  946.   {
  947.     section *t=(section*)cur_labels->get();
  948.     while (n--)
  949.     {
  950.       if ((*name == '.' || (t->code >= cs && t->code <= ce))  &&
  951.           t->name_ptr==offs)
  952.       {
  953.         if (*name == '.') ERROR_MSG("Error: global label \"%s\" already declared\n",name);
  954.         else ERROR_MSG("Error: label \"%s\" already declared in section/function\n",name);
  955.         return PS_ERROR;
  956.       }
  957.       t++;
  958.     }
  959.   }
  960.  
  961.   section s={0,};
  962.   s.name_ptr = offs;
  963.   s.code = ce;
  964.   cur_labels->add(&s,sizeof(s));
  965.  
  966.   return PS_OK;
  967. }
  968.  
  969. int CEXEBuild::add_function(const char *funname)
  970. {
  971.   if (build_cursection_isfunc)
  972.   {
  973.     ERROR_MSG("Error: Function open when creating function (use FunctionEnd first)\n");
  974.     return PS_ERROR;
  975.   }
  976.   if (build_cursection)
  977.   {
  978.     ERROR_MSG("Error: Section open when creating function (use SectionEnd first)\n");
  979.     return PS_ERROR;
  980.   }
  981.   if (cur_page)
  982.   {
  983.     ERROR_MSG("Error: PageEx open when creating function (use PageExEnd first)\n");
  984.     return PS_ERROR;
  985.   }
  986.   if (!funname[0])
  987.   {
  988.     ERROR_MSG("Error: Function must have a name\n");
  989.     return PS_ERROR;
  990.   }
  991.  
  992.   set_uninstall_mode(!strnicmp(funname,"un.",3));
  993.  
  994.   int addr=ns_func.add(funname,0);
  995.   int x;
  996.   int n=cur_functions->getlen()/sizeof(section);
  997.   section *tmp=(section*)cur_functions->get();
  998.   for (x = 0; x < n; x ++)
  999.   {
  1000.     if (tmp[x].name_ptr == addr)
  1001.   {
  1002.     ERROR_MSG("Error: Function named \"%s\" already exists.\n",funname);
  1003.     return PS_ERROR;
  1004.   }
  1005.   }
  1006.  
  1007.   cur_functions->resize((n+1)*sizeof(section));
  1008.   build_cursection=((section*)cur_functions->get())+n;
  1009.   build_cursection_isfunc=1;
  1010.   build_cursection->name_ptr=addr;
  1011.   build_cursection->code=cur_entries->getlen()/sizeof(entry);
  1012.   build_cursection->code_size=0;
  1013.   build_cursection->install_types=0;
  1014.   build_cursection->flags=0;
  1015.   build_cursection->size_kb=0;
  1016.   return PS_OK;
  1017. }
  1018.  
  1019. int CEXEBuild::function_end()
  1020. {
  1021.   if (!build_cursection_isfunc)
  1022.   {
  1023.     ERROR_MSG("Error: No function open, FunctionEnd called\n");
  1024.     return PS_ERROR;
  1025.   }
  1026.   // add ret.
  1027.   add_entry_direct(EW_RET);
  1028.  
  1029.   build_cursection_isfunc=0;
  1030.   build_cursection=NULL;
  1031.  
  1032.   set_uninstall_mode(0);
  1033.   return PS_OK;
  1034. }
  1035.  
  1036.  
  1037. int CEXEBuild::section_add_flags(int flags)
  1038. {
  1039.   if (!build_cursection || build_cursection_isfunc)
  1040.   {
  1041.     ERROR_MSG("Error: can't modify flags when no section is open\n");
  1042.     return PS_ERROR;
  1043.   }
  1044.   build_cursection->flags |= flags;
  1045.   return PS_OK;
  1046. }
  1047.  
  1048. int CEXEBuild::section_add_install_type(int inst_type)
  1049. {
  1050.   if (!build_cursection || build_cursection_isfunc)
  1051.   {
  1052.     ERROR_MSG("Error: can't modify flags when no section is open\n");
  1053.     return PS_ERROR;
  1054.   }
  1055.   if (build_cursection->install_types == ~0)
  1056.     build_cursection->install_types = 0;
  1057.   build_cursection->install_types |= inst_type;
  1058.   return PS_OK;
  1059. }
  1060.  
  1061. void CEXEBuild::section_add_size_kb(int kb)
  1062. {
  1063.   if (build_cursection)
  1064.   {
  1065.     build_cursection->size_kb+=kb;
  1066.   }
  1067. }
  1068.  
  1069. int CEXEBuild::section_end()
  1070. {
  1071.   if (build_cursection_isfunc)
  1072.   {
  1073.     ERROR_MSG("Error: SectionEnd specified in function (not section)\n");
  1074.     return PS_ERROR;
  1075.   }
  1076.   if (!build_cursection)
  1077.   {
  1078.     ERROR_MSG("Error: SectionEnd specified and no sections open\n");
  1079.     return PS_ERROR;
  1080.   }
  1081.   add_entry_direct(EW_RET);
  1082.   build_cursection->code_size--;
  1083.   build_cursection=NULL;
  1084.   if (!subsection_open_cnt)
  1085.     set_uninstall_mode(0);
  1086.   return PS_OK;
  1087. }
  1088.  
  1089. int CEXEBuild::add_section(const char *secname, const char *defname, int expand/*=0*/)
  1090. {
  1091.   if (build_cursection_isfunc)
  1092.   {
  1093.     ERROR_MSG("Error: Section can't create section (already in function, use FunctionEnd first)\n");
  1094.     return PS_ERROR;
  1095.   }
  1096.   if (cur_page) {
  1097.     ERROR_MSG("Error: PageEx already open, call PageExEnd first\n");
  1098.     return PS_ERROR;
  1099.   }
  1100.   if (build_cursection)
  1101.   {
  1102.     ERROR_MSG("Error: Section already open, call SectionEnd first\n");
  1103.     return PS_ERROR;
  1104.   }
  1105.  
  1106.   section new_section;
  1107.   new_section.flags = SF_SELECTED;
  1108.   new_section.flags |= expand ? SF_EXPAND : 0;
  1109.   new_section.code_size = 0;
  1110.   new_section.size_kb = 0;
  1111.  
  1112.   char *name = (char*)secname;
  1113.  
  1114.   if (secname[0] == '-')
  1115.   {
  1116.     if (secname[1])
  1117.     {
  1118.       new_section.flags |= SF_SUBSEC;
  1119.       name++;
  1120.     }
  1121.     else
  1122.       new_section.flags |= SF_SUBSECEND;
  1123.   }
  1124.  
  1125.   if (name[0] == '!')
  1126.   {
  1127.     name++;
  1128.     new_section.flags |= SF_BOLD;
  1129.   }
  1130.  
  1131.   int old_uninstall_mode = uninstall_mode;
  1132.  
  1133.   set_uninstall_mode(0);
  1134.  
  1135.   if (!strnicmp(name, "un.", 3))
  1136.   {
  1137.     set_uninstall_mode(1);
  1138.     name += 3;
  1139.   }
  1140.  
  1141.   if (!stricmp(name, "uninstall"))
  1142.   {
  1143.     set_uninstall_mode(1);
  1144.   }
  1145.  
  1146.   if ((new_section.flags & SF_SUBSECEND) && subsection_open_cnt && old_uninstall_mode)
  1147.   {
  1148.     set_uninstall_mode(1);
  1149.   }
  1150.  
  1151.   if (subsection_open_cnt)
  1152.   {
  1153.     if (uninstall_mode != old_uninstall_mode)
  1154.     {
  1155.       ERROR_MSG("Error: Can't create %s section in %s subsection (use SubSectionEnd first)\n", uninstall_mode ? "uninstaller" : "installer", old_uninstall_mode ? "uninstaller" : "installer");
  1156.       return PS_ERROR;
  1157.     }
  1158.   }
  1159.  
  1160.   new_section.code = cur_entries->getlen() / sizeof(entry);
  1161.  
  1162.   new_section.install_types = *name ? 0 : ~0;
  1163.   new_section.name_ptr = add_string(name);
  1164.  
  1165.   cur_sections->add(&new_section, sizeof(section));
  1166.   build_cursection = (section *) cur_sections->get() + cur_header->blocks[NB_SECTIONS].num;
  1167.  
  1168.   if (defname[0])
  1169.   {
  1170.     char buf[32];
  1171.     wsprintf(buf, "%d", cur_header->blocks[NB_SECTIONS].num);
  1172.     if (definedlist.add(defname, buf))
  1173.     {
  1174.       ERROR_MSG("Error: \"%s\" already defined, can't assign section index!\n", defname);
  1175.       return PS_ERROR;
  1176.     }
  1177.   }
  1178.  
  1179.   cur_header->blocks[NB_SECTIONS].num++;
  1180.  
  1181.   if (new_section.flags & (SF_SUBSEC | SF_SUBSECEND))
  1182.   {
  1183.     add_entry_direct(EW_RET);
  1184.     build_cursection->code_size = 0;
  1185.  
  1186.     build_cursection = 0;
  1187.  
  1188.     if (new_section.flags & SF_SUBSECEND)
  1189.     {
  1190.       subsection_open_cnt--;
  1191.       if (subsection_open_cnt < 0)
  1192.       {
  1193.         ERROR_MSG("SubSectionEnd: no SubSections are open\n");
  1194.         return PS_ERROR;
  1195.       }
  1196.       if (!subsection_open_cnt)
  1197.       {
  1198.         set_uninstall_mode(0);
  1199.       }
  1200.     }
  1201.     else
  1202.       subsection_open_cnt++;
  1203.   }
  1204.  
  1205.   return PS_OK;
  1206. }
  1207.  
  1208. int CEXEBuild::add_entry(const entry *ent)
  1209. {
  1210.   if (!build_cursection && !uninstall_mode)
  1211.   {
  1212.     ERROR_MSG("Error: Can't add entry, no section or function is open!\n");
  1213.     return PS_ERROR;
  1214.   }
  1215.  
  1216.   cur_entries->add(ent,sizeof(entry));
  1217.   build_cursection->code_size++;
  1218.   cur_header->blocks[NB_ENTRIES].num++;
  1219.  
  1220.   return PS_OK;
  1221. }
  1222.  
  1223. int CEXEBuild::add_entry_direct(int which, int o0, int o1, int o2, int o3, int o4, int o5 /*o#=0*/)
  1224. {
  1225.   entry ent;
  1226.   ent.which = which;
  1227.   ent.offsets[0] = o0;
  1228.   ent.offsets[1] = o1;
  1229.   ent.offsets[2] = o2;
  1230.   ent.offsets[3] = o3;
  1231.   ent.offsets[4] = o4;
  1232.   ent.offsets[5] = o5;
  1233.   return add_entry(&ent);
  1234. }
  1235.  
  1236. int CEXEBuild::resolve_jump_int(const char *fn, int *a, int offs, int start, int end)
  1237. {
  1238.   if (*a > 0)
  1239.   {
  1240.     char *lname=(char*)ns_label.get()+*a;
  1241.     if (lname[0] == '-' || lname[0]=='+')
  1242.     {
  1243.       *a=offs+atoi(lname)+1;
  1244.     }
  1245.     else
  1246.     {
  1247.       section *s = (section*)cur_labels->get();
  1248.       int n=cur_labels->getlen()/sizeof(section);
  1249.       while (n-->0)
  1250.       {
  1251.         if ((*lname == '.' || (s->code >= start && s->code <= end)) && s->name_ptr == *a)
  1252.         {
  1253.           *a = s->code+1;     // jumps are to the absolute position, +1 (to differentiate between no jump, and jumping to offset 0)
  1254.           s->flags++;
  1255.           return 0;
  1256.         }
  1257.         s++;
  1258.       }
  1259.  
  1260.       ERROR_MSG("Error: could not resolve label \"%s\" in %s\n",lname,fn);
  1261.       return 1;
  1262.     }
  1263.   }
  1264.   else if (*a < 0) // to jump to a user variable target, -variable_index-1 is already stored.
  1265.   {
  1266.   }
  1267.   // otherwise, *a is 0, which means no jump and we also leave it intact
  1268.   return 0;
  1269. }
  1270.  
  1271. int CEXEBuild::resolve_call_int(const char *fn, const char *str, int fptr, int *ofs)
  1272. {
  1273.   if (fptr < 0) return 0;
  1274.   int nf=cur_functions->getlen()/sizeof(section);
  1275.   section *sec=(section *)cur_functions->get();
  1276.   while (nf-- > 0)
  1277.   {
  1278.     if (sec->name_ptr>0 && sec->name_ptr == fptr)
  1279.     {
  1280.       ofs[0]=sec->code;
  1281.       sec->flags++;
  1282.       return 0;
  1283.     }
  1284.     sec++;
  1285.   }
  1286.   ERROR_MSG("Error: resolving %s function \"%s\" in %s\n",str,(char*)ns_func.get()+fptr,fn);
  1287.   ERROR_MSG("Note: uninstall functions must begin with \"un.\", and install functions must not\n");
  1288.   return 1;
  1289. }
  1290.  
  1291. int CEXEBuild::resolve_instruction(const char *fn, const char *str, entry *w, int offs, int start, int end)
  1292. {
  1293.   if (w->which == EW_NOP)
  1294.   {
  1295.     if (resolve_jump_int(fn,&w->offsets[0],offs,start,end)) return 1;
  1296.   }
  1297. #ifdef NSIS_SUPPORT_MESSAGEBOX
  1298.   else if (w->which == EW_MESSAGEBOX)
  1299.   {
  1300.     if (resolve_jump_int(fn,&w->offsets[3],offs,start,end)) return 1;
  1301.     if (resolve_jump_int(fn,&w->offsets[5],offs,start,end)) return 1;
  1302.   }
  1303. #endif
  1304.   else if (w->which == EW_IFFILEEXISTS)
  1305.   {
  1306.     if (resolve_jump_int(fn,&w->offsets[1],offs,start,end)) return 1;
  1307.     if (resolve_jump_int(fn,&w->offsets[2],offs,start,end)) return 1;
  1308.   }
  1309.   else if (w->which == EW_IFFLAG)
  1310.   {
  1311.     if (resolve_jump_int(fn,&w->offsets[0],offs,start,end)) return 1;
  1312.     if (resolve_jump_int(fn,&w->offsets[1],offs,start,end)) return 1;
  1313.   }
  1314. #ifdef NSIS_SUPPORT_STROPTS
  1315.   else if (w->which == EW_STRCMP)
  1316.   {
  1317.     if (resolve_jump_int(fn,&w->offsets[2],offs,start,end)) return 1;
  1318.     if (resolve_jump_int(fn,&w->offsets[3],offs,start,end)) return 1;
  1319.   }
  1320. #endif
  1321. #ifdef NSIS_SUPPORT_INTOPTS
  1322.   else if (w->which == EW_INTCMP)
  1323.   {
  1324.     if (resolve_jump_int(fn,&w->offsets[2],offs,start,end)) return 1;
  1325.     if (resolve_jump_int(fn,&w->offsets[3],offs,start,end)) return 1;
  1326.     if (resolve_jump_int(fn,&w->offsets[4],offs,start,end)) return 1;
  1327.   }
  1328. #endif
  1329. #ifdef NSIS_SUPPORT_HWNDS
  1330.   else if (w->which == EW_ISWINDOW)
  1331.   {
  1332.     if (resolve_jump_int(fn,&w->offsets[1],offs,start,end)) return 1;
  1333.     if (resolve_jump_int(fn,&w->offsets[2],offs,start,end)) return 1;
  1334.   }
  1335. #endif
  1336.   else if (w->which == EW_CALL)
  1337.   {
  1338.     if (w->offsets[0] >= 0 && w->offsets[1]) // get as jump
  1339.     {
  1340.       if (resolve_jump_int(fn,&w->offsets[0],offs,start,end)) return 1;
  1341.     }
  1342.     else
  1343.     {
  1344.       if (w->offsets[0] >= 0 && resolve_call_int(fn,str,w->offsets[0],w->offsets)) return 1;
  1345.       // if w->offsets[0] >= 0, EW_CALL requires that it 1-based.
  1346.       // otherwise, if < 0, it needs an increment anyway (since it
  1347.       // was encoded with a -2 base, to prevent it looking like an
  1348.       // empty string "")
  1349.       w->offsets[0]++;
  1350.     }
  1351.   }
  1352. #ifdef NSIS_SUPPORT_STROPTS
  1353.   else if (w->which == EW_GETFUNCTIONADDR)
  1354.   {
  1355.     char buf[32];
  1356.     if (w->offsets[1] < 0)
  1357.     {
  1358.       ERROR_MSG("Error: GetFunctionAddress requires a real function to get address of.\n");
  1359.       return 1;
  1360.     }
  1361.  
  1362.     if (resolve_call_int(fn,str,w->offsets[1],&w->offsets[1])) return 1;
  1363.  
  1364.     w->which=EW_ASSIGNVAR;
  1365.     wsprintf(buf,"%d",w->offsets[1]+1); // +1 here to make 1-based.
  1366.     w->offsets[1]=add_string(buf);
  1367.   }
  1368.   else if (w->which == EW_GETLABELADDR)
  1369.   {
  1370.     char buf[32];
  1371.     if (resolve_jump_int(fn,&w->offsets[1],offs,start,end)) return 1;
  1372.     w->which=EW_ASSIGNVAR;
  1373.     wsprintf(buf,"%d",w->offsets[1]);
  1374.     w->offsets[1]=add_string(buf);
  1375.   }
  1376. #endif
  1377.   return 0;
  1378. }
  1379.  
  1380. int CEXEBuild::resolve_coderefs(const char *str)
  1381. {
  1382.   // resolve jumps&calls
  1383.   {
  1384.     section *sec=(section *)cur_functions->get();
  1385.     int l=cur_functions->getlen()/sizeof(section);
  1386.     entry *w=(entry *)cur_entries->get();
  1387.     while (l-- > 0)
  1388.     {
  1389.       int x;
  1390.       for (x = sec->code; x < sec->code+sec->code_size; x ++)
  1391.       {
  1392.         char fname[1024];
  1393.         wsprintf(fname,"function \"%s\"",ns_func.get()+sec->name_ptr);
  1394.         if (resolve_instruction(fname,str,w+x,x,sec->code,sec->code+sec->code_size)) return 1;
  1395.       }
  1396.       sec++;
  1397.     }
  1398.  
  1399.     int cnt=0;
  1400.     sec=(section *)cur_sections->get();
  1401.     l=cur_sections->getlen()/sizeof(section);
  1402.     while (l-- > 0)
  1403.     {
  1404.       int x=sec->name_ptr;
  1405.       char fname[1024];
  1406.       char *secname;
  1407.       if (x < 0)
  1408.       {
  1409.         // lang string
  1410.         secname = "$(lang string)";
  1411.       }
  1412.       else
  1413.       {
  1414.         // normal string
  1415.         secname = cur_strlist->get() + x;
  1416.       }
  1417.       if (x) wsprintf(fname,"%s section \"%s\" (%d)",str,secname,cnt);
  1418.       else wsprintf(fname,"unnamed %s section (%d)",str,cnt);
  1419.       for (x = sec->code; x < sec->code+sec->code_size; x ++)
  1420.       {
  1421.         if (resolve_instruction(fname,str,w+x,x,sec->code,sec->code+sec->code_size))
  1422.           return 1;
  1423.       }
  1424.       sec++;
  1425.       cnt++;
  1426.     }
  1427. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  1428. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1429.     if (cur_pages->getlen()) {
  1430.       page *p=(page *)cur_pages->get();
  1431.       int i = 0;
  1432.       while (i < cur_header->blocks[NB_PAGES].num) {
  1433.         char pagestr[1024];
  1434.         wsprintf(pagestr, "%s pages", str);
  1435.         if (resolve_call_int(pagestr,p->dlg_id?"pre-page":"create-page",p->prefunc,&p->prefunc)) return 1;
  1436.         if (resolve_call_int(pagestr,"show-page",p->showfunc,&p->showfunc)) return 1;
  1437.         if (resolve_call_int(pagestr,"leave-page",p->leavefunc,&p->leavefunc)) return 1;
  1438.         p++;
  1439.         i++;
  1440.       }
  1441.     }
  1442. #endif
  1443. #endif
  1444.   }
  1445.  
  1446. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1447.   // resolve callbacks
  1448.   {
  1449.     struct {
  1450.       char *name;
  1451.       int *p;
  1452.     } callbacks[] = {
  1453.       {"%s.onInit", &cur_header->code_onInit},
  1454.       {"%s.on%sInstSuccess", &cur_header->code_onInstSuccess},
  1455.       {"%s.on%sInstFailed", &cur_header->code_onInstFailed},
  1456.       {"%s.onUserAbort", &cur_header->code_onUserAbort},
  1457.       {"%s.onVerifyInstDir", &cur_header->code_onVerifyInstDir},
  1458. #ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
  1459.       {"%s.onGUIInit", &cur_header->code_onGUIInit},
  1460.       {"%s.onGUIEnd", &cur_header->code_onGUIEnd},
  1461.       {"%s.onMouseOverSection", &cur_header->code_onMouseOverSection},
  1462. #endif
  1463. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1464.       {"%s.onSelChange", &cur_header->code_onSelChange},
  1465. #endif
  1466.       {0, 0}
  1467.     };
  1468.  
  1469.     for (int i = 0; callbacks[i].name; i++) {
  1470.       char *un = uninstall_mode ? "un" : "";
  1471.       char fname[1024];
  1472.       wsprintf(fname, callbacks[i].name, un, un);
  1473.       char cbstr[1024];
  1474.       wsprintf(cbstr, "%s callback", str);
  1475.       char cbstr2[1024];
  1476.       wsprintf(cbstr2, "%s.callbacks", un);
  1477.  
  1478.       if (resolve_call_int(cbstr,cbstr2,ns_func.find(fname,0),callbacks[i].p))
  1479.         return PS_ERROR;
  1480.     }
  1481.   }
  1482. #endif//NSIS_SUPPORT_CODECALLBACKS
  1483.  
  1484.   // optimize unused functions
  1485.   {
  1486.     section *sec=(section *)cur_functions->get();
  1487.     int l=cur_functions->getlen()/sizeof(section);
  1488.     entry *w=(entry*)cur_entries->get();
  1489.     while (l-- > 0)
  1490.     {
  1491.       if (sec->name_ptr)
  1492.       {
  1493.         if (!sec->flags)
  1494.         {
  1495.           if (sec->code_size>0)
  1496.           {
  1497.             warning("%s function \"%s\" not referenced - zeroing code (%d-%d) out\n",str,
  1498.               ns_func.get()+sec->name_ptr,
  1499.               sec->code,sec->code+sec->code_size);
  1500.             memset(w+sec->code,0,sec->code_size*sizeof(entry));
  1501.           }
  1502.         }
  1503.       }
  1504.       sec++;
  1505.     }
  1506.   }
  1507.  
  1508.   // give warnings on unused labels
  1509.   {
  1510.     section *t=(section*)cur_labels->get();
  1511.     int n=cur_labels->getlen()/sizeof(section);
  1512.     while (n-->0)
  1513.     {
  1514.       if (!t->flags)
  1515.       {
  1516.         char *n=(char*)ns_label.get()+t->name_ptr;
  1517.         if (*n == '.') warning("global label \"%s\" not used",n);
  1518.         else warning("label \"%s\" not used",n);
  1519.       }
  1520.       t++;
  1521.     }
  1522.   }
  1523.  
  1524.   return 0;
  1525. }
  1526.  
  1527. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  1528. int CEXEBuild::add_page(int type)
  1529. {
  1530.   page pg = {
  1531.     0,
  1532.     0,
  1533. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1534.     -1,
  1535.     -1,
  1536.     -1,
  1537. #endif
  1538.     0,
  1539.   };
  1540.  
  1541. #ifndef NSIS_CONFIG_LICENSEPAGE
  1542.   if (type == PAGE_LICENSE)
  1543.   {
  1544.     ERROR_MSG("Error: can't add license page, NSIS_CONFIG_LICENSEPAGE not defined.\n");
  1545.     return PS_ERROR;
  1546.   }
  1547. #endif
  1548. #ifndef NSIS_CONFIG_COMPONENTPAGE
  1549.   if (type == PAGE_COMPONENTS)
  1550.   {
  1551.     ERROR_MSG("Error: can't add components page, NSIS_CONFIG_COMPONENTPAGE not defined.\n");
  1552.     return PS_ERROR;
  1553.   }
  1554. #endif
  1555. #ifndef NSIS_CONFIG_UNINSTALL_SUPPORT
  1556.   if (type == PAGE_COMPONENTS)
  1557.   {
  1558.     ERROR_MSG("Error: can't add uninstConfirm page, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n");
  1559.     return PS_ERROR;
  1560.   }
  1561. #endif
  1562.  
  1563.   struct {
  1564.     int wndproc_id;
  1565.     int dlg_id;
  1566.   } ids[] = {
  1567.     {PWP_CUSTOM, 0}, // custom
  1568. #ifdef NSIS_CONFIG_LICENSEPAGE
  1569.     {PWP_LICENSE, IDD_LICENSE}, // license
  1570. #else
  1571.     {0, IDD_LICENSE}, // license
  1572. #endif
  1573. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1574.     {PWP_SELCOM, IDD_SELCOM}, // components
  1575. #else
  1576.     {0, IDD_SELCOM}, // components
  1577. #endif
  1578.     {PWP_DIR, IDD_DIR}, // directory
  1579.     {PWP_INSTFILES, IDD_INSTFILES}, // instfiles
  1580. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1581.     {PWP_UNINST, IDD_UNINST}, // uninstConfirm
  1582. #else
  1583.     {0, IDD_UNINST}, // uninstConfirm
  1584. #endif
  1585.     {PWP_COMPLETED, -1} // completed
  1586.   };
  1587.  
  1588.   pg.wndproc_id = ids[type].wndproc_id;
  1589.   pg.dlg_id = ids[type].dlg_id;
  1590.  
  1591.   cur_pages->add(&pg,sizeof(page));
  1592.  
  1593.   cur_page = (page *)cur_pages->get() + cur_header->blocks[NB_PAGES].num++;
  1594.  
  1595.   cur_page_type = type;
  1596.  
  1597.   return PS_OK;
  1598. }
  1599.  
  1600. int CEXEBuild::page_end()
  1601. {
  1602.   cur_page = 0;
  1603.  
  1604.   return PS_OK;
  1605. }
  1606. #endif
  1607.  
  1608. #ifdef NSIS_SUPPORT_VERSION_INFO
  1609. int CEXEBuild::AddVersionInfo()
  1610. {
  1611.   GrowBuf VerInfoStream;
  1612.   bool bNeedVInfo = false;
  1613.  
  1614.   if ( rVersionInfo.GetStringTablesCount() > 0 )
  1615.   {
  1616.     if ( !version_product_v[0] )
  1617.     {
  1618.       ERROR_MSG("Error: VIProductVersion is required when other version information functions are used.\n");
  1619.       return PS_ERROR;
  1620.     }
  1621.     else
  1622.     {
  1623.       int imm, iml, ilm, ill;
  1624.       if ( sscanf(version_product_v, "%d.%d.%d.%d", &imm, &iml, &ilm, &ill) != 4 )
  1625.       { 
  1626.         ERROR_MSG("Error: invalid VIProductVersion format, should be X.X.X.X\n");
  1627.         return PS_ERROR;
  1628.       }
  1629.       rVersionInfo.SetFileVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm));
  1630.       rVersionInfo.SetProductVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm));
  1631.  
  1632.       init_res_editor();
  1633.       for ( int i = 0; i < rVersionInfo.GetStringTablesCount(); i++ )
  1634.       {
  1635.         LANGID lang_id = rVersionInfo.GetLangID(i);
  1636.         int code_page = rVersionInfo.GetCodePage(i);
  1637.         LanguageTable *Table = GetLangTable(lang_id);
  1638.  
  1639.         if ( !rVersionInfo.FindKey(lang_id, code_page, "FileVersion") )
  1640.           warning("Generating version information for language \"%04d-%s\" without standard key \"FileVersion\"", lang_id, Table->nlf.m_bLoaded ? Table->nlf.m_szName : lang_id == 1033 ? "English" : "???");
  1641.         if ( !rVersionInfo.FindKey(lang_id, code_page, "FileDescription") )
  1642.           warning("Generating version information for language \"%04d-%s\" without standard key \"FileDescription\"", lang_id, Table->nlf.m_bLoaded ? Table->nlf.m_szName : lang_id == 1033 ? "English" : "???");
  1643.         if ( !rVersionInfo.FindKey(lang_id, code_page, "LegalCopyright") )
  1644.           warning("Generating version information for language \"%04d-%s\" without standard key \"LegalCopyright\"", lang_id, Table->nlf.m_bLoaded ? Table->nlf.m_szName : lang_id == 1033 ? "English" : "???");
  1645.  
  1646.         rVersionInfo.ExportToStream(VerInfoStream, i);
  1647.         res_editor->UpdateResource(RT_VERSION, 1, lang_id, (BYTE*)VerInfoStream.get(), VerInfoStream.getlen());
  1648.       }
  1649.     }
  1650.   }
  1651.   
  1652.   return PS_OK;
  1653. }
  1654. #endif // NSIS_SUPPORT_VERSION_INFO
  1655.  
  1656. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  1657. int CEXEBuild::ProcessPages()
  1658. {
  1659.   SCRIPT_MSG("Processing pages... ");
  1660.  
  1661.   int license_normal=0;
  1662.   int license_fsrb=0;
  1663.   int license_fscb=0;
  1664.   int selcom=0;
  1665.   int dir=0, dir_used;
  1666.   int uninstconfirm=0;
  1667.   int instlog=0, instlog_used;
  1668.   int main=0;
  1669.  
  1670. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1671. again:
  1672. #endif
  1673.  
  1674.   dir_used = 0;
  1675.   instlog_used = 0;
  1676.  
  1677. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  1678.   if ((cur_header->flags & (CH_FLAGS_SILENT|CH_FLAGS_SILENT_LOG)) == 0)
  1679. #endif
  1680.   {
  1681.     main++;
  1682.  
  1683. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1684. #define LS(inst, uninst) (uninstall_mode ? uninst : inst)
  1685. #else
  1686. #define LS(inst, uninst) inst
  1687. #endif
  1688.  
  1689.     DefineInnerLangString(NLF_BRANDING);
  1690.  
  1691.     if (!cur_pages->getlen()) {
  1692. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1693.       if (uninstall_mode) {
  1694.         if (HasUserDefined(NLF_UNINST_TEXT)) {
  1695.           add_page(PAGE_UNINSTCONFIRM);
  1696.           page_end();
  1697.         }
  1698.         add_page(PAGE_INSTFILES);
  1699.         page_end();
  1700.         add_page(PAGE_COMPLETED);
  1701.         page_end();
  1702.       }
  1703.       else
  1704. #endif
  1705.       {
  1706. #ifdef NSIS_CONFIG_LICENSEPAGE
  1707.         if (HasUserDefined(NLF_LICENSE_TEXT) && HasUserDefined(NLF_LICENSE_DATA)) {
  1708.           add_page(PAGE_LICENSE);
  1709.           page_end();
  1710.         }
  1711. #endif
  1712. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1713.         if (HasUserDefined(NLF_COMP_TEXT)) {
  1714.           add_page(PAGE_COMPONENTS);
  1715.           page_end();
  1716.         }
  1717. #endif
  1718.         if (HasUserDefined(NLF_DIR_TEXT)) {
  1719.           add_page(PAGE_DIRECTORY);
  1720.           page_end();
  1721.         }
  1722.         add_page(PAGE_INSTFILES);
  1723.         page_end();
  1724.         add_page(PAGE_COMPLETED);
  1725.         page_end();
  1726.       }
  1727.     }
  1728.     // start processing the pages
  1729.     {
  1730.       int i = 0;
  1731.       page *p = (page *) cur_pages->get();
  1732.       
  1733.       for (i = 0; i < cur_header->blocks[NB_PAGES].num; i++, p++) {
  1734.         page *pp = 0;
  1735.  
  1736.         if (i) {
  1737.           pp = p - 1;
  1738.  
  1739.           // set back button
  1740.           p->flags |= PF_BACK_SHOW;
  1741.           if (pp->wndproc_id != PWP_COMPLETED && p->wndproc_id != PWP_COMPLETED && p->wndproc_id != PWP_INSTFILES)
  1742.             p->flags |= PF_BACK_ENABLE;
  1743.           if (!p->back)
  1744.             p->back = DefineInnerLangString(NLF_BTN_BACK);
  1745.  
  1746.           // set previous page's next button
  1747.           if (!pp->next) {
  1748.             int str = 0;
  1749.  
  1750. #ifdef NSIS_CONFIG_LICENSEPAGE
  1751.             if (pp->wndproc_id == PWP_LICENSE && (!(pp->flags & PF_LICENSE_FORCE_SELECTION) || HasUserDefined(NLF_BTN_LICENSE)))
  1752.               str = NLF_BTN_LICENSE;
  1753.             else
  1754. #endif
  1755.             if (p->wndproc_id == PWP_INSTFILES)
  1756.               str = LS(NLF_BTN_INSTALL, NLF_BTN_UNINSTALL);
  1757.             else
  1758.               str = NLF_BTN_NEXT;
  1759.  
  1760.             pp->next = DefineInnerLangString(str);
  1761.           }
  1762.  
  1763.           // set previous page's click next text
  1764.           if (!pp->clicknext) {
  1765.             int str = 0;
  1766.  
  1767.             if (p->wndproc_id == PWP_INSTFILES)
  1768.               str = LS(NLF_CLICK_INSTALL, NLF_CLICK_UNINSTALL);
  1769.             else
  1770.               str = NLF_CLICK_NEXT;
  1771.  
  1772.             pp->clicknext = DefineInnerLangString(str);
  1773.           }
  1774.         }
  1775.  
  1776.         // enable next button
  1777.         if (p->wndproc_id != PWP_INSTFILES)
  1778.           p->flags |= PF_NEXT_ENABLE;
  1779.  
  1780.         // set cancel button
  1781.         if (!p->cancel)
  1782.           p->cancel = DefineInnerLangString(NLF_BTN_CANCEL);
  1783.         if (p->wndproc_id != PWP_INSTFILES && p->wndproc_id != PWP_COMPLETED)
  1784.           p->flags |= PF_CANCEL_ENABLE;
  1785.  
  1786.         // set caption
  1787.         struct {
  1788.           int caption;
  1789.           int ucaption;
  1790.         } captions[] = {
  1791. #ifdef NSIS_CONFIG_LICENSEPAGE
  1792.           {NLF_SUBCAPTION_LICENSE, NLF_SUBCAPTION_LICENSE},
  1793. #endif
  1794. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1795.           {NLF_SUBCAPTION_OPTIONS, NLF_SUBCAPTION_OPTIONS},
  1796. #endif
  1797.           {NLF_SUBCAPTION_DIR, NLF_SUBCAPTION_DIR},
  1798.           {NLF_SUBCAPTION_INSTFILES, NLF_USUBCAPTION_INSTFILES},
  1799. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1800.           {NLF_USUBCAPTION_CONFIRM, NLF_USUBCAPTION_CONFIRM},
  1801. #endif
  1802.           {NLF_SUBCAPTION_COMPLETED, NLF_USUBCAPTION_COMPLETED}
  1803.         };
  1804.  
  1805.         if (!p->caption && p->wndproc_id != PWP_CUSTOM) {
  1806.           p->caption = DefineInnerLangString(LS(captions[p->wndproc_id].caption, captions[p->wndproc_id].ucaption));
  1807.         }
  1808.  
  1809.         // set texts
  1810.         switch (p->dlg_id) {
  1811. #ifdef NSIS_CONFIG_LICENSEPAGE
  1812.           case IDD_LICENSE:
  1813.           case IDD_LICENSE_FSRB:
  1814.           case IDD_LICENSE_FSCB:
  1815.           {
  1816.             if (!(p->flags & PF_PAGE_EX))
  1817.               p->dlg_id = license_res_id;
  1818.             if (!(p->flags & (PF_LICENSE_FORCE_SELECTION | PF_LICENSE_NO_FORCE_SELECTION)))
  1819.               p->dlg_id = license_res_id;
  1820.  
  1821.             p->flags |= PF_NO_NEXT_FOCUS;
  1822.  
  1823.             if (!p->parms[1])
  1824.               p->parms[1] = DefineInnerLangString(NLF_LICENSE_DATA, 0);
  1825.  
  1826.             if (p->dlg_id == IDD_LICENSE) {
  1827.               if (!p->parms[0])
  1828.                 p->parms[0] = DefineInnerLangString(LS(NLF_LICENSE_TEXT, NLF_ULICENSE_TEXT));
  1829.  
  1830.               license_normal++;
  1831.             }
  1832.             else if (p->dlg_id == IDD_LICENSE_FSCB) {
  1833.               p->flags |= PF_LICENSE_FORCE_SELECTION;
  1834.  
  1835.               if (!p->parms[0])
  1836.                 p->parms[0] = DefineInnerLangString(LS(NLF_LICENSE_TEXT_FSCB, NLF_ULICENSE_TEXT_FSCB));
  1837.               if (!p->parms[2])
  1838.                 p->parms[2] = DefineInnerLangString(NLF_BTN_LICENSE_AGREE);
  1839.  
  1840.               license_fscb++;
  1841.             }
  1842.             else if (p->dlg_id == IDD_LICENSE_FSRB) {
  1843.               p->flags |= PF_LICENSE_FORCE_SELECTION;
  1844.  
  1845.               if (!p->parms[0])
  1846.                 p->parms[0] = DefineInnerLangString(LS(NLF_LICENSE_TEXT_FSRB, NLF_ULICENSE_TEXT_FSRB));
  1847.               if (!p->parms[2])
  1848.                 p->parms[2] = DefineInnerLangString(NLF_BTN_LICENSE_AGREE);
  1849.               if (!p->parms[3])
  1850.                 p->parms[3] = DefineInnerLangString(NLF_BTN_LICENSE_DISAGREE);
  1851.  
  1852.               license_fsrb++;
  1853.             }
  1854.             break;
  1855.           }
  1856. #endif
  1857. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1858.           case IDD_SELCOM:
  1859.           {
  1860.             if (!p->parms[0])
  1861.               p->parms[0] = DefineInnerLangString(LS(NLF_COMP_TEXT, NLF_UCOMP_TEXT));
  1862.             if (!p->parms[1])
  1863.               p->parms[1] = DefineInnerLangString(LS(NLF_COMP_SUBTEXT1, NLF_UCOMP_SUBTEXT1));
  1864.             if (!p->parms[2])
  1865.               p->parms[2] = DefineInnerLangString(LS(NLF_COMP_SUBTEXT2, NLF_UCOMP_SUBTEXT2));
  1866.             if (!p->parms[3] && !uninstall_mode && HasUserDefined(NLF_COMP_SUBTEXT1))
  1867.               p->parms[3] = p->parms[1];
  1868.             if (!p->parms[4] && !uninstall_mode && HasUserDefined(NLF_COMP_SUBTEXT2))
  1869.               p->parms[4] = p->parms[2];
  1870.             else if (!p->parms[4])
  1871.               p->parms[4] = DefineInnerLangString(LS(NLF_COMP_SUBTEXT1_NO_INST_TYPES, NLF_UCOMP_SUBTEXT1_NO_INST_TYPES));
  1872.  
  1873.             DefineInnerLangString(NLF_SPACE_REQ);
  1874.             DefineInnerLangString(NLF_BYTE);
  1875.             DefineInnerLangString(NLF_KILO);
  1876.             DefineInnerLangString(NLF_MEGA);
  1877.             DefineInnerLangString(NLF_GIGA);
  1878.  
  1879.             selcom++;
  1880.             break;
  1881.           }
  1882. #endif
  1883.           case IDD_DIR:
  1884.           {
  1885.             if (!p->parms[0])
  1886.               p->parms[0] = DefineInnerLangString(LS(NLF_DIR_TEXT, NLF_UDIR_TEXT));
  1887.             if (!p->parms[1])
  1888.               p->parms[1] = DefineInnerLangString(LS(NLF_DIR_SUBTEXT, NLF_UDIR_SUBTEXT));
  1889.             if (!p->parms[2])
  1890.               p->parms[2] = DefineInnerLangString(NLF_BTN_BROWSE);
  1891.             if (!p->parms[3])
  1892.               p->parms[3] = DefineInnerLangString(LS(NLF_DIR_BROWSETEXT, NLF_UDIR_BROWSETEXT));
  1893.             if (!p->parms[4])
  1894.               p->parms[4] = m_UserVarNames.get("INSTDIR");
  1895.             else
  1896.               p->parms[4]--;
  1897.  
  1898.             DefineInnerLangString(NLF_SPACE_AVAIL);
  1899.             DefineInnerLangString(NLF_SPACE_REQ);
  1900.             DefineInnerLangString(NLF_BYTE);
  1901.             DefineInnerLangString(NLF_KILO);
  1902.             DefineInnerLangString(NLF_MEGA);
  1903.             DefineInnerLangString(NLF_GIGA);
  1904. #ifdef NSIS_CONFIG_LOG
  1905.             DefineInnerLangString(NLF_LOG_INSTALL_PROCESS);
  1906. #endif
  1907.  
  1908.             dir++;
  1909.             break;
  1910.           }
  1911.           case IDD_INSTFILES:
  1912.           {
  1913.             if (!p->parms[1])
  1914.               p->parms[1] = DefineInnerLangString(NLF_BTN_DETAILS);
  1915.             if (!p->parms[2])
  1916.               p->parms[2] = DefineInnerLangString(NLF_COMPLETED);
  1917.  
  1918.             DefineInnerLangString(NLF_COPY_DETAILS);
  1919.  
  1920.             instlog++;
  1921.             instlog_used++;
  1922.             break;
  1923.           }
  1924.           case IDD_UNINST:
  1925.           {
  1926.             if (!p->parms[0])
  1927.               p->parms[0] = DefineInnerLangString(NLF_UNINST_TEXT);
  1928.             if (!p->parms[1])
  1929.               p->parms[1] = DefineInnerLangString(NLF_UNINST_SUBTEXT);
  1930.             if (!p->parms[4])
  1931.               p->parms[4] = m_UserVarNames.get("INSTDIR");
  1932.             else
  1933.               p->parms[4]--;
  1934.  
  1935.             uninstconfirm++;
  1936.             break;
  1937.           }
  1938.         }
  1939.  
  1940.         p->flags &= ~PF_PAGE_EX;
  1941.       }
  1942.  
  1943.       p--;
  1944.  
  1945.       if (!p->next)
  1946.         p->next = DefineInnerLangString(NLF_BTN_CLOSE);
  1947.       if (p->wndproc_id == PWP_COMPLETED)
  1948.         (p-1)->next = DefineInnerLangString(NLF_BTN_CLOSE);
  1949.  
  1950. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1951.       if (uninstall_mode) {
  1952.         if (!uenable_last_page_cancel && instlog_used)
  1953.           p->flags &= ~PF_CANCEL_ENABLE;
  1954.       }
  1955.       else
  1956. #endif
  1957.       {
  1958.         if (!enable_last_page_cancel && instlog_used)
  1959.           p->flags &= ~PF_CANCEL_ENABLE;
  1960.       }
  1961.  
  1962.       if (!instlog_used) {
  1963.         warning("%sage instfiles not used, no sections will be executed!", uninstall_mode ? "Uninstall p" : "P");
  1964.       }
  1965.     }
  1966.   }
  1967.  
  1968. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1969.     if (!uninstall_mode) {
  1970.       set_uninstall_mode(1);
  1971.       goto again;
  1972.     }
  1973.     else
  1974.       set_uninstall_mode(0);
  1975. #endif//NSIS_CONFIG_UNINSTALL_SUPPORT
  1976.  
  1977.  
  1978.   SCRIPT_MSG("Done!\n");
  1979.  
  1980. #define REMOVE_ICON(id) if (disable_window_icon) { \
  1981.     BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); \
  1982.     if (dlg) { \
  1983.       CDialogTemplate dt(dlg,uDefCodePage); \
  1984.       free(dlg); \
  1985.       if (dt.RemoveItem(IDC_ULICON)) { \
  1986.         DialogItemTemplate* text = dt.GetItem(IDC_INTROTEXT); \
  1987.         DialogItemTemplate* prog = dt.GetItem(IDC_PROGRESS); \
  1988.         if (text) { \
  1989.           text->sWidth += text->sX; \
  1990.           text->sX = 0; \
  1991.         } \
  1992.         if (prog) { \
  1993.           prog->sWidth += prog->sX; \
  1994.           prog->sX = 0; \
  1995.         } \
  1996.          \
  1997.         DWORD dwSize; \
  1998.         dlg = dt.Save(dwSize); \
  1999.         res_editor->UpdateResource(RT_DIALOG, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize); \
  2000.       } \
  2001.       res_editor->FreeResource(dlg); \
  2002.     } \
  2003.   }
  2004.  
  2005.   try {
  2006.     SCRIPT_MSG("Removing unused resources... ");
  2007.     init_res_editor();
  2008. #ifdef NSIS_CONFIG_LICENSEPAGE
  2009.     if (!license_normal) {
  2010.       res_editor->UpdateResource(RT_DIALOG, IDD_LICENSE, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2011.     }
  2012.     else REMOVE_ICON(IDD_LICENSE);
  2013.     if (!license_fsrb) {
  2014.       res_editor->UpdateResource(RT_DIALOG, IDD_LICENSE_FSRB, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2015.     }
  2016.     else REMOVE_ICON(IDD_LICENSE_FSRB);
  2017.     if (!license_fscb) {
  2018.       res_editor->UpdateResource(RT_DIALOG, IDD_LICENSE_FSCB, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2019.     }
  2020.     else REMOVE_ICON(IDD_LICENSE_FSCB);
  2021. #endif // NSIS_CONFIG_LICENSEPAGE
  2022. #ifdef NSIS_CONFIG_COMPONENTPAGE
  2023.     if (!selcom) {
  2024.       res_editor->UpdateResource(RT_DIALOG, IDD_SELCOM, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2025.       res_editor->UpdateResource(RT_BITMAP, IDB_BITMAP1, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2026.     }
  2027.     else REMOVE_ICON(IDD_SELCOM);
  2028. #endif // NSIS_CONFIG_COMPONENTPAGE
  2029.     if (!dir) {
  2030.       res_editor->UpdateResource(RT_DIALOG, IDD_DIR, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2031.     }
  2032.     else REMOVE_ICON(IDD_DIR);
  2033. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  2034.     if (!uninstconfirm) {
  2035.       res_editor->UpdateResource(RT_DIALOG, IDD_UNINST, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2036.     }
  2037.     else REMOVE_ICON(IDD_UNINST);
  2038. #endif // NSIS_CONFIG_UNINSTALL_SUPPORT
  2039.     if (!instlog) {
  2040.       res_editor->UpdateResource(RT_DIALOG, IDD_INSTFILES, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2041.     }
  2042.     else REMOVE_ICON(IDD_INSTFILES);
  2043.     if (!main) {
  2044.       res_editor->UpdateResource(RT_DIALOG, IDD_INST, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2045.       if (!build_compress_whole && !build_crcchk)
  2046.         res_editor->UpdateResource(RT_DIALOG, IDD_VERIFY, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0);
  2047.     }
  2048.  
  2049.     SCRIPT_MSG("Done!\n");
  2050.   }
  2051.   catch (exception& err) {
  2052.     ERROR_MSG("\nError: %s\n", err.what());
  2053.     return PS_ERROR;
  2054.   }
  2055.  
  2056.   return PS_OK;
  2057. }
  2058. #endif // NSIS_CONFIG_VISIBLE_SUPPORT
  2059.  
  2060. #ifdef NSIS_CONFIG_COMPONENTPAGE
  2061. void CEXEBuild::PreperInstTypes()
  2062. {
  2063.   if (!(cur_header->flags & CH_FLAGS_NO_CUSTOM))
  2064.     cur_header->install_types[NSIS_MAX_INST_TYPES] = DefineInnerLangString(NLF_COMP_CUSTOM);
  2065.  
  2066.   // set insttype list for RO sections that didn't use SectionIn
  2067.   int i = cur_header->blocks[NB_SECTIONS].num;
  2068.   section *sections = (section *) cur_sections->get();
  2069.  
  2070.   while (i--)
  2071.   {
  2072.     if (sections[i].flags & SF_RO && !sections[i].install_types)
  2073.       sections[i].install_types = ~0;
  2074.   }
  2075.  
  2076.   // set selection to first insttype
  2077.   if (cur_header->install_types[0])
  2078.   {
  2079.     int i = cur_header->blocks[NB_SECTIONS].num;
  2080.     section *sections = (section *) cur_sections->get();
  2081.  
  2082.     // if /o was used abort since the user did his manual choice
  2083.     while (i--)
  2084.       if ((sections[i].flags & SF_SELECTED) == 0)
  2085.         return;
  2086.  
  2087.     i = cur_header->blocks[NB_SECTIONS].num;
  2088.  
  2089.     while (i--)
  2090.       if ((sections[i].install_types & 1) == 0)
  2091.         sections[i].flags &= ~SF_SELECTED;
  2092.   }
  2093. }
  2094. #endif
  2095.  
  2096. void CEXEBuild::PreperHeaders(IGrowBuf *hdrbuf)
  2097. {
  2098.   hdrbuf->add(cur_header,sizeof(header));
  2099. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  2100.   cur_header->blocks[NB_PAGES].offset = hdrbuf->getlen();
  2101.   hdrbuf->add(cur_pages->get(),cur_pages->getlen());
  2102. #endif
  2103.   cur_header->blocks[NB_SECTIONS].offset = hdrbuf->getlen();
  2104.   hdrbuf->add(cur_sections->get(),cur_sections->getlen());
  2105.   cur_header->blocks[NB_ENTRIES].offset = hdrbuf->getlen();
  2106.   hdrbuf->add(cur_entries->get(),cur_entries->getlen());
  2107.   cur_header->blocks[NB_STRINGS].offset = hdrbuf->getlen();
  2108.   hdrbuf->add(cur_strlist->get(),cur_strlist->getlen());
  2109.   cur_header->blocks[NB_LANGTABLES].offset = hdrbuf->getlen();
  2110.   hdrbuf->add(cur_langtables->get(),cur_langtables->getlen());
  2111.   cur_header->blocks[NB_CTLCOLORS].offset = hdrbuf->getlen();
  2112.   hdrbuf->add(cur_ctlcolors->get(),cur_ctlcolors->getlen());
  2113.  
  2114.   memcpy(hdrbuf->get(),cur_header,sizeof(header));
  2115. }
  2116.  
  2117. int CEXEBuild::write_output(void)
  2118. {
  2119. #ifndef NSIS_CONFIG_CRC_SUPPORT
  2120.   build_crcchk=0;
  2121. #endif
  2122.   if (has_called_write_output)
  2123.   {
  2124.     ERROR_MSG("Error (write_output): write_output already called, can't continue\n");
  2125.     return PS_ERROR;
  2126.   }
  2127.   has_called_write_output++;
  2128.   if (!build_output_filename[0])
  2129.   {
  2130.     ERROR_MSG("Error: invalid script: never had OutFile command\n");
  2131.     return PS_ERROR;
  2132.   }
  2133.  
  2134.   {
  2135.     int ns=build_sections.getlen()/sizeof(section);
  2136.     if (!ns)
  2137.     {
  2138.       ERROR_MSG("Error: invalid script: no sections specified\n");
  2139.       return PS_ERROR;
  2140.     }
  2141.   }
  2142.  
  2143.   if (!build_entries.getlen())
  2144.   {
  2145.     ERROR_MSG("Error: invalid script: no entries specified\n");
  2146.     return PS_ERROR;
  2147.   }
  2148.  
  2149.   if (build_cursection)
  2150.   {
  2151.     ERROR_MSG("Error: Section left open at EOF\n");
  2152.     return PS_ERROR;
  2153.   }
  2154.  
  2155.   if (subsection_open_cnt)
  2156.   {
  2157.     ERROR_MSG("Error: SubSection left open at EOF\n");
  2158.     return PS_ERROR;
  2159.   }
  2160.  
  2161.   if (cur_page)
  2162.   {
  2163.     ERROR_MSG("Error: PageEx still open at EOF, cannot proceed\n");
  2164.     return 1;
  2165.   }
  2166.  
  2167.   // deal with functions, for both install and uninstall modes.
  2168.   if (build_cursection_isfunc)
  2169.   {
  2170.     ERROR_MSG("Error: Function still open at EOF, cannot proceed\n");
  2171.     return 1;
  2172.   }
  2173.  
  2174.   int err;
  2175.  
  2176. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  2177.   err = add_plugins_dir_initializer();
  2178.   if (err != PS_OK)
  2179.     return err;
  2180. #endif //NSIS_CONFIG_PLUGIN_SUPPORT
  2181.  
  2182. #ifdef NSIS_SUPPORT_VERSION_INFO
  2183.   err = AddVersionInfo();
  2184.   if (err != PS_OK)
  2185.     return err;
  2186. #endif //NSIS_SUPPORT_VERSION_INFO
  2187.  
  2188. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  2189.   if (ubuild_entries.getlen())
  2190.   {
  2191.     if (!uninstaller_writes_used)
  2192.     {
  2193.       warning("Uninstall section found but WriteUninstaller never used - no uninstaller will be created.");
  2194.     }
  2195.     else
  2196.     {
  2197.       build_uninst.flags|=build_header.flags&(CH_FLAGS_PROGRESS_COLORED|CH_FLAGS_NO_ROOT_DIR);
  2198.  
  2199.       set_uninstall_mode(1);
  2200.       DefineInnerLangString(NLF_UCAPTION);
  2201.       if (resolve_coderefs("uninstall"))
  2202.         return PS_ERROR;
  2203. #ifdef NSIS_CONFIG_COMPONENTPAGE 
  2204.       // set sections to the first insttype
  2205.       PreperInstTypes();
  2206. #endif
  2207.       set_uninstall_mode(0);
  2208.     }
  2209.   }
  2210.   else if (uninstaller_writes_used)
  2211.   {
  2212.     ERROR_MSG("Error: no Uninstall section specified, but WriteUninstaller used %d time(s)\n",uninstaller_writes_used);
  2213.     return PS_ERROR;
  2214.   }
  2215. #endif
  2216.  
  2217.   DefineInnerLangString(NLF_CAPTION);
  2218.   if (resolve_coderefs("install"))
  2219.     return PS_ERROR;
  2220.  
  2221. #ifdef NSIS_CONFIG_COMPONENTPAGE
  2222.   // set sections to the first insttype
  2223.   PreperInstTypes();
  2224. #endif
  2225.  
  2226. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  2227.   err = ProcessPages();
  2228.   if (err != PS_OK)
  2229.     return err;
  2230. #endif //NSIS_CONFIG_VISIBLE_SUPPORT
  2231.  
  2232.   // Generate language tables
  2233.   err = GenerateLangTables();
  2234.   if (err != PS_OK)
  2235.     return err;
  2236.  
  2237.   init_res_editor();
  2238.   VerifyDeclaredUserVarRefs(&m_UserVarNames);
  2239.   int MaxUserVars = m_UserVarNames.getnum();
  2240.   // -1 because the default size is 1
  2241.   if (!res_editor->AddExtraVirtualSize2PESection(VARS_SECTION_NAME, (MaxUserVars - 1) * sizeof(NSIS_STRING)))
  2242.   {
  2243.     ERROR_MSG("Internal compiler error #12346: invalid exehead cannot find section \"%s\"!\n", VARS_SECTION_NAME);
  2244.     return PS_ERROR;
  2245.   }
  2246.  
  2247.   // Save all changes to the exe header
  2248.   try {
  2249.     close_res_editor();
  2250.   }
  2251.   catch (exception& err) {
  2252.     ERROR_MSG("\nError: %s\n", err.what());
  2253.     return PS_ERROR;
  2254.   }
  2255.  
  2256.   // Pack exe header if asked for
  2257.   if (build_packname[0] && build_packcmd[0])
  2258.   {
  2259.     FILE *tmpfile=fopen(build_packname,"wb");
  2260.     if (!tmpfile)
  2261.     {
  2262.       ERROR_MSG("Error: writing temporary file \"%s\" for pack\n",build_packname);
  2263.       return PS_ERROR;
  2264.     }
  2265.     fwrite(header_data_new,1,exeheader_size_new,tmpfile);
  2266.     fclose(tmpfile);
  2267.     if (system(build_packcmd) == -1)
  2268.     {
  2269.       remove(build_packname);
  2270.       ERROR_MSG("Error: calling packer on \"%s\"\n",build_packname);
  2271.       return PS_ERROR;
  2272.     }
  2273.     tmpfile=fopen(build_packname,"rb");
  2274.     if (!tmpfile)
  2275.     {
  2276.       remove(build_packname);
  2277.       ERROR_MSG("Error: reading temporary file \"%s\" after pack\n",build_packname);
  2278.       return PS_ERROR;
  2279.     }
  2280.     fseek(tmpfile,0,SEEK_END);
  2281.     exeheader_size_new=ftell(tmpfile);
  2282.     fseek(tmpfile,0,SEEK_SET);
  2283.     unsigned char *header_data_older=header_data_new;
  2284.     header_data_new=(unsigned char *)malloc(exeheader_size_new);
  2285.     if (!header_data_new)
  2286.     {
  2287.       free(header_data_older);
  2288.       fclose(tmpfile);
  2289.       ERROR_MSG("Error: malloc(%d) failed (exepack)\n",exeheader_size_new);
  2290.       return PS_ERROR;
  2291.     }
  2292.     memset(header_data_new,0,exeheader_size_new);
  2293.     fread(header_data_new,1,exeheader_size_new,tmpfile);
  2294.     fclose(tmpfile);
  2295.     remove(build_packname);
  2296.  
  2297.     // write out exe header, pack, read back in, align to 512, and
  2298.     // update the header info
  2299.   }
  2300.  
  2301.   build_optimize_datablock=0;
  2302.  
  2303.   int data_block_size_before_uninst = build_datablock.getlen();
  2304.  
  2305.   if (uninstall_generate() != PS_OK)
  2306.   {
  2307.     return PS_ERROR;
  2308.   }
  2309.  
  2310.   int crc=0;
  2311.  
  2312.   {
  2313.     char buffer[1024],*p;
  2314.     GetFullPathName(build_output_filename,1024,buffer,&p);
  2315.     notify(MAKENSIS_NOTIFY_OUTPUT, buffer);
  2316.     INFO_MSG("\nOutput: \"%s\"\n",buffer);
  2317.   }
  2318.   FILE *fp = fopen(build_output_filename,"w+b");
  2319.   if (!fp)
  2320.   {
  2321.     ERROR_MSG("Can't open output file\n");
  2322.     return PS_ERROR;
  2323.   }
  2324.  
  2325.   if ((int)fwrite(header_data_new,1,exeheader_size_new,fp) != exeheader_size_new)
  2326.   {
  2327.     ERROR_MSG("Error: can't write %d bytes to output\n",exeheader_size_new);
  2328.     fclose(fp);
  2329.     return PS_ERROR;
  2330.   }
  2331.  
  2332. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2333.   #ifdef NSIS_CONFIG_CRC_ANAL
  2334.     crc=CRC32(crc,header_data_new,exeheader_size_new);
  2335.   #else
  2336.     crc=CRC32(crc,header_data_new+512,exeheader_size_new-512);
  2337.   #endif
  2338. #endif
  2339.  
  2340.   int exeheader_size_new_aligned = (exeheader_size_new + 511) & ~511;
  2341.   if (exeheader_size_new_aligned != exeheader_size_new) {
  2342.     // align to 512
  2343.     const unsigned char z = 0;
  2344.     int write_size = exeheader_size_new_aligned - exeheader_size_new;
  2345.     for (int i=0; i<write_size; i++) {
  2346.       if ((int)fwrite(&z,1,1,fp) != 1)
  2347.       {
  2348.         ERROR_MSG("Error: can't write %d bytes to output\n",write_size);
  2349.         fclose(fp);
  2350.         return PS_ERROR;
  2351.       }
  2352. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2353.       crc=CRC32(crc,&z,1);
  2354. #endif
  2355.     }
  2356.     exeheader_size_new = exeheader_size_new_aligned;
  2357.   }
  2358.  
  2359.   firstheader fh={0,};
  2360.   fh.nsinst[0]=FH_INT1;
  2361.   fh.nsinst[1]=FH_INT2;
  2362.   fh.nsinst[2]=FH_INT3;
  2363.  
  2364. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2365.   fh.flags=(build_crcchk?(build_crcchk==2?FH_FLAGS_FORCE_CRC:0):FH_FLAGS_NO_CRC);
  2366. #else
  2367.   fh.flags=0;
  2368. #endif
  2369. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  2370.   if (build_header.flags&(CH_FLAGS_SILENT|CH_FLAGS_SILENT_LOG)) fh.flags |= FH_FLAGS_SILENT;
  2371. #endif
  2372.   fh.siginfo=FH_SIG;
  2373.  
  2374.   int installinfo_compressed;
  2375.   int fd_start;
  2376.  
  2377. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2378.   if (build_compress_whole)
  2379.   {
  2380.       int n;
  2381.     if (compressor == &lzma_compressor)
  2382.       n = ((CLZMA *) compressor)->Init(build_compress_level, build_compress_dict_size);
  2383.     else
  2384.       n = compressor->Init(build_compress_level);
  2385.     if (n != C_OK)
  2386.     {
  2387.       ERROR_MSG("Internal compiler error #12345: deflateInit() failed(%d).\n", n);
  2388.       return PS_ERROR;
  2389.     }
  2390.   }
  2391. #endif
  2392.  
  2393.   {
  2394.     GrowBuf ihd;
  2395.     {
  2396.       GrowBuf hdrcomp;
  2397.  
  2398.       PreperHeaders(&hdrcomp);
  2399.  
  2400.       if (add_data((char*)hdrcomp.get(),hdrcomp.getlen(),&ihd) < 0)
  2401.         return PS_ERROR;
  2402.  
  2403.       fh.length_of_header=hdrcomp.getlen();
  2404.       installinfo_compressed=ihd.getlen();
  2405.     }
  2406.  
  2407.     if (!build_compress_whole)
  2408.       fh.length_of_all_following_data=ihd.getlen()+build_datablock.getlen()+(int)sizeof(firstheader)+(build_crcchk?sizeof(int):0);
  2409.     else
  2410.       fd_start=ftell(fp);
  2411.  
  2412.     if (fwrite(&fh,1,sizeof(fh),fp) != sizeof(fh))
  2413.     {
  2414.       ERROR_MSG("Error: can't write %d bytes to output\n",sizeof(fh));
  2415.       fclose(fp);
  2416.       return PS_ERROR;
  2417.     }
  2418.  
  2419. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2420.     if (build_compress_whole) {
  2421.       if (deflateToFile(fp,(char*)ihd.get(),ihd.getlen()))
  2422.       {
  2423.         fclose(fp);
  2424.         return PS_ERROR;
  2425.       }
  2426.     }
  2427.     else 
  2428. #endif
  2429.     {
  2430.       if (fwrite(ihd.get(),1,ihd.getlen(),fp) != (unsigned int)ihd.getlen())
  2431.       {
  2432.         ERROR_MSG("Error: can't write %d bytes to output\n",ihd.getlen());
  2433.         fclose(fp);
  2434.         return PS_ERROR;
  2435.       }
  2436. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2437.       crc=CRC32(crc,(unsigned char*)&fh,sizeof(fh));
  2438.       crc=CRC32(crc,(unsigned char*)ihd.get(),ihd.getlen());
  2439. #endif
  2440.     }
  2441.   }
  2442.  
  2443.   INFO_MSG("Install: ");
  2444. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  2445.   int np=build_header.blocks[NB_PAGES].num;
  2446.   INFO_MSG("%d page%s (%d bytes), ",np,np==1?"":"s",np*sizeof(page));
  2447. #endif
  2448.   {
  2449.     int ns=build_sections.getlen()/sizeof(section);
  2450.     section *s=(section*)build_sections.get();
  2451.     int x;
  2452.     int req=0;
  2453.     for (x = 1; x < ns; x ++)
  2454.     {
  2455.       if (!s[x].name_ptr || s[x].flags & SF_RO) req++;
  2456.     }
  2457.     INFO_MSG("%d section%s",ns,ns==1?"":"s");
  2458.     if (req)
  2459.     {
  2460.       INFO_MSG(" (%d required)",req);
  2461.     }
  2462.     INFO_MSG(" (%d bytes), ", build_sections.getlen());
  2463.   }
  2464.   int ne=build_header.blocks[NB_ENTRIES].num;
  2465.   INFO_MSG("%d instruction%s (%d bytes), ",ne,ne==1?"":"s",ne*sizeof(entry));
  2466.   int ns=build_strlist.getnum();
  2467.   INFO_MSG("%d string%s (%d bytes), ",ns,ns==1?"":"s",build_strlist.getlen());
  2468.   int nlt=build_header.blocks[NB_LANGTABLES].num;
  2469.   INFO_MSG("%d language table%s (%d bytes).\n",nlt,nlt==1?"":"s",build_langtables.getlen());
  2470.   if (ubuild_entries.getlen())
  2471.   {
  2472.     INFO_MSG("Uninstall: ");
  2473. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  2474.     np=build_uninst.blocks[NB_PAGES].num;
  2475.     INFO_MSG("%d page%s (%d bytes), \n",np,np==1?"":"s",ubuild_pages.getlen());
  2476. #endif
  2477.     {
  2478.       int ns=ubuild_sections.getlen()/sizeof(section);
  2479.       section *s=(section*)ubuild_sections.get();
  2480.       int x;
  2481.       int req=0;
  2482.       for (x = 1; x < ns; x ++)
  2483.       {
  2484.         if (!s[x].name_ptr || s[x].flags & SF_RO) req++;
  2485.       }
  2486.       INFO_MSG("%d section%s",ns,ns==1?"":"s");
  2487.       if (req)
  2488.       {
  2489.         INFO_MSG(" (%d required)",req);
  2490.       }
  2491.       INFO_MSG(" (%d bytes), ", ubuild_sections.getlen());
  2492.     }
  2493.     ne=build_uninst.blocks[NB_ENTRIES].num;
  2494.     INFO_MSG("%d instruction%s (%d bytes), ",ne,ne==1?"":"s",ubuild_entries.getlen());
  2495.     ns=ubuild_strlist.getnum();
  2496.     INFO_MSG("%d string%s (%d bytes), ",ns,ns==1?"":"s",ubuild_strlist.getlen());
  2497.     nlt=build_uninst.blocks[NB_LANGTABLES].num;
  2498.     INFO_MSG("%d language table%s (%d bytes).\n",nlt,nlt==1?"":"s",ubuild_langtables.getlen());
  2499.   }
  2500.  
  2501.  
  2502.   if (db_opt_save)
  2503.   {
  2504.     int total_out_size_estimate=
  2505.       exeheader_size_new+sizeof(fh)+build_datablock.getlen()+(build_crcchk?sizeof(int):0);
  2506.     int pc=MulDiv(db_opt_save,1000,db_opt_save+total_out_size_estimate);
  2507.     INFO_MSG("Datablock optimizer saved %d bytes (~%d.%d%%).\n",db_opt_save,
  2508.       pc/10,pc%10);
  2509.   }
  2510.  
  2511. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2512.   INFO_MSG("\nUsing %s%s compression.\n\n", compressor->GetName(), build_compress_whole?" (compress whole)":"");
  2513. #endif
  2514.  
  2515.   int total_usize=exeheader_size;
  2516.  
  2517.   INFO_MSG("EXE header size:          %10d / %d bytes\n",exeheader_size_new,exeheader_size);
  2518.  
  2519.   if (build_compress_whole) {
  2520.     INFO_MSG("Install code:                          (%d bytes)\n",
  2521.       sizeof(fh)+fh.length_of_header);
  2522.   }
  2523.   else {
  2524.     INFO_MSG("Install code:             %10d / %d bytes\n",
  2525.       sizeof(fh)+installinfo_compressed,
  2526.       sizeof(fh)+fh.length_of_header);
  2527.   }
  2528.  
  2529.   total_usize+=sizeof(fh)+fh.length_of_header;
  2530.  
  2531.   {
  2532.     int dbsize, dbsizeu;
  2533.     dbsize = build_datablock.getlen();
  2534.     if (uninstall_size>0) dbsize-=uninstall_size;
  2535.  
  2536.     if (build_compress_whole) {
  2537.       dbsizeu=dbsize;
  2538.       INFO_MSG("Install data:                          (%d bytes)\n",dbsizeu);
  2539.     }
  2540.     else {
  2541.       dbsizeu = db_full_size - uninstall_size_full;
  2542.       INFO_MSG("Install data:             %10d / %d bytes\n",dbsize,dbsizeu);
  2543.     }
  2544.     total_usize+=dbsizeu;
  2545.   }
  2546.  
  2547.   if (uninstall_size>=0)
  2548.   {
  2549.     if (build_compress_whole)
  2550.       INFO_MSG("Uninstall code+data:                   (%d bytes)\n",uninstall_size_full);
  2551.     else
  2552.       INFO_MSG("Uninstall code+data:          %6d / %d bytes\n",uninstall_size,uninstall_size_full);
  2553.     total_usize+=uninstall_size_full;
  2554.   }
  2555.  
  2556.   if (build_compress_whole) {
  2557.     INFO_MSG("Compressed data:          ");
  2558.   }
  2559.  
  2560.   if (build_datablock.getlen())
  2561.   {
  2562.     build_datablock.setro(TRUE);
  2563.     int dbl = build_datablock.getlen();
  2564.     int left = dbl;
  2565.     while (left > 0)
  2566.     {
  2567.       int l = min(build_filebuflen, left);
  2568.       char *dbptr = (char *) build_datablock.get(dbl - left, l);
  2569. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2570.       if (build_compress_whole)
  2571.       {
  2572.         if (deflateToFile(fp,dbptr,l))
  2573.         {
  2574.           fclose(fp);
  2575.           return PS_ERROR;
  2576.         }
  2577.       }
  2578.       else 
  2579. #endif
  2580.       {
  2581. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2582.         crc=CRC32(crc,(unsigned char *)dbptr,l);
  2583. #endif
  2584.         if ((int)fwrite(dbptr,1,l,fp) != l)
  2585.         {
  2586.           ERROR_MSG("Error: can't write %d bytes to output\n",l);
  2587.           fclose(fp);
  2588.           return PS_ERROR;
  2589.         }
  2590.         fflush(fp);
  2591.       }
  2592.       build_datablock.release();
  2593.       left -= l;
  2594.     }
  2595.     build_datablock.setro(FALSE);
  2596.     build_datablock.clear();
  2597.   }
  2598. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2599.   if (build_compress_whole) 
  2600.   {
  2601.     if (deflateToFile(fp,NULL,0))
  2602.     {
  2603.       fclose(fp);
  2604.       return PS_ERROR;
  2605.     }
  2606.     compressor->End();
  2607.  
  2608.     unsigned fend = ftell(fp);
  2609.  
  2610.     fh.length_of_all_following_data=ftell(fp)-fd_start+(build_crcchk?sizeof(int):0);
  2611.     INFO_MSG(
  2612.       "%10d / %d bytes\n",
  2613.       ftell(fp) - fd_start,
  2614.       data_block_size_before_uninst + fh.length_of_header + sizeof(firstheader) + uninstall_size_full
  2615.     );
  2616.  
  2617.     fseek(fp,fd_start,SEEK_SET);
  2618.     fwrite(&fh,sizeof(fh),1,fp);
  2619.  
  2620. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2621.     if (build_crcchk)
  2622.     {
  2623.       // check rest of CRC
  2624.       fseek(fp,fd_start,SEEK_SET);
  2625.       for (;;)
  2626.       {
  2627.         char buf[32768];
  2628.         int l=fread(buf,1,sizeof(buf),fp);
  2629.         if (!l) break;
  2630.         crc=CRC32(crc,(unsigned char *)buf,l);
  2631.       }
  2632.     }
  2633. #endif
  2634.     fseek(fp,fend,SEEK_SET); // reset eof flag
  2635.   }
  2636. #endif
  2637.  
  2638.   if (build_crcchk)
  2639.   {
  2640.     total_usize+=sizeof(int);
  2641.     if (fwrite(&crc,1,sizeof(int),fp) != sizeof(int))
  2642.     {
  2643.       ERROR_MSG("Error: can't write %d bytes to output\n",sizeof(int));
  2644.       fclose(fp);
  2645.       return PS_ERROR;
  2646.     }
  2647.     INFO_MSG("CRC (0x%08X):                  4 / 4 bytes\n",crc);
  2648.   }
  2649.   INFO_MSG("\n");
  2650.   {
  2651.     int pc=MulDiv(ftell(fp),1000,total_usize);
  2652.     INFO_MSG("Total size:               %10d / %d bytes (%d.%d%%)\n",
  2653.       ftell(fp),total_usize,pc/10,pc%10);
  2654.   }
  2655.   fclose(fp);
  2656.   print_warnings();
  2657.   return PS_OK;
  2658. }
  2659.  
  2660. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2661. int CEXEBuild::deflateToFile(FILE *fp, char *buf, int len) // len==0 to flush
  2662. {
  2663.   build_compressor_set=true;
  2664.  
  2665.   char obuf[65536];
  2666.   int flush=0;
  2667.   compressor->SetNextIn(buf,len);
  2668.   if (!buf||!len)
  2669.   {
  2670.     char a;
  2671.     compressor->SetNextIn(&a,0);
  2672.     flush=C_FINISH;
  2673.   }
  2674.   for (;;)
  2675.   {
  2676.     compressor->SetNextOut(obuf,sizeof(obuf));
  2677.     int ret=compressor->Compress(flush);
  2678.     if (ret<0 && (ret!=-1 || !flush))
  2679.     {
  2680.       ERROR_MSG("Error: deflateToFile: deflate()=%d\n",ret);
  2681.       return 1;
  2682.     }
  2683.     int l=compressor->GetNextOut()-obuf;
  2684.     if (l)
  2685.     {
  2686.       if (fwrite(obuf,1,l,fp) != (unsigned)l)
  2687.       {
  2688.         ERROR_MSG("Error: deflateToFile fwrite(%d) failed\n",l);
  2689.         return 1;
  2690.       }
  2691.       fflush(fp);
  2692.     }
  2693.     if (!compressor->GetAvailIn() && (!flush || !l)) break;
  2694.   }
  2695.   return 0;
  2696. }
  2697. #endif
  2698.  
  2699. int CEXEBuild::uninstall_generate()
  2700. {
  2701. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  2702.   if (ubuild_entries.getlen() && uninstaller_writes_used)
  2703.   {
  2704.     SCRIPT_MSG("Generating uninstaller... ");
  2705.  
  2706.     firstheader fh={0,};
  2707.  
  2708.     GrowBuf uhd;
  2709.     {
  2710.       GrowBuf udata;
  2711.  
  2712.       set_uninstall_mode(1);
  2713.  
  2714.       PreperHeaders(&udata);
  2715.  
  2716.       fh.length_of_header=udata.getlen();
  2717.       int err=add_data((char*)udata.get(),udata.getlen(),&uhd);
  2718.       set_uninstall_mode(0);
  2719.       if (err < 0) return PS_ERROR;
  2720.     }
  2721.  
  2722.     int crc=0;
  2723.  
  2724.     // Get offsets of icons to replace for uninstall
  2725.     // Also makes sure that the icons are there and in the right size.
  2726.     icon_offset = generate_unicons_offsets(header_data_new, m_unicon_data);
  2727.     if (icon_offset == 0)
  2728.       return PS_ERROR;
  2729.  
  2730.     entry *ent = (entry *) build_entries.get();
  2731.     if (!ent)
  2732.       return PS_ERROR;
  2733.     int ents = build_header.blocks[NB_ENTRIES].num;
  2734.     int uns = uninstaller_writes_used;
  2735.     int uninstdata_offset = build_datablock.getlen();
  2736.     while (ents--)
  2737.     {
  2738.       if (ent->which == EW_WRITEUNINSTALLER)
  2739.       {
  2740.         ent->offsets[1] = uninstdata_offset;
  2741.         ent->offsets[2] = unicondata_size;
  2742.         uns--;
  2743.         if (!uns)
  2744.           break;
  2745.       }
  2746.       ent++;
  2747.     }
  2748.  
  2749.     if (add_db_data((char *)m_unicon_data,unicondata_size) < 0)
  2750.       return PS_ERROR;
  2751. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2752.     {
  2753.       // "create" the uninstaller
  2754.       LPBYTE uninst_header = (LPBYTE) malloc(exeheader_size_new);
  2755.       if (!uninst_header)
  2756.         return PS_ERROR;
  2757.  
  2758.       memcpy(uninst_header, header_data_new, exeheader_size_new);
  2759.  
  2760.       // patch the icons
  2761.       LPBYTE seeker = m_unicon_data;
  2762.       while (*seeker) {
  2763.         DWORD dwSize = *(LPDWORD) seeker;
  2764.         seeker += sizeof(DWORD);
  2765.         DWORD dwOffset = *(LPDWORD) seeker;
  2766.         seeker += sizeof(DWORD);
  2767.         memcpy(uninst_header + dwOffset, seeker, dwSize);
  2768.         seeker += dwSize;
  2769.       }
  2770.  
  2771. #ifdef NSIS_CONFIG_CRC_ANAL
  2772.       crc=CRC32(crc, uninst_header, exeheader_size_new);
  2773. #else
  2774.       crc=CRC32(crc, uninst_header + 512, exeheader_size_new - 512);
  2775. #endif
  2776.  
  2777.       free(uninst_header);
  2778.     }
  2779. #endif
  2780.     fh.nsinst[0]=FH_INT1;
  2781.     fh.nsinst[1]=FH_INT2;
  2782.     fh.nsinst[2]=FH_INT3;
  2783.     fh.flags=FH_FLAGS_UNINSTALL;
  2784.     fh.flags|=(build_crcchk?(build_crcchk==2?FH_FLAGS_FORCE_CRC:0):FH_FLAGS_NO_CRC);
  2785. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  2786.     if (build_uninst.flags&(CH_FLAGS_SILENT|CH_FLAGS_SILENT_LOG)) fh.flags |= FH_FLAGS_SILENT;
  2787. #endif
  2788.     fh.siginfo=FH_SIG;
  2789.     fh.length_of_all_following_data=
  2790.       uhd.getlen()+ubuild_datablock.getlen()+(int)sizeof(firstheader)+(build_crcchk?sizeof(int):0);
  2791.  
  2792.     MMapBuf udata;
  2793.  
  2794.     udata.add(&fh, sizeof(fh));
  2795.  
  2796.     ubuild_datablock.setro(TRUE);
  2797.  
  2798. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2799.     if (build_compress_whole) {
  2800.       // compress uninstaller too
  2801.       {
  2802.         char obuf[65536];
  2803.         int n;
  2804.         if (compressor == &lzma_compressor)
  2805.           n = ((CLZMA *) compressor)->Init(build_compress_level, build_compress_dict_size);
  2806.         else
  2807.           n = compressor->Init(build_compress_level);
  2808.         if (n != C_OK)
  2809.         {
  2810.           ERROR_MSG("Internal compiler error #12345: deflateInit() failed(%d).\n", n);
  2811.           extern void quit(); quit();
  2812.         }
  2813.  
  2814.         compressor->SetNextIn((char*)uhd.get(), uhd.getlen());
  2815.         while (compressor->GetAvailIn())
  2816.         {
  2817.           compressor->SetNextOut(obuf, sizeof(obuf));
  2818.           compressor->Compress(0);
  2819.           if (compressor->GetNextOut() - obuf > 0)
  2820.           {
  2821.             udata.add(obuf, compressor->GetNextOut() - obuf);
  2822.           }
  2823.         }
  2824.  
  2825.         int avail_in = ubuild_datablock.getlen();
  2826.         int in_pos = 0;
  2827.         while (avail_in > 0) {
  2828.           int l = min(avail_in, build_filebuflen);
  2829.  
  2830.           char *p = (char*)ubuild_datablock.get(in_pos, l);
  2831.           compressor->SetNextIn(p, l);
  2832.  
  2833.           while (compressor->GetAvailIn())
  2834.           {
  2835.             compressor->SetNextOut(obuf, sizeof(obuf));
  2836.             compressor->Compress(0);
  2837.             if (compressor->GetNextOut() - obuf > 0)
  2838.               udata.add(obuf, compressor->GetNextOut() - obuf);
  2839.           }
  2840.  
  2841.           ubuild_datablock.release();
  2842.  
  2843.           avail_in -= l;
  2844.           in_pos += l;
  2845.         }
  2846.  
  2847.         for (;;)
  2848.         {
  2849.           compressor->SetNextOut(obuf, sizeof(obuf));
  2850.           compressor->Compress(C_FINISH);
  2851.           if (compressor->GetNextOut() - obuf > 0)
  2852.             udata.add(obuf, compressor->GetNextOut() - obuf);
  2853.           else break;
  2854.         }
  2855.         compressor->End();
  2856.       }
  2857.  
  2858.       firstheader *_fh=(firstheader *)udata.get(0, sizeof(firstheader));
  2859.       _fh->length_of_all_following_data=udata.getlen()+(build_crcchk?sizeof(int):0);
  2860.       udata.release();
  2861.     }
  2862.     else
  2863. #endif//NSIS_CONFIG_COMPRESSION_SUPPORT
  2864.     {
  2865.       udata.add(uhd.get(), uhd.getlen());
  2866.  
  2867.       int st = udata.getlen();
  2868.       int length = ubuild_datablock.getlen();
  2869.       int left = length;
  2870.       udata.resize(st + left);
  2871.       while (left > 0)
  2872.       {
  2873.         int l = min(build_filebuflen, left);
  2874.         void *p = ubuild_datablock.get(length - left, l);
  2875.         memcpy(udata.get(st + length - left, l), p, l);
  2876.         udata.flush(l);
  2877.         udata.release();
  2878.         ubuild_datablock.release();
  2879.         left -= l;
  2880.       }
  2881.     }
  2882.  
  2883.     ubuild_datablock.clear();
  2884.  
  2885.     udata.setro(TRUE);
  2886.  
  2887. #ifdef NSIS_CONFIG_CRC_SUPPORT
  2888.     if (build_crcchk)
  2889.     {
  2890.       int pos = 0;
  2891.       int left = udata.getlen();
  2892.       while (left > 0)
  2893.       {
  2894.         int l = min(build_filebuflen, left);
  2895.         crc = CRC32(crc, (unsigned char *) udata.get(pos, l), l);
  2896.         udata.release();
  2897.         pos += l;
  2898.         left -= l;
  2899.       }
  2900.       udata.add(&crc, sizeof(crc));
  2901.     }
  2902. #endif
  2903.  
  2904.     if (add_db_data(&udata) < 0)
  2905.       return PS_ERROR;
  2906.  
  2907.     udata.clear();
  2908.  
  2909.     //uninstall_size_full=fh.length_of_all_following_data + sizeof(int) + unicondata_size - 32 + sizeof(int);
  2910.     uninstall_size_full=fh.length_of_all_following_data+unicondata_size;
  2911.  
  2912.     // compressed size
  2913.     uninstall_size=build_datablock.getlen()-uninstdata_offset;
  2914.  
  2915.     SCRIPT_MSG("Done!\n");
  2916.   }
  2917. #endif
  2918.   return PS_OK;
  2919. }
  2920.  
  2921.  
  2922. #define SWAP(x,y,i) { i _ii; _ii=x; x=y; y=_ii; }
  2923.  
  2924. void CEXEBuild::set_uninstall_mode(int un)
  2925. {
  2926.   if (un != uninstall_mode)
  2927.   {
  2928.     uninstall_mode=un;
  2929.     if (un)
  2930.     {
  2931.       cur_datablock=&ubuild_datablock;
  2932.       cur_entries=&ubuild_entries;
  2933.       cur_functions=&ubuild_functions;
  2934.       cur_labels=&ubuild_labels;
  2935.       cur_pages=&ubuild_pages;
  2936.       cur_sections=&ubuild_sections;
  2937.       cur_header=&build_uninst;
  2938.       cur_strlist=&ubuild_strlist;
  2939.       cur_langtables=&ubuild_langtables;
  2940.       cur_ctlcolors=&ubuild_ctlcolors;
  2941.     }
  2942.     else
  2943.     {
  2944.       cur_datablock=&build_datablock;
  2945.       cur_entries=&build_entries;
  2946.       cur_functions=&build_functions;
  2947.       cur_labels=&build_labels;
  2948.       cur_pages=&build_pages;
  2949.       cur_sections=&build_sections;
  2950.       cur_header=&build_header;
  2951.       cur_strlist=&build_strlist;
  2952.       cur_langtables=&build_langtables;
  2953.       cur_ctlcolors=&build_ctlcolors;
  2954.     }
  2955.  
  2956.     SWAP(db_opt_save_u,db_opt_save,int);
  2957.     SWAP(db_comp_save_u,db_comp_save,int);
  2958.     SWAP(db_full_size_u,db_full_size,int);
  2959.   }
  2960. }
  2961.  
  2962. extern FILE *g_output;
  2963.  
  2964. void CEXEBuild::warning(const char *s, ...)
  2965. {
  2966.   char buf[NSIS_MAX_STRLEN*4];
  2967.   va_list val;
  2968.   va_start(val,s);
  2969.   vsprintf(buf,s,val);
  2970.   va_end(val);
  2971.   m_warnings.add(buf,0);
  2972.   notify(MAKENSIS_NOTIFY_WARNING,buf);
  2973.   if (display_warnings)
  2974.   {
  2975.     fprintf(g_output,"warning: %s\n",buf);
  2976.     fflush(g_output);
  2977.   }
  2978. }
  2979.  
  2980. void CEXEBuild::warning_fl(const char *s, ...)
  2981. {
  2982.   char buf[NSIS_MAX_STRLEN*4];
  2983.   va_list val;
  2984.   va_start(val,s);
  2985.   vsprintf(buf,s,val);
  2986.   va_end(val);
  2987.   sprintf(buf+strlen(buf)," (%s:%d)",curfilename,linecnt);
  2988.   m_warnings.add(buf,0);
  2989.   notify(MAKENSIS_NOTIFY_WARNING,buf);
  2990.   if (display_warnings)
  2991.   {
  2992.     fprintf(g_output,"warning: %s\n",buf);
  2993.     fflush(g_output);
  2994.   }
  2995. }
  2996.  
  2997. void CEXEBuild::ERROR_MSG(const char *s, ...)
  2998. {
  2999.   if (display_errors || notify_hwnd)
  3000.   {
  3001.     char buf[NSIS_MAX_STRLEN*4];
  3002.     va_list val;
  3003.     va_start(val,s);
  3004.     vsprintf(buf,s,val);
  3005.     va_end(val);
  3006.     notify(MAKENSIS_NOTIFY_ERROR,buf);
  3007.     if (display_errors)
  3008.     {
  3009.       fprintf(g_output,"%s",buf);
  3010.       fflush(g_output);
  3011.     }
  3012.   }
  3013. }
  3014.  
  3015. void CEXEBuild::SCRIPT_MSG(const char *s, ...)
  3016. {
  3017.   if (display_script)
  3018.   {
  3019.     char buf[NSIS_MAX_STRLEN*4];
  3020.     va_list val;
  3021.     va_start(val,s);
  3022.     vsprintf(buf,s,val);
  3023.     va_end(val);
  3024.     fprintf(g_output,"%s",buf);
  3025.     fflush(g_output);
  3026.   }
  3027. }
  3028.  
  3029. void CEXEBuild::INFO_MSG(const char *s, ...)
  3030. {
  3031.   if (display_info)
  3032.   {
  3033.     char buf[NSIS_MAX_STRLEN*4];
  3034.     va_list val;
  3035.     va_start(val,s);
  3036.     vsprintf(buf,s,val);
  3037.     va_end(val);
  3038.     fprintf(g_output,"%s",buf);
  3039.     fflush(g_output);
  3040.   }
  3041. }
  3042.  
  3043. void CEXEBuild::print_warnings()
  3044. {
  3045.   int nw=0,x=m_warnings.getlen();
  3046.   if (!x || !display_warnings) return;
  3047.   char *p=m_warnings.get();
  3048.   while (x>0) if (!p[--x]) nw++;
  3049.   fprintf(g_output,"\n%d warning%s:\n",nw,nw==1?"":"s");
  3050.   for (x = 0; x < nw; x ++)
  3051.   {
  3052.     fprintf(g_output,"  %s\n",p);
  3053.     p+=strlen(p)+1;
  3054.   }
  3055.   fflush(g_output);
  3056. }
  3057.  
  3058. void CEXEBuild::notify(int code, char *data)
  3059. {
  3060.   if (notify_hwnd)
  3061.   {
  3062.     COPYDATASTRUCT cds = {(DWORD)code, strlen(data)+1, data};
  3063.     SendMessage(notify_hwnd, WM_COPYDATA, 0, (LPARAM)&cds);
  3064.   }
  3065. }
  3066.  
  3067. // Added by Ximon Eighteen 5th August 2002
  3068. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  3069. void CEXEBuild::build_plugin_table(void)
  3070. {
  3071.   if (plugins_processed)
  3072.     return;
  3073.   plugins_processed=1;
  3074.  
  3075.   plugin_used = false;
  3076.   uninst_plugin_used = false;
  3077.   char* nsisdir = definedlist.find("NSISDIR");
  3078.   if (nsisdir)
  3079.   {
  3080.     char* searchPath = new char [strlen(nsisdir)+9];
  3081.     if (searchPath)
  3082.     {
  3083.       wsprintf(searchPath,"%s\\plugins",nsisdir);
  3084.       INFO_MSG("Processing plugin dlls: \"%s\\*.dll\"\n",searchPath);
  3085.       m_plugins.FindCommands(searchPath,display_info?true:false);
  3086.       INFO_MSG("\n");
  3087.       delete[] searchPath;
  3088.     }
  3089.   }
  3090. }
  3091.  
  3092. #define FLAG_OFFSET(flag) (FIELD_OFFSET(exec_flags, flag)/sizeof(int))
  3093.  
  3094. int CEXEBuild::add_plugins_dir_initializer(void)
  3095. {
  3096.   if (!plugin_used && !uninst_plugin_used) return PS_OK;
  3097.  
  3098.   SCRIPT_MSG("Adding plug-ins initializing function... ");
  3099.  
  3100.   bool uninstall = !plugin_used;
  3101.  
  3102.   int ret;
  3103.   int zero_offset;
  3104.  
  3105.   int var_zero;
  3106.   var_zero=m_UserVarNames.get("0");
  3107.  
  3108. again:
  3109.   // Function [un.]Initialize_____Plugins
  3110.   ret=add_function(uninstall?"un.Initialize_____Plugins":"Initialize_____Plugins");
  3111.   if (ret != PS_OK) return ret;
  3112.  
  3113.   // don't move this, depends on [un.]
  3114.   zero_offset=add_string("$0");
  3115.  
  3116.   // SetDetailsPrint none
  3117.   ret=add_entry_direct(EW_UPDATETEXT, 0, 16);
  3118.   if (ret != PS_OK) return ret;
  3119.  
  3120.   // StrCmp $PLUGINSDIR ""
  3121.   ret=add_entry_direct(EW_STRCMP, add_string("$PLUGINSDIR"), 0, 0, ns_label.add("Initialize_____Plugins_done",0));
  3122.   if (ret != PS_OK) return ret;
  3123.   // Push $0
  3124.   ret=add_entry_direct(EW_PUSHPOP, zero_offset);
  3125.   if (ret != PS_OK) return ret;
  3126.   // ClearErrors
  3127.   ret=add_entry_direct(EW_SETFLAG, FLAG_OFFSET(exec_error));
  3128.   if (ret != PS_OK) return ret;
  3129.   // GetTempFileName $0
  3130.   ret=add_entry_direct(EW_GETTEMPFILENAME, var_zero, add_string("$TEMP"));
  3131.   if (ret != PS_OK) return ret;
  3132.   // Delete $0 - the temp file created
  3133.   ret=add_entry_direct(EW_DELETEFILE, zero_offset);
  3134.   if (ret != PS_OK) return ret;
  3135.   // CraeteDirectory $0 - a dir instead of that temp file
  3136.   ret=add_entry_direct(EW_CREATEDIR, zero_offset);
  3137.   if (ret != PS_OK) return ret;
  3138.   // IfErrors Initialize_____Plugins_error - detect errors
  3139.   ret=add_entry_direct(EW_IFFLAG, ns_label.add("Initialize_____Plugins_error",0), 0, FLAG_OFFSET(exec_error));
  3140.   if (ret != PS_OK) return ret;
  3141.   // Copy $0 to $PLUGINSDIR
  3142.   ret=add_entry_direct(EW_ASSIGNVAR, m_UserVarNames.get("PLUGINSDIR"), zero_offset);
  3143.   if (ret != PS_OK) return ret;
  3144.   // Pop $0
  3145.   ret=add_entry_direct(EW_PUSHPOP, var_zero, 1);
  3146.   if (ret != PS_OK) return ret;
  3147.  
  3148.   // done
  3149.   if (add_label("Initialize_____Plugins_done")) return PS_ERROR;
  3150.   // Return
  3151.   ret=add_entry_direct(EW_RET);
  3152.   if (ret != PS_OK) return ret;
  3153.  
  3154.   // error
  3155.   if (add_label("Initialize_____Plugins_error")) return PS_ERROR;
  3156.   // error message box
  3157.   ret=add_entry_direct(EW_MESSAGEBOX, MB_OK|MB_ICONSTOP|(IDOK<<20), add_string("Error! Can't initialize plug-ins directory. Please try again later."));
  3158.   if (ret != PS_OK) return ret;
  3159.   // Quit
  3160.   ret=add_entry_direct(EW_QUIT);
  3161.   if (ret != PS_OK) return ret;
  3162.  
  3163.   // FunctionEnd
  3164.   ret=function_end();
  3165.   if (ret != PS_OK) return ret;
  3166.  
  3167.   if (uninst_plugin_used && !uninstall) {
  3168.     uninstall = true;
  3169.     goto again;
  3170.   }
  3171.  
  3172.   SCRIPT_MSG("Done!\n");
  3173.  
  3174.   return PS_OK;
  3175. }
  3176. #endif // NSIS_CONFIG_PLUGIN_SUPPORT
  3177.  
  3178. void CEXEBuild::init_res_editor()
  3179. {
  3180.   build_compressor_set = true;
  3181.   if (!res_editor)
  3182.     res_editor = new CResourceEditor(header_data_new, exeheader_size_new);
  3183. }
  3184.  
  3185. void CEXEBuild::close_res_editor()
  3186. {
  3187.   if (!res_editor) return;
  3188.   DWORD newsize;
  3189.   // query size
  3190.   newsize = res_editor->Save(NULL, newsize);
  3191.   unsigned char *new_header = (unsigned char *) malloc(newsize);
  3192.   // save
  3193.   res_editor->Save(new_header, newsize);
  3194.   free(header_data_new);
  3195.   header_data_new = new_header;
  3196.   exeheader_size_new = (int) newsize;
  3197.   delete res_editor;
  3198.   res_editor=0;
  3199. }
  3200.  
  3201. int CEXEBuild::DeclaredUserVar(const char *szVarName)
  3202. {
  3203.   if ( m_ShellConstants.get((char*)szVarName) >= 0 )
  3204.   {
  3205.     ERROR_MSG("Error: name \"%s\" in use by constant\n", szVarName);
  3206.     return PS_ERROR;  
  3207.   }
  3208.  
  3209.   int idxUserVar = m_UserVarNames.get((char*)szVarName);
  3210.   if ( idxUserVar >= 0 )
  3211.   {
  3212.     ERROR_MSG("Error: variable \"%s\" already declared\n", szVarName);
  3213.     return PS_ERROR;  
  3214.   }
  3215.   const char *pVarName = szVarName;
  3216.   int iVarLen = strlen(szVarName);
  3217.  
  3218.   if ( iVarLen > 60 )
  3219.   {
  3220.     ERROR_MSG("Error: variable name too long!\n");
  3221.     return PS_ERROR;
  3222.   }
  3223.   else if ( !iVarLen )
  3224.   {
  3225.     ERROR_MSG("Error: variable with empty name!\n");
  3226.     return PS_ERROR;
  3227.   }
  3228.   else
  3229.   {
  3230.     while ( *pVarName )
  3231.     {
  3232.       if ( !isSimpleChar(*pVarName) )
  3233.       {
  3234.         ERROR_MSG("Error: invalid charaters in variable name \"%s\", use only charaters [a-z][A-Z][0-9] and '_'\n", szVarName);
  3235.         return PS_ERROR;
  3236.       }
  3237.       pVarName++;
  3238.     }
  3239.   }
  3240.  
  3241.   m_UserVarNames.add(szVarName);
  3242.   if (m_UserVarNames.getnum() > MAX_CODED)
  3243.   {
  3244.     ERROR_MSG("Error: too many user variables declared. Maximum allowed is %u.\n", MAX_CODED - m_iBaseVarsNum);
  3245.     return PS_ERROR;
  3246.   }
  3247.   return PS_OK;
  3248. }
  3249.  
  3250.  
  3251. int CEXEBuild::GetUserVarIndex(LineParser &line, int token)
  3252. {
  3253.   char *p = line.gettoken_str(token);
  3254.   if ( *p == '$' && *(p+1) )
  3255.   {
  3256.     int idxUserVar = m_UserVarNames.get((char *)p+1);
  3257.     if (idxUserVar >= 0 && m_UserVarNames.get_reference(idxUserVar) >= 0)
  3258.     {
  3259.       m_UserVarNames.inc_reference(idxUserVar);
  3260.       return idxUserVar;
  3261.     }
  3262.     else
  3263.     {
  3264.         int idxConst = m_ShellConstants.get((char *)p+1);
  3265.         if ( idxConst >= 0 )
  3266.         {
  3267.             ERROR_MSG("Error: cannot change constants : %s\n", p);
  3268.         }
  3269.     }
  3270.   }
  3271.   return -1;
  3272. }
  3273.  
  3274. void CEXEBuild::VerifyDeclaredUserVarRefs(UserVarsStringList *pVarsStringList)
  3275. {
  3276.   for (int i = m_iBaseVarsNum; i < pVarsStringList->getnum(); i++)
  3277.   {
  3278.     if (!pVarsStringList->get_reference(i))
  3279.     {      
  3280.       warning("Variable \"%s\" not referenced, wasting memory!", pVarsStringList->idx2name(i));
  3281.     }  
  3282.   }
  3283. }
  3284.