diff --git a/Examples/UserVars.nsi b/Examples/UserVars.nsi new file mode 100644 index 00000000..673f676d --- /dev/null +++ b/Examples/UserVars.nsi @@ -0,0 +1,46 @@ +; VersionInfo.nsi +; +; This script shows you how to declare and user VARIABLES. + +;-------------------------------- +!include "MUI.nsh" + +!define MUI_PRODUCT "User Variables" +!define MUI_VERSION "1.0" + +;-------------------------------- +;Configuration + + ;General + OutFile "UserVars.exe" + ShowInstDetails nevershow + +;-------------------------------- +;Pages + + !insertmacro MUI_PAGE_INSTFILES + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +; Declaration of User Variables with command DIM, allowed charaters for variables names : [a-z][A-Z][0-9] and '_' + + DIM "Name" + DIM "Serial" + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecCopyUI + + StrCpy $0 "Admin" + StrCpy "$Name" $0 + StrCpy "$Serial" "12345" + + MessageBox MB_OK "User Name: $Name$\n$\nSerial Number: $Serial" + +SectionEnd + diff --git a/Examples/VersionInfo.nsi b/Examples/VersionInfo.nsi index 4d599a3d..82ff76dd 100644 --- a/Examples/VersionInfo.nsi +++ b/Examples/VersionInfo.nsi @@ -12,19 +12,17 @@ OutFile "VersionInfo.exe" ;-------------------------------- ;Version Information - VISetVersionLanguage 2057 1200 ; English UK - VIAddTranslation 2057 1200 ; English UK VIProductVersion "1.2.3.4" - VIAddVersionKey "ProductName" "Test Application" - VIAddVersionKey "Comments" "A test comment" - VIAddVersionKey "CompanyName" "Fake company" - VIAddVersionKey "LegalTrademarks" "Test Application is a trademark of Fake company" - VIAddVersionKey "LegalCopyright" "© Fake company" - VIAddVersionKey "FileDescription" "Test Application" - VIAddVersionKey "FileVersion" "1.2.3" + VIAddVersionKey ${LANG_ENGLISH} "ProductName" "Test Application" + VIAddVersionKey ${LANG_ENGLISH} "Comments" "A test comment" + VIAddVersionKey ${LANG_ENGLISH} "CompanyName" "Fake company" + VIAddVersionKey ${LANG_ENGLISH} "LegalTrademarks" "Test Application is a trademark of Fake company" + VIAddVersionKey ${LANG_ENGLISH} "LegalCopyright" "© Fake company" + VIAddVersionKey ${LANG_ENGLISH} "FileDescription" "Test Application" + VIAddVersionKey ${LANG_ENGLISH} "FileVersion" "1.2.3" ;-------------------------------- Section "" -SectionEnd \ No newline at end of file +SectionEnd diff --git a/Source/ResourceVersionInfo.cpp b/Source/ResourceVersionInfo.cpp index 99cd8586..ad66a08b 100644 --- a/Source/ResourceVersionInfo.cpp +++ b/Source/ResourceVersionInfo.cpp @@ -28,12 +28,24 @@ CResourceVersionInfo::CResourceVersionInfo() // Detect local codepage and language WORD Lang = GetSystemDefaultLangID(); WORD CodePage = GetACP(); - char Buff[10]; - sprintf(Buff, "%04x%04x", Lang, CodePage); - SetVersionInfoLang(Buff); +/* + SetKeyValue(Lang, CodePage, "Comments", "Portuguese"); + SetKeyValue(Lang, CodePage, "FileVersion", "1.2"); + SetKeyValue(Lang, CodePage, "FileDescription", "Soft"); + SetKeyValue(Lang, CodePage, "LegalCopyright", "My"); + SetKeyValue(Lang, CodePage, "InternalName", "My"); + SetKeyValue(Lang, CodePage, "CompanyName", "rats"); + SetKeyValue(Lang, CodePage, "ProductVersion", "ProductVersion"); - AddTranslation(CodePage, Lang); - b_CustomTranslations = false; + Lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + SetKeyValue(Lang, CodePage, "Comments", "English"); + SetKeyValue(Lang, CodePage, "FileVersion", "1.2"); + SetKeyValue(Lang, CodePage, "FileDescription", "Soft"); + SetKeyValue(Lang, CodePage, "LegalCopyright", "My"); + SetKeyValue(Lang, CodePage, "InternalName", "My"); + SetKeyValue(Lang, CodePage, "CompanyName", "rats"); + SetKeyValue(Lang, CodePage, "ProductVersion", "ProductVersion"); +*/ } CResourceVersionInfo::~CResourceVersionInfo() @@ -58,14 +70,13 @@ void CResourceVersionInfo::SetProductVersion(int HighPart, int LowPart) m_FixedInfo.dwProductVersionMS = HighPart; } -// Util function -wstring StrToWstr(const string& istr) +// Util function - must be freeded +WCHAR* StrToWstrAlloc(const char* istr, int codepage) { - wstring wstr; - for(string::const_iterator it = istr.begin(); it != istr.end(); ++it) - { - wstr += (unsigned char)*it; - } return wstr; + int strSize = strlen(istr); + WCHAR* wstr = new WCHAR[(strSize*2)]; + MultiByteToWideChar(codepage, 0, istr, -1, wstr, strSize*2); + return wstr; } int GetVersionHeader (LPSTR &p, WORD &wLength, WORD &wValueLength, WORD &wType) @@ -95,7 +106,7 @@ void PadStream (GrowBuf &strm) strm.add (&ZEROS, 4 - (strm.getlen() % 4)); } -void SaveVersionHeader (GrowBuf &strm, WORD wLength, WORD wValueLength, WORD wType, const wstring &key, void *value) +void SaveVersionHeader (GrowBuf &strm, WORD wLength, WORD wValueLength, WORD wType, const WCHAR *key, void *value) { WORD valueLen; WORD keyLen; @@ -104,8 +115,8 @@ void SaveVersionHeader (GrowBuf &strm, WORD wLength, WORD wValueLength, WORD wTy strm.add (&wValueLength, sizeof (wValueLength)); strm.add (&wType, sizeof (wType)); - keyLen = (key.length() + 1) * sizeof (WCHAR); - strm.add ((void*)key.c_str(), keyLen); + keyLen = (wcslen(key) + 1) * sizeof (WCHAR); + strm.add ((void*)key, keyLen); PadStream(strm); @@ -118,112 +129,129 @@ void SaveVersionHeader (GrowBuf &strm, WORD wLength, WORD wValueLength, WORD wTy } } -void CResourceVersionInfo::ExportToStream(GrowBuf &strm) +void CResourceVersionInfo::ExportToStream(GrowBuf &strm, int Index) { DWORD v; WORD wSize; int p, p1; - wstring KeyName, KeyValue; - + WCHAR *KeyName, *KeyValue; + + strm.resize(0); SaveVersionHeader (strm, 0, sizeof (VS_FIXEDFILEINFO), 0, L"VS_VERSION_INFO", &m_FixedInfo); - if ( m_ChildStrings.getnum() > 0 ) + DefineList *pChildStrings = m_ChildStringLists.get_strings(Index); + if ( pChildStrings->getnum() > 0 ) { - GrowBuf stringInfoStream; - KeyName = StrToWstr(m_VersionInfoLang); + GrowBuf stringInfoStream; + int codepage = m_ChildStringLists.get_codepage(Index); + LANGID langid = m_ChildStringLists.get_lang(Index); + char Buff[16]; + sprintf(Buff, "%04x%04x", langid, codepage); + KeyName = StrToWstrAlloc(Buff, CP_ACP); + SaveVersionHeader (stringInfoStream, 0, 0, 0, KeyName, &ZEROS); + delete [] KeyName; + + for ( int i = 0; i < pChildStrings->getnum(); i++ ) + { + PadStream (stringInfoStream); - SaveVersionHeader (stringInfoStream, 0, 0, 0, KeyName.c_str(), &ZEROS); + p = stringInfoStream.getlen(); + KeyName = StrToWstrAlloc(pChildStrings->getname(i), codepage); + KeyValue = StrToWstrAlloc(pChildStrings->getvalue(i), codepage); + SaveVersionHeader (stringInfoStream, 0, wcslen(KeyValue) + 1, 1, KeyName, (void*)KeyValue); + delete [] KeyName; + delete [] KeyValue; + wSize = stringInfoStream.getlen() - p; - for ( int i = 0; i < m_ChildStrings.getnum(); i++ ) - { - PadStream (stringInfoStream); - - p = stringInfoStream.getlen(); - KeyName = StrToWstr(m_ChildStrings.getname(i)); - KeyValue = StrToWstr(m_ChildStrings.getvalue(i)); - SaveVersionHeader (stringInfoStream, 0, KeyValue.length() + 1, 1, KeyName.c_str(), (void*)KeyValue.c_str()); - wSize = stringInfoStream.getlen() - p; - - *(WORD*)((PBYTE)stringInfoStream.get()+p)=wSize; - } - - wSize = stringInfoStream.getlen(); - *(WORD*)((PBYTE)stringInfoStream.get())=wSize; - - PadStream (strm); - p = strm.getlen(); - SaveVersionHeader (strm, 0, 0, 0, L"StringFileInfo", &ZEROS); - strm.add (stringInfoStream.get(), stringInfoStream.getlen()); - wSize = strm.getlen() - p; - - *(WORD*)((PBYTE)strm.get()+p)=wSize; + *(WORD*)((PBYTE)stringInfoStream.get()+p)=wSize; + } + + wSize = stringInfoStream.getlen(); + *(WORD*)((PBYTE)stringInfoStream.get())=wSize; + + PadStream (strm); + p = strm.getlen(); + SaveVersionHeader (strm, 0, 0, 0, L"StringFileInfo", &ZEROS); + strm.add (stringInfoStream.get(), stringInfoStream.getlen()); + wSize = strm.getlen() - p; + + *(WORD*)((PBYTE)strm.get()+p)=wSize; } - if ( m_Translations.size() > 0 ) + // Show all languages avaiable using Var-Translations + if ( m_ChildStringLists.getnum() > 0 ) { - PadStream (strm); - p = strm.getlen(); - SaveVersionHeader (strm, 0, 0, 0, L"VarFileInfo", &ZEROS); - PadStream (strm); - - p1 = strm.getlen(); - SaveVersionHeader (strm, 0, 0, 0, L"Translation", &ZEROS); - - for ( int i = 0; i < m_Translations.size(); i++ ) + PadStream (strm); + p = strm.getlen(); + SaveVersionHeader (strm, 0, 0, 0, L"VarFileInfo", &ZEROS); + PadStream (strm); + + p1 = strm.getlen(); + SaveVersionHeader (strm, 0, 0, 0, L"Translation", &ZEROS); + + // First add selected code language translation + v = MAKELONG(m_ChildStringLists.get_lang(Index), m_ChildStringLists.get_codepage(Index)); + strm.add (&v, sizeof (v)); + + for ( int k =0; k < m_ChildStringLists.getnum(); k++ ) + { + if ( k != Index ) { - v = m_Translations[i]; - strm.add (&v, sizeof (v)); + v = MAKELONG(m_ChildStringLists.get_lang(k), m_ChildStringLists.get_codepage(k)); + strm.add (&v, sizeof (v)); } - - wSize = strm.getlen() - p1; - *(WORD*)((PBYTE)strm.get()+p1)=wSize; - wSize = sizeof (int) * m_Translations.size(); - p1+=sizeof(WORD); - *(WORD*)((PBYTE)strm.get()+p1)=wSize; - - wSize = strm.getlen() - p; - *(WORD*)((PBYTE)strm.get()+p)=wSize; + } + + wSize = strm.getlen() - p1; + *(WORD*)((PBYTE)strm.get()+p1)=wSize; + wSize = sizeof (int) * m_ChildStringLists.getnum(); + p1+=sizeof(WORD); + *(WORD*)((PBYTE)strm.get()+p1)=wSize; + + wSize = strm.getlen() - p; + *(WORD*)((PBYTE)strm.get()+p)=wSize; } wSize = strm.getlen(); *(WORD*)((PBYTE)strm.get())=wSize; } -void CResourceVersionInfo::SetKeyValue(char* AKeyName, char* AValue) +// Returns 0 if success, 1 if already defined +int CResourceVersionInfo::SetKeyValue(LANGID lang_id, int codepage, char* AKeyName, char* AValue) { - m_ChildStrings.add(AKeyName, AValue); + int pos = m_ChildStringLists.find(lang_id, codepage); + if ( pos == -1 ) + { + pos = m_ChildStringLists.add(lang_id, codepage); + } + DefineList *pStrings = m_ChildStringLists.get_strings(pos); + return pStrings->add(AKeyName, AValue); } -void CResourceVersionInfo::AddTranslation(WORD CodePage, WORD LangID ) +int CResourceVersionInfo::GetStringTablesCount() { - if ( !b_CustomTranslations ) - { - b_CustomTranslations = true; - m_Translations.clear(); // remove local system default, user want to customize - } - DWORD dwTrans = MAKELONG(LangID, CodePage); - if ( find(m_Translations.begin(), m_Translations.end(), dwTrans) == m_Translations.end() ) - m_Translations.push_back(dwTrans); + return m_ChildStringLists.getnum(); } -int CResourceVersionInfo::GetKeyCount() +LANGID CResourceVersionInfo::GetLangID(int Index) { - return m_ChildStrings.getnum(); + return m_ChildStringLists.get_lang(Index); } -int CResourceVersionInfo::GetTranslationCount() +int CResourceVersionInfo::GetCodePage(int Index) { - return m_Translations.size(); + return m_ChildStringLists.get_codepage(Index); } -char *CResourceVersionInfo::FindKey(char *pKeyName) +char *CResourceVersionInfo::FindKey(LANGID LangID, int codepage, char *pKeyName) { - return m_ChildStrings.find(pKeyName); -} - -void CResourceVersionInfo::SetVersionInfoLang(char *pLandCp) -{ - m_VersionInfoLang = pLandCp; + int pos = m_ChildStringLists.find(LangID, codepage); + if ( pos == -1 ) + { + return NULL; + } + DefineList *pStrings = m_ChildStringLists.get_strings(pos); + return pStrings->find(pKeyName); } bool CResourceVersionInfo::IsValidCodePage(WORD codePage ) diff --git a/Source/ResourceVersionInfo.h b/Source/ResourceVersionInfo.h index c1162b5b..6cdaca71 100644 --- a/Source/ResourceVersionInfo.h +++ b/Source/ResourceVersionInfo.h @@ -14,28 +14,83 @@ #include using namespace std; +struct version_string_list { + int codepage; + LANGID lang_id; + int name; + DefineList *pChildStrings; +}; + +class CVersionStrigList : public SortedStringListND +{ +public: + int add(LANGID langid, int codepage) + { + char Buff[10]; + sprintf(Buff, "%04x", langid); + int pos = SortedStringListND::add(Buff); + if (pos == -1) return false; + ((struct version_string_list*)gr.get())[pos].pChildStrings = new DefineList; + ((struct version_string_list*)gr.get())[pos].codepage = codepage; + ((struct version_string_list*)gr.get())[pos].lang_id = langid; + return pos; + } + + LANGID get_lang(int idx) + { + version_string_list *data=(version_string_list *)gr.get(); + return data[idx].lang_id; + } + + int get_codepage(int idx) + { + version_string_list *data=(version_string_list *)gr.get(); + return data[idx].codepage; + } + + DefineList* get_strings(int idx) + { + version_string_list *data=(version_string_list *)gr.get(); + return data[idx].pChildStrings; + } + + int find(LANGID lang_id, int codepage) + { + char Buff[10]; + sprintf(Buff, "%04x", lang_id); + return SortedStringListND::find(Buff); + } + + int getlen() + { + return strings.getlen(); + } + + int getnum() + { + return gr.getlen()/sizeof(struct version_string_list); + } +}; + ///////////////////////////////////////////////////////////////////////////////////////////// class CResourceVersionInfo { VS_FIXEDFILEINFO m_FixedInfo; - DefineList m_ChildStrings; - vector< DWORD > m_Translations; - string m_VersionInfoLang; - bool b_CustomTranslations; + CVersionStrigList m_ChildStringLists; + char m_VersionInfoLang[10]; public: CResourceVersionInfo(); virtual ~CResourceVersionInfo(); - void SetKeyValue (char *AKeyName, char *AValue); - void AddTranslation(WORD CodePage, WORD LangID ); + int SetKeyValue(LANGID lang_id, int codepage, char* AKeyName, char* AValue); void SetFileFlags(int Value); void SetFileVersion(int HighPart, int LowPart); void SetProductVersion(int HighPart, int LowPart); - void ExportToStream(GrowBuf &strm); - int GetKeyCount(); - int GetTranslationCount(); - char *FindKey(char *pKeyName); - void SetVersionInfoLang(char *pLandCp); + void ExportToStream(GrowBuf &strm, int Index); + int GetStringTablesCount(); + LANGID GetLangID(int Index); + int GetCodePage(int Index); + char *FindKey(LANGID LangID, int codepage, char *pKeyName); bool IsValidCodePage(WORD codePage ); }; diff --git a/Source/build.cpp b/Source/build.cpp index b1f45e96..b2c73296 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -13,6 +13,11 @@ #include "exehead/lang.h" #include "ResourceVersionInfo.h" +bool isSimpleChar(char ch) +{ + return (ch == '_' ) || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); +} + void CEXEBuild::define(const char *p, const char *v) { definedlist.add(p,v); @@ -241,8 +246,6 @@ CEXEBuild::CEXEBuild() // Added by ramon 6 jun 2003 #ifdef NSIS_SUPPORT_VERSION_INFO - version_codePage=0; - version_lang=0; version_product_v[0]=0; #endif @@ -305,6 +308,9 @@ CEXEBuild::CEXEBuild() #endif last_used_lang=MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + char lang_id[16]; + wsprintf(lang_id, "%u", last_used_lang); + definedlist.add("LANG_ENGLISH",lang_id); build_header.common.num_pages=0; #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT @@ -335,6 +341,37 @@ CEXEBuild::CEXEBuild() use_first_insttype=true; build_header.license_bg=-COLOR_BTNFACE; + +#ifdef NSIS_SUPPORT_NAMED_USERVARS + // Register user variables $0, $1 and so one + char Aux[3]; + for ( int i = 0; i < 10; i++ ) // 0 - 9 + { + sprintf(Aux, "%d", i); + DeclaredUserVar(Aux); + } + for ( i = 0; i < 10; i++ ) // 10 - 19 + { + sprintf(Aux, "R%d", i); + DeclaredUserVar(Aux); + } + DeclaredUserVar("CMDLINE"); // 20 everything before here doesn't have trailing slash removal + DeclaredUserVar("INSTDIR"); // 21 + DeclaredUserVar("OUTDIR"); // 22 + DeclaredUserVar("EXEDIR"); // 23 + DeclaredUserVar("LANGUAGE"); // 24 + DeclaredUserVar("PLUGINSDIR"); // 25 + DeclaredUserVar("PROGRAMFILES"); // 26 + DeclaredUserVar("SMPROGRAMS"); // 27 + DeclaredUserVar("SMSTARTUP"); // 28 + DeclaredUserVar("DESKTOP"); // 29 + DeclaredUserVar("STARTMENU"); // 30 + DeclaredUserVar("QUICKLAUNCH"); // 31 + DeclaredUserVar("TEMP"); // 32 + DeclaredUserVar("WINDIR"); // 33 + DeclaredUserVar("SYSDIR"); // 34 everything after here doesn't have trailing slash removal + DeclaredUserVar("HWNDPARENT"); // 35 +#endif } int CEXEBuild::getcurdbsize() { return cur_datablock->getlen(); } @@ -355,6 +392,7 @@ int CEXEBuild::add_intstring(const int i) // returns offset in stringblock // based on Dave Laundon's code int CEXEBuild::preprocess_string(char *out, const char *in) { +#ifndef NSIS_SUPPORT_NAMED_USERVARS static const char VarNames[] = "HWNDPARENT\0" // 0 "0\0" // 1 @@ -394,7 +432,8 @@ int CEXEBuild::preprocess_string(char *out, const char *in) "WINDIR\0" // 34 "SYSDIR\0" // 35 ; - +#endif + const char *p=in; while (*p) { @@ -406,9 +445,15 @@ int CEXEBuild::preprocess_string(char *out, const char *in) while (l--) { int i = (unsigned char)*p++; +#ifndef NSIS_SUPPORT_NAMED_USERVARS if (i >= VAR_CODES_START) { *out++ = (char)255; } +#else + if (i == VAR_CODES_START || i == 255 ) { + *out++ = (char)255; + } +#endif *out++=i; } continue; @@ -418,16 +463,25 @@ int CEXEBuild::preprocess_string(char *out, const char *in) p=np; +#ifndef NSIS_SUPPORT_NAMED_USERVARS // Test for characters extending into the variable codes if (i >= VAR_CODES_START) { *out++ = (char)255; } +#else + // Test for characters that equals to control char of variable codes + if (i == VAR_CODES_START || i == 255 ) { + *out++ = (char)255; + } +#endif else if (i == '$') { if (*p == '$') p++; // Can simply convert $$ to $ now else { +#ifndef NSIS_SUPPORT_NAMED_USERVARS + const char *pVarName; for ( pVarName = VarNames, i = VAR_CODES_START; @@ -444,43 +498,30 @@ int CEXEBuild::preprocess_string(char *out, const char *in) p += strlen(pVarName); } else // warning should go here +#endif // not NSIS_SUPPORT_NAMED_USERVARS { #ifdef NSIS_SUPPORT_NAMED_USERVARS bool bProceced=false; - if ( *p == '[' ) + if ( *p ) { - char *pUserVarName = (char *)p+1; - while ( *pUserVarName ) + const char *pUserVarName = p; + while ( isSimpleChar(*pUserVarName) ) + pUserVarName++; + + while ( pUserVarName > p ) { - if ( *pUserVarName == ']' ) - { - *pUserVarName='\0'; - int idxUserVar = m_UserVarNames.get((char*)p+1); - int varLen = strlen(p)+1; - *pUserVarName=']'; // restore + const char * Debug = p-(pUserVarName-p); + int idxUserVar = m_UserVarNames.get((char*)p, pUserVarName-p); if ( idxUserVar >= 0 ) { - *out++=(unsigned int)VAR_CODES_START + 36; // Named user variable; - *(WORD*)out=((WORD)idxUserVar+USER_VARS_COUNT) | 0xF000; + *out++=(unsigned int)VAR_CODES_START; // Named user variable; + *(WORD*)out=((WORD)idxUserVar+1) | 0xF000; out += sizeof(WORD); - p += varLen; + p += pUserVarName-p; bProceced = true; - { - for ( WORD i = 0; i < 0x0FFF; i++ ) - { - WORD bb = i | 0xF000; - WORD ok = bb & 0x0FFF; - if ( ok != i ) - { - warning("Problems with %d",i); - } - - } - } + break; } - break; - } - pUserVarName++; + pUserVarName--; } } if ( bProceced ) @@ -1273,7 +1314,7 @@ int CEXEBuild::write_output(void) GrowBuf VerInfoStream; bool bNeedVInfo = false; - if ( rVersionInfo.GetKeyCount() > 0 ) + if ( rVersionInfo.GetStringTablesCount() > 0 ) { if ( !version_product_v[0] ) { @@ -1291,19 +1332,23 @@ int CEXEBuild::write_output(void) rVersionInfo.SetFileVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); rVersionInfo.SetProductVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); - //rVersionInfo.AddTranslation(0x0,0x0409); - rVersionInfo.ExportToStream(VerInfoStream); init_res_editor(); - res_editor->UpdateResource(RT_VERSION, 1, 0, (BYTE*)VerInfoStream.get(), VerInfoStream.getlen()); + for ( int i = 0; i < rVersionInfo.GetStringTablesCount(); i++ ) + { + LANGID lang_id = rVersionInfo.GetLangID(i); + int code_page = rVersionInfo.GetCodePage(i); + StringTable * Table = GetTable(lang_id); + + if ( !rVersionInfo.FindKey(lang_id, code_page, "FileVersion") ) + warning("Generating version information for language \"%04d-%s\" without standard key \"FileVersion\"", lang_id, Table->nlf ? Table->nlf->m_szName : lang_id == 1033 ? "English" : "???"); + if ( !rVersionInfo.FindKey(lang_id, code_page, "FileDescription") ) + warning("Generating version information for language \"%04d-%s\" without standard key \"FileDescription\"", lang_id, Table->nlf ? Table->nlf->m_szName : lang_id == 1033 ? "English" : "???"); + if ( !rVersionInfo.FindKey(lang_id, code_page, "LegalCopyright") ) + warning("Generating version information for language \"%04d-%s\" without standard key \"LegalCopyright\"", lang_id, Table->nlf ? Table->nlf->m_szName : lang_id == 1033 ? "English" : "???"); - if ( !rVersionInfo.GetTranslationCount() ) - warning("Generating version information without any language/codepage defined."); - if ( !rVersionInfo.FindKey("FileVersion") ) - warning("Generating version information without standard key \"FileVersion\""); - if ( !rVersionInfo.FindKey("FileDescription") ) - warning("Generating version information without standard key \"FileDescription\""); - if ( !rVersionInfo.FindKey("LegalCopyright") ) - warning("Generating version information without standard key \"LegalCopyright\""); + rVersionInfo.ExportToStream(VerInfoStream, i); + res_editor->UpdateResource(RT_VERSION, 1, lang_id, (BYTE*)VerInfoStream.get(), VerInfoStream.getlen()); + } } } @@ -2419,6 +2464,11 @@ int CEXEBuild::add_plugins_dir_initializer(void) int ret; int zero_offset; +#ifdef NSIS_SUPPORT_NAMED_USERVARS + int var_zero; + var_zero=m_UserVarNames.get("0"); +#endif + again: // Function [un.]Initialize_____Plugins ret=add_function(uninstall?"un.Initialize_____Plugins":"Initialize_____Plugins"); @@ -2441,7 +2491,11 @@ again: ret=add_entry_direct(EW_SETFLAG, FLAG_OFFSET(exec_error)); if (ret != PS_OK) return ret; // GetTempFileName $0 +#ifdef NSIS_SUPPORT_NAMED_USERVARS + ret=add_entry_direct(EW_GETTEMPFILENAME, var_zero); +#else ret=add_entry_direct(EW_GETTEMPFILENAME); +#endif if (ret != PS_OK) return ret; // Delete $0 - the temp file created ret=add_entry_direct(EW_DELETEFILE, zero_offset); @@ -2453,10 +2507,18 @@ again: ret=add_entry_direct(EW_IFFLAG, ns_label.add("Initialize_____Plugins_error",0), 0, FIELD_OFFSET(installer_flags, exec_error)/sizeof(int)); if (ret != PS_OK) return ret; // Copy $0 to $PLUGINSDIR +#ifdef NSIS_SUPPORT_NAMED_USERVARS + ret=add_entry_direct(EW_ASSIGNVAR, m_UserVarNames.get("PLUGINSDIR"), zero_offset); +#else ret=add_entry_direct(EW_ASSIGNVAR, 25, zero_offset); +#endif if (ret != PS_OK) return ret; // Pop $0 +#ifdef NSIS_SUPPORT_NAMED_USERVARS + ret=add_entry_direct(EW_PUSHPOP, var_zero, 1); +#else ret=add_entry_direct(EW_PUSHPOP, 0, 1); +#endif if (ret != PS_OK) return ret; // done @@ -2532,12 +2594,9 @@ int CEXEBuild::DeclaredUserVar(const char *szVarName) { while ( *pVarName ) { - if ((*pVarName < '0') || - (*pVarName > '9' && *pVarName < 'A' ) || - (*pVarName > 'Z' && *pVarName < 'a' && *pVarName != '_' ) || - (*pVarName > 'z') ) + if ( !isSimpleChar(*pVarName) ) { - ERROR_MSG("Error: invalid charaters in variable name \"%s\"\n", szVarName); + ERROR_MSG("Error: invalid charaters in variable name \"%s\", use only charaters [a-z][A-Z][0-9] and '_'\n", szVarName); return PS_ERROR; } pVarName++; @@ -2556,35 +2615,23 @@ int CEXEBuild::DeclaredUserVar(const char *szVarName) int CEXEBuild::GetUserVarIndex(LineParser &line, int token) { +#ifdef NSIS_SUPPORT_NAMED_USERVARS + + char *p = line.gettoken_str(token); + if ( *p == '$' && *(p+1) ) + { + int idxUserVar = m_UserVarNames.get((char *)p+1); + if ( idxUserVar >= 0 ) + { + return idxUserVar; + } + } + return -1; +#else + static const char *usrvars="$0\0$1\0$2\0$3\0$4\0$5\0$6\0$7\0$8\0$9\0" "$R0\0$R1\0$R2\0$R3\0$R4\0$R5\0$R6\0$R7\0$R8\0$R9\0" "$CMDLINE\0$INSTDIR\0$OUTDIR\0$EXEDIR\0$LANGUAGE\0"; - int res = line.gettoken_enum(token, usrvars); -// Added by ramon 3 jun 2003 -#ifdef NSIS_SUPPORT_NAMED_USERVARS - if ( res < 0 ) - { - char *p = line.gettoken_str(token); - if ( *p == '$' && *(p+1) == '[' ) - { - char *pUserVarName = (char *)p+2; - while ( *pUserVarName ) - { - if ( *pUserVarName == ']' ) - { - *pUserVarName='\0'; - int idxUserVar = m_UserVarNames.get((char*)p+2); - *pUserVarName=']'; // restore - if ( idxUserVar >= 0 ) - { - res=idxUserVar+USER_VARS_COUNT; // User named variable; - } - break; - } - pUserVarName++; - } - } - } + return line.gettoken_enum(token, usrvars); #endif - return res; } diff --git a/Source/build.h b/Source/build.h index d577e8c4..4e30afb1 100644 --- a/Source/build.h +++ b/Source/build.h @@ -10,6 +10,7 @@ using namespace std; #include "lang.h" #include "ResourceEditor.h" #include "ResourceVersionInfo.h" +#include "uservars.h" #include "exehead/fileform.h" #include "exehead/config.h" @@ -173,7 +174,7 @@ class CEXEBuild { int GetUserVarIndex(LineParser &line, int token); // Added by ramon 3 jun 2003 #ifdef NSIS_SUPPORT_NAMED_USERVARS - LangStringList m_UserVarNames; + UserVarsStringList m_UserVarNames; int DeclaredUserVar(const char *VarName); #endif @@ -214,7 +215,6 @@ class CEXEBuild { // Added by ramon 6 jun 2003 #ifdef NSIS_SUPPORT_VERSION_INFO CResourceVersionInfo rVersionInfo; - int version_codePage, version_lang; char version_product_v[1024]; #endif diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index be7f7177..9af588cc 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -515,7 +515,7 @@ DWORD NSISCALL SetSelfFilePointer(LONG lDistanceToMove, DWORD dwMoveMethod); // $0..$9, $INSTDIR, etc are encoded as ASCII bytes starting from this value. // Added by ramon 3 jun 2003 #ifdef NSIS_SUPPORT_NAMED_USERVARS - #define VAR_CODES_START (256 - 38) + #define VAR_CODES_START 250 #else #ifdef NSIS_CONFIG_PLUGIN_SUPPORT #define VAR_CODES_START (256 - 37) diff --git a/Source/exehead/util.c b/Source/exehead/util.c index 398c7203..0adbcf55 100644 --- a/Source/exehead/util.c +++ b/Source/exehead/util.c @@ -400,6 +400,7 @@ char * NSISCALL process_string(const char *in) while (*in && out - ps_tmpbuf < NSIS_MAX_STRLEN) { int nVarIdx = (unsigned char)*in++; +#ifndef NSIS_SUPPORT_NAMED_USERVARS if (nVarIdx < VAR_CODES_START) { *out++ = nVarIdx; @@ -443,24 +444,9 @@ char * NSISCALL process_string(const char *in) case VAR_CODES_START + 24: // EXEDIR case VAR_CODES_START + 25: // LANGUAGE case VAR_CODES_START + 26: // PLUGINSDIR -#ifdef NSIS_SUPPORT_NAMED_USERVARS - case VAR_CODES_START + 36: // NAMED USER VARS - { - if ( nVarIdx == (VAR_CODES_START + 36) ) - { - //char Buf[200]; - nVarIdx = *(WORD*)in & 0x0FFF; in+=sizeof(WORD); - //wsprintf(Buf, "Request var index %d", nVarIdx); - //MessageBox(0,Buf,0,0); - } - else - nVarIdx = nVarIdx - (VAR_CODES_START + 1); - mystrcpy(out, g_usrvars[nVarIdx]); - } -#else mystrcpy(out, g_usrvars[nVarIdx - (VAR_CODES_START + 1)]); break; -#endif + case VAR_CODES_START + 27: // PROGRAMFILES smwcvesf[41]=0; myRegGetStr(HKEY_LOCAL_MACHINE, smwcvesf, "ProgramFilesDir", out); @@ -522,27 +508,112 @@ char * NSISCALL process_string(const char *in) GetSystemDirectory(out, NSIS_MAX_STRLEN); break; -#ifdef NSIS_SUPPORT_NAMED_USERVARS - #if USER_VARS_COUNT + MAX_NAMED_USER_VARS > 0x0FFF - #error "Too many named variables! Decrease MAX_NAMED_USER_VARS" - #endif - - #if VAR_CODES_START + 36 >= 255 - #error "Too many variables! Extend VAR_CODES_START!" - #endif -#else #if VAR_CODES_START + 35 >= 255 #error "Too many variables! Extend VAR_CODES_START!" #endif -#endif } // switch // validate the directory name - if (nVarIdx > 21+VAR_CODES_START && nVarIdx < VAR_CODES_START + 36 ) { // only if not $0 to $R9, $CMDLINE, or $HWNDPARENT + if (nVarIdx > 21+VAR_CODES_START ) { // only if not $0 to $R9, $CMDLINE, or $HWNDPARENT // ($LANGUAGE can't have trailing backslash anyway...) validate_filename(out); } out+=mystrlen(out); } // >= VAR_CODES_START +#else + + if (nVarIdx == 255) + { + *out++ = *in++; + } + else if (nVarIdx != VAR_CODES_START) + { + *out++ = nVarIdx; + } + else + { + DWORD f; + static char smwcvesf[]="Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; + nVarIdx = (*(WORD*)in & 0x0FFF)-1; in+=sizeof(WORD); + switch (nVarIdx) // The order of this list must match that in ..\strlist.cpp (err, build.cpp -J) + { + case 26: // PROGRAMFILES + smwcvesf[41]=0; + myRegGetStr(HKEY_LOCAL_MACHINE, smwcvesf, "ProgramFilesDir", out); + if (!*out) + mystrcpy(out, "C:\\Program Files"); + break; + + case 27: // SMPROGRAMS + case 28: // SMSTARTUP + case 29: // DESKTOP + case 30: // STARTMENU + case 31: // QUICKLAUNCH + { + static const char *tab[]={ + "Programs", + "Startup", + "Desktop", + "Start Menu", + "AppData" + }; + static char name[20]="Common "; + const char *name_=tab[nVarIdx-27]; + mystrcpy(name+7,name_); + f=g_flags.all_user_var & (nVarIdx != 31); + + again: + + smwcvesf[41]='\\'; + myRegGetStr(f?HKEY_LOCAL_MACHINE:HKEY_CURRENT_USER, + smwcvesf, + f?name:name_,out); + if (!out[0]) + { + if (f) + { + f=0; goto again; + } + mystrcpy(out,temp_directory); + } + + if (nVarIdx == 31) { + lstrcat(out, "\\Microsoft\\Internet Explorer\\Quick Launch"); + f = GetFileAttributes(out); + if (f != (DWORD)-1 && (f & FILE_ATTRIBUTE_DIRECTORY)) + break; + } + else break; + } + + case 32: // TEMP + mystrcpy(out,temp_directory); + break; + + case 33: // WINDIR + GetWindowsDirectory(out, NSIS_MAX_STRLEN); + break; + + case 34: // SYSDIR + GetSystemDirectory(out, NSIS_MAX_STRLEN); + break; + + case 35: // HWNDPARENT + myitoa(out, (unsigned int)g_hwnd); + break; + + default: + mystrcpy(out, g_usrvars[nVarIdx]); + break; + + } // switch + // validate the directory name + if (nVarIdx > 21 && nVarIdx < 36 ) { // only if not $0 to $R9, $CMDLINE, or $HWNDPARENT and not great than $SYSDIR + // ($LANGUAGE can't have trailing backslash anyway...) + validate_filename(out); + } + out+=mystrlen(out); + } // == VAR_CODES_START +#endif } // while *out = 0; return ps_tmpbuf; @@ -608,4 +679,4 @@ void NSISCALL log_write(int close) } } } -#endif \ No newline at end of file +#endif diff --git a/Source/makenssi.dsp b/Source/makenssi.dsp index 458bd263..22c24ada 100644 --- a/Source/makenssi.dsp +++ b/Source/makenssi.dsp @@ -69,8 +69,8 @@ LINK32=link.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /Ob2 /D "_CONSOLE" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /FD /c # SUBTRACT BASE CPP /Fr /YX /Yc /Yu -# ADD CPP /nologo /MLd /W3 /GX /ZI /Od /D "_CONSOLE" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /FD /c -# SUBTRACT CPP /Fr /YX /Yc /Yu +# ADD CPP /nologo /MLd /W3 /GX /ZI /Od /D "_CONSOLE" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /Fr /FD /c +# SUBTRACT CPP /YX /Yc /Yu # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -260,6 +260,10 @@ SOURCE=.\tokens.h # End Source File # Begin Source File +SOURCE=.\uservars.h +# End Source File +# Begin Source File + SOURCE=.\util.h # End Source File # End Group diff --git a/Source/script.cpp b/Source/script.cpp index 08306909..442d9260 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -1968,8 +1968,15 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) uDefCodePage = newNLF->m_uCodePage; } build_nlfs.push_back(newNLF); - LANGID lang = newNLF->m_wLangId; - GetTable(lang); + StringTable * Table = GetTable(newNLF->m_wLangId); + + for (i = 0; i < build_nlfs.size(); i++) { + if (build_nlfs[i]->m_wLangId == Table->lang_id) { + Table->nlf = build_nlfs[i]; + break; + } + } + last_used_lang = newNLF->m_wLangId; // define LANG_LangName as "####" (lang id) // for example ${LANG_ENGLISH} = 1033 @@ -4391,8 +4398,9 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) #ifdef NSIS_SUPPORT_VERSION_INFO case TOK_VI_ADDKEY: { - char *pKey = line.gettoken_str(1); - char *pValue = line.gettoken_str(2); + LANGID LangID = line.gettoken_int(1); + char *pKey = line.gettoken_str(2); + char *pValue = line.gettoken_str(3); if ( !(*pKey) ) { ERROR_MSG("Error: empty name for version info key!\n"); @@ -4400,64 +4408,27 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) } else { - SCRIPT_MSG("%s = \"%s\"=\"%s\" \n",line.gettoken_str(0), line.gettoken_str(1), line.gettoken_str(2)); - rVersionInfo.SetKeyValue(pKey, pValue); - return PS_OK; - } - } - case TOK_VI_ADDTRANSLATION: - { - int s1, s2; - int language = line.gettoken_int(1, &s1); - int codepage = line.gettoken_int(2, &s2); - if ( !s1 || !s2 ) - PRINTHELP() - else - { - if ( !rVersionInfo.IsValidCodePage(codepage) ) - { - ERROR_MSG("Error: invalid codepage id %d!\n", codepage); - return PS_ERROR; - } - if ( !IsValidLocale(language, LCID_SUPPORTED) ) - { - ERROR_MSG("Error: invalid language id %d!\n", language); - return PS_ERROR; - } - rVersionInfo.AddTranslation(codepage, language); - return PS_OK; - } - } + SCRIPT_MSG("%s: \"%s\" \"%s\" \"%s\"\n", line.gettoken_str(0), line.gettoken_str(1), line.gettoken_str(2), line.gettoken_str(3)); + StringTable *strTable = GetTable(LangID); + if ( line.gettoken_int(1) == 0 && !strTable->nlf ) + warning("%s: \"%s\" language not loaded, using default \"1033-English\". (%s:%d)", line.gettoken_str(0), line.gettoken_str(1), curfilename,linecnt); + if ( rVersionInfo.SetKeyValue(LangID, strTable->nlf ? strTable->nlf->m_uCodePage : 1252 /*English US*/, pKey, pValue) ) + { + ERROR_MSG("%s: \"%s\" \"%04d-%s\" already defined!\n",line.gettoken_str(0), line.gettoken_str(2), LangID, strTable->nlf ? strTable->nlf->m_szName : LangID == 1033 ? "English" : "???"); + return PS_ERROR; + } + return make_sure_not_in_secorfunc(line.gettoken_str(0)); + } + } case TOK_VI_SETPRODUCTVERSION: - strcpy(version_product_v, line.gettoken_str(1)); - return PS_OK; - - case TOK_VI_SETVERSIONLANGUAGE: - { - int s1, s2; - int language = line.gettoken_int(1, &s1); - int codepage = line.gettoken_int(2, &s2); - if ( !s1 || !s2 ) - PRINTHELP() - else + if ( version_product_v[0] ) { - if ( !rVersionInfo.IsValidCodePage(codepage) ) - { - ERROR_MSG("Error: invalid codepage id %d!\n", codepage); + ERROR_MSG("Error: %s already defined!\n", line.gettoken_str(0)); return PS_ERROR; - } - if ( !IsValidLocale(language, LCID_SUPPORTED) ) - { - ERROR_MSG("Error: invalid language id %d!\n", language); - return PS_ERROR; - } - char Buf[10]; - sprintf(Buf, "%04x%04x", language, codepage); - rVersionInfo.SetVersionInfoLang(Buf); - return PS_OK; } - } + strcpy(version_product_v, line.gettoken_str(1)); + return make_sure_not_in_secorfunc(line.gettoken_str(0)); #else case TOK_VI_ADDKEY: diff --git a/Source/strlist.h b/Source/strlist.h index b6d1b79b..6f3d7a7f 100644 --- a/Source/strlist.h +++ b/Source/strlist.h @@ -278,7 +278,7 @@ class SortedStringListND // no delete - can be placed in GrowBuf { int where; T newstruct={0,}; - int pos=find(name,case_sensitive,1,&where); + int pos=find(name,-1,case_sensitive,1,&where); if (pos==-1) return alwaysreturnpos ? where : -1; newstruct.name=strings.add(name,strlen(name)+1); @@ -292,7 +292,8 @@ class SortedStringListND // no delete - can be placed in GrowBuf // returns -1 if not found, position if found // if returnbestpos=1 returns -1 if found, best pos to insert if not found - int find(const char *str, int case_sensitive=0, int returnbestpos=0, int *where=0) + // if n_chars equal to -1 all string is tested + int find(const char *str, size_t n_chars=-1, int case_sensitive=0, int returnbestpos=0, int *where=0) { T *data=(T *)gr.get(); int ul=gr.getlen()/sizeof(T); @@ -302,10 +303,22 @@ class SortedStringListND // no delete - can be placed in GrowBuf while (ul > ll) { int res; - if (case_sensitive) - res=strcmp(str, (char*)strings.get() + data[nextpos].name); + const char *pCurr = (char*)strings.get() + data[nextpos].name; + if (n_chars == -1 || n_chars != strlen(pCurr) ) + { + if (case_sensitive) + res=strcmp(str, pCurr); + else + res=stricmp(str, pCurr); + } else - res=stricmp(str, (char*)strings.get() + data[nextpos].name); + { + if (case_sensitive) + res=strncmp(str, pCurr, n_chars); + else + res=strnicmp(str, pCurr, n_chars); + } + if (res==0) { if (where) *where = nextpos; diff --git a/Source/tokens.cpp b/Source/tokens.cpp index 5311445a..77f0b3f8 100644 --- a/Source/tokens.cpp +++ b/Source/tokens.cpp @@ -230,9 +230,7 @@ static tokenType tokenlist[TOK__LAST] = // Added by ramon 3 jun 2003 {TOK_DEFVAR,"dim",1,0,"VarName"}, // Added by ramon 6 jun 2003 -{TOK_VI_ADDKEY,"VIAddVersionKey", 2, 0, "[keyname] [value]"}, -{TOK_VI_ADDTRANSLATION,"VIAddTranslation", 2, 0, "[short language id] [short codepage id]"}, -{TOK_VI_SETVERSIONLANGUAGE,"VISetVersionLanguage", 2, 0, "[short language id] [short codepage id]"}, +{TOK_VI_ADDKEY,"VIAddVersionKey", 3, 0, "lang_id keyname value"}, {TOK_VI_SETPRODUCTVERSION,"VIProductVersion", 1, 0, "[version string X.X.X.X]"}, }; diff --git a/Source/tokens.h b/Source/tokens.h index 9bc6a3c5..4aedad13 100644 --- a/Source/tokens.h +++ b/Source/tokens.h @@ -217,9 +217,7 @@ enum // Added by ramon 3 jun 2003 TOK_DEFVAR, TOK_VI_ADDKEY, - TOK_VI_ADDTRANSLATION, TOK_VI_SETPRODUCTVERSION, - TOK_VI_SETVERSIONLANGUAGE, TOK__LAST, TOK__PLUGINCOMMAND diff --git a/Source/uservars.h b/Source/uservars.h new file mode 100644 index 00000000..71d306bc --- /dev/null +++ b/Source/uservars.h @@ -0,0 +1,27 @@ +// uservars.h by Ramon 10 Jun 2003 + +#ifndef ___USERVARS___H_____ +#define ___USERVARS___H_____ + +#ifdef NSIS_SUPPORT_NAMED_USERVARS + +#include "Lang.h" + +class UserVarsStringList : public LangStringList +{ + public: + UserVarsStringList() + { + } + ~UserVarsStringList() { } + + int get(char *name, size_t n_chars = -1) + { + int v=SortedStringListND::find(name, n_chars); + if (v==-1) return -1; + return (((struct langstring*)gr.get())[v].index); + } +}; +#endif //NSIS_SUPPORT_NAMED_USERVARS + +#endif