diff --git a/Source/ResourceEditor.cpp b/Source/ResourceEditor.cpp index 111df70d..1e2e6659 100644 --- a/Source/ResourceEditor.cpp +++ b/Source/ResourceEditor.cpp @@ -274,8 +274,10 @@ BYTE* CResourceEditor::Save(DWORD &dwSize) { // Refresh the headers of the sections that come after the resource section, and the data directory for (i++; i < ntHeaders->FileHeader.NumberOfSections; i++) { - sectionHeadersArray[i].PointerToRawData -= IMAGE_FIRST_SECTION(m_ntHeaders)[m_dwResourceSectionIndex].SizeOfRawData; - sectionHeadersArray[i].PointerToRawData += dwRsrcSizeAligned; + if ( sectionHeadersArray[i].PointerToRawData ) { + sectionHeadersArray[i].PointerToRawData -= IMAGE_FIRST_SECTION(m_ntHeaders)[m_dwResourceSectionIndex].SizeOfRawData; + sectionHeadersArray[i].PointerToRawData += dwRsrcSizeAligned; + } int secInDataDir = 0; for (unsigned int j = 0; j < ntHeaders->OptionalHeader.NumberOfRvaAndSizes; j++) if (ntHeaders->OptionalHeader.DataDirectory[j].VirtualAddress == sectionHeadersArray[i].VirtualAddress) @@ -325,6 +327,36 @@ BYTE* CResourceEditor::Save(DWORD &dwSize) { return pbNewPE; } +// This function scans exe sections and after find a match with given name +// increments it's virtual size (auto fixes image size based on section alignment, etc) +bool CResourceEditor::AddExtraVirtualSize2PESection(const char* pszSectionName, int addsize) +{ + PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders); + + // Refresh the headers of the sections that come after the resource section, and the data directory + for (int i =0; i < m_ntHeaders->FileHeader.NumberOfSections; i++) { + if ( !strcmp((LPCSTR)sectionHeadersArray[i].Name, pszSectionName) ) { + sectionHeadersArray[i].Misc.VirtualSize += addsize; + sectionHeadersArray[i].Characteristics &= ~IMAGE_SCN_MEM_DISCARDABLE; + sectionHeadersArray[i].Misc.VirtualSize = RALIGN(sectionHeadersArray[i].Misc.VirtualSize, m_ntHeaders->OptionalHeader.SectionAlignment); + // now fix any section after + for (int k=i+1; k< m_ntHeaders->FileHeader.NumberOfSections; k++, i++) { + sectionHeadersArray[k].VirtualAddress = sectionHeadersArray[i].VirtualAddress + sectionHeadersArray[i].Misc.VirtualSize; + sectionHeadersArray[k].VirtualAddress = RALIGN(sectionHeadersArray[k].VirtualAddress, m_ntHeaders->OptionalHeader.SectionAlignment); + if ( m_dwResourceSectionIndex == k ) + { + // fix the resources virtual address if it changed + m_dwResourceSectionVA = m_ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = sectionHeadersArray[k].VirtualAddress; + } + } + + return true; + } + } + + return false; +} + ////////////////////////////////////////////////////////////////////// // Private Methods ////////////////////////////////////////////////////////////////////// diff --git a/Source/ResourceEditor.h b/Source/ResourceEditor.h index 09696693..65b84d71 100644 --- a/Source/ResourceEditor.h +++ b/Source/ResourceEditor.h @@ -68,6 +68,7 @@ public: bool UpdateResource(WORD szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); BYTE* GetResource(char* szType, char* szName, LANGID wLanguage); + bool AddExtraVirtualSize2PESection(const char* pszSectionName, int addsize); BYTE* Save(DWORD &dwSize); private: diff --git a/Source/build.cpp b/Source/build.cpp index ac7d3d4c..415790b9 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -351,52 +351,53 @@ CEXEBuild::CEXEBuild() build_header.license_bg=-COLOR_BTNFACE; #ifdef NSIS_SUPPORT_NAMED_USERVARS - // Register user variables $0, $1 and so one + // Register static user variables $0, $1 and so one + // with ONE of reference count, to avoid warning on this vars char Aux[3]; for ( int i = 0; i < 10; i++ ) // 0 - 9 { sprintf(Aux, "%d", i); - m_UserVarNames.add(Aux); - m_UnUserVarNames.add(Aux); + m_UserVarNames.add(Aux,1); + m_UnUserVarNames.add(Aux,1); } for ( i = 0; i < 10; i++ ) // 10 - 19 { sprintf(Aux, "R%d", i); - m_UserVarNames.add(Aux); - m_UnUserVarNames.add(Aux); + m_UserVarNames.add(Aux,1); + m_UnUserVarNames.add(Aux,1); } - m_UserVarNames.add("CMDLINE"); // 20 everything before here doesn't have trailing slash removal - m_UnUserVarNames.add("CMDLINE"); - m_UserVarNames.add("INSTDIR"); // 21 - m_UnUserVarNames.add("INSTDIR"); - m_UserVarNames.add("OUTDIR"); // 22 - m_UnUserVarNames.add("OUTDIR"); - m_UserVarNames.add("EXEDIR"); // 23 - m_UnUserVarNames.add("EXEDIR"); - m_UserVarNames.add("LANGUAGE"); // 24 - m_UnUserVarNames.add("LANGUAGE"); - m_UserVarNames.add("PLUGINSDIR"); // 25 - m_UnUserVarNames.add("PLUGINSDIR"); - m_UserVarNames.add("PROGRAMFILES"); // 26 - m_UnUserVarNames.add("PROGRAMFILES"); - m_UserVarNames.add("SMPROGRAMS"); // 27 - m_UnUserVarNames.add("SMPROGRAMS"); - m_UserVarNames.add("SMSTARTUP"); // 28 - m_UnUserVarNames.add("SMSTARTUP"); - m_UserVarNames.add("DESKTOP"); // 29 - m_UnUserVarNames.add("DESKTOP"); - m_UserVarNames.add("STARTMENU"); // 30 - m_UnUserVarNames.add("STARTMENU"); - m_UserVarNames.add("QUICKLAUNCH"); // 31 - m_UnUserVarNames.add("QUICKLAUNCH"); - m_UserVarNames.add("TEMP"); // 32 - m_UnUserVarNames.add("TEMP"); - m_UserVarNames.add("WINDIR"); // 33 - m_UnUserVarNames.add("WINDIR"); - m_UserVarNames.add("SYSDIR"); // 34 everything after here doesn't have trailing slash removal - m_UnUserVarNames.add("SYSDIR"); - m_UserVarNames.add("HWNDPARENT"); // 35 - m_UnUserVarNames.add("HWNDPARENT"); + m_UserVarNames.add("CMDLINE",1); // 20 everything before here doesn't have trailing slash removal + m_UnUserVarNames.add("CMDLINE",1); + m_UserVarNames.add("INSTDIR",1); // 21 + m_UnUserVarNames.add("INSTDIR",1); + m_UserVarNames.add("OUTDIR",1); // 22 + m_UnUserVarNames.add("OUTDIR",1); + m_UserVarNames.add("EXEDIR",1); // 23 + m_UnUserVarNames.add("EXEDIR",1); + m_UserVarNames.add("LANGUAGE",1); // 24 + m_UnUserVarNames.add("LANGUAGE",1); + m_UserVarNames.add("PLUGINSDIR",1); // 25 + m_UnUserVarNames.add("PLUGINSDIR",1); + m_UserVarNames.add("PROGRAMFILES",1); // 26 + m_UnUserVarNames.add("PROGRAMFILES",1); + m_UserVarNames.add("SMPROGRAMS",1); // 27 + m_UnUserVarNames.add("SMPROGRAMS",1); + m_UserVarNames.add("SMSTARTUP",1); // 28 + m_UnUserVarNames.add("SMSTARTUP",1); + m_UserVarNames.add("DESKTOP",1); // 29 + m_UnUserVarNames.add("DESKTOP",1); + m_UserVarNames.add("STARTMENU",1); // 30 + m_UnUserVarNames.add("STARTMENU",1); + m_UserVarNames.add("QUICKLAUNCH",1); // 31 + m_UnUserVarNames.add("QUICKLAUNCH",1); + m_UserVarNames.add("TEMP",1); // 32 + m_UnUserVarNames.add("TEMP",1); + m_UserVarNames.add("WINDIR",1); // 33 + m_UnUserVarNames.add("WINDIR",1); + m_UserVarNames.add("SYSDIR",1); // 34 everything after here doesn't have trailing slash removal + m_UnUserVarNames.add("SYSDIR",1); + m_UserVarNames.add("HWNDPARENT",1); // 35 + m_UnUserVarNames.add("HWNDPARENT",1); #endif } @@ -544,11 +545,14 @@ int CEXEBuild::preprocess_string(char *out, const char *in) while ( pUserVarName > p ) { - const char * Debug = p-(pUserVarName-p); - int idxUserVar = uninstall_mode ? m_UnUserVarNames.get((char*)p, pUserVarName-p) : m_UserVarNames.get((char*)p, pUserVarName-p); if ( idxUserVar >= 0 ) { + // Well, using variables inside string formating doens't mean + // using the variable, beacuse it will be always an empty string + // which is also memory wasting + // So the line below must be commented !?? + //uninstall_mode ? m_UnUserVarNames.inc_reference(idxUserVar): m_UserVarNames.inc_reference(idxUserVar); *out++=(unsigned int)VAR_CODES_START; // Named user variable; *(WORD*)out=((WORD)idxUserVar+1) | 0xF000; out += sizeof(WORD); @@ -1868,9 +1872,20 @@ int CEXEBuild::write_output(void) // Generate language tables if (WriteStringTables() == PS_ERROR) return PS_ERROR; +#ifdef NSIS_SUPPORT_NAMED_USERVARS + VerifyDeclaredUserVarRefs(&m_UserVarNames); + VerifyDeclaredUserVarRefs(&m_UnUserVarNames); + int MaxUserVars = max(m_UserVarNames.getnum(), m_UnUserVarNames.getnum()); + if (!res_editor->AddExtraVirtualSize2PESection(VARS_SECTION_NAME, (MaxUserVars-TOTAL_COMPATIBLE_STATIC_VARS_COUNT) * sizeof(NSIS_STRING))) + { + ERROR_MSG("Internal compiler error #12346: invalid exehead cannot find section \"%s\"!\n", VARS_SECTION_NAME); + return PS_ERROR; + } +#endif + // Save all changes to the exe header try { - close_res_editor(); + close_res_editor(); } catch (exception& err) { ERROR_MSG("\nError: %s\n", err.what()); @@ -2017,9 +2032,6 @@ int CEXEBuild::write_output(void) installinfo_compressed=ihd.getlen(); fh.length_of_header=hdrcomp.getlen(); -#ifdef NSIS_SUPPORT_NAMED_USERVARS - fh.length_of_uservars=m_UserVarNames.getnum()*sizeof(NSIS_STRING); -#endif } @@ -2306,9 +2318,6 @@ int CEXEBuild::uninstall_generate() set_uninstall_mode(1); fh.length_of_header=udata.getlen(); -#ifdef NSIS_SUPPORT_NAMED_USERVARS - fh.length_of_uservars=m_UnUserVarNames.getnum()*sizeof(NSIS_STRING); -#endif int err=add_data((char*)udata.get(),udata.getlen(),&uhd); set_uninstall_mode(0); if (err < 0) return PS_ERROR; @@ -2738,11 +2747,13 @@ int CEXEBuild::GetUserVarIndex(LineParser &line, int token) #ifdef NSIS_SUPPORT_NAMED_USERVARS char *p = line.gettoken_str(token); + UserVarsStringList *pUserVarList = uninstall_mode ? &m_UnUserVarNames : &m_UserVarNames; if ( *p == '$' && *(p+1) ) { - int idxUserVar = uninstall_mode ? m_UnUserVarNames.get((char *)p+1) : m_UserVarNames.get((char *)p+1); + int idxUserVar = pUserVarList->get((char *)p+1); if ( idxUserVar >= 0 ) { + pUserVarList->inc_reference(idxUserVar); return idxUserVar; } else @@ -2772,3 +2783,16 @@ int CEXEBuild::GetUserVarIndex(LineParser &line, int token) return line.gettoken_enum(token, usrvars); #endif } + +#ifdef NSIS_SUPPORT_NAMED_USERVARS +void CEXEBuild::VerifyDeclaredUserVarRefs(UserVarsStringList *pVarsStringList) +{ + for ( int i = TOTAL_COMPATIBLE_STATIC_VARS_COUNT; i < pVarsStringList->getnum(); i++ ) + { + if ( !pVarsStringList->get_reference(i) ) + { + warning("Variable \"%s\" not referenced, wasting memory!", pVarsStringList->idx2name(i)); + } + } +} +#endif \ No newline at end of file diff --git a/Source/build.h b/Source/build.h index ee78da5c..4c0e4ade 100644 --- a/Source/build.h +++ b/Source/build.h @@ -202,6 +202,7 @@ class CEXEBuild { UserVarsStringList m_UserVarNames; UserVarsStringList m_UnUserVarNames; int DeclaredUserVar(const char *VarName); + void VerifyDeclaredUserVarRefs(UserVarsStringList *pVarsStringList); #endif // a whole bunch O data. diff --git a/Source/exehead/Main.c b/Source/exehead/Main.c index ae9163f8..50defde6 100644 --- a/Source/exehead/Main.c +++ b/Source/exehead/Main.c @@ -108,7 +108,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpszCmdParam, InitCommonControls(); - GetTempPath(sizeof(temp_directory), temp_directory); + GetTempPath(sizeof(state_temp_dir), state_temp_dir); + CreateDirectory(state_temp_dir,NULL); lstrcpyn(state_command_line,GetCommandLine(),NSIS_MAX_STRLEN); @@ -308,7 +309,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpszCmdParam, static char ibuf[NSIS_MAX_STRLEN]; buf2[0]='\"'; - mystrcpy(buf2+1,temp_directory); + mystrcpy(buf2+1,state_temp_dir); lstrcat(buf2,s); DeleteFile(buf2+1); // clean up after all the other ones if they are there @@ -334,7 +335,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpszCmdParam, lstrcat(buf2,realcmds); lstrcat(buf2," _?="); lstrcat(buf2,ibuf); - hProc=myCreateProcess(buf2,temp_directory); + hProc=myCreateProcess(buf2,state_temp_dir); if (hProc) CloseHandle(hProc); else m_Err = g_errorcopyinginstall; } diff --git a/Source/exehead/config.h b/Source/exehead/config.h index 884f5fbb..c24dcfdd 100644 --- a/Source/exehead/config.h +++ b/Source/exehead/config.h @@ -26,16 +26,6 @@ // really a big deal, but not usually needed). #define NSIS_MAX_STRLEN 1024 -#define USER_VARS_COUNT 26 - -typedef char NSIS_STRING[NSIS_MAX_STRLEN]; - -// MAX_NAMED_USER_VARS defines the maximum of named user variables -// the complier also use this value to abort if exceded -// The real maximum is (0x0FFF - USER_VARS_COUNT) = 4069 -// But 500 variables are a more than enough (and only consume more 512kb of memory) -#define MAX_NAMED_USER_VARS 500 - // NSIS_MAX_INST_TYPES specified the maximum install types. // note that this should not exceed 32, ever. #define NSIS_MAX_INST_TYPES 32 @@ -364,6 +354,26 @@ typedef char NSIS_STRING[NSIS_MAX_STRLEN]; #define NSIS_SUPPORT_STANDARD_PREDEFINES #endif +// This is the old static var count that occupies memory +// From $0 to $PLUGINSDIR +#define USER_VARS_COUNT 26 + +#ifdef NSIS_SUPPORT_NAMED_USERVARS +// This is the total number of old static var +// From $0 to $HWNDPARENT +#define TOTAL_COMPATIBLE_STATIC_VARS_COUNT 36 + +#define VARS_SECTION_NAME ".ndata" + +typedef char NSIS_STRING[NSIS_MAX_STRLEN]; + +// MAX_NAMED_USER_VARS defines the maximum of named user variables +// the complier also use this value to abort if exceded +// The real maximum is (0x0FFF - USER_VARS_COUNT) = 4068 +#define MAX_NAMED_USER_VARS (0x0FFF - USER_VARS_COUNT) + +#endif //NSIS_SUPPORT_NAMED_USERVARS + #endif//!APSTUDIO_INVOKED #endif // NSIS_CONFIG_H diff --git a/Source/exehead/exec.c b/Source/exehead/exec.c index 86190e17..35af1e32 100644 --- a/Source/exehead/exec.c +++ b/Source/exehead/exec.c @@ -367,7 +367,7 @@ static int NSISCALL ExecuteEntry(entry *entry_) int n=100; while (n--) { - if (GetTempFileName(temp_directory,"nst",0,textout)) + if (GetTempFileName(state_temp_dir,"nst",0,textout)) return 0; } g_flags.exec_error++; @@ -1443,7 +1443,7 @@ static int NSISCALL ExecuteEntry(entry *entry_) filebuf=(unsigned char *)my_GlobalAlloc(g_filehdrsize); if (filebuf) { - int fixoffs=0; + //int fixoffs=0; DWORD lout; SetSelfFilePointer(0,FILE_BEGIN); ReadSelfFile((char*)filebuf,g_filehdrsize); diff --git a/Source/exehead/fileform.c b/Source/exehead/fileform.c index cea93088..62b8da35 100644 --- a/Source/exehead/fileform.c +++ b/Source/exehead/fileform.c @@ -52,17 +52,7 @@ int NSISCALL isheader(firstheader *h) #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT static z_stream g_inflate_stream; #endif -/* -void DEBUG(const char* Frm, ...) -{ - char Buf[1024]; - va_list va; - va_start(va, Frm); - wvsprintf(Buf, Frm, va); - MessageBox(0, Buf, 0, 0); - va_end(va); -} -*/ + const char * NSISCALL loadHeaders(void) { void *data; @@ -70,13 +60,7 @@ const char * NSISCALL loadHeaders(void) if (!ReadSelfFile((LPVOID)&h,sizeof(h)) || !isheader(&h)) return _LANG_INVALIDCRC; -#ifdef NSIS_SUPPORT_NAMED_USERVARS - //DEBUG("Needed size is : %i", h.length_of_header + h.length_of_uservars); - g_usrvars = (NSIS_STRING*)GlobalReAlloc(g_usrvars, h.length_of_header + h.length_of_uservars, GMEM_MOVEABLE); - data = (void*)(g_usrvars[0]+h.length_of_uservars); -#else data=(void*)my_GlobalAlloc(h.length_of_header); -#endif #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT inflateInit(&g_inflate_stream); @@ -86,7 +70,7 @@ const char * NSISCALL loadHeaders(void) { char fno[MAX_PATH]; - GetTempFileName(temp_directory,"nst",0,fno); + GetTempFileName(state_temp_dir,"nst",0,fno); dbd_hFile=CreateFile(fno,GENERIC_WRITE|GENERIC_READ,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,NULL); if (dbd_hFile == INVALID_HANDLE_VALUE) { diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index cd2a8e2c..1fedfd74 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -204,10 +204,6 @@ typedef struct // these point to the header+sections+entries+stringtable in the datablock int length_of_header; -#ifdef NSIS_SUPPORT_NAMED_USERVARS - // this store the sized needed to store all user vars - int length_of_uservars; -#endif // this specifies the length of all the data (including the firstheader and CRC) int length_of_all_following_data; diff --git a/Source/exehead/state.h b/Source/exehead/state.h index 6fa90a76..26089951 100644 --- a/Source/exehead/state.h +++ b/Source/exehead/state.h @@ -1,15 +1,16 @@ -extern char temp_directory[NSIS_MAX_STRLEN]; #ifdef NSIS_SUPPORT_NAMED_USERVARS - extern NSIS_STRING *g_usrvars; - #define state_command_line g_usrvars[20] - #define state_install_directory g_usrvars[21] - #define state_output_directory g_usrvars[22] - #define state_exe_directory g_usrvars[23] - #define state_language g_usrvars[24] + extern NSIS_STRING g_usrvars[TOTAL_COMPATIBLE_STATIC_VARS_COUNT]; + #define state_command_line g_usrvars[20] + #define state_install_directory g_usrvars[21] + #define state_output_directory g_usrvars[22] + #define state_exe_directory g_usrvars[23] + #define state_language g_usrvars[24] #ifdef NSIS_CONFIG_PLUGIN_SUPPORT - #define state_plugins_dir g_usrvars[25] + #define state_plugins_dir g_usrvars[25] #endif + #define state_temp_dir g_usrvars[32] #else + extern char temp_directory[NSIS_MAX_STRLEN]; extern char g_usrvars[USER_VARS_COUNT][NSIS_MAX_STRLEN]; extern char *state_command_line; extern char *state_install_directory; @@ -19,6 +20,7 @@ extern char temp_directory[NSIS_MAX_STRLEN]; #ifdef NSIS_CONFIG_PLUGIN_SUPPORT extern char *state_plugins_dir; #endif + #define state_temp_dir temp_directory #endif extern char g_caption[NSIS_MAX_STRLEN*2]; diff --git a/Source/exehead/util.c b/Source/exehead/util.c index 99be0b89..420235fb 100644 --- a/Source/exehead/util.c +++ b/Source/exehead/util.c @@ -14,10 +14,20 @@ char g_log_file[1024]; #endif -char temp_directory[NSIS_MAX_STRLEN]; #ifdef NSIS_SUPPORT_NAMED_USERVARS - NSIS_STRING *g_usrvars; + // *** DO NOT DECLARE MORE VARIABLES INSIDE THIS PRAGMAS *** + // This will produce a special section called ".ndata" (stands for nsis data) + // this way makensis during build time, can search for this section by name + // and change the virtual size of this section + // which result in extra memory for extra variables without code to do allocation :) + // nsis then removes the "DISCARDABLE" style from section (for safe) + #pragma bss_seg( VARS_SECTION_NAME ) + NSIS_STRING g_usrvars[TOTAL_COMPATIBLE_STATIC_VARS_COUNT]; + #pragma bss_seg() + #define SECTION_VARS_RWD "/section:" ## VARS_SECTION_NAME ## ",rwd" + #pragma comment(linker, SECTION_VARS_RWD) #else + char temp_directory[NSIS_MAX_STRLEN]; char g_usrvars[USER_VARS_COUNT][NSIS_MAX_STRLEN]; char *state_command_line=g_usrvars[20]; char *state_install_directory=g_usrvars[21]; @@ -580,7 +590,7 @@ char * NSISCALL process_string(const char *in) { f=0; goto again; } - mystrcpy(out,temp_directory); + mystrcpy(out,state_temp_dir); } if (nVarIdx == 31) { @@ -592,10 +602,6 @@ char * NSISCALL process_string(const char *in) else break; } - case 32: // TEMP - mystrcpy(out,temp_directory); - break; - case 33: // WINDIR GetWindowsDirectory(out, NSIS_MAX_STRLEN); break; @@ -612,7 +618,7 @@ char * NSISCALL process_string(const char *in) mystrcpy(out, g_usrvars[nVarIdx]); } // switch // validate the directory name - if (nVarIdx > 21 && nVarIdx < 36 ) { // only if not $0 to $R9, $CMDLINE, or $HWNDPARENT and not great than $SYSDIR + if (nVarIdx > 21 && nVarIdx < TOTAL_COMPATIBLE_STATIC_VARS_COUNT ) { // only if not $0 to $R9, $CMDLINE, or $HWNDPARENT and not great than $SYSDIR // ($LANGUAGE can't have trailing backslash anyway...) validate_filename(out); } diff --git a/Source/uservars.h b/Source/uservars.h index 71d306bc..d5617642 100644 --- a/Source/uservars.h +++ b/Source/uservars.h @@ -7,19 +7,84 @@ #include "Lang.h" -class UserVarsStringList : public LangStringList +struct uservarstring { + int name; + int index; + int pos; + int reference; +}; + +class UserVarsStringList : public SortedStringListND { public: UserVarsStringList() { + index = 0; } ~UserVarsStringList() { } + int add(const char *name, int ref_count = 0 ) + { + int pos=SortedStringListND::add(name); + if (pos == -1) return -1; + + ((struct uservarstring*)gr.get())[pos].index = index; + ((struct uservarstring*)gr.get())[pos].pos = pos; + ((struct uservarstring*)gr.get())[pos].reference = ref_count; + + int temp = index; + index++; + + return temp; + } + int get(char *name, size_t n_chars = -1) { - int v=SortedStringListND::find(name, n_chars); + int v=SortedStringListND::find(name, n_chars); if (v==-1) return -1; - return (((struct langstring*)gr.get())[v].index); + return (((struct uservarstring*)gr.get())[v].index); + } + + int getnum() + { + return index; + } + + int get_reference(int idx) + { + int pos=get_internal_idx(idx); + if (pos==-1) return -1; + return (((struct uservarstring*)gr.get())[pos].reference); + } + + int inc_reference(int idx) + { + int pos=get_internal_idx(idx); + ((struct uservarstring*)gr.get())[pos].reference++; + return (((struct uservarstring*)gr.get())[pos].reference)-1; + } + + char *idx2name(int idx) + { + int pos=get_internal_idx(idx); + if (pos==-1) return NULL; + struct uservarstring *data=(struct uservarstring *)gr.get(); + return ((char*)strings.get() + data[pos].name); + } + + private: + int index; + int get_internal_idx(int idx) + { + struct uservarstring *data=(struct uservarstring *)gr.get(); + for (int i = 0; i < index; i++) + { + if (data[i].index == idx) + { + return i; + } + } + return -1; } }; #endif //NSIS_SUPPORT_NAMED_USERVARS