1 // NsisIn.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/StringToInt.h"
7
8 #include "../../Common/LimitedStreams.h"
9 #include "../../Common/StreamUtils.h"
10
11 #include "NsisIn.h"
12
13 #define Get16(p) GetUi16(p)
14 #define Get32(p) GetUi32(p)
15
16 // #define NUM_SPEED_TESTS 1000
17
18 namespace NArchive {
19 namespace NNsis {
20
21 static const size_t kInputBufSize = 1 << 20;
22
23 const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE;
24 static const UInt32 kMask_IsCompressed = (UInt32)1 << 31;
25
26 static const unsigned kNumCommandParams = 6;
27 static const unsigned kCmdSize = 4 + kNumCommandParams * 4;
28
29 #ifdef NSIS_SCRIPT
30 #define CR_LF "\x0D\x0A"
31 #endif
32
33 static const char * const kErrorStr = "$_ERROR_STR_";
34
35 #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
36
37
38 /* There are several versions of NSIS:
39 1) Original NSIS:
40 NSIS-2 ANSI
41 NSIS-3 ANSI
42 NSIS-3 Unicode
43 2) NSIS from Jim Park that extends old NSIS-2 to Unicode support:
44 NSIS-Park-(1,2,3) ANSI
45 NSIS-Park-(1,2,3) Unicode
46
47 The command IDs layout is slightly different for different versions.
48 Also there are additional "log" versions of NSIS that support EW_LOG.
49 We use the layout of "NSIS-3 Unicode" without "log" as main layout.
50 And we transfer the command IDs to main layout, if another layout is detected. */
51
52
53 enum
54 {
55 EW_INVALID_OPCODE,
56 EW_RET, // Return
57 EW_NOP, // Nop, Goto
58 EW_ABORT, // Abort
59 EW_QUIT, // Quit
60 EW_CALL, // Call, InitPluginsDir
61 EW_UPDATETEXT, // DetailPrint
62 EW_SLEEP, // Sleep
63 EW_BRINGTOFRONT, // BringToFront
64 EW_CHDETAILSVIEW, // SetDetailsView
65 EW_SETFILEATTRIBUTES, // SetFileAttributes
66 EW_CREATEDIR, // CreateDirectory, SetOutPath
67 EW_IFFILEEXISTS, // IfFileExists
68 EW_SETFLAG, // SetRebootFlag, ...
69 EW_IFFLAG, // IfAbort, IfSilent, IfErrors, IfRebootFlag
70 EW_GETFLAG, // GetInstDirError, GetErrorLevel
71 EW_RENAME, // Rename
72 EW_GETFULLPATHNAME, // GetFullPathName
73 EW_SEARCHPATH, // SearchPath
74 EW_GETTEMPFILENAME, // GetTempFileName
75 EW_EXTRACTFILE, // File
76 EW_DELETEFILE, // Delete
77 EW_MESSAGEBOX, // MessageBox
78 EW_RMDIR, // RMDir
79 EW_STRLEN, // StrLen
80 EW_ASSIGNVAR, // StrCpy
81 EW_STRCMP, // StrCmp
82 EW_READENVSTR, // ReadEnvStr, ExpandEnvStrings
83 EW_INTCMP, // IntCmp, IntCmpU
84 EW_INTOP, // IntOp
85 EW_INTFMT, // IntFmt/Int64Fmt
86 EW_PUSHPOP, // Push/Pop/Exchange
87 EW_FINDWINDOW, // FindWindow
88 EW_SENDMESSAGE, // SendMessage
89 EW_ISWINDOW, // IsWindow
90 EW_GETDLGITEM, // GetDlgItem
91 EW_SETCTLCOLORS, // SetCtlColors
92 EW_SETBRANDINGIMAGE, // SetBrandingImage / LoadAndSetImage
93 EW_CREATEFONT, // CreateFont
94 EW_SHOWWINDOW, // ShowWindow, EnableWindow, HideWindow
95 EW_SHELLEXEC, // ExecShell
96 EW_EXECUTE, // Exec, ExecWait
97 EW_GETFILETIME, // GetFileTime
98 EW_GETDLLVERSION, // GetDLLVersion
99
100 // EW_GETFONTVERSION, // Park : 2.46.2
101 // EW_GETFONTNAME, // Park : 2.46.3
102
103 EW_REGISTERDLL, // RegDLL, UnRegDLL, CallInstDLL
104 EW_CREATESHORTCUT, // CreateShortCut
105 EW_COPYFILES, // CopyFiles
106 EW_REBOOT, // Reboot
107 EW_WRITEINI, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI
108 EW_READINISTR, // ReadINIStr
109 EW_DELREG, // DeleteRegValue, DeleteRegKey
110 EW_WRITEREG, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD
111 EW_READREGSTR, // ReadRegStr, ReadRegDWORD
112 EW_REGENUM, // EnumRegKey, EnumRegValue
113 EW_FCLOSE, // FileClose
114 EW_FOPEN, // FileOpen
115 EW_FPUTS, // FileWrite, FileWriteByte
116 EW_FGETS, // FileRead, FileReadByte
117
118 // Park
119 // EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord
120 // EW_FGETWS, // FileReadUTF16LE, FileReadWord
121
122 EW_FSEEK, // FileSeek
123 EW_FINDCLOSE, // FindClose
124 EW_FINDNEXT, // FindNext
125 EW_FINDFIRST, // FindFirst
126 EW_WRITEUNINSTALLER, // WriteUninstaller
127
128 // Park : since 2.46.3 the log is enabled in main Park version
129 // EW_LOG, // LogSet, LogText
130
131 EW_SECTIONSET, // Get*, Set*
132 EW_INSTTYPESET, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType
133
134 /*
135 // before v3.06 nsis it was so:
136 // instructions not actually implemented in exehead, but used in compiler.
137 EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR
138 EW_GETFUNCTIONADDR,
139 */
140
141 // v3.06 and later it was changed to:
142 EW_GETOSINFO,
143 EW_RESERVEDOPCODE,
144
145 EW_LOCKWINDOW, // LockWindow
146
147 // 2 unicode commands available only in Unicode archive
148 EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord
149 EW_FGETWS, // FileReadUTF16LE, FileReadWord
150
151 /*
152 // since v3.06 the fllowing IDs codes was moved here:
153 // Opcodes listed here are not actually used in exehead. No exehead opcodes should be present after these!
154 EW_GETLABELADDR, // --> EW_ASSIGNVAR
155 EW_GETFUNCTIONADDR, // --> EW_ASSIGNVAR
156 */
157
158 // The following IDs are not IDs in real order.
159 // We just need some IDs to translate eny extended layout to main layout.
160
161 EW_LOG, // LogSet, LogText
162
163 // Park
164 EW_FINDPROC, // FindProc
165
166 EW_GETFONTVERSION, // GetFontVersion
167 EW_GETFONTNAME, // GetFontName
168
169 kNumCmds
170 };
171
172
173
174 struct CCommandInfo
175 {
176 Byte NumParams;
177 };
178
179 static const CCommandInfo k_Commands[kNumCmds] =
180 {
181 { 0 }, // "Invalid" },
182 { 0 }, // Return
183 { 1 }, // Nop, Goto
184 { 1 }, // "Abort" },
185 { 0 }, // "Quit" },
186 { 2 }, // Call
187 { 6 }, // "DetailPrint" }, // 1 param in new versions, 6 in old NSIS versions
188 { 1 }, // "Sleep" },
189 { 0 }, // "BringToFront" },
190 { 2 }, // "SetDetailsView" },
191 { 2 }, // "SetFileAttributes" },
192 { 3 }, // CreateDirectory, SetOutPath
193 { 3 }, // "IfFileExists" },
194 { 3 }, // SetRebootFlag, ...
195 { 4 }, // "If" }, // IfAbort, IfSilent, IfErrors, IfRebootFlag
196 { 2 }, // "Get" }, // GetInstDirError, GetErrorLevel
197 { 4 }, // "Rename" },
198 { 3 }, // "GetFullPathName" },
199 { 2 }, // "SearchPath" },
200 { 2 }, // "GetTempFileName" },
201 { 6 }, // "File"
202 { 2 }, // "Delete" },
203 { 6 }, // "MessageBox" },
204 { 2 }, // "RMDir" },
205 { 2 }, // "StrLen" },
206 { 4 }, // StrCpy, GetCurrentAddress
207 { 5 }, // "StrCmp" },
208 { 3 }, // ReadEnvStr, ExpandEnvStrings
209 { 6 }, // "IntCmp" },
210 { 4 }, // "IntOp" },
211 { 4 }, // "IntFmt" }, EW_INTFMT
212 { 6 }, // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage.
213 { 5 }, // "FindWindow" },
214 { 6 }, // "SendMessage" },
215 { 3 }, // "IsWindow" },
216 { 3 }, // "GetDlgItem" },
217 { 2 }, // "SetCtlColors" },
218 { 4 }, // "SetBrandingImage" } // LoadAndSetImage
219 { 5 }, // "CreateFont" },
220 { 4 }, // ShowWindow, EnableWindow, HideWindow
221 { 6 }, // "ExecShell" },
222 { 3 }, // "Exec" }, // Exec, ExecWait
223 { 3 }, // "GetFileTime" },
224 { 4 }, // "GetDLLVersion" },
225 { 6 }, // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage.
226 { 6 }, // "CreateShortCut" },
227 { 4 }, // "CopyFiles" },
228 { 1 }, // "Reboot" },
229 { 5 }, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI
230 { 4 }, // "ReadINIStr" },
231 { 5 }, // "DeleteReg" }, // DeleteRegKey, DeleteRegValue
232 { 6 }, // "WriteReg" }, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD
233 { 5 }, // "ReadReg" }, // ReadRegStr, ReadRegDWORD
234 { 5 }, // "EnumReg" }, // EnumRegKey, EnumRegValue
235 { 1 }, // "FileClose" },
236 { 4 }, // "FileOpen" },
237 { 3 }, // "FileWrite" }, // FileWrite, FileWriteByte
238 { 4 }, // "FileRead" }, // FileRead, FileReadByte
239 { 4 }, // "FileSeek" },
240 { 1 }, // "FindClose" },
241 { 2 }, // "FindNext" },
242 { 3 }, // "FindFirst" },
243 { 4 }, // "WriteUninstaller" },
244 { 5 }, // "Section" }, // ***
245 { 4 }, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType
246
247 // { 6 }, // "GetLabelAddr" }, // before 3.06
248 { 6 }, // "GetOsInfo" }, GetKnownFolderPath, ReadMemory, // v3.06+
249
250 { 2 }, // "GetFunctionAddress" }, // before 3.06
251
252 { 1 }, // "LockWindow" },
253 { 4 }, // "FileWrite" }, // FileWriteUTF16LE, FileWriteWord
254 { 4 }, // "FileRead" }, // FileReadUTF16LE, FileReadWord
255
256 { 2 }, // "Log" }, // LogSet, LogText
257 // Park
258 { 2 }, // "FindProc" },
259 { 2 }, // "GetFontVersion" },
260 { 2 }, // "GetFontName" }
261 };
262
263 #ifdef NSIS_SCRIPT
264
265 static const char * const k_CommandNames[kNumCmds] =
266 {
267 "Invalid"
268 , NULL // Return
269 , NULL // Nop, Goto
270 , "Abort"
271 , "Quit"
272 , NULL // Call
273 , "DetailPrint" // 1 param in new versions, 6 in old NSIS versions
274 , "Sleep"
275 , "BringToFront"
276 , "SetDetailsView"
277 , "SetFileAttributes"
278 , NULL // CreateDirectory, SetOutPath
279 , "IfFileExists"
280 , NULL // SetRebootFlag, ...
281 , "If" // IfAbort, IfSilent, IfErrors, IfRebootFlag
282 , "Get" // GetInstDirError, GetErrorLevel
283 , "Rename"
284 , "GetFullPathName"
285 , "SearchPath"
286 , "GetTempFileName"
287 , NULL // File
288 , "Delete"
289 , "MessageBox"
290 , "RMDir"
291 , "StrLen"
292 , NULL // StrCpy, GetCurrentAddress
293 , "StrCmp"
294 , NULL // ReadEnvStr, ExpandEnvStrings
295 , NULL // IntCmp / Int64Cmp / EW_INTCMP
296 , "IntOp"
297 , NULL // IntFmt / Int64Fmt / EW_INTFMT
298 , NULL // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage.
299 , "FindWindow"
300 , "SendMessage"
301 , "IsWindow"
302 , "GetDlgItem"
303 , "SetCtlColors"
304 , "SetBrandingImage"
305 , "CreateFont"
306 , NULL // ShowWindow, EnableWindow, HideWindow
307 , "ExecShell"
308 , "Exec" // Exec, ExecWait
309 , "GetFileTime"
310 , "GetDLLVersion"
311 , NULL // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage.
312 , "CreateShortCut"
313 , "CopyFiles"
314 , "Reboot"
315 , NULL // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI
316 , "ReadINIStr"
317 , "DeleteReg" // DeleteRegKey, DeleteRegValue
318 , "WriteReg" // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD
319 , "ReadReg" // ReadRegStr, ReadRegDWORD
320 , "EnumReg" // EnumRegKey, EnumRegValue
321 , "FileClose"
322 , "FileOpen"
323 , "FileWrite" // FileWrite, FileWriteByte
324 , "FileRead" // FileRead, FileReadByte
325 , "FileSeek"
326 , "FindClose"
327 , "FindNext"
328 , "FindFirst"
329 , "WriteUninstaller"
330 , "Section" // ***
331 , NULL // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType
332
333 , NULL // "GetOsInfo" // , "GetLabelAddr" //
334 , "GetFunctionAddress"
335
336 , "LockWindow"
337 , "FileWrite" // FileWriteUTF16LE, FileWriteWord
338 , "FileRead" // FileReadUTF16LE, FileReadWord
339
340 , "Log" // LogSet, LogText
341
342 // Park
343 , "FindProc"
344 , "GetFontVersion"
345 , "GetFontName"
346 };
347
348 #endif
349
350 /* NSIS can use one name for two CSIDL_*** and CSIDL_COMMON_*** items (CurrentUser / AllUsers)
351 Some NSIS shell names are not identical to WIN32 CSIDL_* names.
352 NSIS doesn't use some CSIDL_* values. But we add name for all CSIDL_ (marked with '+'). */
353
354 static const char * const kShellStrings[] =
355 {
356 "DESKTOP" // +
357 , "INTERNET" // +
358 , "SMPROGRAMS" // CSIDL_PROGRAMS
359 , "CONTROLS" // +
360 , "PRINTERS" // +
361 , "DOCUMENTS" // CSIDL_PERSONAL
362 , "FAVORITES" // CSIDL_FAVORITES
363 , "SMSTARTUP" // CSIDL_STARTUP
364 , "RECENT" // CSIDL_RECENT
365 , "SENDTO" // CSIDL_SENDTO
366 , "BITBUCKET" // +
367 , "STARTMENU"
368 , NULL // CSIDL_MYDOCUMENTS = CSIDL_PERSONAL
369 , "MUSIC" // CSIDL_MYMUSIC
370 , "VIDEOS" // CSIDL_MYVIDEO
371 , NULL
372 , "DESKTOP" // CSIDL_DESKTOPDIRECTORY
373 , "DRIVES" // +
374 , "NETWORK" // +
375 , "NETHOOD"
376 , "FONTS"
377 , "TEMPLATES"
378 , "STARTMENU" // CSIDL_COMMON_STARTMENU
379 , "SMPROGRAMS" // CSIDL_COMMON_PROGRAMS
380 , "SMSTARTUP" // CSIDL_COMMON_STARTUP
381 , "DESKTOP" // CSIDL_COMMON_DESKTOPDIRECTORY
382 , "APPDATA" // CSIDL_APPDATA !!! "QUICKLAUNCH"
383 , "PRINTHOOD"
384 , "LOCALAPPDATA"
385 , "ALTSTARTUP"
386 , "ALTSTARTUP" // CSIDL_COMMON_ALTSTARTUP
387 , "FAVORITES" // CSIDL_COMMON_FAVORITES
388 , "INTERNET_CACHE"
389 , "COOKIES"
390 , "HISTORY"
391 , "APPDATA" // CSIDL_COMMON_APPDATA
392 , "WINDIR"
393 , "SYSDIR"
394 , "PROGRAM_FILES" // +
395 , "PICTURES" // CSIDL_MYPICTURES
396 , "PROFILE"
397 , "SYSTEMX86" // +
398 , "PROGRAM_FILESX86" // +
399 , "PROGRAM_FILES_COMMON" // +
400 , "PROGRAM_FILES_COMMONX8" // + CSIDL_PROGRAM_FILES_COMMONX86
401 , "TEMPLATES" // CSIDL_COMMON_TEMPLATES
402 , "DOCUMENTS" // CSIDL_COMMON_DOCUMENTS
403 , "ADMINTOOLS" // CSIDL_COMMON_ADMINTOOLS
404 , "ADMINTOOLS" // CSIDL_ADMINTOOLS
405 , "CONNECTIONS" // +
406 , NULL
407 , NULL
408 , NULL
409 , "MUSIC" // CSIDL_COMMON_MUSIC
410 , "PICTURES" // CSIDL_COMMON_PICTURES
411 , "VIDEOS" // CSIDL_COMMON_VIDEO
412 , "RESOURCES"
413 , "RESOURCES_LOCALIZED"
414 , "COMMON_OEM_LINKS" // +
415 , "CDBURN_AREA"
416 , NULL // unused
417 , "COMPUTERSNEARME" // +
418 };
419
420
UIntToString(AString & s,UInt32 v)421 static inline void UIntToString(AString &s, UInt32 v)
422 {
423 s.Add_UInt32(v);
424 }
425
426 #ifdef NSIS_SCRIPT
427
Add_UInt(UInt32 v)428 void CInArchive::Add_UInt(UInt32 v)
429 {
430 char sz[16];
431 ConvertUInt32ToString(v, sz);
432 Script += sz;
433 }
434
Add_SignedInt(CDynLimBuf & s,Int32 v)435 static void Add_SignedInt(CDynLimBuf &s, Int32 v)
436 {
437 char sz[32];
438 ConvertInt64ToString(v, sz);
439 s += sz;
440 }
441
Add_Hex(CDynLimBuf & s,UInt32 v)442 static void Add_Hex(CDynLimBuf &s, UInt32 v)
443 {
444 char sz[16];
445 sz[0] = '0';
446 sz[1] = 'x';
447 ConvertUInt32ToHex(v, sz + 2);
448 s += sz;
449 }
450
GetUi16Str_Len(const Byte * p)451 static UInt32 GetUi16Str_Len(const Byte *p)
452 {
453 const Byte *pp = p;
454 for (; *pp != 0 || *(pp + 1) != 0; pp += 2);
455 return (UInt32)((pp - p) >> 1);
456 }
457
AddLicense(UInt32 param,Int32 langID)458 void CInArchive::AddLicense(UInt32 param, Int32 langID)
459 {
460 Space();
461 if (param >= NumStringChars ||
462 param + 1 >= NumStringChars)
463 {
464 Script += kErrorStr;
465 return;
466 }
467 strUsed[param] = 1;
468
469 UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param);
470 UInt32 offset = start + (IsUnicode ? 2 : 1);
471 {
472 FOR_VECTOR (i, LicenseFiles)
473 {
474 const CLicenseFile &lic = LicenseFiles[i];
475 if (offset == lic.Offset)
476 {
477 Script += lic.Name;
478 return;
479 }
480 }
481 }
482 AString fileName ("[LICENSE]");
483 if (langID >= 0)
484 {
485 fileName += "\\license-";
486 // LangId_To_String(fileName, langID);
487 UIntToString(fileName, langID);
488 }
489 else if (++_numRootLicenses > 1)
490 {
491 fileName += '-';
492 UIntToString(fileName, _numRootLicenses);
493 }
494 const Byte *sz = (_data + start);
495 unsigned marker = IsUnicode ? Get16(sz) : *sz;
496 bool isRTF = (marker == 2);
497 fileName += isRTF ? ".rtf" : ".txt"; // if (*sz == 1) it's text;
498 Script += fileName;
499
500 CLicenseFile &lic = LicenseFiles.AddNew();
501 lic.Name = fileName;
502 lic.Offset = offset;
503 if (!IsUnicode)
504 lic.Size = (UInt32)strlen((const char *)sz + 1);
505 else
506 {
507 sz += 2;
508 UInt32 len = GetUi16Str_Len(sz);
509 lic.Size = len * 2;
510 if (isRTF)
511 {
512 lic.Text.Alloc((size_t)len);
513 for (UInt32 i = 0; i < len; i++, sz += 2)
514 {
515 unsigned c = Get16(sz);
516 if (c >= 256)
517 c = '?';
518 lic.Text[i] = (Byte)(c);
519 }
520 lic.Size = len;
521 lic.Offset = 0;
522 }
523 }
524 }
525
526 #endif
527
528
529 // #define kVar_CMDLINE 20
530 #define kVar_INSTDIR 21
531 #define kVar_OUTDIR 22
532 #define kVar_EXEDIR 23
533 // #define kVar_LANGUAGE 24
534 #define kVar_TEMP 25
535 #define kVar_PLUGINSDIR 26
536 #define kVar_EXEPATH 27 // NSIS 2.26+
537 // #define kVar_EXEFILE 28 // NSIS 2.26+
538
539 #define kVar_HWNDPARENT_225 27
540 #ifdef NSIS_SCRIPT
541 #define kVar_HWNDPARENT 29
542 #endif
543
544 // #define kVar__CLICK 30
545 #define kVar_Spec_OUTDIR_225 29 // NSIS 2.04 - 2.25
546 #define kVar_Spec_OUTDIR 31 // NSIS 2.26+
547
548
549 static const char * const kVarStrings[] =
550 {
551 "CMDLINE"
552 , "INSTDIR"
553 , "OUTDIR"
554 , "EXEDIR"
555 , "LANGUAGE"
556 , "TEMP"
557 , "PLUGINSDIR"
558 , "EXEPATH" // NSIS 2.26+
559 , "EXEFILE" // NSIS 2.26+
560 , "HWNDPARENT"
561 , "_CLICK" // is set from page->clicknext
562 , "_OUTDIR" // NSIS 2.04+
563 };
564
565 static const unsigned kNumInternalVars = 20 + ARRAY_SIZE(kVarStrings);
566
567 #define GET_NUM_INTERNAL_VARS (IsNsis200 ? kNumInternalVars - 3 : IsNsis225 ? kNumInternalVars - 2 : kNumInternalVars);
568
GetVar2(AString & res,UInt32 index)569 void CInArchive::GetVar2(AString &res, UInt32 index)
570 {
571 if (index < 20)
572 {
573 if (index >= 10)
574 {
575 res += 'R';
576 index -= 10;
577 }
578 UIntToString(res, index);
579 }
580 else
581 {
582 unsigned numInternalVars = GET_NUM_INTERNAL_VARS;
583 if (index < numInternalVars)
584 {
585 if (IsNsis225 && index >= kVar_EXEPATH)
586 index += 2;
587 res += kVarStrings[index - 20];
588 }
589 else
590 {
591 res += '_';
592 UIntToString(res, index - numInternalVars);
593 res += '_';
594 }
595 }
596 }
597
GetVar(AString & res,UInt32 index)598 void CInArchive::GetVar(AString &res, UInt32 index)
599 {
600 res += '$';
601 GetVar2(res, index);
602 }
603
604 #ifdef NSIS_SCRIPT
605
Add_Var(UInt32 index)606 void CInArchive::Add_Var(UInt32 index)
607 {
608 _tempString_for_GetVar.Empty();
609 GetVar(_tempString_for_GetVar, index);
610 Script += _tempString_for_GetVar;
611 }
612
AddParam_Var(UInt32 index)613 void CInArchive::AddParam_Var(UInt32 index)
614 {
615 Space();
616 Add_Var(index);
617 }
618
AddParam_UInt(UInt32 value)619 void CInArchive::AddParam_UInt(UInt32 value)
620 {
621 Space();
622 Add_UInt(value);
623 }
624
625 #endif
626
627
628 #define NS_CODE_SKIP 252
629 #define NS_CODE_VAR 253
630 #define NS_CODE_SHELL 254
631 // #define NS_CODE_LANG 255
632
633 // #define NS_3_CODE_LANG 1
634 #define NS_3_CODE_SHELL 2
635 #define NS_3_CODE_VAR 3
636 #define NS_3_CODE_SKIP 4
637
638 #define PARK_CODE_SKIP 0xE000
639 #define PARK_CODE_VAR 0xE001
640 #define PARK_CODE_SHELL 0xE002
641 #define PARK_CODE_LANG 0xE003
642
643 #define IS_NS_SPEC_CHAR(c) ((c) >= NS_CODE_SKIP)
644 #define IS_PARK_SPEC_CHAR(c) ((c) >= PARK_CODE_SKIP && (c) <= PARK_CODE_LANG)
645
646 #define DECODE_NUMBER_FROM_2_CHARS(c0, c1) (((c0) & 0x7F) | (((unsigned)((c1) & 0x7F)) << 7))
647 #define CONVERT_NUMBER_NS_3_UNICODE(n) n = ((n & 0x7F) | (((n >> 8) & 0x7F) << 7))
648 #define CONVERT_NUMBER_PARK(n) n &= 0x7FFF
649
650
AreStringsEqual_16and8(const Byte * p16,const char * p8)651 static bool AreStringsEqual_16and8(const Byte *p16, const char *p8)
652 {
653 for (;;)
654 {
655 unsigned c16 = Get16(p16); p16 += 2;
656 unsigned c = (Byte)(*p8++);
657 if (c16 != c)
658 return false;
659 if (c == 0)
660 return true;
661 }
662 }
663
GetShellString(AString & s,unsigned index1,unsigned index2)664 void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2)
665 {
666 // zeros are not allowed here.
667 // if (index1 == 0 || index2 == 0) throw 333;
668
669 if ((index1 & 0x80) != 0)
670 {
671 unsigned offset = (index1 & 0x3F);
672
673 /* NSIS reads registry string:
674 keyName = HKLM Software\\Microsoft\\Windows\\CurrentVersion
675 mask = KEY_WOW64_64KEY, If 64-bit flag in index1 is set
676 valueName = string(offset)
677 If registry reading is failed, NSIS uses second parameter (index2)
678 to read string. The recursion is possible in that case in NSIS.
679 We don't parse index2 string. We only set strUsed status for that
680 string (but without recursion). */
681
682 if (offset >= NumStringChars)
683 {
684 s += kErrorStr;
685 return;
686 }
687
688 #ifdef NSIS_SCRIPT
689 strUsed[offset] = 1;
690 if (index2 < NumStringChars)
691 strUsed[index2] = 1;
692 #endif
693
694 const Byte *p = (const Byte *)(_data + _stringsPos);
695 int id = -1;
696 if (IsUnicode)
697 {
698 p += offset * 2;
699 if (AreStringsEqual_16and8(p, "ProgramFilesDir"))
700 id = 0;
701 else if (AreStringsEqual_16and8(p, "CommonFilesDir"))
702 id = 1;
703 }
704 else
705 {
706 p += offset;
707 if (strcmp((const char *)p, "ProgramFilesDir") == 0)
708 id = 0;
709 else if (strcmp((const char *)p, "CommonFilesDir") == 0)
710 id = 1;
711 }
712
713 s += ((id >= 0) ? (id == 0 ? "$PROGRAMFILES" : "$COMMONFILES") :
714 "$_ERROR_UNSUPPORTED_VALUE_REGISTRY_");
715 // s += ((index1 & 0x40) != 0) ? "64" : "32";
716 if ((index1 & 0x40) != 0)
717 s += "64";
718
719 if (id < 0)
720 {
721 s += '(';
722 if (IsUnicode)
723 {
724 for (unsigned i = 0; i < 256; i++)
725 {
726 wchar_t c = Get16(p + i * 2);
727 if (c == 0)
728 break;
729 if (c < 0x80)
730 s += (char)c;
731 }
732 }
733 else
734 s += (const char *)p;
735 s += ')';
736 }
737 return;
738 }
739
740 s += '$';
741 if (index1 < ARRAY_SIZE(kShellStrings))
742 {
743 const char *sz = kShellStrings[index1];
744 if (sz)
745 {
746 s += sz;
747 return;
748 }
749 }
750 if (index2 < ARRAY_SIZE(kShellStrings))
751 {
752 const char *sz = kShellStrings[index2];
753 if (sz)
754 {
755 s += sz;
756 return;
757 }
758 }
759 s += "_ERROR_UNSUPPORTED_SHELL_";
760 s += '[';
761 UIntToString(s, index1);
762 s += ',';
763 UIntToString(s, index2);
764 s += ']';
765 }
766
767 #ifdef NSIS_SCRIPT
768
Add_LangStr_Simple(UInt32 id)769 void CInArchive::Add_LangStr_Simple(UInt32 id)
770 {
771 Script += "LSTR_";
772 Add_UInt(id);
773 }
774
775 #endif
776
Add_LangStr(AString & res,UInt32 id)777 void CInArchive::Add_LangStr(AString &res, UInt32 id)
778 {
779 #ifdef NSIS_SCRIPT
780 langStrIDs.Add(id);
781 #endif
782 res += "$(LSTR_";
783 UIntToString(res, id);
784 res += ')';
785 }
786
GetNsisString_Raw(const Byte * s)787 void CInArchive::GetNsisString_Raw(const Byte *s)
788 {
789 Raw_AString.Empty();
790
791 if (NsisType != k_NsisType_Nsis3)
792 {
793 for (;;)
794 {
795 Byte c = *s++;
796 if (c == 0)
797 return;
798 if (IS_NS_SPEC_CHAR(c))
799 {
800 Byte c0 = *s++;
801 if (c0 == 0)
802 return;
803 if (c != NS_CODE_SKIP)
804 {
805 Byte c1 = *s++;
806 if (c1 == 0)
807 return;
808
809 if (c == NS_CODE_SHELL)
810 GetShellString(Raw_AString, c0, c1);
811 else
812 {
813 unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
814 if (c == NS_CODE_VAR)
815 GetVar(Raw_AString, n);
816 else // if (c == NS_CODE_LANG)
817 Add_LangStr(Raw_AString, n);
818 }
819 continue;
820 }
821 c = c0;
822 }
823 Raw_AString += (char)c;
824 }
825 }
826
827 // NSIS-3 ANSI
828 for (;;)
829 {
830 Byte c = *s++;
831 if (c <= NS_3_CODE_SKIP)
832 {
833 if (c == 0)
834 return;
835 Byte c0 = *s++;
836 if (c0 == 0)
837 return;
838 if (c != NS_3_CODE_SKIP)
839 {
840 Byte c1 = *s++;
841 if (c1 == 0)
842 return;
843
844 if (c == NS_3_CODE_SHELL)
845 GetShellString(Raw_AString, c0, c1);
846 else
847 {
848 unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
849 if (c == NS_3_CODE_VAR)
850 GetVar(Raw_AString, n);
851 else // if (c == NS_3_CODE_LANG)
852 Add_LangStr(Raw_AString, n);
853 }
854 continue;
855 }
856 c = c0;
857 }
858 Raw_AString += (char)c;
859 }
860 }
861
862 #ifdef NSIS_SCRIPT
863
GetNsisString(AString & res,const Byte * s)864 void CInArchive::GetNsisString(AString &res, const Byte *s)
865 {
866 for (;;)
867 {
868 Byte c = *s++;
869 if (c == 0)
870 return;
871 if (NsisType != k_NsisType_Nsis3)
872 {
873 if (IS_NS_SPEC_CHAR(c))
874 {
875 Byte c0 = *s++;
876 if (c0 == 0)
877 return;
878 if (c != NS_CODE_SKIP)
879 {
880 Byte c1 = *s++;
881 if (c1 == 0)
882 return;
883 if (c == NS_CODE_SHELL)
884 GetShellString(res, c0, c1);
885 else
886 {
887 unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
888 if (c == NS_CODE_VAR)
889 GetVar(res, n);
890 else // if (c == NS_CODE_LANG)
891 Add_LangStr(res, n);
892 }
893 continue;
894 }
895 c = c0;
896 }
897 }
898 else
899 {
900 // NSIS-3 ANSI
901 if (c <= NS_3_CODE_SKIP)
902 {
903 Byte c0 = *s++;
904 if (c0 == 0)
905 return;
906 if (c0 == 0)
907 break;
908 if (c != NS_3_CODE_SKIP)
909 {
910 Byte c1 = *s++;
911 if (c1 == 0)
912 return;
913 if (c == NS_3_CODE_SHELL)
914 GetShellString(res, c0, c1);
915 else
916 {
917 unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
918 if (c == NS_3_CODE_VAR)
919 GetVar(res, n);
920 else // if (c == NS_3_CODE_LANG)
921 Add_LangStr(res, n);
922 }
923 continue;
924 }
925 c = c0;
926 }
927 }
928
929 {
930 const char *e;
931 if (c == 9) e = "$\\t";
932 else if (c == 10) e = "$\\n";
933 else if (c == 13) e = "$\\r";
934 else if (c == '"') e = "$\\\"";
935 else if (c == '$') e = "$$";
936 else
937 {
938 res += (char)c;
939 continue;
940 }
941 res += e;
942 continue;
943 }
944 }
945 }
946
947 #endif
948
GetNsisString_Unicode_Raw(const Byte * p)949 void CInArchive::GetNsisString_Unicode_Raw(const Byte *p)
950 {
951 Raw_UString.Empty();
952
953 if (IsPark())
954 {
955 for (;;)
956 {
957 unsigned c = Get16(p);
958 p += 2;
959 if (c == 0)
960 break;
961 if (c < 0x80)
962 {
963 Raw_UString += (char)c;
964 continue;
965 }
966
967 if (IS_PARK_SPEC_CHAR(c))
968 {
969 unsigned n = Get16(p);
970 p += 2;
971 if (n == 0)
972 break;
973 if (c != PARK_CODE_SKIP)
974 {
975 Raw_AString.Empty();
976 if (c == PARK_CODE_SHELL)
977 GetShellString(Raw_AString, n & 0xFF, n >> 8);
978 else
979 {
980 CONVERT_NUMBER_PARK(n);
981 if (c == PARK_CODE_VAR)
982 GetVar(Raw_AString, n);
983 else // if (c == PARK_CODE_LANG)
984 Add_LangStr(Raw_AString, n);
985 }
986 Raw_UString += Raw_AString.Ptr(); // check it !
987 continue;
988 }
989 c = n;
990 }
991
992 Raw_UString += (wchar_t)c;
993 }
994
995 return;
996 }
997
998 // NSIS-3 Unicode
999 for (;;)
1000 {
1001 unsigned c = Get16(p);
1002 p += 2;
1003 if (c > NS_3_CODE_SKIP)
1004 {
1005 Raw_UString += (wchar_t)c;
1006 continue;
1007 }
1008 if (c == 0)
1009 break;
1010
1011 unsigned n = Get16(p);
1012 p += 2;
1013 if (n == 0)
1014 break;
1015 if (c == NS_3_CODE_SKIP)
1016 {
1017 Raw_UString += (wchar_t)n;
1018 continue;
1019 }
1020
1021 Raw_AString.Empty();
1022 if (c == NS_3_CODE_SHELL)
1023 GetShellString(Raw_AString, n & 0xFF, n >> 8);
1024 else
1025 {
1026 CONVERT_NUMBER_NS_3_UNICODE(n);
1027 if (c == NS_3_CODE_VAR)
1028 GetVar(Raw_AString, n);
1029 else // if (c == NS_3_CODE_LANG)
1030 Add_LangStr(Raw_AString, n);
1031 }
1032 Raw_UString += Raw_AString.Ptr();
1033 }
1034 }
1035
1036 #ifdef NSIS_SCRIPT
1037
1038 static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
1039
GetNsisString_Unicode(AString & res,const Byte * p)1040 void CInArchive::GetNsisString_Unicode(AString &res, const Byte *p)
1041 {
1042 for (;;)
1043 {
1044 unsigned c = Get16(p);
1045 p += 2;
1046 if (c == 0)
1047 break;
1048 if (IsPark())
1049 {
1050 if (IS_PARK_SPEC_CHAR(c))
1051 {
1052 unsigned n = Get16(p);
1053 p += 2;
1054 if (n == 0)
1055 break;
1056 if (c != PARK_CODE_SKIP)
1057 {
1058 if (c == PARK_CODE_SHELL)
1059 GetShellString(res, n & 0xFF, n >> 8);
1060 else
1061 {
1062 CONVERT_NUMBER_PARK(n);
1063 if (c == PARK_CODE_VAR)
1064 GetVar(res, n);
1065 else // if (c == PARK_CODE_LANG)
1066 Add_LangStr(res, n);
1067 }
1068 continue;
1069 }
1070 c = n;
1071 }
1072 }
1073 else
1074 {
1075 // NSIS-3 Unicode
1076 if (c <= NS_3_CODE_SKIP)
1077 {
1078 unsigned n = Get16(p);
1079 p += 2;
1080 if (n == 0)
1081 break;
1082 if (c != NS_3_CODE_SKIP)
1083 {
1084 if (c == NS_3_CODE_SHELL)
1085 GetShellString(res, n & 0xFF, n >> 8);
1086 else
1087 {
1088 CONVERT_NUMBER_NS_3_UNICODE(n);
1089 if (c == NS_3_CODE_VAR)
1090 GetVar(res, n);
1091 else // if (c == NS_3_CODE_LANG)
1092 Add_LangStr(res, n);
1093 }
1094 continue;
1095 }
1096 c = n;
1097 }
1098 }
1099
1100 if (c < 0x80)
1101 {
1102 const char *e;
1103 if (c == 9) e = "$\\t";
1104 else if (c == 10) e = "$\\n";
1105 else if (c == 13) e = "$\\r";
1106 else if (c == '"') e = "$\\\"";
1107 else if (c == '$') e = "$$";
1108 else
1109 {
1110 res += (char)c;
1111 continue;
1112 }
1113 res += e;
1114 continue;
1115 }
1116
1117 UInt32 value = c;
1118 /*
1119 if (value >= 0xD800 && value < 0xE000)
1120 {
1121 UInt32 c2;
1122 if (value >= 0xDC00 || srcPos == srcLen)
1123 break;
1124 c2 = src[srcPos++];
1125 if (c2 < 0xDC00 || c2 >= 0xE000)
1126 break;
1127 value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
1128 }
1129 */
1130 unsigned numAdds;
1131 for (numAdds = 1; numAdds < 5; numAdds++)
1132 if (value < (((UInt32)1) << (numAdds * 5 + 6)))
1133 break;
1134 res += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
1135 do
1136 {
1137 numAdds--;
1138 res += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
1139 // destPos++;
1140 }
1141 while (numAdds != 0);
1142
1143 // AddToUtf8(res, c);
1144 }
1145 }
1146
1147 #endif
1148
ReadString2_Raw(UInt32 pos)1149 void CInArchive::ReadString2_Raw(UInt32 pos)
1150 {
1151 Raw_AString.Empty();
1152 Raw_UString.Empty();
1153 if ((Int32)pos < 0)
1154 Add_LangStr(Raw_AString, -((Int32)pos + 1));
1155 else if (pos >= NumStringChars)
1156 {
1157 Raw_AString += kErrorStr;
1158 // UIntToString(Raw_AString, pos);
1159 }
1160 else
1161 {
1162 if (IsUnicode)
1163 GetNsisString_Unicode_Raw(_data + _stringsPos + pos * 2);
1164 else
1165 GetNsisString_Raw(_data + _stringsPos + pos);
1166 return;
1167 }
1168 Raw_UString = Raw_AString.Ptr();
1169 }
1170
IsGoodString(UInt32 param) const1171 bool CInArchive::IsGoodString(UInt32 param) const
1172 {
1173 if (param >= NumStringChars)
1174 return false;
1175 if (param == 0)
1176 return true;
1177 const Byte *p = _data + _stringsPos;
1178 unsigned c;
1179 if (IsUnicode)
1180 c = Get16(p + param * 2 - 2);
1181 else
1182 c = p[param - 1];
1183 // some files have '\\' character before string?
1184 return (c == 0 || c == '\\');
1185 }
1186
AreTwoParamStringsEqual(UInt32 param1,UInt32 param2) const1187 bool CInArchive::AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const
1188 {
1189 if (param1 == param2)
1190 return true;
1191
1192 /* NSIS-3.0a1 probably contains bug, so it can use 2 different strings
1193 with same content. So we check real string also.
1194 Also it's possible to check identical postfix parts of strings. */
1195
1196 if (param1 >= NumStringChars ||
1197 param2 >= NumStringChars)
1198 return false;
1199
1200 const Byte *p = _data + _stringsPos;
1201
1202 if (IsUnicode)
1203 {
1204 const Byte *p1 = p + param1 * 2;
1205 const Byte *p2 = p + param2 * 2;
1206 for (;;)
1207 {
1208 UInt16 c = Get16(p1);
1209 if (c != Get16(p2))
1210 return false;
1211 if (c == 0)
1212 return true;
1213 p1 += 2;
1214 p2 += 2;
1215 }
1216 }
1217 else
1218 {
1219 const Byte *p1 = p + param1;
1220 const Byte *p2 = p + param2;
1221 for (;;)
1222 {
1223 Byte c = *p1++;
1224 if (c != *p2++)
1225 return false;
1226 if (c == 0)
1227 return true;
1228 }
1229 }
1230 }
1231
1232 #ifdef NSIS_SCRIPT
1233
GetNumUsedVars() const1234 UInt32 CInArchive::GetNumUsedVars() const
1235 {
1236 UInt32 numUsedVars = 0;
1237 const Byte *data = (const Byte *)_data + _stringsPos;
1238 unsigned npi = 0;
1239 for (UInt32 i = 0; i < NumStringChars;)
1240 {
1241 bool process = true;
1242 if (npi < noParseStringIndexes.Size() && noParseStringIndexes[npi] == i)
1243 {
1244 process = false;
1245 npi++;
1246 }
1247
1248 if (IsUnicode)
1249 {
1250 if (IsPark())
1251 {
1252 for (;;)
1253 {
1254 unsigned c = Get16(data + i * 2);
1255 i++;
1256 if (c == 0)
1257 break;
1258 if (IS_PARK_SPEC_CHAR(c))
1259 {
1260 UInt32 n = Get16(data + i * 2);
1261 i++;
1262 if (n == 0)
1263 break;
1264 if (process && c == PARK_CODE_VAR)
1265 {
1266 CONVERT_NUMBER_PARK(n);
1267 n++;
1268 if (numUsedVars < n)
1269 numUsedVars = n;
1270 }
1271 }
1272 }
1273 }
1274 else // NSIS-3 Unicode
1275 {
1276 for (;;)
1277 {
1278 unsigned c = Get16(data + i * 2);
1279 i++;
1280 if (c == 0)
1281 break;
1282 if (c > NS_3_CODE_SKIP)
1283 continue;
1284 UInt32 n = Get16(data + i * 2);
1285 i++;
1286 if (n == 0)
1287 break;
1288 if (process && c == NS_3_CODE_VAR)
1289 {
1290 CONVERT_NUMBER_NS_3_UNICODE(n);
1291 n++;
1292 if (numUsedVars < n)
1293 numUsedVars = n;
1294 }
1295 }
1296 }
1297 }
1298 else // not Unicode (ANSI)
1299 {
1300 if (NsisType != k_NsisType_Nsis3)
1301 {
1302 for (;;)
1303 {
1304 Byte c = data[i++];
1305 if (c == 0)
1306 break;
1307 if (IS_NS_SPEC_CHAR(c))
1308 {
1309 Byte c0 = data[i++];
1310 if (c0 == 0)
1311 break;
1312 if (c == NS_CODE_SKIP)
1313 continue;
1314 Byte c1 = data[i++];
1315 if (c1 == 0)
1316 break;
1317 if (process && c == NS_CODE_VAR)
1318 {
1319 UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
1320 n++;
1321 if (numUsedVars < n)
1322 numUsedVars = n;
1323 }
1324 }
1325 }
1326 }
1327 else
1328 {
1329 // NSIS-3 ANSI
1330 for (;;)
1331 {
1332 Byte c = data[i++];
1333 if (c == 0)
1334 break;
1335 if (c > NS_3_CODE_SKIP)
1336 continue;
1337
1338 Byte c0 = data[i++];
1339 if (c0 == 0)
1340 break;
1341 if (c == NS_3_CODE_SKIP)
1342 continue;
1343 Byte c1 = data[i++];
1344 if (c1 == 0)
1345 break;
1346 if (process && c == NS_3_CODE_VAR)
1347 {
1348 UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
1349 n++;
1350 if (numUsedVars < n)
1351 numUsedVars = n;
1352 }
1353 }
1354 }
1355 }
1356 }
1357 return numUsedVars;
1358 }
1359
ReadString2(AString & s,UInt32 pos)1360 void CInArchive::ReadString2(AString &s, UInt32 pos)
1361 {
1362 if ((Int32)pos < 0)
1363 {
1364 Add_LangStr(s, -((Int32)pos + 1));
1365 return;
1366 }
1367
1368 if (pos >= NumStringChars)
1369 {
1370 s += kErrorStr;
1371 // UIntToString(s, pos);
1372 return;
1373 }
1374
1375 #ifdef NSIS_SCRIPT
1376 strUsed[pos] = 1;
1377 #endif
1378
1379 if (IsUnicode)
1380 GetNsisString_Unicode(s, _data + _stringsPos + pos * 2);
1381 else
1382 GetNsisString(s, _data + _stringsPos + pos);
1383 }
1384
1385 #endif
1386
1387 #ifdef NSIS_SCRIPT
1388
1389 // #define DEL_DIR 1
1390 #define DEL_RECURSE 2
1391 #define DEL_REBOOT 4
1392 // #define DEL_SIMPLE 8
1393
AddRegRoot(UInt32 val)1394 void CInArchive::AddRegRoot(UInt32 val)
1395 {
1396 Space();
1397 const char *s;
1398 switch (val)
1399 {
1400 case 0: s = "SHCTX"; break;
1401 case 0x80000000: s = "HKCR"; break;
1402 case 0x80000001: s = "HKCU"; break;
1403 case 0x80000002: s = "HKLM"; break;
1404 case 0x80000003: s = "HKU"; break;
1405 case 0x80000004: s = "HKPD"; break;
1406 case 0x80000005: s = "HKCC"; break;
1407 case 0x80000006: s = "HKDD"; break;
1408 case 0x80000050: s = "HKPT"; break;
1409 case 0x80000060: s = "HKPN"; break;
1410 default:
1411 // Script += " RRRRR ";
1412 // throw 1;
1413 Add_Hex(Script, val); return;
1414 }
1415 Script += s;
1416 }
1417
1418 static const char * const g_WinAttrib[] =
1419 {
1420 "READONLY"
1421 , "HIDDEN"
1422 , "SYSTEM"
1423 , NULL
1424 , "DIRECTORY"
1425 , "ARCHIVE"
1426 , "DEVICE"
1427 , "NORMAL"
1428 , "TEMPORARY"
1429 , "SPARSE_FILE"
1430 , "REPARSE_POINT"
1431 , "COMPRESSED"
1432 , "OFFLINE"
1433 , "NOT_CONTENT_INDEXED"
1434 , "ENCRYPTED"
1435 , NULL
1436 , "VIRTUAL"
1437 };
1438
1439 #define FLAGS_DELIMITER '|'
1440
FlagsToString2(CDynLimBuf & s,const char * const * table,unsigned num,UInt32 flags)1441 static void FlagsToString2(CDynLimBuf &s, const char * const *table, unsigned num, UInt32 flags)
1442 {
1443 bool filled = false;
1444 for (unsigned i = 0; i < num; i++)
1445 {
1446 UInt32 f = (UInt32)1 << i;
1447 if ((flags & f) != 0)
1448 {
1449 const char *name = table[i];
1450 if (name)
1451 {
1452 if (filled)
1453 s += FLAGS_DELIMITER;
1454 filled = true;
1455 s += name;
1456 flags &= ~f;
1457 }
1458 }
1459 }
1460 if (flags != 0)
1461 {
1462 if (filled)
1463 s += FLAGS_DELIMITER;
1464 Add_Hex(s, flags);
1465 }
1466 }
1467
DoesNeedQuotes(const char * s)1468 static bool DoesNeedQuotes(const char *s)
1469 {
1470 {
1471 char c = s[0];
1472 if (c == 0 || c == '#' || c == ';' || (c == '/' && s[1] == '*'))
1473 return true;
1474 }
1475 for (;;)
1476 {
1477 char c = *s++;
1478 if (c == 0)
1479 return false;
1480 if (c == ' ')
1481 return true;
1482 }
1483 }
1484
Add_QuStr(const AString & s)1485 void CInArchive::Add_QuStr(const AString &s)
1486 {
1487 bool needQuotes = DoesNeedQuotes(s);
1488 if (needQuotes)
1489 Script += '\"';
1490 Script += s;
1491 if (needQuotes)
1492 Script += '\"';
1493 }
1494
SpaceQuStr(const AString & s)1495 void CInArchive::SpaceQuStr(const AString &s)
1496 {
1497 Space();
1498 Add_QuStr(s);
1499 }
1500
AddParam(UInt32 pos)1501 void CInArchive::AddParam(UInt32 pos)
1502 {
1503 _tempString.Empty();
1504 ReadString2(_tempString, pos);
1505 SpaceQuStr(_tempString);
1506 }
1507
AddParams(const UInt32 * params,unsigned num)1508 void CInArchive::AddParams(const UInt32 *params, unsigned num)
1509 {
1510 for (unsigned i = 0; i < num; i++)
1511 AddParam(params[i]);
1512 }
1513
AddOptionalParam(UInt32 pos)1514 void CInArchive::AddOptionalParam(UInt32 pos)
1515 {
1516 if (pos != 0)
1517 AddParam(pos);
1518 }
1519
GetNumParams(const UInt32 * params,unsigned num)1520 static unsigned GetNumParams(const UInt32 *params, unsigned num)
1521 {
1522 for (; num > 0 && params[num - 1] == 0; num--);
1523 return num;
1524 }
1525
AddOptionalParams(const UInt32 * params,unsigned num)1526 void CInArchive::AddOptionalParams(const UInt32 *params, unsigned num)
1527 {
1528 AddParams(params, GetNumParams(params, num));
1529 }
1530
1531
1532 static const UInt32 CMD_REF_Goto = (1 << 0);
1533 static const UInt32 CMD_REF_Call = (1 << 1);
1534 static const UInt32 CMD_REF_Pre = (1 << 2);
1535 static const UInt32 CMD_REF_Show = (1 << 3);
1536 static const UInt32 CMD_REF_Leave = (1 << 4);
1537 static const UInt32 CMD_REF_OnFunc = (1 << 5);
1538 static const UInt32 CMD_REF_Section = (1 << 6);
1539 static const UInt32 CMD_REF_InitPluginDir = (1 << 7);
1540 // static const UInt32 CMD_REF_Creator = (1 << 5); // _Pre is used instead
1541 static const unsigned CMD_REF_OnFunc_NumShifts = 28; // it uses for onFunc too
1542 static const unsigned CMD_REF_Page_NumShifts = 16; // it uses for onFunc too
1543 static const UInt32 CMD_REF_Page_Mask = 0x0FFF0000;
1544 static const UInt32 CMD_REF_OnFunc_Mask = 0xF0000000;
1545
IsPageFunc(UInt32 flag)1546 inline bool IsPageFunc(UInt32 flag)
1547 {
1548 return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave)) != 0;
1549 }
1550
IsFunc(UInt32 flag)1551 inline bool IsFunc(UInt32 flag)
1552 {
1553 // return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0;
1554 return (flag & (CMD_REF_Call | CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0;
1555 }
1556
IsProbablyEndOfFunc(UInt32 flag)1557 inline bool IsProbablyEndOfFunc(UInt32 flag)
1558 {
1559 return (flag != 0 && flag != CMD_REF_Goto);
1560 }
1561
1562 static const char * const kOnFunc[] =
1563 {
1564 "Init"
1565 , "InstSuccess"
1566 , "InstFailed"
1567 , "UserAbort"
1568 , "GUIInit"
1569 , "GUIEnd"
1570 , "MouseOverSection"
1571 , "VerifyInstDir"
1572 , "SelChange"
1573 , "RebootFailed"
1574 };
1575
Add_FuncName(const UInt32 * labels,UInt32 index)1576 void CInArchive::Add_FuncName(const UInt32 *labels, UInt32 index)
1577 {
1578 UInt32 mask = labels[index];
1579 if (mask & CMD_REF_OnFunc)
1580 {
1581 Script += ".on";
1582 Script += kOnFunc[labels[index] >> CMD_REF_OnFunc_NumShifts];
1583 }
1584 else if (mask & CMD_REF_InitPluginDir)
1585 {
1586 /*
1587 if (!IsInstaller)
1588 Script += "un."
1589 */
1590 Script += "Initialize_____Plugins";
1591 }
1592 else
1593 {
1594 Script += "func_";
1595 Add_UInt(index);
1596 }
1597 }
1598
AddParam_Func(const UInt32 * labels,UInt32 index)1599 void CInArchive::AddParam_Func(const UInt32 *labels, UInt32 index)
1600 {
1601 Space();
1602 if ((Int32)index >= 0)
1603 Add_FuncName(labels, index);
1604 else
1605 AddQuotes();
1606 }
1607
1608
Add_LabelName(UInt32 index)1609 void CInArchive::Add_LabelName(UInt32 index)
1610 {
1611 Script += "label_";
1612 Add_UInt(index);
1613 }
1614
1615 // param != 0
Add_GotoVar(UInt32 param)1616 void CInArchive::Add_GotoVar(UInt32 param)
1617 {
1618 Space();
1619 if ((Int32)param < 0)
1620 Add_Var(-((Int32)param + 1));
1621 else
1622 Add_LabelName(param - 1);
1623 }
1624
Add_GotoVar1(UInt32 param)1625 void CInArchive::Add_GotoVar1(UInt32 param)
1626 {
1627 if (param == 0)
1628 Script += " 0";
1629 else
1630 Add_GotoVar(param);
1631 }
1632
Add_GotoVars2(const UInt32 * params)1633 void CInArchive::Add_GotoVars2(const UInt32 *params)
1634 {
1635 Add_GotoVar1(params[0]);
1636 if (params[1] != 0)
1637 Add_GotoVar(params[1]);
1638 }
1639
NoLabels(const UInt32 * labels,UInt32 num)1640 static bool NoLabels(const UInt32 *labels, UInt32 num)
1641 {
1642 for (UInt32 i = 0; i < num; i++)
1643 if (labels[i] != 0)
1644 return false;
1645 return true;
1646 }
1647
1648 static const char * const k_REBOOTOK = " /REBOOTOK";
1649
1650 #define MY__MB_ABORTRETRYIGNORE 2
1651 #define MY__MB_RETRYCANCEL 5
1652
1653 static const char * const k_MB_Buttons[] =
1654 {
1655 "OK"
1656 , "OKCANCEL"
1657 , "ABORTRETRYIGNORE"
1658 , "YESNOCANCEL"
1659 , "YESNO"
1660 , "RETRYCANCEL"
1661 , "CANCELTRYCONTINUE"
1662 };
1663
1664 #define MY__MB_ICONSTOP (1 << 4)
1665
1666 static const char * const k_MB_Icons[] =
1667 {
1668 NULL
1669 , "ICONSTOP"
1670 , "ICONQUESTION"
1671 , "ICONEXCLAMATION"
1672 , "ICONINFORMATION"
1673 };
1674
1675 static const char * const k_MB_Flags[] =
1676 {
1677 "HELP"
1678 , "NOFOCUS"
1679 , "SETFOREGROUND"
1680 , "DEFAULT_DESKTOP_ONLY"
1681 , "TOPMOST"
1682 , "RIGHT"
1683 , "RTLREADING"
1684 // , "SERVICE_NOTIFICATION" // unsupported. That bit is used for NSIS purposes
1685 };
1686
1687 #define MY__IDCANCEL 2
1688 #define MY__IDIGNORE 5
1689
1690 static const char * const k_Button_IDs[] =
1691 {
1692 "0"
1693 , "IDOK"
1694 , "IDCANCEL"
1695 , "IDABORT"
1696 , "IDRETRY"
1697 , "IDIGNORE"
1698 , "IDYES"
1699 , "IDNO"
1700 , "IDCLOSE"
1701 , "IDHELP"
1702 , "IDTRYAGAIN"
1703 , "IDCONTINUE"
1704 };
1705
Add_ButtonID(UInt32 buttonID)1706 void CInArchive::Add_ButtonID(UInt32 buttonID)
1707 {
1708 Space();
1709 if (buttonID < ARRAY_SIZE(k_Button_IDs))
1710 Script += k_Button_IDs[buttonID];
1711 else
1712 {
1713 Script += "Button_";
1714 Add_UInt(buttonID);
1715 }
1716 }
1717
IsDirectString_Equal(UInt32 offset,const char * s) const1718 bool CInArchive::IsDirectString_Equal(UInt32 offset, const char *s) const
1719 {
1720 if (offset >= NumStringChars)
1721 return false;
1722 if (IsUnicode)
1723 return AreStringsEqual_16and8(_data + _stringsPos + offset * 2, s);
1724 else
1725 return strcmp((const char *)(const Byte *)_data + _stringsPos + offset, s) == 0;
1726 }
1727
StringToUInt32(const char * s,UInt32 & res)1728 static bool StringToUInt32(const char *s, UInt32 &res)
1729 {
1730 const char *end;
1731 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
1732 res = ConvertHexStringToUInt32(s + 2, &end);
1733 else
1734 res = ConvertStringToUInt32(s, &end);
1735 return (*end == 0);
1736 }
1737
1738 static const unsigned k_CtlColors32_Size = 24;
1739 static const unsigned k_CtlColors64_Size = 28;
1740
1741 #define GET_CtlColors_SIZE(is64) ((is64) ? k_CtlColors64_Size : k_CtlColors32_Size)
1742
1743 struct CNsis_CtlColors
1744 {
1745 UInt32 text; // COLORREF
1746 UInt32 bkc; // COLORREF
1747 UInt32 lbStyle;
1748 UInt32 bkb; // HBRUSH
1749 Int32 bkmode;
1750 Int32 flags;
1751 UInt32 bkb_hi32;
1752
1753 void Parse(const Byte *p, bool is64);
1754 };
1755
Parse(const Byte * p,bool is64)1756 void CNsis_CtlColors::Parse(const Byte *p, bool is64)
1757 {
1758 text = Get32(p);
1759 bkc = Get32(p + 4);
1760 if (is64)
1761 {
1762 bkb = Get32(p + 8);
1763 bkb_hi32 = Get32(p + 12);
1764 lbStyle = Get32(p + 16);
1765 p += 4;
1766 }
1767 else
1768 {
1769 lbStyle = Get32(p + 8);
1770 bkb = Get32(p + 12);
1771 }
1772 bkmode = (Int32)Get32(p + 16);
1773 flags = (Int32)Get32(p + 20);
1774 }
1775
1776 // Win32 constants
1777 #define MY__TRANSPARENT 1
1778 // #define MY__OPAQUE 2
1779
1780 #define MY__GENERIC_READ ((UInt32)1 << 31)
1781 #define MY__GENERIC_WRITE ((UInt32)1 << 30)
1782 #define MY__GENERIC_EXECUTE ((UInt32)1 << 29)
1783 #define MY__GENERIC_ALL ((UInt32)1 << 28)
1784
1785 #define MY__CREATE_NEW 1
1786 #define MY__CREATE_ALWAYS 2
1787 #define MY__OPEN_EXISTING 3
1788 #define MY__OPEN_ALWAYS 4
1789 #define MY__TRUNCATE_EXISTING 5
1790
1791 // text/bg colors
1792 #define kColorsFlags_TEXT 1
1793 #define kColorsFlags_TEXT_SYS 2
1794 #define kColorsFlags_BK 4
1795 #define kColorsFlags_BK_SYS 8
1796 #define kColorsFlags_BKB 16
1797
Add_Color2(UInt32 v)1798 void CInArchive::Add_Color2(UInt32 v)
1799 {
1800 v = ((v & 0xFF) << 16) | (v & 0xFF00) | ((v >> 16) & 0xFF);
1801 char sz[32];
1802 for (int i = 5; i >= 0; i--)
1803 {
1804 unsigned t = v & 0xF;
1805 v >>= 4;
1806 sz[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
1807 }
1808 sz[6] = 0;
1809 Script += sz;
1810 }
1811
Add_ColorParam(UInt32 v)1812 void CInArchive::Add_ColorParam(UInt32 v)
1813 {
1814 Space();
1815 Add_Color2(v);
1816 }
1817
Add_Color(UInt32 v)1818 void CInArchive::Add_Color(UInt32 v)
1819 {
1820 Script += "0x";
1821 Add_Color2(v);
1822 }
1823
1824 #define MY__SW_HIDE 0
1825 #define MY__SW_SHOWNORMAL 1
1826
1827 #define MY__SW_SHOWMINIMIZED 2
1828 #define MY__SW_SHOWMINNOACTIVE 7
1829 #define MY__SW_SHOWNA 8
1830
1831 static const char * const kShowWindow_Commands[] =
1832 {
1833 "HIDE"
1834 , "SHOWNORMAL" // "NORMAL"
1835 , "SHOWMINIMIZED"
1836 , "SHOWMAXIMIZED" // "MAXIMIZE"
1837 , "SHOWNOACTIVATE"
1838 , "SHOW"
1839 , "MINIMIZE"
1840 , "SHOWMINNOACTIVE"
1841 , "SHOWNA"
1842 , "RESTORE"
1843 , "SHOWDEFAULT"
1844 , "FORCEMINIMIZE" // "MAX"
1845 };
1846
Add_ShowWindow_Cmd_2(AString & s,UInt32 cmd)1847 static void Add_ShowWindow_Cmd_2(AString &s, UInt32 cmd)
1848 {
1849 if (cmd < ARRAY_SIZE(kShowWindow_Commands))
1850 {
1851 s += "SW_";
1852 s += kShowWindow_Commands[cmd];
1853 }
1854 else
1855 UIntToString(s, cmd);
1856 }
1857
Add_ShowWindow_Cmd(UInt32 cmd)1858 void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd)
1859 {
1860 if (cmd < ARRAY_SIZE(kShowWindow_Commands))
1861 {
1862 Script += "SW_";
1863 Script += kShowWindow_Commands[cmd];
1864 }
1865 else
1866 Add_UInt(cmd);
1867 }
1868
Add_TypeFromList(const char * const * table,unsigned tableSize,UInt32 type)1869 void CInArchive::Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type)
1870 {
1871 if (type < tableSize)
1872 Script += table[type];
1873 else
1874 {
1875 Script += '_';
1876 Add_UInt(type);
1877 }
1878 }
1879
1880 #define ADD_TYPE_FROM_LIST(table, type) Add_TypeFromList(table, ARRAY_SIZE(table), type)
1881
1882 enum
1883 {
1884 k_ExecFlags_AutoClose,
1885 k_ExecFlags_ShellVarContext,
1886 k_ExecFlags_Errors,
1887 k_ExecFlags_Abort,
1888 k_ExecFlags_RebootFlag,
1889 k_ExecFlags_reboot_called,
1890 k_ExecFlags_cur_insttype,
1891 k_ExecFlags_plugin_api_version,
1892 k_ExecFlags_Silent,
1893 k_ExecFlags_InstDirError,
1894 k_ExecFlags_rtl,
1895 k_ExecFlags_ErrorLevel,
1896 k_ExecFlags_RegView,
1897 k_ExecFlags_DetailsPrint = 13,
1898 };
1899
1900 // Names for NSIS exec_flags_t structure vars
1901 static const char * const kExecFlags_VarsNames[] =
1902 {
1903 "AutoClose" // autoclose;
1904 , "ShellVarContext" // all_user_var;
1905 , "Errors" // exec_error;
1906 , "Abort" // abort;
1907 , "RebootFlag" // exec_reboot; // NSIS_SUPPORT_REBOOT
1908 , "reboot_called" // reboot_called; // NSIS_SUPPORT_REBOOT
1909 , "cur_insttype" // XXX_cur_insttype; // depreacted
1910 , "plugin_api_version" // plugin_api_version; // see NSISPIAPIVER_CURR
1911 // used to be XXX_insttype_changed
1912 , "Silent" // silent; // NSIS_CONFIG_SILENT_SUPPORT
1913 , "InstDirError" // instdir_error;
1914 , "rtl" // rtl;
1915 , "ErrorLevel" // errlvl;
1916 , "RegView" // alter_reg_view;
1917 , "DetailsPrint" // status_update;
1918 };
1919
Add_ExecFlags(UInt32 flagsType)1920 void CInArchive::Add_ExecFlags(UInt32 flagsType)
1921 {
1922 ADD_TYPE_FROM_LIST(kExecFlags_VarsNames, flagsType);
1923 }
1924
1925
1926 // ---------- Page ----------
1927
1928 // page flags
1929 #define PF_CANCEL_ENABLE 4
1930 #define PF_LICENSE_FORCE_SELECTION 32
1931 #define PF_LICENSE_NO_FORCE_SELECTION 64
1932 #define PF_PAGE_EX 512
1933 #define PF_DIR_NO_BTN_DISABLE 1024
1934 /*
1935 #define PF_LICENSE_SELECTED 1
1936 #define PF_NEXT_ENABLE 2
1937 #define PF_BACK_SHOW 8
1938 #define PF_LICENSE_STREAM 16
1939 #define PF_NO_NEXT_FOCUS 128
1940 #define PF_BACK_ENABLE 256
1941 */
1942
1943 // page window proc
1944 enum
1945 {
1946 PWP_LICENSE,
1947 PWP_SELCOM,
1948 PWP_DIR,
1949 PWP_INSTFILES,
1950 PWP_UNINST,
1951 PWP_COMPLETED,
1952 PWP_CUSTOM
1953 };
1954
1955 static const char * const kPageTypes[] =
1956 {
1957 "license"
1958 , "components"
1959 , "directory"
1960 , "instfiles"
1961 , "uninstConfirm"
1962 , "COMPLETED"
1963 , "custom"
1964 };
1965
1966 #define SET_FUNC_REF(x, flag) if ((Int32)(x) >= 0 && (x) < bh.Num) \
1967 { labels[x] = (labels[x] & ~CMD_REF_Page_Mask) | ((flag) | (pageIndex << CMD_REF_Page_NumShifts)); }
1968
1969 // #define IDD_LICENSE 102
1970 #define IDD_LICENSE_FSRB 108
1971 #define IDD_LICENSE_FSCB 109
1972
AddPageOption1(UInt32 param,const char * name)1973 void CInArchive::AddPageOption1(UInt32 param, const char *name)
1974 {
1975 if (param == 0)
1976 return;
1977 TabString(name);
1978 AddParam(param);
1979 NewLine();
1980 }
1981
AddPageOption(const UInt32 * params,unsigned num,const char * name)1982 void CInArchive::AddPageOption(const UInt32 *params, unsigned num, const char *name)
1983 {
1984 num = GetNumParams(params, num);
1985 if (num == 0)
1986 return;
1987 TabString(name);
1988 AddParams(params, num);
1989 NewLine();
1990 }
1991
Separator()1992 void CInArchive::Separator()
1993 {
1994 AddLF();
1995 AddCommentAndString("--------------------");
1996 AddLF();
1997 }
1998
Space()1999 void CInArchive::Space()
2000 {
2001 Script += ' ';
2002 }
2003
Tab()2004 void CInArchive::Tab()
2005 {
2006 Script += " ";
2007 }
2008
Tab(bool commented)2009 void CInArchive::Tab(bool commented)
2010 {
2011 Script += commented ? " ; " : " ";
2012 }
2013
BigSpaceComment()2014 void CInArchive::BigSpaceComment()
2015 {
2016 Script += " ; ";
2017 }
2018
SmallSpaceComment()2019 void CInArchive::SmallSpaceComment()
2020 {
2021 Script += " ; ";
2022 }
2023
AddCommentAndString(const char * s)2024 void CInArchive::AddCommentAndString(const char *s)
2025 {
2026 Script += "; ";
2027 Script += s;
2028 }
2029
AddError(const char * s)2030 void CInArchive::AddError(const char *s)
2031 {
2032 BigSpaceComment();
2033 Script += "!!! ERROR: ";
2034 Script += s;
2035 }
2036
AddErrorLF(const char * s)2037 void CInArchive::AddErrorLF(const char *s)
2038 {
2039 AddError(s);
2040 AddLF();
2041 }
2042
CommentOpen()2043 void CInArchive::CommentOpen()
2044 {
2045 AddStringLF("/*");
2046 }
2047
CommentClose()2048 void CInArchive::CommentClose()
2049 {
2050 AddStringLF("*/");
2051 }
2052
AddLF()2053 void CInArchive::AddLF()
2054 {
2055 Script += CR_LF;
2056 }
2057
AddQuotes()2058 void CInArchive::AddQuotes()
2059 {
2060 Script += "\"\"";
2061 }
2062
TabString(const char * s)2063 void CInArchive::TabString(const char *s)
2064 {
2065 Tab();
2066 Script += s;
2067 }
2068
AddStringLF(const char * s)2069 void CInArchive::AddStringLF(const char *s)
2070 {
2071 Script += s;
2072 AddLF();
2073 }
2074
2075 // ---------- Section ----------
2076
2077 static const char * const kSection_VarsNames[] =
2078 {
2079 "Text"
2080 , "InstTypes"
2081 , "Flags"
2082 , "Code"
2083 , "CodeSize"
2084 , "Size" // size in KB
2085 };
2086
Add_SectOp(UInt32 opType)2087 void CInArchive::Add_SectOp(UInt32 opType)
2088 {
2089 ADD_TYPE_FROM_LIST(kSection_VarsNames, opType);
2090 }
2091
Parse(const Byte * p)2092 void CSection::Parse(const Byte *p)
2093 {
2094 Name = Get32(p);
2095 InstallTypes = Get32(p + 4);
2096 Flags = Get32(p + 8);
2097 StartCmdIndex = Get32(p + 12);
2098 NumCommands = Get32(p + 16);
2099 SizeKB = Get32(p + 20);
2100 };
2101
2102 // used for section->flags
2103 #define SF_SELECTED (1 << 0)
2104 #define SF_SECGRP (1 << 1)
2105 #define SF_SECGRPEND (1 << 2)
2106 #define SF_BOLD (1 << 3)
2107 #define SF_RO (1 << 4)
2108 #define SF_EXPAND (1 << 5)
2109 /*
2110 #define SF_PSELECTED (1 << 6)
2111 #define SF_TOGGLED (1 << 7)
2112 #define SF_NAMECHG (1 << 8)
2113 */
2114
PrintSectionBegin(const CSection & sect,unsigned index)2115 bool CInArchive::PrintSectionBegin(const CSection §, unsigned index)
2116 {
2117 AString name;
2118 if (sect.Flags & SF_BOLD)
2119 name += '!';
2120 AString s2;
2121 ReadString2(s2, sect.Name);
2122 if (!IsInstaller)
2123 {
2124 if (!StringsAreEqualNoCase_Ascii(s2, "uninstall"))
2125 name += "un.";
2126 }
2127 name += s2;
2128
2129 if (sect.Flags & SF_SECGRPEND)
2130 {
2131 AddStringLF("SectionGroupEnd");
2132 return true;
2133 }
2134
2135 if (sect.Flags & SF_SECGRP)
2136 {
2137 Script += "SectionGroup";
2138 if (sect.Flags & SF_EXPAND)
2139 Script += " /e";
2140 SpaceQuStr(name);
2141 Script += " ; Section";
2142 AddParam_UInt(index);
2143 NewLine();
2144 return true;
2145 }
2146
2147 Script += "Section";
2148 if ((sect.Flags & SF_SELECTED) == 0)
2149 Script += " /o";
2150 if (!name.IsEmpty())
2151 SpaceQuStr(name);
2152
2153 /*
2154 if (!name.IsEmpty())
2155 Script += ' ';
2156 else
2157 */
2158 SmallSpaceComment();
2159 Script += "Section_";
2160 Add_UInt(index);
2161
2162 /*
2163 Script += " ; flags = ";
2164 Add_Hex(Script, sect.Flags);
2165 */
2166
2167 NewLine();
2168
2169 if (sect.SizeKB != 0)
2170 {
2171 // probably we must show AddSize, only if there is additional size.
2172 Tab();
2173 AddCommentAndString("AddSize");
2174 AddParam_UInt(sect.SizeKB);
2175 AddLF();
2176 }
2177
2178 bool needSectionIn =
2179 (sect.Name != 0 && sect.InstallTypes != 0) ||
2180 (sect.Name == 0 && sect.InstallTypes != 0xFFFFFFFF);
2181 if (needSectionIn || (sect.Flags & SF_RO) != 0)
2182 {
2183 TabString("SectionIn");
2184 UInt32 instTypes = sect.InstallTypes;
2185 for (int i = 0; i < 32; i++, instTypes >>= 1)
2186 if ((instTypes & 1) != 0)
2187 {
2188 AddParam_UInt(i + 1);
2189 }
2190 if ((sect.Flags & SF_RO) != 0)
2191 Script += " RO";
2192 AddLF();
2193 }
2194 return false;
2195 }
2196
PrintSectionEnd()2197 void CInArchive::PrintSectionEnd()
2198 {
2199 AddStringLF("SectionEnd");
2200 AddLF();
2201 }
2202
2203 // static const unsigned kOnFuncShift = 4;
2204
ClearLangComment()2205 void CInArchive::ClearLangComment()
2206 {
2207 langStrIDs.Clear();
2208 }
2209
PrintNumComment(const char * name,UInt32 value)2210 void CInArchive::PrintNumComment(const char *name, UInt32 value)
2211 {
2212 // size_t len = Script.Len();
2213 AddCommentAndString(name);
2214 Script += ": ";
2215 Add_UInt(value);
2216 AddLF();
2217 /*
2218 len = Script.Len() - len;
2219 char sz[16];
2220 ConvertUInt32ToString(value, sz);
2221 len += MyStringLen(sz);
2222 for (; len < 20; len++)
2223 Space();
2224 AddStringLF(sz);
2225 */
2226 }
2227
2228
NewLine()2229 void CInArchive::NewLine()
2230 {
2231 if (!langStrIDs.IsEmpty())
2232 {
2233 BigSpaceComment();
2234 for (unsigned i = 0; i < langStrIDs.Size() && i < 20; i++)
2235 {
2236 /*
2237 if (i != 0)
2238 Script += ' ';
2239 */
2240 UInt32 langStr = langStrIDs[i];
2241 if (langStr >= _numLangStrings)
2242 {
2243 AddError("langStr");
2244 break;
2245 }
2246 UInt32 param = Get32(_mainLang + langStr * 4);
2247 if (param != 0)
2248 AddParam(param);
2249 }
2250 ClearLangComment();
2251 }
2252 AddLF();
2253 }
2254
2255 static const UInt32 kPageSize = 16 * 4;
2256
2257 static const char * const k_SetOverwrite_Modes[] =
2258 {
2259 "on"
2260 , "off"
2261 , "try"
2262 , "ifnewer"
2263 , "ifdiff"
2264 // "lastused"
2265 };
2266
2267
MessageBox_MB_Part(UInt32 param)2268 void CInArchive::MessageBox_MB_Part(UInt32 param)
2269 {
2270 {
2271 UInt32 v = param & 0xF;
2272 Script += " MB_";
2273 if (v < ARRAY_SIZE(k_MB_Buttons))
2274 Script += k_MB_Buttons[v];
2275 else
2276 {
2277 Script += "Buttons_";
2278 Add_UInt(v);
2279 }
2280 }
2281 {
2282 UInt32 icon = (param >> 4) & 0x7;
2283 if (icon != 0)
2284 {
2285 Script += "|MB_";
2286 if (icon < ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon] != 0)
2287 Script += k_MB_Icons[icon];
2288 else
2289 {
2290 Script += "Icon_";
2291 Add_UInt(icon);
2292 }
2293 }
2294 }
2295 if ((param & 0x80) != 0)
2296 Script += "|MB_USERICON";
2297 {
2298 UInt32 defButton = (param >> 8) & 0xF;
2299 if (defButton != 0)
2300 {
2301 Script += "|MB_DEFBUTTON";
2302 Add_UInt(defButton + 1);
2303 }
2304 }
2305 {
2306 UInt32 modal = (param >> 12) & 0x3;
2307 if (modal == 1) Script += "|MB_SYSTEMMODAL";
2308 else if (modal == 2) Script += "|MB_TASKMODAL";
2309 else if (modal == 3) Script += "|0x3000";
2310 UInt32 flags = (param >> 14);
2311 for (unsigned i = 0; i < ARRAY_SIZE(k_MB_Flags); i++)
2312 if ((flags & (1 << i)) != 0)
2313 {
2314 Script += "|MB_";
2315 Script += k_MB_Flags[i];
2316 }
2317 }
2318 }
2319
2320 #define GET_CMD_PARAM(ppp, index) Get32((ppp) + 4 + (index) * 4)
2321
2322 static const Byte k_InitPluginDir_Commands[] =
2323 { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 };
2324
CompareCommands(const Byte * rawCmds,const Byte * sequence,size_t numCommands)2325 bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands)
2326 {
2327 for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize)
2328 if (GetCmd(Get32(rawCmds)) != sequence[kkk])
2329 return false;
2330 return true;
2331 }
2332
2333
2334 static const UInt32 kSectionSize_base = 6 * 4;
2335 // static const UInt32 kSectionSize_8bit = kSectionSize_base + 1024;
2336 // static const UInt32 kSectionSize_16bit = kSectionSize_base + 1024 * 2;
2337 // static const UInt32 kSectionSize_16bit_Big = kSectionSize_base + 8196 * 2;
2338 // 8196 is default string length in NSIS-Unicode since 2.37.3
2339
2340 #endif
2341
2342
AddString(AString & dest,const char * src)2343 static void AddString(AString &dest, const char *src)
2344 {
2345 dest.Add_Space_if_NotEmpty();
2346 dest += src;
2347 }
2348
GetFormatDescription() const2349 AString CInArchive::GetFormatDescription() const
2350 {
2351 AString s ("NSIS-");
2352 char c;
2353 if (IsPark())
2354 {
2355 s += "Park-";
2356 c = '1';
2357 if (NsisType == k_NsisType_Park2) c = '2';
2358 else if (NsisType == k_NsisType_Park3) c = '3';
2359 }
2360 else
2361 {
2362 c = '2';
2363 if (NsisType == k_NsisType_Nsis3)
2364 c = '3';
2365 }
2366 s += c;
2367 if (IsNsis200)
2368 s += ".00";
2369 else if (IsNsis225)
2370 s += ".25";
2371
2372 if (IsUnicode)
2373 AddString(s, "Unicode");
2374
2375 if (Is64Bit)
2376 AddString(s, "64-bit");
2377
2378 if (LogCmdIsEnabled)
2379 AddString(s, "log");
2380
2381 if (BadCmd >= 0)
2382 {
2383 AddString(s, "BadCmd=");
2384 UIntToString(s, BadCmd);
2385 }
2386 return s;
2387 }
2388
2389 #ifdef NSIS_SCRIPT
2390
2391 static const unsigned kNumAdditionalParkCmds = 3;
2392
GetNumSupportedCommands() const2393 unsigned CInArchive::GetNumSupportedCommands() const
2394 {
2395 unsigned numCmds = IsPark() ? (unsigned)kNumCmds : (unsigned)(kNumCmds) - kNumAdditionalParkCmds;
2396 if (!LogCmdIsEnabled)
2397 numCmds--;
2398 if (!IsUnicode)
2399 numCmds -= 2;
2400 return numCmds;
2401 }
2402
2403 #endif
2404
GetCmd(UInt32 a)2405 UInt32 CInArchive::GetCmd(UInt32 a)
2406 {
2407 if (!IsPark())
2408 {
2409 if (!LogCmdIsEnabled)
2410 return a;
2411 if (a < EW_SECTIONSET)
2412 return a;
2413 if (a == EW_SECTIONSET)
2414 return EW_LOG;
2415 return a - 1;
2416 }
2417
2418 if (a < EW_REGISTERDLL)
2419 return a;
2420 if (NsisType >= k_NsisType_Park2)
2421 {
2422 if (a == EW_REGISTERDLL) return EW_GETFONTVERSION;
2423 a--;
2424 }
2425 if (NsisType >= k_NsisType_Park3)
2426 {
2427 if (a == EW_REGISTERDLL) return EW_GETFONTNAME;
2428 a--;
2429 }
2430 if (a >= EW_FSEEK)
2431 {
2432 if (IsUnicode)
2433 {
2434 if (a == EW_FSEEK) return EW_FPUTWS;
2435 if (a == EW_FSEEK + 1) return EW_FPUTWS + 1;
2436 a -= 2;
2437 }
2438
2439 if (a >= EW_SECTIONSET && LogCmdIsEnabled)
2440 {
2441 if (a == EW_SECTIONSET)
2442 return EW_LOG;
2443 return a - 1;
2444 }
2445 if (a == EW_FPUTWS)
2446 return EW_FINDPROC;
2447 // if (a > EW_FPUTWS) return 0;
2448 }
2449 return a;
2450 }
2451
FindBadCmd(const CBlockHeader & bh,const Byte * p)2452 void CInArchive::FindBadCmd(const CBlockHeader &bh, const Byte *p)
2453 {
2454 BadCmd = -1;
2455
2456 for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
2457 {
2458 UInt32 id = GetCmd(Get32(p));
2459 if (id >= kNumCmds)
2460 continue;
2461 if (BadCmd >= 0 && id >= (unsigned)BadCmd)
2462 continue;
2463 unsigned i;
2464 if (IsNsis3_OrHigher())
2465 {
2466 if (id == EW_RESERVEDOPCODE)
2467 {
2468 BadCmd = id;
2469 continue;
2470 }
2471 }
2472 else
2473 {
2474 // if (id == EW_GETLABELADDR || id == EW_GETFUNCTIONADDR)
2475 if (id == EW_RESERVEDOPCODE || id == EW_GETOSINFO)
2476 {
2477 BadCmd = id;
2478 continue;
2479 }
2480 }
2481 for (i = 6; i != 0; i--)
2482 {
2483 UInt32 param = Get32(p + i * 4);
2484 if (param != 0)
2485 break;
2486 }
2487 if (id == EW_FINDPROC && i == 0)
2488 {
2489 BadCmd = id;
2490 continue;
2491 }
2492 if (k_Commands[id].NumParams < i)
2493 BadCmd = id;
2494 }
2495 }
2496
2497 /* We calculate the number of parameters in commands to detect
2498 layout of commands. It's not very good way.
2499 If you know simpler and more robust way to detect Version and layout,
2500 please write to 7-Zip forum */
2501
DetectNsisType(const CBlockHeader & bh,const Byte * p)2502 void CInArchive::DetectNsisType(const CBlockHeader &bh, const Byte *p)
2503 {
2504 bool strongPark = false;
2505 bool strongNsis = false;
2506
2507 if (NumStringChars > 2)
2508 {
2509 const Byte *strData = _data + _stringsPos;
2510 if (IsUnicode)
2511 {
2512 UInt32 num = NumStringChars - 2;
2513 for (UInt32 i = 0; i < num; i++)
2514 {
2515 if (Get16(strData + i * 2) == 0)
2516 {
2517 unsigned c2 = Get16(strData + 2 + i * 2);
2518 // it can be TXT/RTF with marker char (1 or 2). so we must check next char
2519 // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL)
2520 if (c2 == NS_3_CODE_VAR)
2521 {
2522 // 18.06: fixed: is it correct ?
2523 // if ((Get16(strData + 3 + i * 2) & 0x8000) != 0)
2524 if ((Get16(strData + 4 + i * 2) & 0x8080) == 0x8080)
2525 {
2526 NsisType = k_NsisType_Nsis3;
2527 strongNsis = true;
2528 break;
2529 }
2530 }
2531 }
2532 }
2533 if (!strongNsis)
2534 {
2535 NsisType = k_NsisType_Park1;
2536 strongPark = true;
2537 }
2538 }
2539 else
2540 {
2541 UInt32 num = NumStringChars - 2;
2542 for (UInt32 i = 0; i < num; i++)
2543 {
2544 if (strData[i] == 0)
2545 {
2546 Byte c2 = strData[i + 1];
2547 // it can be TXT/RTF with marker char (1 or 2). so we must check next char
2548 // for marker=1 (txt)
2549 if (c2 == NS_3_CODE_VAR)
2550 // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL && c2 != 1)
2551 {
2552 if ((strData[i + 2] & 0x80) != 0)
2553 {
2554 // const char *p2 = (const char *)(strData + i + 1);
2555 // p2 = p2;
2556 NsisType = k_NsisType_Nsis3;
2557 strongNsis = true;
2558 break;
2559 }
2560 }
2561 }
2562 }
2563 }
2564 }
2565
2566 if (NsisType == k_NsisType_Nsis2 && !IsUnicode)
2567 {
2568 const Byte *p2 = p;
2569
2570 for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize)
2571 {
2572 UInt32 cmd = GetCmd(Get32(p2));
2573 if (cmd != EW_GETDLGITEM &&
2574 cmd != EW_ASSIGNVAR)
2575 continue;
2576
2577 UInt32 params[kNumCommandParams];
2578 for (unsigned i = 0; i < kNumCommandParams; i++)
2579 params[i] = Get32(p2 + 4 + 4 * i);
2580
2581 if (cmd == EW_GETDLGITEM)
2582 {
2583 // we can use also EW_SETCTLCOLORS
2584 if (IsVarStr(params[1], kVar_HWNDPARENT_225))
2585 {
2586 IsNsis225 = true;
2587 if (params[0] == kVar_Spec_OUTDIR_225)
2588 {
2589 IsNsis200 = true;
2590 break;
2591 }
2592 }
2593 }
2594 else // if (cmd == EW_ASSIGNVAR)
2595 {
2596 if (params[0] == kVar_Spec_OUTDIR_225 &&
2597 params[2] == 0 &&
2598 params[3] == 0 &&
2599 IsVarStr(params[1], kVar_OUTDIR))
2600 IsNsis225 = true;
2601 }
2602 }
2603 }
2604
2605 bool parkVer_WasDetected = false;
2606
2607 if (!strongNsis && !IsNsis225 && !IsNsis200)
2608 {
2609 // it must be before FindBadCmd(bh, p);
2610 unsigned mask = 0;
2611
2612 unsigned numInsertMax = IsUnicode ? 4 : 2;
2613
2614 const Byte *p2 = p;
2615
2616 for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize)
2617 {
2618 UInt32 cmd = Get32(p2); // we use original (not converted) command
2619
2620 if (cmd < EW_WRITEUNINSTALLER ||
2621 cmd > EW_WRITEUNINSTALLER + numInsertMax)
2622 continue;
2623
2624 UInt32 params[kNumCommandParams];
2625 for (unsigned i = 0; i < kNumCommandParams; i++)
2626 params[i] = Get32(p2 + 4 + 4 * i);
2627
2628 if (params[4] != 0 ||
2629 params[5] != 0 ||
2630 params[0] <= 1 ||
2631 params[3] <= 1)
2632 continue;
2633
2634 UInt32 altParam = params[3];
2635 if (!IsGoodString(params[0]) ||
2636 !IsGoodString(altParam))
2637 continue;
2638
2639 UInt32 additional = 0;
2640 if (GetVarIndexFinished(altParam, '\\', additional) != kVar_INSTDIR)
2641 continue;
2642 if (AreTwoParamStringsEqual(altParam + additional, params[0]))
2643 {
2644 unsigned numInserts = cmd - EW_WRITEUNINSTALLER;
2645 mask |= (1 << numInserts);
2646 }
2647 }
2648
2649 if (mask == 1)
2650 {
2651 parkVer_WasDetected = true; // it can be original NSIS or Park-1
2652 }
2653 else if (mask != 0)
2654 {
2655 ENsisType newType = NsisType;
2656 if (IsUnicode)
2657 switch (mask)
2658 {
2659 case (1 << 3): newType = k_NsisType_Park2; break;
2660 case (1 << 4): newType = k_NsisType_Park3; break;
2661 }
2662 else
2663 switch (mask)
2664 {
2665 case (1 << 1): newType = k_NsisType_Park2; break;
2666 case (1 << 2): newType = k_NsisType_Park3; break;
2667 }
2668 if (newType != NsisType)
2669 {
2670 parkVer_WasDetected = true;
2671 NsisType = newType;
2672 }
2673 }
2674 }
2675
2676 FindBadCmd(bh, p);
2677
2678 /*
2679 if (strongNsis)
2680 return;
2681 */
2682
2683 if (BadCmd < EW_REGISTERDLL)
2684 return;
2685
2686 /*
2687 // in ANSI archive we don't check Park and log version
2688 if (!IsUnicode)
2689 return;
2690 */
2691
2692 // We can support Park-ANSI archives, if we remove if (strongPark) check
2693 if (strongPark && !parkVer_WasDetected)
2694 {
2695 if (BadCmd < EW_SECTIONSET)
2696 {
2697 NsisType = k_NsisType_Park3;
2698 LogCmdIsEnabled = true; // version 3 is provided with log enabled
2699 FindBadCmd(bh, p);
2700 if (BadCmd > 0 && BadCmd < EW_SECTIONSET)
2701 {
2702 NsisType = k_NsisType_Park2;
2703 LogCmdIsEnabled = false;
2704 FindBadCmd(bh, p);
2705 if (BadCmd > 0 && BadCmd < EW_SECTIONSET)
2706 {
2707 NsisType = k_NsisType_Park1;
2708 FindBadCmd(bh, p);
2709 }
2710 }
2711 }
2712 }
2713
2714 if (BadCmd >= EW_SECTIONSET)
2715 {
2716 LogCmdIsEnabled = !LogCmdIsEnabled;
2717 FindBadCmd(bh, p);
2718 if (BadCmd >= EW_SECTIONSET && LogCmdIsEnabled)
2719 {
2720 LogCmdIsEnabled = false;
2721 FindBadCmd(bh, p);
2722 }
2723 }
2724 }
2725
GetVarIndex(UInt32 strPos) const2726 Int32 CInArchive::GetVarIndex(UInt32 strPos) const
2727 {
2728 if (strPos >= NumStringChars)
2729 return -1;
2730
2731 if (IsUnicode)
2732 {
2733 if (NumStringChars - strPos < 3 * 2)
2734 return -1;
2735 const Byte *p = _data + _stringsPos + strPos * 2;
2736 unsigned code = Get16(p);
2737 if (IsPark())
2738 {
2739 if (code != PARK_CODE_VAR)
2740 return -1;
2741 UInt32 n = Get16(p + 2);
2742 if (n == 0)
2743 return -1;
2744 CONVERT_NUMBER_PARK(n);
2745 return (Int32)n;
2746 }
2747
2748 // NSIS-3
2749 {
2750 if (code != NS_3_CODE_VAR)
2751 return -1;
2752 UInt32 n = Get16(p + 2);
2753 if (n == 0)
2754 return -1;
2755 CONVERT_NUMBER_NS_3_UNICODE(n);
2756 return (Int32)n;
2757 }
2758 }
2759
2760 if (NumStringChars - strPos < 4)
2761 return -1;
2762
2763 const Byte *p = _data + _stringsPos + strPos;
2764 unsigned c = *p;
2765 if (NsisType == k_NsisType_Nsis3)
2766 {
2767 if (c != NS_3_CODE_VAR)
2768 return -1;
2769 }
2770 else if (c != NS_CODE_VAR)
2771 return -1;
2772
2773 unsigned c0 = p[1];
2774 if (c0 == 0)
2775 return -1;
2776 unsigned c1 = p[2];
2777 if (c1 == 0)
2778 return -1;
2779 return DECODE_NUMBER_FROM_2_CHARS(c0, c1);
2780 }
2781
GetVarIndex(UInt32 strPos,UInt32 & resOffset) const2782 Int32 CInArchive::GetVarIndex(UInt32 strPos, UInt32 &resOffset) const
2783 {
2784 resOffset = 0;
2785 Int32 varIndex = GetVarIndex(strPos);
2786 if (varIndex < 0)
2787 return varIndex;
2788 if (IsUnicode)
2789 {
2790 if (NumStringChars - strPos < 2 * 2)
2791 return -1;
2792 resOffset = 2;
2793 }
2794 else
2795 {
2796 if (NumStringChars - strPos < 3)
2797 return -1;
2798 resOffset = 3;
2799 }
2800 return varIndex;
2801 }
2802
GetVarIndexFinished(UInt32 strPos,Byte endChar,UInt32 & resOffset) const2803 Int32 CInArchive::GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const
2804 {
2805 resOffset = 0;
2806 Int32 varIndex = GetVarIndex(strPos);
2807 if (varIndex < 0)
2808 return varIndex;
2809 if (IsUnicode)
2810 {
2811 if (NumStringChars - strPos < 3 * 2)
2812 return -1;
2813 const Byte *p = _data + _stringsPos + strPos * 2;
2814 if (Get16(p + 4) != endChar)
2815 return -1;
2816 resOffset = 3;
2817 }
2818 else
2819 {
2820 if (NumStringChars - strPos < 4)
2821 return -1;
2822 const Byte *p = _data + _stringsPos + strPos;
2823 if (p[3] != endChar)
2824 return -1;
2825 resOffset = 4;
2826 }
2827 return varIndex;
2828 }
2829
IsVarStr(UInt32 strPos,UInt32 varIndex) const2830 bool CInArchive::IsVarStr(UInt32 strPos, UInt32 varIndex) const
2831 {
2832 if (varIndex > (UInt32)0x7FFF)
2833 return false;
2834 UInt32 resOffset;
2835 return GetVarIndexFinished(strPos, 0, resOffset) == (Int32)varIndex;
2836 }
2837
IsAbsolutePathVar(UInt32 strPos) const2838 bool CInArchive::IsAbsolutePathVar(UInt32 strPos) const
2839 {
2840 Int32 varIndex = GetVarIndex(strPos);
2841 if (varIndex < 0)
2842 return false;
2843 switch (varIndex)
2844 {
2845 case kVar_INSTDIR:
2846 case kVar_EXEDIR:
2847 case kVar_TEMP:
2848 case kVar_PLUGINSDIR:
2849 return true;
2850 }
2851 return false;
2852 }
2853
2854 #define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
2855
2856 // We use same check as in NSIS decoder
IsDrivePath(const wchar_t * s)2857 static bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; }
IsDrivePath(const char * s)2858 static bool IsDrivePath(const char *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; }
2859
IsAbsolutePath(const wchar_t * s)2860 static bool IsAbsolutePath(const wchar_t *s)
2861 {
2862 return (s[0] == WCHAR_PATH_SEPARATOR && s[1] == WCHAR_PATH_SEPARATOR) || IsDrivePath(s);
2863 }
2864
IsAbsolutePath(const char * s)2865 static bool IsAbsolutePath(const char *s)
2866 {
2867 return (s[0] == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) || IsDrivePath(s);
2868 }
2869
SetItemName(CItem & item,UInt32 strPos)2870 void CInArchive::SetItemName(CItem &item, UInt32 strPos)
2871 {
2872 ReadString2_Raw(strPos);
2873 bool isAbs = IsAbsolutePathVar(strPos);
2874 if (IsUnicode)
2875 {
2876 item.NameU = Raw_UString;
2877 if (!isAbs && !IsAbsolutePath(Raw_UString))
2878 item.Prefix = UPrefixes.Size() - 1;
2879 }
2880 else
2881 {
2882 item.NameA = Raw_AString;
2883 if (!isAbs && !IsAbsolutePath(Raw_AString))
2884 item.Prefix = APrefixes.Size() - 1;
2885 }
2886 }
2887
ReadEntries(const CBlockHeader & bh)2888 HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
2889 {
2890 #ifdef NSIS_SCRIPT
2891 CDynLimBuf &s = Script;
2892
2893 CObjArray<UInt32> labels;
2894 labels.Alloc(bh.Num);
2895 memset(labels, 0, bh.Num * sizeof(UInt32));
2896
2897 {
2898 const Byte *p = _data;
2899 UInt32 i;
2900 for (i = 0; i < numOnFunc; i++)
2901 {
2902 UInt32 func = Get32(p + onFuncOffset + 4 * i);
2903 if (func < bh.Num)
2904 labels[func] = (labels[func] & ~CMD_REF_OnFunc_Mask) | (CMD_REF_OnFunc | (i << CMD_REF_OnFunc_NumShifts));
2905 }
2906 }
2907
2908 /*
2909 {
2910 for (int i = 0; i < OnFuncs.Size(); i++)
2911 {
2912 UInt32 address = OnFuncs[i] >> kOnFuncShift;
2913 if (address < bh.Num)
2914 }
2915 }
2916 */
2917
2918 if (bhPages.Num != 0)
2919 {
2920 Separator();
2921 PrintNumComment("PAGES", bhPages.Num);
2922
2923 if (bhPages.Num > (1 << 12)
2924 || bhPages.Offset > _size
2925 || bhPages.Num * kPageSize > _size - bhPages.Offset)
2926 {
2927 AddErrorLF("Pages error");
2928 }
2929 else
2930 {
2931
2932 AddLF();
2933 const Byte *p = _data + bhPages.Offset;
2934
2935 for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, p += kPageSize)
2936 {
2937 UInt32 dlgID = Get32(p);
2938 UInt32 wndProcID = Get32(p + 4);
2939 UInt32 preFunc = Get32(p + 8);
2940 UInt32 showFunc = Get32(p + 12);
2941 UInt32 leaveFunc = Get32(p + 16);
2942 UInt32 flags = Get32(p + 20);
2943 UInt32 caption = Get32(p + 24);
2944 // UInt32 back = Get32(p + 28);
2945 UInt32 next = Get32(p + 32);
2946 // UInt32 clickNext = Get32(p + 36);
2947 // UInt32 cancel = Get32(p + 40);
2948 UInt32 params[5];
2949 for (int i = 0; i < 5; i++)
2950 params[i] = Get32(p + 44 + 4 * i);
2951
2952 SET_FUNC_REF(preFunc, CMD_REF_Pre);
2953 SET_FUNC_REF(showFunc, CMD_REF_Show);
2954 SET_FUNC_REF(leaveFunc, CMD_REF_Leave);
2955
2956 if (wndProcID == PWP_COMPLETED)
2957 CommentOpen();
2958
2959 AddCommentAndString("Page ");
2960 Add_UInt(pageIndex);
2961 AddLF();
2962
2963 if (flags & PF_PAGE_EX)
2964 {
2965 s += "PageEx ";
2966 if (!IsInstaller)
2967 s += "un.";
2968 }
2969 else
2970 s += IsInstaller ? "Page " : "UninstPage ";
2971
2972 if (wndProcID < ARRAY_SIZE(kPageTypes))
2973 s += kPageTypes[wndProcID];
2974 else
2975 Add_UInt(wndProcID);
2976
2977
2978 bool needCallbacks = (
2979 (Int32)preFunc >= 0 ||
2980 (Int32)showFunc >= 0 ||
2981 (Int32)leaveFunc >= 0);
2982
2983 if (flags & PF_PAGE_EX)
2984 {
2985 AddLF();
2986 if (needCallbacks)
2987 TabString("PageCallbacks");
2988 }
2989
2990 if (needCallbacks)
2991 {
2992 AddParam_Func(labels, preFunc); // it's creator_function for PWP_CUSTOM
2993 if (wndProcID != PWP_CUSTOM)
2994 {
2995 AddParam_Func(labels, showFunc);
2996 }
2997 AddParam_Func(labels, leaveFunc);
2998 }
2999
3000 if ((flags & PF_PAGE_EX) == 0)
3001 {
3002 // AddOptionalParam(caption);
3003 if (flags & PF_CANCEL_ENABLE)
3004 s += " /ENABLECANCEL";
3005 AddLF();
3006 }
3007 else
3008 {
3009 AddLF();
3010 AddPageOption1(caption, "Caption");
3011 }
3012
3013 if (wndProcID == PWP_LICENSE)
3014 {
3015 if ((flags & PF_LICENSE_NO_FORCE_SELECTION) != 0 ||
3016 (flags & PF_LICENSE_FORCE_SELECTION) != 0)
3017 {
3018 TabString("LicenseForceSelection ");
3019 if (flags & PF_LICENSE_NO_FORCE_SELECTION)
3020 s += "off";
3021 else
3022 {
3023 if (dlgID == IDD_LICENSE_FSCB)
3024 s += "checkbox";
3025 else if (dlgID == IDD_LICENSE_FSRB)
3026 s += "radiobuttons";
3027 else
3028 Add_UInt(dlgID);
3029 AddOptionalParams(params + 2, 2);
3030 }
3031 NewLine();
3032 }
3033
3034 if (params[0] != 0 || next != 0)
3035 {
3036 TabString("LicenseText");
3037 AddParam(params[0]);
3038 AddOptionalParam(next);
3039 NewLine();
3040 }
3041 if (params[1] != 0)
3042 {
3043 TabString("LicenseData");
3044 if ((Int32)params[1] < 0)
3045 AddParam(params[1]);
3046 else
3047 AddLicense(params[1], -1);
3048 ClearLangComment();
3049 NewLine();
3050 }
3051 }
3052 else if (wndProcID == PWP_SELCOM)
3053 AddPageOption(params, 3, "ComponentsText");
3054 else if (wndProcID == PWP_DIR)
3055 {
3056 AddPageOption(params, 4, "DirText");
3057 if (params[4] != 0)
3058 {
3059 TabString("DirVar");
3060 AddParam_Var(params[4] - 1);
3061 AddLF();
3062 }
3063 if (flags & PF_DIR_NO_BTN_DISABLE)
3064 {
3065 TabString("DirVerify leave");
3066 AddLF();
3067 }
3068
3069 }
3070 else if (wndProcID == PWP_INSTFILES)
3071 {
3072 AddPageOption1(params[2], "CompletedText");
3073 AddPageOption1(params[1], "DetailsButtonText");
3074 }
3075 else if (wndProcID == PWP_UNINST)
3076 {
3077 if (params[4] != 0)
3078 {
3079 TabString("DirVar");
3080 AddParam_Var(params[4] - 1);
3081 AddLF();
3082 }
3083 AddPageOption(params, 2, "UninstallText");
3084 }
3085
3086 if (flags & PF_PAGE_EX)
3087 {
3088 s += "PageExEnd";
3089 NewLine();
3090 }
3091 if (wndProcID == PWP_COMPLETED)
3092 CommentClose();
3093 NewLine();
3094 }
3095 }
3096 }
3097
3098 CObjArray<CSection> Sections;
3099
3100 {
3101 Separator();
3102 PrintNumComment("SECTIONS", bhSections.Num);
3103 PrintNumComment("COMMANDS", bh.Num);
3104 AddLF();
3105
3106 if (bhSections.Num > (1 << 15)
3107 // || bhSections.Offset > _size
3108 // || (bhSections.Num * SectionSize > _size - bhSections.Offset)
3109 )
3110 {
3111 AddErrorLF("Sections error");
3112 }
3113 else if (bhSections.Num != 0)
3114 {
3115 Sections.Alloc((unsigned)bhSections.Num);
3116 const Byte *p = _data + bhSections.Offset;
3117 for (UInt32 i = 0; i < bhSections.Num; i++, p += SectionSize)
3118 {
3119 CSection §ion = Sections[i];
3120 section.Parse(p);
3121 if (section.StartCmdIndex < bh.Num)
3122 labels[section.StartCmdIndex] |= CMD_REF_Section;
3123 }
3124 }
3125 }
3126
3127 #endif
3128
3129 const Byte *p;
3130 UInt32 kkk;
3131
3132 #ifdef NSIS_SCRIPT
3133
3134 p = _data + bh.Offset;
3135
3136 for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
3137 {
3138 UInt32 commandId = GetCmd(Get32(p));
3139 UInt32 mask;
3140 switch (commandId)
3141 {
3142 case EW_NOP: mask = 1 << 0; break;
3143 case EW_IFFILEEXISTS: mask = 3 << 1; break;
3144 case EW_IFFLAG: mask = 3 << 0; break;
3145 case EW_MESSAGEBOX: mask = 5 << 3; break;
3146 case EW_STRCMP: mask = 3 << 2; break;
3147 case EW_INTCMP: mask = 7 << 2; break;
3148 case EW_ISWINDOW: mask = 3 << 1; break;
3149 case EW_CALL:
3150 {
3151 if (Get32(p + 4 + 4) == 1) // it's Call :Label
3152 {
3153 mask = 1 << 0;
3154 break;
3155 }
3156 UInt32 param0 = Get32(p + 4);
3157 if ((Int32)param0 > 0)
3158 labels[param0 - 1] |= CMD_REF_Call;
3159 continue;
3160 }
3161 default: continue;
3162 }
3163 for (unsigned i = 0; mask != 0; i++, mask >>= 1)
3164 if (mask & 1)
3165 {
3166 UInt32 param = Get32(p + 4 + 4 * i);
3167 if ((Int32)param > 0 && (Int32)param <= (Int32)bh.Num)
3168 labels[param - 1] |= CMD_REF_Goto;
3169 }
3170 }
3171
3172 int InitPluginsDir_Start = -1;
3173 int InitPluginsDir_End = -1;
3174 p = _data + bh.Offset;
3175 for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
3176 {
3177 UInt32 flg = labels[kkk];
3178 /*
3179 if (IsFunc(flg))
3180 {
3181 AddLF();
3182 for (int i = 0; i < 14; i++)
3183 {
3184 UInt32 commandId = GetCmd(Get32(p + kCmdSize * i));
3185 s += ", ";
3186 UIntToString(s, commandId);
3187 }
3188 AddLF();
3189 }
3190 */
3191 if (IsFunc(flg)
3192 && bh.Num - kkk >= ARRAY_SIZE(k_InitPluginDir_Commands)
3193 && CompareCommands(p, k_InitPluginDir_Commands, ARRAY_SIZE(k_InitPluginDir_Commands)))
3194 {
3195 InitPluginsDir_Start = kkk;
3196 InitPluginsDir_End = (int)(kkk + ARRAY_SIZE(k_InitPluginDir_Commands));
3197 labels[kkk] |= CMD_REF_InitPluginDir;
3198 break;
3199 }
3200 }
3201
3202 #endif
3203
3204 // AString prefixA_Temp;
3205 // UString prefixU_Temp;
3206
3207
3208 // const UInt32 kFindS = 158;
3209
3210 #ifdef NSIS_SCRIPT
3211
3212 UInt32 curSectionIndex = 0;
3213 // UInt32 lastSectionEndCmd = 0xFFFFFFFF;
3214 bool sectionIsOpen = false;
3215 // int curOnFunc = 0;
3216 bool onFuncIsOpen = false;
3217
3218 /*
3219 for (unsigned yyy = 0; yyy + 3 < _data.Size(); yyy++)
3220 {
3221 UInt32 val = Get32(_data + yyy);
3222 if (val == kFindS)
3223 val = val;
3224 }
3225 */
3226
3227 UInt32 overwrite_State = 0; // "SetOverwrite on"
3228 Int32 allowSkipFiles_State = -1; // -1: on, -2: off, >=0 : RAW value
3229 UInt32 endCommentIndex = 0;
3230
3231 unsigned numSupportedCommands = GetNumSupportedCommands();
3232
3233 #endif
3234
3235 p = _data + bh.Offset;
3236
3237 UString spec_outdir_U;
3238 AString spec_outdir_A;
3239
3240 UPrefixes.Add(UString("$INSTDIR"));
3241 APrefixes.Add(AString("$INSTDIR"));
3242
3243 p = _data + bh.Offset;
3244
3245 unsigned spec_outdir_VarIndex = IsNsis225 ?
3246 kVar_Spec_OUTDIR_225 :
3247 kVar_Spec_OUTDIR;
3248
3249 for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
3250 {
3251 UInt32 commandId;
3252 UInt32 params[kNumCommandParams];
3253 commandId = GetCmd(Get32(p));
3254 {
3255 for (unsigned i = 0; i < kNumCommandParams; i++)
3256 {
3257 params[i] = Get32(p + 4 + 4 * i);
3258 /*
3259 if (params[i] == kFindS)
3260 i = i;
3261 */
3262 }
3263 }
3264
3265 #ifdef NSIS_SCRIPT
3266
3267 bool IsSectionGroup = false;
3268 while (curSectionIndex < bhSections.Num)
3269 {
3270 const CSection § = Sections[curSectionIndex];
3271 if (sectionIsOpen)
3272 {
3273 if (sect.StartCmdIndex + sect.NumCommands + 1 != kkk)
3274 break;
3275 PrintSectionEnd();
3276 sectionIsOpen = false;
3277 // lastSectionEndCmd = kkk;
3278 curSectionIndex++;
3279 continue;
3280 }
3281 if (sect.StartCmdIndex != kkk)
3282 break;
3283 if (PrintSectionBegin(sect, curSectionIndex))
3284 {
3285 IsSectionGroup = true;
3286 curSectionIndex++;
3287 // do we need to flush prefixes in new section?
3288 // FlushOutPathPrefixes();
3289 }
3290 else
3291 sectionIsOpen = true;
3292 }
3293
3294 /*
3295 if (curOnFunc < OnFuncs.Size())
3296 {
3297 if ((OnFuncs[curOnFunc] >> kOnFuncShift) == kkk)
3298 {
3299 s += "Function .on";
3300 s += kOnFunc[OnFuncs[curOnFunc++] & ((1 << kOnFuncShift) - 1)];
3301 AddLF();
3302 onFuncIsOpen = true;
3303 }
3304 }
3305 */
3306
3307 if (labels[kkk] != 0 && labels[kkk] != CMD_REF_Section)
3308 {
3309 UInt32 flg = labels[kkk];
3310 if (IsFunc(flg))
3311 {
3312 if ((int)kkk == InitPluginsDir_Start)
3313 CommentOpen();
3314
3315 onFuncIsOpen = true;
3316 s += "Function ";
3317 Add_FuncName(labels, kkk);
3318 if (IsPageFunc(flg))
3319 {
3320 BigSpaceComment();
3321 s += "Page ";
3322 Add_UInt((flg & CMD_REF_Page_Mask) >> CMD_REF_Page_NumShifts);
3323 // if (flg & CMD_REF_Creator) s += ", Creator";
3324 if (flg & CMD_REF_Leave) s += ", Leave";
3325 if (flg & CMD_REF_Pre) s += ", Pre";
3326 if (flg & CMD_REF_Show) s += ", Show";
3327 }
3328 AddLF();
3329 }
3330 if (flg & CMD_REF_Goto)
3331 {
3332 Add_LabelName(kkk);
3333 s += ':';
3334 AddLF();
3335 }
3336 }
3337
3338 if (commandId != EW_RET)
3339 {
3340 Tab(kkk < endCommentIndex);
3341 }
3342
3343 /*
3344 UInt32 originalCmd = Get32(p);
3345 if (originalCmd >= EW_REGISTERDLL)
3346 {
3347 UIntToString(s, originalCmd);
3348 s += ' ';
3349 if (originalCmd != commandId)
3350 {
3351 UIntToString(s, commandId);
3352 s += ' ';
3353 }
3354 }
3355 */
3356
3357 unsigned numSkipParams = 0;
3358
3359 if (commandId < ARRAY_SIZE(k_Commands) && commandId < numSupportedCommands)
3360 {
3361 numSkipParams = k_Commands[commandId].NumParams;
3362 const char *sz = k_CommandNames[commandId];
3363 if (sz)
3364 s += sz;
3365 }
3366 else
3367 {
3368 s += "Command";
3369 Add_UInt(commandId);
3370 /* We don't show wrong commands that use overlapped ids.
3371 So we change commandId to big value */
3372 if (commandId < (1 << 12))
3373 commandId += (1 << 12);
3374 }
3375
3376 #endif
3377
3378 switch (commandId)
3379 {
3380 case EW_CREATEDIR:
3381 {
3382 bool isSetOutPath = (params[1] != 0);
3383
3384 if (isSetOutPath)
3385 {
3386 UInt32 par0 = params[0];
3387
3388 UInt32 resOffset;
3389 Int32 idx = GetVarIndex(par0, resOffset);
3390 if (idx == (Int32)spec_outdir_VarIndex ||
3391 idx == kVar_OUTDIR)
3392 par0 += resOffset;
3393
3394 ReadString2_Raw(par0);
3395
3396 if (IsUnicode)
3397 {
3398 if (idx == (Int32)spec_outdir_VarIndex)
3399 Raw_UString.Insert(0, spec_outdir_U);
3400 else if (idx == kVar_OUTDIR)
3401 Raw_UString.Insert(0, UPrefixes.Back());
3402 UPrefixes.Add(Raw_UString);
3403 }
3404 else
3405 {
3406 if (idx == (Int32)spec_outdir_VarIndex)
3407 Raw_AString.Insert(0, spec_outdir_A);
3408 else if (idx == kVar_OUTDIR)
3409 Raw_AString.Insert(0, APrefixes.Back());
3410 APrefixes.Add(Raw_AString);
3411 }
3412 }
3413
3414 #ifdef NSIS_SCRIPT
3415 s += isSetOutPath ? "SetOutPath" : "CreateDirectory";
3416 AddParam(params[0]);
3417 if (params[2] != 0) // 2.51+ & 3.0b3+
3418 {
3419 SmallSpaceComment();
3420 s += "CreateRestrictedDirectory";
3421 }
3422 #endif
3423
3424 break;
3425 }
3426
3427
3428 case EW_ASSIGNVAR:
3429 {
3430 if (params[0] == spec_outdir_VarIndex)
3431 {
3432 spec_outdir_U.Empty();
3433 spec_outdir_A.Empty();
3434 if (IsVarStr(params[1], kVar_OUTDIR) &&
3435 params[2] == 0 &&
3436 params[3] == 0)
3437 {
3438 spec_outdir_U = UPrefixes.Back(); // outdir_U;
3439 spec_outdir_A = APrefixes.Back(); // outdir_A;
3440 }
3441 }
3442
3443 #ifdef NSIS_SCRIPT
3444
3445 if (params[2] == 0 &&
3446 params[3] == 0 &&
3447 params[4] == 0 &&
3448 params[5] == 0 &&
3449 params[1] != 0 &&
3450 params[1] < NumStringChars)
3451 {
3452 char sz[16];
3453 ConvertUInt32ToString(kkk + 1, sz);
3454 if (IsDirectString_Equal(params[1], sz))
3455 {
3456 // we suppose that it's GetCurrentAddress command
3457 // but there is probability that it's StrCpy command
3458 s += "GetCurrentAddress";
3459 AddParam_Var(params[0]);
3460 SmallSpaceComment();
3461 }
3462 }
3463 s += "StrCpy";
3464 AddParam_Var(params[0]);
3465 AddParam(params[1]);
3466
3467 AddOptionalParams(params + 2, 2);
3468
3469 #endif
3470
3471 break;
3472 }
3473
3474 case EW_EXTRACTFILE:
3475 {
3476 CItem &item = Items.AddNew();
3477
3478 UInt32 par1 = params[1];
3479
3480 SetItemName(item, par1);
3481
3482 item.Pos = params[2];
3483 item.MTime.dwLowDateTime = params[3];
3484 item.MTime.dwHighDateTime = params[4];
3485
3486 #ifdef NSIS_SCRIPT
3487
3488 {
3489 UInt32 overwrite = params[0] & 0x7;
3490 if (overwrite != overwrite_State)
3491 {
3492 s += "SetOverwrite ";
3493 ADD_TYPE_FROM_LIST(k_SetOverwrite_Modes, overwrite);
3494 overwrite_State = overwrite;
3495 AddLF();
3496 Tab(kkk < endCommentIndex);
3497 }
3498 }
3499
3500 {
3501 UInt32 nsisMB = params[0] >> 3;
3502 if ((Int32)nsisMB != allowSkipFiles_State)
3503 {
3504 UInt32 mb = nsisMB & ((1 << 20) - 1); // old/new NSIS
3505 UInt32 b1 = nsisMB >> 21; // NSIS 2.06+
3506 UInt32 b2 = nsisMB >> 20; // NSIS old
3507 Int32 asf = (Int32)nsisMB;
3508 if (mb == (MY__MB_ABORTRETRYIGNORE | MY__MB_ICONSTOP) && (b1 == MY__IDIGNORE || b2 == MY__IDIGNORE))
3509 asf = -1;
3510 else if (mb == (MY__MB_RETRYCANCEL | MY__MB_ICONSTOP) && (b1 == MY__IDCANCEL || b2 == MY__IDCANCEL))
3511 asf = -2;
3512 else
3513 {
3514 AddCommentAndString("AllowSkipFiles [Overwrite]: ");
3515 MessageBox_MB_Part(mb);
3516 if (b1 != 0)
3517 {
3518 s += " /SD";
3519 Add_ButtonID(b1);
3520 }
3521 }
3522 if (asf != allowSkipFiles_State)
3523 {
3524 if (asf < 0)
3525 {
3526 s += "AllowSkipFiles ";
3527 s += (asf == -1) ? "on" : "off";
3528 }
3529 AddLF();
3530 Tab(kkk < endCommentIndex);
3531 }
3532 allowSkipFiles_State = (Int32)nsisMB;
3533 }
3534 }
3535
3536 s += "File";
3537 AddParam(params[1]);
3538
3539 /* params[5] contains link to LangString (negative value)
3540 with NLF_FILE_ERROR or NLF_FILE_ERROR_NOIGNORE message for MessageBox.
3541 We don't need to print it. */
3542
3543 #endif
3544
3545 if (IsVarStr(par1, 10)) // is $R0
3546 {
3547 // we parse InstallLib macro in 7-Zip installers
3548 unsigned kBackOffset = 28;
3549 if (kkk > 1)
3550 {
3551 // detect old version of InstallLib macro
3552 if (Get32(p - 1 * kCmdSize) == EW_NOP) // goto command
3553 kBackOffset -= 2;
3554 }
3555
3556 if (kkk > kBackOffset)
3557 {
3558 const Byte *p2 = p - kBackOffset * kCmdSize;
3559 UInt32 cmd = Get32(p2);
3560 if (cmd == EW_ASSIGNVAR)
3561 {
3562 UInt32 pars[6];
3563 for (int i = 0; i < 6; i++)
3564 pars[i] = Get32(p2 + i * 4 + 4);
3565 if (pars[0] == 10 + 4 && pars[2] == 0 && pars[3] == 0) // 10 + 4 means $R4
3566 {
3567 item.Prefix = -1;
3568 item.NameA.Empty();
3569 item.NameU.Empty();
3570 SetItemName(item, pars[1]);
3571 // maybe here we can restore original item name, if new name is empty
3572 }
3573 }
3574 }
3575 }
3576 /* UInt32 allowIgnore = params[5]; */
3577 break;
3578 }
3579
3580 case EW_SETFILEATTRIBUTES:
3581 {
3582 if (kkk > 0 && Get32(p - kCmdSize) == EW_EXTRACTFILE)
3583 {
3584 if (params[0] == Get32(p - kCmdSize + 4 + 4 * 1)) // compare with PrevCmd.Params[1]
3585 {
3586 CItem &item = Items.Back();
3587 item.Attrib_Defined = true;
3588 item.Attrib = params[1];
3589 }
3590 }
3591 #ifdef NSIS_SCRIPT
3592 AddParam(params[0]);
3593 Space();
3594 FlagsToString2(s, g_WinAttrib, ARRAY_SIZE(g_WinAttrib), params[1]);
3595 #endif
3596 break;
3597 }
3598
3599 case EW_WRITEUNINSTALLER:
3600 {
3601 /* NSIS 2.29+ writes alternative path to params[3]
3602 "$INSTDIR\\" + Str(params[0])
3603 NSIS installer uses alternative path, if main path
3604 from params[0] is not absolute path */
3605
3606 bool pathOk = (params[0] > 0) && IsGoodString(params[0]);
3607
3608 if (!pathOk)
3609 {
3610 #ifdef NSIS_SCRIPT
3611 AddError("bad path");
3612 #endif
3613 break;
3614 }
3615
3616 bool altPathOk = true;
3617
3618 UInt32 altParam = params[3];
3619 if (altParam != 0)
3620 {
3621 altPathOk = false;
3622 UInt32 additional = 0;
3623 if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR)
3624 altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]);
3625 }
3626
3627
3628 #ifdef NSIS_SCRIPT
3629
3630 AddParam(params[0]);
3631
3632 /*
3633 for (int i = 1; i < 3; i++)
3634 AddParam_UInt(params[i]);
3635 */
3636
3637 if (params[3] != 0)
3638 {
3639 SmallSpaceComment();
3640 AddParam(params[3]);
3641 }
3642
3643 #endif
3644
3645 if (!altPathOk)
3646 {
3647 #ifdef NSIS_SCRIPT
3648 AddError("alt path error");
3649 #endif
3650 }
3651
3652 if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER)
3653 {
3654 /* We don't cases with incorrect installer commands.
3655 Such bad installer item can break unpacking for other items. */
3656 #ifdef NSIS_SCRIPT
3657 AddError("SKIP possible BadCmd");
3658 #endif
3659 break;
3660 }
3661
3662 CItem &item = Items.AddNew();;
3663
3664 SetItemName(item, params[0]);
3665
3666 item.Pos = params[1];
3667 item.PatchSize = params[2];
3668 item.IsUninstaller = true;
3669
3670 /*
3671 // we can add second time to test the code
3672 CItem item2 = item;
3673 item2.NameU += L'2';
3674 item2.NameA += '2';
3675 Items.Add(item2);
3676 */
3677
3678 break;
3679 }
3680
3681 #ifdef NSIS_SCRIPT
3682
3683 case EW_RET:
3684 {
3685 // bool needComment = false;
3686 if (onFuncIsOpen)
3687 {
3688 if (kkk == bh.Num - 1 || IsProbablyEndOfFunc(labels[kkk + 1]))
3689 {
3690 AddStringLF("FunctionEnd");
3691
3692 if ((int)kkk + 1 == InitPluginsDir_End)
3693 CommentClose();
3694 AddLF();
3695 onFuncIsOpen = false;
3696 // needComment = true;
3697 break;
3698 }
3699 }
3700 // if (!needComment)
3701 if (IsSectionGroup)
3702 break;
3703 if (sectionIsOpen)
3704 {
3705 const CSection § = Sections[curSectionIndex];
3706 if (sect.StartCmdIndex + sect.NumCommands == kkk)
3707 {
3708 PrintSectionEnd();
3709 sectionIsOpen = false;
3710 curSectionIndex++;
3711 break;
3712 }
3713
3714 // needComment = true;
3715 // break;
3716 }
3717
3718 /*
3719 if (needComment)
3720 s += " ;";
3721 */
3722 TabString("Return");
3723 AddLF();
3724 break;
3725 }
3726
3727 case EW_NOP:
3728 {
3729 if (params[0] == 0)
3730 s += "Nop";
3731 else
3732 {
3733 s += "Goto";
3734 Add_GotoVar(params[0]);
3735 }
3736 break;
3737 }
3738
3739 case EW_ABORT:
3740 {
3741 AddOptionalParam(params[0]);
3742 break;
3743 }
3744
3745 case EW_CALL:
3746 {
3747 if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_EXTRACTFILE)
3748 {
3749 UInt32 par1 = GET_CMD_PARAM(p + kCmdSize, 1);
3750
3751 UInt32 pluginPar = 0;
3752
3753 if (GetVarIndexFinished(par1, '\\', pluginPar) == kVar_PLUGINSDIR)
3754 {
3755 pluginPar += par1;
3756 UInt32 commandId2 = GetCmd(Get32(p + kCmdSize * 2));
3757 if (commandId2 == EW_SETFLAG || commandId2 == EW_UPDATETEXT)
3758 {
3759 UInt32 i;
3760 for (i = kkk + 3; i < bh.Num; i++)
3761 {
3762 const Byte *pCmd = p + kCmdSize * (i - kkk);
3763 UInt32 commandId3 = GetCmd(Get32(pCmd));
3764 if (commandId3 != EW_PUSHPOP
3765 || GET_CMD_PARAM(pCmd, 1) != 0
3766 || GET_CMD_PARAM(pCmd, 2) != 0)
3767 break;
3768 }
3769 if (i < bh.Num)
3770 {
3771 const Byte *pCmd = p + kCmdSize * (i - kkk);
3772
3773 // UInt32 callDll_Param = GET_CMD_PARAM(pCmd, 0);
3774 // UInt32 file_Param = GET_CMD_PARAM(p + kCmdSize, 1);
3775
3776 if (GetCmd(Get32(pCmd)) == EW_REGISTERDLL &&
3777 AreTwoParamStringsEqual(
3778 GET_CMD_PARAM(pCmd, 0),
3779 GET_CMD_PARAM(p + kCmdSize, 1)))
3780 {
3781 // params[4] = 1 means GetModuleHandle attempt before default LoadLibraryEx;
3782 /// new versions of NSIS use params[4] = 1 for Plugin command
3783 if (GET_CMD_PARAM(pCmd, 2) == 0
3784 // && GET_CMD_PARAM(pCmd, 4) != 0
3785 )
3786 {
3787 {
3788 AString s2;
3789 ReadString2(s2, pluginPar);
3790 if (s2.Len() >= 4 &&
3791 StringsAreEqualNoCase_Ascii(s2.RightPtr(4), ".dll"))
3792 s2.DeleteFrom(s2.Len() - 4);
3793 s2 += "::";
3794 AString func;
3795 ReadString2(func, GET_CMD_PARAM(pCmd, 1));
3796 s2 += func;
3797 Add_QuStr(s2);
3798
3799 if (GET_CMD_PARAM(pCmd, 3) == 1)
3800 s += " /NOUNLOAD";
3801
3802 for (UInt32 j = i - 1; j >= kkk + 3; j--)
3803 {
3804 const Byte *pCmd2 = p + kCmdSize * (j - kkk);
3805 AddParam(GET_CMD_PARAM(pCmd2, 0));
3806 }
3807 NewLine();
3808 Tab(true);
3809 endCommentIndex = i + 1;
3810 }
3811 }
3812 }
3813 }
3814 }
3815 }
3816 }
3817 {
3818 const Byte *nextCmd = p + kCmdSize;
3819 UInt32 commandId2 = GetCmd(Get32(nextCmd));
3820 if (commandId2 == EW_SETFLAG
3821 && GET_CMD_PARAM(nextCmd, 0) == k_ExecFlags_DetailsPrint
3822 && GET_CMD_PARAM(nextCmd, 2) != 0) // is "lastused"
3823 // || commandId2 == EW_UPDATETEXT)
3824 {
3825 if ((Int32)params[0] > 0 && labels[params[0] - 1] & CMD_REF_InitPluginDir)
3826 {
3827 s += "InitPluginsDir";
3828 AddLF();
3829 Tab(true);
3830 endCommentIndex = kkk + 2;
3831 }
3832 }
3833 }
3834
3835 s += "Call ";
3836 if ((Int32)params[0] < 0)
3837 Add_Var(-((Int32)params[0] + 1));
3838 else if (params[0] == 0)
3839 s += '0';
3840 else
3841 {
3842 UInt32 val = params[0] - 1;
3843 if (params[1] == 1) // it's Call :Label
3844 {
3845 s += ':';
3846 Add_LabelName(val);
3847 }
3848 else // if (params[1] == 0) // it's Call Func
3849 Add_FuncName(labels, val);
3850 }
3851 break;
3852 }
3853
3854 case EW_UPDATETEXT:
3855 case EW_SLEEP:
3856 {
3857 AddParam(params[0]);
3858 break;
3859 }
3860
3861 case EW_CHDETAILSVIEW:
3862 {
3863 if (params[0] == MY__SW_SHOWNA && params[1] == MY__SW_HIDE) s += " show";
3864 else if (params[1] == MY__SW_SHOWNA && params[0] == MY__SW_HIDE) s += " hide";
3865 else
3866 for (int i = 0; i < 2; i++)
3867 {
3868 Space();
3869 Add_ShowWindow_Cmd(params[i]);
3870 }
3871 break;
3872 }
3873
3874 case EW_IFFILEEXISTS:
3875 {
3876 AddParam(params[0]);
3877 Add_GotoVars2(¶ms[1]);
3878 break;
3879 }
3880
3881 case EW_SETFLAG:
3882 {
3883 AString temp;
3884 ReadString2(temp, params[1]);
3885 if (params[0] == k_ExecFlags_Errors && params[2] == 0)
3886 {
3887 s += (temp.Len() == 1 && temp[0] == '0') ? "ClearErrors" : "SetErrors";
3888 break;
3889 }
3890 s += "Set";
3891 Add_ExecFlags(params[0]);
3892
3893 if (params[2] != 0)
3894 {
3895 s += " lastused";
3896 break;
3897 }
3898 UInt32 v;
3899 if (StringToUInt32(temp, v))
3900 {
3901 const char *s2 = NULL;
3902 switch (params[0])
3903 {
3904 case k_ExecFlags_AutoClose:
3905 case k_ExecFlags_RebootFlag:
3906 if (v < 2) { s2 = (v == 0) ? "false" : "true"; } break;
3907 case k_ExecFlags_ShellVarContext:
3908 if (v < 2) { s2 = (v == 0) ? "current" : "all"; } break;
3909 case k_ExecFlags_Silent:
3910 if (v < 2) { s2 = (v == 0) ? "normal" : "silent"; } break;
3911 case k_ExecFlags_RegView:
3912 if (v == 0) s2 = "32";
3913 else if (v == 256) s2 = "64";
3914 break;
3915 case k_ExecFlags_DetailsPrint:
3916 if (v == 0) s2 = "both";
3917 else if (v == 2) s2 = "textonly";
3918 else if (v == 4) s2 = "listonly";
3919 else if (v == 6) s2 = "none";
3920 break;
3921 }
3922 if (s2)
3923 {
3924 s += ' ';
3925 s += s2;
3926 break;
3927 }
3928 }
3929 SpaceQuStr(temp);
3930 break;
3931 }
3932
3933 case EW_IFFLAG:
3934 {
3935 Add_ExecFlags(params[2]);
3936 Add_GotoVars2(¶ms[0]);
3937 /*
3938 static const unsigned kIfErrors = 2;
3939 if (params[2] != kIfErrors && params[3] != 0xFFFFFFFF ||
3940 params[2] == kIfErrors && params[3] != 0)
3941 {
3942 s += " # FLAG &= ";
3943 AddParam_UInt(params[3]);
3944 }
3945 */
3946 break;
3947 }
3948
3949 case EW_GETFLAG:
3950 {
3951 Add_ExecFlags(params[1]);
3952 AddParam_Var(params[0]);
3953 break;
3954 }
3955
3956 case EW_RENAME:
3957 {
3958 if (params[2] != 0)
3959 s += k_REBOOTOK;
3960 AddParams(params, 2);
3961 if (params[3] != 0)
3962 {
3963 SmallSpaceComment();
3964 AddParam(params[3]); // rename comment for log file
3965 }
3966 break;
3967 }
3968
3969 case EW_GETFULLPATHNAME:
3970 {
3971 if (params[2] == 0)
3972 s += " /SHORT";
3973 AddParam_Var(params[1]);
3974 AddParam(params[0]);
3975 break;
3976 }
3977
3978 case EW_SEARCHPATH:
3979 case EW_STRLEN:
3980 {
3981 AddParam_Var(params[0]);
3982 AddParam(params[1]);
3983 break;
3984 }
3985
3986 case EW_GETTEMPFILENAME:
3987 {
3988 AddParam_Var(params[0]);
3989 AString temp;
3990 ReadString2(temp, params[1]);
3991 if (temp != "$TEMP")
3992 SpaceQuStr(temp);
3993 break;
3994 }
3995
3996 case EW_DELETEFILE:
3997 {
3998 UInt32 flag = params[1];
3999 if ((flag & DEL_REBOOT) != 0)
4000 s += k_REBOOTOK;
4001 AddParam(params[0]);
4002 break;
4003 }
4004
4005 case EW_MESSAGEBOX:
4006 {
4007 MessageBox_MB_Part(params[0]);
4008 AddParam(params[1]);
4009 {
4010 UInt32 buttonID = (params[0] >> 21); // NSIS 2.06+
4011 if (buttonID != 0)
4012 {
4013 s += " /SD";
4014 Add_ButtonID(buttonID);
4015 }
4016 }
4017 for (int i = 2; i < 6; i += 2)
4018 if (params[i] != 0)
4019 {
4020 Add_ButtonID(params[i]);
4021 Add_GotoVar1(params[i + 1]);
4022 }
4023 break;
4024 }
4025
4026 case EW_RMDIR:
4027 {
4028 UInt32 flag = params[1];
4029 if ((flag & DEL_RECURSE) != 0)
4030 s += " /r";
4031 if ((flag & DEL_REBOOT) != 0)
4032 s += k_REBOOTOK;
4033 AddParam(params[0]);
4034 break;
4035 }
4036
4037 case EW_STRCMP:
4038 {
4039 if (params[4] != 0)
4040 s += 'S';
4041 AddParams(params, 2);
4042 Add_GotoVars2(¶ms[2]);
4043 break;
4044 }
4045
4046 case EW_READENVSTR:
4047 {
4048 s += (params[2] != 0) ?
4049 "ReadEnvStr" :
4050 "ExpandEnvStrings";
4051 AddParam_Var(params[0]);
4052 AString temp;
4053 ReadString2(temp, params[1]);
4054 if (params[2] != 0 &&temp.Len() >= 2 && temp[0] == '%' && temp.Back() == '%')
4055 {
4056 temp.DeleteBack();
4057 temp.Delete(0);
4058 }
4059 SpaceQuStr(temp);
4060 break;
4061 }
4062
4063 case EW_INTCMP:
4064 {
4065 s += "Int";
4066 const UInt32 param5 = params[5];
4067 if (param5 & 0x8000)
4068 s += "64"; // v3.03+
4069 s += "Cmp";
4070 if (IsNsis3_OrHigher() ? (param5 & 1) : (param5 != 0))
4071 s += 'U';
4072 AddParams(params, 2);
4073 Add_GotoVar1(params[2]);
4074 if (params[3] != 0 || params[4] != 0)
4075 Add_GotoVars2(params + 3);
4076 break;
4077 }
4078
4079 case EW_INTOP:
4080 {
4081 AddParam_Var(params[0]);
4082 const char * const kOps = "+-*/|&^!|&%<>>"; // NSIS 2.01+
4083 // "+-*/|&^!|&%"; // NSIS 2.0b4+
4084 // "+-*/|&^~!|&%"; // NSIS old
4085 const UInt32 opIndex = params[3];
4086 const char c = (opIndex < 14) ? kOps[opIndex] : '?';
4087 const char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c;
4088 const int numOps = (opIndex == 7) ? 1 : 2;
4089 AddParam(params[1]);
4090 if (numOps == 2 && c == '^' && IsDirectString_Equal(params[2], "0xFFFFFFFF"))
4091 s += " ~ ;";
4092 Space();
4093 s += c;
4094 if (numOps != 1)
4095 {
4096 if (opIndex == 13) // v3.03+ : operation ">>>"
4097 s += c;
4098 if (c2 != 0)
4099 s += c2;
4100 AddParam(params[2]);
4101 }
4102 break;
4103 }
4104
4105 case EW_INTFMT:
4106 {
4107 if (params[3])
4108 s += "Int64Fmt"; // v3.03+
4109 else
4110 s += "IntFmt";
4111 AddParam_Var(params[0]);
4112 AddParams(params + 1, 2);
4113 break;
4114 }
4115
4116 case EW_PUSHPOP:
4117 {
4118 if (params[2] != 0)
4119 {
4120 s += "Exch";
4121 if (params[2] != 1)
4122 AddParam_UInt(params[2]);
4123 }
4124 else if (params[1] != 0)
4125 {
4126 s += "Pop";
4127 AddParam_Var(params[0]);
4128 }
4129 else
4130 {
4131 if (NoLabels(labels + kkk + 1, 2)
4132 && Get32(p + kCmdSize) == EW_PUSHPOP // Exch"
4133 && GET_CMD_PARAM(p + kCmdSize, 2) == 1
4134 && Get32(p + kCmdSize * 2) == EW_PUSHPOP // Pop $VAR
4135 && GET_CMD_PARAM(p + kCmdSize * 2, 1) != 0)
4136 {
4137 if (IsVarStr(params[0], GET_CMD_PARAM(p + kCmdSize * 2, 0)))
4138 {
4139 s += "Exch";
4140 AddParam(params[0]);
4141 NewLine();
4142 Tab(true);
4143 endCommentIndex = kkk + 3;
4144 }
4145 }
4146 s += "Push";
4147 AddParam(params[0]);
4148 }
4149 break;
4150 }
4151
4152 case EW_FINDWINDOW:
4153 {
4154 AddParam_Var(params[0]);
4155 AddParam(params[1]);
4156 AddOptionalParams(params + 2, 3);
4157 break;
4158 }
4159
4160 case EW_SENDMESSAGE:
4161 {
4162 // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
4163 AddParam(params[1]);
4164
4165 const char *w = NULL;
4166 AString t;
4167 ReadString2(t, params[2]);
4168 UInt32 wm;
4169 if (StringToUInt32(t, wm))
4170 {
4171 switch (wm)
4172 {
4173 case 0x0C: w = "SETTEXT"; break;
4174 case 0x10: w = "CLOSE"; break;
4175 case 0x30: w = "SETFONT"; break;
4176 }
4177 }
4178 if (w)
4179 {
4180 s += " ${WM_";
4181 s += w;
4182 s += '}';
4183 }
4184 else
4185 SpaceQuStr(t);
4186
4187 UInt32 spec = params[5];
4188 for (unsigned i = 0; i < 2; i++)
4189 {
4190 AString s2;
4191 if (spec & ((UInt32)1 << i))
4192 s2 += "STR:";
4193 ReadString2(s2, params[3 + i]);
4194 SpaceQuStr(s2);
4195 }
4196
4197 if ((Int32)params[0] >= 0)
4198 AddParam_Var(params[0]);
4199
4200 spec >>= 2;
4201 if (spec != 0)
4202 {
4203 s += " /TIMEOUT=";
4204 Add_UInt(spec);
4205 }
4206 break;
4207 }
4208
4209 case EW_ISWINDOW:
4210 {
4211 AddParam(params[0]);
4212 Add_GotoVars2(¶ms[1]);
4213 break;
4214 }
4215
4216 case EW_GETDLGITEM:
4217 {
4218 AddParam_Var(params[0]);
4219 AddParams(params + 1, 2);
4220 break;
4221 }
4222
4223 case EW_SETCTLCOLORS:
4224 {
4225 AddParam(params[0]);
4226
4227 UInt32 offset = params[1];
4228
4229 if (_size < bhCtlColors.Offset
4230 || _size - bhCtlColors.Offset < offset
4231 || _size - bhCtlColors.Offset - offset < GET_CtlColors_SIZE(Is64Bit))
4232 {
4233 AddError("bad offset");
4234 break;
4235 }
4236
4237 const Byte *p2 = _data + bhCtlColors.Offset + offset;
4238 CNsis_CtlColors colors;
4239 colors.Parse(p2, Is64Bit);
4240
4241 if ((colors.flags & kColorsFlags_BK_SYS) != 0 ||
4242 (colors.flags & kColorsFlags_TEXT_SYS) != 0)
4243 s += " /BRANDING";
4244
4245 AString bk;
4246 bool bkc = false;
4247 if (colors.bkmode == MY__TRANSPARENT)
4248 bk += " transparent";
4249 else if (colors.flags & kColorsFlags_BKB)
4250 {
4251 if ((colors.flags & kColorsFlags_BK_SYS) == 0 &&
4252 (colors.flags & kColorsFlags_BK) != 0)
4253 bkc = true;
4254 }
4255 if ((colors.flags & kColorsFlags_TEXT) != 0 || !bk.IsEmpty() || bkc)
4256 {
4257 Space();
4258 if ((colors.flags & kColorsFlags_TEXT_SYS) != 0 || (colors.flags & kColorsFlags_TEXT) == 0)
4259 AddQuotes();
4260 else
4261 Add_Color(colors.text);
4262 }
4263 s += bk;
4264 if (bkc)
4265 {
4266 Space();
4267 Add_Color(colors.bkc);
4268 }
4269
4270 break;
4271 }
4272
4273 // case EW_LOADANDSETIMAGE:
4274 case EW_SETBRANDINGIMAGE:
4275 {
4276 s += " /IMGID=";
4277 Add_UInt(params[1]);
4278 if (params[2] == 1)
4279 s += " /RESIZETOFIT";
4280 AddParam(params[0]);
4281 break;
4282 }
4283
4284 case EW_CREATEFONT:
4285 {
4286 AddParam_Var(params[0]);
4287 AddParam(params[1]);
4288 AddOptionalParams(params + 2, 2);
4289 if (params[4] & 1) s += " /ITALIC";
4290 if (params[4] & 2) s += " /UNDERLINE";
4291 if (params[4] & 4) s += " /STRIKE";
4292 break;
4293 }
4294
4295 case EW_SHOWWINDOW:
4296 {
4297 AString hw, sw;
4298 ReadString2(hw, params[0]);
4299 ReadString2(sw, params[1]);
4300 if (params[3] != 0)
4301 s += "EnableWindow";
4302 else
4303 {
4304 UInt32 val;
4305 bool valDefined = false;
4306 if (StringToUInt32(sw, val))
4307 {
4308 if (val < ARRAY_SIZE(kShowWindow_Commands))
4309 {
4310 sw.Empty();
4311 sw += "${";
4312 Add_ShowWindow_Cmd_2(sw, val);
4313 sw += '}';
4314 valDefined = true;
4315 }
4316 }
4317 bool isHwndParent = IsVarStr(params[0], IsNsis225 ? kVar_HWNDPARENT_225 : kVar_HWNDPARENT);
4318 if (params[2] != 0)
4319 {
4320 if (valDefined && val == 0 && isHwndParent)
4321 {
4322 s += "HideWindow";
4323 break;
4324 }
4325 }
4326 if (valDefined && val == 5 && isHwndParent &&
4327 kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_BRINGTOFRONT)
4328 {
4329 s += " ; ";
4330 }
4331 s += "ShowWindow";
4332 }
4333 SpaceQuStr(hw);
4334 SpaceQuStr(sw);
4335 break;
4336 }
4337
4338 case EW_SHELLEXEC:
4339 {
4340 AddParams(params, 2);
4341 if (params[2] != 0 || params[3] != MY__SW_SHOWNORMAL)
4342 {
4343 AddParam(params[2]);
4344 if (params[3] != MY__SW_SHOWNORMAL)
4345 {
4346 Space();
4347 Add_ShowWindow_Cmd(params[3]);
4348 }
4349 }
4350 if (params[5] != 0)
4351 {
4352 s += " ;";
4353 AddParam(params[5]); // it's tatus text update
4354 }
4355 break;
4356 }
4357
4358 case EW_EXECUTE:
4359 {
4360 if (params[2] != 0)
4361 s += "Wait";
4362 AddParam(params[0]);
4363 if (params[2] != 0)
4364 if ((Int32)params[1] >= 0)
4365 AddParam_Var(params[1]);
4366 break;
4367 }
4368
4369 case EW_GETFILETIME:
4370 case EW_GETDLLVERSION:
4371 {
4372 if (commandId == EW_GETDLLVERSION)
4373 if (params[3] == 2)
4374 s += " /ProductVersion"; // v3.08+
4375 AddParam(params[2]);
4376 AddParam_Var(params[0]);
4377 AddParam_Var(params[1]);
4378 break;
4379 }
4380
4381 case EW_REGISTERDLL:
4382 {
4383 AString func;
4384 ReadString2(func, params[1]);
4385 bool printFunc = true;
4386 // params[4] = 1; for plugin command
4387 if (params[2] == 0)
4388 {
4389 s += "CallInstDLL";
4390 AddParam(params[0]);
4391 if (params[3] == 1)
4392 s += " /NOUNLOAD";
4393 }
4394 else
4395 {
4396 if (func == "DllUnregisterServer")
4397 {
4398 s += "UnRegDLL";
4399 printFunc = false;
4400 }
4401 else
4402 {
4403 s += "RegDLL";
4404 if (func == "DllRegisterServer")
4405 printFunc = false;
4406 }
4407 AddParam(params[0]);
4408 }
4409 if (printFunc)
4410 SpaceQuStr(func);
4411 break;
4412 }
4413
4414 case EW_CREATESHORTCUT:
4415 {
4416 unsigned numParams;
4417 #define IsNsis3d0b3_OrHigher() 0 // change it
4418 const unsigned v3_0b3 = IsNsis3d0b3_OrHigher();
4419 for (numParams = 6; numParams > 2; numParams--)
4420 if (params[numParams - 1] != 0)
4421 break;
4422
4423 const UInt32 spec = params[4];
4424 const unsigned sw_shift = v3_0b3 ? 12 : 8;
4425 const UInt32 sw_mask = v3_0b3 ? 0x7000 : 0x7F;
4426 if (spec & 0x8000) // NSIS 3.0b0
4427 s += " /NoWorkingDir";
4428
4429 AddParams(params, numParams > 4 ? 4 : numParams);
4430 if (numParams <= 4)
4431 break;
4432
4433 UInt32 icon = (spec & (v3_0b3 ? 0xFFF : 0xFF));
4434 Space();
4435 if (icon != 0)
4436 Add_UInt(icon);
4437 else
4438 AddQuotes();
4439
4440 if ((spec >> sw_shift) == 0 && numParams < 6)
4441 break;
4442 UInt32 sw = (spec >> sw_shift) & sw_mask;
4443 Space();
4444 // NSIS encoder replaces these names:
4445 if (sw == MY__SW_SHOWMINNOACTIVE)
4446 sw = MY__SW_SHOWMINIMIZED;
4447 if (sw == 0)
4448 AddQuotes();
4449 else
4450 Add_ShowWindow_Cmd(sw);
4451
4452 UInt32 modKey = spec >> 24;
4453 UInt32 key = (spec >> 16) & 0xFF;
4454
4455 if (modKey == 0 && key == 0)
4456 {
4457 if (numParams < 6)
4458 break;
4459 Space();
4460 AddQuotes();
4461 }
4462 else
4463 {
4464 Space();
4465 if (modKey & 1) s += "SHIFT|"; // HOTKEYF_SHIFT
4466 if (modKey & 2) s += "CONTROL|";
4467 if (modKey & 4) s += "ALT|";
4468 if (modKey & 8) s += "EXT|";
4469
4470 static const unsigned kMy_VK_F1 = 0x70;
4471 if (key >= kMy_VK_F1 && key <= kMy_VK_F1 + 23)
4472 {
4473 s += 'F';
4474 Add_UInt(key - kMy_VK_F1 + 1);
4475 }
4476 else if ((key >= 'A' && key <= 'Z') || (key >= '0' && key <= '9'))
4477 s += (char)key;
4478 else
4479 {
4480 s += "Char_";
4481 Add_UInt(key);
4482 }
4483 }
4484 AddOptionalParam(params[5]); // description
4485 break;
4486 }
4487
4488 case EW_COPYFILES:
4489 {
4490 if (params[2] & 0x04) s += " /SILENT"; // FOF_SILENT
4491 if (params[2] & 0x80) s += " /FILESONLY"; // FOF_FILESONLY
4492 AddParams(params, 2);
4493 if (params[3] != 0)
4494 {
4495 s += " ;";
4496 AddParam(params[3]); // status text update
4497 }
4498 break;
4499 }
4500
4501 case EW_REBOOT:
4502 {
4503 if (params[0] != 0xbadf00d)
4504 s += " ; Corrupted ???";
4505 else if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_QUIT)
4506 endCommentIndex = kkk + 2;
4507 break;
4508 }
4509
4510 case EW_WRITEINI:
4511 {
4512 unsigned numAlwaysParams = 0;
4513 if (params[0] == 0) // Section
4514 s += "FlushINI";
4515 else if (params[4] != 0)
4516 {
4517 s += "WriteINIStr";
4518 numAlwaysParams = 3;
4519 }
4520 else
4521 {
4522 s += "DeleteINI";
4523 s += (params[1] == 0) ? "Sec" : "Str";
4524 numAlwaysParams = 1;
4525 }
4526 AddParam(params[3]); // filename
4527 // Section, EntryName, Value
4528 AddParams(params, numAlwaysParams);
4529 AddOptionalParams(params + numAlwaysParams, 3 - numAlwaysParams);
4530 break;
4531 }
4532
4533 case EW_READINISTR:
4534 {
4535 AddParam_Var(params[0]);
4536 AddParam(params[3]); // FileName
4537 AddParams(params +1, 2); // Section, EntryName
4538 break;
4539 }
4540
4541 case EW_DELREG:
4542 {
4543 // NSIS 2.00 used another scheme!
4544
4545 if (params[4] == 0)
4546 s += "Value";
4547 else
4548 {
4549 s += "Key";
4550 if (params[4] & 2)
4551 s += " /ifempty";
4552 // TODO: /ifnosubkeys, /ifnovalues
4553 }
4554 AddRegRoot(params[1]);
4555 AddParam(params[2]);
4556 AddOptionalParam(params[3]);
4557 break;
4558 }
4559
4560 case EW_WRITEREG:
4561 {
4562 const char *s2 = 0;
4563 switch (params[4])
4564 {
4565 case 1: s2 = "Str"; break;
4566 case 2: s2 = "ExpandStr"; break; // maybe unused
4567 case 3: s2 = "Bin"; break;
4568 case 4: s2 = "DWORD"; break;
4569 default:
4570 s += '?';
4571 Add_UInt(params[4]);
4572 }
4573 if (params[4] == 1 && params[5] == 2)
4574 s2 = "ExpandStr";
4575 if (params[4] == 3 && params[5] == 7)
4576 s2 = "MultiStr"; // v3.02+
4577 if (s2)
4578 s += s2;
4579 AddRegRoot(params[0]);
4580 AddParams(params + 1, 2); // keyName, valueName
4581 if (params[4] != 3)
4582 AddParam(params[3]); // value
4583 else
4584 {
4585 // Binary data.
4586 Space();
4587 UInt32 offset = params[3];
4588 bool isSupported = false;
4589 if (AfterHeaderSize >= 4
4590 && bhData.Offset <= AfterHeaderSize - 4
4591 && offset <= AfterHeaderSize - 4 - bhData.Offset)
4592 {
4593 // we support it for solid archives.
4594 const Byte *p2 = _afterHeader + bhData.Offset + offset;
4595 UInt32 size = Get32(p2);
4596 if (size <= AfterHeaderSize - 4 - bhData.Offset - offset)
4597 {
4598 for (UInt32 i = 0; i < size; i++)
4599 {
4600 Byte b = (p2 + 4)[i];
4601 unsigned t;
4602 t = (b >> 4); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
4603 t = (b & 15); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
4604 }
4605 isSupported = true;
4606 }
4607 }
4608 if (!isSupported)
4609 {
4610 // we must read from file here;
4611 s += "data[";
4612 Add_UInt(offset);
4613 s += " ... ]";
4614 s += " ; !!! Unsupported";
4615 }
4616 }
4617 break;
4618 }
4619
4620 case EW_READREGSTR:
4621 {
4622 s += (params[4] == 1) ? "DWORD" : "Str";
4623 AddParam_Var(params[0]);
4624 AddRegRoot(params[1]);
4625 AddParams(params + 2, 2);
4626 break;
4627 }
4628
4629 case EW_REGENUM:
4630 {
4631 s += (params[4] != 0) ? "Key" : "Value";
4632 AddParam_Var(params[0]);
4633 AddRegRoot(params[1]);
4634 AddParams(params + 2, 2);
4635 break;
4636 }
4637
4638 case EW_FCLOSE:
4639 case EW_FINDCLOSE:
4640 {
4641 AddParam_Var(params[0]);
4642 break;
4643 }
4644
4645 case EW_FOPEN:
4646 {
4647 AddParam_Var(params[0]);
4648 AddParam(params[3]);
4649 UInt32 acc = params[1]; // dwDesiredAccess
4650 UInt32 creat = params[2]; // dwCreationDisposition
4651 if (acc == 0 && creat == 0)
4652 break;
4653 char cc = 0;
4654 if (acc == MY__GENERIC_READ && creat == OPEN_EXISTING)
4655 cc = 'r';
4656 else if (creat == CREATE_ALWAYS && acc == MY__GENERIC_WRITE)
4657 cc = 'w';
4658 else if (creat == OPEN_ALWAYS && (acc == (MY__GENERIC_WRITE | MY__GENERIC_READ)))
4659 cc = 'a';
4660 // cc = 0;
4661 if (cc != 0)
4662 {
4663 Space();
4664 s += cc;
4665 break;
4666 }
4667
4668 if (acc & MY__GENERIC_READ) s += " GENERIC_READ";
4669 if (acc & MY__GENERIC_WRITE) s += " GENERIC_WRITE";
4670 if (acc & MY__GENERIC_EXECUTE) s += " GENERIC_EXECUTE";
4671 if (acc & MY__GENERIC_ALL) s += " GENERIC_ALL";
4672
4673 const char *s2 = NULL;
4674 switch (creat)
4675 {
4676 case MY__CREATE_NEW: s2 = "CREATE_NEW"; break;
4677 case MY__CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break;
4678 case MY__OPEN_EXISTING: s2 = "OPEN_EXISTING"; break;
4679 case MY__OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break;
4680 case MY__TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break;
4681 }
4682 Space();
4683 if (s2)
4684 s += s2;
4685 else
4686 Add_UInt(creat);
4687 break;
4688 }
4689
4690 case EW_FPUTS:
4691 case EW_FPUTWS:
4692 {
4693 if (commandId == EW_FPUTWS)
4694 s += (params[2] == 0) ? "UTF16LE" : "Word";
4695 else if (params[2] != 0)
4696 s += "Byte";
4697 if (params[2] == 0 && params[3])
4698 s += " /BOM"; // v3.0b3+
4699 AddParam_Var(params[0]);
4700 AddParam(params[1]);
4701 break;
4702 }
4703
4704 case EW_FGETS:
4705 case EW_FGETWS:
4706 {
4707 if (commandId == EW_FPUTWS)
4708 s += (params[3] == 0) ? "UTF16LE" : "Word";
4709 if (params[3] != 0)
4710 s += "Byte";
4711 AddParam_Var(params[0]);
4712 AddParam_Var(params[1]);
4713 AString maxLenStr;
4714 ReadString2(maxLenStr, params[2]);
4715 UInt32 maxLen;
4716 if (StringToUInt32(maxLenStr, maxLen))
4717 {
4718 if (maxLen == 1 && params[3] != 0)
4719 break;
4720 if (maxLen == 1023 && params[3] == 0) // NSIS_MAX_STRLEN - 1; can be other value!!
4721 break;
4722 }
4723 SpaceQuStr(maxLenStr);
4724 break;
4725 }
4726
4727 case EW_FSEEK:
4728 {
4729 AddParam_Var(params[0]);
4730 AddParam(params[2]);
4731 if (params[3] == 1) s += " CUR"; // FILE_CURRENT
4732 if (params[3] == 2) s += " END"; // FILE_END
4733 if ((Int32)params[1] >= 0)
4734 {
4735 if (params[3] == 0) s += " SET"; // FILE_BEGIN
4736 AddParam_Var(params[1]);
4737 }
4738 break;
4739 }
4740
4741 case EW_FINDNEXT:
4742 {
4743 AddParam_Var(params[1]);
4744 AddParam_Var(params[0]);
4745 break;
4746 }
4747
4748 case EW_FINDFIRST:
4749 {
4750 AddParam_Var(params[1]);
4751 AddParam_Var(params[0]);
4752 AddParam(params[2]);
4753 break;
4754 }
4755
4756 case EW_LOG:
4757 {
4758 if (params[0] != 0)
4759 {
4760 s += "Set ";
4761 s += (params[1] == 0) ? "off" : "on";
4762 }
4763 else
4764 {
4765 s += "Text";
4766 AddParam(params[1]);
4767 }
4768 break;
4769 }
4770
4771 case EW_SECTIONSET:
4772 {
4773 if ((Int32)params[2] >= 0)
4774 {
4775 s += "Get";
4776 Add_SectOp(params[2]);
4777 AddParam(params[0]);
4778 AddParam_Var(params[1]);
4779 }
4780 else
4781 {
4782 s += "Set";
4783 UInt32 t = -(Int32)params[2] - 1;
4784 Add_SectOp(t);
4785 AddParam(params[0]);
4786 AddParam(params[t == 0 ? 4 : 1]);
4787
4788 // params[3] != 0 means call SectionFlagsChanged in installer
4789 // used by SECTIONSETFLAGS command
4790 }
4791 break;
4792 }
4793
4794 case EW_INSTTYPESET:
4795 {
4796 int numQwParams = 0;
4797 const char *s2;
4798 if (params[3] == 0)
4799 {
4800 if (params[2] == 0)
4801 {
4802 s2 = "InstTypeGetText";
4803 numQwParams = 1;
4804 }
4805 else
4806 {
4807 s2 = "InstTypeSetText";
4808 numQwParams = 2;
4809 }
4810 }
4811 else
4812 {
4813 if (params[2] == 0)
4814 s2 = "GetCurInstType";
4815 else
4816 {
4817 s2 = "SetCurInstType";
4818 numQwParams = 1;
4819 }
4820 }
4821 s += s2;
4822 AddParams(params, numQwParams);
4823 if (params[2] == 0)
4824 AddParam_Var(params[1]);
4825 break;
4826 }
4827
4828 case EW_GETOSINFO:
4829 {
4830 if (IsNsis3_OrHigher())
4831 {
4832 // v3.06+
4833 if (params[3] == 0) // GETOSINFO_KNOWNFOLDER
4834 {
4835 s += "GetKnownFolderPath";
4836 AddParam_Var(params[1]);
4837 AddParam(params[2]);
4838 break;
4839 }
4840 else if (params[3] == 1) // GETOSINFO_READMEMORY
4841 {
4842 s += "ReadMemory";
4843 AddParam_Var(params[1]);
4844 AddParam(params[2]);
4845 AddParam(params[4]);
4846 // if (params[2] == "0") AddCommentAndString("GetWinVer");
4847 }
4848 else
4849 s += "GetOsInfo";
4850 break;
4851 }
4852 s += "GetLabelAddr"; // before v3.06+
4853 break;
4854 }
4855
4856 case EW_LOCKWINDOW:
4857 {
4858 s += (params[0] == 0) ? " on" : " off";
4859 break;
4860 }
4861
4862 case EW_FINDPROC:
4863 {
4864 AddParam_Var(params[0]);
4865 AddParam(params[1]);
4866 break;
4867 }
4868
4869 default:
4870 {
4871 numSkipParams = 0;
4872 }
4873 #endif
4874 }
4875
4876 #ifdef NSIS_SCRIPT
4877
4878 unsigned numParams = kNumCommandParams;
4879
4880 for (; numParams > 0; numParams--)
4881 if (params[numParams - 1] != 0)
4882 break;
4883
4884 if (numParams > numSkipParams)
4885 {
4886 s += " ; !!!! Unknown Params: ";
4887 unsigned i;
4888 for (i = 0; i < numParams; i++)
4889 AddParam(params[i]);
4890
4891 s += " ;";
4892
4893 for (i = 0; i < numParams; i++)
4894 {
4895 Space();
4896 UInt32 v = params[i];
4897 if (v > 0xFFF00000)
4898 Add_SignedInt(s, (Int32)v);
4899 else
4900 Add_UInt(v);
4901 }
4902 }
4903
4904 NewLine();
4905
4906 #endif
4907 }
4908
4909 #ifdef NSIS_SCRIPT
4910
4911 if (sectionIsOpen)
4912 {
4913 if (curSectionIndex < bhSections.Num)
4914 {
4915 const CSection § = Sections[curSectionIndex];
4916 if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk)
4917 {
4918 PrintSectionEnd();
4919 sectionIsOpen = false;
4920 // lastSectionEndCmd = kkk;
4921 curSectionIndex++;
4922 }
4923 }
4924 }
4925
4926 while (curSectionIndex < bhSections.Num)
4927 {
4928 const CSection § = Sections[curSectionIndex];
4929 if (sectionIsOpen)
4930 {
4931 if (sect.StartCmdIndex + sect.NumCommands != kkk)
4932 AddErrorLF("SECTION ERROR");
4933 PrintSectionEnd();
4934 sectionIsOpen = false;
4935 curSectionIndex++;
4936 }
4937 else
4938 {
4939 if (PrintSectionBegin(sect, curSectionIndex))
4940 curSectionIndex++;
4941 else
4942 sectionIsOpen = true;
4943 }
4944 }
4945
4946 #endif
4947
4948 return S_OK;
4949 }
4950
CompareItems(void * const * p1,void * const * p2,void * param)4951 static int CompareItems(void *const *p1, void *const *p2, void *param)
4952 {
4953 const CItem &i1 = **(const CItem *const *)p1;
4954 const CItem &i2 = **(const CItem *const *)p2;
4955 RINOZ(MyCompare(i1.Pos, i2.Pos));
4956 const CInArchive *inArchive = (const CInArchive *)param;
4957 if (inArchive->IsUnicode)
4958 {
4959 if (i1.Prefix != i2.Prefix)
4960 {
4961 if (i1.Prefix < 0) return -1;
4962 if (i2.Prefix < 0) return 1;
4963 RINOZ(
4964 inArchive->UPrefixes[i1.Prefix].Compare(
4965 inArchive->UPrefixes[i2.Prefix]));
4966 }
4967 RINOZ(i1.NameU.Compare(i2.NameU));
4968 }
4969 else
4970 {
4971 if (i1.Prefix != i2.Prefix)
4972 {
4973 if (i1.Prefix < 0) return -1;
4974 if (i2.Prefix < 0) return 1;
4975 RINOZ(strcmp(
4976 inArchive->APrefixes[i1.Prefix],
4977 inArchive->APrefixes[i2.Prefix]));
4978 }
4979 RINOZ(strcmp(i1.NameA, i2.NameA));
4980 }
4981 return 0;
4982 }
4983
SortItems()4984 HRESULT CInArchive::SortItems()
4985 {
4986 {
4987 Items.Sort(CompareItems, (void *)this);
4988 unsigned i;
4989
4990 for (i = 0; i + 1 < Items.Size(); i++)
4991 {
4992 const CItem &i1 = Items[i];
4993 const CItem &i2 = Items[i + 1];
4994 if (i1.Pos != i2.Pos)
4995 continue;
4996
4997 if (IsUnicode)
4998 {
4999 if (i1.NameU != i2.NameU) continue;
5000 if (i1.Prefix != i2.Prefix)
5001 {
5002 if (i1.Prefix < 0 || i2.Prefix < 0) continue;
5003 if (UPrefixes[i1.Prefix] != UPrefixes[i2.Prefix]) continue;
5004 }
5005 }
5006 else
5007 {
5008 if (i1.NameA != i2.NameA) continue;
5009 if (i1.Prefix != i2.Prefix)
5010 {
5011 if (i1.Prefix < 0 || i2.Prefix < 0) continue;
5012 if (APrefixes[i1.Prefix] != APrefixes[i2.Prefix]) continue;
5013 }
5014 }
5015 Items.Delete(i + 1);
5016 i--;
5017 }
5018
5019 for (i = 0; i < Items.Size(); i++)
5020 {
5021 CItem &item = Items[i];
5022 UInt32 curPos = item.Pos + 4;
5023 for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++)
5024 {
5025 UInt32 nextPos = Items[nextIndex].Pos;
5026 if (curPos <= nextPos)
5027 {
5028 item.EstimatedSize_Defined = true;
5029 item.EstimatedSize = nextPos - curPos;
5030 break;
5031 }
5032 }
5033 }
5034
5035 if (!IsSolid)
5036 {
5037 for (i = 0; i < Items.Size(); i++)
5038 {
5039 CItem &item = Items[i];
5040 RINOK(SeekToNonSolidItem(i));
5041 const UInt32 kSigSize = 4 + 1 + 1 + 4; // size,[flag],prop,dict
5042 BYTE sig[kSigSize];
5043 size_t processedSize = kSigSize;
5044 RINOK(ReadStream(_stream, sig, &processedSize));
5045 if (processedSize < 4)
5046 return S_FALSE;
5047 UInt32 size = Get32(sig);
5048 if ((size & kMask_IsCompressed) != 0)
5049 {
5050 item.IsCompressed = true;
5051 size &= ~kMask_IsCompressed;
5052 if (Method == NMethodType::kLZMA)
5053 {
5054 if (processedSize < 9)
5055 return S_FALSE;
5056 /*
5057 if (FilterFlag)
5058 item.UseFilter = (sig[4] != 0);
5059 */
5060 item.DictionarySize = Get32(sig + 4 + 1 + (FilterFlag ? 1 : 0));
5061 }
5062 }
5063 else
5064 {
5065 item.IsCompressed = false;
5066 item.Size = size;
5067 item.Size_Defined = true;
5068 }
5069 item.CompressedSize = size;
5070 item.CompressedSize_Defined = true;
5071 }
5072 }
5073 }
5074 return S_OK;
5075 }
5076
5077 #ifdef NSIS_SCRIPT
5078 // Flags for common_header.flags
5079 // #define CH_FLAGS_DETAILS_SHOWDETAILS 1
5080 // #define CH_FLAGS_DETAILS_NEVERSHOW 2
5081 #define CH_FLAGS_PROGRESS_COLORED 4
5082 #define CH_FLAGS_SILENT 8
5083 #define CH_FLAGS_SILENT_LOG 16
5084 #define CH_FLAGS_AUTO_CLOSE 32
5085 // #define CH_FLAGS_DIR_NO_SHOW 64 // unused now
5086 #define CH_FLAGS_NO_ROOT_DIR 128
5087 #define CH_FLAGS_COMP_ONLY_ON_CUSTOM 256
5088 #define CH_FLAGS_NO_CUSTOM 512
5089
5090 static const char * const k_PostStrings[] =
5091 {
5092 "install_directory_auto_append"
5093 , "uninstchild" // NSIS 2.25+, used by uninstaller:
5094 , "uninstcmd" // NSIS 2.25+, used by uninstaller:
5095 , "wininit" // NSIS 2.25+, used by move file on reboot
5096 };
5097 #endif
5098
5099
Parse(const Byte * p,unsigned bhoSize)5100 void CBlockHeader::Parse(const Byte *p, unsigned bhoSize)
5101 {
5102 if (bhoSize == 12)
5103 {
5104 // UInt64 a = GetUi64(p);
5105 if (GetUi32(p + 4) != 0)
5106 throw 1;
5107 }
5108 Offset = GetUi32(p);
5109 Num = GetUi32(p + bhoSize - 4);
5110 }
5111
5112 #define PARSE_BH(k, bh) bh.Parse (p1 + 4 + bhoSize * k, bhoSize)
5113
5114
Parse()5115 HRESULT CInArchive::Parse()
5116 {
5117 // UInt32 offset = ReadUInt32();
5118 // ???? offset == FirstHeader.HeaderSize
5119 const Byte * const p1 = _data;
5120
5121 if (_size < 4 + 12 * 8)
5122 Is64Bit = false;
5123 else
5124 {
5125 Is64Bit = true;
5126 // here we test high 32-bit of possible UInt64 CBlockHeader::Offset field
5127 for (int k = 0; k < 8; k++)
5128 if (GetUi32(p1 + 4 + 12 * k + 4) != 0)
5129 Is64Bit = false;
5130 }
5131
5132 const unsigned bhoSize = Is64Bit ? 12 : 8;
5133 if (_size < 4 + bhoSize * 8)
5134 return S_FALSE;
5135
5136 CBlockHeader bhEntries, bhStrings, bhLangTables;
5137
5138 PARSE_BH (2, bhEntries);
5139 PARSE_BH (3, bhStrings);
5140 PARSE_BH (4, bhLangTables);
5141
5142 #ifdef NSIS_SCRIPT
5143
5144 CBlockHeader bhFont;
5145 PARSE_BH (0, bhPages);
5146 PARSE_BH (1, bhSections);
5147 PARSE_BH (5, bhCtlColors);
5148 PARSE_BH (6, bhFont);
5149 PARSE_BH (7, bhData);
5150
5151 #endif
5152
5153 _stringsPos = bhStrings.Offset;
5154 if (_stringsPos > _size
5155 || bhLangTables.Offset > _size
5156 || bhEntries.Offset > _size)
5157 return S_FALSE;
5158 {
5159 if (bhLangTables.Offset < bhStrings.Offset)
5160 return S_FALSE;
5161 const UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset;
5162 if (stringTableSize < 2)
5163 return S_FALSE;
5164 const Byte *strData = _data + _stringsPos;
5165 if (strData[stringTableSize - 1] != 0)
5166 return S_FALSE;
5167 IsUnicode = (Get16(strData) == 0);
5168 NumStringChars = stringTableSize;
5169 if (IsUnicode)
5170 {
5171 if ((stringTableSize & 1) != 0)
5172 return S_FALSE;
5173 NumStringChars >>= 1;
5174 if (strData[stringTableSize - 2] != 0)
5175 return S_FALSE;
5176 }
5177 }
5178
5179 if (bhEntries.Num > (1 << 25))
5180 return S_FALSE;
5181 if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset)
5182 return S_FALSE;
5183
5184 DetectNsisType(bhEntries, _data + bhEntries.Offset);
5185
5186 Decoder.IsNsisDeflate = (NsisType != k_NsisType_Nsis3);
5187
5188 // some NSIS files (that are not detected as k_NsisType_Nsis3)
5189 // use original (non-NSIS) Deflate
5190 // How to detect these cases?
5191
5192 // Decoder.IsNsisDeflate = false;
5193
5194
5195 #ifdef NSIS_SCRIPT
5196
5197 {
5198 AddCommentAndString("NSIS script");
5199 if (IsUnicode)
5200 Script += " (UTF-8)";
5201 Space();
5202 Script += GetFormatDescription();
5203 AddLF();
5204 }
5205 {
5206 AddCommentAndString(IsInstaller ? "Install" : "Uninstall");
5207 AddLF();
5208 }
5209
5210 AddLF();
5211 if (Is64Bit)
5212 AddStringLF("Target AMD64-Unicode"); // TODO: Read PE machine type and use the correct CPU type
5213 else if (IsUnicode)
5214 AddStringLF("Unicode true");
5215 else if (IsNsis3_OrHigher())
5216 AddStringLF("Unicode false"); // Unicode is the default in 3.07+
5217
5218 if (Method != NMethodType::kCopy)
5219 {
5220 const char *m = NULL;
5221 switch (Method)
5222 {
5223 case NMethodType::kDeflate: m = "zlib"; break;
5224 case NMethodType::kBZip2: m = "bzip2"; break;
5225 case NMethodType::kLZMA: m = "lzma"; break;
5226 default: break;
5227 }
5228 Script += "SetCompressor";
5229 if (IsSolid)
5230 Script += " /SOLID";
5231 if (m)
5232 {
5233 Space();
5234 Script += m;
5235 }
5236 AddLF();
5237 }
5238 if (Method == NMethodType::kLZMA)
5239 {
5240 // if (DictionarySize != (8 << 20))
5241 {
5242 Script += "SetCompressorDictSize";
5243 AddParam_UInt(DictionarySize >> 20);
5244 AddLF();
5245 }
5246 }
5247
5248 Separator();
5249 PrintNumComment("HEADER SIZE", FirstHeader.HeaderSize);
5250 // if (bhPages.Offset != 300 && bhPages.Offset != 288)
5251 if (bhPages.Offset != 0)
5252 {
5253 PrintNumComment("START HEADER SIZE", bhPages.Offset);
5254 }
5255
5256 if (bhSections.Num > 0)
5257 {
5258 if (bhEntries.Offset < bhSections.Offset)
5259 return S_FALSE;
5260 SectionSize = (bhEntries.Offset - bhSections.Offset) / bhSections.Num;
5261 if (bhSections.Offset + bhSections.Num * SectionSize != bhEntries.Offset)
5262 return S_FALSE;
5263 if (SectionSize < kSectionSize_base)
5264 return S_FALSE;
5265 UInt32 maxStringLen = SectionSize - kSectionSize_base;
5266 if (IsUnicode)
5267 {
5268 if ((maxStringLen & 1) != 0)
5269 return S_FALSE;
5270 maxStringLen >>= 1;
5271 }
5272 // if (maxStringLen != 1024)
5273 {
5274 if (maxStringLen == 0)
5275 PrintNumComment("SECTION SIZE", SectionSize);
5276 else
5277 PrintNumComment("MAX STRING LENGTH", maxStringLen);
5278 }
5279 }
5280
5281 PrintNumComment("STRING CHARS", NumStringChars);
5282 // PrintNumComment("LANG TABLE SIZE", bhCtlColors.Offset - bhLangTables.Offset);
5283
5284 if (bhCtlColors.Offset > _size)
5285 AddErrorLF("Bad COLORS TABLE");
5286 // PrintNumComment("COLORS TABLE SIZE", bhFont.Offset - bhCtlColors.Offset);
5287 if (bhCtlColors.Num != 0)
5288 PrintNumComment("COLORS Num", bhCtlColors.Num);
5289
5290 // bhData uses offset in _afterHeader (not in _data)
5291 // PrintNumComment("FONT TABLE SIZE", bhData.Offset - bhFont.Offset);
5292 if (bhFont.Num != 0)
5293 PrintNumComment("FONTS Num", bhFont.Num);
5294
5295 // PrintNumComment("DATA SIZE", FirstHeader.HeaderSize - bhData.Offset);
5296 if (bhData.Num != 0)
5297 PrintNumComment("DATA NUM", bhData.Num);
5298
5299 AddLF();
5300
5301 AddStringLF("OutFile [NSIS].exe");
5302 AddStringLF("!include WinMessages.nsh");
5303
5304 AddLF();
5305
5306 strUsed.Alloc(NumStringChars);
5307 memset(strUsed, 0, NumStringChars);
5308
5309 {
5310 UInt32 ehFlags = Get32(p1);
5311 UInt32 showDetails = ehFlags & 3;// CH_FLAGS_DETAILS_SHOWDETAILS & CH_FLAGS_DETAILS_NEVERSHOW;
5312 if (showDetails >= 1 && showDetails <= 2)
5313 {
5314 Script += IsInstaller ? "ShowInstDetails" : "ShowUninstDetails";
5315 Script += (showDetails == 1) ? " show" : " nevershow";
5316 AddLF();
5317 }
5318 if (ehFlags & CH_FLAGS_PROGRESS_COLORED) AddStringLF("InstProgressFlags colored" );
5319 if ((ehFlags & (CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG)) != 0)
5320 {
5321 Script += IsInstaller ? "SilentInstall " : "SilentUnInstall ";
5322 Script += (ehFlags & CH_FLAGS_SILENT_LOG) ? "silentlog" : "silent";
5323 AddLF();
5324 }
5325 if (ehFlags & CH_FLAGS_AUTO_CLOSE) AddStringLF("AutoCloseWindow true");
5326 if ((ehFlags & CH_FLAGS_NO_ROOT_DIR) == 0) AddStringLF("AllowRootDirInstall true");
5327 if (ehFlags & CH_FLAGS_NO_CUSTOM) AddStringLF("InstType /NOCUSTOM");
5328 if (ehFlags & CH_FLAGS_COMP_ONLY_ON_CUSTOM) AddStringLF("InstType /COMPONENTSONLYONCUSTOM");
5329 }
5330
5331 // Separator();
5332 // AddLF();
5333
5334 Int32 licenseLangIndex = -1;
5335 {
5336 const Byte *pp = _data + bhPages.Offset;
5337
5338 for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, pp += kPageSize)
5339 {
5340 UInt32 wndProcID = Get32(pp + 4);
5341 UInt32 param1 = Get32(pp + 44 + 4 * 1);
5342 if (wndProcID != PWP_LICENSE || param1 == 0)
5343 continue;
5344 if ((Int32)param1 < 0)
5345 licenseLangIndex = - ((Int32)param1 + 1);
5346 else
5347 noParseStringIndexes.AddToUniqueSorted(param1);
5348 }
5349 }
5350
5351 unsigned paramsOffset;
5352 {
5353 unsigned numBhs = 8;
5354 // probably its for old NSIS?
5355 if (bhoSize == 8 && bhPages.Offset == 276)
5356 numBhs = 7;
5357 paramsOffset = 4 + bhoSize * numBhs;
5358 }
5359
5360 const Byte *p2 = p1 + paramsOffset;
5361
5362 {
5363 UInt32 rootKey = Get32(p2); // (rootKey = -1) in uninstaller by default (the bug in NSIS)
5364 UInt32 subKey = Get32(p2 + 4);
5365 UInt32 value = Get32(p2 + 8);
5366 if ((rootKey != 0 && rootKey != (UInt32)(Int32)-1) || subKey != 0 || value != 0)
5367 {
5368 Script += "InstallDirRegKey";
5369 AddRegRoot(rootKey);
5370 AddParam(subKey);
5371 AddParam(value);
5372 AddLF();
5373 }
5374 }
5375
5376
5377 {
5378 UInt32 bg_color1 = Get32(p2 + 12);
5379 UInt32 bg_color2 = Get32(p2 + 16);
5380 UInt32 bg_textcolor = Get32(p2 + 20);
5381 if (bg_color1 != (UInt32)(Int32)-1 || bg_color2 != (UInt32)(Int32)-1 || bg_textcolor != (UInt32)(Int32)-1)
5382 {
5383 Script += "BGGradient";
5384 if (bg_color1 != 0 || bg_color2 != 0xFF0000 || bg_textcolor != (UInt32)(Int32)-1)
5385 {
5386 Add_ColorParam(bg_color1);
5387 Add_ColorParam(bg_color2);
5388 if (bg_textcolor != (UInt32)(Int32)-1)
5389 Add_ColorParam(bg_textcolor);
5390 }
5391 AddLF();
5392 }
5393 }
5394
5395 {
5396 UInt32 lb_bg = Get32(p2 + 24);
5397 UInt32 lb_fg = Get32(p2 + 28);
5398 if ((lb_bg != (UInt32)(Int32)-1 || lb_fg != (UInt32)(Int32)-1) &&
5399 (lb_bg != 0 || lb_fg != 0xFF00))
5400 {
5401 Script += "InstallColors";
5402 Add_ColorParam(lb_fg);
5403 Add_ColorParam(lb_bg);
5404 AddLF();
5405 }
5406 }
5407
5408 UInt32 license_bg = Get32(p2 + 36);
5409 if (license_bg != (UInt32)(Int32)-1 &&
5410 license_bg != (UInt32)(Int32)-15) // COLOR_BTNFACE
5411 {
5412 Script += "LicenseBkColor";
5413 if ((Int32)license_bg == -5) // COLOR_WINDOW
5414 Script += " /windows";
5415 /*
5416 else if ((Int32)license_bg == -15)
5417 Script += " /grey";
5418 */
5419 else
5420 Add_ColorParam(license_bg);
5421 AddLF();
5422 }
5423
5424 if (bhLangTables.Num > 0)
5425 {
5426 const UInt32 langtable_size = Get32(p2 + 32);
5427
5428 if (langtable_size == (UInt32)(Int32)-1)
5429 return E_NOTIMPL; // maybe it's old NSIS archive()
5430
5431 if (langtable_size < 10)
5432 return S_FALSE;
5433 if (bhLangTables.Num > (_size - bhLangTables.Offset) / langtable_size)
5434 return S_FALSE;
5435
5436 const UInt32 numStrings = (langtable_size - 10) / 4;
5437 _numLangStrings = numStrings;
5438 AddLF();
5439 Separator();
5440 PrintNumComment("LANG TABLES", bhLangTables.Num);
5441 PrintNumComment("LANG STRINGS", numStrings);
5442 AddLF();
5443
5444 if (licenseLangIndex >= 0 && (unsigned)licenseLangIndex < numStrings)
5445 {
5446 for (UInt32 i = 0; i < bhLangTables.Num; i++)
5447 {
5448 const Byte * const p = _data + bhLangTables.Offset + langtable_size * i;
5449 const UInt16 langID = Get16(p);
5450 UInt32 val = Get32(p + 10 + (UInt32)licenseLangIndex * 4);
5451 if (val != 0)
5452 {
5453 Script += "LicenseLangString ";
5454 Add_LangStr_Simple(licenseLangIndex);
5455 AddParam_UInt(langID);
5456 AddLicense(val, langID);
5457 noParseStringIndexes.AddToUniqueSorted(val);
5458 NewLine();
5459 }
5460 }
5461 AddLF();
5462 }
5463
5464 UInt32 names[3] = { 0 };
5465
5466 UInt32 i;
5467 for (i = 0; i < bhLangTables.Num; i++)
5468 {
5469 const Byte * const p = _data + bhLangTables.Offset + langtable_size * i;
5470 const UInt16 langID = Get16(p);
5471 if (i == 0 || langID == 1033)
5472 _mainLang = p + 10;
5473 for (unsigned k = 0; k < ARRAY_SIZE(names) && k < numStrings; k++)
5474 {
5475 UInt32 v = Get32(p + 10 + k * 4);
5476 if (v != 0 && (langID == 1033 || names[k] == 0))
5477 names[k] = v;
5478 }
5479 }
5480
5481 const UInt32 name = names[2];
5482 if (name != 0)
5483 {
5484 Script += "Name";
5485 AddParam(name);
5486 NewLine();
5487
5488 ReadString2(Name, name);
5489 }
5490
5491 /*
5492 const UInt32 caption = names[1];
5493 if (caption != 0)
5494 {
5495 Script += "Caption";
5496 AddParam(caption);
5497 NewLine();
5498 }
5499 */
5500
5501 const UInt32 brandingText = names[0];
5502 if (brandingText != 0)
5503 {
5504 Script += "BrandingText";
5505 AddParam(brandingText);
5506 NewLine();
5507
5508 ReadString2(BrandingText, brandingText);
5509 }
5510
5511 for (i = 0; i < bhLangTables.Num; i++)
5512 {
5513 const Byte * const p = _data + bhLangTables.Offset + langtable_size * i;
5514 const UInt16 langID = Get16(p);
5515
5516 AddLF();
5517 AddCommentAndString("LANG:");
5518 AddParam_UInt(langID);
5519 /*
5520 Script += " (";
5521 LangId_To_String(Script, langID);
5522 Script += ')';
5523 */
5524 AddLF();
5525 // UInt32 dlg_offset = Get32(p + 2);
5526 // UInt32 g_exec_flags_rtl = Get32(p + 6);
5527
5528
5529 for (UInt32 j = 0; j < numStrings; j++)
5530 {
5531 UInt32 val = Get32(p + 10 + j * 4);
5532 if (val != 0)
5533 {
5534 if ((Int32)j != licenseLangIndex)
5535 {
5536 Script += "LangString ";
5537 Add_LangStr_Simple(j);
5538 AddParam_UInt(langID);
5539 AddParam(val);
5540 AddLF();
5541 }
5542 }
5543 }
5544 AddLF();
5545 }
5546 ClearLangComment();
5547 }
5548
5549 {
5550 unsigned numInternalVars = GET_NUM_INTERNAL_VARS;
5551 UInt32 numUsedVars = GetNumUsedVars();
5552 if (numUsedVars > numInternalVars)
5553 {
5554 Separator();
5555 PrintNumComment("VARIABLES", numUsedVars - numInternalVars);
5556 AddLF();
5557 AString temp;
5558 for (UInt32 i = numInternalVars; i < numUsedVars; i++)
5559 {
5560 Script += "Var ";
5561 temp.Empty();
5562 GetVar2(temp, i);
5563 AddStringLF(temp);
5564 }
5565 AddLF();
5566 }
5567 }
5568
5569 onFuncOffset = paramsOffset + 40;
5570 numOnFunc = ARRAY_SIZE(kOnFunc);
5571 if (bhPages.Offset == 276)
5572 numOnFunc--;
5573 p2 += 40 + numOnFunc * 4;
5574
5575 #define NSIS_MAX_INST_TYPES 32
5576
5577 AddLF();
5578
5579 UInt32 i;
5580 for (i = 0; i < NSIS_MAX_INST_TYPES + 1; i++, p2 += 4)
5581 {
5582 UInt32 instType = Get32(p2);
5583 if (instType != 0)
5584 {
5585 Script += "InstType";
5586 AString s2;
5587 if (!IsInstaller)
5588 s2 += "un.";
5589 ReadString2(s2, instType);
5590 SpaceQuStr(s2);
5591 NewLine();
5592 }
5593 }
5594
5595 {
5596 UInt32 installDir = Get32(p2);
5597 p2 += 4;
5598 if (installDir != 0)
5599 {
5600 Script += "InstallDir";
5601 AddParam(installDir);
5602 NewLine();
5603 }
5604 }
5605
5606 if (bhPages.Offset >= 288)
5607 for (i = 0; i < 4; i++)
5608 {
5609 if (i != 0 && bhPages.Offset < 300)
5610 break;
5611 UInt32 param = Get32(p2 + 4 * i);
5612 if (param == 0 || param == (UInt32)(Int32)-1)
5613 continue;
5614
5615 /*
5616 uninstaller:
5617 UInt32 uninstChild = Get32(p2 + 8); // "$TEMP\\$1u_.exe"
5618 UInt32 uninstCmd = Get32(p2 + 12); // "\"$TEMP\\$1u_.exe\" $0 _?=$INSTDIR\\"
5619 int str_wininit = Get32(p2 + 16); // "$WINDIR\\wininit.ini"
5620 */
5621
5622 AddCommentAndString(k_PostStrings[i]);
5623 Script += " =";
5624 AddParam(param);
5625 NewLine();
5626 }
5627
5628 AddLF();
5629
5630 #endif
5631
5632 RINOK(ReadEntries(bhEntries));
5633
5634 #ifdef NSIS_SCRIPT
5635
5636 Separator();
5637 AddCommentAndString("UNREFERENCED STRINGS:");
5638 AddLF();
5639 AddLF();
5640 CommentOpen();
5641
5642 for (i = 0; i < NumStringChars;)
5643 {
5644 if (!strUsed[i] && i != 0)
5645 // Script += "!!! ";
5646 {
5647 Add_UInt(i);
5648 AddParam(i);
5649 NewLine();
5650 }
5651 if (IsUnicode)
5652 i += GetUi16Str_Len((const Byte *)_data + _stringsPos + i * 2);
5653 else
5654 i += (UInt32)strlen((const char *)(const Byte *)_data + _stringsPos + i);
5655 i++;
5656 }
5657 CommentClose();
5658 #endif
5659
5660 return SortItems();
5661 }
5662
IsLZMA(const Byte * p,UInt32 & dictionary)5663 static bool IsLZMA(const Byte *p, UInt32 &dictionary)
5664 {
5665 dictionary = Get32(p + 1);
5666 return (p[0] == 0x5D &&
5667 p[1] == 0x00 && p[2] == 0x00 &&
5668 p[5] == 0x00 && (p[6] & 0x80) == 0x00);
5669 }
5670
IsLZMA(const Byte * p,UInt32 & dictionary,bool & thereIsFlag)5671 static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag)
5672 {
5673 if (IsLZMA(p, dictionary))
5674 {
5675 thereIsFlag = false;
5676 return true;
5677 }
5678 if (p[0] <= 1 && IsLZMA(p + 1, dictionary))
5679 {
5680 thereIsFlag = true;
5681 return true;
5682 }
5683 return false;
5684 }
5685
IsBZip2(const Byte * p)5686 static bool IsBZip2(const Byte *p)
5687 {
5688 return (p[0] == 0x31 && p[1] < 14);
5689 }
5690
Open2(const Byte * sig,size_t size)5691 HRESULT CInArchive::Open2(const Byte *sig, size_t size)
5692 {
5693 const UInt32 kSigSize = 4 + 1 + 5 + 2; // size, flag, 5 - lzma props, 2 - lzma first bytes
5694 if (size < kSigSize)
5695 return S_FALSE;
5696
5697 _headerIsCompressed = true;
5698 IsSolid = true;
5699 FilterFlag = false;
5700 UseFilter = false;
5701 DictionarySize = 1;
5702
5703 #ifdef NSIS_SCRIPT
5704 AfterHeaderSize = 0;
5705 #endif
5706
5707 UInt32 compressedHeaderSize = Get32(sig);
5708
5709
5710 /*
5711 XX XX XX XX XX XX XX XX == FirstHeader.HeaderSize, nonsolid, uncompressed
5712 5D 00 00 dd dd 00 solid LZMA
5713 00 5D 00 00 dd dd 00 solid LZMA, empty filter (there are no such archives)
5714 01 5D 00 00 dd dd 00 solid LZMA, BCJ filter (only 7-Zip installer used that format)
5715
5716 SS SS SS 80 00 5D 00 00 dd dd 00 non-solid LZMA, empty filter
5717 SS SS SS 80 01 5D 00 00 dd dd 00 non-solid LZMA, BCJ filte
5718 SS SS SS 80 01 tt non-solid BZip (tt < 14
5719 SS SS SS 80 non-solid deflate
5720
5721 01 tt solid BZip (tt < 14
5722 other solid Deflate
5723 */
5724
5725 if (compressedHeaderSize == FirstHeader.HeaderSize)
5726 {
5727 _headerIsCompressed = false;
5728 IsSolid = false;
5729 Method = NMethodType::kCopy;
5730 }
5731 else if (IsLZMA(sig, DictionarySize, FilterFlag))
5732 Method = NMethodType::kLZMA;
5733 else if (sig[3] == 0x80)
5734 {
5735 IsSolid = false;
5736 if (IsLZMA(sig + 4, DictionarySize, FilterFlag) && sig[3] == 0x80)
5737 Method = NMethodType::kLZMA;
5738 else if (IsBZip2(sig + 4))
5739 Method = NMethodType::kBZip2;
5740 else
5741 Method = NMethodType::kDeflate;
5742 }
5743 else if (IsBZip2(sig))
5744 Method = NMethodType::kBZip2;
5745 else
5746 Method = NMethodType::kDeflate;
5747
5748 if (IsSolid)
5749 {
5750 RINOK(SeekTo_DataStreamOffset());
5751 }
5752 else
5753 {
5754 _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0);
5755 compressedHeaderSize &= ~kMask_IsCompressed;
5756 _nonSolidStartOffset = compressedHeaderSize;
5757 RINOK(SeekTo(DataStreamOffset + 4));
5758 }
5759
5760 if (FirstHeader.HeaderSize == 0)
5761 return S_FALSE;
5762
5763 _data.Alloc(FirstHeader.HeaderSize);
5764 _size = (size_t)FirstHeader.HeaderSize;
5765
5766 Decoder.Method = Method;
5767 Decoder.FilterFlag = FilterFlag;
5768 Decoder.Solid = IsSolid;
5769
5770 Decoder.IsNsisDeflate = true; // we need some smart check that NSIS is not NSIS3 here.
5771
5772 Decoder.InputStream = _stream;
5773 Decoder.Buffer.Alloc(kInputBufSize);
5774 Decoder.StreamPos = 0;
5775
5776 if (_headerIsCompressed)
5777 {
5778 RINOK(Decoder.Init(_stream, UseFilter));
5779 if (IsSolid)
5780 {
5781 size_t processedSize = 4;
5782 Byte buf[4];
5783 RINOK(Decoder.Read(buf, &processedSize));
5784 if (processedSize != 4)
5785 return S_FALSE;
5786 if (Get32((const Byte *)buf) != FirstHeader.HeaderSize)
5787 return S_FALSE;
5788 }
5789 {
5790 size_t processedSize = FirstHeader.HeaderSize;
5791 RINOK(Decoder.Read(_data, &processedSize));
5792 if (processedSize != FirstHeader.HeaderSize)
5793 return S_FALSE;
5794 }
5795
5796 #ifdef NSIS_SCRIPT
5797 if (IsSolid)
5798 {
5799 /* we need additional bytes for data for WriteRegBin */
5800 AfterHeaderSize = (1 << 12);
5801 _afterHeader.Alloc(AfterHeaderSize);
5802 size_t processedSize = AfterHeaderSize;
5803 RINOK(Decoder.Read(_afterHeader, &processedSize));
5804 AfterHeaderSize = (UInt32)processedSize;
5805 }
5806 #endif
5807 }
5808 else
5809 {
5810 size_t processedSize = FirstHeader.HeaderSize;
5811 RINOK(ReadStream(_stream, (Byte *)_data, &processedSize));
5812 if (processedSize < FirstHeader.HeaderSize)
5813 return S_FALSE;
5814 }
5815
5816 #ifdef NUM_SPEED_TESTS
5817 for (unsigned i = 0; i < NUM_SPEED_TESTS; i++)
5818 {
5819 RINOK(Parse());
5820 Clear2();
5821 }
5822 #endif
5823
5824 return Parse();
5825 }
5826
5827 /*
5828 NsisExe =
5829 {
5830 ExeStub
5831 Archive // must start from 512 * N
5832 #ifndef NSIS_CONFIG_CRC_ANAL
5833 {
5834 Some additional data
5835 }
5836 }
5837
5838 Archive
5839 {
5840 FirstHeader
5841 Data
5842 #ifdef NSIS_CONFIG_CRC_SUPPORT && FirstHeader.ThereIsCrc()
5843 {
5844 CRC
5845 }
5846 }
5847
5848 FirstHeader
5849 {
5850 UInt32 Flags;
5851 Byte Signature[16];
5852 // points to the header+sections+entries+stringtable in the datablock
5853 UInt32 HeaderSize;
5854 UInt32 ArcSize;
5855 }
5856 */
5857
5858
5859 // ---------- PE (EXE) parsing ----------
5860
5861 static const unsigned k_PE_StartSize = 0x40;
5862 static const unsigned k_PE_HeaderSize = 4 + 20;
5863 static const unsigned k_PE_OptHeader32_Size_MIN = 96;
5864
CheckPeOffset(UInt32 pe)5865 static inline bool CheckPeOffset(UInt32 pe)
5866 {
5867 return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0);
5868 }
5869
5870
IsArc_Pe(const Byte * p,size_t size)5871 static bool IsArc_Pe(const Byte *p, size_t size)
5872 {
5873 if (size < 2)
5874 return false;
5875 if (p[0] != 'M' || p[1] != 'Z')
5876 return false;
5877 if (size < k_PE_StartSize)
5878 return false; // k_IsArc_Res_NEED_MORE;
5879 UInt32 pe = Get32(p + 0x3C);
5880 if (!CheckPeOffset(pe))
5881 return false;
5882 if (pe + k_PE_HeaderSize > size)
5883 return false; // k_IsArc_Res_NEED_MORE;
5884
5885 p += pe;
5886 if (Get32(p) != 0x00004550)
5887 return false;
5888 return Get16(p + 4 + 16) >= k_PE_OptHeader32_Size_MIN;
5889 }
5890
Open(IInStream * inStream,const UInt64 * maxCheckStartPosition)5891 HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition)
5892 {
5893 Clear();
5894
5895 RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &StartOffset));
5896
5897 const UInt32 kStartHeaderSize = 4 * 7;
5898 const unsigned kStep = 512; // nsis start is aligned for 512
5899 Byte buf[kStep];
5900 UInt64 pos = StartOffset;
5901 size_t bufSize = 0;
5902 UInt64 pePos = (UInt64)(Int64)-1;
5903
5904 for (;;)
5905 {
5906 bufSize = kStep;
5907 RINOK(ReadStream(inStream, buf, &bufSize));
5908 if (bufSize < kStartHeaderSize)
5909 return S_FALSE;
5910 if (memcmp(buf + 4, kSignature, kSignatureSize) == 0)
5911 break;
5912 if (IsArc_Pe(buf, bufSize))
5913 pePos = pos;
5914 pos += kStep;
5915 UInt64 proc = pos - StartOffset;
5916 if (maxCheckStartPosition && proc > *maxCheckStartPosition)
5917 {
5918 if (pePos == 0)
5919 {
5920 if (proc > (1 << 20))
5921 return S_FALSE;
5922 }
5923 else
5924 return S_FALSE;
5925 }
5926 }
5927
5928 if (pePos == (UInt64)(Int64)-1)
5929 {
5930 UInt64 posCur = StartOffset;
5931 for (;;)
5932 {
5933 if (posCur < kStep)
5934 break;
5935 posCur -= kStep;
5936 if (pos - posCur > (1 << 20))
5937 break;
5938 bufSize = kStep;
5939 RINOK(inStream->Seek(posCur, STREAM_SEEK_SET, NULL));
5940 RINOK(ReadStream(inStream, buf, &bufSize));
5941 if (bufSize < kStep)
5942 break;
5943 if (IsArc_Pe(buf, bufSize))
5944 {
5945 pePos = posCur;
5946 break;
5947 }
5948 }
5949
5950 // restore buf to nsis header
5951 bufSize = kStep;
5952 RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL));
5953 RINOK(ReadStream(inStream, buf, &bufSize));
5954 if (bufSize < kStartHeaderSize)
5955 return S_FALSE;
5956 }
5957
5958 StartOffset = pos;
5959 UInt32 peSize = 0;
5960
5961 if (pePos != (UInt64)(Int64)-1)
5962 {
5963 UInt64 peSize64 = (pos - pePos);
5964 if (peSize64 < (1 << 20))
5965 {
5966 peSize = (UInt32)peSize64;
5967 StartOffset = pePos;
5968 }
5969 }
5970
5971 DataStreamOffset = pos + kStartHeaderSize;
5972 FirstHeader.Flags = Get32(buf);
5973 if ((FirstHeader.Flags & (~kFlagsMask)) != 0)
5974 {
5975 // return E_NOTIMPL;
5976 return S_FALSE;
5977 }
5978 IsInstaller = (FirstHeader.Flags & NFlags::kUninstall) == 0;
5979
5980 FirstHeader.HeaderSize = Get32(buf + kSignatureSize + 4);
5981 FirstHeader.ArcSize = Get32(buf + kSignatureSize + 8);
5982 if (FirstHeader.ArcSize <= kStartHeaderSize)
5983 return S_FALSE;
5984
5985 /*
5986 if ((FirstHeader.Flags & NFlags::k_BI_ExternalFileSupport) != 0)
5987 {
5988 UInt32 datablock_low = Get32(buf + kSignatureSize + 12);
5989 UInt32 datablock_high = Get32(buf + kSignatureSize + 16);
5990 }
5991 */
5992
5993 RINOK(inStream->Seek(0, STREAM_SEEK_END, &_fileSize));
5994
5995 IsArc = true;
5996
5997 if (peSize != 0)
5998 {
5999 ExeStub.Alloc(peSize);
6000 RINOK(inStream->Seek(pePos, STREAM_SEEK_SET, NULL));
6001 RINOK(ReadStream_FALSE(inStream, ExeStub, peSize));
6002 }
6003
6004 HRESULT res = S_FALSE;
6005 try
6006 {
6007 CLimitedInStream *_limitedStreamSpec = new CLimitedInStream;
6008 _stream = _limitedStreamSpec;
6009 _limitedStreamSpec->SetStream(inStream);
6010 _limitedStreamSpec->InitAndSeek(pos, FirstHeader.ArcSize);
6011 DataStreamOffset -= pos;
6012 res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize);
6013 }
6014 catch(...)
6015 {
6016 _stream.Release();
6017 throw;
6018 // res = S_FALSE;
6019 }
6020 if (res != S_OK)
6021 {
6022 _stream.Release();
6023 // Clear();
6024 }
6025 return res;
6026 }
6027
ConvertToUnicode(const AString & s) const6028 UString CInArchive::ConvertToUnicode(const AString &s) const
6029 {
6030 if (IsUnicode)
6031 {
6032 UString res;
6033 // if (
6034 ConvertUTF8ToUnicode(s, res);
6035 return res;
6036 }
6037 return MultiByteToUnicodeString(s);
6038 }
6039
Clear2()6040 void CInArchive::Clear2()
6041 {
6042 IsUnicode = false;
6043 NsisType = k_NsisType_Nsis2;
6044 IsNsis225 = false;
6045 IsNsis200 = false;
6046 LogCmdIsEnabled = false;
6047 BadCmd = -1;
6048 Is64Bit = false;
6049
6050 #ifdef NSIS_SCRIPT
6051 Name.Empty();
6052 BrandingText.Empty();
6053 Script.Empty();
6054 LicenseFiles.Clear();
6055 _numRootLicenses = 0;
6056 _numLangStrings = 0;
6057 langStrIDs.Clear();
6058 LangComment.Empty();
6059 noParseStringIndexes.Clear();
6060 #endif
6061
6062 APrefixes.Clear();
6063 UPrefixes.Clear();
6064 Items.Clear();
6065 IsUnicode = false;
6066 ExeStub.Free();
6067 }
6068
Clear()6069 void CInArchive::Clear()
6070 {
6071 Clear2();
6072 IsArc = false;
6073 _stream.Release();
6074 }
6075
6076 }}
6077