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