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