home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 October / Chip_2001-10_cd1.bin / zkuste / delphi / nastroje / d23456 / NSIS.EXE / Source / build.cpp next >
C/C++ Source or Header  |  2001-05-30  |  32KB  |  1,151 lines

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include "zlib/zlib.h"
  4. #include "exehead/config.h"
  5. #include "exehead/fileform.h"
  6.  
  7. #include "exedata.h"
  8.  
  9. #include "build.h"
  10. #include "util.h"
  11.  
  12. void CEXEBuild::define(char *p) 
  13.   definedlist.add(p,0); 
  14. }
  15.  
  16.  
  17. CEXEBuild::~CEXEBuild()
  18. {
  19.   free(header_data_new);
  20. }
  21.  
  22. CEXEBuild::CEXEBuild()
  23. {
  24.   has_called_write_output=0;
  25.  
  26.   ns_func.add("",0); // make sure offset 0 is special on these (i.e. never used by a label)
  27.   ns_label.add("",0);
  28.  
  29.   header_data_new=(unsigned char*)malloc(exeheader_size);
  30.   exeheader_size_new=exeheader_size;
  31.  
  32.   if (!header_data_new) 
  33.   {
  34.     printf("Internal compiler error #12345: malloc(%d) failed\n",exeheader_size_new);
  35.     extern void quit(); quit();
  36.   }
  37.  
  38.   memcpy(header_data_new,header_data,exeheader_size);
  39.   enabled_bitmap_offset = find_data_offset((char*)header_data_new,exeheader_size_new,(char*)bitmap1_data,BMP_HDRSKIP,sizeof(bitmap1_data));
  40.   disabled_bitmap_offset = find_data_offset((char*)header_data_new,exeheader_size_new,(char*)bitmap2_data,BMP_HDRSKIP,sizeof(bitmap2_data));
  41.   icon_offset = find_data_offset((char*)header_data_new,exeheader_size_new,(char*)icon_data,ICO_HDRSKIP,sizeof(icon_data));
  42.  
  43.   if (enabled_bitmap_offset < 0 || disabled_bitmap_offset < 0 || icon_offset < 0)
  44.   {
  45.     printf("Internal compiler error #12345: icons missing\n"); 
  46.     extern void quit(); quit();
  47.   }
  48.  
  49.   strcpy(cur_out_path,"$INSTDIR");
  50.  
  51. #ifdef NSIS_CONFIG_LOG
  52.   definedlist.add("NSIS_CONFIG_LOG",0);
  53. #endif
  54. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  55.   definedlist.add("NSIS_CONFIG_UNINSTALL_SUPPORT",0);
  56. #endif
  57. #ifdef NSIS_SUPPORT_NETSCAPEPLUGINS
  58.   definedlist.add("NSIS_SUPPORT_NETSCAPEPLUGINS",0);
  59. #endif
  60. #ifdef NSIS_SUPPORT_ACTIVEXREG
  61.   definedlist.add("NSIS_SUPPORT_ACTIVEXREG",0);
  62. #endif
  63. #ifdef NSIS_SUPPORT_BGBG
  64.   definedlist.add("NSIS_SUPPORT_BGBG",0);
  65. #endif
  66.  
  67.   db_opt_save=db_comp_save=db_full_size=db_opt_save_u=db_comp_save_u=db_full_size_u=0;
  68.  
  69.   cur_entries=&build_entries;
  70.   cur_datablock=&build_datablock;
  71.   cur_functions=&build_functions;
  72.   cur_labels=&build_labels;
  73.  
  74.   build_cursection_isfunc=0;
  75.   build_cursection=NULL;
  76.   // init public data.
  77.   build_packname[0]=build_packcmd[0]=build_output_filename[0]=0;
  78.  
  79.   build_overwrite=0;
  80.   build_compress=1;
  81.   build_crcchk=1; 
  82.   build_datesave=1;
  83.   build_optimize_datablock=1;
  84.  
  85.   memset(&build_header,-1,sizeof(build_header));
  86.  
  87.   build_header.install_reg_rootkey=0;
  88.   build_header.no_custom_instmode_flag=0;
  89.   build_header.num_sections=0;
  90.   build_header.num_entries=0;
  91.   build_header.silent_install=0;
  92.   build_header.auto_close=0;
  93.   build_header.show_details=0;
  94.   build_header.no_show_dirpage=0;
  95.   build_header.lb_bg=RGB(0,0,0);
  96.   build_header.lb_fg=RGB(0,255,0);
  97.   uninstall_mode=0;
  98.   uninstall_size_full=0;
  99.   uninstall_size=-1;
  100.   
  101.   memset(&build_uninst,-1,sizeof(build_uninst));
  102.   build_uninst.lb_bg=RGB(0,0,0);
  103.   build_uninst.lb_fg=RGB(0,255,0);
  104.   build_uninst.num_entries=0;
  105.   build_uninst.code[0]=build_uninst.code[1]=0;
  106.  
  107.   memcpy(m_unicon_data,unicon_data,sizeof(m_unicon_data));
  108. }
  109.  
  110. int CEXEBuild::getcurdbsize() { return cur_datablock->getlen(); }
  111.  
  112. int CEXEBuild::add_string(char *string) // returns offset in stringblock
  113. {
  114.   if (uninstall_mode) return add_string_uninst(string);
  115.   return add_string_main(string);
  116. }
  117. int CEXEBuild::add_string_main(char *string) // returns offset (in string block)
  118. {
  119.   if (!*string) return -1;
  120.   if (strstr(string,"$WAVISDIR") || strstr(string,"$WADSPDIR"))
  121.     warning("$WAVISDIR and $WADSPDIR are no longer supported.\n");
  122.   return build_strlist.add(string,2);
  123. }
  124.  
  125. int CEXEBuild::add_string_uninst(char *string) // returns offset (in string block)
  126. {
  127.   if (!*string) return -1;
  128.   if (strstr(string,"$WAVISDIR") || strstr(string,"$WADSPDIR"))
  129.     warning("$WAVISDIR and $WADSPDIR are no longer supported.\n");
  130.   return ubuild_strlist.add(string,2);
  131. }
  132.  
  133. // what it does is, when you pass it the offset of the last item added, it will determine if 
  134. // that data is already present in the datablock, and if so, reference it instead (and shorten
  135. // the datablock as necessary). Reduces overhead if you want to add files to a couple places.
  136. // Woo, an optimizing installer generator, now we're styling.
  137.  
  138. int CEXEBuild::datablock_optimize(int start_offset)
  139. {
  140.   int this_len = cur_datablock->getlen()-start_offset;
  141.   int pos=0;
  142.  
  143.   if (!build_optimize_datablock) return start_offset;
  144.  
  145.   char *db=(char*)cur_datablock->get();
  146.   int first_int=*(int*)(db+start_offset);
  147.   if (this_len >= 4) while (pos < start_offset)
  148.   {
  149.     int this_int = *(int*)(db+pos);
  150.     if (this_int == first_int && !memcmp(db+pos,db+start_offset,this_len))
  151.     {
  152.       db_opt_save+=this_len;
  153.       cur_datablock->resize(max(start_offset,pos+this_len));
  154.       return pos;
  155.     }
  156.     pos += 4 + (this_int&0x7fffffff);
  157.   }
  158.  
  159.   return start_offset;
  160. }
  161.  
  162. int CEXEBuild::add_data(char *data, int length) // returns offset
  163. {
  164.   int done=0;
  165.  
  166.   if (length < 0)
  167.   {
  168.     printf("Error: add_data() called with length=%d\n",length);
  169.     return -1;
  170.   }
  171.  
  172.   int st=cur_datablock->getlen();
  173.  
  174.   if (build_compress)
  175.   {
  176.  
  177.     z_stream stream={0,};
  178.  
  179.     // grow datablock so that there is room to compress into
  180.     int bufferlen=length+1024+length/1000;
  181.     cur_datablock->resize(st+bufferlen+sizeof(int));
  182.  
  183.     if (deflateInit(&stream, 9) != Z_OK) 
  184.     {
  185.       printf("Error: deflateInit() failed in add_data()\n");
  186.       return -1;
  187.     }
  188.  
  189.     stream.next_in = (Bytef*)data;
  190.     stream.avail_in = (uInt)length;
  191.  
  192.     stream.next_out = (unsigned char *)cur_datablock->get() + st + sizeof(int);
  193.     stream.avail_out = bufferlen;
  194.  
  195.     deflate(&stream, Z_SYNC_FLUSH);
  196.  
  197.     int used=bufferlen-stream.avail_out;
  198.  
  199.     deflateEnd(&stream);
  200.  
  201.     
  202.     if (build_compress == 2 || used < length)
  203.     {
  204.       done=1;
  205.       cur_datablock->resize(st+used+sizeof(int));
  206.  
  207.       *((int*)((char *)cur_datablock->get()+st)) = used|0x80000000;
  208.       int nst=datablock_optimize(st);
  209.       if (nst == st) db_comp_save+=length-used;
  210.       else st=nst;
  211.     }
  212.   }
  213.  
  214.   if (!done)
  215.   {
  216.     cur_datablock->resize(st);
  217.     cur_datablock->add(&length,sizeof(int));
  218.     cur_datablock->add(data,length);
  219.     st=datablock_optimize(st);
  220.   }
  221.  
  222.   db_full_size += length + sizeof(int);
  223.  
  224.   return st;
  225. }
  226.  
  227. int CEXEBuild::add_label(char *name)
  228. {
  229.   if (!build_cursection && !uninstall_mode)
  230.   {
  231.     printf("Error: Label declaration not valid outside of function/section\n"); 
  232.     return PS_ERROR;
  233.   }
  234.   if ((name[0] >= '0' && name[0] <= '9') || name[0] == '-' || name[0] == ' ' || name[0] == ':')
  235.   {
  236.     printf("Error: labels must not begin with 0-9, -, :, or a space.\n"); 
  237.     return PS_ERROR;
  238.   }
  239.   int cs;
  240.   int ce;
  241.   if (build_cursection)
  242.   {
  243.     cs=build_cursection->code[0];
  244.     ce=build_cursection->code[1];
  245.   }
  246.   else
  247.   {
  248.     cs=build_uninst.code[0];
  249.     ce=build_uninst.code[1];
  250.   }
  251.  
  252.   char *p=strdup(name);
  253.   if (p[strlen(p)-1] == ':') p[strlen(p)-1]=0;
  254.   int offs=ns_label.add(p,0);
  255.   free(p);
  256.  
  257.   int n=cur_labels->getlen()/sizeof(section);
  258.   if (n)
  259.   {
  260.     section *t=(section*)cur_labels->get();
  261.     while (n--)
  262.     {
  263.       if (t->code[0] >= cs && t->code[0] <= ce && t->name_ptr==offs)
  264.       {
  265.         printf("Error: label \"%s\" already declared in section/function\n",name);
  266.         return PS_ERROR;
  267.       }
  268.       t++;
  269.     }
  270.   }
  271.   
  272.   section s={0,};
  273.   s.name_ptr = offs;
  274.   s.code[0] = ce;
  275.   cur_labels->add(&s,sizeof(s));
  276.  
  277.   return PS_OK;
  278. }
  279.  
  280. int CEXEBuild::add_function(char *funname)
  281. {
  282.   if (build_cursection_isfunc)
  283.   {
  284.     printf("Error: Function open when creating function (use FunctionEnd first)\n");
  285.     return PS_ERROR;
  286.   }
  287.   if (build_cursection)
  288.   {
  289.     printf("Error: Section open when creating function (use SectionEnd first)\n");
  290.     return PS_ERROR;
  291.   }
  292.   if (!funname[0])
  293.   {
  294.     printf("Error: Function must have a name\n");
  295.     return PS_ERROR;
  296.   }
  297.  
  298.   if (!strnicmp(funname,"un.",3))
  299.   {
  300.     set_uninstall_mode(1);
  301.   }
  302.  
  303.   int addr=ns_func.add(funname,0);
  304.   int x;
  305.   int n=cur_functions->getlen()/sizeof(section);
  306.   section *tmp=(section*)cur_functions->get();
  307.   for (x = 0; x < n; x ++)
  308.   {
  309.     if (tmp[x].name_ptr == addr)
  310.     {
  311.       printf("Error: Function named \"%s\" already exists.\n",funname);
  312.       return PS_ERROR;
  313.     }
  314.   }
  315.  
  316.   cur_functions->resize((n+1)*sizeof(section));
  317.   build_cursection=((section*)cur_functions->get())+n;
  318.   build_cursection_isfunc=1;
  319.   build_cursection->name_ptr=addr;
  320.   build_cursection->code[0]=cur_entries->getlen()/sizeof(entry);
  321.   build_cursection->code[1]=build_cursection->code[0];
  322.   build_cursection->default_state=0;
  323.   build_cursection->size_kb=0;
  324.   return PS_OK;
  325. }
  326.  
  327. int CEXEBuild::function_end()
  328. {
  329.   if (!build_cursection_isfunc)
  330.   {
  331.     printf("Error: No function open, FunctionEnd called\n");
  332.     return PS_ERROR;
  333.   }
  334.   build_cursection_isfunc=0;
  335.   build_cursection=NULL;
  336.  
  337.   // add invalid opcode, useful for error checking, and
  338.   // makes sure that labels at end of functions work properly.
  339.   entry ent={0,};
  340.   cur_entries->add(&ent,sizeof(entry));
  341.   if (!uninstall_mode) build_header.num_entries++;
  342.   else build_uninst.num_entries++;
  343.  
  344.   set_uninstall_mode(0);
  345.   return PS_OK;
  346. }
  347.  
  348.  
  349. int CEXEBuild::section_add_flags(int flags)
  350. {
  351.   if (uninstall_mode)
  352.   {
  353.     printf("Error: can't modify flags of uninstall section\n");
  354.     return PS_ERROR;
  355.   }
  356.   if (!build_cursection || build_cursection_isfunc)
  357.   {
  358.     printf("Error: can't modify flags when no section is open\n");
  359.     return PS_ERROR;
  360.   }
  361.   build_cursection->default_state|=flags;
  362.   return PS_OK;
  363. }
  364.  
  365. void CEXEBuild::section_add_size_kb(int kb)
  366. {
  367.   if (build_cursection)
  368.   {
  369.     build_cursection->size_kb+=kb;
  370.   }
  371. }
  372.  
  373. int CEXEBuild::section_end()
  374. {
  375.   if (build_cursection_isfunc)
  376.   {
  377.     printf("Error: SectionEnd specified in function (not section)\n");
  378.     return PS_ERROR;
  379.   }
  380.   else if (uninstall_mode)
  381.   {
  382.     set_uninstall_mode(0);
  383.   }
  384.   else if (!build_cursection)
  385.   {
  386.     printf("Error: SectionEnd specified and no sections open\n");
  387.     return PS_ERROR;
  388.   }
  389.   else 
  390.   {
  391.     // add invalid opcode, useful for error checking, and
  392.     // makes sure that labels at end of inst sections work properly.
  393.     entry ent={0,};
  394.     cur_entries->add(&ent,sizeof(entry));
  395.     build_header.num_entries++;
  396.   }
  397.   build_cursection=NULL;
  398.   return PS_OK;
  399. }
  400.  
  401. int CEXEBuild::add_section(char *secname, char *file, int line)
  402. {
  403.   if (build_cursection_isfunc)
  404.   {
  405.     printf("Error: Section can't create section (already in function, use FunctionEnd first)\n");
  406.     return PS_ERROR;
  407.   }
  408.   if (build_cursection || uninstall_mode)
  409.   {
  410.     printf("Error: Section already open, call SectionEnd first\n");
  411.     return PS_ERROR;
  412.   }
  413.   if (!stricmp(secname,"uninstall"))
  414.   {
  415.     if (build_uninst.code[0] != build_uninst.code[1])
  416.     {
  417.       printf("Error: Uninstall section already specified\n");
  418.       return PS_ERROR;
  419.     }
  420.     build_uninst.code[0]=ubuild_entries.getlen()/sizeof(entry);
  421.     build_uninst.code[1]=build_uninst.code[0];
  422.     set_uninstall_mode(1);
  423.     build_cursection=NULL;
  424.     return PS_OK;
  425.   }
  426.   else if (uninstall_mode)
  427.   {
  428.     set_uninstall_mode(0);
  429.   }
  430.   int n=(build_sections.getlen()/sizeof(section));
  431.   build_sections.resize(build_sections.getlen()+sizeof(section));
  432.   build_cursection=((section*)build_sections.get()) + n;
  433.   build_cursection->default_state=(!n||!secname[0])?0x80000000:0;
  434.   build_cursection->name_ptr=add_string(secname);
  435.   build_cursection->code[0]=cur_entries->getlen()/sizeof(entry);
  436.   build_cursection->code[1]=build_cursection->code[0];
  437.   build_cursection->size_kb=0;
  438.  
  439.   if (secname[0]=='-')
  440.   {
  441.     if (!n)
  442.     {
  443.       printf("Error: SectionDivider cannot be first section\n");
  444.       return PS_ERROR;
  445.     }
  446.     build_cursection=NULL;
  447.   }
  448.   
  449.   build_header.num_sections++;
  450.  
  451.   return PS_OK;
  452. }
  453.  
  454. int CEXEBuild::make_sure_not_in_secorfunc(char *str)
  455. {
  456.   if (build_cursection || uninstall_mode)
  457.   {
  458.     printf("Error: command %s not valid in %s\n",str,build_cursection_isfunc?"function":"section");
  459.     return PS_ERROR;
  460.   }
  461.   return PS_OK;
  462. }
  463.  
  464. int CEXEBuild::add_entry(entry *ent)
  465. {
  466.   if (!build_cursection && !uninstall_mode) 
  467.   {
  468.     printf("Error: Can't add entry, no section or function is open!\n");
  469.     return PS_ERROR;
  470.   }
  471.  
  472.   cur_entries->add(ent,sizeof(entry));
  473.  
  474.   if (!uninstall_mode)
  475.   {
  476.     if (!build_cursection_isfunc && build_cursection->name_ptr >=0 && build_strlist.get()[build_cursection->name_ptr] == '-')
  477.     {
  478.       printf("Error: cannot add entry to divider section\n");
  479.       return PS_ERROR;
  480.     }
  481.     build_cursection->code[1]=++build_header.num_entries;
  482.   }
  483.   else
  484.   {
  485.     build_uninst.num_entries++;
  486.     if (build_cursection) build_cursection->code[1]=build_uninst.num_entries;
  487.     else build_uninst.code[1]=build_uninst.num_entries;
  488.   }
  489.  
  490.   return PS_OK;
  491. }
  492.  
  493. void CEXEBuild::printline(int l)
  494. {
  495.   while (l > 2) 
  496.   {
  497.     printf("-=");
  498.     l-=2;
  499.   }
  500.   if (l) printf("-");
  501.   printf("\n");
  502. }
  503.  
  504.  
  505. int CEXEBuild::resolve_jump_int(int *a, int offs, int start, int end)
  506. {
  507.   if (*a != 0)
  508.   {
  509.     section *s = (section*)cur_labels->get();
  510.     int n=cur_labels->getlen()/sizeof(section);
  511.     while (n-->0)
  512.     {
  513.       if (s->code[0] >= start && s->code[0] <= end && s->name_ptr == *a)
  514.       {
  515. //        printf("Resolved jump label \"%s\" to %d\n",(char*)ns_label.get()+*a,s->code_start-offs-1);
  516.         *a = s->code[0]-offs - 1;
  517.         s->default_state++;
  518.         return 0;
  519.       }
  520.       s++;
  521.     }
  522.  
  523.     printf("Error: resolve_jump_int: could not resolve jump \"%s\"\n",(char*)ns_label.get()+*a);
  524.     return 1;
  525.   }
  526.   return 0;
  527. }
  528.  
  529. int CEXEBuild::resolve_instruction(entry *w, int offs, int start, int end)
  530. {
  531.   if (w->which == EW_NOP)
  532.   {
  533.     if (resolve_jump_int(&w->offsets[0],offs,start,end)) return 1;
  534.   }
  535.   else if (w->which == EW_FINDWINDOW)
  536.   {
  537.     if (resolve_jump_int(&w->offsets[4],offs,start,end)) return 1;
  538.   }
  539.   else if (w->which == EW_MESSAGEBOX)
  540.   {
  541.     if (resolve_jump_int(&w->offsets[3],offs,start,end)) return 1;
  542.   }
  543.   else if (w->which == EW_IFFILEEXISTS)
  544.   {
  545.     if (resolve_jump_int(&w->offsets[1],offs,start,end)) return 1;
  546.     if (resolve_jump_int(&w->offsets[2],offs,start,end)) return 1;
  547.   }
  548.   else if (w->which == EW_IFERRORS)
  549.   {
  550.     if (resolve_jump_int(&w->offsets[0],offs,start,end)) return 1;
  551.     if (resolve_jump_int(&w->offsets[1],offs,start,end)) return 1;
  552.   }
  553.   else if (w->which == EW_STRCMP)
  554.   {
  555.     if (resolve_jump_int(&w->offsets[2],offs,start,end)) return 1;
  556.     if (resolve_jump_int(&w->offsets[3],offs,start,end)) return 1;
  557.   }
  558.   else if (w->which == EW_COMPAREDLLS || w->which == EW_COMPAREFILETIMES)
  559.   {
  560.     if (resolve_jump_int(&w->offsets[2],offs,start,end)) return 1;
  561.     if (resolve_jump_int(&w->offsets[3],offs,start,end)) return 1;
  562.   }
  563.   return 0;
  564. }
  565.  
  566. int CEXEBuild::resolve_function(char *str, int fptr, int *ofs)
  567. {
  568.   if (fptr < 0) return 0;
  569.   int nf=cur_functions->getlen()/sizeof(section);
  570.   section *sec=(section *)cur_functions->get();
  571.   while (nf-- > 0)
  572.   {
  573.     if (sec->name_ptr && sec->name_ptr == fptr)
  574.     {
  575. //      printf("Resolved %s function: \"%s\" to (%d,%d)\n",str,
  576.   //      (char*)ns_func.get()+fptr,sec->code_start,sec->code_end);
  577.       ofs[0]=sec->code[0];
  578.       ofs[1]=sec->code[1];
  579.       sec->default_state++;
  580.       return 0;
  581.     }
  582.     sec++;
  583.   }
  584.   printf("Error resolving %s function \"%s\"\n",str,(char*)ns_func.get()+fptr);
  585.   printf("Note: uninstall functions must begin with \"un.\", and install functions must not\n");
  586.   return 1;
  587. }
  588.  
  589.  
  590. int CEXEBuild::resolve_functions(char *str)
  591. {
  592.   // resolve calls
  593.   {
  594.     int l=cur_entries->getlen()/sizeof(entry);
  595.     if (l)
  596.     {
  597.       int x;
  598.       entry *w=(entry*)cur_entries->get();
  599.       for (x = 0; x < l; x ++)
  600.       {
  601.         if (w[x].which == EW_CALL) // call, that needs resolve
  602.         {
  603.           if (resolve_function(str,w[x].offsets[0],w[x].offsets)) return 1;
  604.         }
  605.       }
  606.     }
  607.   }
  608.  
  609.   // resolve jumps
  610.   {
  611.     section *sec=(section *)cur_functions->get();    
  612.     int l=cur_functions->getlen()/sizeof(section);
  613.     entry *w=(entry*)cur_entries->get();
  614.     while (l-- > 0)
  615.     {
  616.       int x;
  617.       for (x = sec->code[0]; x < sec->code[1]; x ++)
  618.         if (resolve_instruction(w+x,x,sec->code[0],sec->code[1])) return 1;
  619.  
  620.       sec++;
  621.     }
  622.     if (uninstall_mode)
  623.     {
  624.       int x;
  625.       for (x = build_uninst.code[0]; x < build_uninst.code[1]; x ++)
  626.         if (resolve_instruction(w+x,x,build_uninst.code[0],build_uninst.code[1])) return 1;
  627.     }
  628.     else
  629.     {
  630.       sec=(section *)build_sections.get();
  631.       l=build_sections.getlen()/sizeof(section);
  632.       while (l-- > 0)
  633.       {
  634.         int x;
  635.         for (x = sec->code[0]; x < sec->code[1]; x ++)
  636.           if (resolve_instruction(w+x,x,sec->code[0],sec->code[1])) return 1;
  637.         sec++;
  638.       }
  639.     }
  640.   }
  641.  
  642.   // optimize unused functions
  643.   {
  644.     section *sec=(section *)cur_functions->get();    
  645.     int l=cur_functions->getlen()/sizeof(section);
  646.     entry *w=(entry*)cur_entries->get();
  647.     while (l-- > 0)
  648.     {
  649.       if (sec->name_ptr)
  650.       {
  651.         if (!sec->default_state)
  652.         {
  653.           if (sec->code[1]>sec->code[0])
  654.           {
  655.             printf("%s function \"%s\" not referenced - zeroing code (%d-%d) out\n",str,
  656.               ns_func.get()+sec->name_ptr,
  657.               sec->code[0],sec->code[1]);
  658.             memset(w+sec->code[0],0,(sec->code[1]-sec->code[0])*sizeof(entry));
  659.           }
  660.         }
  661.       }
  662.       sec++;
  663.     }
  664.   }
  665.  
  666.   // give warnings on unused labels
  667.   {
  668.     section *t=(section*)cur_labels->get();
  669.     int n=cur_labels->getlen()/sizeof(section);
  670.     while (n-->0)
  671.     {
  672.       if (!t->default_state)
  673.       {
  674.         warning("label \"%s\" not used",(char*)ns_label.get()+t->name_ptr);
  675.       }
  676.       t++;
  677.     }
  678.   }
  679.   
  680.   return 0;
  681. }
  682.  
  683. int CEXEBuild::write_output(void)
  684. {
  685.   if (has_called_write_output)
  686.   {
  687.     printf("Error (write_output): write_output already called, can't continue\n");
  688.     return PS_ERROR;
  689.   }
  690.   has_called_write_output++;
  691.   if (!build_output_filename[0])
  692.   {
  693.     printf("Error: invalid script: never had OutFile command\n");
  694.     return PS_ERROR;
  695.   }
  696.  
  697.   {
  698.     int ns=build_sections.getlen()/sizeof(section);
  699.     if (!ns)
  700.     {
  701.       printf("Error: invalid script: no sections specified\n");
  702.       return PS_ERROR;
  703.     }
  704.  
  705.     if ((build_header.componenttext_ptr < 0 ||
  706.         !build_strlist.get()[build_header.componenttext_ptr]) &&
  707.         ns > 1 &&
  708.         !build_header.silent_install
  709.         )
  710.     {
  711.       section *s=(section*)build_sections.get();
  712.       while (ns--)
  713.       {
  714.         s->default_state|=0x80000000;
  715.         s++;
  716.       }
  717.       printf("Component Page disabled, making all sections enabled by default\n");
  718.     }
  719.   }
  720.   if (!build_entries.getlen())
  721.   {
  722.     printf("Error: invalid script: no entries specified\n");
  723.     return PS_ERROR;
  724.   }
  725.  
  726.   if (build_header.name_ptr < 0)
  727.   {
  728.     warning("Name command not specified. Assuming default.");
  729.     build_header.name_ptr=add_string_main("Name");
  730.     build_uninst.name_ptr=add_string_uninst("Name");
  731.   }
  732.  
  733. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  734.   if (ubuild_entries.getlen() && build_header.uninstall_exe_name_ptr < 0)
  735.   {
  736.     warning("Uninstall turned on but UninstallExeName command not specified. Assuming default.");
  737.     build_header.uninstall_exe_name_ptr=add_string_main("nsuninst.exe");
  738.   }
  739. #endif
  740.  
  741.   if (build_cursection || uninstall_mode)
  742.   {
  743.     printf("Error: Section left open at EOF\n");
  744.     return PS_ERROR;
  745.   }
  746.   
  747.   // deal with functions, for both install and uninstall modes.
  748.   if (build_cursection_isfunc)
  749.   {
  750.     printf("Error: Function still open at EOF, cannot proceed\n");
  751.     return 1;
  752.   }
  753.   set_uninstall_mode(1);
  754.   if (resolve_functions("uninstall")) return PS_ERROR;
  755.   set_uninstall_mode(0);
  756.  
  757.   if (resolve_function("install callback",ns_func.find(".onInit",0),build_header.code_onInit)) return PS_ERROR;
  758.   if (resolve_function("install callback",ns_func.find(".onInstSuccess",0),build_header.code_onInstSuccess)) return PS_ERROR;
  759.   if (resolve_function("install callback",ns_func.find(".onInstFailed",0),build_header.code_onInstFailed)) return PS_ERROR;
  760.   if (resolve_function("install callback",ns_func.find(".onUserAbort",0),build_header.code_onUserAbort)) return PS_ERROR;
  761.   if (resolve_function("install callback",ns_func.find(".onVerifyInstDir",0),build_header.code_onVerifyInstDir)) return PS_ERROR;
  762.   
  763.   if (resolve_functions("install")) return PS_ERROR;
  764.  
  765.  
  766.   if (build_header.caption_ptr < 0)
  767.   {
  768.     char buf[1024];
  769.     wsprintf(buf,"%s Setup",build_strlist.get()+build_header.name_ptr);
  770.     build_header.caption_ptr=add_string_main(buf);
  771.   }
  772.  
  773.   if (build_packname[0] && build_packcmd[0])
  774.   {
  775.     FILE *tmpfile=fopen(build_packname,"wb");
  776.     if (!tmpfile)
  777.     {
  778.       printf("Error: writing temporary file \"%s\" for pack\n",build_packname);
  779.       return PS_ERROR;
  780.     }
  781.     fwrite(header_data_new,1,exeheader_size_new,tmpfile);
  782.     fclose(tmpfile);
  783.     if (system(build_packcmd) == -1)
  784.     {
  785.       remove(build_packname);
  786.       printf("Error: calling packer on \"%s\"\n",build_packname);
  787.       return PS_ERROR;
  788.     }
  789.     tmpfile=fopen(build_packname,"rb");
  790.     if (!tmpfile)
  791.     {
  792.       remove(build_packname);
  793.       printf("Error: reading temporary file \"%s\" after pack\n",build_packname);
  794.       return PS_ERROR;
  795.     }
  796.     fseek(tmpfile,0,SEEK_END);
  797.     exeheader_size_new=ftell(tmpfile);
  798.     exeheader_size_new+=511;
  799.     exeheader_size_new&=~511; // align to 512.
  800.     fseek(tmpfile,0,SEEK_SET);
  801.     unsigned char *header_data_older=header_data_new;
  802.     header_data_new=(unsigned char *)malloc(exeheader_size_new);
  803.     if (!header_data_new)
  804.     {
  805.       free(header_data_older);
  806.       fclose(tmpfile);
  807.       printf("Error: malloc(%d) failed (exepack)\n",exeheader_size_new);
  808.       return PS_ERROR;
  809.     }
  810.     memset(header_data_new,0,exeheader_size_new);
  811.     fread(header_data_new,1,exeheader_size_new,tmpfile);
  812.     fclose(tmpfile);
  813.     remove(build_packname);
  814.  
  815.     printf("Locating install icon after compress: ");
  816.     icon_offset = find_data_offset((char*)header_data_new,exeheader_size_new,
  817.                      (char*)header_data_older+icon_offset,ICO_HDRSKIP,sizeof(icon_data));
  818.     free(header_data_older);
  819.     if (icon_offset < 0)
  820.     {
  821.       return PS_ERROR;
  822.     }
  823.     printf("found at offset %d\n",icon_offset);
  824.     // write out exe header, pack, read back in, align to 512, and
  825.     // update the header info
  826.   }
  827.  
  828.   build_optimize_datablock=0;
  829.  
  830.   if (uninstall_generate() != PS_OK) 
  831.   {
  832.     return PS_ERROR;
  833.   }
  834.  
  835.   int crc=0;
  836.  
  837.   printf("\n");
  838.   printline(79);
  839.  
  840.   printf("Output: \"%s\"\n",build_output_filename);
  841.   FILE *fp = fopen(build_output_filename,"wb");
  842.   if (!fp) 
  843.   {
  844.     perror("Can't open output file");
  845.     return PS_ERROR;
  846.   }
  847.  
  848.   if ((int)fwrite(header_data_new,1,exeheader_size_new,fp) != exeheader_size_new)
  849.   {
  850.     printf("Error: can't write %d bytes to output\n",exeheader_size_new);
  851.     fclose(fp);
  852.     return PS_ERROR;
  853.   }
  854.   crc=adler32(crc,header_data_new,exeheader_size_new);
  855.  
  856.   firstheader fh={0,};
  857.   fh.nsinst[0]=FH_INT1;
  858.   fh.nsinst[1]=FH_INT2;
  859.   fh.nsinst[2]=FH_INT3;
  860.   fh.flags=(build_crcchk?FH_FLAGS_CRC:0);
  861.   if (build_header.silent_install) fh.flags |= FH_FLAGS_SILENT;
  862.   fh.siginfo=FH_SIG;
  863.  
  864.   int installinfo_compressed;
  865.   {
  866.     GrowBuf hdrcomp;
  867.     hdrcomp.add(&build_header,sizeof(build_header)); 
  868.     hdrcomp.add(build_sections.get(),build_sections.getlen()); 
  869.     hdrcomp.add(build_entries.get(),build_entries.getlen());
  870.     hdrcomp.add(build_strlist.get(),build_strlist.getlen());
  871.  
  872.     installinfo_compressed=-build_datablock.getlen();
  873.     fh.header_ptr = add_data((char*)hdrcomp.get(),hdrcomp.getlen());
  874.     installinfo_compressed+=build_datablock.getlen()-sizeof(int);
  875.  
  876.  
  877.     fh.length_of_header=hdrcomp.getlen();
  878.     if (fh.header_ptr < 0) return PS_ERROR;
  879.   }
  880.  
  881.   fh.length_of_all_following_data=build_datablock.getlen()+(int)sizeof(firstheader)+(build_crcchk?sizeof(int):0);
  882.  
  883.   int do_padding=0;
  884.   if (build_crcchk && fh.length_of_all_following_data < 516)
  885.   {
  886.     do_padding=516-fh.length_of_all_following_data;
  887.     fh.length_of_all_following_data=516;
  888.   }
  889.  
  890.   if (fwrite(&fh,1,sizeof(fh),fp) != sizeof(fh))
  891.   {
  892.     printf("Error: can't write %d bytes to output\n",sizeof(fh));
  893.     fclose(fp);
  894.     return PS_ERROR;
  895.   }
  896.   crc=adler32(crc,(unsigned char*)&fh,sizeof(fh));
  897.  
  898.   {
  899.     int ns=build_sections.getlen()/sizeof(section);
  900.     section *s=(section*)build_sections.get();
  901.     int x;
  902.     int req=1;
  903.     int div=0;
  904.     int divptr=build_strlist.find("-",2);
  905.     for (x = 1; x < ns; x ++)
  906.     {
  907.       if (s[x].name_ptr == divptr) div++;
  908.       if (s[x].name_ptr == -1)  req++;
  909.     }
  910.     printf("Install: %d section%s",ns,ns==1?"":"s");
  911.     if (req||div) 
  912.     {
  913.       printf(" (");
  914.       if (req) 
  915.       {
  916.         printf("%d required",req);
  917.         if (div) printf(", ");
  918.       }
  919.       if (div) printf("%d divider%s",div,div==1?"":"s");
  920.       printf(")");
  921.     }
  922.     printf(".\n");
  923.   }
  924.   int ne=build_entries.getlen()/sizeof(entry);
  925.   printf("Install: %d instruction%s, ",ne,ne==1?"":"s");
  926.   printf("%d byte string table.\n",build_strlist.getlen());
  927.   if (ubuild_entries.getlen()) 
  928.   {
  929.     int tmp=ubuild_entries.getlen()/sizeof(entry);
  930.     printf("Uninstall: ");
  931.     printf("%d instruction%s, ",tmp,tmp==1?"":"s");
  932.     printf("%d byte string table.\n",ubuild_strlist.getlen());
  933.   }
  934.  
  935.  
  936.   if (db_opt_save) 
  937.   {
  938.     int total_out_size_estimate=
  939.       exeheader_size_new+sizeof(fh)+build_datablock.getlen()+(build_crcchk?4:0);
  940.     int pc=MulDiv(db_opt_save,1000,db_opt_save+total_out_size_estimate);
  941.     printf("Datablock optimizer saved %d bytes (~%d.%d%%).\n",db_opt_save,
  942.       pc/10,pc%10);
  943.   }
  944.  
  945.   printf("\n");
  946.   int total_usize=exeheader_size;
  947.  
  948.   printf("EXE header size:        %10d / %d bytes\n",exeheader_size_new,exeheader_size);
  949.  
  950.   printf("Install code+strings:   %10d / %d bytes\n",
  951.     sizeof(fh)+installinfo_compressed+sizeof(int),
  952.     sizeof(fh)+fh.length_of_header+sizeof(int)); 
  953.  
  954.   total_usize+=sizeof(fh)+fh.length_of_header+sizeof(int);
  955.  
  956.   {
  957.     int dbsize, dbsizeu;
  958.     dbsize = build_datablock.getlen()-installinfo_compressed - sizeof(int);
  959.     if (uninstall_size>0) dbsize-=uninstall_size;
  960.  
  961.     dbsizeu = db_full_size-fh.length_of_header - sizeof(int) - uninstall_size_full;
  962.  
  963.     printf("Install data:           %10d / %d bytes\n",dbsize,dbsizeu);
  964.     total_usize+=dbsizeu;
  965.   }
  966.  
  967.  
  968.   if (build_datablock.getlen())
  969.   {
  970.     char *dbptr=(char *)build_datablock.get();
  971.     int dbl=build_datablock.getlen();
  972.     while (dbl > 0)
  973.     {
  974.       int l=dbl;
  975.       if (l > 32768) l=32768;
  976.       crc=adler32(crc,(unsigned char *)dbptr,l);
  977.       if ((int)fwrite(dbptr,1,l,fp) != l)
  978.       {
  979.         printf("Error: can't write %d bytes to output\n",l);
  980.         fclose(fp);
  981.         return PS_ERROR;
  982.       }
  983.       dbptr+=l;
  984.       dbl-=l;
  985.     }
  986.   }
  987.  
  988.   if (uninstall_size>=0) 
  989.   {
  990.     printf("Uninstall code+data+strings:%6d / %d bytes\n",uninstall_size,uninstall_size_full);
  991.     total_usize+=uninstall_size_full;
  992.   }
  993.   if (do_padding)
  994.   {
  995.     unsigned char buf[516];
  996.     memset(buf,0,sizeof(buf));
  997.     if ((int)fwrite(buf,1,do_padding,fp) != do_padding)
  998.     {
  999.       printf("Error: can't write %d bytes to output\n",do_padding);
  1000.       fclose(fp);
  1001.       return PS_ERROR;
  1002.     }
  1003.     crc=adler32(crc,buf,do_padding);
  1004.     printf("Padding:                  %8d / %d bytes\n",do_padding,do_padding);
  1005.     total_usize+=do_padding;
  1006.   }
  1007.  
  1008.   if (build_crcchk) 
  1009.   {
  1010.     total_usize+=sizeof(int);
  1011.     if (fwrite(&crc,1,sizeof(int),fp) != sizeof(int))
  1012.     {
  1013.       printf("Error: can't write %d bytes to output\n",sizeof(int));
  1014.       fclose(fp);
  1015.       return PS_ERROR;
  1016.     }
  1017.     printf("CRC (0x%08X):                4 / 4 bytes\n",crc);
  1018.   }
  1019.   printline(57);
  1020.   {
  1021.     int pc=MulDiv(ftell(fp),1000,total_usize);
  1022.     printf("Total size:             %10d / %d bytes (%d.%d%%)\n",ftell(fp),total_usize,pc/10,pc%10);
  1023.   }
  1024.   fclose(fp);
  1025.   print_warnings();
  1026.   return PS_OK;
  1027. }
  1028.  
  1029.  
  1030. int CEXEBuild::uninstall_generate()
  1031. {
  1032. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1033.   if (ubuild_entries.getlen()) 
  1034.   {
  1035.     firstheader fh={0,};
  1036.  
  1037.     // add one more bit (the code+strtabs) to the uninstall datablock
  1038.     {
  1039.       GrowBuf udata;
  1040.  
  1041.       udata.add(&build_uninst,sizeof(build_uninst));
  1042.       udata.add(ubuild_entries.get(),ubuild_entries.getlen());
  1043.       udata.add(ubuild_strlist.get(),ubuild_strlist.getlen()); 
  1044.     
  1045.       set_uninstall_mode(1);
  1046.       fh.length_of_header=udata.getlen();
  1047.       fh.header_ptr=add_data((char*)udata.get(),udata.getlen());      
  1048.       set_uninstall_mode(0);
  1049.       if (fh.header_ptr < 0) return PS_ERROR;
  1050.     }
  1051.         
  1052.     int crc=0;
  1053.  
  1054.     build_header.uninstdata_offset=build_datablock.getlen();
  1055.     build_header.uninstexehead_iconoffset = icon_offset+ICO_HDRSKIP;
  1056.  
  1057.     if (add_data((char *)m_unicon_data+ICO_HDRSKIP,766-ICO_HDRSKIP) < 0)
  1058.       return PS_ERROR;
  1059.     crc=adler32(crc,header_data_new,icon_offset+ICO_HDRSKIP);
  1060.     crc=adler32(crc,m_unicon_data+ICO_HDRSKIP,766-ICO_HDRSKIP);
  1061.     crc=adler32(crc,header_data_new+icon_offset+766,exeheader_size_new-766-icon_offset);
  1062.  
  1063.     fh.nsinst[0]=FH_INT1;
  1064.     fh.nsinst[1]=FH_INT2;
  1065.     fh.nsinst[2]=FH_INT3;
  1066.     fh.flags = FH_FLAGS_UNINSTALL | (build_crcchk?FH_FLAGS_CRC:0);
  1067.     fh.siginfo=FH_SIG;
  1068.     fh.length_of_all_following_data=
  1069.       ubuild_datablock.getlen()+(int)sizeof(firstheader)+(build_crcchk?sizeof(int):0);
  1070.  
  1071.     if (build_crcchk && fh.length_of_all_following_data < 516)
  1072.     {
  1073.       fh.length_of_all_following_data=516;
  1074.     }
  1075.  
  1076.     GrowBuf udata;
  1077.     udata.add(&fh,sizeof(fh));
  1078.     udata.add(ubuild_datablock.get(),ubuild_datablock.getlen());
  1079.  
  1080.     if (build_crcchk)
  1081.     {
  1082.       if (udata.getlen() < 512)
  1083.       {
  1084.         char buf[512];
  1085.         memset(buf,0,512);
  1086.         udata.add(buf,512-udata.getlen());
  1087.       }
  1088.       int s=adler32(crc,(unsigned char*)udata.get(),udata.getlen());
  1089.       udata.add(&s,sizeof(int));
  1090.     }
  1091.  
  1092.     if (add_data((char*)udata.get(),fh.length_of_all_following_data) < 0) 
  1093.       return PS_ERROR;
  1094.  
  1095.     uninstall_size_full=fh.length_of_all_following_data + sizeof(int) + 766 - 32 + sizeof(int);
  1096.  
  1097.     // compressed size
  1098.     uninstall_size=build_datablock.getlen()-build_header.uninstdata_offset;
  1099.   }
  1100. #endif
  1101.   return PS_OK;
  1102. }
  1103.  
  1104.  
  1105. #define SWAP(x,y,i) { i _ii; _ii=x; x=y; y=_ii; }
  1106.  
  1107. void CEXEBuild::set_uninstall_mode(int un)
  1108. {
  1109.   if (un != uninstall_mode)
  1110.   {
  1111.     uninstall_mode=un;
  1112.     if (un) cur_datablock=&ubuild_datablock;
  1113.     else cur_datablock=&build_datablock;
  1114.     if (un) cur_entries=&ubuild_entries;
  1115.     else cur_entries=&build_entries;
  1116.     if (un) cur_functions=&ubuild_functions;
  1117.     else cur_functions=&build_functions;
  1118.     if (un) cur_labels=&ubuild_labels;
  1119.     else cur_labels=&build_labels;
  1120.  
  1121.     SWAP(db_opt_save_u,db_opt_save,int);
  1122.     SWAP(db_comp_save_u,db_comp_save,int);
  1123.     SWAP(db_full_size_u,db_full_size,int);
  1124.   }
  1125. }
  1126.  
  1127. void CEXEBuild::warning(char *s, ...)
  1128. {
  1129.   char buf[4096];
  1130.   va_list val;
  1131.   va_start(val,s);
  1132.   vsprintf(buf,s,val);
  1133.   va_end(val);
  1134.   m_warnings.add(buf,-1);
  1135.   printf("warning: %s\n",buf);
  1136. }
  1137.  
  1138. void CEXEBuild::print_warnings()
  1139. {
  1140.   int nw=0,x=m_warnings.getlen();
  1141.   if (!x) return;
  1142.   char *p=m_warnings.get();
  1143.   while (x>0) if (!p[--x]) nw++;
  1144.   printf("\n%d warning%s:\n",nw,nw==1?"":"s");
  1145.   for (x = 0; x < nw; x ++)
  1146.   {
  1147.     printf("  %s\n",p);
  1148.     p+=strlen(p)+1;
  1149.   }
  1150. }