diff options
Diffstat (limited to 'CPP/7zip/Archive/Nsis/NsisIn.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Nsis/NsisIn.cpp | 6343 |
1 files changed, 5403 insertions, 940 deletions
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index 40756008..71791c03 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp @@ -2,1271 +2,5540 @@ #include "StdAfx.h" -#include "../../../../C/CpuArch.h" - -#include "Common/IntToString.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/StreamUtils.h" #include "NsisIn.h" +#define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) +// #define NUM_SPEED_TESTS 1000 + namespace NArchive { namespace NNsis { -Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; +static const size_t kInputBufSize = 1 << 20; + +static const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; +static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; + +static const unsigned kNumCommandParams = 6; +static const unsigned kCmdSize = 4 + kNumCommandParams * 4; #ifdef NSIS_SCRIPT -static const char *kCrLf = "\x0D\x0A"; +#define CR_LF "\x0D\x0A" #endif -#define NS_UN_SKIP_CODE 0xE000 -#define NS_UN_VAR_CODE 0xE001 -#define NS_UN_SHELL_CODE 0xE002 -#define NS_UN_LANG_CODE 0xE003 -#define NS_UN_CODES_START NS_UN_SKIP_CODE -#define NS_UN_CODES_END NS_UN_LANG_CODE +static const char *kErrorStr = "$_ERROR_STR_"; + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + + +/* There are several versions of NSIS: + 1) Original NSIS: + NSIS-2 ANSI + NSIS-3 ANSI + NSIS-3 Unicode + 2) NSIS from Jim Park that extends old NSIS-2 to Unicode support: + NSIS-Park-(1,2,3) ANSI + NSIS-Park-(1,2,3) Unicode -Byte CInArchive::ReadByte() + The command IDs layout is slightly different for different versions. + Also there are additional "log" versions of NSIS that support EW_LOG. + We use the layout of "NSIS-3 Unicode" without "log" as main layout. + And we transfer the command IDs to main layout, if another layout is detected. */ + + +enum { - if (_posInData >= _size) - throw 1; - return _data[_posInData++]; + EW_INVALID_OPCODE, + EW_RET, // Return + EW_NOP, // Nop, Goto + EW_ABORT, // Abort + EW_QUIT, // Quit + EW_CALL, // Call, InitPluginsDir + EW_UPDATETEXT, // DetailPrint + EW_SLEEP, // Sleep + EW_BRINGTOFRONT, // BringToFront + EW_CHDETAILSVIEW, // SetDetailsView + EW_SETFILEATTRIBUTES, // SetFileAttributes + EW_CREATEDIR, // CreateDirectory, SetOutPath + EW_IFFILEEXISTS, // IfFileExists + EW_SETFLAG, // SetRebootFlag, ... + EW_IFFLAG, // IfAbort, IfSilent, IfErrors, IfRebootFlag + EW_GETFLAG, // GetInstDirError, GetErrorLevel + EW_RENAME, // Rename + EW_GETFULLPATHNAME, // GetFullPathName + EW_SEARCHPATH, // SearchPath + EW_GETTEMPFILENAME, // GetTempFileName + EW_EXTRACTFILE, // File + EW_DELETEFILE, // Delete + EW_MESSAGEBOX, // MessageBox + EW_RMDIR, // RMDir + EW_STRLEN, // StrLen + EW_ASSIGNVAR, // StrCpy + EW_STRCMP, // StrCmp + EW_READENVSTR, // ReadEnvStr, ExpandEnvStrings + EW_INTCMP, // IntCmp, IntCmpU + EW_INTOP, // IntOp + EW_INTFMT, // IntFmt + EW_PUSHPOP, // Push/Pop/Exchange + EW_FINDWINDOW, // FindWindow + EW_SENDMESSAGE, // SendMessage + EW_ISWINDOW, // IsWindow + EW_GETDLGITEM, // GetDlgItem + EW_SETCTLCOLORS, // SerCtlColors + EW_SETBRANDINGIMAGE, // SetBrandingImage + EW_CREATEFONT, // CreateFont + EW_SHOWWINDOW, // ShowWindow, EnableWindow, HideWindow + EW_SHELLEXEC, // ExecShell + EW_EXECUTE, // Exec, ExecWait + EW_GETFILETIME, // GetFileTime + EW_GETDLLVERSION, // GetDLLVersion + + // EW_GETFONTVERSION, // Park : 2.46.2 + // EW_GETFONTNAME, // Park : 2.46.3 + + EW_REGISTERDLL, // RegDLL, UnRegDLL, CallInstDLL + EW_CREATESHORTCUT, // CreateShortCut + EW_COPYFILES, // CopyFiles + EW_REBOOT, // Reboot + EW_WRITEINI, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + EW_READINISTR, // ReadINIStr + EW_DELREG, // DeleteRegValue, DeleteRegKey + EW_WRITEREG, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + EW_READREGSTR, // ReadRegStr, ReadRegDWORD + EW_REGENUM, // EnumRegKey, EnumRegValue + EW_FCLOSE, // FileClose + EW_FOPEN, // FileOpen + EW_FPUTS, // FileWrite, FileWriteByte + EW_FGETS, // FileRead, FileReadByte + + // Park + // EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord + // EW_FGETWS, // FileReadUTF16LE, FileReadWord + + EW_FSEEK, // FileSeek + EW_FINDCLOSE, // FindClose + EW_FINDNEXT, // FindNext + EW_FINDFIRST, // FindFirst + EW_WRITEUNINSTALLER, // WriteUninstaller + + // Park : since 2.46.3 the log is enabled in main Park version + // EW_LOG, // LogSet, LogText + + EW_SECTIONSET, // Get*, Set* + EW_INSTTYPESET, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + + // instructions not actually implemented in exehead, but used in compiler. + EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR + EW_GETFUNCTIONADDR, + + EW_LOCKWINDOW, // LockWindow + + // 2 unicode commands available only in Unicode archive + EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord + EW_FGETWS, // FileReadUTF16LE, FileReadWord + + // The following IDs are not IDs in real order. + // We just need some IDs to translate eny extended layout to main layout. + + EW_LOG, // LogSet, LogText + + // Park + EW_FINDPROC, // FindProc + + EW_GETFONTVERSION, // GetFontVersion + EW_GETFONTNAME, // GetFontName + + kNumCmds +}; + +static const unsigned kNumAdditionalParkCmds = 3; + +struct CCommandInfo +{ + Byte NumParams; +}; + +static const CCommandInfo k_Commands[kNumCmds] = +{ + { 0 }, // "Invalid" }, + { 0 }, // Return + { 1 }, // Nop, Goto + { 1 }, // "Abort" }, + { 0 }, // "Quit" }, + { 2 }, // Call + { 6 }, // "DetailPrint" }, // 1 param in new versions, 6 in old NSIS versions + { 1 }, // "Sleep" }, + { 0 }, // "BringToFront" }, + { 2 }, // "SetDetailsView" }, + { 2 }, // "SetFileAttributes" }, + { 2 }, // CreateDirectory, SetOutPath + { 3 }, // "IfFileExists" }, + { 3 }, // SetRebootFlag, ... + { 4 }, // "If" }, // IfAbort, IfSilent, IfErrors, IfRebootFlag + { 2 }, // "Get" }, // GetInstDirError, GetErrorLevel + { 4 }, // "Rename" }, + { 3 }, // "GetFullPathName" }, + { 2 }, // "SearchPath" }, + { 2 }, // "GetTempFileName" }, + { 6 }, // "File" + { 2 }, // "Delete" }, + { 6 }, // "MessageBox" }, + { 2 }, // "RMDir" }, + { 2 }, // "StrLen" }, + { 4 }, // StrCpy, GetCurrentAddress + { 5 }, // "StrCmp" }, + { 3 }, // ReadEnvStr, ExpandEnvStrings + { 6 }, // "IntCmp" }, + { 4 }, // "IntOp" }, + { 3 }, // "IntFmt" }, + { 6 }, // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. + { 5 }, // "FindWindow" }, + { 6 }, // "SendMessage" }, + { 3 }, // "IsWindow" }, + { 3 }, // "GetDlgItem" }, + { 2 }, // "SetCtlColors" }, + { 3 }, // "SetBrandingImage" }, + { 5 }, // "CreateFont" }, + { 4 }, // ShowWindow, EnableWindow, HideWindow + { 6 }, // "ExecShell" }, + { 3 }, // "Exec" }, // Exec, ExecWait + { 3 }, // "GetFileTime" }, + { 3 }, // "GetDLLVersion" }, + { 6 }, // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. + { 6 }, // "CreateShortCut" }, + { 4 }, // "CopyFiles" }, + { 1 }, // "Reboot" }, + { 5 }, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + { 4 }, // "ReadINIStr" }, + { 5 }, // "DeleteReg" }, // DeleteRegKey, DeleteRegValue + { 6 }, // "WriteReg" }, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + { 5 }, // "ReadReg" }, // ReadRegStr, ReadRegDWORD + { 5 }, // "EnumReg" }, // EnumRegKey, EnumRegValue + { 1 }, // "FileClose" }, + { 4 }, // "FileOpen" }, + { 3 }, // "FileWrite" }, // FileWrite, FileWriteByte + { 4 }, // "FileRead" }, // FileRead, FileReadByte + { 4 }, // "FileSeek" }, + { 1 }, // "FindClose" }, + { 2 }, // "FindNext" }, + { 3 }, // "FindFirst" }, + { 4 }, // "WriteUninstaller" }, + { 5 }, // "Section" }, // *** + { 4 }, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + { 6 }, // "GetLabelAddr" }, + { 2 }, // "GetFunctionAddress" }, + { 1 }, // "LockWindow" }, + { 3 }, // "FileWrite" }, // FileWriteUTF16LE, FileWriteWord + { 4 }, // "FileRead" }, // FileReadUTF16LE, FileReadWord + + { 2 }, // "Log" }, // LogSet, LogText + // Park + { 2 }, // "FindProc" }, + { 2 }, // "GetFontVersion" }, + { 2 }, // "GetFontName" } +}; + +#ifdef NSIS_SCRIPT + +static const char *k_CommandNames[kNumCmds] = +{ + "Invalid" + , NULL // Return + , NULL // Nop, Goto + , "Abort" + , "Quit" + , NULL // Call + , "DetailPrint" // 1 param in new versions, 6 in old NSIS versions + , "Sleep" + , "BringToFront" + , "SetDetailsView" + , "SetFileAttributes" + , NULL // CreateDirectory, SetOutPath + , "IfFileExists" + , NULL // SetRebootFlag, ... + , "If" // IfAbort, IfSilent, IfErrors, IfRebootFlag + , "Get" // GetInstDirError, GetErrorLevel + , "Rename" + , "GetFullPathName" + , "SearchPath" + , "GetTempFileName" + , NULL // File + , "Delete" + , "MessageBox" + , "RMDir" + , "StrLen" + , NULL // StrCpy, GetCurrentAddress + , "StrCmp" + , NULL // ReadEnvStr, ExpandEnvStrings + , "IntCmp" + , "IntOp" + , "IntFmt" + , NULL // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. + , "FindWindow" + , "SendMessage" + , "IsWindow" + , "GetDlgItem" + , "SetCtlColors" + , "SetBrandingImage" + , "CreateFont" + , NULL // ShowWindow, EnableWindow, HideWindow + , "ExecShell" + , "Exec" // Exec, ExecWait + , "GetFileTime" + , "GetDLLVersion" + , NULL // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. + , "CreateShortCut" + , "CopyFiles" + , "Reboot" + , NULL // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + , "ReadINIStr" + , "DeleteReg" // DeleteRegKey, DeleteRegValue + , "WriteReg" // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + , "ReadReg" // ReadRegStr, ReadRegDWORD + , "EnumReg" // EnumRegKey, EnumRegValue + , "FileClose" + , "FileOpen" + , "FileWrite" // FileWrite, FileWriteByte + , "FileRead" // FileRead, FileReadByte + , "FileSeek" + , "FindClose" + , "FindNext" + , "FindFirst" + , "WriteUninstaller" + , "Section" // *** + , NULL // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + , "GetLabelAddr" + , "GetFunctionAddress" + , "LockWindow" + , "FileWrite" // FileWriteUTF16LE, FileWriteWord + , "FileRead" // FileReadUTF16LE, FileReadWord + + , "Log" // LogSet, LogText + + // Park + , "FindProc" + , "GetFontVersion" + , "GetFontName" +}; + +#endif + +/* NSIS can use one name for two CSIDL_*** and CSIDL_COMMON_*** items (CurrentUser / AllUsers) + Some NSIS shell names are not identical to WIN32 CSIDL_* names. + NSIS doesn't use some CSIDL_* values. But we add name for all CSIDL_ (marked with '+'). */ + +static const char *kShellStrings[] = +{ + "DESKTOP" // + + , "INTERNET" // + + , "SMPROGRAMS" // CSIDL_PROGRAMS + , "CONTROLS" // + + , "PRINTERS" // + + , "DOCUMENTS" // CSIDL_PERSONAL + , "FAVORITES" // CSIDL_FAVORITES + , "SMSTARTUP" // CSIDL_STARTUP + , "RECENT" // CSIDL_RECENT + , "SENDTO" // CSIDL_SENDTO + , "BITBUCKET" // + + , "STARTMENU" + , NULL // CSIDL_MYDOCUMENTS = CSIDL_PERSONAL + , "MUSIC" // CSIDL_MYMUSIC + , "VIDEOS" // CSIDL_MYVIDEO + , NULL + , "DESKTOP" // CSIDL_DESKTOPDIRECTORY + , "DRIVES" // + + , "NETWORK" // + + , "NETHOOD" + , "FONTS" + , "TEMPLATES" + , "STARTMENU" // CSIDL_COMMON_STARTMENU + , "SMPROGRAMS" // CSIDL_COMMON_PROGRAMS + , "SMSTARTUP" // CSIDL_COMMON_STARTUP + , "DESKTOP" // CSIDL_COMMON_DESKTOPDIRECTORY + , "APPDATA" // CSIDL_APPDATA !!! "QUICKLAUNCH" + , "PRINTHOOD" + , "LOCALAPPDATA" + , "ALTSTARTUP" + , "ALTSTARTUP" // CSIDL_COMMON_ALTSTARTUP + , "FAVORITES" // CSIDL_COMMON_FAVORITES + , "INTERNET_CACHE" + , "COOKIES" + , "HISTORY" + , "APPDATA" // CSIDL_COMMON_APPDATA + , "WINDIR" + , "SYSDIR" + , "PROGRAM_FILES" // + + , "PICTURES" // CSIDL_MYPICTURES + , "PROFILE" + , "SYSTEMX86" // + + , "PROGRAM_FILESX86" // + + , "PROGRAM_FILES_COMMON" // + + , "PROGRAM_FILES_COMMONX8" // + CSIDL_PROGRAM_FILES_COMMONX86 + , "TEMPLATES" // CSIDL_COMMON_TEMPLATES + , "DOCUMENTS" // CSIDL_COMMON_DOCUMENTS + , "ADMINTOOLS" // CSIDL_COMMON_ADMINTOOLS + , "ADMINTOOLS" // CSIDL_ADMINTOOLS + , "CONNECTIONS" // + + , NULL + , NULL + , NULL + , "MUSIC" // CSIDL_COMMON_MUSIC + , "PICTURES" // CSIDL_COMMON_PICTURES + , "VIDEOS" // CSIDL_COMMON_VIDEO + , "RESOURCES" + , "RESOURCES_LOCALIZED" + , "COMMON_OEM_LINKS" // + + , "CDBURN_AREA" + , NULL // unused + , "COMPUTERSNEARME" // + +}; + + +static void UIntToString(AString &s, UInt32 v) +{ + char sz[16]; + ConvertUInt32ToString(v, sz); + s += sz; } -UInt32 CInArchive::ReadUInt32() +#ifdef NSIS_SCRIPT + +void CInArchive::Add_UInt(UInt32 v) { - UInt32 value = 0; - for (int i = 0; i < 4; i++) - value |= ((UInt32)(ReadByte()) << (8 * i)); - return value; + char sz[16]; + ConvertUInt32ToString(v, sz); + Script += sz; } -void CInArchive::ReadBlockHeader(CBlockHeader &bh) +static void Add_SignedInt(CDynLimBuf &s, Int32 v) { - bh.Offset = ReadUInt32(); - bh.Num = ReadUInt32(); + char sz[32]; + ConvertInt64ToString(v, sz); + s += sz; } -#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } +static void Add_Hex(CDynLimBuf &s, UInt32 v) +{ + char sz[16]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(v, sz + 2); + s += sz; +} -static int CompareItems(void *const *p1, void *const *p2, void * /* param */) +static UInt32 GetUi16Str_Len(const Byte *p) { - const CItem &i1 = **(CItem **)p1; - const CItem &i2 = **(CItem **)p2; - RINOZ(MyCompare(i1.Pos, i2.Pos)); - if (i1.IsUnicode) + const Byte *pp = p; + for (; *pp != 0 || *(pp + 1) != 0; pp += 2); + return (UInt32)((pp - p) >> 1); +} + +void CInArchive::AddLicense(UInt32 param, Int32 langID) +{ + Space(); + if (param >= NumStringChars || + param + 1 >= NumStringChars) + { + Script += kErrorStr; + return; + } + strUsed[param] = 1; + + UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param); + UInt32 offset = start + (IsUnicode ? 2 : 1); + { + FOR_VECTOR (i, LicenseFiles) + { + const CLicenseFile &lic = LicenseFiles[i]; + if (offset == lic.Offset) + { + Script += lic.Name; + return; + } + } + } + AString fileName = "[LICENSE]"; + if (langID >= 0) + { + fileName += "\\license-"; + // LangId_To_String(fileName, langID); + UIntToString(fileName, langID); + } + else if (++_numRootLicenses > 1) { - RINOZ(i1.PrefixU.Compare(i2.PrefixU)); - RINOZ(i1.NameU.Compare(i2.NameU)); + fileName += '-'; + UIntToString(fileName, _numRootLicenses); } + const Byte *sz = (_data + start); + unsigned marker = IsUnicode ? Get16(sz) : *sz; + bool isRTF = (marker == 2); + fileName += isRTF ? ".rtf" : ".txt"; // if (*sz == 1) it's text; + Script += fileName; + + CLicenseFile &lic = LicenseFiles.AddNew(); + lic.Name = fileName; + lic.Offset = offset; + if (!IsUnicode) + lic.Size = (UInt32)strlen((const char *)sz + 1); else { - RINOZ(i1.PrefixA.Compare(i2.PrefixA)); - RINOZ(i1.NameA.Compare(i2.NameA)); + sz += 2; + UInt32 len = GetUi16Str_Len(sz); + lic.Size = len * 2; + if (isRTF) + { + lic.Text.Alloc((size_t)len); + for (UInt32 i = 0; i < len; i++, sz += 2) + { + unsigned c = Get16(sz); + if (c >= 256) + c = '?'; + lic.Text[i] = (Byte)(c); + } + lic.Size = len; + lic.Offset = 0; + } } - return 0; } -static AString UIntToString(UInt32 v) +#endif + + +#define kVar_CMDLINE 20 +#define kVar_INSTDIR 21 +#define kVar_OUTDIR 22 +#define kVar_EXEDIR 23 +#define kVar_LANGUAGE 24 +#define kVar_TEMP 25 +#define kVar_PLUGINSDIR 26 +#define kVar_EXEPATH 27 // NSIS 2.26+ +#define kVar_EXEFILE 28 // NSIS 2.26+ + +#define kVar_HWNDPARENT_225 27 +#define kVar_HWNDPARENT 29 + +// #define kVar__CLICK 30 +#define kVar_Spec_OUTDIR_225 29 // NSIS 2.04 - 2.25 +#define kVar_Spec_OUTDIR 31 // NSIS 2.26+ + + +static const char *kVarStrings[] = { - char sz[32]; - ConvertUInt64ToString(v, sz); - return sz; + "CMDLINE" + , "INSTDIR" + , "OUTDIR" + , "EXEDIR" + , "LANGUAGE" + , "TEMP" + , "PLUGINSDIR" + , "EXEPATH" // NSIS 2.26+ + , "EXEFILE" // NSIS 2.26+ + , "HWNDPARENT" + , "_CLICK" // is set from page->clicknext + , "_OUTDIR" // NSIS 2.04+ +}; + +static const unsigned kNumInternalVars = 20 + ARRAY_SIZE(kVarStrings); + +#define GET_NUM_INTERNAL_VARS (IsNsis200 ? kNumInternalVars - 3 : IsNsis225 ? kNumInternalVars - 2 : kNumInternalVars); + +void CInArchive::GetVar2(AString &res, UInt32 index) +{ + if (index < 20) + { + if (index >= 10) + { + res += 'R'; + index -= 10; + } + UIntToString(res, index); + } + else + { + unsigned numInternalVars = GET_NUM_INTERNAL_VARS; + if (index < numInternalVars) + { + if (IsNsis225 && index >= kVar_EXEPATH) + index += 2; + res += kVarStrings[index - 20]; + } + else + { + res += '_'; + UIntToString(res, index - numInternalVars); + res += '_'; + } + } } -static AString IntToString(Int32 v) +void CInArchive::GetVar(AString &res, UInt32 index) { - char sz[32]; - ConvertInt64ToString(v, sz); - return sz; + res += '$'; + GetVar2(res, index); +} + +#ifdef NSIS_SCRIPT + +void CInArchive::Add_Var(UInt32 index) +{ + _tempString_for_GetVar.Empty(); + GetVar(_tempString_for_GetVar, index); + Script += _tempString_for_GetVar; +} + +void CInArchive::AddParam_Var(UInt32 index) +{ + Space(); + Add_Var(index); +} + +void CInArchive::AddParam_UInt(UInt32 value) +{ + Space(); + Add_UInt(value); +} + +#endif + + +#define NS_CODE_SKIP 252 +#define NS_CODE_VAR 253 +#define NS_CODE_SHELL 254 +#define NS_CODE_LANG 255 + +#define NS_3_CODE_LANG 1 +#define NS_3_CODE_SHELL 2 +#define NS_3_CODE_VAR 3 +#define NS_3_CODE_SKIP 4 + +#define PARK_CODE_SKIP 0xE000 +#define PARK_CODE_VAR 0xE001 +#define PARK_CODE_SHELL 0xE002 +#define PARK_CODE_LANG 0xE003 + +#define IS_NS_SPEC_CHAR(c) ((c) >= NS_CODE_SKIP) +#define IS_PARK_SPEC_CHAR(c) ((c) >= PARK_CODE_SKIP && (c) <= PARK_CODE_LANG) + +#define DECODE_NUMBER_FROM_2_CHARS(c0, c1) (((c0) & 0x7F) | (((unsigned)((c1) & 0x7F)) << 7)) +#define CONVERT_NUMBER_NS_3_UNICODE(n) n = ((n & 0x7F) | (((n >> 8) & 0x7F) << 7)) +#define CONVERT_NUMBER_PARK(n) n &= 0x7FFF + + +static bool AreStringsEqual_16and8(const Byte *p16, const char *p8) +{ + for (;;) + { + unsigned c16 = Get16(p16); p16 += 2; + unsigned c = (Byte)(*p8++); + if (c16 != c) + return false; + if (c == 0) + return true; + } +} + +void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2) +{ + // zeros are not allowed here. + // if (index1 == 0 || index2 == 0) throw 333; + + if ((index1 & 0x80) != 0) + { + unsigned offset = (index1 & 0x3F); + + /* NSIS reads registry string: + keyName = HKLM Software\\Microsoft\\Windows\\CurrentVersion + mask = KEY_WOW64_64KEY, If 64-bit flag in index1 is set + valueName = string(offset) + If registry reading is failed, NSIS uses second parameter (index2) + to read string. The recursion is possible in that case in NSIS. + We don't parse index2 string. We only set strUsed status for that + string (but without recursion). */ + + if (offset >= NumStringChars) + { + s += kErrorStr; + return; + } + + #ifdef NSIS_SCRIPT + strUsed[offset] = 1; + if (index2 < NumStringChars) + strUsed[index2] = 1; + #endif + + const Byte *p = (const Byte *)(_data + _stringsPos); + int id = -1; + if (IsUnicode) + { + p += offset * 2; + if (AreStringsEqual_16and8(p, "ProgramFilesDir")) + id = 0; + else if (AreStringsEqual_16and8(p, "CommonFilesDir")) + id = 1; + } + else + { + p += offset; + if (strcmp((const char *)p, "ProgramFilesDir") == 0) + id = 0; + else if (strcmp((const char *)p, "CommonFilesDir") == 0) + id = 1; + } + + s += ((id >= 0) ? (id == 0 ? "$PROGRAMFILES" : "$COMMONFILES") : + "$_ERROR_UNSUPPORTED_VALUE_REGISTRY_"); + // s += ((index1 & 0x40) != 0) ? "64" : "32"; + if ((index1 & 0x40) != 0) + s += "64"; + + if (id < 0) + { + s += '('; + if (IsUnicode) + { + for (unsigned i = 0; i < 256; i++) + { + wchar_t c = Get16(p + i * 2); + if (c == 0) + break; + if (c < 0x80) + s += (char)c; + } + } + else + s += (const char *)p; + s += ')'; + } + return; + } + + s += '$'; + if (index1 < ARRAY_SIZE(kShellStrings)) + { + const char *sz = kShellStrings[index1]; + if (sz) + { + s += sz; + return; + } + } + if (index2 < ARRAY_SIZE(kShellStrings)) + { + const char *sz = kShellStrings[index2]; + if (sz) + { + s += sz; + return; + } + } + s += "_ERROR_UNSUPPORTED_SHELL_"; + s += '['; + UIntToString(s, index1); + s += ','; + UIntToString(s, index2); + s += ']'; +} + +#ifdef NSIS_SCRIPT + +void CInArchive::Add_LangStr_Simple(UInt32 id) +{ + Script += "LSTR_"; + Add_UInt(id); +} + +#endif + +void CInArchive::Add_LangStr(AString &res, UInt32 id) +{ + #ifdef NSIS_SCRIPT + langStrIDs.Add(id); + #endif + res += "$(LSTR_"; + UIntToString(res, id); + res += ')'; +} + +void CInArchive::GetNsisString_Raw(const Byte *s) +{ + Raw_AString.Empty(); + + if (NsisType != k_NsisType_Nsis3) + { + for (;;) + { + Byte c = *s++; + if (c == 0) + return; + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + + if (c == NS_CODE_SHELL) + GetShellString(Raw_AString, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + continue; + } + c = c0; + } + Raw_AString += (char)c; + } + } + + // NSIS-3 ANSI + for (;;) + { + Byte c = *s++; + if (c <= NS_3_CODE_SKIP) + { + if (c == 0) + return; + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_3_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + + if (c == NS_3_CODE_SHELL) + GetShellString(Raw_AString, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_3_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + continue; + } + c = c0; + } + Raw_AString += (char)c; + } +} + +#ifdef NSIS_SCRIPT + +void CInArchive::GetNsisString(AString &res, const Byte *s) +{ + for (;;) + { + Byte c = *s++; + if (c == 0) + return; + if (NsisType != k_NsisType_Nsis3) + { + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + if (c == NS_CODE_SHELL) + GetShellString(res, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_CODE_VAR) + GetVar(res, n); + else // if (c == NS_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = c0; + } + } + else + { + // NSIS-3 ANSI + if (c <= NS_3_CODE_SKIP) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c0 == 0) + break; + if (c != NS_3_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + if (c == NS_3_CODE_SHELL) + GetShellString(res, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_3_CODE_VAR) + GetVar(res, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = c0; + } + } + + { + const char *e; + if (c == 9) e = "$\\t"; + else if (c == 10) e = "$\\n"; + else if (c == 13) e = "$\\r"; + else if (c == '"') e = "$\\\""; + else if (c == '$') e = "$$"; + else + { + res += (char)c; + continue; + } + res += e; + continue; + } + } } -AString CInArchive::ReadStringA(UInt32 pos) const +#endif + +void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) { - AString s; - if (pos >= _size) - return IntToString((Int32)pos); - UInt32 offset = GetOffset() + _stringsPos + pos; + Raw_UString.Empty(); + + if (IsPark()) + { + for (;;) + { + unsigned c = Get16(p); + p += 2; + if (c == 0) + break; + if (c < 0x80) + { + Raw_UString += (wchar_t)c; + continue; + } + + if (IS_PARK_SPEC_CHAR(c)) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != PARK_CODE_SKIP) + { + Raw_AString.Empty(); + if (c == PARK_CODE_SHELL) + GetShellString(Raw_AString, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_PARK(n); + if (c == PARK_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == PARK_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + for (const Byte *s = (const Byte *)(const char *)Raw_AString; *s != 0; s++) + Raw_UString += *s; + continue; + } + c = n; + } + + Raw_UString += (wchar_t)c; + } + + return; + } + + // NSIS-3 Unicode for (;;) { - if (offset >= _size) - break; // throw 1; - char c = _data[offset++]; + unsigned c = Get16(p); + p += 2; + if (c > NS_3_CODE_SKIP) + { + Raw_UString += (wchar_t)c; + continue; + } if (c == 0) break; - s += c; + + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c == NS_3_CODE_SKIP) + { + Raw_UString += (wchar_t)n; + continue; + } + + Raw_AString.Empty(); + if (c == NS_3_CODE_SHELL) + GetShellString(Raw_AString, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_NS_3_UNICODE(n); + if (c == NS_3_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + for (const Byte *s = (const Byte *)(const char *)Raw_AString; *s != 0; s++) + Raw_UString += (wchar_t)*s; } - return s; } -UString CInArchive::ReadStringU(UInt32 pos) const +#ifdef NSIS_SCRIPT + +static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +void CInArchive::GetNsisString_Unicode(AString &res, const Byte *p) { - UString s; - UInt32 offset = GetOffset() + _stringsPos + (pos * 2); for (;;) { - if (offset >= _size || offset + 1 >= _size) - return s; // throw 1; - char c0 = _data[offset++]; - char c1 = _data[offset++]; - wchar_t c = (c0 | ((wchar_t)c1 << 8)); + unsigned c = Get16(p); + p += 2; if (c == 0) break; - s += c; + if (IsPark()) + { + if (IS_PARK_SPEC_CHAR(c)) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != PARK_CODE_SKIP) + { + if (c == PARK_CODE_SHELL) + GetShellString(res, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_PARK(n); + if (c == PARK_CODE_VAR) + GetVar(res, n); + else // if (c == PARK_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = n; + } + } + else + { + // NSIS-3 Unicode + if (c <= NS_3_CODE_SKIP) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != NS_3_CODE_SKIP) + { + if (c == NS_3_CODE_SHELL) + GetShellString(res, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_NS_3_UNICODE(n); + if (c == NS_3_CODE_VAR) + GetVar(res, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = n; + } + } + + if (c < 0x80) + { + const char *e; + if (c == 9) e = "$\\t"; + else if (c == 10) e = "$\\n"; + else if (c == 13) e = "$\\r"; + else if (c == '"') e = "$\\\""; + else if (c == '$') e = "$$"; + else + { + res += (char)c; + continue; + } + res += e; + continue; + } + + UInt32 value = c; + /* + if (value >= 0xD800 && value < 0xE000) + { + UInt32 c2; + if (value >= 0xDC00 || srcPos == srcLen) + break; + c2 = src[srcPos++]; + if (c2 < 0xDC00 || c2 >= 0xE000) + break; + value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + } + */ + unsigned numAdds; + for (numAdds = 1; numAdds < 5; numAdds++) + if (value < (((UInt32)1) << (numAdds * 5 + 6))) + break; + res += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); + do + { + numAdds--; + res += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); + // destPos++; + } + while (numAdds != 0); + + // AddToUtf8(res, c); } - return s; } -/* -static AString ParsePrefix(const AString &prefix) +#endif + +void CInArchive::ReadString2_Raw(UInt32 pos) { - AString res = prefix; - if (prefix.Length() >= 3) + Raw_AString.Empty(); + Raw_UString.Empty(); + if ((Int32)pos < 0) + Add_LangStr(Raw_AString, -((Int32)pos + 1)); + else if (pos >= NumStringChars) { - if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x95 && (Byte)prefix[2] == 0x80) - res = "$INSTDIR" + prefix.Mid(3); - else if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x96 && (Byte)prefix[2] == 0x80) - res = "$OUTDIR" + prefix.Mid(3); + Raw_AString += kErrorStr; + // UIntToString(Raw_AString, pos); } - return res; + else + { + if (IsUnicode) + GetNsisString_Unicode_Raw(_data + _stringsPos + pos * 2); + else + GetNsisString_Raw(_data + _stringsPos + pos); + return; + } + for (const char *s = (const char *)Raw_AString; *s != 0; s++) + Raw_UString += *s; } -*/ -#define SYSREGKEY "Software\\Microsoft\\Windows\\CurrentVersion" +bool CInArchive::IsGoodString(UInt32 param) const +{ + if (param >= NumStringChars) + return false; + if (param == 0) + return true; + const Byte *p = _data + _stringsPos; + if (IsUnicode) + return (Get16(p + param * 2 - 2)) == 0; + return p[param - 1] == 0; +} -/* -# define CSIDL_PROGRAMS 0x2 -# define CSIDL_PRINTERS 0x4 -# define CSIDL_PERSONAL 0x5 -# define CSIDL_FAVORITES 0x6 -# define CSIDL_STARTUP 0x7 -# define CSIDL_RECENT 0x8 -# define CSIDL_SENDTO 0x9 -# define CSIDL_STARTMENU 0xB -# define CSIDL_MYMUSIC 0xD -# define CSIDL_MYVIDEO 0xE - -# define CSIDL_DESKTOPDIRECTORY 0x10 -# define CSIDL_NETHOOD 0x13 -# define CSIDL_FONTS 0x14 -# define CSIDL_TEMPLATES 0x15 -# define CSIDL_COMMON_STARTMENU 0x16 -# define CSIDL_COMMON_PROGRAMS 0x17 -# define CSIDL_COMMON_STARTUP 0x18 -# define CSIDL_COMMON_DESKTOPDIRECTORY 0x19 -# define CSIDL_APPDATA 0x1A -# define CSIDL_PRINTHOOD 0x1B -# define CSIDL_LOCAL_APPDATA 0x1C -# define CSIDL_ALTSTARTUP 0x1D -# define CSIDL_COMMON_ALTSTARTUP 0x1E -# define CSIDL_COMMON_FAVORITES 0x1F - -# define CSIDL_INTERNET_CACHE 0x20 -# define CSIDL_COOKIES 0x21 -# define CSIDL_HISTORY 0x22 -# define CSIDL_COMMON_APPDATA 0x23 -# define CSIDL_WINDOWS 0x24 -# define CSIDL_SYSTEM 0x25 -# define CSIDL_PROGRAM_FILES 0x26 -# define CSIDL_MYPICTURES 0x27 -# define CSIDL_PROFILE 0x28 -# define CSIDL_PROGRAM_FILES_COMMON 0x2B -# define CSIDL_COMMON_TEMPLATES 0x2D -# define CSIDL_COMMON_DOCUMENTS 0x2E -# define CSIDL_COMMON_ADMINTOOLS 0x2F - -# define CSIDL_ADMINTOOLS 0x30 -# define CSIDL_COMMON_MUSIC 0x35 -# define CSIDL_COMMON_PICTURES 0x36 -# define CSIDL_COMMON_VIDEO 0x37 -# define CSIDL_RESOURCES 0x38 -# define CSIDL_RESOURCES_LOCALIZED 0x39 -# define CSIDL_CDBURN_AREA 0x3B -*/ +bool CInArchive::AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const +{ + if (param1 == param2) + return true; + + /* NSIS-3.0a1 probably contains bug, so it can use 2 different strings + with same content. So we check real string also. + Also it's possible to check identical postfix parts of strings. */ + + if (param1 >= NumStringChars || + param2 >= NumStringChars) + return false; + + const Byte *p = _data + _stringsPos; + + if (IsUnicode) + { + const Byte *p1 = p + param1 * 2; + const Byte *p2 = p + param2 * 2; + for (;;) + { + UInt16 c = Get16(p1); + if (c != Get16(p2)) + return false; + if (c == 0) + return true; + p1 += 2; + p2 += 2; + } + } + else + { + const Byte *p1 = p + param1; + const Byte *p2 = p + param2; + for (;;) + { + Byte c = *p1++; + if (c != *p2++) + return false; + if (c == 0) + return true; + } + } +} + +#ifdef NSIS_SCRIPT + +UInt32 CInArchive::GetNumUsedVars() const +{ + UInt32 numUsedVars = 0; + const Byte *data = (const Byte *)_data + _stringsPos; + unsigned npi = 0; + for (UInt32 i = 0; i < NumStringChars;) + { + bool process = true; + if (npi < noParseStringIndexes.Size() && noParseStringIndexes[npi] == i) + { + process = false; + npi++; + } + + if (IsUnicode) + { + if (IsPark()) + { + for (;;) + { + unsigned c = Get16(data + i * 2); + i++; + if (c == 0) + break; + if (IS_PARK_SPEC_CHAR(c)) + { + UInt32 n = Get16(data + i * 2); + i++; + if (n == 0) + break; + if (process && c == PARK_CODE_VAR) + { + CONVERT_NUMBER_PARK(n); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else // NSIS-3 Unicode + { + for (;;) + { + unsigned c = Get16(data + i * 2); + i++; + if (c == 0) + break; + if (c > NS_3_CODE_SKIP) + continue; + UInt32 n = Get16(data + i * 2); + i++; + if (n == 0) + break; + if (process && c == NS_3_CODE_VAR) + { + CONVERT_NUMBER_NS_3_UNICODE(n); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else // not Unicode (ANSI) + { + if (NsisType != k_NsisType_Nsis3) + { + for (;;) + { + Byte c = data[i++]; + if (c == 0) + break; + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = data[i++]; + if (c0 == 0) + break; + if (c == NS_CODE_SKIP) + continue; + Byte c1 = data[i++]; + if (c1 == 0) + break; + if (process && c == NS_CODE_VAR) + { + UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else + { + // NSIS-3 ANSI + for (;;) + { + Byte c = data[i++]; + if (c == 0) + break; + if (c > NS_3_CODE_SKIP) + continue; + + Byte c0 = data[i++]; + if (c0 == 0) + break; + if (c == NS_3_CODE_SKIP) + continue; + Byte c1 = data[i++]; + if (c1 == 0) + break; + if (process && c == NS_3_CODE_VAR) + { + UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + } + return numUsedVars; +} + +void CInArchive::ReadString2(AString &s, UInt32 pos) +{ + if ((Int32)pos < 0) + { + Add_LangStr(s, -((Int32)pos + 1)); + return; + } + + if (pos >= NumStringChars) + { + s += kErrorStr; + // UIntToString(s, pos); + return; + } + + #ifdef NSIS_SCRIPT + strUsed[pos] = 1; + #endif + + if (IsUnicode) + GetNsisString_Unicode(s, _data + _stringsPos + pos * 2); + else + GetNsisString(s, _data + _stringsPos + pos); +} + +#endif + +#ifdef NSIS_SCRIPT + +#define DEL_DIR 1 +#define DEL_RECURSE 2 +#define DEL_REBOOT 4 +// #define DEL_SIMPLE 8 + +void CInArchive::AddRegRoot(UInt32 val) +{ + Space(); + const char *s; + switch (val) + { + case 0: s = "SHCTX"; break; + case 0x80000000: s = "HKCR"; break; + case 0x80000001: s = "HKCU"; break; + case 0x80000002: s = "HKLM"; break; + case 0x80000003: s = "HKU"; break; + case 0x80000004: s = "HKPD"; break; + case 0x80000005: s = "HKCC"; break; + case 0x80000006: s = "HKDD"; break; + case 0x80000050: s = "HKPT"; break; + case 0x80000060: s = "HKPN"; break; + default: + // Script += " RRRRR "; + // throw 1; + Add_Hex(Script, val); return; + } + Script += s; +} -struct CCommandPair +static const char *g_WinAttrib[] = { - int NumParams; - const char *Name; + "READONLY" + , "HIDDEN" + , "SYSTEM" + , NULL + , "DIRECTORY" + , "ARCHIVE" + , "DEVICE" + , "NORMAL" + , "TEMPORARY" + , "SPARSE_FILE" + , "REPARSE_POINT" + , "COMPRESSED" + , "OFFLINE" + , "NOT_CONTENT_INDEXED" + , "ENCRYPTED" + , NULL + , "VIRTUAL" }; -enum +#define FLAGS_DELIMITER '|' + +static void FlagsToString2(CDynLimBuf &s, const char **table, unsigned num, UInt32 flags) { - // 0 - EW_INVALID_OPCODE, // zero is invalid. useful for catching errors. (otherwise an all zeroes instruction - // does nothing, which is easily ignored but means something is wrong. - EW_RET, // return from function call - EW_NOP, // Nop/Jump, do nothing: 1, [?new address+1:advance one] - EW_ABORT, // Abort: 1 [status] - EW_QUIT, // Quit: 0 - EW_CALL, // Call: 1 [new address+1] - EW_UPDATETEXT, // Update status text: 2 [update str, ui_st_updateflag=?ui_st_updateflag:this] - EW_SLEEP, // Sleep: 1 [sleep time in milliseconds] - EW_BRINGTOFRONT, // BringToFront: 0 - EW_CHDETAILSVIEW, // SetDetailsView: 2 [listaction,buttonaction] - - // 10 - EW_SETFILEATTRIBUTES, // SetFileAttributes: 2 [filename, attributes] - EW_CREATEDIR, // Create directory: 2, [path, ?update$INSTDIR] - EW_IFFILEEXISTS, // IfFileExists: 3, [file name, jump amount if exists, jump amount if not exists] - EW_SETFLAG, // Sets a flag: 2 [id, data] - EW_IFFLAG, // If a flag: 4 [on, off, id, new value mask] - EW_GETFLAG, // Gets a flag: 2 [output, id] - EW_RENAME, // Rename: 3 [old, new, rebootok] - EW_GETFULLPATHNAME, // GetFullPathName: 2 [output, input, ?lfn:sfn] - EW_SEARCHPATH, // SearchPath: 2 [output, filename] - EW_GETTEMPFILENAME, // GetTempFileName: 2 [output, base_dir] - - // 20 - EW_EXTRACTFILE, // File to extract: 6 [overwriteflag, output filename, compressed filedata, filedatetimelow, filedatetimehigh, allow ignore] - // overwriteflag: 0x1 = no. 0x0=force, 0x2=try, 0x3=if date is newer - EW_DELETEFILE, // Delete File: 2, [filename, rebootok] - EW_MESSAGEBOX, // MessageBox: 5,[MB_flags,text,retv1:retv2,moveonretv1:moveonretv2] - EW_RMDIR, // RMDir: 2 [path, recursiveflag] - EW_STRLEN, // StrLen: 2 [output, input] - EW_ASSIGNVAR, // Assign: 4 [variable (0-9) to assign, string to assign, maxlen, startpos] - EW_STRCMP, // StrCmp: 5 [str1, str2, jump_if_equal, jump_if_not_equal, case-sensitive?] - EW_READENVSTR, // ReadEnvStr/ExpandEnvStrings: 3 [output, string_with_env_variables, IsRead] - EW_INTCMP, // IntCmp: 6 [val1, val2, equal, val1<val2, val1>val2, unsigned?] - EW_INTOP, // IntOp: 4 [output, input1, input2, op] where op: 0=add, 1=sub, 2=mul, 3=div, 4=bor, 5=band, 6=bxor, 7=bnot input1, 8=lnot input1, 9=lor, 10=land], 11=1%2 - - // 30 - EW_INTFMT, // IntFmt: [output, format, input] - EW_PUSHPOP, // Push/Pop/Exchange: 3 [variable/string, ?pop:push, ?exch] - EW_FINDWINDOW, // FindWindow: 5, [outputvar, window class,window name, window_parent, window_after] - EW_SENDMESSAGE, // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] - EW_ISWINDOW, // IsWindow: 3 [hwnd, jump_if_window, jump_if_notwindow] - EW_GETDLGITEM, // GetDlgItem: 3: [outputvar, dialog, item_id] - EW_SETCTLCOLORS, // SerCtlColors: 3: [hwnd, pointer to struct colors] - EW_SETBRANDINGIMAGE, // SetBrandingImage: 1: [Bitmap file] - EW_CREATEFONT, // CreateFont: 5: [handle output, face name, height, weight, flags] - EW_SHOWWINDOW, // ShowWindow: 2: [hwnd, show state] - - // 40 - EW_SHELLEXEC, // ShellExecute program: 4, [shell action, complete commandline, parameters, showwindow] - EW_EXECUTE, // Execute program: 3,[complete command line,waitflag,>=0?output errorcode] - EW_GETFILETIME, // GetFileTime; 3 [file highout lowout] - EW_GETDLLVERSION, // GetDLLVersion: 3 [file highout lowout] - EW_REGISTERDLL, // Register DLL: 3,[DLL file name, string ptr of function to call, text to put in display (<0 if none/pass parms), 1 - no unload, 0 - unload] - EW_CREATESHORTCUT, // Make Shortcut: 5, [link file, target file, parameters, icon file, iconindex|show mode<<8|hotkey<<16] - EW_COPYFILES, // CopyFiles: 3 [source mask, destination location, flags] - EW_REBOOT, // Reboot: 0 - EW_WRITEINI, // Write INI String: 4, [Section, Name, Value, INI File] - EW_READINISTR, // ReadINIStr: 4 [output, section, name, ini_file] - - // 50 - EW_DELREG, // DeleteRegValue/DeleteRegKey: 4, [root key(int), KeyName, ValueName, delkeyonlyifempty]. ValueName is -1 if delete key - EW_WRITEREG, // Write Registry value: 5, [RootKey(int),KeyName,ItemName,ItemData,typelen] - // typelen=1 for str, 2 for dword, 3 for binary, 0 for expanded str - EW_READREGSTR, // ReadRegStr: 5 [output, rootkey(int), keyname, itemname, ==1?int::str] - EW_REGENUM, // RegEnum: 5 [output, rootkey, keyname, index, ?key:value] - EW_FCLOSE, // FileClose: 1 [handle] - EW_FOPEN, // FileOpen: 4 [name, openmode, createmode, outputhandle] - EW_FPUTS, // FileWrite: 3 [handle, string, ?int:string] - EW_FGETS, // FileRead: 4 [handle, output, maxlen, ?getchar:gets] - EW_FSEEK, // FileSeek: 4 [handle, offset, mode, >=0?positionoutput] - EW_FINDCLOSE, // FindClose: 1 [handle] - - // 60 - EW_FINDNEXT, // FindNext: 2 [output, handle] - EW_FINDFIRST, // FindFirst: 2 [filespec, output, handleoutput] - EW_WRITEUNINSTALLER, // WriteUninstaller: 3 [name, offset, icon_size] - EW_LOG, // LogText: 2 [0, text] / LogSet: [1, logstate] - EW_SECTIONSET, // SectionSetText: 3: [idx, 0, text] - // SectionGetText: 3: [idx, 1, output] - // SectionSetFlags: 3: [idx, 2, flags] - // SectionGetFlags: 3: [idx, 3, output] - EW_INSTTYPESET, // InstTypeSetFlags: 3: [idx, 0, flags] - // InstTypeGetFlags: 3: [idx, 1, output] - // instructions not actually implemented in exehead, but used in compiler. - EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR - EW_GETFUNCTIONADDR, + bool filled = false; + for (unsigned i = 0; i < num; i++) + { + UInt32 f = (UInt32)1 << i; + if ((flags & f) != 0) + { + const char *name = table[i]; + if (name) + { + if (filled) + s += FLAGS_DELIMITER; + filled = true; + s += name; + flags &= ~f; + } + } + } + if (flags != 0) + { + if (filled) + s += FLAGS_DELIMITER; + Add_Hex(s, flags); + } +} + +static bool DoesNeedQuotes(const char *s) +{ + char c = s[0]; + if (c == 0 || c == '#' || c == ';' || (c == '/' && s[1] == '*')) + return true; + for (;;) + { + char c = *s++; + if (c == 0) + return false; + if (c == ' ') + return true; + } +} + +void CInArchive::Add_QuStr(const AString &s) +{ + bool needQuotes = DoesNeedQuotes(s); + if (needQuotes) + Script += '\"'; + Script += s; + if (needQuotes) + Script += '\"'; +} + +void CInArchive::SpaceQuStr(const AString &s) +{ + Space(); + Add_QuStr(s); +} + +void CInArchive::AddParam(UInt32 pos) +{ + _tempString.Empty(); + ReadString2(_tempString, pos); + SpaceQuStr(_tempString); +} + +void CInArchive::AddParams(const UInt32 *params, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + AddParam(params[i]); +} + +void CInArchive::AddOptionalParam(UInt32 pos) +{ + if (pos != 0) + AddParam(pos); +} - EW_LOCKWINDOW +static unsigned GetNumParams(const UInt32 *params, unsigned num) +{ + for (; num > 0 && params[num - 1] == 0; num--); + return num; +} + +void CInArchive::AddOptionalParams(const UInt32 *params, unsigned num) +{ + AddParams(params, GetNumParams(params, num)); +} + + +static const UInt32 CMD_REF_Goto = (1 << 0); +static const UInt32 CMD_REF_Call = (1 << 1); +static const UInt32 CMD_REF_Pre = (1 << 2); +static const UInt32 CMD_REF_Show = (1 << 3); +static const UInt32 CMD_REF_Leave = (1 << 4); +static const UInt32 CMD_REF_OnFunc = (1 << 5); +static const UInt32 CMD_REF_Section = (1 << 6); +static const UInt32 CMD_REF_InitPluginDir = (1 << 7); +// static const UInt32 CMD_REF_Creator = (1 << 5); // _Pre is used instead +static const unsigned CMD_REF_OnFunc_NumShifts = 28; // it uses for onFunc too +static const unsigned CMD_REF_Page_NumShifts = 16; // it uses for onFunc too +static const UInt32 CMD_REF_Page_Mask = 0x0FFF0000; +static const UInt32 CMD_REF_OnFunc_Mask = 0xF0000000; + +inline bool IsPageFunc(UInt32 flag) +{ + return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave)) != 0; +} + +inline bool IsFunc(UInt32 flag) +{ + // return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; + return (flag & (CMD_REF_Call | CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; +} + +inline bool IsProbablyEndOfFunc(UInt32 flag) +{ + return (flag != 0 && flag != CMD_REF_Goto); +} + +static const char *kOnFunc[] = +{ + "Init" + , "InstSuccess" + , "InstFailed" + , "UserAbort" + , "GUIInit" + , "GUIEnd" + , "MouseOverSection" + , "VerifyInstDir" + , "SelChange" + , "RebootFailed" }; -#ifdef NSIS_SCRIPT -static CCommandPair kCommandPairs[] = -{ - { 0, "Invalid" }, - { 0, "Return" }, - { 1, "Goto" }, - { 0, "Abort" }, - { 0, "Quit" }, - { 1, "Call" }, - { 2, "UpdateSatusText" }, - { 1, "Sleep" }, - { 0, "BringToFront" }, - { 2, "SetDetailsView" }, - - { 2, "SetFileAttributes" }, - { 2, "SetOutPath" }, - { 3, "IfFileExists" }, - { 2, "SetFlag" }, - { 4, "IfFlag" }, - { 2, "GetFlag" }, - { 3, "Rename" }, - { 2, "GetFullPathName" }, - { 2, "SearchPath" }, - { 2, "GetTempFileName" }, - - { 6, "File" }, - { 2, "Delete" }, - { 5, "MessageBox" }, - { 2, "RMDir" }, - { 2, "StrLen" }, - { 4, "StrCpy" }, - { 5, "StrCmp" }, - { 3, "ReadEnvStr" }, - { 6, "IntCmp" }, - { 4, "IntOp" }, - - { 3, "IntFmt" }, - { 3, "PushPop" }, - { 5, "FindWindow" }, - { 6, "SendMessage" }, - { 3, "IsWindow" }, - { 3, "GetDlgItem" }, - { 3, "SerCtlColors" }, - { 1, "SetBrandingImage" }, - { 5, "CreateFont" }, - { 2, "ShowWindow" }, - - { 4, "ShellExecute" }, - { 3, "Execute" }, - { 3, "GetFileTime" }, - { 3, "GetDLLVersion" }, - { 3, "RegisterDLL" }, - { 5, "CreateShortCut" }, - { 3, "CopyFiles" }, - { 0, "Reboot" }, - { 4, "WriteINIStr" }, - { 4, "ReadINIStr" }, - - { 4, "DelReg" }, - { 5, "WriteReg" }, - { 5, "ReadRegStr" }, - { 5, "RegEnum" }, - { 1, "FileClose" }, - { 4, "FileOpen" }, - { 3, "FileWrite" }, - { 4, "FileRead" }, - { 4, "FileSeek" }, - { 1, "FindClose" }, - - { 2, "FindNext" }, - { 2, "FindFirst" }, - { 3, "WriteUninstaller" }, - { 2, "LogText" }, - { 3, "Section?etText" }, - { 3, "InstType?etFlags" }, - { 6, "GetLabelAddr" }, - { 2, "GetFunctionAddress" }, - { 6, "LockWindow" } +void CInArchive::Add_FuncName(const UInt32 *labels, UInt32 index) +{ + UInt32 mask = labels[index]; + if (mask & CMD_REF_OnFunc) + { + Script += ".on"; + Script += kOnFunc[labels[index] >> CMD_REF_OnFunc_NumShifts]; + } + else if (mask & CMD_REF_InitPluginDir) + { + /* + if (!IsInstaller) + Script += "un." + */ + Script += "Initialize_____Plugins"; + } + else + { + Script += "func_"; + Add_UInt(index); + } +} + +void CInArchive::AddParam_Func(const UInt32 *labels, UInt32 index) +{ + Space(); + if ((Int32)index >= 0) + Add_FuncName(labels, index); + else + AddQuotes(); +} + + +void CInArchive::Add_LabelName(UInt32 index) +{ + Script += "label_"; + Add_UInt(index); +} + +// param != 0 +void CInArchive::Add_GotoVar(UInt32 param) +{ + Space(); + if ((Int32)param < 0) + Add_Var(-((Int32)param + 1)); + else + Add_LabelName(param - 1); +} + +void CInArchive::Add_GotoVar1(UInt32 param) +{ + if (param == 0) + Script += " 0"; + else + Add_GotoVar(param); +} + +void CInArchive::Add_GotoVars2(const UInt32 *params) +{ + Add_GotoVar1(params[0]); + if (params[1] != 0) + Add_GotoVar(params[1]); +} + +static bool NoLabels(const UInt32 *labels, UInt32 num) +{ + for (UInt32 i = 0; i < num; i++) + if (labels[i] != 0) + return false; + return true; +} + +static const char *k_REBOOTOK = " /REBOOTOK"; + +#define MY__MB_ABORTRETRYIGNORE 2 +#define MY__MB_RETRYCANCEL 5 + +static const char *k_MB_Buttons[] = +{ + "OK" + , "OKCANCEL" + , "ABORTRETRYIGNORE" + , "YESNOCANCEL" + , "YESNO" + , "RETRYCANCEL" + , "CANCELTRYCONTINUE" }; -#endif +#define MY__MB_ICONSTOP (1 << 4) -static const char *kShellStrings[] = +static const char *k_MB_Icons[] = +{ + NULL + , "ICONSTOP" + , "ICONQUESTION" + , "ICONEXCLAMATION" + , "ICONINFORMATION" +}; + +static const char *k_MB_Flags[] = +{ + "HELP" + , "NOFOCUS" + , "SETFOREGROUND" + , "DEFAULT_DESKTOP_ONLY" + , "TOPMOST" + , "RIGHT" + , "RTLREADING" + // , "SERVICE_NOTIFICATION" // unsupported. That bit is used for NSIS purposes +}; + +#define MY__IDCANCEL 2 +#define MY__IDIGNORE 5 + +static const char *k_Button_IDs[] = +{ + "0" + , "IDOK" + , "IDCANCEL" + , "IDABORT" + , "IDRETRY" + , "IDIGNORE" + , "IDYES" + , "IDNO" + , "IDCLOSE" + , "IDHELP" + , "IDTRYAGAIN" + , "IDCONTINUE" +}; + +void CInArchive::Add_ButtonID(UInt32 buttonID) +{ + Space(); + if (buttonID < ARRAY_SIZE(k_Button_IDs)) + Script += k_Button_IDs[buttonID]; + else + { + Script += "Button_"; + Add_UInt(buttonID); + } +} + +bool CInArchive::IsDirectString_Equal(UInt32 offset, const char *s) const +{ + if (offset >= NumStringChars) + return false; + if (IsUnicode) + return AreStringsEqual_16and8(_data + _stringsPos + offset * 2, s); + else + return strcmp((const char *)(const Byte *)_data + _stringsPos + offset, s) == 0; +} + +static UInt32 ConvertHexStringToUInt32(const char *s, const char **end) +{ + UInt32 result = 0; + for (int i = 0; i < 8; i++) + { + char c = *s; + UInt32 v; + if (c >= '0' && c <= '9') v = (c - '0'); + else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); + else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); + else + { + if (end != NULL) + *end = s; + return result; + } + result <<= 4; + result |= v; + s++; + } + if (end != NULL) + *end = s; + return 0; +} + +static bool StringToUInt32(const char *s, UInt32 &res) +{ + const char *end; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + res = ConvertHexStringToUInt32(s + 2, &end); + else + res = ConvertStringToUInt32(s, &end); + return (*end == 0); +} + +static const unsigned k_CtlColors_Size = 24; + +struct CNsis_CtlColors +{ + UInt32 text; // COLORREF + UInt32 bkc; // COLORREF + UInt32 lbStyle; + UInt32 bkb; // HBRUSH + Int32 bkmode; + Int32 flags; + + void Parse(const Byte *p); +}; + +void CNsis_CtlColors::Parse(const Byte *p) +{ + text = Get32(p); + bkc = Get32(p + 4); + lbStyle = Get32(p + 8); + bkb = Get32(p + 12); + bkmode = (Int32)Get32(p + 16); + flags = (Int32)Get32(p + 20); +} + +// Win32 constants +#define MY__TRANSPARENT 1 +#define MY__OPAQUE 2 + +#define MY__GENERIC_READ (1 << 31) +#define MY__GENERIC_WRITE (1 << 30) +#define MY__GENERIC_EXECUTE (1 << 29) +#define MY__GENERIC_ALL (1 << 28) + +#define MY__CREATE_NEW 1 +#define MY__CREATE_ALWAYS 2 +#define MY__OPEN_EXISTING 3 +#define MY__OPEN_ALWAYS 4 +#define MY__TRUNCATE_EXISTING 5 + +// text/bg colors +#define kColorsFlags_TEXT 1 +#define kColorsFlags_TEXT_SYS 2 +#define kColorsFlags_BK 4 +#define kColorsFlags_BK_SYS 8 +#define kColorsFlags_BKB 16 + +void CInArchive::Add_Color2(UInt32 v) +{ + v = ((v & 0xFF) << 16) | (v & 0xFF00) | ((v >> 16) & 0xFF); + char sz[32]; + for (int i = 5; i >= 0; i--) + { + unsigned t = v & 0xF; + v >>= 4; + sz[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + } + sz[6] = 0; + Script += sz; +} + +void CInArchive::Add_ColorParam(UInt32 v) +{ + Space(); + Add_Color2(v); +} + +void CInArchive::Add_Color(UInt32 v) +{ + Script += "0x"; + Add_Color2(v); +} + +#define MY__SW_HIDE 0 +#define MY__SW_SHOWNORMAL 1 + +#define MY__SW_SHOWMINIMIZED 2 +#define MY__SW_SHOWMINNOACTIVE 7 +#define MY__SW_SHOWNA 8 + +static const char *kShowWindow_Commands[] = +{ + "HIDE" + , "SHOWNORMAL" // "NORMAL" + , "SHOWMINIMIZED" + , "SHOWMAXIMIZED" // "MAXIMIZE" + , "SHOWNOACTIVATE" + , "SHOW" + , "MINIMIZE" + , "SHOWMINNOACTIVE" + , "SHOWNA" + , "RESTORE" + , "SHOWDEFAULT" + , "FORCEMINIMIZE" // "MAX" +}; + +static void Add_ShowWindow_Cmd_2(AString &s, UInt32 cmd) { - "", - "", - - "SMPROGRAMS", - "", - "PRINTERS", - "DOCUMENTS", - "FAVORITES", - "SMSTARTUP", - "RECENT", - "SENDTO", - "", - "STARTMENU", - "", - "MUSIC", - "VIDEO", - "", - - "DESKTOP", - "", - "", - "NETHOOD", - "FONTS", - "TEMPLATES", - "COMMONSTARTMENU", - "COMMONFILES", - "COMMON_STARTUP", - "COMMON_DESKTOPDIRECTORY", - "QUICKLAUNCH", - "PRINTHOOD", - "LOCALAPPDATA", - "ALTSTARTUP", - "ALTSTARTUP", - "FAVORITES", - - "INTERNET_CACHE", - "COOKIES", - "HISTORY", - "APPDATA", - "WINDIR", - "SYSDIR", - "PROGRAMFILES", - "PICTURES", - "PROFILE", - "", - "", - "COMMONFILES", - "", - "TEMPLATES", - "DOCUMENTS", - "ADMINTOOLS", - - "ADMINTOOLS", - "", - "", - "", - "", - "MUSIC", - "PICTURES", - "VIDEO", - "RESOURCES", - "RESOURCES_LOCALIZED", - "", - "CDBURN_AREA" + if (cmd < ARRAY_SIZE(kShowWindow_Commands)) + { + s += "SW_"; + s += kShowWindow_Commands[cmd]; + } + else + UIntToString(s, cmd); +} + +void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd) +{ + if (cmd < ARRAY_SIZE(kShowWindow_Commands)) + { + Script += "SW_"; + Script += kShowWindow_Commands[cmd]; + } + else + Add_UInt(cmd); +} + +void CInArchive::Add_TypeFromList(const char **table, unsigned tableSize, UInt32 type) +{ + if (type < tableSize) + Script += table[type]; + else + { + Script += '_'; + Add_UInt(type); + } +} + +#define ADD_TYPE_FROM_LIST(table, type) Add_TypeFromList(table, ARRAY_SIZE(table), type) + +enum +{ + k_ExecFlags_AutoClose, + k_ExecFlags_ShellVarContext, + k_ExecFlags_Errors, + k_ExecFlags_Abort, + k_ExecFlags_RebootFlag, + k_ExecFlags_reboot_called, + k_ExecFlags_cur_insttype, + k_ExecFlags_plugin_api_version, + k_ExecFlags_Silent, + k_ExecFlags_InstDirError, + k_ExecFlags_rtl, + k_ExecFlags_ErrorLevel, + k_ExecFlags_RegView, + k_ExecFlags_DetailsPrint = 13, }; -static const int kNumShellStrings = sizeof(kShellStrings) / sizeof(kShellStrings[0]); +// Names for NSIS exec_flags_t structure vars +static const char *kExecFlags_VarsNames[] = +{ + "AutoClose" // autoclose; + , "ShellVarContext" // all_user_var; + , "Errors" // exec_error; + , "Abort" // abort; + , "RebootFlag" // exec_reboot; // NSIS_SUPPORT_REBOOT + , "reboot_called" // reboot_called; // NSIS_SUPPORT_REBOOT + , "cur_insttype" // XXX_cur_insttype; // depreacted + , "plugin_api_version" // plugin_api_version; // see NSISPIAPIVER_CURR + // used to be XXX_insttype_changed + , "Silent" // silent; // NSIS_CONFIG_SILENT_SUPPORT + , "InstDirError" // instdir_error; + , "rtl" // rtl; + , "ErrorLevel" // errlvl; + , "RegView" // alter_reg_view; + , "DetailsPrint" // status_update; +}; +void CInArchive::Add_ExecFlags(UInt32 flagsType) +{ + ADD_TYPE_FROM_LIST(kExecFlags_VarsNames, flagsType); +} + + +// ---------- Page ---------- + +// page flags +#define PF_CANCEL_ENABLE 4 +#define PF_LICENSE_FORCE_SELECTION 32 +#define PF_LICENSE_NO_FORCE_SELECTION 64 +#define PF_PAGE_EX 512 +#define PF_DIR_NO_BTN_DISABLE 1024 /* -# define CMDLINE 20 // everything before here doesn't have trailing slash removal -# define INSTDIR 21 -# define OUTDIR 22 -# define EXEDIR 23 -# define LANGUAGE 24 -# define TEMP 25 -# define PLUGINSDIR 26 -# define HWNDPARENT 27 -# define _CLICK 28 -# define _OUTDIR 29 +#define PF_LICENSE_SELECTED 1 +#define PF_NEXT_ENABLE 2 +#define PF_BACK_SHOW 8 +#define PF_LICENSE_STREAM 16 +#define PF_NO_NEXT_FOCUS 128 +#define PF_BACK_ENABLE 256 */ -static const char *kVarStrings[] = +// page window proc +enum +{ + PWP_LICENSE, + PWP_SELCOM, + PWP_DIR, + PWP_INSTFILES, + PWP_UNINST, + PWP_COMPLETED, + PWP_CUSTOM +}; + +static const char *kPageTypes[] = +{ + "license" + , "components" + , "directory" + , "instfiles" + , "uninstConfirm" + , "COMPLETED" + , "custom" +}; + +#define SET_FUNC_REF(x, flag) if ((Int32)(x) >= 0 && (x) < bh.Num) \ + { labels[x] = (labels[x] & ~CMD_REF_Page_Mask) | ((flag) | (pageIndex << CMD_REF_Page_NumShifts)); } + +// #define IDD_LICENSE 102 +#define IDD_LICENSE_FSRB 108 +#define IDD_LICENSE_FSCB 109 + +void CInArchive::AddPageOption1(UInt32 param, const char *name) +{ + if (param == 0) + return; + TabString(name); + AddParam(param); + NewLine(); +} + +void CInArchive::AddPageOption(const UInt32 *params, unsigned num, const char *name) +{ + num = GetNumParams(params, num); + if (num == 0) + return; + TabString(name); + AddParams(params, num); + NewLine(); +} + +void CInArchive::Separator() +{ + AddLF(); + AddCommentAndString("--------------------"); + AddLF(); +} + +void CInArchive::Space() +{ + Script += ' '; +} + +void CInArchive::Tab() +{ + Script += " "; +} + +void CInArchive::Tab(bool commented) +{ + Script += commented ? " ; " : " "; +} + +void CInArchive::BigSpaceComment() +{ + Script += " ; "; +} + +void CInArchive::SmallSpaceComment() +{ + Script += " ; "; +} + +void CInArchive::AddCommentAndString(const char *s) +{ + Script += "; "; + Script += s; +} + +void CInArchive::AddError(const char *s) +{ + BigSpaceComment(); + Script += "!!! ERROR: "; + Script += s; +} + +void CInArchive::AddErrorLF(const char *s) +{ + AddError(s); + AddLF(); +} + +void CInArchive::CommentOpen() +{ + AddStringLF("/*"); +} + +void CInArchive::CommentClose() +{ + AddStringLF("*/"); +} + +void CInArchive::AddLF() +{ + Script += CR_LF; +} + +void CInArchive::AddQuotes() +{ + Script += "\"\""; +} + +void CInArchive::TabString(const char *s) +{ + Tab(); + Script += s; +} + +void CInArchive::AddStringLF(const char *s) +{ + Script += s; + AddLF(); +} + +// ---------- Section ---------- + +static const char *kSection_VarsNames[] = { - "CMDLINE", - "INSTDIR", - "OUTDIR", - "EXEDIR", - "LANGUAGE", - "TEMP", - "PLUGINSDIR", - "EXEPATH", // test it - "EXEFILE", // test it - "HWNDPARENT", - "_CLICK", - "_OUTDIR" + "Text" + , "InstTypes" + , "Flags" + , "Code" + , "CodeSize" + , "Size" // size in KB }; -static const int kNumVarStrings = sizeof(kVarStrings) / sizeof(kVarStrings[0]); +void CInArchive::Add_SectOp(UInt32 opType) +{ + ADD_TYPE_FROM_LIST(kSection_VarsNames, opType); +} + +void CSection::Parse(const Byte *p) +{ + Name = Get32(p); + InstallTypes = Get32(p + 4); + Flags = Get32(p + 8); + StartCmdIndex = Get32(p + 12); + NumCommands = Get32(p + 16); + SizeKB = Get32(p + 20); +}; +// used for section->flags +#define SF_SELECTED (1 << 0) +#define SF_SECGRP (1 << 1) +#define SF_SECGRPEND (1 << 2) +#define SF_BOLD (1 << 3) +#define SF_RO (1 << 4) +#define SF_EXPAND (1 << 5) +#define SF_PSELECTED (1 << 6) +#define SF_TOGGLED (1 << 7) +#define SF_NAMECHG (1 << 8) -static AString GetVar(UInt32 index) +bool CInArchive::PrintSectionBegin(const CSection §, unsigned index) { - AString res = "$"; - if (index < 10) - res += UIntToString(index); - else if (index < 20) + AString name; + if (sect.Flags & SF_BOLD) + name += '!'; + AString s2; + ReadString2(s2, sect.Name); + if (!IsInstaller) { - res += "R"; - res += UIntToString(index - 10); + if (!StringsAreEqualNoCase_Ascii(s2, "uninstall")) + name += "un."; } - else if (index < 20 + kNumVarStrings) - res += kVarStrings[index - 20]; + name += s2; + + if (sect.Flags & SF_SECGRPEND) + { + AddStringLF("SectionGroupEnd"); + return true; + } + + if (sect.Flags & SF_SECGRP) + { + Script += "SectionGroup"; + if (sect.Flags & SF_EXPAND) + Script += " /e"; + SpaceQuStr(name); + Script += " ; Section"; + AddParam_UInt(index); + NewLine(); + return true; + } + + Script += "Section"; + if ((sect.Flags & SF_SELECTED) == 0) + Script += " /o"; + if (!name.IsEmpty()) + SpaceQuStr(name); + + /* + if (!name.IsEmpty()) + Script += ' '; else + */ + SmallSpaceComment(); + Script += "Section_"; + Add_UInt(index); + + /* + Script += " ; flags = "; + Add_Hex(Script, sect.Flags); + */ + + NewLine(); + + if (sect.SizeKB != 0) { - res += "["; - res += UIntToString(index); - res += "]"; + // probably we must show AddSize, only if there is additional size. + Tab(); + AddCommentAndString("AddSize"); + AddParam_UInt(sect.SizeKB); + AddLF(); } - return res; + + bool needSectionIn = + (sect.Name != 0 && sect.InstallTypes != 0) || + (sect.Name == 0 && sect.InstallTypes != 0xFFFFFFFF); + if (needSectionIn || (sect.Flags & SF_RO) != 0) + { + TabString("SectionIn"); + UInt32 instTypes = sect.InstallTypes; + for (int i = 0; i < 32; i++, instTypes >>= 1) + if ((instTypes & 1) != 0) + { + AddParam_UInt(i + 1); + } + if ((sect.Flags & SF_RO) != 0) + Script += " RO"; + AddLF(); + } + return false; } -#define NS_SKIP_CODE 252 -#define NS_VAR_CODE 253 -#define NS_SHELL_CODE 254 -#define NS_LANG_CODE 255 -#define NS_CODES_START NS_SKIP_CODE +void CInArchive::PrintSectionEnd() +{ + AddStringLF("SectionEnd"); + AddLF(); +} + +// static const unsigned kOnFuncShift = 4; -static AString GetShellString(int index) +void CInArchive::ClearLangComment() { - AString res = "$"; - if (index < kNumShellStrings) + langStrIDs.Clear(); +} + +void CInArchive::PrintNumComment(const char *name, UInt32 value) +{ + // size_t len = Script.Len(); + AddCommentAndString(name); + Script += ": "; + Add_UInt(value); + AddLF(); + /* + len = Script.Len() - len; + char sz[16]; + ConvertUInt32ToString(value, sz); + len += MyStringLen(sz); + for (; len < 20; len++) + Space(); + AddStringLF(sz); + */ +} + + +void CInArchive::NewLine() +{ + if (!langStrIDs.IsEmpty()) { - const char *sz = kShellStrings[index]; - if (sz[0] != 0) - return res + sz; + BigSpaceComment(); + for (unsigned i = 0; i < langStrIDs.Size() && i < 20; i++) + { + /* + if (i != 0) + Script += ' '; + */ + UInt32 langStr = langStrIDs[i]; + if (langStr >= _numLangStrings) + { + AddError("langStr"); + break; + } + UInt32 param = Get32(_mainLang + langStr * 4); + if (param != 0) + AddParam(param); + } + ClearLangComment(); } - res += "SHELL["; - res += UIntToString(index); - res += "]"; - return res; + AddLF(); } -// Based on Dave Laundon's simplified process_string -AString GetNsisString(const AString &s) +static const UInt32 kPageSize = 16 * 4; + +static const char *k_SetOverwrite_Modes[] = +{ + "on" + , "off" + , "try" + , "ifnewer" + , "ifdiff" + // "lastused" +}; + + +void CInArchive::MessageBox_MB_Part(UInt32 param) { - AString res; - for (int i = 0; i < s.Length();) { - unsigned char nVarIdx = s[i++]; - if (nVarIdx > NS_CODES_START && i + 2 <= s.Length()) + UInt32 v = param & 0xF; + Script += " MB_"; + if (v < ARRAY_SIZE(k_MB_Buttons)) + Script += k_MB_Buttons[v]; + else { - int nData = s[i++] & 0x7F; - unsigned char c1 = s[i++]; - nData |= (((int)(c1 & 0x7F)) << 7); + Script += "Buttons_"; + Add_UInt(v); + } + } + { + UInt32 icon = (param >> 4) & 0x7; + if (icon != 0) + { + Script += "|MB_"; + if (icon < ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon] != 0) + Script += k_MB_Icons[icon]; + else + { + Script += "Icon_"; + Add_UInt(icon); + } + } + } + if ((param & 0x80) != 0) + Script += "|MB_USERICON"; + { + UInt32 defButton = (param >> 8) & 0xF; + if (defButton != 0) + { + Script += "|MB_DEFBUTTON"; + Add_UInt(defButton + 1); + } + } + { + UInt32 modal = (param >> 12) & 0x3; + if (modal == 1) Script += "|MB_SYSTEMMODAL"; + else if (modal == 2) Script += "|MB_TASKMODAL"; + else if (modal == 3) Script += "|0x3000"; + UInt32 flags = (param >> 14); + for (int i = 0; i < ARRAY_SIZE(k_MB_Flags); i++) + if ((flags & (1 << i)) != 0) + { + Script += "|MB_"; + Script += k_MB_Flags[i]; + } + } +} + +#define GET_CMD_PARAM(ppp, index) Get32((ppp) + 4 + (index) * 4) + +static const Byte k_InitPluginDir_Commands[] = + { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 }; + +bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) +{ + for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize) + if (GetCmd(Get32(rawCmds)) != sequence[kkk]) + return false; + return true; +} + +#endif + +static const UInt32 kSectionSize_base = 6 * 4; +static const UInt32 kSectionSize_8bit = kSectionSize_base + 1024; +static const UInt32 kSectionSize_16bit = kSectionSize_base + 1024 * 2; +static const UInt32 kSectionSize_16bit_Big = kSectionSize_base + 8196 * 2; +// 8196 is default string length in NSIS-Unicode since 2.37.3 + + +static void AddString(AString &dest, const char *src) +{ + if (!dest.IsEmpty()) + dest += ' '; + dest += src; +} + +AString CInArchive::GetFormatDescription() const +{ + AString s = "NSIS-"; + char c; + if (IsPark()) + { + s += "Park-"; + c = '1'; + if (NsisType == k_NsisType_Park2) c = '2'; + else if (NsisType == k_NsisType_Park3) c = '3'; + } + else + { + c = '2'; + if (NsisType == k_NsisType_Nsis3) + c = '3'; + } + s += c; + if (IsNsis200) + s += ".00"; + else if (IsNsis225) + s += ".25"; + + if (IsUnicode) + AddString(s, "Unicode"); + if (LogCmdIsEnabled) + AddString(s, "log"); + if (BadCmd >= 0) + { + AddString(s, "BadCmd="); + UIntToString(s, BadCmd); + } + return s; +} + +#ifdef NSIS_SCRIPT + +unsigned CInArchive::GetNumSupportedCommands() const +{ + unsigned numCmds = IsPark() ? kNumCmds : kNumCmds - kNumAdditionalParkCmds; + if (!LogCmdIsEnabled) + numCmds--; + if (!IsUnicode) + numCmds -= 2; + return numCmds; +} + +#endif + +UInt32 CInArchive::GetCmd(UInt32 a) +{ + if (!IsPark()) + { + if (!LogCmdIsEnabled) + return a; + if (a < EW_SECTIONSET) + return a; + if (a == EW_SECTIONSET) + return EW_LOG; + return a - 1; + } - if (nVarIdx == NS_SHELL_CODE) - res += GetShellString(c1); - else if (nVarIdx == NS_VAR_CODE) - res += GetVar(nData); - else if (nVarIdx == NS_LANG_CODE) - res += "NS_LANG_CODE"; + if (a < EW_REGISTERDLL) + return a; + if (NsisType >= k_NsisType_Park2) + { + if (a == EW_REGISTERDLL) return EW_GETFONTVERSION; + a--; + } + if (NsisType >= k_NsisType_Park3) + { + if (a == EW_REGISTERDLL) return EW_GETFONTNAME; + a--; + } + if (a >= EW_FSEEK) + { + if (IsUnicode) + { + if (a == EW_FSEEK) return EW_FPUTWS; + if (a == EW_FSEEK + 1) return EW_FPUTWS + 1; + a -= 2; } - else if (nVarIdx == NS_SKIP_CODE) + + if (a >= EW_SECTIONSET && LogCmdIsEnabled) { - if (i < s.Length()) - res += s[i++]; + if (a == EW_SECTIONSET) + return EW_LOG; + return a - 1; } - else // Normal char - res += (char)nVarIdx; + if (a == EW_FPUTWS) + return EW_FINDPROC; + // if (a > EW_FPUTWS) return 0; } - return res; + return a; } -UString GetNsisString(const UString &s) +void CInArchive::FindBadCmd(const CBlockHeader &bh, const Byte *p) { - UString res; - for (int i = 0; i < s.Length();) + BadCmd = -1; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) { - wchar_t nVarIdx = s[i++]; - if (nVarIdx > NS_UN_CODES_START && nVarIdx <= NS_UN_CODES_END) + UInt32 id = GetCmd(Get32(p)); + if (id >= kNumCmds) + continue; + if (BadCmd >= 0 && id >= (unsigned)BadCmd) + continue; + unsigned i; + if (id == EW_GETLABELADDR || + id == EW_GETFUNCTIONADDR) { - if (i == s.Length()) + BadCmd = id; + continue; + } + for (i = 6; i != 0; i--) + { + UInt32 param = Get32(p + i * 4); + if (param != 0) break; - int nData = s[i++] & 0x7FFF; + } + if (id == EW_FINDPROC && i == 0) + { + BadCmd = id; + continue; + } + if (k_Commands[id].NumParams < i) + BadCmd = id; + } +} - if (nVarIdx == NS_UN_SHELL_CODE) - res += GetUnicodeString(GetShellString(nData >> 8)); - else if (nVarIdx == NS_UN_VAR_CODE) - res += GetUnicodeString(GetVar(nData)); - else if (nVarIdx == NS_UN_LANG_CODE) - res += L"NS_LANG_CODE"; +/* We calculate the number of parameters in commands to detect + layout of commands. It's not very good way. + If you know simpler and more robust way to detect Version and layout, + please write to 7-Zip forum */ + +void CInArchive::DetectNsisType(const CBlockHeader &bh, const Byte *p) +{ + bool strongPark = false; + bool strongNsis = false; + + { + const Byte *strData = _data + _stringsPos; + if (IsUnicode) + { + UInt32 num = NumStringChars; + for (UInt32 i = 0; i < num; i++) + { + if (Get16(strData + i * 2) == 0) + { + unsigned c2 = Get16(strData + 2 + i * 2); + // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL) + if (c2 == NS_3_CODE_VAR) + { + // it can be TXT/RTF string with marker char (1 or 2). so we must next char + // const wchar_t *p2 = (const wchar_t *)(strData + i * 2 + 2); + // p2 = p2; + if ((Get16(strData + 3 + i * 2) & 0x8000) != 0) + { + NsisType = k_NsisType_Nsis3; + strongNsis = true; + break; + } + } + } + } + if (!strongNsis) + { + NsisType = k_NsisType_Park1; + strongPark = true; + } } - else if (nVarIdx == NS_UN_SKIP_CODE) + else { - if (i == s.Length()) - break; - res += s[i++]; + UInt32 num = NumStringChars; + for (UInt32 i = 0; i < num; i++) + { + if (strData[i] == 0) + { + Byte c2 = strData[i + 1]; + // it can be TXT/RTF with marker char (1 or 2). so we must check next char + // for marker=1 (txt) + if (c2 == NS_3_CODE_VAR) + // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL && c2 != 1) + { + if ((strData[i+ 2] & 0x80) != 0) + { + // const char *p2 = (const char *)(strData + i + 1); + // p2 = p2; + NsisType = k_NsisType_Nsis3; + strongNsis = true; + break; + } + } + } + } + } + } + + if (NsisType == k_NsisType_Nsis2 && !IsUnicode) + { + const Byte *p2 = p; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) + { + UInt32 cmd = GetCmd(Get32(p2)); + if (cmd != EW_GETDLGITEM && + cmd != EW_ASSIGNVAR) + continue; + + UInt32 params[kNumCommandParams]; + for (unsigned i = 0; i < kNumCommandParams; i++) + params[i] = Get32(p2 + 4 + 4 * i); + + if (cmd == EW_GETDLGITEM) + { + // we can use also EW_SETCTLCOLORS + if (IsVarStr(params[1], kVar_HWNDPARENT_225)) + { + IsNsis225 = true; + if (params[0] == kVar_Spec_OUTDIR_225) + { + IsNsis200 = true; + break; + } + } + } + else // if (cmd == EW_ASSIGNVAR) + { + if (params[0] == kVar_Spec_OUTDIR_225 && + params[2] == 0 && + params[3] == 0 && + IsVarStr(params[1], kVar_OUTDIR)) + IsNsis225 = true; + } + } + } + + bool parkVer_WasDetected = false; + + if (!strongNsis && !IsNsis225 && !IsNsis200) + { + // it must be before FindBadCmd(bh, p); + unsigned mask = 0; + + unsigned numInsertMax = IsUnicode ? 4 : 2; + + const Byte *p2 = p; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) + { + UInt32 cmd = Get32(p2); // we use original (not converted) command + + if (cmd < EW_WRITEUNINSTALLER || + cmd > EW_WRITEUNINSTALLER + numInsertMax) + continue; + + UInt32 params[kNumCommandParams]; + for (unsigned i = 0; i < kNumCommandParams; i++) + params[i] = Get32(p2 + 4 + 4 * i); + + if (params[4] != 0 || + params[5] != 0 || + params[0] <= 1 || + params[3] <= 1) + continue; + + UInt32 altParam = params[3]; + if (!IsGoodString(params[0]) || + !IsGoodString(altParam)) + continue; + + UInt32 additional = 0; + if (GetVarIndexFinished(altParam, '\\', additional) != kVar_INSTDIR) + continue; + if (AreTwoParamStringsEqual(altParam + additional, params[0])) + { + unsigned numInserts = cmd - EW_WRITEUNINSTALLER; + mask |= (1 << numInserts); + } + } + + if (mask == 1) + { + parkVer_WasDetected = true; // it can be original NSIS or Park-1 + } + else if (mask != 0) + { + ENsisType newType = NsisType; + if (IsUnicode) + switch (mask) + { + case (1 << 3): newType = k_NsisType_Park2; break; + case (1 << 4): newType = k_NsisType_Park3; break; + } + else + switch (mask) + { + case (1 << 1): newType = k_NsisType_Park2; break; + case (1 << 2): newType = k_NsisType_Park3; break; + } + if (newType != NsisType) + { + parkVer_WasDetected = true; + NsisType = newType; + } + } + } + + FindBadCmd(bh, p); + + /* + if (strongNsis) + return; + */ + + if (BadCmd < EW_REGISTERDLL) + return; + + /* + // in ANSI archive we don't check Park and log version + if (!IsUnicode) + return; + */ + + // We can support Park-ANSI archives, if we remove if (strongPark) check + if (strongPark && !parkVer_WasDetected) + { + if (BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park3; + LogCmdIsEnabled = true; // version 3 is provided with log enabled + FindBadCmd(bh, p); + if (BadCmd > 0 && BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park2; + LogCmdIsEnabled = false; + FindBadCmd(bh, p); + if (BadCmd > 0 && BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park1; + FindBadCmd(bh, p); + } + } + } + } + + if (BadCmd >= EW_SECTIONSET) + { + LogCmdIsEnabled = !LogCmdIsEnabled; + FindBadCmd(bh, p); + if (BadCmd >= EW_SECTIONSET && LogCmdIsEnabled) + { + LogCmdIsEnabled = false; + FindBadCmd(bh, p); } - else // Normal char - res += (char)nVarIdx; } - return res; } -AString CInArchive::ReadString2A(UInt32 pos) const +Int32 CInArchive::GetVarIndex(UInt32 strPos) const { - return GetNsisString(ReadStringA(pos)); + if (strPos >= NumStringChars) + return -1; + + if (IsUnicode) + { + if (NumStringChars - strPos < 3 * 2) + return -1; + const Byte *p = _data + _stringsPos + strPos * 2; + unsigned code = Get16(p); + if (IsPark()) + { + if (code != PARK_CODE_VAR) + return -1; + UInt32 n = Get16(p + 2); + if (n == 0) + return -1; + CONVERT_NUMBER_PARK(n); + return (Int32)n; + } + + // NSIS-3 + { + if (code != NS_3_CODE_VAR) + return -1; + UInt32 n = Get16(p + 2); + if (n == 0) + return -1; + CONVERT_NUMBER_NS_3_UNICODE(n); + return (Int32)n; + } + } + + if (NumStringChars - strPos < 4) + return -1; + + const Byte *p = _data + _stringsPos + strPos; + unsigned c = *p; + if (NsisType == k_NsisType_Nsis3) + { + if (c != NS_3_CODE_VAR) + return -1; + } + else if (c != NS_CODE_VAR) + return -1; + + unsigned c0 = p[1]; + if (c0 == 0) + return -1; + unsigned c1 = p[2]; + if (c1 == 0) + return -1; + return DECODE_NUMBER_FROM_2_CHARS(c0, c1); } -UString CInArchive::ReadString2U(UInt32 pos) const +Int32 CInArchive::GetVarIndex(UInt32 strPos, UInt32 &resOffset) const { - return GetNsisString(ReadStringU(pos)); + resOffset = 0; + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return varIndex; + if (IsUnicode) + { + if (NumStringChars - strPos < 2 * 2) + return -1; + resOffset = 2; + } + else + { + if (NumStringChars - strPos < 3) + return -1; + resOffset = 3; + } + return varIndex; } -AString CInArchive::ReadString2(UInt32 pos) const +Int32 CInArchive::GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const { + resOffset = 0; + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return varIndex; if (IsUnicode) - return UnicodeStringToMultiByte(ReadString2U(pos)); + { + if (NumStringChars - strPos < 3 * 2) + return -1; + const Byte *p = _data + _stringsPos + strPos * 2; + if (Get16(p + 4) != endChar) + return -1; + resOffset = 3; + } else - return ReadString2A(pos); + { + if (NumStringChars - strPos < 4) + return -1; + const Byte *p = _data + _stringsPos + strPos; + if (p[3] != endChar) + return -1; + resOffset = 4; + } + return varIndex; } -AString CInArchive::ReadString2Qw(UInt32 pos) const +bool CInArchive::IsVarStr(UInt32 strPos, UInt32 varIndex) const { - return "\"" + ReadString2(pos) + "\""; + if (varIndex > (UInt32)0x7FFF) + return false; + UInt32 resOffset; + return GetVarIndexFinished(strPos, 0, resOffset) == (Int32)varIndex; } -#define DEL_DIR 1 -#define DEL_RECURSE 2 -#define DEL_REBOOT 4 -// #define DEL_SIMPLE 8 +bool CInArchive::IsAbsolutePathVar(UInt32 strPos) const +{ + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return false; + switch (varIndex) + { + case kVar_INSTDIR: + case kVar_EXEDIR: + case kVar_TEMP: + case kVar_PLUGINSDIR: + return true; + } + return false; +} + +#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') -static const int kNumEntryParams = 6; +// We use same check as in NSIS decoder +bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } +bool IsDrivePath(const char *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } + +static bool IsAbsolutePath(const wchar_t *s) +{ + return + s[0] == WCHAR_PATH_SEPARATOR && + s[1] == WCHAR_PATH_SEPARATOR || + IsDrivePath(s); +} + +static bool IsAbsolutePath(const char *s) +{ + return + s[0] == CHAR_PATH_SEPARATOR && + s[1] == CHAR_PATH_SEPARATOR || + IsDrivePath(s); +} -struct CEntry +void CInArchive::SetItemName(CItem &item, UInt32 strPos) { - UInt32 Which; - UInt32 Params[kNumEntryParams]; - AString GetParamsString(int numParams); - CEntry() + ReadString2_Raw(strPos); + bool isAbs = IsAbsolutePathVar(strPos); + if (IsUnicode) { - Which = 0; - for (UInt32 j = 0; j < kNumEntryParams; j++) - Params[j] = 0; + item.NameU = Raw_UString; + if (!isAbs && !IsAbsolutePath(Raw_UString)) + item.Prefix = UPrefixes.Size() - 1; } -}; + else + { + item.NameA = Raw_AString; + if (!isAbs && !IsAbsolutePath(Raw_AString)) + item.Prefix = APrefixes.Size() - 1; + } +} -AString CEntry::GetParamsString(int numParams) +HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) { - AString s; - for (int i = 0; i < numParams; i++) + #ifdef NSIS_SCRIPT + CDynLimBuf &s = Script; + + CObjArray<UInt32> labels; + labels.Alloc(bh.Num); + memset(labels, 0, bh.Num * sizeof(UInt32)); + { - s += " "; - UInt32 v = Params[i]; - if (v > 0xFFF00000) - s += IntToString((Int32)Params[i]); + const Byte *p = _data; + UInt32 i; + for (i = 0; i < numOnFunc; i++) + { + UInt32 func = Get32(p + onFuncOffset + 4 * i); + if (func < bh.Num) + labels[func] = (labels[func] & ~CMD_REF_OnFunc_Mask) | (CMD_REF_OnFunc | (i << CMD_REF_OnFunc_NumShifts)); + } + } + + /* + { + for (int i = 0; i < OnFuncs.Size(); i++) + { + UInt32 address = OnFuncs[i] >> kOnFuncShift; + if (address < bh.Num) + } + } + */ + + if (bhPages.Num != 0) + { + Separator(); + PrintNumComment("PAGES", bhPages.Num); + + if (bhPages.Num > (1 << 12) + || bhPages.Offset > _size + || bhPages.Num * kPageSize > _size - bhPages.Offset) + { + AddErrorLF("Pages error"); + } else - s += UIntToString(Params[i]); + { + + AddLF(); + const Byte *p = _data + bhPages.Offset; + + for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, p += kPageSize) + { + UInt32 dlgID = Get32(p); + UInt32 wndProcID = Get32(p + 4); + UInt32 preFunc = Get32(p + 8); + UInt32 showFunc = Get32(p + 12); + UInt32 leaveFunc = Get32(p + 16); + UInt32 flags = Get32(p + 20); + UInt32 caption = Get32(p + 24); + // UInt32 back = Get32(p + 28); + UInt32 next = Get32(p + 32); + // UInt32 clickNext = Get32(p + 36); + // UInt32 cancel = Get32(p + 40); + UInt32 params[5]; + for (int i = 0; i < 5; i++) + params[i] = Get32(p + 44 + 4 * i); + + SET_FUNC_REF(preFunc, CMD_REF_Pre); + SET_FUNC_REF(showFunc, CMD_REF_Show); + SET_FUNC_REF(leaveFunc, CMD_REF_Leave); + + if (wndProcID == PWP_COMPLETED) + CommentOpen(); + + AddCommentAndString("Page "); + Add_UInt(pageIndex); + AddLF(); + + if (flags & PF_PAGE_EX) + { + s += "PageEx "; + if (!IsInstaller) + s += "un."; + } + else + s += IsInstaller ? "Page " : "UninstPage "; + + if (wndProcID < ARRAY_SIZE(kPageTypes)) + s += kPageTypes[wndProcID]; + else + Add_UInt(wndProcID); + + + bool needCallbacks = ( + (Int32)preFunc >= 0 || + (Int32)showFunc >= 0 || + (Int32)leaveFunc >= 0); + + if (flags & PF_PAGE_EX) + { + AddLF(); + if (needCallbacks) + TabString("PageCallbacks"); + } + + if (needCallbacks) + { + AddParam_Func(labels, preFunc); // it's creator_function for PWP_CUSTOM + if (wndProcID != PWP_CUSTOM) + { + AddParam_Func(labels, showFunc); + } + AddParam_Func(labels, leaveFunc); + } + + if ((flags & PF_PAGE_EX) == 0) + { + // AddOptionalParam(caption); + if (flags & PF_CANCEL_ENABLE) + s += " /ENABLECANCEL"; + AddLF(); + } + else + { + AddLF(); + AddPageOption1(caption, "Caption"); + } + + if (wndProcID == PWP_LICENSE) + { + if ((flags & PF_LICENSE_NO_FORCE_SELECTION) != 0 || + (flags & PF_LICENSE_FORCE_SELECTION) != 0) + { + TabString("LicenseForceSelection "); + if (flags & PF_LICENSE_NO_FORCE_SELECTION) + s += "off"; + else + { + if (dlgID == IDD_LICENSE_FSCB) + s += "checkbox"; + else if (dlgID == IDD_LICENSE_FSRB) + s += "radiobuttons"; + else + Add_UInt(dlgID); + AddOptionalParams(params + 2, 2); + } + NewLine(); + } + + if (params[0] != 0 || next != 0) + { + TabString("LicenseText"); + AddParam(params[0]); + AddOptionalParam(next); + NewLine(); + } + if (params[1] != 0) + { + TabString("LicenseData"); + if ((Int32)params[1] < 0) + AddParam(params[1]); + else + AddLicense(params[1], -1); + ClearLangComment(); + NewLine(); + } + } + else if (wndProcID == PWP_SELCOM) + AddPageOption(params, 3, "ComponentsText"); + else if (wndProcID == PWP_DIR) + { + AddPageOption(params, 4, "DirText"); + if (params[4] != 0) + { + TabString("DirVar"); + AddParam_Var(params[4] - 1); + AddLF(); + } + if (flags & PF_DIR_NO_BTN_DISABLE) + { + TabString("DirVerify leave"); + AddLF(); + } + + } + else if (wndProcID == PWP_INSTFILES) + { + AddPageOption1(params[2], "CompletedText"); + AddPageOption1(params[1], "DetailsButtonText"); + } + else if (wndProcID == PWP_UNINST) + { + if (params[4] != 0) + { + TabString("DirVar"); + AddParam_Var(params[4] - 1); + AddLF(); + } + AddPageOption(params, 2, "UninstallText"); + } + + if (flags & PF_PAGE_EX) + { + s += "PageExEnd"; + NewLine(); + } + if (wndProcID == PWP_COMPLETED) + CommentClose(); + NewLine(); + } + } } - return s; -} -#ifdef NSIS_SCRIPT + CObjArray<CSection> Sections; -static AString GetRegRootID(UInt32 val) -{ - const char *s; - switch(val) { - case 0: s = "SHCTX"; break; - case 0x80000000: s = "HKCR"; break; - case 0x80000001: s = "HKCU"; break; - case 0x80000002: s = "HKLM"; break; - case 0x80000003: s = "HKU"; break; - case 0x80000004: s = "HKPD"; break; - case 0x80000005: s = "HKCC"; break; - case 0x80000006: s = "HKDD"; break; - case 0x80000050: s = "HKPT"; break; - case 0x80000060: s = "HKPN"; break; - default: - return UIntToString(val); break; + Separator(); + PrintNumComment("SECTIONS", bhSections.Num); + PrintNumComment("COMMANDS", bh.Num); + AddLF(); + + if (bhSections.Num > (1 << 15) + // || bhSections.Offset > _size + // || (bhSections.Num * SectionSize > _size - bhSections.Offset) + ) + { + AddErrorLF("Sections error"); + } + else if (bhSections.Num != 0) + { + Sections.Alloc((unsigned)bhSections.Num); + const Byte *p = _data + bhSections.Offset; + for (UInt32 i = 0; i < bhSections.Num; i++, p += SectionSize) + { + CSection §ion = Sections[i]; + section.Parse(p); + if (section.StartCmdIndex < bh.Num) + labels[section.StartCmdIndex] |= CMD_REF_Section; + } + } } - return s; -} -#endif + #endif -HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) -{ - _posInData = bh.Offset + GetOffset(); - AString prefixA; - UString prefixU; - for (UInt32 i = 0; i < bh.Num; i++) + const Byte *p; + UInt32 kkk; + + #ifdef NSIS_SCRIPT + + p = _data + bh.Offset; + + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + UInt32 commandId = GetCmd(Get32(p)); + UInt32 mask; + switch (commandId) + { + case EW_NOP: mask = 1 << 0; break; + case EW_IFFILEEXISTS: mask = 3 << 1; break; + case EW_IFFLAG: mask = 3 << 0; break; + case EW_MESSAGEBOX: mask = 5 << 3; break; + case EW_STRCMP: mask = 3 << 2; break; + case EW_INTCMP: mask = 7 << 2; break; + case EW_ISWINDOW: mask = 3 << 1; break; + case EW_CALL: + { + if (Get32(p + 4 + 4) == 1) // it's Call :Label + { + mask = 1 << 0; + break; + } + UInt32 param0 = Get32(p + 4); + if ((Int32)param0 > 0) + labels[param0 - 1] |= CMD_REF_Call; + continue; + } + default: continue; + } + for (int i = 0; mask != 0; i++, mask >>= 1) + if (mask & 1) + { + UInt32 param = Get32(p + 4 + 4 * i); + if ((Int32)param > 0 && (Int32)param <= (Int32)bh.Num) + labels[param - 1] |= CMD_REF_Goto; + } + } + + int InitPluginsDir_Start = -1; + int InitPluginsDir_End = -1; + p = _data + bh.Offset; + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + UInt32 flg = labels[kkk]; + /* + if (IsFunc(flg)) + { + AddLF(); + for (int i = 0; i < 14; i++) + { + UInt32 commandId = GetCmd(Get32(p + kCmdSize * i)); + s += ", "; + UIntToString(s, commandId); + } + AddLF(); + } + */ + if (IsFunc(flg) + && bh.Num - kkk >= ARRAY_SIZE(k_InitPluginDir_Commands) + && CompareCommands(p, k_InitPluginDir_Commands, ARRAY_SIZE(k_InitPluginDir_Commands))) + { + InitPluginsDir_Start = kkk; + InitPluginsDir_End = kkk + ARRAY_SIZE(k_InitPluginDir_Commands); + labels[kkk] |= CMD_REF_InitPluginDir; + break; + } + } + + #endif + + // AString prefixA_Temp; + // UString prefixU_Temp; + + + // const UInt32 kFindS = 158; + + #ifdef NSIS_SCRIPT + + UInt32 curSectionIndex = 0; + // UInt32 lastSectionEndCmd = 0xFFFFFFFF; + bool sectionIsOpen = false; + // int curOnFunc = 0; + bool onFuncIsOpen = false; + + /* + for (unsigned yyy = 0; yyy + 3 < _data.Size(); yyy++) + { + UInt32 val = Get32(_data + yyy); + if (val == kFindS) + val = val; + } + */ + + UInt32 overwrite_State = 0; // "SetOverwrite on" + Int32 allowSkipFiles_State = -1; // -1: on, -2: off, >=0 : RAW value + UInt32 endCommentIndex = 0; + + unsigned numSupportedCommands = GetNumSupportedCommands(); + + #endif + + p = _data + bh.Offset; + + UString spec_outdir_U; + AString spec_outdir_A; + + UPrefixes.Add(L"$INSTDIR"); + APrefixes.Add("$INSTDIR"); + + p = _data + bh.Offset; + + unsigned spec_outdir_VarIndex = IsNsis225 ? + kVar_Spec_OUTDIR_225 : + kVar_Spec_OUTDIR; + + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) { - CEntry e; - e.Which = ReadUInt32(); - for (UInt32 j = 0; j < kNumEntryParams; j++) - e.Params[j] = ReadUInt32(); + UInt32 commandId; + UInt32 params[kNumCommandParams]; + commandId = GetCmd(Get32(p)); + { + for (unsigned i = 0; i < kNumCommandParams; i++) + { + params[i] = Get32(p + 4 + 4 * i); + /* + if (params[i] == kFindS) + i = i; + */ + } + } + #ifdef NSIS_SCRIPT - if (e.Which != EW_PUSHPOP && e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0])) + + bool IsSectionGroup = false; + while (curSectionIndex < bhSections.Num) { - const CCommandPair &pair = kCommandPairs[e.Which]; - Script += pair.Name; + const CSection § = Sections[curSectionIndex]; + if (sectionIsOpen) + { + if (sect.StartCmdIndex + sect.NumCommands + 1 != kkk) + break; + PrintSectionEnd(); + sectionIsOpen = false; + // lastSectionEndCmd = kkk; + curSectionIndex++; + continue; + } + if (sect.StartCmdIndex != kkk) + break; + if (PrintSectionBegin(sect, curSectionIndex)) + { + IsSectionGroup = true; + curSectionIndex++; + // do we need to flush prefixes in new section? + // FlushOutPathPrefixes(); + } + else + sectionIsOpen = true; } + + /* + if (curOnFunc < OnFuncs.Size()) + { + if ((OnFuncs[curOnFunc] >> kOnFuncShift) == kkk) + { + s += "Function .on"; + s += kOnFunc[OnFuncs[curOnFunc++] & ((1 << kOnFuncShift) - 1)]; + AddLF(); + onFuncIsOpen = true; + } + } + */ + + if (labels[kkk] != 0 && labels[kkk] != CMD_REF_Section) + { + UInt32 flg = labels[kkk]; + if (IsFunc(flg)) + { + if ((int)kkk == InitPluginsDir_Start) + CommentOpen(); + + onFuncIsOpen = true; + s += "Function "; + Add_FuncName(labels, kkk); + if (IsPageFunc(flg)) + { + BigSpaceComment(); + s += "Page "; + Add_UInt((flg & CMD_REF_Page_Mask) >> CMD_REF_Page_NumShifts); + // if (flg & CMD_REF_Creator) s += ", Creator"; + if (flg & CMD_REF_Leave) s += ", Leave"; + if (flg & CMD_REF_Pre) s += ", Pre"; + if (flg & CMD_REF_Show) s += ", Show"; + } + AddLF(); + } + if (flg & CMD_REF_Goto) + { + Add_LabelName(kkk); + s += ':'; + AddLF(); + } + } + + if (commandId != EW_RET) + { + Tab(kkk < endCommentIndex); + } + + /* + UInt32 originalCmd = Get32(p); + if (originalCmd >= EW_REGISTERDLL) + { + UIntToString(s, originalCmd); + s += ' '; + if (originalCmd != commandId) + { + UIntToString(s, commandId); + s += ' '; + } + } + */ + + unsigned numSkipParams = 0; + + if (commandId < ARRAY_SIZE(k_Commands) && commandId < numSupportedCommands) + { + numSkipParams = k_Commands[commandId].NumParams; + const char *sz = k_CommandNames[commandId]; + if (sz) + s += sz; + } + else + { + s += "Command"; + Add_UInt(commandId); + /* We don't show wrong commands that use overlapped ids. + So we change commandId to big value */ + if (commandId < (1 << 12)) + commandId += (1 << 12); + } + #endif - switch (e.Which) + switch (commandId) { case EW_CREATEDIR: { - if (IsUnicode) + bool isSetOutPath = (params[1] != 0); + + if (isSetOutPath) { - prefixU.Empty(); - prefixU = ReadString2U(e.Params[0]); + UInt32 par0 = params[0]; + + UInt32 resOffset; + Int32 idx = GetVarIndex(par0, resOffset); + if (idx == (Int32)spec_outdir_VarIndex || + idx == kVar_OUTDIR) + par0 += resOffset; + + ReadString2_Raw(par0); + + if (IsUnicode) + { + if (idx == (Int32)spec_outdir_VarIndex) + Raw_UString.Insert(0, spec_outdir_U); + else if (idx == kVar_OUTDIR) + Raw_UString.Insert(0, UPrefixes.Back()); + UPrefixes.Add(Raw_UString); + } + else + { + if (idx == (Int32)spec_outdir_VarIndex) + Raw_AString.Insert(0, spec_outdir_A); + else if (idx == kVar_OUTDIR) + Raw_AString.Insert(0, APrefixes.Back()); + APrefixes.Add(Raw_AString); + } } - else + + #ifdef NSIS_SCRIPT + s += isSetOutPath ? "SetOutPath" : "CreateDirectory"; + AddParam(params[0]); + #endif + + break; + } + + + case EW_ASSIGNVAR: + { + if (params[0] == spec_outdir_VarIndex) { - prefixA.Empty(); - prefixA = ReadString2A(e.Params[0]); + spec_outdir_U.Empty(); + spec_outdir_A.Empty(); + if (IsVarStr(params[1], kVar_OUTDIR) && + params[2] == 0 && + params[3] == 0) + { + if (IsVarStr(params[1], kVar_OUTDIR)) + { + spec_outdir_U = UPrefixes.Back(); // outdir_U; + spec_outdir_A = APrefixes.Back();// outdir_A; + } + } } + #ifdef NSIS_SCRIPT - Script += " "; - if (IsUnicode) - Script += UnicodeStringToMultiByte(prefixU); - else - Script += prefixA; + + if (params[2] == 0 && + params[3] == 0 && + params[4] == 0 && + params[5] == 0 && + params[1] != 0 && + params[1] < NumStringChars) + { + char sz[16]; + ConvertUInt32ToString(kkk + 1, sz); + if (IsDirectString_Equal(params[1], sz)) + { + // we suppose that it's GetCurrentAddress command + // but there is probability that it's StrCpy command + s += "GetCurrentAddress"; + AddParam_Var(params[0]); + SmallSpaceComment(); + } + } + s += "StrCpy"; + AddParam_Var(params[0]); + AddParam(params[1]); + + AddOptionalParams(params + 2, 2); + #endif + break; } case EW_EXTRACTFILE: { - CItem item; - item.IsUnicode = IsUnicode; - if (IsUnicode) + CItem &item = Items.AddNew(); + + UInt32 par1 = params[1]; + + SetItemName(item, par1); + + item.Pos = params[2]; + item.MTime.dwLowDateTime = params[3]; + item.MTime.dwHighDateTime = params[4]; + + #ifdef NSIS_SCRIPT + { - item.PrefixU = prefixU; - item.NameU = ReadString2U(e.Params[1]); + UInt32 overwrite = params[0] & 0x7; + if (overwrite != overwrite_State) + { + s += "SetOverwrite "; + ADD_TYPE_FROM_LIST(k_SetOverwrite_Modes, overwrite); + overwrite_State = overwrite; + AddLF(); + Tab(kkk < endCommentIndex); + } } - else + { - item.PrefixA = prefixA; - item.NameA = ReadString2A(e.Params[1]); + UInt32 nsisMB = params[0] >> 3; + if ((Int32)nsisMB != allowSkipFiles_State) + { + UInt32 mb = nsisMB & ((1 << 20) - 1); // old/new NSIS + UInt32 b1 = nsisMB >> 21; // NSIS 2.06+ + UInt32 b2 = nsisMB >> 20; // NSIS old + Int32 asf = (Int32)nsisMB; + if (mb == (MY__MB_ABORTRETRYIGNORE | MY__MB_ICONSTOP) && (b1 == MY__IDIGNORE || b2 == MY__IDIGNORE)) + asf = -1; + else if (mb == (MY__MB_RETRYCANCEL | MY__MB_ICONSTOP) && (b1 == MY__IDCANCEL || b2 == MY__IDCANCEL)) + asf = -2; + else + { + AddCommentAndString("AllowSkipFiles [Overwrite]: "); + MessageBox_MB_Part(mb); + if (b1 != 0) + { + s += " /SD"; + Add_ButtonID(b1); + } + } + if (asf != allowSkipFiles_State) + { + if (asf < 0) + { + s += "AllowSkipFiles "; + s += (asf == -1) ? "on" : "off"; + } + AddLF(); + Tab(kkk < endCommentIndex); + } + allowSkipFiles_State = (Int32)nsisMB; + } } - /* UInt32 overwriteFlag = e.Params[0]; */ - item.Pos = e.Params[2]; - item.MTime.dwLowDateTime = e.Params[3]; - item.MTime.dwHighDateTime = e.Params[4]; - /* UInt32 allowIgnore = e.Params[5]; */ - if (Items.Size() > 0) + + s += "File"; + AddParam(params[1]); + + /* params[5] contains link to LangString (negative value) + with NLF_FILE_ERROR or NLF_FILE_ERROR_NOIGNORE message for MessageBox. + We don't need to print it. */ + + #endif + + if (IsVarStr(par1, 10)) // is $R0 { - /* - if (item.Pos == Items.Back().Pos) - continue; - */ + // we parse InstallLib macro in 7-Zip installers + unsigned kBackOffset = 28; + if (kkk > 1) + { + // detect old version of InstallLib macro + if (Get32(p - 1 * kCmdSize) == EW_NOP) // goto command + kBackOffset -= 2; + } + + if (kkk > kBackOffset) + { + const Byte *p2 = p - kBackOffset * kCmdSize; + UInt32 cmd = Get32(p2); + if (cmd == EW_ASSIGNVAR) + { + UInt32 pars[6]; + for (int i = 0; i < 6; i++) + pars[i] = Get32(p2 + i * 4 + 4); + if (pars[0] == 10 + 4 && pars[2] == 0 && pars[3] == 0) // 10 + 4 means $R4 + { + ReadString2_Raw(pars[1]); + if (IsUnicode) + { + if (!Raw_UString.IsEmpty()) + item.NameU = Raw_UString; + } + else + { + if (!Raw_AString.IsEmpty()) + item.NameA = Raw_AString; + } + } + } + } } - Items.Add(item); - #ifdef NSIS_SCRIPT - Script += " "; + /* UInt32 allowIgnore = params[5]; */ + break; + } - if (IsUnicode) - Script += UnicodeStringToMultiByte(item.NameU); - else - Script += item.NameA; + case EW_SETFILEATTRIBUTES: + { + if (kkk > 0 && Get32(p - kCmdSize) == EW_EXTRACTFILE) + { + if (params[0] == Get32(p - kCmdSize + 4 + 4 * 1)) // compare with PrevCmd.Params[1] + { + CItem &item = Items.Back(); + item.Attrib_Defined = true; + item.Attrib = params[1]; + } + } + #ifdef NSIS_SCRIPT + AddParam(params[0]); + Space(); + FlagsToString2(s, g_WinAttrib, ARRAY_SIZE(g_WinAttrib), params[1]); #endif break; } + case EW_WRITEUNINSTALLER: + { + /* NSIS 2.29+ writes alternative path to params[3] + "$INSTDIR\\" + Str(params[0]) + NSIS installer uses alternative path, if main path + from params[0] is not absolute path */ + + bool pathOk = (params[0] > 0) && IsGoodString(params[0]); + + if (!pathOk) + { + #ifdef NSIS_SCRIPT + AddError("bad path"); + #endif + break; + } + + bool altPathOk = true; + + UInt32 altParam = params[3]; + if (altParam != 0) + { + altPathOk = false; + UInt32 additional = 0; + if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR) + altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]); + } + + + #ifdef NSIS_SCRIPT + + AddParam(params[0]); + + SmallSpaceComment(); + + /* + for (int i = 1; i < 3; i++) + AddParam_UInt(params[i]); + */ + + if (params[3] != 0) + AddParam(params[3]); + + #endif + + if (!altPathOk) + { + #ifdef NSIS_SCRIPT + AddError("alt path error"); + #endif + } + + if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER) + { + /* We don't cases with incorrect installer commands. + Such bad installer item can break unpacking for other items. */ + #ifdef NSIS_SCRIPT + AddError("SKIP possible BadCmd"); + #endif + break; + } + + CItem &item = Items.AddNew();; + + SetItemName(item, params[0]); + + item.Pos = params[1]; + item.PatchSize = params[2]; + item.IsUninstaller = true; + + /* + // we can add second time to test the code + CItem item2 = item; + item2.NameU += L'2'; + item2.NameA += '2'; + Items.Add(item2); + */ + + break; + } #ifdef NSIS_SCRIPT + + case EW_RET: + { + // bool needComment = false; + if (onFuncIsOpen) + { + if (kkk == bh.Num - 1 || IsProbablyEndOfFunc(labels[kkk + 1])) + { + AddStringLF("FunctionEnd"); + + if ((int)kkk + 1 == InitPluginsDir_End) + CommentClose(); + AddLF(); + onFuncIsOpen = false; + // needComment = true; + break; + } + } + // if (!needComment) + if (IsSectionGroup) + break; + if (sectionIsOpen) + { + const CSection § = Sections[curSectionIndex]; + if (sect.StartCmdIndex + sect.NumCommands == kkk) + { + PrintSectionEnd(); + sectionIsOpen = false; + curSectionIndex++; + break; + } + + // needComment = true; + // break; + } + + /* + if (needComment) + s += " ;"; + */ + TabString("Return"); + AddLF(); + break; + } + + case EW_NOP: + { + if (params[0] == 0) + s += "Nop"; + else + { + s += "Goto"; + Add_GotoVar(params[0]); + } + break; + } + + case EW_ABORT: + { + AddOptionalParam(params[0]); + break; + } + + case EW_CALL: + { + if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_EXTRACTFILE) + { + UInt32 par1 = GET_CMD_PARAM(p + kCmdSize, 1); + + UInt32 pluginPar = 0; + + if (GetVarIndexFinished(par1, '\\', pluginPar) == kVar_PLUGINSDIR) + { + pluginPar += par1; + UInt32 commandId2 = GetCmd(Get32(p + kCmdSize * 2)); + if (commandId2 == EW_SETFLAG || commandId2 == EW_UPDATETEXT) + { + UInt32 i; + for (i = kkk + 3; i < bh.Num; i++) + { + const Byte *pCmd = p + kCmdSize * (i - kkk); + UInt32 commandId3 = GetCmd(Get32(pCmd)); + if (commandId3 != EW_PUSHPOP + || GET_CMD_PARAM(pCmd, 1) != 0 + || GET_CMD_PARAM(pCmd, 2) != 0) + break; + } + if (i < bh.Num) + { + const Byte *pCmd = p + kCmdSize * (i - kkk); + + // UInt32 callDll_Param = GET_CMD_PARAM(pCmd, 0); + // UInt32 file_Param = GET_CMD_PARAM(p + kCmdSize, 1); + + if (GetCmd(Get32(pCmd)) == EW_REGISTERDLL && + AreTwoParamStringsEqual( + GET_CMD_PARAM(pCmd, 0), + GET_CMD_PARAM(p + kCmdSize, 1))) + { + // params[4] = 1 means GetModuleHandle attempt before default LoadLibraryEx; + /// new versions of NSIS use params[4] = 1 for Plugin command + if (GET_CMD_PARAM(pCmd, 2) == 0 + // && GET_CMD_PARAM(pCmd, 4) != 0 + ) + { + { + AString s2; + ReadString2(s2, pluginPar); + if (s2.Len() >= 4 && + StringsAreEqualNoCase_Ascii(s2.RightPtr(4), ".dll")) + s2.DeleteFrom(s2.Len() - 4); + s2 += "::"; + AString func; + ReadString2(func, GET_CMD_PARAM(pCmd, 1)); + s2 += func; + Add_QuStr(s2); + + if (GET_CMD_PARAM(pCmd, 3) == 1) + s += " /NOUNLOAD"; + + for (UInt32 j = i - 1; j >= kkk + 3; j--) + { + const Byte *pCmd = p - kCmdSize * (kkk - j); + AddParam(GET_CMD_PARAM(pCmd, 0)); + } + NewLine(); + Tab(true); + endCommentIndex = i + 1; + } + } + } + } + } + } + } + { + const Byte *nextCmd = p + kCmdSize; + UInt32 commandId2 = GetCmd(Get32(nextCmd)); + if (commandId2 == EW_SETFLAG + && GET_CMD_PARAM(nextCmd, 0) == k_ExecFlags_DetailsPrint + && GET_CMD_PARAM(nextCmd, 2) != 0) // is "lastused" + // || commandId2 == EW_UPDATETEXT) + { + if ((Int32)params[0] > 0 && labels[params[0] - 1] & CMD_REF_InitPluginDir) + { + s += "InitPluginsDir"; + AddLF(); + Tab(true); + endCommentIndex = kkk + 2; + } + } + } + + s += "Call "; + if ((Int32)params[0] < 0) + Add_Var(-((Int32)params[0] + 1)); + else if (params[0] == 0) + s += '0'; + else + { + UInt32 val = params[0] - 1; + if (params[1] == 1) // it's Call :Label + { + s += ':'; + Add_LabelName(val); + } + else // if (params[1] == 0) // it's Call Func + Add_FuncName(labels, val); + } + break; + } + case EW_UPDATETEXT: + case EW_SLEEP: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += UIntToString(e.Params[1]); + AddParam(params[0]); break; } - case EW_SETFILEATTRIBUTES: + + case EW_CHDETAILSVIEW: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += UIntToString(e.Params[1]); + if (params[0] == MY__SW_SHOWNA && params[1] == MY__SW_HIDE) s += " show"; + else if (params[1] == MY__SW_SHOWNA && params[0] == MY__SW_HIDE) s += " hide"; + else + for (int i = 0; i < 2; i++) + { + Space(); + Add_ShowWindow_Cmd(params[i]); + } break; } + case EW_IFFILEEXISTS: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += UIntToString(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + AddParam(params[0]); + Add_GotoVars2(¶ms[1]); break; } + + case EW_SETFLAG: + { + AString temp; + ReadString2(temp, params[1]); + if (params[0] == k_ExecFlags_Errors && params[2] == 0) + { + s += (temp.Len() == 1 && temp[0] == '0') ? "ClearErrors" : "SetErrors"; + break; + } + s += "Set"; + Add_ExecFlags(params[0]); + + if (params[2] != 0) + { + s += " lastused"; + break; + } + UInt32 v; + if (StringToUInt32(temp, v)) + { + const char *s2 = NULL; + switch (params[0]) + { + case k_ExecFlags_AutoClose: + case k_ExecFlags_RebootFlag: + if (v < 2) s2 = (v == 0) ? "false" : "true"; break; + case k_ExecFlags_ShellVarContext: + if (v < 2) s2 = (v == 0) ? "current" : "all"; break; + case k_ExecFlags_Silent: + if (v < 2) s2 = (v == 0) ? "normal" : "silent"; break; + case k_ExecFlags_RegView: + if (v == 0) s2 = "32"; + else if (v == 256) s2 = "64"; + break; + case k_ExecFlags_DetailsPrint: + if (v == 0) s2 = "both"; + else if (v == 2) s2 = "textonly"; + else if (v == 4) s2 = "listonly"; + else if (v == 6) s2 = "none"; + } + if (s2) + { + s += ' '; + s += s2; + break; + } + } + SpaceQuStr(temp); + break; + } + + case EW_IFFLAG: + { + Add_ExecFlags(params[2]); + Add_GotoVars2(¶ms[0]); + /* + static const unsigned kIfErrors = 2; + if (params[2] != kIfErrors && params[3] != 0xFFFFFFFF || + params[2] == kIfErrors && params[3] != 0) + { + s += " # FLAG &= "; + AddParam_UInt(params[3]); + } + */ + break; + } + + case EW_GETFLAG: + { + Add_ExecFlags(params[1]); + AddParam_Var(params[0]); + break; + } + case EW_RENAME: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + if (params[2] != 0) + s += k_REBOOTOK; + AddParams(params, 2); + if (params[3] != 0) + { + SmallSpaceComment(); + AddParam(params[3]); // rename comment for log file + } break; } + case EW_GETFULLPATHNAME: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + if (params[2] == 0) + s += " /SHORT"; + AddParam_Var(params[1]); + AddParam(params[0]); break; } + case EW_SEARCHPATH: + case EW_STRLEN: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); + AddParam_Var(params[0]); + AddParam(params[1]); break; } + case EW_GETTEMPFILENAME: { - AString s; - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); + AddParam_Var(params[0]); + AString temp; + ReadString2(temp, params[1]); + if (temp != "$TEMP") + SpaceQuStr(temp); break; } case EW_DELETEFILE: { - UInt64 flag = e.Params[1]; - if (flag != 0) + UInt32 flag = params[1]; + if ((flag & DEL_REBOOT) != 0) + s += k_REBOOTOK; + AddParam(params[0]); + break; + } + + case EW_MESSAGEBOX: + { + MessageBox_MB_Part(params[0]); + AddParam(params[1]); { - Script += " "; - if (flag == DEL_REBOOT) - Script += "/REBOOTOK"; - else - Script += UIntToString(e.Params[1]); + UInt32 buttonID = (params[0] >> 21); // NSIS 2.06+ + if (buttonID != 0) + { + s += " /SD"; + Add_ButtonID(buttonID); + } } - Script += " "; - Script += ReadString2(e.Params[0]); + for (int i = 2; i < 6; i += 2) + if (params[i] != 0) + { + Add_ButtonID(params[i]); + Add_GotoVar1(params[i + 1]); + } break; } + case EW_RMDIR: { - UInt64 flag = e.Params[1]; - if (flag != 0) + UInt32 flag = params[1]; + if ((flag & DEL_RECURSE) != 0) + s += " /r"; + if ((flag & DEL_REBOOT) != 0) + s += k_REBOOTOK; + AddParam(params[0]); + break; + } + + case EW_STRCMP: + { + if (params[4] != 0) + s += 'S'; + AddParams(params, 2); + Add_GotoVars2(¶ms[2]); + break; + } + + case EW_READENVSTR: + { + s += (params[2] != 0) ? + "ReadEnvStr" : + "ExpandEnvStrings"; + AddParam_Var(params[0]); + AString temp; + ReadString2(temp, params[1]); + if (params[2] != 0 &&temp.Len() >= 2 && temp[0] == '%' && temp.Back() == '%') { - if ((flag & DEL_REBOOT) != 0) - Script += " /REBOOTOK"; - if ((flag & DEL_RECURSE) != 0) - Script += " /r"; + temp.DeleteBack(); + temp.Delete(0); } - Script += " "; - Script += ReadString2(e.Params[0]); + SpaceQuStr(temp); break; } - case EW_STRLEN: + + case EW_INTCMP: { - Script += " "; - Script += GetVar(e.Params[0]);; - Script += " "; - Script += ReadString2Qw(e.Params[1]); + if (params[5] != 0) + s += 'U'; + AddParams(params, 2); + Add_GotoVar1(params[2]); + if (params[3] != 0 || params[4] != 0) + Add_GotoVars2(params + 3); break; } - case EW_ASSIGNVAR: + + case EW_INTOP: { - Script += " "; - Script += GetVar(e.Params[0]);; - Script += " "; - Script += ReadString2Qw(e.Params[1]); - AString maxLen, startOffset; - if (e.Params[2] != 0) - maxLen = ReadString2(e.Params[2]); - if (e.Params[3] != 0) - startOffset = ReadString2(e.Params[3]); - if (!maxLen.IsEmpty() || !startOffset.IsEmpty()) - { - Script += " "; - if (maxLen.IsEmpty()) - Script += "\"\""; - else - Script += maxLen; - if (!startOffset.IsEmpty()) + AddParam_Var(params[0]); + const char *kOps = "+-*/|&^!|&%<>"; // NSIS 2.01+ + // "+-*/|&^!|&%"; // NSIS 2.0b4+ + // "+-*/|&^~!|&%"; // NSIS old + UInt32 opIndex = params[3]; + char c = (opIndex < 13) ? kOps[opIndex] : '?'; + char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c; + int numOps = (opIndex == 7) ? 1 : 2; + AddParam(params[1]); + if (numOps == 2 && c == '^' && IsDirectString_Equal(params[2], "0xFFFFFFFF")) + s += " ~ ;"; + Space(); + s += c; + if (numOps != 1) + { + if (c2 != 0) + s += c2; + AddParam(params[2]); + } + break; + } + + case EW_INTFMT: + { + AddParam_Var(params[0]); + AddParams(params + 1, 2); + break; + } + + case EW_PUSHPOP: + { + if (params[2] != 0) + { + s += "Exch"; + if (params[2] != 1) + AddParam_UInt(params[2]); + } + else if (params[1] != 0) + { + s += "Pop"; + AddParam_Var(params[0]); + } + else + { + if (NoLabels(labels + kkk + 1, 2) + && Get32(p + kCmdSize) == EW_PUSHPOP // Exch" + && GET_CMD_PARAM(p + kCmdSize, 2) == 1 + && Get32(p + kCmdSize * 2) == EW_PUSHPOP // Pop $VAR + && GET_CMD_PARAM(p + kCmdSize * 2, 1) != 0) { - Script += " "; - Script += startOffset; + if (IsVarStr(params[0], GET_CMD_PARAM(p + kCmdSize * 2, 0))) + { + s += "Exch"; + AddParam(params[0]); + NewLine(); + Tab(true); + endCommentIndex = kkk + 3; + } } + s += "Push"; + AddParam(params[0]); } break; } - case EW_STRCMP: + + case EW_FINDWINDOW: { - Script += " "; + AddParam_Var(params[0]); + AddParam(params[1]); + AddOptionalParams(params + 2, 3); + break; + } - Script += " "; - Script += ReadString2Qw(e.Params[0]); + case EW_SENDMESSAGE: + { + // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] + AddParam(params[1]); + + const char *w = NULL; + AString t; + ReadString2(t, params[2]); + UInt32 wm; + if (StringToUInt32(t, wm)) + { + switch (wm) + { + case 0x0C: w = "SETTEXT"; break; + case 0x10: w = "CLOSE"; break; + case 0x30: w = "SETFONT"; break; + } + } + if (w) + { + s += " ${WM_"; + s += w; + s += '}'; + } + else + SpaceQuStr(t); - Script += " "; - Script += ReadString2Qw(e.Params[1]); + UInt32 spec = params[5]; + for (unsigned i = 0; i < 2; i++) + { + AString s2; + if (spec & ((UInt32)1 << i)) + s2 += "STR:"; + ReadString2(s2, params[3 + i]); + SpaceQuStr(s2); + } - for (int j = 2; j < 5; j++) + if ((Int32)params[0] >= 0) + AddParam_Var(params[0]); + + spec >>= 2; + if (spec != 0) { - Script += " "; - Script += UIntToString(e.Params[j]); + s += " /TIMEOUT="; + Add_UInt(spec); } break; } - case EW_INTCMP: + + case EW_ISWINDOW: { - if (e.Params[5] != 0) - Script += "U"; + AddParam(params[0]); + Add_GotoVars2(¶ms[1]); + break; + } + + case EW_GETDLGITEM: + { + AddParam_Var(params[0]); + AddParams(params + 1, 2); + break; + } + + case EW_SETCTLCOLORS: + { + AddParam(params[0]); + + UInt32 offset = params[1]; + + if (_size < bhCtlColors.Offset + || _size - bhCtlColors.Offset < offset + || _size - bhCtlColors.Offset - offset < k_CtlColors_Size) + { + AddError("bad offset"); + break; + } - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); + const Byte *p2 = _data + bhCtlColors.Offset + offset; + CNsis_CtlColors colors; + colors.Parse(p2); - for (int i = 2; i < 5; i++) + if ((colors.flags & kColorsFlags_BK_SYS) != 0 || + (colors.flags & kColorsFlags_TEXT_SYS) != 0) + s += " /BRANDING"; + + AString bk; + bool bkc = false; + if (colors.bkmode == MY__TRANSPARENT) + bk += " transparent"; + else if (colors.flags & kColorsFlags_BKB) { - Script += " "; - Script += UIntToString(e.Params[i]); + if ((colors.flags & kColorsFlags_BK_SYS) == 0 && + (colors.flags & kColorsFlags_BK) != 0) + bkc = true; } + if ((colors.flags & kColorsFlags_TEXT) != 0 || !bk.IsEmpty() || bkc) + { + Space(); + if ((colors.flags & kColorsFlags_TEXT_SYS) != 0 || (colors.flags & kColorsFlags_TEXT) == 0) + AddQuotes(); + else + Add_Color(colors.text); + } + s += bk; + if (bkc) + { + Space(); + Add_Color(colors.bkc); + } + break; } - case EW_INTOP: + + case EW_SETBRANDINGIMAGE: { - Script += " "; - Script += GetVar(e.Params[0]); - Script += " "; - int numOps = 2; - AString op; - switch (e.Params[3]) - { - case 0: op = '+'; break; - case 1: op = '-'; break; - case 2: op = '*'; break; - case 3: op = '/'; break; - case 4: op = '|'; break; - case 5: op = '&'; break; - case 6: op = '^'; break; - case 7: op = '~'; numOps = 1; break; - case 8: op = '!'; numOps = 1; break; - case 9: op = "||"; break; - case 10: op = "&&"; break; - case 11: op = '%'; break; - default: op = UIntToString(e.Params[3]); - } - AString p1 = ReadString2(e.Params[1]); - if (numOps == 1) - { - Script += op; - Script += p1; - } + s += " /IMGID="; + Add_UInt(params[1]); + if (params[2] == 1) + s += " /RESIZETOFIT"; + AddParam(params[0]); + break; + } + + case EW_CREATEFONT: + { + AddParam_Var(params[0]); + AddParam(params[1]); + AddOptionalParams(params + 2, 2); + if (params[4] & 1) s += " /ITALIC"; + if (params[4] & 2) s += " /UNDERLINE"; + if (params[4] & 4) s += " /STRIKE"; + break; + } + + case EW_SHOWWINDOW: + { + AString hw, sw; + ReadString2(hw, params[0]); + ReadString2(sw, params[1]); + if (params[3] != 0) + s += "EnableWindow"; else { - Script += p1; - Script += " "; - Script += op; - Script += " "; - Script += ReadString2(e.Params[2]); + UInt32 val; + bool valDefined = false; + if (StringToUInt32(sw, val)) + { + if (val < ARRAY_SIZE(kShowWindow_Commands)) + { + sw.Empty(); + sw += "${"; + Add_ShowWindow_Cmd_2(sw, val); + sw += '}'; + valDefined = true; + } + } + bool isHwndParent = IsVarStr(params[0], IsNsis225 ? kVar_HWNDPARENT_225 : kVar_HWNDPARENT); + if (params[2] != 0) + { + if (valDefined && val == 0 && isHwndParent) + { + s += "HideWindow"; + break; + } + } + if (valDefined && val == 5 && isHwndParent && + kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_BRINGTOFRONT) + { + s += " ; "; + } + s += "ShowWindow"; } + SpaceQuStr(hw); + SpaceQuStr(sw); break; } - case EW_PUSHPOP: + case EW_SHELLEXEC: { - int isPop = (e.Params[1] != 0); - if (isPop) + AddParams(params, 2); + if (params[2] != 0 || params[3] != MY__SW_SHOWNORMAL) { - Script += "Pop"; - Script += " "; - Script += GetVar(e.Params[0]);; + AddParam(params[2]); + if (params[3] != MY__SW_SHOWNORMAL) + { + Space(); + Add_ShowWindow_Cmd(params[3]); + } + } + if (params[5] != 0) + { + s += " ;"; + AddParam(params[5]); // it's tatus text update + } + break; + } + + case EW_EXECUTE: + { + if (params[2] != 0) + s += "Wait"; + AddParam(params[0]); + if (params[2] != 0) + if ((Int32)params[1] >= 0) + AddParam_Var(params[1]); + break; + } + + case EW_GETFILETIME: + case EW_GETDLLVERSION: + { + AddParam(params[2]); + AddParam_Var(params[0]); + AddParam_Var(params[1]); + break; + } + + case EW_REGISTERDLL: + { + AString func; + ReadString2(func, params[1]); + bool printFunc = true; + // params[4] = 1; for plugin command + if (params[2] == 0) + { + s += "CallInstDLL"; + AddParam(params[0]); + if (params[3] == 1) + s += " /NOUNLOAD"; } else { - int isExch = (e.Params[2] != 0); - if (isExch) + if (func == "DllUnregisterServer") { - Script += "Exch"; + s += "UnRegDLL"; + printFunc = false; } else { - Script += "Push"; - Script += " "; - Script += ReadString2(e.Params[0]); + s += "RegDLL"; + if (func == "DllRegisterServer") + printFunc = false; } + AddParam(params[0]); } + if (printFunc) + SpaceQuStr(func); break; } - case EW_SENDMESSAGE: + case EW_CREATESHORTCUT: { - // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] - Script += " "; - // Script += ReadString2(e.Params[0]); - // Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += ReadString2(e.Params[2]); - - Script += " "; - UInt32 spec = e.Params[5]; - // if (spec & 1) - Script += IntToString(e.Params[3]); - // else - // Script += ReadString2(e.Params[3]); + unsigned numParams; + for (numParams = 6; numParams > 2; numParams--) + if (params[numParams - 1] != 0) + break; + + UInt32 spec = params[4]; + if (spec & 0x8000) // NSIS 3.0b0 + s += " /NoWorkingDir"; + + AddParams(params, numParams > 4 ? 4 : numParams); + if (numParams <= 4) + break; + + UInt32 icon = (spec & 0xFF); + Space(); + if (icon != 0) + Add_UInt(icon); + else + AddQuotes(); + + if ((spec >> 8) == 0 && numParams < 6) + break; + UInt32 sw = (spec >> 8) & 0x7F; + Space(); + // NSIS encoder replaces these names: + if (sw == MY__SW_SHOWMINNOACTIVE) + sw = MY__SW_SHOWMINIMIZED; + if (sw == 0) + AddQuotes(); + else + Add_ShowWindow_Cmd(sw); - Script += " "; - // if (spec & 2) - Script += IntToString(e.Params[4]); - // else - // Script += ReadString2(e.Params[4]); + UInt32 modKey = spec >> 24; + UInt32 key = (spec >> 16) & 0xFF; - if ((Int32)e.Params[0] >= 0) + if (modKey == 0 && key == 0) { - Script += " "; - Script += GetVar(e.Params[1]); + if (numParams < 6) + break; + Space(); + AddQuotes(); } - - spec >>= 2; - if (spec != 0) + else { - Script += " /TIMEOUT="; - Script += IntToString(spec); + Space(); + if (modKey & 1) s += "SHIFT|"; // HOTKEYF_SHIFT + if (modKey & 2) s += "CONTROL|"; + if (modKey & 4) s += "ALT|"; + if (modKey & 8) s += "EXT|"; + + static const unsigned kMy_VK_F1 = 0x70; + if (key >= kMy_VK_F1 && key <= kMy_VK_F1 + 23) + { + s += 'F'; + Add_UInt(key - kMy_VK_F1 + 1); + } + else if (key >= 'A' && key <= 'Z' || key >= '0' && key <= '9') + s += (char)key; + else + { + s += "Char_"; + Add_UInt(key); + } } + AddOptionalParam(params[5]); // description break; } - case EW_GETDLGITEM: + case EW_COPYFILES: { - Script += " "; - Script += GetVar(e.Params[0]);; - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += ReadString2(e.Params[2]); + if (params[2] & 0x04) s += " /SILENT"; // FOF_SILENT + if (params[2] & 0x80) s += " /FILESONLY"; // FOF_FILESONLY + AddParams(params, 2); + if (params[3] != 0) + { + s += " ;"; + AddParam(params[3]); // status text update + } break; - } - + } - case EW_REGISTERDLL: + case EW_REBOOT: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + if (params[0] != 0xbadf00d) + s += " ; Corrupted ???"; + else if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_QUIT) + endCommentIndex = kkk + 2; break; } - case EW_CREATESHORTCUT: + case EW_WRITEINI: { - AString s; - - Script += " "; - Script += ReadString2Qw(e.Params[0]); + unsigned numAlwaysParams = 0; + if (params[0] == 0) // Section + s += "FlushINI"; + else if (params[4] != 0) + { + s += "WriteINIStr"; + numAlwaysParams = 3; + } + else + { + s += "DeleteINI"; + s += (params[1] == 0) ? "Sec" : "Str"; + numAlwaysParams = 1; + } + AddParam(params[3]); // filename + // Section, EntryName, Value + AddParams(params, numAlwaysParams); + AddOptionalParams(params + numAlwaysParams, 3 - numAlwaysParams); + break; + } - Script += " "; - Script += ReadString2Qw(e.Params[1]); + case EW_READINISTR: + { + AddParam_Var(params[0]); + AddParam(params[3]); // FileName + AddParams(params +1, 2); // Section, EntryName + break; + } - for (int j = 2; j < 5; j++) + case EW_DELREG: + { + // NSIS 2.00 used another scheme! + + if (params[4] == 0) + s += "Value"; + else { - Script += " "; - Script += UIntToString(e.Params[j]); + s += "Key"; + if (params[4] & 2) + s += " /ifempty"; } + AddRegRoot(params[1]); + AddParam(params[2]); + AddOptionalParam(params[3]); break; } - /* - case EW_DELREG: + case EW_WRITEREG: { - AString keyName, valueName; - keyName = ReadString2(e.Params[1]); - bool isValue = (e.Params[2] != -1); - if (isValue) + const char *s2 = 0; + switch (params[4]) { - valueName = ReadString2(e.Params[2]); - Script += "Key"; + case 1: s2 = "Str"; break; + case 2: s2 = "ExpandStr"; break; // maybe unused + case 3: s2 = "Bin"; break; + case 4: s2 = "DWORD"; break; + default: + s += '?'; + Add_UInt(params[4]); } + if (params[4] == 1 && params[5] == 2) + s2 = "ExpandStr"; + if (s2) + s += s2; + AddRegRoot(params[0]); + AddParams(params + 1, 2); // keyName, valueName + if (params[4] != 3) + AddParam(params[3]); // value else - Script += "Value"; - Script += " "; - Script += UIntToString(e.Params[0]); - Script += " "; - Script += keyName; - if (isValue) { - Script += " "; - Script += valueName; + // Binary data. + Space(); + UInt32 offset = params[3]; + bool isSupported = false; + if (AfterHeaderSize >= 4 + && bhData.Offset <= AfterHeaderSize - 4 + && offset <= AfterHeaderSize - 4 - bhData.Offset) + { + // we support it for solid archives. + const Byte *p2 = _afterHeader + bhData.Offset + offset; + UInt32 size = Get32(p2); + if (size <= AfterHeaderSize - 4 - bhData.Offset - offset) + { + for (UInt32 i = 0; i < size; i++) + { + Byte b = (p2 + 4)[i]; + unsigned t; + t = (b >> 4); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + t = (b & 15); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + } + isSupported = true; + } + } + if (!isSupported) + { + // we must read from file here; + s += "data["; + Add_UInt(offset); + s += " ... ]"; + s += " ; !!! Unsupported"; + } } - Script += " "; - Script += UIntToString(e.Params[3]); break; } - */ - case EW_WRITEREG: + case EW_READREGSTR: + { + s += (params[4] == 1) ? "DWORD" : "Str"; + AddParam_Var(params[0]); + AddRegRoot(params[1]); + AddParams(params + 2, 2); + break; + } + + case EW_REGENUM: + { + s += (params[4] != 0) ? "Key" : "Value"; + AddParam_Var(params[0]); + AddRegRoot(params[1]); + AddParams(params + 2, 2); + break; + } + + case EW_FCLOSE: + case EW_FINDCLOSE: + { + AddParam_Var(params[0]); + break; + } + + case EW_FOPEN: { - AString s; - switch(e.Params[4]) + AddParam_Var(params[0]); + AddParam(params[3]); + UInt32 acc = params[1]; // dwDesiredAccess + UInt32 creat = params[2]; // dwCreationDisposition + if (acc == 0 && creat == 0) + break; + char cc = 0; + if (acc == MY__GENERIC_READ && creat == OPEN_EXISTING) + cc = 'r'; + else if (creat == CREATE_ALWAYS && acc == MY__GENERIC_WRITE) + cc = 'w'; + else if (creat == OPEN_ALWAYS && (acc == (MY__GENERIC_WRITE | MY__GENERIC_READ))) + cc = 'a'; + // cc = 0; + if (cc != 0) { - case 1: s = "Str"; break; - case 2: s = "ExpandStr"; break; - case 3: s = "Bin"; break; - case 4: s = "DWORD"; break; - default: s = "?" + UIntToString(e.Params[4]); break; + Space(); + s += cc; + break; } - Script += s; - Script += " "; - Script += GetRegRootID(e.Params[0]); - Script += " "; - AString keyName, valueName; - keyName = ReadString2Qw(e.Params[1]); - Script += keyName; - Script += " "; + if (acc & MY__GENERIC_READ) s += " GENERIC_READ"; + if (acc & MY__GENERIC_WRITE) s += " GENERIC_WRITE"; + if (acc & MY__GENERIC_EXECUTE) s += " GENERIC_EXECUTE"; + if (acc & MY__GENERIC_ALL) s += " GENERIC_ALL"; - valueName = ReadString2Qw(e.Params[2]); - Script += valueName; - Script += " "; + const char *s2 = NULL; + switch (creat) + { + case MY__CREATE_NEW: s2 = "CREATE_NEW"; break; + case MY__CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break; + case MY__OPEN_EXISTING: s2 = "OPEN_EXISTING"; break; + case MY__OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break; + case MY__TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break; + } + Space(); + if (s2) + s += s2; + else + Add_UInt(creat); + break; + } - valueName = ReadString2Qw(e.Params[3]); - Script += valueName; - Script += " "; + case EW_FPUTS: + case EW_FPUTWS: + { + if (commandId == EW_FPUTWS) + s += (params[2] == 0) ? "UTF16LE" : "Word"; + else if (params[2] != 0) + s += "Byte"; + AddParam_Var(params[0]); + AddParam(params[1]); + break; + } + case EW_FGETS: + case EW_FGETWS: + { + if (commandId == EW_FPUTWS) + s += (params[3] == 0) ? "UTF16LE" : "Word"; + if (params[3] != 0) + s += "Byte"; + AddParam_Var(params[0]); + AddParam_Var(params[1]); + AString maxLenStr; + ReadString2(maxLenStr, params[2]); + UInt32 maxLen; + if (StringToUInt32(maxLenStr, maxLen)) + { + if (maxLen == 1 && params[3] != 0) + break; + if (maxLen == 1023 && params[3] == 0) // NSIS_MAX_STRLEN - 1; can be other value!! + break; + } + SpaceQuStr(maxLenStr); break; } - case EW_WRITEUNINSTALLER: + case EW_FSEEK: { - Script += " "; - Script += ReadString2(e.Params[0]); - for (int j = 1; j < 3; j++) + AddParam_Var(params[0]); + AddParam(params[2]); + if (params[3] == 1) s += " CUR"; // FILE_CURRENT + if (params[3] == 2) s += " END"; // FILE_END + if ((Int32)params[1] >= 0) { - Script += " "; - Script += UIntToString(e.Params[j]); + if (params[3] == 0) s += " SET"; // FILE_BEGIN + AddParam_Var(params[1]); } break; } - default: + case EW_FINDNEXT: + { + AddParam_Var(params[1]); + AddParam_Var(params[0]); + break; + } + + case EW_FINDFIRST: + { + AddParam_Var(params[1]); + AddParam_Var(params[0]); + AddParam(params[2]); + break; + } + + case EW_LOG: { - int numParams = kNumEntryParams; - if (e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0])) + if (params[0] != 0) { - const CCommandPair &pair = kCommandPairs[e.Which]; - // Script += pair.Name; - numParams = pair.NumParams; + s += "Set "; + s += (params[1] == 0) ? "off" : "on"; } else { - Script += "Unknown"; - Script += UIntToString(e.Which); + s += "Text"; + AddParam(params[1]); } - Script += e.GetParamsString(numParams); + } + + case EW_SECTIONSET: + { + if ((Int32)params[2] >= 0) + { + s += "Get"; + Add_SectOp(params[2]); + AddParam(params[0]); + AddParam_Var(params[1]); + } + else + { + s += "Set"; + UInt32 t = -(Int32)params[2] - 1; + Add_SectOp(t); + AddParam(params[0]); + AddParam(params[t == 0 ? 4 : 1]); + + // params[3] != 0 means call SectionFlagsChanged in installer + // used by SECTIONSETFLAGS command + } + break; + } + + case EW_INSTTYPESET: + { + int numQwParams = 0; + const char *s2; + if (params[3] == 0) + { + if (params[2] == 0) + { + s2 = "InstTypeGetText"; + numQwParams = 1; + } + else + { + s2 = "InstTypeSetText"; + numQwParams = 2; + } + } + else + { + if (params[2] == 0) + s2 = "GetCurInstType"; + else + { + s2 = "SetCurInstType"; + numQwParams = 1; + } + } + s += s2; + AddParams(params, numQwParams); + if (params[2] == 0) + AddParam_Var(params[1]); + break; + } + + case EW_LOCKWINDOW: + { + s += (params[0] == 0) ? " on" : " off"; + break; + } + + case EW_FINDPROC: + { + AddParam_Var(params[0]); + AddParam(params[1]); + break; + } + + default: + { + numSkipParams = 0; } #endif } + #ifdef NSIS_SCRIPT - Script += kCrLf; + + unsigned numParams = kNumCommandParams; + + for (; numParams > 0; numParams--) + if (params[numParams - 1] != 0) + break; + + if (numParams > numSkipParams) + { + s += " ; !!!! Unknown Params: "; + unsigned i; + for (i = 0; i < numParams; i++) + AddParam(params[i]); + + s += " ;"; + + for (i = 0; i < numParams; i++) + { + Space(); + UInt32 v = params[i]; + if (v > 0xFFF00000) + Add_SignedInt(s, (Int32)v); + else + Add_UInt(v); + } + } + + NewLine(); + #endif } + #ifdef NSIS_SCRIPT + + if (sectionIsOpen) + { + if (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk) + { + PrintSectionEnd(); + sectionIsOpen = false; + // lastSectionEndCmd = kkk; + curSectionIndex++; + } + } + } + + while (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sectionIsOpen) + { + if (sect.StartCmdIndex + sect.NumCommands != kkk) + AddErrorLF("SECTION ERROR"); + PrintSectionEnd(); + sectionIsOpen = false; + curSectionIndex++; + } + else + { + if (curSectionIndex == 49) + curSectionIndex = curSectionIndex; + + if (PrintSectionBegin(sect, curSectionIndex)) + curSectionIndex++; + else + sectionIsOpen = true; + } + } + + #endif + + return S_OK; +} + +static int CompareItems(void *const *p1, void *const *p2, void *param) +{ + const CItem &i1 = **(CItem **)p1; + const CItem &i2 = **(CItem **)p2; + RINOZ(MyCompare(i1.Pos, i2.Pos)); + const CInArchive *inArchive = (const CInArchive *)param; + if (inArchive->IsUnicode) + { + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0) return -1; + if (i2.Prefix < 0) return 1; + RINOZ(wcscmp( + inArchive->UPrefixes[i1.Prefix], + inArchive->UPrefixes[i2.Prefix])); + } + RINOZ(wcscmp(i1.NameU, i2.NameU)); + } + else + { + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0) return -1; + if (i2.Prefix < 0) return 1; + RINOZ(strcmp( + inArchive->APrefixes[i1.Prefix], + inArchive->APrefixes[i2.Prefix])); + } + RINOZ(strcmp(i1.NameA, i2.NameA)); + } + return 0; +} + +HRESULT CInArchive::SortItems() +{ { - Items.Sort(CompareItems, 0); - int i; - // if (IsSolid) - for (i = 0; i + 1 < Items.Size();) + Items.Sort(CompareItems, (void *)this); + unsigned i; + + for (i = 0; i + 1 < Items.Size(); i++) { - bool sameName = IsUnicode ? - (Items[i].NameU == Items[i + 1].NameU) : - (Items[i].NameA == Items[i + 1].NameA); - if (Items[i].Pos == Items[i + 1].Pos && sameName) - Items.Delete(i + 1); + const CItem &i1 = Items[i]; + const CItem &i2 = Items[i + 1]; + if (i1.Pos != i2.Pos) + continue; + + if (IsUnicode) + { + if (i1.NameU != i2.NameU) continue; + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0 || i2.Prefix < 0) continue; + if (UPrefixes[i1.Prefix] != UPrefixes[i2.Prefix]) continue; + } + } else - i++; + { + if (i1.NameA != i2.NameA) continue; + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0 || i2.Prefix < 0) continue; + if (APrefixes[i1.Prefix] != APrefixes[i2.Prefix]) continue; + } + } + Items.Delete(i + 1); + i--; } + for (i = 0; i < Items.Size(); i++) { CItem &item = Items[i]; UInt32 curPos = item.Pos + 4; - for (int nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) + for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) { UInt32 nextPos = Items[nextIndex].Pos; if (curPos <= nextPos) { - item.EstimatedSizeIsDefined = true; + item.EstimatedSize_Defined = true; item.EstimatedSize = nextPos - curPos; break; } } } + if (!IsSolid) { for (i = 0; i < Items.Size(); i++) { CItem &item = Items[i]; RINOK(_stream->Seek(GetPosOfNonSolidItem(i), STREAM_SEEK_SET, NULL)); - const UInt32 kSigSize = 4 + 1 + 5; + const UInt32 kSigSize = 4 + 1 + 1 + 4; // size,[flag],prop,dict BYTE sig[kSigSize]; size_t processedSize = kSigSize; RINOK(ReadStream(_stream, sig, &processedSize)); if (processedSize < 4) return S_FALSE; UInt32 size = Get32(sig); - if ((size & 0x80000000) != 0) + if ((size & kMask_IsCompressed) != 0) { item.IsCompressed = true; - // is compressed; - size &= ~0x80000000; + size &= ~kMask_IsCompressed; if (Method == NMethodType::kLZMA) { if (processedSize < 9) return S_FALSE; + /* if (FilterFlag) item.UseFilter = (sig[4] != 0); - item.DictionarySize = Get32(sig + 5 + (FilterFlag ? 1 : 0)); + */ + item.DictionarySize = Get32(sig + 4 + 1 + (FilterFlag ? 1 : 0)); } } else { item.IsCompressed = false; item.Size = size; - item.SizeIsDefined = true; + item.Size_Defined = true; } item.CompressedSize = size; - item.CompressedSizeIsDefined = true; + item.CompressedSize_Defined = true; } } } return S_OK; } +// Flags for common_header.flags +#define CH_FLAGS_DETAILS_SHOWDETAILS 1 +#define CH_FLAGS_DETAILS_NEVERSHOW 2 +#define CH_FLAGS_PROGRESS_COLORED 4 +#define CH_FLAGS_SILENT 8 +#define CH_FLAGS_SILENT_LOG 16 +#define CH_FLAGS_AUTO_CLOSE 32 +#define CH_FLAGS_DIR_NO_SHOW 64 // unused now +#define CH_FLAGS_NO_ROOT_DIR 128 +#define CH_FLAGS_COMP_ONLY_ON_CUSTOM 256 +#define CH_FLAGS_NO_CUSTOM 512 + +static const char *k_PostStrings[] = +{ + "install_directory_auto_append" + , "uninstchild" // NSIS 2.25+, used by uninstaller: + , "uninstcmd" // NSIS 2.25+, used by uninstaller: + , "wininit" // NSIS 2.25+, used by move file on reboot +}; + HRESULT CInArchive::Parse() { // UInt32 offset = ReadUInt32(); - // ???? offset == FirstHeader.HeaderLength - /* UInt32 ehFlags = */ ReadUInt32(); - CBlockHeader bhPages, bhSections, bhEntries, bhStrings, bhLangTables, bhCtlColors, bhData; - // CBlockHeader bgFont; - ReadBlockHeader(bhPages); - ReadBlockHeader(bhSections); - ReadBlockHeader(bhEntries); - ReadBlockHeader(bhStrings); - ReadBlockHeader(bhLangTables); - ReadBlockHeader(bhCtlColors); - // ReadBlockHeader(bgFont); - ReadBlockHeader(bhData); + // ???? offset == FirstHeader.HeaderSize + const Byte *p = _data; + + CBlockHeader bhEntries, bhStrings, bhLangTables; + bhEntries.Parse(p + 4 + 8 * 2); + bhStrings.Parse(p + 4 + 8 * 3); + bhLangTables.Parse(p + 4 + 8 * 4); + + #ifdef NSIS_SCRIPT + + CBlockHeader bhFont; + bhPages.Parse(p + 4 + 8 * 0); + bhSections.Parse(p + 4 + 8 * 1); + bhCtlColors.Parse(p + 4 + 8 * 5); + bhFont.Parse(p + 4 + 8 * 6); + bhData.Parse(p + 4 + 8 * 7); + + #endif _stringsPos = bhStrings.Offset; - UInt32 pos = GetOffset() + _stringsPos; - int numZeros0 = 0; - int numZeros1 = 0; - int i; - const int kBlockSize = 256; - for (i = 0; i < kBlockSize; i++) - { - if (pos >= _size || pos + 1 >= _size) - break; - char c0 = _data[pos++]; - char c1 = _data[pos++]; - wchar_t c = (c0 | ((wchar_t)c1 << 8)); + if (_stringsPos > _size) + return S_FALSE; + { + if (bhLangTables.Offset < bhStrings.Offset) + return S_FALSE; + UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset; + if (stringTableSize < 2) + return S_FALSE; + const Byte *strData = _data + _stringsPos; + if (strData[stringTableSize - 1] != 0) + return S_FALSE; + IsUnicode = (Get16(strData) == 0); + NumStringChars = stringTableSize; + if (IsUnicode) + { + if ((stringTableSize & 1) != 0) + return S_FALSE; + NumStringChars >>= 1; + if (strData[stringTableSize - 2] != 0) + return S_FALSE; + } - if (c >= NS_UN_CODES_START && c < NS_UN_CODES_END) + } + + if (bhEntries.Num > (1 << 25)) + return S_FALSE; + if (bhEntries.Offset > _size) + return S_FALSE; + if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset) + return S_FALSE; + + DetectNsisType(bhEntries, _data + bhEntries.Offset); + + #ifdef NSIS_SCRIPT + + { + AddCommentAndString("NSIS script"); + if (IsUnicode) + Script += " (UTF-8)"; + Space(); + Script += GetFormatDescription(); + AddLF(); + } + { + AddCommentAndString(IsInstaller ? "Install" : "Uninstall"); + AddLF(); + } + + AddLF(); + if (IsUnicode) + AddStringLF("Unicode true"); + + if (Method != NMethodType::kCopy) + { + const char *m = NULL; + switch (Method) { - if (pos >= _size || pos + 1 >= _size) - break; - pos += 2; - numZeros1++; + case NMethodType::kDeflate: m = "zlib"; break; + case NMethodType::kBZip2: m = "bzip2"; break; + case NMethodType::kLZMA: m = "lzma"; break; + } + Script += "SetCompressor"; + if (IsSolid) + Script += " /SOLID"; + if (m) + { + Space(); + Script += m; + } + AddLF(); + } + if (Method == NMethodType::kLZMA) + { + // if (DictionarySize != (8 << 20)) + { + Script += "SetCompressorDictSize"; + AddParam_UInt(DictionarySize >> 20); + AddLF(); } + } + + Separator(); + PrintNumComment("HEADER SIZE", FirstHeader.HeaderSize); + // if (bhPages.Offset != 300 && bhPages.Offset != 288) + if (bhPages.Offset != 0) + { + PrintNumComment("START HEADER SIZE", bhPages.Offset); + } + + if (bhSections.Num > 0) + { + if (bhEntries.Offset < bhSections.Offset) + return S_FALSE; + SectionSize = (bhEntries.Offset - bhSections.Offset) / bhSections.Num; + if (bhSections.Offset + bhSections.Num * SectionSize != bhEntries.Offset) + return S_FALSE; + if (SectionSize < kSectionSize_base) + return S_FALSE; + UInt32 maxStringLen = SectionSize - kSectionSize_base; + if (IsUnicode) + { + if ((maxStringLen & 1) != 0) + return S_FALSE; + maxStringLen >>= 1; + } + // if (maxStringLen != 1024) + { + if (maxStringLen == 0) + PrintNumComment("SECTION SIZE", SectionSize); + else + PrintNumComment("MAX STRING LENGTH", maxStringLen); + } + } + + PrintNumComment("STRING CHARS", NumStringChars); + // PrintNumComment("LANG TABLE SIZE", bhCtlColors.Offset - bhLangTables.Offset); + + if (bhCtlColors.Offset > _size) + AddErrorLF("Bad COLORS TABLE"); + // PrintNumComment("COLORS TABLE SIZE", bhFont.Offset - bhCtlColors.Offset); + if (bhCtlColors.Num != 0) + PrintNumComment("COLORS Num", bhCtlColors.Num); + + // bhData uses offset in _afterHeader (not in _data) + // PrintNumComment("FONT TABLE SIZE", bhData.Offset - bhFont.Offset); + if (bhFont.Num != 0) + PrintNumComment("FONTS Num", bhFont.Num); + + // PrintNumComment("DATA SIZE", FirstHeader.HeaderSize - bhData.Offset); + if (bhData.Num != 0) + PrintNumComment("DATA NUM", bhData.Num); + + AddLF(); + + AddStringLF("OutFile [NSIS].exe"); + AddStringLF("!include WinMessages.nsh"); + + AddLF(); + + strUsed.Alloc(NumStringChars); + memset(strUsed, 0, NumStringChars); + + { + UInt32 ehFlags = Get32(p); + UInt32 showDetails = ehFlags & 3;// CH_FLAGS_DETAILS_SHOWDETAILS & CH_FLAGS_DETAILS_NEVERSHOW; + if (showDetails >= 1 && showDetails <= 2) + { + Script += IsInstaller ? "ShowInstDetails" : "ShowUninstDetails"; + Script += (showDetails == 1) ? " show" : " nevershow"; + AddLF(); + } + if (ehFlags & CH_FLAGS_PROGRESS_COLORED) AddStringLF("InstProgressFlags colored" ); + if ((ehFlags & (CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG)) != 0) + { + Script += IsInstaller ? "SilentInstall " : "SilentUnInstall "; + Script += (ehFlags & CH_FLAGS_SILENT_LOG) ? "silentlog" : "silent"; + AddLF(); + } + if (ehFlags & CH_FLAGS_AUTO_CLOSE) AddStringLF("AutoCloseWindow true"); + if ((ehFlags & CH_FLAGS_NO_ROOT_DIR) == 0) AddStringLF("AllowRootDirInstall true"); + if (ehFlags & CH_FLAGS_NO_CUSTOM) AddStringLF("InstType /NOCUSTOM"); + if (ehFlags & CH_FLAGS_COMP_ONLY_ON_CUSTOM) AddStringLF("InstType /COMPONENTSONLYONCUSTOM"); + } + + // Separator(); + // AddLF(); + + Int32 licenseLangIndex = -1; + { + const Byte *pp = _data + bhPages.Offset; + + for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, pp += kPageSize) + { + UInt32 wndProcID = Get32(pp + 4); + UInt32 param1 = Get32(pp + 44 + 4 * 1); + if (wndProcID != PWP_LICENSE || param1 == 0) + continue; + if ((Int32)param1 < 0) + licenseLangIndex = - ((Int32)param1 + 1); + else + noParseStringIndexes.AddToUniqueSorted(param1); + } + } + + unsigned paramsOffset = 4 + 8 * 8; + if (bhPages.Offset == 276) + paramsOffset -= 8; + + const Byte *p2 = p + paramsOffset; + + { + UInt32 rootKey = Get32(p2); // (rootKey = -1) in uninstaller by default (the bug in NSIS) + UInt32 subKey = Get32(p2 + 4); + UInt32 value = Get32(p2 + 8); + if ((rootKey != 0 && rootKey != (UInt32)(Int32)-1) || subKey != 0 || value != 0) + { + Script += "InstallDirRegKey"; + AddRegRoot(rootKey); + AddParam(subKey); + AddParam(value); + NewLine(); + } + } + + + { + UInt32 bg_color1 = Get32(p2 + 12); + UInt32 bg_color2 = Get32(p2 + 16); + UInt32 bg_textcolor = Get32(p2 + 20); + if (bg_color1 != (UInt32)(Int32)-1 || bg_color2 != (UInt32)(Int32)-1 || bg_textcolor != (UInt32)(Int32)-1) + { + Script += "BGGradient"; + if (bg_color1 != 0 || bg_color2 != 0xFF0000 || bg_textcolor != (UInt32)(Int32)-1) + { + Add_ColorParam(bg_color1); + Add_ColorParam(bg_color2); + if (bg_textcolor != (UInt32)(Int32)-1) + Add_ColorParam(bg_textcolor); + } + AddLF(); + } + } + + { + UInt32 lb_bg = Get32(p2 + 24); + UInt32 lb_fg = Get32(p2 + 28); + if ((lb_bg != (UInt32)(Int32)-1 || lb_fg != (UInt32)(Int32)-1) && + (lb_bg != 0 || lb_fg != 0xFF00)) + { + Script += "InstallColors"; + Add_ColorParam(lb_fg); + Add_ColorParam(lb_bg); + AddLF(); + } + } + + UInt32 license_bg = Get32(p2 + 36); + if (license_bg != (UInt32)(Int32)-1 && license_bg != -15) // COLOR_BTNFACE + { + Script += "LicenseBkColor"; + if ((Int32)license_bg == -5) // COLOR_WINDOW + Script += " /windows"; + /* + else if ((Int32)license_bg == -15) + Script += " /grey"; + */ else + Add_ColorParam(license_bg); + AddLF(); + } + + UInt32 langtable_size = Get32(p2 + 32); + if (bhLangTables.Num > 0) + { + UInt32 numStrings = (langtable_size - 10) / 4; + _numLangStrings = numStrings; + AddLF(); + Separator(); + PrintNumComment("LANG TABLES", bhLangTables.Num); + PrintNumComment("LANG STRINGS", numStrings); + AddLF(); + + if (licenseLangIndex >= 0) + { + for (UInt32 i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + UInt32 val = Get32(p + 10 + licenseLangIndex * 4); + if (val != 0) + { + Script += "LicenseLangString "; + Add_LangStr_Simple(licenseLangIndex); + AddParam_UInt(langID); + AddLicense(val, langID); + noParseStringIndexes.AddToUniqueSorted(val); + NewLine(); + } + } + AddLF(); + } + + UInt32 brandingText = 0; + UInt32 caption = 0; + UInt32 name = 0; + UInt32 i; + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + if (i == 0 || langID == 1033) + _mainLang = p + 10; + { + UInt32 v = Get32(p + 10 + 0 * 4); + if (v != 0 && (langID == 1033 || brandingText == 0)) + brandingText = v; + } + { + UInt32 v = Get32(p + 10 + 1 * 4); + if (v != 0 && (langID == 1033 || caption == 0)) + caption = v; + } + { + UInt32 v = Get32(p + 10 + 2 * 4); + if (v != 0 && (langID == 1033 || name == 0)) + name = v; + } + } + + if (name != 0) { - if (c0 == 0 && c1 != 0) - numZeros0++; - if (c1 == 0) - numZeros1++; + Script += "Name"; + AddParam(name); + NewLine(); + + ReadString2(Name, name); + } + + /* + if (caption != 0) + { + Script += "Caption"; + AddParam(caption); + NewLine(); + } + */ + + if (brandingText != 0) + { + Script += "BrandingText"; + AddParam(brandingText); + NewLine(); + + ReadString2(BrandingText, brandingText); } - // printf("\nnumZeros0 = %2x %2x", _data[pos + 0], _data[pos + 1]); + + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + + AddLF(); + AddCommentAndString("LANG:"); + AddParam_UInt(langID); + /* + Script += " ("; + LangId_To_String(Script, langID); + Script += ')'; + */ + AddLF(); + // UInt32 dlg_offset = Get32(p + 2); + // UInt32 g_exec_flags_rtl = Get32(p + 6); + + + for (UInt32 j = 0; j < numStrings; j++) + { + UInt32 val = Get32(p + 10 + j * 4); + if (val != 0) + { + if ((Int32)j != licenseLangIndex) + { + Script += "LangString "; + Add_LangStr_Simple(j); + AddParam_UInt(langID); + AddParam(val); + AddLF(); + } + } + } + AddLF(); + } + ClearLangComment(); } - IsUnicode = (numZeros1 > numZeros0 * 3 + kBlockSize / 16); - // printf("\nnumZeros0 = %3d numZeros1 = %3d", numZeros0, numZeros1); - return ReadEntries(bhEntries); + + { + unsigned numInternalVars = GET_NUM_INTERNAL_VARS; + UInt32 numUsedVars = GetNumUsedVars(); + if (numUsedVars > numInternalVars) + { + Separator(); + PrintNumComment("VARIABLES", numUsedVars - numInternalVars); + AddLF(); + AString temp; + for (UInt32 i = numInternalVars; i < numUsedVars; i++) + { + Script += "Var "; + temp.Empty(); + GetVar2(temp, i); + AddStringLF(temp); + } + AddLF(); + } + } + + onFuncOffset = paramsOffset + 40; + numOnFunc = ARRAY_SIZE(kOnFunc); + if (bhPages.Offset == 276) + numOnFunc--; + p2 += 40 + numOnFunc * 4; + + #define NSIS_MAX_INST_TYPES 32 + + AddLF(); + + UInt32 i; + for (i = 0; i < NSIS_MAX_INST_TYPES + 1; i++, p2 += 4) + { + UInt32 instType = Get32(p2); + if (instType != 0) + { + Script += "InstType"; + AString s2; + if (!IsInstaller) + s2 += "un."; + ReadString2(s2, instType); + SpaceQuStr(s2); + NewLine(); + } + } + + { + UInt32 installDir = Get32(p2); + p2 += 4; + if (installDir != 0) + { + Script += "InstallDir"; + AddParam(installDir); + NewLine(); + } + } + + if (bhPages.Offset >= 288) + for (i = 0; i < 4; i++) + { + if (i != 0 && bhPages.Offset < 300) + break; + UInt32 param = Get32(p2 + 4 * i); + if (param == 0 || param == (UInt32)(Int32)-1) + continue; + + /* + uninstaller: + UInt32 uninstChild = Get32(p2 + 8); // "$TEMP\\$1u_.exe" + UInt32 uninstCmd = Get32(p2 + 12); // "\"$TEMP\\$1u_.exe\" $0 _?=$INSTDIR\\" + int str_wininit = Get32(p2 + 16); // "$WINDIR\\wininit.ini" + */ + + AddCommentAndString(k_PostStrings[i]); + Script += " ="; + AddParam(param); + NewLine(); + } + + AddLF(); + + #endif + + RINOK(ReadEntries(bhEntries)); + + #ifdef NSIS_SCRIPT + + Separator(); + AddCommentAndString("UNREFERENCED STRINGS:"); + AddLF(); + AddLF(); + CommentOpen(); + + for (i = 0; i < NumStringChars;) + { + if (!strUsed[i] && i != 0) + // Script += "!!! "; + { + Add_UInt(i); + AddParam(i); + NewLine(); + } + if (IsUnicode) + i += GetUi16Str_Len((const Byte *)_data + _stringsPos + i * 2); + else + i += (UInt32)strlen((const char *)(const Byte *)_data + _stringsPos + i); + i++; + } + CommentClose(); + #endif + + return SortItems(); } static bool IsLZMA(const Byte *p, UInt32 &dictionary) { dictionary = Get32(p + 1); - return (p[0] == 0x5D && p[1] == 0x00 && p[2] == 0x00 && p[5] == 0x00); + return (p[0] == 0x5D && + p[1] == 0x00 && p[2] == 0x00 && + p[5] == 0x00 && (p[6] & 0x80) == 0x00); } static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag) @@ -1276,7 +5545,7 @@ static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag) thereIsFlag = false; return true; } - if (IsLZMA(p + 1, dictionary)) + if (p[0] <= 1 && IsLZMA(p + 1, dictionary)) { thereIsFlag = true; return true; @@ -1289,92 +5558,131 @@ static bool IsBZip2(const Byte *p) return (p[0] == 0x31 && p[1] < 14); } -HRESULT CInArchive::Open2( - DECL_EXTERNAL_CODECS_LOC_VARS2 - ) +HRESULT CInArchive::Open2(const Byte *sig, size_t size) { - RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &StreamOffset)); - - const UInt32 kSigSize = 4 + 1 + 5 + 1; // size, flag, lzma props, lzma first byte - BYTE sig[kSigSize]; - RINOK(ReadStream_FALSE(_stream, sig, kSigSize)); - UInt64 position; - RINOK(_stream->Seek(StreamOffset, STREAM_SEEK_SET, &position)); + const UInt32 kSigSize = 4 + 1 + 5 + 2; // size, flag, 5 - lzma props, 2 - lzma first bytes + if (size < kSigSize) + return S_FALSE; _headerIsCompressed = true; IsSolid = true; FilterFlag = false; + UseFilter = false; DictionarySize = 1; + #ifdef NSIS_SCRIPT + AfterHeaderSize = 0; + #endif + UInt32 compressedHeaderSize = Get32(sig); - if (compressedHeaderSize == FirstHeader.HeaderLength) + + /* + XX XX XX XX XX XX XX XX == FirstHeader.HeaderSize, nonsolid, uncompressed + 5D 00 00 dd dd 00 solid LZMA + 00 5D 00 00 dd dd 00 solid LZMA, empty filter (there are no such archives) + 01 5D 00 00 dd dd 00 solid LZMA, BCJ filter (only 7-Zip installer used that format) + + SS SS SS 80 00 5D 00 00 dd dd 00 non-solid LZMA, empty filter + SS SS SS 80 01 5D 00 00 dd dd 00 non-solid LZMA, BCJ filte + SS SS SS 80 01 tt non-solid BZip (tt < 14 + SS SS SS 80 non-solid deflate + + 01 tt solid BZip (tt < 14 + other solid Deflate + */ + + if (compressedHeaderSize == FirstHeader.HeaderSize) { _headerIsCompressed = false; IsSolid = false; Method = NMethodType::kCopy; } else if (IsLZMA(sig, DictionarySize, FilterFlag)) - { Method = NMethodType::kLZMA; - } - else if (IsLZMA(sig + 4, DictionarySize, FilterFlag)) - { - IsSolid = false; - Method = NMethodType::kLZMA; - } else if (sig[3] == 0x80) { IsSolid = false; - if (IsBZip2(sig + 4)) + if (IsLZMA(sig + 4, DictionarySize, FilterFlag) && sig[3] == 0x80) + Method = NMethodType::kLZMA; + else if (IsBZip2(sig + 4)) Method = NMethodType::kBZip2; else Method = NMethodType::kDeflate; } else if (IsBZip2(sig)) - { Method = NMethodType::kBZip2; - } else - { Method = NMethodType::kDeflate; - } - _posInData = 0; - if (!IsSolid) + if (IsSolid) + { + RINOK(_stream->Seek(DataStreamOffset, STREAM_SEEK_SET, NULL)); + } + else { - _headerIsCompressed = ((compressedHeaderSize & 0x80000000) != 0); - if (_headerIsCompressed) - compressedHeaderSize &= ~0x80000000; + _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0); + compressedHeaderSize &= ~kMask_IsCompressed; _nonSolidStartOffset = compressedHeaderSize; - RINOK(_stream->Seek(StreamOffset + 4, STREAM_SEEK_SET, NULL)); + RINOK(_stream->Seek(DataStreamOffset + 4, STREAM_SEEK_SET, NULL)); } - UInt32 unpackSize = FirstHeader.HeaderLength; + + _data.Alloc(FirstHeader.HeaderSize); + _size = (size_t)FirstHeader.HeaderSize; + + Decoder.Method = Method; + Decoder.FilterFlag = FilterFlag; + Decoder.Solid = IsSolid; + Decoder.InputStream = _stream; + Decoder.Buffer.Alloc(kInputBufSize); + Decoder.StreamPos = 0; + if (_headerIsCompressed) { - // unpackSize = (1 << 23); - _data.SetCapacity(unpackSize); - RINOK(Decoder.Init( - EXTERNAL_CODECS_LOC_VARS - _stream, Method, FilterFlag, UseFilter)); - size_t processedSize = unpackSize; + RINOK(Decoder.Init(_stream, UseFilter)); + if (IsSolid) + { + size_t processedSize = 4; + Byte buf[4]; + RINOK(Decoder.Read(buf, &processedSize)); + if (processedSize != 4) + return S_FALSE; + if (Get32((const Byte *)buf) != FirstHeader.HeaderSize) + return S_FALSE; + } + size_t processedSize = FirstHeader.HeaderSize; RINOK(Decoder.Read(_data, &processedSize)); - if (processedSize != unpackSize) + if (processedSize != FirstHeader.HeaderSize) return S_FALSE; - _size = processedSize; + + #ifdef NSIS_SCRIPT if (IsSolid) { - UInt32 size2 = ReadUInt32(); - if (size2 < _size) - _size = size2; + /* we need additional bytes for data for WriteRegBin */ + AfterHeaderSize = (1 << 12); + _afterHeader.Alloc(AfterHeaderSize); + size_t processedSize = AfterHeaderSize; + RINOK(Decoder.Read(_afterHeader, &processedSize)); + AfterHeaderSize = (UInt32)processedSize; } + #endif } else { - _data.SetCapacity(unpackSize); - _size = (size_t)unpackSize; - RINOK(ReadStream_FALSE(_stream, (Byte *)_data, unpackSize)); + size_t processedSize = FirstHeader.HeaderSize; + RINOK(ReadStream(_stream, (Byte *)_data, &processedSize)); + if (processedSize < FirstHeader.HeaderSize) + return S_FALSE; } + + #ifdef NUM_SPEED_TESTS + for (unsigned i = 0; i < NUM_SPEED_TESTS; i++) + { + RINOK(Parse()); + Clear2(); + } + #endif + return Parse(); } @@ -1404,57 +5712,212 @@ FirstHeader UInt32 Flags; Byte Signature[16]; // points to the header+sections+entries+stringtable in the datablock - UInt32 HeaderLength; - UInt32 ArchiveSize; + UInt32 HeaderSize; + UInt32 ArcSize; } */ -HRESULT CInArchive::Open( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, const UInt64 *maxCheckStartPosition) + +// ---------- PE (EXE) parsing ---------- + +static const unsigned k_PE_StartSize = 0x40; +static const unsigned k_PE_HeaderSize = 4 + 20; +static const unsigned k_PE_OptHeader32_Size_MIN = 96; + +static inline bool CheckPeOffset(UInt32 pe) +{ + return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0); +} + + +static bool IsArc_Pe(const Byte *p, size_t size) +{ + if (size < 2) + return false; + if (p[0] != 'M' || p[1] != 'Z') + return false; + if (size < k_PE_StartSize) + return false; // k_IsArc_Res_NEED_MORE; + UInt32 pe = Get32(p + 0x3C); + if (!CheckPeOffset(pe)) + return false; + if (pe + k_PE_HeaderSize > size) + return false; // k_IsArc_Res_NEED_MORE; + + p += pe; + if (Get32(p) != 0x00004550) + return false; + return Get16(p + 4 + 16) >= k_PE_OptHeader32_Size_MIN; +} + +HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition) { Clear(); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - UInt64 maxSize = ((maxCheckStartPosition != 0) ? *maxCheckStartPosition : 0); - const UInt32 kStep = 512; - Byte buffer[kStep]; - UInt64 position = 0; - for (; position <= maxSize; position += kStep) + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &StartOffset)); + + const UInt32 kStartHeaderSize = 4 * 7; + const unsigned kStep = 512; // nsis start is aligned for 512 + Byte buf[kStep]; + UInt64 pos = StartOffset; + size_t bufSize = 0; + UInt64 pePos = (UInt64)(Int64)-1; + + for (;;) { - RINOK(ReadStream_FALSE(inStream, buffer, kStep)); - if (memcmp(buffer + 4, kSignature, kSignatureSize) == 0) + bufSize = kStep; + RINOK(ReadStream(inStream, buf, &bufSize)); + if (bufSize < kStartHeaderSize) + return S_FALSE; + if (memcmp(buf + 4, kSignature, kSignatureSize) == 0) break; + if (IsArc_Pe(buf, bufSize)) + pePos = pos; + pos += kStep; + UInt64 proc = pos - StartOffset; + if (maxCheckStartPosition && proc > *maxCheckStartPosition) + { + if (pePos == 0) + { + if (proc > (1 << 20)) + return S_FALSE; + } + else + return S_FALSE; + } + } + + if (pePos == (UInt64)(Int64)-1) + { + UInt64 posCur = StartOffset; + for (;;) + { + if (posCur < kStep) + break; + posCur -= kStep; + if (pos - posCur > (1 << 20)) + break; + bufSize = kStep; + RINOK(inStream->Seek(posCur, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream(inStream, buf, &bufSize)); + if (bufSize < kStep) + break; + if (IsArc_Pe(buf, bufSize)) + { + pePos = posCur; + break; + } + } + + // restore buf to nsis header + bufSize = kStep; + RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream(inStream, buf, &bufSize)); + if (bufSize < kStartHeaderSize) + return S_FALSE; + } + + StartOffset = pos; + UInt32 peSize = 0; + + if (pePos != (UInt64)(Int64)-1) + { + UInt64 peSize64 = (pos - pePos); + if (peSize64 < (1 << 20)) + { + peSize = (UInt32)peSize64; + StartOffset = pePos; + } } - if (position > maxSize) + + DataStreamOffset = pos + kStartHeaderSize; + FirstHeader.Flags = Get32(buf); + if ((FirstHeader.Flags & (~kFlagsMask)) != 0) return S_FALSE; - const UInt32 kStartHeaderSize = 4 * 7; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &_archiveSize)); - RINOK(inStream->Seek(position + kStartHeaderSize, STREAM_SEEK_SET, 0)); - FirstHeader.Flags = Get32(buffer); - FirstHeader.HeaderLength = Get32(buffer + kSignatureSize + 4); - FirstHeader.ArchiveSize = Get32(buffer + kSignatureSize + 8); - if (_archiveSize - position < FirstHeader.ArchiveSize) + IsInstaller = (FirstHeader.Flags & NFlags::kUninstall) == 0; + + FirstHeader.HeaderSize = Get32(buf + kSignatureSize + 4); + FirstHeader.ArcSize = Get32(buf + kSignatureSize + 8); + if (FirstHeader.ArcSize <= kStartHeaderSize) return S_FALSE; + + RINOK(inStream->Seek(0, STREAM_SEEK_END, &_fileSize)); + IsArc = true; + + if (peSize != 0) + { + ExeStub.Alloc(peSize); + RINOK(inStream->Seek(pePos, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, ExeStub, peSize)); + } + + HRESULT res = S_FALSE; try { - _stream = inStream; - HRESULT res = Open2(EXTERNAL_CODECS_LOC_VARS2); - if (res != S_OK) - Clear(); + CLimitedInStream *_limitedStreamSpec = new CLimitedInStream; + _stream = _limitedStreamSpec; + _limitedStreamSpec->SetStream(inStream); + _limitedStreamSpec->InitAndSeek(pos, FirstHeader.ArcSize); + DataStreamOffset -= pos; + res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize); + } + catch(...) + { + _stream.Release(); + throw; + // res = S_FALSE; + } + if (res != S_OK) + { _stream.Release(); - return res; + // Clear(); } - catch(...) { Clear(); return S_FALSE; } + return res; } -void CInArchive::Clear() +UString CInArchive::ConvertToUnicode(const AString &s) const +{ + if (IsUnicode) + { + UString res; + if (ConvertUTF8ToUnicode(s, res)) + return res; + } + return MultiByteToUnicodeString(s); +} + +void CInArchive::Clear2() { + IsUnicode = false; + NsisType = k_NsisType_Nsis2; + IsNsis225 = false; + IsNsis200 = false; + LogCmdIsEnabled = false; + BadCmd = -1; + #ifdef NSIS_SCRIPT + Name.Empty(); + BrandingText.Empty(); Script.Empty(); + LicenseFiles.Clear(); + _numRootLicenses = 0; + langStrIDs.Clear(); + LangComment.Empty(); + noParseStringIndexes.Clear(); #endif + + APrefixes.Clear(); + UPrefixes.Clear(); Items.Clear(); + IsUnicode = false; + ExeStub.Free(); +} + +void CInArchive::Clear() +{ + Clear2(); + IsArc = false; _stream.Release(); } |