1 // NsisIn.h 2 3 #ifndef ZIP7_INC_ARCHIVE_NSIS_IN_H 4 #define ZIP7_INC_ARCHIVE_NSIS_IN_H 5 6 #include "../../../../C/CpuArch.h" 7 8 #include "../../../Common/DynLimBuf.h" 9 #include "../../../Common/MyBuffer.h" 10 #include "../../../Common/MyCom.h" 11 #include "../../../Common/StringConvert.h" 12 #include "../../../Common/UTFConvert.h" 13 14 #include "../../Common/StreamUtils.h" 15 16 #include "NsisDecode.h" 17 18 /* If NSIS_SCRIPT is defined, it will decompile NSIS script to [NSIS].nsi file. 19 The code is much larger in that case. */ 20 21 // #define NSIS_SCRIPT 22 23 namespace NArchive { 24 namespace NNsis { 25 26 const size_t kScriptSizeLimit = 1 << 27; 27 28 const unsigned kSignatureSize = 16; 29 extern const Byte kSignature[kSignatureSize]; 30 #define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 'N', 'u', 'l', 'l', 's', 'o', 'f', 't', 'I', 'n', 's', 't' } 31 32 const UInt32 kFlagsMask = 0xF; 33 namespace NFlags 34 { 35 const UInt32 kUninstall = 1; 36 const UInt32 kSilent = 2; 37 const UInt32 kNoCrc = 4; 38 const UInt32 kForceCrc = 8; 39 // NSISBI fork flags: 40 const UInt32 k_BI_LongOffset = 16; 41 const UInt32 k_BI_ExternalFileSupport = 32; 42 const UInt32 k_BI_ExternalFile = 64; 43 const UInt32 k_BI_IsStubInstaller = 128; 44 } 45 46 struct CFirstHeader 47 { 48 UInt32 Flags; 49 UInt32 HeaderSize; 50 UInt32 ArcSize; 51 ThereIsCrcCFirstHeader52 bool ThereIsCrc() const 53 { 54 return 55 (Flags & NFlags::kForceCrc) != 0 || 56 (Flags & NFlags::kNoCrc) == 0; 57 } 58 GetDataSizeCFirstHeader59 UInt32 GetDataSize() const { return ArcSize - (ThereIsCrc() ? 4 : 0); } 60 }; 61 62 63 struct CBlockHeader 64 { 65 UInt32 Offset; 66 UInt32 Num; 67 68 void Parse(const Byte *p, unsigned bhoSize); 69 }; 70 71 struct CItem 72 { 73 bool IsEmptyFile; 74 bool IsCompressed; 75 bool Size_Defined; 76 bool CompressedSize_Defined; 77 bool EstimatedSize_Defined; 78 bool Attrib_Defined; 79 bool IsUninstaller; 80 // bool UseFilter; 81 82 UInt32 Attrib; 83 UInt32 Pos; // = 0, if (IsEmptyFile == true) 84 UInt32 Size; 85 UInt32 CompressedSize; 86 UInt32 EstimatedSize; 87 UInt32 DictionarySize; 88 UInt32 PatchSize; // for Uninstaller.exe 89 int Prefix; // - 1 means no prefix 90 91 FILETIME MTime; 92 AString NameA; 93 UString NameU; 94 Is_PatchedUninstallerCItem95 bool Is_PatchedUninstaller() const { return PatchSize != 0; } 96 CItemCItem97 CItem(): 98 IsEmptyFile(false), 99 IsCompressed(true), 100 Size_Defined(false), 101 CompressedSize_Defined(false), 102 EstimatedSize_Defined(false), 103 Attrib_Defined(false), 104 IsUninstaller(false), 105 // UseFilter(false), 106 Attrib(0), 107 Pos(0), 108 Size(0), 109 CompressedSize(0), 110 EstimatedSize(0), 111 DictionarySize(1), 112 PatchSize(0), 113 Prefix(-1) 114 { 115 MTime.dwLowDateTime = 0; 116 MTime.dwHighDateTime = 0; 117 } 118 119 /* 120 bool IsINSTDIR() const 121 { 122 return (PrefixA.Len() >= 3 || PrefixU.Len() >= 3); 123 } 124 */ 125 }; 126 127 enum ENsisType 128 { 129 k_NsisType_Nsis2, 130 k_NsisType_Nsis3, 131 k_NsisType_Park1, // Park 2.46.1- 132 k_NsisType_Park2, // Park 2.46.2 : GetFontVersion 133 k_NsisType_Park3 // Park 2.46.3+ : GetFontName 134 }; 135 136 #ifdef NSIS_SCRIPT 137 138 struct CSection 139 { 140 UInt32 InstallTypes; // bits set for each of the different install_types, if any. 141 UInt32 Flags; // SF_* - defined above 142 UInt32 StartCmdIndex; // code; 143 UInt32 NumCommands; // code_size; 144 UInt32 SizeKB; 145 UInt32 Name; 146 147 void Parse(const Byte *data); 148 }; 149 150 struct CLicenseFile 151 { 152 UInt32 Offset; 153 UInt32 Size; 154 AString Name; 155 CByteBuffer Text; 156 }; 157 158 #endif 159 160 class CInArchive 161 { 162 public: 163 #ifdef NSIS_SCRIPT 164 CDynLimBuf Script; 165 #endif 166 CByteBuffer _data; 167 CObjectVector<CItem> Items; 168 bool IsUnicode; 169 bool Is64Bit; 170 private: 171 UInt32 _stringsPos; // relative to _data 172 UInt32 NumStringChars; 173 size_t _size; // it's Header Size 174 175 AString Raw_AString; 176 UString Raw_UString; 177 178 ENsisType NsisType; 179 bool IsNsis200; // NSIS 2.03 and before 180 bool IsNsis225; // NSIS 2.25 and before 181 bool LogCmdIsEnabled; 182 int BadCmd; // -1: no bad command; in another cases lowest bad command id 183 IsPark()184 bool IsPark() const { return NsisType >= k_NsisType_Park1; } IsNsis3_OrHigher()185 bool IsNsis3_OrHigher() const { return NsisType == k_NsisType_Nsis3; } 186 187 UInt64 _fileSize; 188 189 bool _headerIsCompressed; 190 UInt32 _nonSolidStartOffset; 191 192 #ifdef NSIS_SCRIPT 193 194 CByteBuffer strUsed; 195 196 CBlockHeader bhPages; 197 CBlockHeader bhSections; 198 CBlockHeader bhCtlColors; 199 CBlockHeader bhData; 200 UInt32 AfterHeaderSize; 201 CByteBuffer _afterHeader; 202 203 UInt32 SectionSize; 204 const Byte *_mainLang; 205 UInt32 _numLangStrings; 206 AString LangComment; 207 CRecordVector<UInt32> langStrIDs; 208 UInt32 numOnFunc; 209 UInt32 onFuncOffset; 210 // CRecordVector<UInt32> OnFuncs; 211 unsigned _numRootLicenses; 212 CRecordVector<UInt32> noParseStringIndexes; 213 AString _tempString_for_GetVar; 214 AString _tempString_for_AddFuncName; 215 AString _tempString; 216 217 #endif 218 219 220 public: 221 CMyComPtr<IInStream> _stream; // it's limited stream that contains only NSIS archive 222 UInt64 StartOffset; // offset in original stream. 223 UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream 224 225 bool IsArc; 226 227 CDecoder Decoder; 228 CByteBuffer ExeStub; 229 CFirstHeader FirstHeader; 230 NMethodType::EEnum Method; 231 UInt32 DictionarySize; 232 bool IsSolid; 233 bool UseFilter; 234 bool FilterFlag; 235 236 bool IsInstaller; 237 AString Name; 238 AString BrandingText; 239 UStringVector UPrefixes; 240 AStringVector APrefixes; 241 242 #ifdef NSIS_SCRIPT 243 CObjectVector<CLicenseFile> LicenseFiles; 244 #endif 245 246 private: 247 void GetShellString(AString &s, unsigned index1, unsigned index2); 248 void GetNsisString_Raw(const Byte *s); 249 void GetNsisString_Unicode_Raw(const Byte *s); 250 void ReadString2_Raw(UInt32 pos); 251 bool IsGoodString(UInt32 param) const; 252 bool AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const; 253 254 void Add_LangStr(AString &res, UInt32 id); 255 256 #ifdef NSIS_SCRIPT 257 258 void Add_UInt(UInt32 v); 259 void AddLicense(UInt32 param, Int32 langID); 260 261 void Add_LangStr_Simple(UInt32 id); 262 void Add_FuncName(const UInt32 *labels, UInt32 index); 263 void AddParam_Func(const UInt32 *labels, UInt32 index); 264 void Add_LabelName(UInt32 index); 265 266 void Add_Color2(UInt32 v); 267 void Add_ColorParam(UInt32 v); 268 void Add_Color(UInt32 index); 269 270 void Add_ButtonID(UInt32 buttonID); 271 272 void Add_ShowWindow_Cmd(UInt32 cmd); 273 void Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type); 274 void Add_ExecFlags(UInt32 flagsType); 275 void Add_SectOp(UInt32 opType); 276 277 void Add_Var(UInt32 index); 278 void AddParam_Var(UInt32 value); 279 void AddParam_UInt(UInt32 value); 280 281 void Add_GotoVar(UInt32 param); 282 void Add_GotoVar1(UInt32 param); 283 void Add_GotoVars2(const UInt32 *params); 284 285 286 287 bool PrintSectionBegin(const CSection §, unsigned index); 288 void PrintSectionEnd(); 289 290 void GetNsisString(AString &res, const Byte *s); 291 void GetNsisString_Unicode(AString &res, const Byte *s); 292 UInt32 GetNumUsedVars() const; 293 void ReadString2(AString &s, UInt32 pos); 294 295 void MessageBox_MB_Part(UInt32 param); 296 void AddParam(UInt32 pos); 297 void AddOptionalParam(UInt32 pos); 298 void AddParams(const UInt32 *params, unsigned num); 299 void AddPageOption1(UInt32 param, const char *name); 300 void AddPageOption(const UInt32 *params, unsigned num, const char *name); 301 void AddOptionalParams(const UInt32 *params, unsigned num); 302 void AddRegRoot(UInt32 value); 303 304 305 void ClearLangComment(); 306 void Separator(); 307 void Space(); 308 void Tab(); 309 void Tab(bool commented); 310 void BigSpaceComment(); 311 void SmallSpaceComment(); 312 void AddCommentAndString(const char *s); 313 void AddError(const char *s); 314 void AddErrorLF(const char *s); 315 void CommentOpen(); 316 void CommentClose(); 317 void AddLF(); 318 void AddQuotes(); 319 void TabString(const char *s); 320 void AddStringLF(const char *s); 321 void NewLine(); 322 void PrintNumComment(const char *name, UInt32 value); 323 void Add_QuStr(const AString &s); 324 void SpaceQuStr(const AString &s); 325 bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands); 326 327 #endif 328 329 #ifdef NSIS_SCRIPT 330 unsigned GetNumSupportedCommands() const; 331 #endif 332 333 UInt32 GetCmd(UInt32 a); 334 void FindBadCmd(const CBlockHeader &bh, const Byte *); 335 void DetectNsisType(const CBlockHeader &bh, const Byte *); 336 337 HRESULT ReadEntries(const CBlockHeader &bh); 338 HRESULT SortItems(); 339 HRESULT Parse(); 340 HRESULT Open2(const Byte *data, size_t size); 341 void Clear2(); 342 343 void GetVar2(AString &res, UInt32 index); 344 void GetVar(AString &res, UInt32 index); 345 Int32 GetVarIndex(UInt32 strPos) const; 346 Int32 GetVarIndex(UInt32 strPos, UInt32 &resOffset) const; 347 Int32 GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const; 348 bool IsVarStr(UInt32 strPos, UInt32 varIndex) const; 349 bool IsAbsolutePathVar(UInt32 strPos) const; 350 void SetItemName(CItem &item, UInt32 strPos); 351 352 public: 353 HRESULT Open(IInStream *inStream, const UInt64 *maxCheckStartPosition); 354 AString GetFormatDescription() const; InitDecoder()355 HRESULT InitDecoder() 356 { 357 bool useFilter; 358 return Decoder.Init(_stream, useFilter); 359 } 360 SeekTo(UInt64 pos)361 HRESULT SeekTo(UInt64 pos) 362 { 363 return InStream_SeekSet(_stream, pos); 364 } 365 SeekTo_DataStreamOffset()366 HRESULT SeekTo_DataStreamOffset() 367 { 368 return SeekTo(DataStreamOffset); 369 } 370 SeekToNonSolidItem(unsigned index)371 HRESULT SeekToNonSolidItem(unsigned index) 372 { 373 return SeekTo(GetPosOfNonSolidItem(index)); 374 } 375 376 void Clear(); 377 378 bool IsDirectString_Equal(UInt32 offset, const char *s) const; 379 /* 380 UInt64 GetDataPos(unsigned index) 381 { 382 const CItem &item = Items[index]; 383 return GetOffset() + FirstHeader.HeaderSize + item.Pos; 384 } 385 */ 386 GetPosOfSolidItem(unsigned index)387 UInt64 GetPosOfSolidItem(unsigned index) const 388 { 389 const CItem &item = Items[index]; 390 return 4 + (UInt64)FirstHeader.HeaderSize + item.Pos; 391 } 392 GetPosOfNonSolidItem(unsigned index)393 UInt64 GetPosOfNonSolidItem(unsigned index) const 394 { 395 const CItem &item = Items[index]; 396 return DataStreamOffset + _nonSolidStartOffset + 4 + item.Pos; 397 } 398 Release()399 void Release() 400 { 401 Decoder.Release(); 402 } 403 IsTruncated()404 bool IsTruncated() const { return (_fileSize - StartOffset < FirstHeader.ArcSize); } 405 GetReducedName(unsigned index)406 UString GetReducedName(unsigned index) const 407 { 408 const CItem &item = Items[index]; 409 410 UString s; 411 if (item.Prefix >= 0) 412 { 413 if (IsUnicode) 414 s = UPrefixes[item.Prefix]; 415 else 416 s = MultiByteToUnicodeString(APrefixes[item.Prefix]); 417 if (s.Len() > 0) 418 if (s.Back() != L'\\') 419 s.Add_Char('\\'); 420 } 421 422 if (IsUnicode) 423 { 424 s += item.NameU; 425 if (item.NameU.IsEmpty()) 426 s += "file"; 427 } 428 else 429 { 430 s += MultiByteToUnicodeString(item.NameA); 431 if (item.NameA.IsEmpty()) 432 s += "file"; 433 } 434 435 const char * const kRemoveStr = "$INSTDIR\\"; 436 if (s.IsPrefixedBy_Ascii_NoCase(kRemoveStr)) 437 { 438 s.Delete(0, MyStringLen(kRemoveStr)); 439 if (s[0] == L'\\') 440 s.DeleteFrontal(1); 441 } 442 if (item.Is_PatchedUninstaller() && ExeStub.Size() == 0) 443 s += ".nsis"; 444 return s; 445 } 446 447 UString ConvertToUnicode(const AString &s) const; 448 CInArchive()449 CInArchive() 450 #ifdef NSIS_SCRIPT 451 : Script(kScriptSizeLimit) 452 #endif 453 {} 454 }; 455 456 }} 457 458 #endif 459