// NsisIn.cpp #include "StdAfx.h" #include "../../../../C/CpuArch.h" #include "Common/IntToString.h" #include "../../Common/StreamUtils.h" #include "NsisIn.h" #define Get32(p) GetUi32(p) namespace NArchive { namespace NNsis { Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; #ifdef NSIS_SCRIPT static const char *kCrLf = "\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 Byte CInArchive::ReadByte() { if (_posInData >= _size) throw 1; return _data[_posInData++]; } UInt32 CInArchive::ReadUInt32() { UInt32 value = 0; for (int i = 0; i < 4; i++) value |= ((UInt32)(ReadByte()) << (8 * i)); return value; } void CInArchive::ReadBlockHeader(CBlockHeader &bh) { bh.Offset = ReadUInt32(); bh.Num = ReadUInt32(); } #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } 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)); if (i1.IsUnicode) { RINOZ(i1.PrefixU.Compare(i2.PrefixU)); RINOZ(i1.NameU.Compare(i2.NameU)); } else { RINOZ(i1.PrefixA.Compare(i2.PrefixA)); RINOZ(i1.NameA.Compare(i2.NameA)); } return 0; } static AString UIntToString(UInt32 v) { char sz[32]; ConvertUInt64ToString(v, sz); return sz; } static AString IntToString(Int32 v) { char sz[32]; ConvertInt64ToString(v, sz); return sz; } AString CInArchive::ReadStringA(UInt32 pos) const { AString s; if (pos >= _size) return IntToString((Int32)pos); UInt32 offset = GetOffset() + _stringsPos + pos; for (;;) { if (offset >= _size) break; // throw 1; char c = _data[offset++]; if (c == 0) break; s += c; } return s; } UString CInArchive::ReadStringU(UInt32 pos) const { 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)); if (c == 0) break; s += c; } return s; } /* static AString ParsePrefix(const AString &prefix) { AString res = prefix; if (prefix.Length() >= 3) { 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); } return res; } */ #define SYSREGKEY "Software\\Microsoft\\Windows\\CurrentVersion" /* # 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 */ struct CCommandPair { int NumParams; const char *Name; }; enum { // 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, val1val2, 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, EW_LOCKWINDOW }; #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" } }; #endif static const char *kShellStrings[] = { "", "", "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" }; static const int kNumShellStrings = sizeof(kShellStrings) / sizeof(kShellStrings[0]); /* # 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 */ static const char *kVarStrings[] = { "CMDLINE", "INSTDIR", "OUTDIR", "EXEDIR", "LANGUAGE", "TEMP", "PLUGINSDIR", "EXEPATH", // test it "EXEFILE", // test it "HWNDPARENT", "_CLICK", "_OUTDIR" }; static const int kNumVarStrings = sizeof(kVarStrings) / sizeof(kVarStrings[0]); static AString GetVar(UInt32 index) { AString res = "$"; if (index < 10) res += UIntToString(index); else if (index < 20) { res += "R"; res += UIntToString(index - 10); } else if (index < 20 + kNumVarStrings) res += kVarStrings[index - 20]; else { res += "["; res += UIntToString(index); res += "]"; } return res; } #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 static AString GetShellString(int index) { AString res = "$"; if (index < kNumShellStrings) { const char *sz = kShellStrings[index]; if (sz[0] != 0) return res + sz; } res += "SHELL["; res += UIntToString(index); res += "]"; return res; } // Based on Dave Laundon's simplified process_string AString GetNsisString(const AString &s) { AString res; for (int i = 0; i < s.Length();) { unsigned char nVarIdx = s[i++]; if (nVarIdx > NS_CODES_START && i + 2 <= s.Length()) { int nData = s[i++] & 0x7F; unsigned char c1 = s[i++]; nData |= (((int)(c1 & 0x7F)) << 7); 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"; } else if (nVarIdx == NS_SKIP_CODE) { if (i < s.Length()) res += s[i++]; } else // Normal char res += (char)nVarIdx; } return res; } UString GetNsisString(const UString &s) { UString res; for (int i = 0; i < s.Length();) { wchar_t nVarIdx = s[i++]; if (nVarIdx > NS_UN_CODES_START && nVarIdx <= NS_UN_CODES_END) { if (i == s.Length()) break; int nData = s[i++] & 0x7FFF; 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"; } else if (nVarIdx == NS_UN_SKIP_CODE) { if (i == s.Length()) break; res += s[i++]; } else // Normal char res += (char)nVarIdx; } return res; } AString CInArchive::ReadString2A(UInt32 pos) const { return GetNsisString(ReadStringA(pos)); } UString CInArchive::ReadString2U(UInt32 pos) const { return GetNsisString(ReadStringU(pos)); } AString CInArchive::ReadString2(UInt32 pos) const { if (IsUnicode) return UnicodeStringToMultiByte(ReadString2U(pos)); else return ReadString2A(pos); } AString CInArchive::ReadString2Qw(UInt32 pos) const { return "\"" + ReadString2(pos) + "\""; } #define DEL_DIR 1 #define DEL_RECURSE 2 #define DEL_REBOOT 4 // #define DEL_SIMPLE 8 static const int kNumEntryParams = 6; struct CEntry { UInt32 Which; UInt32 Params[kNumEntryParams]; AString GetParamsString(int numParams); CEntry() { Which = 0; for (UInt32 j = 0; j < kNumEntryParams; j++) Params[j] = 0; } }; AString CEntry::GetParamsString(int numParams) { AString s; for (int i = 0; i < numParams; i++) { s += " "; UInt32 v = Params[i]; if (v > 0xFFF00000) s += IntToString((Int32)Params[i]); else s += UIntToString(Params[i]); } return s; } #ifdef NSIS_SCRIPT 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; } return s; } #endif HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) { _posInData = bh.Offset + GetOffset(); AString prefixA; UString prefixU; for (UInt32 i = 0; i < bh.Num; i++) { CEntry e; e.Which = ReadUInt32(); for (UInt32 j = 0; j < kNumEntryParams; j++) e.Params[j] = ReadUInt32(); #ifdef NSIS_SCRIPT if (e.Which != EW_PUSHPOP && e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0])) { const CCommandPair &pair = kCommandPairs[e.Which]; Script += pair.Name; } #endif switch (e.Which) { case EW_CREATEDIR: { if (IsUnicode) { prefixU.Empty(); prefixU = ReadString2U(e.Params[0]); } else { prefixA.Empty(); prefixA = ReadString2A(e.Params[0]); } #ifdef NSIS_SCRIPT Script += " "; if (IsUnicode) Script += UnicodeStringToMultiByte(prefixU); else Script += prefixA; #endif break; } case EW_EXTRACTFILE: { CItem item; item.IsUnicode = IsUnicode; if (IsUnicode) { item.PrefixU = prefixU; item.NameU = ReadString2U(e.Params[1]); } else { item.PrefixA = prefixA; item.NameA = ReadString2A(e.Params[1]); } /* 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) { /* if (item.Pos == Items.Back().Pos) continue; */ } Items.Add(item); #ifdef NSIS_SCRIPT Script += " "; if (IsUnicode) Script += UnicodeStringToMultiByte(item.NameU); else Script += item.NameA; #endif break; } #ifdef NSIS_SCRIPT case EW_UPDATETEXT: { Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += UIntToString(e.Params[1]); break; } case EW_SETFILEATTRIBUTES: { Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += UIntToString(e.Params[1]); break; } case EW_IFFILEEXISTS: { Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += UIntToString(e.Params[1]); Script += " "; Script += UIntToString(e.Params[2]); break; } case EW_RENAME: { Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += ReadString2(e.Params[1]); Script += " "; Script += UIntToString(e.Params[2]); break; } case EW_GETFULLPATHNAME: { Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += ReadString2(e.Params[1]); Script += " "; Script += UIntToString(e.Params[2]); break; } case EW_SEARCHPATH: { Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += ReadString2(e.Params[1]); break; } case EW_GETTEMPFILENAME: { AString s; Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += ReadString2(e.Params[1]); break; } case EW_DELETEFILE: { UInt64 flag = e.Params[1]; if (flag != 0) { Script += " "; if (flag == DEL_REBOOT) Script += "/REBOOTOK"; else Script += UIntToString(e.Params[1]); } Script += " "; Script += ReadString2(e.Params[0]); break; } case EW_RMDIR: { UInt64 flag = e.Params[1]; if (flag != 0) { if ((flag & DEL_REBOOT) != 0) Script += " /REBOOTOK"; if ((flag & DEL_RECURSE) != 0) Script += " /r"; } Script += " "; Script += ReadString2(e.Params[0]); break; } case EW_STRLEN: { Script += " "; Script += GetVar(e.Params[0]);; Script += " "; Script += ReadString2Qw(e.Params[1]); break; } case EW_ASSIGNVAR: { 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()) { Script += " "; Script += startOffset; } } break; } case EW_STRCMP: { Script += " "; Script += " "; Script += ReadString2Qw(e.Params[0]); Script += " "; Script += ReadString2Qw(e.Params[1]); for (int j = 2; j < 5; j++) { Script += " "; Script += UIntToString(e.Params[j]); } break; } case EW_INTCMP: { if (e.Params[5] != 0) Script += "U"; Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += ReadString2(e.Params[1]); for (int i = 2; i < 5; i++) { Script += " "; Script += UIntToString(e.Params[i]); } break; } case EW_INTOP: { 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; } else { Script += p1; Script += " "; Script += op; Script += " "; Script += ReadString2(e.Params[2]); } break; } case EW_PUSHPOP: { int isPop = (e.Params[1] != 0); if (isPop) { Script += "Pop"; Script += " "; Script += GetVar(e.Params[0]);; } else { int isExch = (e.Params[2] != 0); if (isExch) { Script += "Exch"; } else { Script += "Push"; Script += " "; Script += ReadString2(e.Params[0]); } } break; } case EW_SENDMESSAGE: { // 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]); Script += " "; // if (spec & 2) Script += IntToString(e.Params[4]); // else // Script += ReadString2(e.Params[4]); if ((Int32)e.Params[0] >= 0) { Script += " "; Script += GetVar(e.Params[1]); } spec >>= 2; if (spec != 0) { Script += " /TIMEOUT="; Script += IntToString(spec); } break; } case EW_GETDLGITEM: { Script += " "; Script += GetVar(e.Params[0]);; Script += " "; Script += ReadString2(e.Params[1]); Script += " "; Script += ReadString2(e.Params[2]); break; } case EW_REGISTERDLL: { Script += " "; Script += ReadString2(e.Params[0]); Script += " "; Script += ReadString2(e.Params[1]); Script += " "; Script += UIntToString(e.Params[2]); break; } case EW_CREATESHORTCUT: { AString s; Script += " "; Script += ReadString2Qw(e.Params[0]); Script += " "; Script += ReadString2Qw(e.Params[1]); for (int j = 2; j < 5; j++) { Script += " "; Script += UIntToString(e.Params[j]); } break; } /* case EW_DELREG: { AString keyName, valueName; keyName = ReadString2(e.Params[1]); bool isValue = (e.Params[2] != -1); if (isValue) { valueName = ReadString2(e.Params[2]); Script += "Key"; } else Script += "Value"; Script += " "; Script += UIntToString(e.Params[0]); Script += " "; Script += keyName; if (isValue) { Script += " "; Script += valueName; } Script += " "; Script += UIntToString(e.Params[3]); break; } */ case EW_WRITEREG: { AString s; switch(e.Params[4]) { 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; } Script += s; Script += " "; Script += GetRegRootID(e.Params[0]); Script += " "; AString keyName, valueName; keyName = ReadString2Qw(e.Params[1]); Script += keyName; Script += " "; valueName = ReadString2Qw(e.Params[2]); Script += valueName; Script += " "; valueName = ReadString2Qw(e.Params[3]); Script += valueName; Script += " "; break; } case EW_WRITEUNINSTALLER: { Script += " "; Script += ReadString2(e.Params[0]); for (int j = 1; j < 3; j++) { Script += " "; Script += UIntToString(e.Params[j]); } break; } default: { int numParams = kNumEntryParams; if (e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0])) { const CCommandPair &pair = kCommandPairs[e.Which]; // Script += pair.Name; numParams = pair.NumParams; } else { Script += "Unknown"; Script += UIntToString(e.Which); } Script += e.GetParamsString(numParams); } #endif } #ifdef NSIS_SCRIPT Script += kCrLf; #endif } { Items.Sort(CompareItems, 0); int i; // if (IsSolid) for (i = 0; i + 1 < Items.Size();) { 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); else 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++) { UInt32 nextPos = Items[nextIndex].Pos; if (curPos <= nextPos) { item.EstimatedSizeIsDefined = 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; 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) { item.IsCompressed = true; // is compressed; size &= ~0x80000000; 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)); } } else { item.IsCompressed = false; item.Size = size; item.SizeIsDefined = true; } item.CompressedSize = size; item.CompressedSizeIsDefined = true; } } } return S_OK; } 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); _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 (c >= NS_UN_CODES_START && c < NS_UN_CODES_END) { if (pos >= _size || pos + 1 >= _size) break; pos += 2; numZeros1++; } else { if (c0 == 0 && c1 != 0) numZeros0++; if (c1 == 0) numZeros1++; } // printf("\nnumZeros0 = %2x %2x", _data[pos + 0], _data[pos + 1]); } IsUnicode = (numZeros1 > numZeros0 * 3 + kBlockSize / 16); // printf("\nnumZeros0 = %3d numZeros1 = %3d", numZeros0, numZeros1); return ReadEntries(bhEntries); } 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); } static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag) { if (IsLZMA(p, dictionary)) { thereIsFlag = false; return true; } if (IsLZMA(p + 1, dictionary)) { thereIsFlag = true; return true; } return false; } static bool IsBZip2(const Byte *p) { return (p[0] == 0x31 && p[1] < 14); } HRESULT CInArchive::Open2( DECL_EXTERNAL_CODECS_LOC_VARS2 ) { 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)); _headerIsCompressed = true; IsSolid = true; FilterFlag = false; DictionarySize = 1; UInt32 compressedHeaderSize = Get32(sig); if (compressedHeaderSize == FirstHeader.HeaderLength) { _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)) Method = NMethodType::kBZip2; else Method = NMethodType::kDeflate; } else if (IsBZip2(sig)) { Method = NMethodType::kBZip2; } else { Method = NMethodType::kDeflate; } _posInData = 0; if (!IsSolid) { _headerIsCompressed = ((compressedHeaderSize & 0x80000000) != 0); if (_headerIsCompressed) compressedHeaderSize &= ~0x80000000; _nonSolidStartOffset = compressedHeaderSize; RINOK(_stream->Seek(StreamOffset + 4, STREAM_SEEK_SET, NULL)); } UInt32 unpackSize = FirstHeader.HeaderLength; 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.Read(_data, &processedSize)); if (processedSize != unpackSize) return S_FALSE; _size = processedSize; if (IsSolid) { UInt32 size2 = ReadUInt32(); if (size2 < _size) _size = size2; } } else { _data.SetCapacity(unpackSize); _size = (size_t)unpackSize; RINOK(ReadStream_FALSE(_stream, (Byte *)_data, unpackSize)); } return Parse(); } /* NsisExe = { ExeStub Archive // must start from 512 * N #ifndef NSIS_CONFIG_CRC_ANAL { Some additional data } } Archive { FirstHeader Data #ifdef NSIS_CONFIG_CRC_SUPPORT && FirstHeader.ThereIsCrc() { CRC } } FirstHeader { UInt32 Flags; Byte Signature[16]; // points to the header+sections+entries+stringtable in the datablock UInt32 HeaderLength; UInt32 ArchiveSize; } */ HRESULT CInArchive::Open( DECL_EXTERNAL_CODECS_LOC_VARS 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(ReadStream_FALSE(inStream, buffer, kStep)); if (memcmp(buffer + 4, kSignature, kSignatureSize) == 0) break; } if (position > maxSize) 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) return S_FALSE; try { _stream = inStream; HRESULT res = Open2(EXTERNAL_CODECS_LOC_VARS2); if (res != S_OK) Clear(); _stream.Release(); return res; } catch(...) { Clear(); return S_FALSE; } } void CInArchive::Clear() { #ifdef NSIS_SCRIPT Script.Empty(); #endif Items.Clear(); _stream.Release(); } }}