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