From 859c2ad6eb63393200887f518ac275e40761b281 Mon Sep 17 00:00:00 2001 From: anders_k Date: Thu, 29 Dec 2016 21:59:35 +0000 Subject: [PATCH] Added basic WriteRegMultiStr support (RFE #382, patch #219) git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6829 212acab6-be3b-0410-9dea-997c60f758d6 --- Docs/src/history.but | 4 ++++ Docs/src/registry.but | 8 +++++++ Source/Platform.h | 1 + Source/exehead/exec.c | 2 +- Source/lineparse.cpp | 25 +++++++++++++++++++++ Source/lineparse.h | 1 + Source/script.cpp | 52 +++++++++++++++++-------------------------- Source/tokens.cpp | 1 + Source/tokens.h | 1 + 9 files changed, 62 insertions(+), 33 deletions(-) diff --git a/Docs/src/history.but b/Docs/src/history.but index ad164128..d3c40afb 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -6,6 +6,10 @@ Released on ? ?th, 2017 \S1{v3.02-cl} Changelog +\S2{} Major Changes + +\b Added \R{writeregmultistr}{WriteRegMultiStr} (\W{http://sf.net/p/nsis/feature-requests/382}{RFE #382}, \W{http://sf.net/p/nsis/patches/219}{patch #219}) + \S2{} Minor Changes \b MultiUser now supports $ProgramFiles64 (\W{http://sf.net/p/nsis/bugs/843}{bug #843}) diff --git a/Docs/src/registry.but b/Docs/src/registry.but index 90c0b392..880827d9 100644 --- a/Docs/src/registry.but +++ b/Docs/src/registry.but @@ -188,6 +188,14 @@ The error flag is set if the string could not be written to the registry. The ty \c WriteRegExpandStr HKLM "Software\My Company\My Software" "Expand String Value" "%WINDIR%\notepad.exe" +\S2{writeregmultistr} WriteRegMultiStr + +\c /REGEDIT5 root_key subkey key_name value + +Writes a multi-string value. The /REGEDIT5 switch must be used and specifies that the data is in the hex format used by .reg files on Windows 2000 and later. + +\c WriteRegMultiStr /REGEDIT5 HKCU "Software\NSIS\Test" "Multi Value" 66,00,6f,00,6f,00,00,00,62,00,61,00,72,00,00,00,00,00 + \S2{setregview} SetRegView \c \\32\\|64|lastused diff --git a/Source/Platform.h b/Source/Platform.h index aa85d50f..e9a88f63 100644 --- a/Source/Platform.h +++ b/Source/Platform.h @@ -651,6 +651,7 @@ typedef DWORDLONG ULONGLONG,*PULONGLONG; # define REG_EXPAND_SZ 2 # define REG_BINARY 3 # define REG_DWORD 4 +# define REG_MULTI_SZ 7 #endif // show modes diff --git a/Source/exehead/exec.c b/Source/exehead/exec.c index 6d5702b7..57762266 100644 --- a/Source/exehead/exec.c +++ b/Source/exehead/exec.c @@ -1274,7 +1274,7 @@ static int NSISCALL ExecuteEntry(entry *entry_) // use buf2, buf3 and buf4 size = GetCompressedDataFromDataBlockToMemory(parm3, data, (3 * NSIS_MAX_STRLEN)*sizeof(TCHAR)); LogData2Hex(binbuf, COUNTOF(binbuf), data, size); - log_printf5(_T("WriteRegBin: \"%s\\%s\" \"%s\"=\"%s\""),rkn,buf1,buf0,binbuf); + log_printf6(_T("%s: \"%s\\%s\" \"%s\"=\"%s\""),rtype==REG_MULTI_SZ?_T("WriteRegMultiStr"):_T("WriteRegBin"),rkn,buf1,buf0,binbuf); } if (size >= 0 && RegSetValueEx(hKey,buf0,0,rtype,data,size) == ERROR_SUCCESS) diff --git a/Source/lineparse.cpp b/Source/lineparse.cpp index 62311e41..8b5b4c04 100644 --- a/Source/lineparse.cpp +++ b/Source/lineparse.cpp @@ -149,6 +149,31 @@ double LineParser::gettoken_number(int token, int *success/*=0*/) const return forceint ? gettoken_int(token,success) : gettoken_float(token,success); } +int LineParser::gettoken_binstrdata(int token, char*buffer, int bufcap) const +{ + const TCHAR*p=gettoken_str(token); + int a,b,c,d=0; + while (*p) + { + a=*p; + if (a >= _T('0') && a <= _T('9')) a-=_T('0'); + else if (a >= _T('a') && a <= _T('f')) a-=_T('a')-10; + else if (a >= _T('A') && a <= _T('F')) a-=_T('A')-10; + else if (a == _T(',')) { ++p; continue; } // Allow comma separator (for Regedit5 .reg format) + else break; + b=*++p; + if (b >= _T('0') && b <= _T('9')) b-=_T('0'); + else if (b >= _T('a') && b <= _T('f')) b-=_T('a')-10; + else if (b >= _T('A') && b <= _T('F')) b-=_T('A')-10; + else break; + c=(a<<4)|b, p++; + if (d >= bufcap) return -1; // Buffer too small + buffer[d++]=c; + } + if (*p) return -2; // Did not parse the entire buffer + return d; +} + TCHAR* LineParser::gettoken_str(int token) const { token+=m_eat; diff --git a/Source/lineparse.h b/Source/lineparse.h index 8df1738d..295b013f 100644 --- a/Source/lineparse.h +++ b/Source/lineparse.h @@ -35,6 +35,7 @@ class LineParser { double gettoken_float(int token, int *success=0) const; int gettoken_int(int token, int *success=0) const; double gettoken_number(int token, int *success=0) const; + int gettoken_binstrdata(int token, char*buffer, int bufcap) const; TCHAR *gettoken_str(int token) const; int gettoken_enum(int token, const TCHAR *strlist); // null separated list diff --git a/Source/script.cpp b/Source/script.cpp index f921d516..dc278fd6 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -5391,60 +5391,47 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) case TOK_WRITEREGSTR: case TOK_WRITEREGEXPANDSTR: case TOK_WRITEREGBIN: + case TOK_WRITEREGMULTISZ: case TOK_WRITEREGDWORD: { + const TCHAR*cmdname=get_commandtoken_name(which_token); + int reg5=0==line.gettoken_enum(1,_T("/REGEDIT5\0")), multisz=which_token==TOK_WRITEREGMULTISZ; + if (reg5) line.eattoken(); int k=line.gettoken_enum(1,rootkeys[0]); if (k == -1) k=line.gettoken_enum(1,rootkeys[1]); - if (k == -1) PRINTHELP() + if (k == -1 || reg5 != multisz) PRINTHELPEX(cmdname); // WriteRegMultiStr only supports the /REGEDIT5 serialized format right now but we really should allow variables at some point. ent.which=EW_WRITEREG; ent.offsets[0]=REGROOTKEYTOINT(rootkey_tab[k]); ent.offsets[1]=add_string(line.gettoken_str(2)); if (line.gettoken_str(2)[0] == _T('\\')) - warning_fl(_T("%") NPRIs _T(": registry path name begins with \'\\\', may cause problems"),line.gettoken_str(0)); + warning_fl(_T("%") NPRIs _T(": registry path name begins with \'\\\', may cause problems"),cmdname); ent.offsets[2]=add_string(line.gettoken_str(3)); if (which_token == TOK_WRITEREGSTR || which_token == TOK_WRITEREGEXPANDSTR) { SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T("\\%") NPRIs _T("\\%") NPRIs _T("=%") NPRIs _T("\n"), - line.gettoken_str(0),line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); + cmdname,line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); ent.offsets[3]=add_string(line.gettoken_str(4)); ent.offsets[4]=ent.offsets[5]=REG_SZ; if (which_token == TOK_WRITEREGEXPANDSTR) ent.offsets[5]=REG_EXPAND_SZ; } - if (which_token == TOK_WRITEREGBIN) + if (which_token == TOK_WRITEREGBIN || multisz) { - char data[3*NSIS_MAX_STRLEN]; // Jim Park: Keep the data as char / 8 bits - TCHAR *p=line.gettoken_str(4); - int data_len=0; - while (*p) + char data[3*NSIS_MAX_STRLEN]; + int data_len=line.gettoken_binstrdata(4, data, sizeof(data)); + if (data_len < 0) { - int c; - int a,b; - a=*p; - if (a >= _T('0') && a <= _T('9')) a-=_T('0'); - else if (a >= _T('a') && a <= _T('f')) a-=_T('a')-10; - else if (a >= _T('A') && a <= _T('F')) a-=_T('A')-10; - else break; - b=*++p; - if (b >= _T('0') && b <= _T('9')) b-=_T('0'); - else if (b >= _T('a') && b <= _T('f')) b-=_T('a')-10; - else if (b >= _T('A') && b <= _T('F')) b-=_T('A')-10; - else break; - p++; - c=(a<<4)|b; - if (data_len >= 3*NSIS_MAX_STRLEN) - { - ERROR_MSG(_T("WriteRegBin: %d bytes of data exceeded\n"),3*NSIS_MAX_STRLEN); - return PS_ERROR; - } - data[data_len++]=c; + if (data_len == -2) PRINTHELPEX(cmdname); + ERROR_MSG(_T("%") NPRIs _T(": %d bytes of data exceeded\n"),cmdname,sizeof(data)); + return PS_ERROR; } - if (*p) PRINTHELP() - SCRIPT_MSG(_T("WriteRegBin: %") NPRIs _T("\\%") NPRIs _T("\\%") NPRIs _T("=%") NPRIs _T("\n"), - line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); + if (multisz && (data_len < 4 || *(UINT32*)(&data[data_len-4]))) PRINTHELPEX(cmdname); + SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T("\\%") NPRIs _T("\\%") NPRIs _T("=%") NPRIs _T("\n"), + cmdname,line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); + if (multisz && !build_unicode) for (int p1=0, p2=p1; p1 < data_len; data_len--) data[p1++]=data[p2], p2+=2; // BUGBUG: Should convert each string from UTF-16 to DBCS but only exehead knows the codepage, limited to ASCII for now. ent.offsets[3]=add_db_data(data,data_len); if (ent.offsets[3] < 0) return PS_ERROR; - ent.offsets[4]=ent.offsets[5]=REG_BINARY; + ent.offsets[4]=REG_BINARY, ent.offsets[5]=multisz?REG_MULTI_SZ:REG_BINARY; } if (which_token == TOK_WRITEREGDWORD) { @@ -5481,6 +5468,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) case TOK_WRITEREGSTR: case TOK_WRITEREGEXPANDSTR: case TOK_WRITEREGBIN: + case TOK_WRITEREGMULTISZ: case TOK_WRITEREGDWORD: case TOK_ENUMREGKEY: case TOK_ENUMREGVAL: diff --git a/Source/tokens.cpp b/Source/tokens.cpp index 998bcf29..5546de9f 100644 --- a/Source/tokens.cpp +++ b/Source/tokens.cpp @@ -236,6 +236,7 @@ static tokenType tokenlist[TOK__LAST] = {TOK_WINDOWICON,_T("WindowIcon"),1,0,_T("on|off"),TP_GLOBAL}, {TOK_WRITEINISTR,_T("WriteINIStr"),4,0,_T("ini_file section_name entry_name new_value"),TP_CODE}, {TOK_WRITEREGBIN,_T("WriteRegBin"),4,0,_T("rootkey subkey entry_name hex_string_like_12848412AB\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE}, +{TOK_WRITEREGMULTISZ, _T("WriteRegMultiStr"),5,0,_T("/REGEDIT5 rootkey subkey entry_name hex_string_like_660000000000\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE}, {TOK_WRITEREGDWORD,_T("WriteRegDWORD"),4,0,_T("rootkey subkey entry_name new_value_dword\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE}, {TOK_WRITEREGSTR,_T("WriteRegStr"),4,0,_T("rootkey subkey entry_name new_value_string\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE}, {TOK_WRITEREGEXPANDSTR,_T("WriteRegExpandStr"),4,0,_T("rootkey subkey entry_name new_value_string\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE}, diff --git a/Source/tokens.h b/Source/tokens.h index 533b07b0..b952c035 100644 --- a/Source/tokens.h +++ b/Source/tokens.h @@ -186,6 +186,7 @@ enum TOK_WRITEREGSTR, TOK_WRITEREGEXPANDSTR, TOK_WRITEREGBIN, + TOK_WRITEREGMULTISZ, TOK_WRITEREGDWORD, TOK_DELETEINISEC, TOK_DELETEINISTR,