diff --git a/Source/ResourceVersionInfo.cpp b/Source/ResourceVersionInfo.cpp index 1091c485..99cd8586 100644 --- a/Source/ResourceVersionInfo.cpp +++ b/Source/ResourceVersionInfo.cpp @@ -7,6 +7,14 @@ #include "ResourceVersionInfo.h" #ifdef NSIS_SUPPORT_VERSION_INFO + +int ValidCodePages[] = { +437, 708, 709, 710, 720, 737, 775, 850, 852, 855, 85, 86, 86, 86, 86, 864, +865, 866, 869, 874, 932, 936, 949, 950, 1200, 1250, 1251, 1252, 1253, 1254, +1255, 1256, 1257, 1258, 20000, 20001, 20002, 20003, 20004, 20005, 20127, 20261, +20269, 20866, 21027, 21866, 28591, 28592, 28593, 28594, 28595, 28596, 28597, 28598, +28599, 29001, 1361, 0 }; + ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -16,6 +24,16 @@ CResourceVersionInfo::CResourceVersionInfo() m_FixedInfo.dwSignature = 0xFEEF04BD; m_FixedInfo.dwFileOS = VOS__WINDOWS32; m_FixedInfo.dwFileType = VFT_APP; + + // Detect local codepage and language + WORD Lang = GetSystemDefaultLangID(); + WORD CodePage = GetACP(); + char Buff[10]; + sprintf(Buff, "%04x%04x", Lang, CodePage); + SetVersionInfoLang(Buff); + + AddTranslation(CodePage, Lang); + b_CustomTranslations = false; } CResourceVersionInfo::~CResourceVersionInfo() @@ -46,7 +64,7 @@ wstring StrToWstr(const string& istr) wstring wstr; for(string::const_iterator it = istr.begin(); it != istr.end(); ++it) { - wstr += *it; + wstr += (unsigned char)*it; } return wstr; } @@ -112,8 +130,9 @@ void CResourceVersionInfo::ExportToStream(GrowBuf &strm) if ( m_ChildStrings.getnum() > 0 ) { GrowBuf stringInfoStream; + KeyName = StrToWstr(m_VersionInfoLang); - SaveVersionHeader (stringInfoStream, 0, 0, 0, VERINFO_LANGUAGE, &ZEROS); + SaveVersionHeader (stringInfoStream, 0, 0, 0, KeyName.c_str(), &ZEROS); for ( int i = 0; i < m_ChildStrings.getnum(); i++ ) { @@ -177,8 +196,46 @@ void CResourceVersionInfo::SetKeyValue(char* AKeyName, char* AValue) void CResourceVersionInfo::AddTranslation(WORD CodePage, WORD LangID ) { + 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); } + +int CResourceVersionInfo::GetKeyCount() +{ + return m_ChildStrings.getnum(); +} + +int CResourceVersionInfo::GetTranslationCount() +{ + return m_Translations.size(); +} + +char *CResourceVersionInfo::FindKey(char *pKeyName) +{ + return m_ChildStrings.find(pKeyName); +} + +void CResourceVersionInfo::SetVersionInfoLang(char *pLandCp) +{ + m_VersionInfoLang = pLandCp; +} + +bool CResourceVersionInfo::IsValidCodePage(WORD codePage ) +{ + int *pCP = ValidCodePages; + if ( !codePage ) + return false; + while ( *pCP++ ) + { + if ( *pCP == codePage ) + return true; + } + return false; +} #endif \ No newline at end of file diff --git a/Source/ResourceVersionInfo.h b/Source/ResourceVersionInfo.h index f20d9060..c1162b5b 100644 --- a/Source/ResourceVersionInfo.h +++ b/Source/ResourceVersionInfo.h @@ -14,14 +14,14 @@ #include using namespace std; -#define VERINFO_LANGUAGE L"040904b0" // English language and codepage -#define VERINFO_TRANSLATION 0x04B00409 // English language and codepage ///////////////////////////////////////////////////////////////////////////////////////////// class CResourceVersionInfo { VS_FIXEDFILEINFO m_FixedInfo; DefineList m_ChildStrings; vector< DWORD > m_Translations; + string m_VersionInfoLang; + bool b_CustomTranslations; public: CResourceVersionInfo(); @@ -32,6 +32,11 @@ public: 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); + bool IsValidCodePage(WORD codePage ); }; #endif diff --git a/Source/build.cpp b/Source/build.cpp index f3052f9f..b1f45e96 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -241,8 +241,9 @@ CEXEBuild::CEXEBuild() // Added by ramon 6 jun 2003 #ifdef NSIS_SUPPORT_VERSION_INFO - szVIProductVersion[0]=szVIProductName[0]=szVICompanyName[0]=0; - szVIComments[0]=szVILegalTrademarks[0]=szVILegalCopyrights[0]=szVIDescription[0]=0; + version_codePage=0; + version_lang=0; + version_product_v[0]=0; #endif build_overwrite=0; @@ -1269,51 +1270,12 @@ int CEXEBuild::resolve_coderefs(const char *str) int CEXEBuild::write_output(void) { #ifdef NSIS_SUPPORT_VERSION_INFO - CResourceVersionInfo ResourceVersionInfo; GrowBuf VerInfoStream; bool bNeedVInfo = false; - ResourceVersionInfo.SetFileFlags(VS_FF_DEBUG); - - if ( szVIProductVersion[0] ) { - ResourceVersionInfo.SetKeyValue("ProductVersion", szVIProductVersion); - ResourceVersionInfo.SetKeyValue("FileVersion", szVIProductVersion); // this is needed to explorer show version tab with some info - bNeedVInfo = true; - } - - if ( szVIProductName[0] ) { - ResourceVersionInfo.SetKeyValue("ProductName", szVIProductName); - bNeedVInfo = true; - } - - if ( szVICompanyName[0] ) { - ResourceVersionInfo.SetKeyValue("CompanyName", szVICompanyName); - bNeedVInfo = true; - } - - if ( szVIComments[0] ) { - ResourceVersionInfo.SetKeyValue("Comments", szVIComments); - bNeedVInfo = true; - } - - if ( szVILegalTrademarks[0] ) { - ResourceVersionInfo.SetKeyValue("LegalTrademarks", szVILegalTrademarks); - bNeedVInfo = true; - } - - if ( szVILegalCopyrights[0] ) { - ResourceVersionInfo.SetKeyValue("LegalCopyright", szVILegalCopyrights); - bNeedVInfo = true; - } - - if ( szVIDescription[0] ) { - ResourceVersionInfo.SetKeyValue("FileDescription", szVIDescription); - bNeedVInfo = true; - } - - if ( bNeedVInfo ) + if ( rVersionInfo.GetKeyCount() > 0 ) { - if ( !szVIProductVersion[0] ) + if ( !version_product_v[0] ) { ERROR_MSG("Error: VIProductVersion is required when other version information functions are used.\n"); return PS_ERROR; @@ -1321,18 +1283,27 @@ int CEXEBuild::write_output(void) else { int imm, iml, ilm, ill; - if ( sscanf(szVIProductVersion, "%d.%d.%d.%d", &imm, &iml, &ilm, &ill) != 4 ) + if ( sscanf(version_product_v, "%d.%d.%d.%d", &imm, &iml, &ilm, &ill) != 4 ) { ERROR_MSG("Error: invalid VIProductVersion format, should be X.X.X.X\n"); return PS_ERROR; } - ResourceVersionInfo.SetFileVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); - ResourceVersionInfo.SetProductVersion(MAKELONG(iml, imm),MAKELONG(ill, ilm)); - ResourceVersionInfo.SetKeyValue("InternalName", build_output_filename); - ResourceVersionInfo.AddTranslation(0x0,0x0409); - ResourceVersionInfo.ExportToStream(VerInfoStream); + 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()); + + 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\""); } } diff --git a/Source/build.h b/Source/build.h index aa1cccd2..d577e8c4 100644 --- a/Source/build.h +++ b/Source/build.h @@ -9,6 +9,7 @@ using namespace std; #include "lineparse.h" #include "lang.h" #include "ResourceEditor.h" +#include "ResourceVersionInfo.h" #include "exehead/fileform.h" #include "exehead/config.h" @@ -212,13 +213,9 @@ class CEXEBuild { // Added by ramon 6 jun 2003 #ifdef NSIS_SUPPORT_VERSION_INFO - char szVIProductVersion[1024]; - char szVIProductName[1024]; - char szVICompanyName[1024]; - char szVIComments[1024]; - char szVILegalTrademarks[1024]; - char szVILegalCopyrights[1024]; - char szVIDescription[1024]; + CResourceVersionInfo rVersionInfo; + int version_codePage, version_lang; + char version_product_v[1024]; #endif int subsection_open_cnt; diff --git a/Source/script.cpp b/Source/script.cpp index e123905c..08306909 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -4389,54 +4389,81 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) // Added by ramon 6 jun 2003 #ifdef NSIS_SUPPORT_VERSION_INFO - case TOK_VI_PRODUCTVERSION: - case TOK_VI_PRODUCTNAME: - case TOK_VI_COMPANY: - case TOK_VI_COMMENTS: - case TOK_VI_LEGALTRADEMARKS: - case TOK_VI_LEGALCOPYRIGHTS: - case TOK_VI_DESCRIPTION: + case TOK_VI_ADDKEY: { - char *pVI; - switch (which_token) - { - case TOK_VI_PRODUCTVERSION: - pVI = szVIProductVersion; break; - case TOK_VI_PRODUCTNAME: - pVI = szVIProductName; break; - case TOK_VI_COMPANY: - pVI = szVICompanyName; break; - case TOK_VI_COMMENTS: - pVI = szVIComments; break; - case TOK_VI_LEGALTRADEMARKS: - pVI = szVILegalTrademarks; break; - case TOK_VI_LEGALCOPYRIGHTS: - pVI = szVILegalCopyrights; break; - case TOK_VI_DESCRIPTION: - pVI = szVIDescription; break; - } - - if ( pVI[0] ) + char *pKey = line.gettoken_str(1); + char *pValue = line.gettoken_str(2); + if ( !(*pKey) ) { - ERROR_MSG("Error: %s already defined.\n",line.gettoken_str(0)); + ERROR_MSG("Error: empty name for version info key!\n"); return PS_ERROR; } else { - SCRIPT_MSG("%s = \"%s\"\n",line.gettoken_str(0), line.gettoken_str(1)); - strcpy(pVI, line.gettoken_str(1)); + 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; + } + } + + 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 ( !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; + } + char Buf[10]; + sprintf(Buf, "%04x%04x", language, codepage); + rVersionInfo.SetVersionInfoLang(Buf); + return PS_OK; + } + } #else - case TOK_VI_PRODUCTVERSION: - case TOK_VI_PRODUCTNAME: - case TOK_VI_COMPANY: - case TOK_VI_COMMENTS: - case TOK_VI_LEGALTRADEMARKS: - case TOK_VI_LEGALCOPYRIGHTS: - case TOK_VI_DESCRIPTION: + case TOK_VI_ADDKEY: + case TOK_VI_ADDTRANSLATION: + case TOK_VI_SETPRODUCTVERSION: + case TOK_VI_SETVERSIONLANGUAGE: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_VERSION_INFO not defined.\n",line.gettoken_str(0)); return PS_ERROR; #endif diff --git a/Source/tokens.cpp b/Source/tokens.cpp index 3ed12b11..5311445a 100644 --- a/Source/tokens.cpp +++ b/Source/tokens.cpp @@ -230,13 +230,10 @@ 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_PRODUCTVERSION,"VIProductVersion", 1, 0, "product version"}, -{TOK_VI_PRODUCTNAME,"VIProductName", 1, 0, "product name"}, -{TOK_VI_COMPANY,"VICompanyName", 1, 0, "company name"}, -{TOK_VI_COMMENTS,"VIComments", 1, 0, "comments"}, -{TOK_VI_LEGALTRADEMARKS,"VILegalTrademarks", 1, 0, "legal trademarks"}, -{TOK_VI_LEGALCOPYRIGHTS,"VILegalCopyrights", 1, 0, "legal copyrights"}, -{TOK_VI_DESCRIPTION, "VIDescription", 1, 0, "description text"}, +{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_SETPRODUCTVERSION,"VIProductVersion", 1, 0, "[version string X.X.X.X]"}, }; void CEXEBuild::print_help(char *commandname) diff --git a/Source/tokens.h b/Source/tokens.h index 332ee2ee..9bc6a3c5 100644 --- a/Source/tokens.h +++ b/Source/tokens.h @@ -216,13 +216,10 @@ enum TOK_ALLOWSKIPFILES, // Added by ramon 3 jun 2003 TOK_DEFVAR, - TOK_VI_PRODUCTVERSION, - TOK_VI_PRODUCTNAME, - TOK_VI_COMPANY, - TOK_VI_COMMENTS, - TOK_VI_LEGALTRADEMARKS, - TOK_VI_LEGALCOPYRIGHTS, - TOK_VI_DESCRIPTION, + TOK_VI_ADDKEY, + TOK_VI_ADDTRANSLATION, + TOK_VI_SETPRODUCTVERSION, + TOK_VI_SETVERSIONLANGUAGE, TOK__LAST, TOK__PLUGINCOMMAND diff --git a/TODO.txt b/TODO.txt index bf236a9c..f232c80f 100644 --- a/TODO.txt +++ b/TODO.txt @@ -6,7 +6,7 @@ NSIS * DATE, FILE, TIME, etc. defines -* add version numbers for the installer +* add named user variables * component page for uninstaller, multiple sections