Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | (******************************************************************) |
2 | (* SFX for DelZip v1.8 *) |
||
3 | (* Copyright 1997, Microchip Systems / Carl Bunton *) |
||
4 | (* e-mail: Twojags@cris.com *) |
||
5 | (* Web-page: http://www.concentric.net/~twojags *) |
||
6 | (* *) |
||
7 | (* modified by Markus Stephany *) |
||
8 | (* modified by Russell Peters, Roger Aelbrecht |
||
9 | This library is free software; you can redistribute it and/or |
||
10 | modify it under the terms of the GNU Lesser General Public |
||
11 | License as published by the Free Software Foundation; either |
||
12 | version 2.1 of the License, or (at your option) any later version. |
||
13 | |||
14 | This library is distributed in the hope that it will be useful, |
||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
17 | Lesser General Public License (licence.txt) for more details. |
||
18 | |||
19 | You should have received a copy of the GNU Lesser General Public |
||
20 | License along with this library; if not, write to the Free Software |
||
21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||
22 | |||
23 | contact: problems AT delphizip DOT org |
||
24 | updates: http://www.delphizip.org |
||
25 | |||
26 | modified 2008-11-03 |
||
27 | ---------------------------------------------------------------------------*) |
||
28 | unit ZMSFXProcs19; |
||
29 | |||
30 | { |
||
31 | this unit contains utility functions and main function used by delzipsfx |
||
32 | |||
33 | } |
||
34 | |||
35 | interface |
||
36 | |||
37 | { modifications marked with ##FR are enhancements and bug fixes by |
||
38 | Frank Reichert F.Rei@gmx.de, thanks! |
||
39 | |||
40 | |||
41 | |||
42 | |||
43 | |||
44 | |||
45 | !!!!!!!!!!!!! spanning/multivolume support based on Roger Aelbrecht's BCB |
||
46 | version of the sfx; thanks a lot Roger! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||
47 | |||
48 | |||
49 | } |
||
50 | |||
51 | uses Messages, Windows, ZMSFXDefs19, ZMSFXInt19, ZMSFXStrings19, |
||
52 | {$ifdef DEBUG_SFX} |
||
53 | SysUtils, // Run1, |
||
54 | {$endif} |
||
55 | ZMSFXStructs19; |
||
56 | |||
57 | // execute |
||
58 | procedure Run; |
||
59 | |||
60 | // resize or move a control on the main dialog (or the dialog itself) |
||
61 | // depending on the visibility of the files listview |
||
62 | procedure ResizeControl(const wnd: HWND; const bReposition: boolean; yDiff: integer); |
||
63 | |||
64 | // enable/disable all child controls of the given window |
||
65 | // except of progress bars |
||
66 | procedure EnableChildren(const wnd: HWND; const bEnable: boolean); |
||
67 | |||
68 | // get the text for the run checkbox |
||
69 | function GetRunCheckBoxText: string; |
||
70 | |||
71 | // get an error message if ExcuteCMD failed |
||
72 | function GetRunErrorMessage: string; |
||
73 | |||
74 | // compare two strings / case insesitive |
||
75 | function CompareText(const s1, s2: string): boolean; |
||
76 | |||
77 | // get an argument out of VStr_SFX_CmdLine |
||
78 | function GetArgument(const iIndex: integer): string; |
||
79 | |||
80 | // check whether the file to execute is an .inf installation file |
||
81 | function TestForInf(const sr1: string): boolean; |
||
82 | |||
83 | // format a string (replace '><' by args) |
||
84 | function FmtStr1(const sFormat: string; const arg1: string): string; |
||
85 | function FmtStrID1(id: integer; const arg1: string): string; |
||
86 | function FmtStr2(const sFormat: string; const arg1, arg2: string): string; |
||
87 | //function FmtStr3(const sFormat: string; const arg1, arg2, arg3: string): string; |
||
88 | //function FmtStrID2(id: integer; const arg1, arg2: string): string; |
||
89 | |||
90 | // angus johnson, ajohnson@rpi.net.au |
||
91 | // set the filetime of an extracted file to the value stored in the archive |
||
92 | procedure FileSetDate(const hFile: THandle; const iAge: integer); |
||
93 | |||
94 | // unstore the current archive file / uncompressed |
||
95 | procedure Unstore; |
||
96 | |||
97 | // force the existence of a directory (and its parents) |
||
98 | function ForceDirectories(sDir: string): boolean; // RCV04 |
||
99 | |||
100 | // change input file position |
||
101 | function FSeek(const Offset: int64; const MoveMethod: word): int64; //##FR was procedure |
||
102 | |||
103 | // fill crc32 buffer |
||
104 | procedure Crc32_Buf(str: PByte; len: integer; var crc: cardinal); |
||
105 | |||
106 | // handle relative paths, strip directory name |
||
107 | function ExtractFileName(const sFileName: string): string; |
||
108 | |||
109 | // return the smaller value |
||
110 | function Min(const I1, I2: longint): longint; |
||
111 | |||
112 | // ensure trailing backslash |
||
113 | function AppendDirSeparator(const sDir: string): string; //##FR modified |
||
114 | |||
115 | // ensure NO trailing backslash |
||
116 | function RemoveDirSeparator(const sDir: string): string; |
||
117 | |||
118 | // does the directory exist? |
||
119 | function DirectoryExists(const sDir: string): boolean; |
||
120 | |||
121 | // does the file exist? |
||
122 | function FileExists(const sFileName: string): boolean; |
||
123 | |||
124 | // extract the file's path |
||
125 | function ExtractFilePath(const sFilename: string): string; |
||
126 | |||
127 | // replace environment vars by their contents |
||
128 | function ExpandEnv(const Str: string): string; |
||
129 | |||
130 | // show a message box |
||
131 | function MsgBox(const wndpar: HWND; const sMsg, sTitle: string; |
||
132 | const uType: cardinal): integer; |
||
133 | |||
134 | // show an error message |
||
135 | procedure ErrorMsgBox(const wndPar: HWND; const sMsg: string); |
||
136 | procedure ErrorMsgBoxFmt1(const wndPar: HWND; id: integer; const arg1: string); |
||
137 | |||
138 | // read from input file |
||
139 | function FRead(var Buffer; const cNum: cardinal): cardinal; |
||
140 | |||
141 | // read from a file and bail if not all data could be read |
||
142 | procedure CheckFRead(var Buffer; const cNumBytes: cardinal); |
||
143 | |||
144 | // write to a file and bail if not all data could be written |
||
145 | procedure CheckFWrite(const FH: THandle; const Buffer; const cNumBytes: cardinal; |
||
146 | const FileName: string); |
||
147 | |||
148 | |||
149 | // read TSFXFileHeader from input file |
||
150 | procedure GetDefParams; |
||
151 | |||
152 | // execute the command-line read from the sfx header, if any |
||
153 | function ExecuteCMD: cardinal; |
||
154 | |||
155 | // check password |
||
156 | function decrypt_pw(Encrypt_Head: PAnsiChar; EncHead_len: byte; BitFlag: word; |
||
157 | CRC, FileDate: longint; const sPassword: AnsiString): boolean; |
||
158 | |||
159 | // decrypt arcive contents |
||
160 | function decrypt_byte: integer; |
||
161 | |||
162 | // Update the encryption keys with the next byte of plain text |
||
163 | procedure UpdateKeys(c: byte); |
||
164 | |||
165 | // initially fill the crc table |
||
166 | procedure Make_CRC32Table; |
||
167 | |||
168 | // from Angus Johnson's TZip-SFX code: |
||
169 | // get the executable's file size to get rid of caring about the exe size |
||
170 | function GetExeSize: cardinal; |
||
171 | |||
172 | // from Angus Johnson's TZip-SFX code: |
||
173 | // fill the listview |
||
174 | procedure FillListView(wndOwner: hWnd); |
||
175 | |||
176 | // fatal error, exit |
||
177 | procedure ErrorHaltID(id: integer); overload; |
||
178 | procedure ErrorHaltFmt(id: integer; const arg1: string); |
||
179 | procedure ErrorHalt(const sMsg: string); |
||
180 | |||
181 | function Extract(wndOwner: hWnd): boolean; |
||
182 | |||
183 | function StrGetEditText(wndPar: HWND): string; |
||
184 | |||
185 | |||
186 | // listview handling |
||
187 | procedure AddFilesListViewCol(const wndDlg: HWND; const iIndex: integer; |
||
188 | const szCaption: string; const iDirection, iWidth: integer); |
||
189 | |||
190 | procedure SelectAllInFilesListView(const wndDlg: HWND); |
||
191 | |||
192 | // get current directory |
||
193 | function GetCurDir: string; |
||
194 | |||
195 | // add an entry to the list view |
||
196 | procedure AddFileToList(const wndOwner: HWND; const sName: string; |
||
197 | const Rec: TZ64CentralEntry; const IsDir: boolean); |
||
198 | // const Rec: TZipCentralHeader; const IsDir: boolean); |
||
199 | |||
200 | procedure SetLangStrings(hLC: hWnd); |
||
201 | |||
202 | // return pointer to temporary buffer of at least size |
||
203 | function GetXBuf(size: integer): pByte; |
||
204 | |||
205 | // dispatch windows messages |
||
206 | procedure ProcessMessages; |
||
207 | |||
208 | // Int to Str |
||
209 | function Int2Str(n: int64; wide: integer = -1): String; |
||
210 | |||
211 | // return the Detached name |
||
212 | function DetachedName(const num: string): string; |
||
213 | |||
214 | function LoadResource(id: integer): Pointer; |
||
215 | |||
216 | // cleanup, free globals |
||
217 | procedure Finish; |
||
218 | //{$endif} |
||
219 | |||
220 | // check codepage of filename |
||
221 | implementation |
||
222 | |||
223 | uses |
||
224 | ZMSFXDialogs19, ZMSFXVars19, ZMSFXInflate19, ZMSFXWinTrust;//, SysUtils; |
||
225 | |||
226 | var |
||
227 | xbuf: PByte = nil; |
||
228 | xbufsize: integer = 0; |
||
229 | |||
230 | // return pointer to temporary buffer of at least size |
||
231 | function GetXBuf(size: integer): pByte; |
||
232 | begin |
||
233 | if (xbuf <> nil) and (xbufsize > 0) and (size <= xbufsize) then |
||
234 | begin |
||
235 | // use the existing buffer |
||
236 | Result := pByte(xbuf); |
||
237 | Exit; |
||
238 | end; |
||
239 | |||
240 | if (size > xbufsize) or (size < 0) or (xbuf = nil) or (xbufsize <= 0) then |
||
241 | begin |
||
242 | // clear old buf |
||
243 | if xbuf <> nil then |
||
244 | FreeMem(xbuf); |
||
245 | xbuf := nil; |
||
246 | xbufsize := 0; |
||
247 | Result := nil; |
||
248 | if size <= 0 then |
||
249 | exit; |
||
250 | end; |
||
251 | xbufsize := succ(size or $3FF); |
||
252 | GetMem(xbuf, xbufsize); |
||
253 | Result := pByte(xbuf); |
||
254 | if Result = nil then |
||
255 | ErrorHalt('no memory'); // probably need error message |
||
256 | end; |
||
257 | |||
258 | type |
||
259 | TCharSet = set of AnsiChar; |
||
260 | function CharInSet(c: Char; theSet: TCharSet): boolean; |
||
261 | {$IFDEF UNICODE} |
||
262 | var |
||
263 | ac: AnsiChar; |
||
264 | {$ENDIF} |
||
265 | begin |
||
266 | {$IFDEF UNICODE} |
||
267 | Result := False; |
||
268 | if c < HIGH(AnsiChar) then |
||
269 | begin |
||
270 | ac := AnsiChar(Ord(c) and $FF); |
||
271 | Result := ac in theSet; |
||
272 | end; |
||
273 | {$ELSE} |
||
274 | Result := c in theSet; |
||
275 | {$ENDIF} |
||
276 | end; |
||
277 | |||
278 | procedure BadArchive; |
||
279 | begin |
||
280 | ErrorHaltFmt(SFX_Err_Archive, VStr_ExeName); |
||
281 | end; |
||
282 | |||
283 | // find extra data tag |
||
284 | // IN x => extra data, size = length extra data |
||
285 | // found x => tag data, size = data size, result = true |
||
286 | // not found size = <= 0, result = true; |
||
287 | function ExtraData(var x: pByte; var size: integer; tag: word): boolean; |
||
288 | type |
||
289 | TagHead = packed record |
||
290 | tg: WORD; |
||
291 | sz: WORD; |
||
292 | end; |
||
293 | pTagHead = ^TagHead; |
||
294 | var |
||
295 | hed: TagHead; |
||
296 | begin |
||
297 | Result := False; |
||
298 | // size := 0; |
||
299 | while size > (sizeof(TagHead) + 2) do |
||
300 | begin |
||
301 | hed := pTagHead(x)^; |
||
302 | dec(size, sizeof(TagHead)); |
||
303 | if hed.tg = Tag then |
||
304 | begin |
||
305 | Result := hed.sz <= size; |
||
306 | if Result then |
||
307 | begin |
||
308 | inc(x, sizeof(TagHead)); |
||
309 | size := hed.sz; |
||
310 | end |
||
311 | else |
||
312 | size := -1; // invalid |
||
313 | exit; |
||
314 | end; |
||
315 | dec(size, hed.sz); |
||
316 | inc(x, hed.sz + sizeof(TagHead)); |
||
317 | end; |
||
318 | size := 0; |
||
319 | end; |
||
320 | |||
321 | (*---------------------------------------------------------------------------- |
||
322 | 3.4.0.0 17 Oct 2007 RA new function check if EOC is needed |
||
323 | *) |
||
324 | function NeedEOC64(const EOC: TZipEndOfCentral): bool; |
||
325 | begin |
||
326 | Result := ((EOC.TotalEntries = MAX_WORD) or (EOC.CentralOffSet = MAX_UNSIGNED) or |
||
327 | (EOC.CentralEntries = MAX_WORD) or (EOC.CentralSize = MAX_UNSIGNED) or |
||
328 | (EOC.ThisDiskNo = MAX_WORD) or (EOC.CentralDiskNo = MAX_WORD)); |
||
329 | end; |
||
330 | |||
331 | (*---------------------------------------------------------------------------- |
||
332 | 3.4.0.0 17 Oct 2007 RA new function locate and read EOC64 |
||
333 | result:= 0 = OK ; <0 error |
||
334 | *) |
||
335 | procedure GetEOC64(EOCOffset: word; var EOC64: TZipEOC64); |
||
336 | var |
||
337 | Posn: int64; |
||
338 | Loc: TZip64EOCLocator; |
||
339 | begin |
||
340 | Posn := EOCOffset - SizeOf(TZip64EOCLocator); |
||
341 | // TZip64EOCLocator Loc; |
||
342 | if (Posn >= 0) then |
||
343 | begin |
||
344 | FSeek(Posn, FILE_BEGIN); |
||
345 | if (FRead(Loc, SizeOf(TZip64EOCLocator)) <> SizeOf(TZip64EOCLocator)) then |
||
346 | BadArchive; |
||
347 | if (Loc.LocSig = ZipEOC64LocatorSig) then |
||
348 | begin |
||
349 | // locator found |
||
350 | if (FSeek(int64(Loc.EOC64RelOfs), 0) < 0) then |
||
351 | BadArchive; |
||
352 | if (FRead(EOC64, SizeOf(TZipEOC64)) <> SizeOf(TZipEOC64)) then |
||
353 | BadArchive; |
||
354 | if (EOC64.EOC64Sig <> ZipEndCentral64Sig) then |
||
355 | BadArchive; |
||
356 | end; |
||
357 | end; |
||
358 | end; |
||
359 | |||
360 | (*---------------------------------------------------------------------------- |
||
361 | 3.4.0.0 12 May 2007 RA new function |
||
362 | copy CFH to Z64CFH and read Z64 data if needed |
||
363 | *) |
||
364 | procedure GetZ64Entry(const CFH: TZipCentralHeader; var Z64CFH: TZ64CentralEntry); |
||
365 | var |
||
366 | xlen: integer; |
||
367 | p: pByte; |
||
368 | wsz: word; |
||
369 | begin |
||
370 | Move(CFH.HeaderSig, Z64CFH.HeaderSig, 22); // copy headersig to crc32 |
||
371 | Z64CFH.FileNameLen := CFH.FileNameLen; |
||
372 | Z64CFH.ExtraLen := CFH.ExtraLen; |
||
373 | Z64CFH.FileComLen := CFH.FileComLen; |
||
374 | Z64CFH.IntFileAtt := CFH.IntFileAtt; |
||
375 | Z64CFH.ExtFileAtt := CFH.ExtFileAtt; |
||
376 | Z64CFH.ComprSize := CFH.ComprSize; // values to be corrected for Z64 |
||
377 | Z64CFH.UnComprSize := CFH.UnComprSize; |
||
378 | Z64CFH.RelOffLocal := CFH.RelOffLocal; |
||
379 | Z64CFH.DiskStart := CFH.DiskStart; |
||
380 | Z64CFH.MTime := 0; |
||
381 | Z64CFH.ATime := 0; |
||
382 | Z64CFH.CTime := 0; |
||
383 | if CFH.ExtraLen = 0 then |
||
384 | Exit; // no extra data |
||
385 | // any ntfs stamps? |
||
386 | xlen := CFH.ExtraLen; |
||
387 | p := xbuf; |
||
388 | // if ExtraData(p, xlen, NTFS_STAMP_TAG) and (xlen >= 24) then |
||
389 | if ExtraData(p, xlen, NTFS_STAMP_TAG) and (xlen >= 32) then |
||
390 | begin |
||
391 | Inc(p, 4); // skip Reserved and find sub-tag 1 |
||
392 | if ExtraData(p, xlen, 1) and (xlen >= 24) then |
||
393 | begin |
||
394 | Z64CFH.MTime := PXNTFData(p)^.MTime; |
||
395 | Z64CFH.ATime := PXNTFData(p)^.ATime; |
||
396 | Z64CFH.CTime := PXNTFData(p)^.CTime; |
||
397 | end; |
||
398 | end; |
||
399 | if (CFH.VersionNeed < 45) {or (CFH.ExtraLen = 0)} then |
||
400 | Exit; // nocorrection needed |
||
401 | if (CFH.UnComprSize <> MAX_UNSIGNED) and (CFH.ComprSize <> MAX_UNSIGNED) and |
||
402 | (CFH.RelOffLocal <> MAX_UNSIGNED) and (CFH.DiskStart = MAX_WORD) then |
||
403 | Exit; // not Zip64 |
||
404 | xlen := CFH.ExtraLen; |
||
405 | p := xbuf; |
||
406 | if not ExtraData(p, xlen, Zip64_data_tag) then |
||
407 | BadArchive; // no Zip64 data |
||
408 | wsz := xlen; |
||
409 | if (CFH.UnComprSize = MAX_UNSIGNED) then |
||
410 | begin |
||
411 | if (wsz < 8) then |
||
412 | BadArchive; |
||
413 | Z64CFH.UnComprSize := pInt64(p)^; |
||
414 | Inc(p, Sizeof(int64)); |
||
415 | wsz := wsz - word(SizeOf(int64)); |
||
416 | end; |
||
417 | if (CFH.ComprSize = MAX_UNSIGNED) then |
||
418 | begin |
||
419 | if (wsz < 8) then |
||
420 | BadArchive; |
||
421 | Z64CFH.ComprSize := pInt64(p)^; |
||
422 | Inc(p, Sizeof(int64)); |
||
423 | wsz := wsz - word(SizeOf(int64)); |
||
424 | end; |
||
425 | if (CFH.RelOffLocal = MAX_UNSIGNED) then |
||
426 | begin |
||
427 | if (wsz < 8) then |
||
428 | BadArchive; |
||
429 | Z64CFH.RelOffLocal := pInt64(p)^; |
||
430 | Inc(p, Sizeof(int64)); |
||
431 | wsz := wsz - word(SizeOf(int64)); |
||
432 | end; |
||
433 | if (CFH.DiskStart = MAX_WORD) then |
||
434 | begin |
||
435 | if (wsz < 4) then |
||
436 | BadArchive; |
||
437 | Z64CFH.DiskStart := pInt64(p)^; |
||
438 | end; |
||
439 | end; |
||
440 | |||
441 | // return default Ansi codepage for locale |
||
442 | function DefCP(LangID: integer): integer; |
||
443 | var |
||
444 | tmp: array[0..15] of char; |
||
445 | i: integer; |
||
446 | c: char; |
||
447 | begin |
||
448 | Result := 0; |
||
449 | if GetLocaleInfo(LangID, LOCALE_IDEFAULTANSICODEPAGE, PChar(@tmp[0]), 6) <> 0 then |
||
450 | begin |
||
451 | Result := 0; |
||
452 | i := 0; |
||
453 | c := tmp[0]; |
||
454 | while CharInSet(c, ['0'..'9']) do |
||
455 | begin |
||
456 | Result := (Result * 10) + (ord(c)-ord('0')); |
||
457 | inc(i); |
||
458 | if i > 6 then |
||
459 | break; |
||
460 | c := tmp[i]; |
||
461 | end; |
||
462 | end; |
||
463 | end; |
||
464 | |||
465 | // set the filetime of an extracted file to the value stored in the archive |
||
466 | procedure FileSetDate(const hFile: THandle; const iAge: integer); |
||
467 | var |
||
468 | LocalFileTime, FileTime: TFileTime; |
||
469 | begin |
||
470 | DosDateTimeToFileTime(HIWORD(iAge), LOWORD(iAge), LocalFileTime); |
||
471 | LocalFileTimeToFileTime(LocalFileTime, FileTime); |
||
472 | SetFileTime(hFile, nil, nil, @FileTime); |
||
473 | end; |
||
474 | |||
475 | (*--------------------------------------------------------------------------*) |
||
476 | |||
477 | function UpdC32(Octet: byte; Crc: cardinal): cardinal; |
||
478 | begin |
||
479 | Result := VArr_CRC32Table[byte(Crc xor cardinal(Octet))] xor |
||
480 | ((Crc shr 8) and $00FFFFFF); |
||
481 | end; |
||
482 | |||
483 | (*--------------------------------------------------------------------------*) |
||
484 | |||
485 | // fill crc32 buffer |
||
486 | |||
487 | procedure Crc32_Buf(str: PByte; len: integer; var crc: cardinal); |
||
488 | begin |
||
489 | while len > 0 do |
||
490 | begin |
||
491 | crc := UpdC32(byte(str^), crc); |
||
492 | Inc(str); |
||
493 | Dec(len); |
||
494 | end; |
||
495 | end; |
||
496 | |||
497 | (*--------------------------------------------------------------------------*) |
||
498 | |||
499 | // return the smaller value |
||
500 | |||
501 | function Min(const I1, I2: longint): longint; |
||
502 | begin |
||
503 | if I2 < I1 then |
||
504 | Result := I2 |
||
505 | else |
||
506 | Result := I1; |
||
507 | end; |
||
508 | |||
509 | (*--------------------------------------------------------------------------*) |
||
510 | |||
511 | // unstore the current archive file / uncompressed |
||
512 | |||
513 | procedure Unstore; |
||
514 | var |
||
515 | c: cardinal; |
||
516 | cNumBytes: TWriteFileWritten; |
||
517 | OutBuf: PAnsiChar; |
||
518 | begin |
||
519 | GetMem(OutBuf, Min(VInt_BytesToGo, WSIZE) + 2); |
||
520 | try |
||
521 | while VInt_BytesToGo > 0 do |
||
522 | begin |
||
523 | cNumBytes := Min(VInt_BytesToGo, WSIZE); |
||
524 | CheckFRead(OutBuf^, cNumBytes); |
||
525 | Dec(VInt_BytesToGo, cNumBytes); |
||
526 | if (VRec_ZipHeader.Flag and 1) = 1 then |
||
527 | for c := 0 to cNumBytes - 1 do |
||
528 | begin |
||
529 | OutBuf[c] := AnsiChar(Byte(OutBuf[c]) xor decrypt_byte); |
||
530 | {update_keys} UpdateKeys(byte(OutBuf[c])); |
||
531 | end; |
||
532 | CheckFWrite(VH_OutFile, OutBuf^, cNumBytes, VStr_OutFile); |
||
533 | Crc32_Buf(PByte(outbuf), cNumBytes, VDW_CRC32Val); |
||
534 | end; |
||
535 | finally |
||
536 | FreeMem(OutBuf); |
||
537 | end; |
||
538 | end; |
||
539 | |||
540 | (*--------------------------------------------------------------------------*) |
||
541 | |||
542 | |||
543 | // change input file position |
||
544 | |||
545 | function FSeek(const Offset: int64; const MoveMethod: word): int64; //##FR |
||
546 | {$IFDEF VERD6up} |
||
547 | begin |
||
548 | Result := FileSeek(VH_InFile, Offset, MoveMethod); |
||
549 | end; |
||
550 | {$ELSE} |
||
551 | type |
||
552 | I64Rec = packed record |
||
553 | case integer of |
||
554 | 0: (I: int64); |
||
555 | 1: (Lo, Hi: cardinal); |
||
556 | end; |
||
557 | var |
||
558 | r: I64Rec; |
||
559 | begin |
||
560 | r.I := Offset; |
||
561 | r.Lo := SetFilePointer(VH_InFile, integer(r.Lo), @r.Hi, MoveMethod); |
||
562 | if (r.Lo = cardinal(-1)) and (GetLastError <> 0) then |
||
563 | r.I := -1; |
||
564 | Result := r.i; |
||
565 | end; |
||
566 | |||
567 | {$ENDIF} |
||
568 | (*--------------------------------------------------------------------------*) |
||
569 | |||
570 | // read from input file |
||
571 | |||
572 | function FRead(var Buffer; const cNum: cardinal): cardinal; |
||
573 | var |
||
574 | dummy: TWriteFileWritten; |
||
575 | begin |
||
576 | if ReadFile(VH_InFile, Buffer, cNum, dummy, nil) then |
||
577 | Result := dummy |
||
578 | else |
||
579 | Result := 0; |
||
580 | end; |
||
581 | |||
582 | (*--------------------------------------------------------------------------*) |
||
583 | |||
584 | |||
585 | // read from a file and bail if not all data could be read |
||
586 | |||
587 | procedure CheckFRead(var Buffer; const cNumBytes: cardinal); |
||
588 | var |
||
589 | Read: TWriteFileWritten; |
||
590 | begin |
||
591 | Read := 0; |
||
592 | |||
593 | if (not ReadFile(VH_InFile, Buffer, cNumBytes, Read, nil)) or |
||
594 | (cardinal(Read) <> cNumBytes) then |
||
595 | ErrorHaltID(SFX_Err_ArchiveCorrupted); |
||
596 | end; |
||
597 | |||
598 | (*--------------------------------------------------------------------------*) |
||
599 | |||
600 | |||
601 | // write to a file and bail ifnot all data could be written |
||
602 | |||
603 | procedure CheckFWrite(const FH: THandle; const Buffer; const cNumBytes: cardinal; |
||
604 | const FileName: string); |
||
605 | var |
||
606 | Written: TWriteFileWritten; |
||
607 | begin |
||
608 | Written := 0; |
||
609 | // stop overrun |
||
610 | if cNumBytes > VInt_MaxWrite then |
||
611 | ErrorHaltFmt(SFX_Err_CannotWriteFile, FileName); |
||
612 | // write to memory if file not open and address set |
||
613 | if (FH = INVALID_HANDLE_VALUE) and (VP_SBuf <> nil) then |
||
614 | begin |
||
615 | Move(Buffer, VP_SBuf^, cNumBytes); |
||
616 | Inc(VP_SBuf, cNumBytes); |
||
617 | Written := cNumBytes; |
||
618 | end |
||
619 | else |
||
620 | |||
621 | // don't know why, but sometimes WriteFile returns FALSE though |
||
622 | // all bytes have successfully been written, so do not check the API's result |
||
623 | WriteFile(FH, Buffer, cNumBytes, Written, nil); |
||
624 | |||
625 | // seems to reliably show that all's ok or not |
||
626 | if cardinal(Written) <> cNumBytes then |
||
627 | ErrorHaltFmt(SFX_Err_CannotWriteFile, FileName); |
||
628 | VInt_MaxWrite := VInt_MaxWrite - cNumBytes; |
||
629 | end; |
||
630 | |||
631 | (*--------------------------------------------------------------------------*) |
||
632 | |||
633 | |||
634 | // extract the file's path |
||
635 | function ExtractFilePath(const sFilename: string): string; |
||
636 | var |
||
637 | i: integer; |
||
638 | begin |
||
639 | (* Handle archive relative paths *) |
||
640 | i := Length(sFilename); |
||
641 | if (i = 3) and (Pos(':', sFilename) > 0) then |
||
642 | Result := sFilename |
||
643 | else |
||
644 | begin |
||
645 | while (i > 0) and not CharInSet(sFilename[i], ['\', '/', ':']) do |
||
646 | Dec(i); |
||
647 | if i > 0 then |
||
648 | begin |
||
649 | if CharInSet(sFilename[i], ['\', '/']) then |
||
650 | if i <> 3 then |
||
651 | Dec(i) |
||
652 | else |
||
653 | if sFilename[2] <> ':' then |
||
654 | Dec(i); |
||
655 | end; |
||
656 | Result := Copy(sFilename, 1, i); |
||
657 | end; |
||
658 | end; |
||
659 | |||
660 | (*--------------------------------------------------------------------------*) |
||
661 | |||
662 | // handle relative paths, strip directory name |
||
663 | |||
664 | function ExtractFileName(const sFileName: string): string; |
||
665 | var |
||
666 | I: integer; |
||
667 | begin |
||
668 | (* Handle archive relative paths *) |
||
669 | I := Length(sFileName); |
||
670 | while (I > 0) and not CharInSet(sFileName[I], ['\', '/', ':']) do |
||
671 | Dec(I); |
||
672 | Result := Copy(sFileName, I + 1, MaxInt); |
||
673 | end; |
||
674 | |||
675 | (*--------------------------------------------------------------------------*) |
||
676 | |||
677 | |||
678 | // does the directory exist? |
||
679 | function DirectoryExists(const sDir: string): boolean; |
||
680 | var |
||
681 | Code: integer; |
||
682 | begin |
||
683 | Code := GetFileAttributes(PChar(sDir)); |
||
684 | Result := (Code <> -1) and ((FILE_ATTRIBUTE_DIRECTORY and Code) <> 0); |
||
685 | end; |
||
686 | |||
687 | (*--------------------------------------------------------------------------*) |
||
688 | |||
689 | // does the file exist? |
||
690 | function FileExists(const sFileName: string): boolean; |
||
691 | var |
||
692 | Code: Cardinal; |
||
693 | begin |
||
694 | Code := GetFileAttributes(PChar(sFileName)); |
||
695 | Result := (Code <> Cardinal(-1)); |
||
696 | end; |
||
697 | |||
698 | (*--------------------------------------------------------------------------*) |
||
699 | |||
700 | // force the existence of a directory (and its parents) |
||
701 | |||
702 | function ForceDirectories(sDir: string): boolean; |
||
703 | begin |
||
704 | Result := True; |
||
705 | sDir := RemoveDirSeparator(sDir); |
||
706 | if Length(sDir) = 0 then |
||
707 | exit; |
||
708 | if DirectoryExists(sDir) or (ExtractFilePath(sDir) = sDir) then |
||
709 | Exit; // avoid 'xyz:\' problem. |
||
710 | if not ForceDirectories(ExtractFilePath(sDir)) then |
||
711 | Result := False |
||
712 | else |
||
713 | Result := CreateDirectory(PChar(sDir), nil); |
||
714 | end; |
||
715 | |||
716 | (*--------------------------------------------------------------------------*) |
||
717 | |||
718 | // ensure trailing backslash |
||
719 | |||
720 | function AppendDirSeparator(const sDir: string): string; //##FR modified |
||
721 | var |
||
722 | i: integer; |
||
723 | begin |
||
724 | i := Length(sDir); |
||
725 | Result := sDir; |
||
726 | if i > 0 then |
||
727 | if Result[i] <> Chr_DirSep then |
||
728 | Result := Result + Chr_DirSep; |
||
729 | end; |
||
730 | |||
731 | (*--------------------------------------------------------------------------*) |
||
732 | |||
733 | // ensure NO trailing backslash |
||
734 | |||
735 | function RemoveDirSeparator(const sDir: string): string; |
||
736 | begin |
||
737 | Result := sDir; |
||
738 | while (Length(Result) > 0) and (Result[Length(Result)] = Chr_DirSep) do |
||
739 | SetLength(Result, Length(Result) - 1); |
||
740 | end; |
||
741 | |||
742 | (*--------------------------------------------------------------------------*) |
||
743 | |||
744 | // expand environment variables |
||
745 | |||
746 | function ExpandEnv(const Str: string): string; |
||
747 | var |
||
748 | pch: PChar; |
||
749 | begin |
||
750 | GetMem(pch, MAX_PATH * 2); |
||
751 | try |
||
752 | FillChar(pch^, MAX_PATH * 2, 0); |
||
753 | if ExpandEnvironmentStrings(PChar(Str), pch, (MAX_PATH * 2) - 1) > 0 then |
||
754 | Result := pch |
||
755 | else |
||
756 | Result := ''; |
||
757 | finally |
||
758 | FreeMem(pch); |
||
759 | end; |
||
760 | end; |
||
761 | |||
762 | (*--------------------------------------------------------------------------*) |
||
763 | |||
764 | // show a message box |
||
765 | |||
766 | function MsgBox(const wndpar: HWND; const sMsg, sTitle: string; |
||
767 | const uType: cardinal): integer; |
||
768 | begin |
||
769 | Result := MessageBox(wndPar, PChar(sMsg), PChar(sTitle), uType or MB_TASKMODAL); |
||
770 | end; |
||
771 | |||
772 | (*--------------------------------------------------------------------------*) |
||
773 | // show an error message |
||
774 | |||
775 | procedure ErrorMsgBox(const wndPar: HWND; const sMsg: string); |
||
776 | begin |
||
777 | MsgBox(wndPar, sMsg, PChar(SFXString(SFX_Cap_Err)), MB_ICONSTOP); |
||
778 | end; |
||
779 | |||
780 | procedure ErrorMsgBoxFmt1(const wndPar: HWND; id: integer; const arg1: string); |
||
781 | begin |
||
782 | ErrorMsgBox(wndPar, FmtStrID1(id, arg1)); |
||
783 | end; |
||
784 | |||
785 | (*--------------------------------------------------------------------------*) |
||
786 | |||
787 | // compare two strings / case insensitive |
||
788 | |||
789 | function CompareText(const s1, s2: string): boolean; |
||
790 | begin |
||
791 | Result := (Length(s1) = Length(s2)) and (lstrcmpi(PChar(s1), PChar(s2)) = 0); |
||
792 | end; |
||
793 | |||
794 | (*--------------------------------------------------------------------------*) |
||
795 | |||
796 | // to check correct file size of the input file +++ 08/13/98 |
||
797 | |||
798 | function FindEOCRecord: cardinal; |
||
799 | var |
||
800 | pRec: PZipEndOfCentral; |
||
801 | cBufferSize, cRead, cFilePos: cardinal; |
||
802 | pBuffer: PAnsiChar; |
||
803 | cCurrentPos: cardinal; |
||
804 | c: cardinal; |
||
805 | //loop counter only var for compiler optimization (register value) ##FR |
||
806 | bOK: boolean; |
||
807 | begin |
||
808 | Result := HIGH(cardinal); |
||
809 | // get the needed size of the buffer ( max 65536 + SizeOf( eocd ), min SizeOf( file ) ) |
||
810 | bOK := False; |
||
811 | cBufferSize := GetFileSize(VH_InFile, nil) - cardinal(VInt_FileBegin); |
||
812 | if cBufferSize > 65558 then |
||
813 | cBufferSize := 65558; |
||
814 | |||
815 | if cBufferSize > sizeof(TZipEndOfCentral) then |
||
816 | //if smaller, then no correct zip file |
||
817 | begin |
||
818 | GetMem(pBuffer, cBufferSize); |
||
819 | try |
||
820 | cCurrentPos := FSeek(0, FILE_CURRENT); //##FR mark the current file pos |
||
821 | cFilePos := FSeek(-cBufferSize, FILE_END); |
||
822 | //FSeek is now a function, not a proc, see sfxmisc.pas |
||
823 | cRead := FRead(pBuffer[0], cBufferSize); |
||
824 | FSeek(cCurrentPos, FILE_BEGIN); //##FR jump back to marked filepos |
||
825 | if cRead = cBufferSize then |
||
826 | for c := 0 to cBufferSize - sizeof(TZipEndOfCentral) do |
||
827 | begin |
||
828 | pRec := Pointer(cardinal(pBuffer) + c); |
||
829 | if pRec^.HeaderSig = ZipEndOfCentralSig then |
||
830 | begin |
||
831 | // eocd is found, now check if size is correct ( = pos+22+eocd.commentsize) |
||
832 | if (pRec^.ZipCommentLen + cFilePos + c + |
||
833 | sizeof(TZipEndOfCentral)) = GetFileSize(VH_InFile, nil) then |
||
834 | begin |
||
835 | bOK := True; // set ok flag |
||
836 | Result := cFilePos + c; |
||
837 | Break; |
||
838 | end; |
||
839 | end; |
||
840 | end; |
||
841 | finally |
||
842 | FreeMem(pBuffer); |
||
843 | end; |
||
844 | end; |
||
845 | |||
846 | if not bOK then |
||
847 | ErrorHaltID(SFX_Err_ArchiveCorrupted); |
||
848 | end; |
||
849 | |||
850 | (*--------------------------------------------------------------------------*) |
||
851 | |||
852 | // get the index of a string in an array / case insensitive |
||
853 | |||
854 | function StrArrayIndexOf(s1: string; const args: array of string): integer; |
||
855 | var |
||
856 | i: integer; |
||
857 | begin |
||
858 | Result := -1; |
||
859 | for i := Low(args) to High(args) do |
||
860 | if CompareText(s1, args[i]) then |
||
861 | begin |
||
862 | Result := i; |
||
863 | Break; |
||
864 | end; |
||
865 | end; |
||
866 | |||
867 | (*--------------------------------------------------------------------------*) |
||
868 | |||
869 | // read a sfx header string |
||
870 | {$IFDEF UNICODE} |
||
871 | procedure ReadSFXString(var sToRead: string; const iLen: integer); |
||
872 | var |
||
873 | utf8s: UTF8String; |
||
874 | begin |
||
875 | if iLen > 0 then |
||
876 | begin |
||
877 | SetLength(utf8s, iLen); |
||
878 | CheckFRead(utf8s[1], iLen); |
||
879 | end; |
||
880 | sToRead := String(utf8s); |
||
881 | end; |
||
882 | {$ELSE} |
||
883 | procedure ReadSFXString(var sToRead: string; const iLen: integer); |
||
884 | begin |
||
885 | if iLen > 0 then |
||
886 | begin |
||
887 | SetLength(sToRead, iLen); |
||
888 | CheckFRead(sToRead[1], iLen); |
||
889 | end; |
||
890 | end; |
||
891 | {$ENDIF} |
||
892 | |||
893 | (*--------------------------------------------------------------------------*) |
||
894 | |||
895 | // read a path from registry or return '' |
||
896 | function GetPathFromRegistry(sPath: string): string; |
||
897 | var |
||
898 | sRoot, sValue, sSuffix, sData: string; |
||
899 | i: integer; |
||
900 | c: cardinal; |
||
901 | hkRoot, hkOpen: HKEY; |
||
902 | begin |
||
903 | // format hkxy\reg path\value[|suffix] |
||
904 | Result := ''; |
||
905 | sRoot := ''; |
||
906 | sValue := ''; |
||
907 | sSuffix := ''; |
||
908 | |||
909 | i := Pos(Chr_DirSep, sPath); // root\... |
||
910 | if i > 0 then |
||
911 | begin |
||
912 | sRoot := Copy(sPath, 1, i - 1); |
||
913 | Delete(sPath, 1, i); |
||
914 | i := Pos('|', sPath); // ...|suffix |
||
915 | if i > 0 then |
||
916 | begin |
||
917 | sSuffix := Copy(sPath, i + 1, MaxInt); |
||
918 | Delete(sPath, i, MaxInt); |
||
919 | end; |
||
920 | |||
921 | i := Length(sPath); |
||
922 | while (i > 0) and (sPath[i] <> Chr_DirSep) do |
||
923 | Dec(i); |
||
924 | if (i > 0) and (i < Length(sPath)) then // ..\value |
||
925 | begin |
||
926 | sValue := Copy(sPath, i + 1, MaxInt); |
||
927 | Delete(sPath, i, MaxInt); |
||
928 | end; |
||
929 | |||
930 | case StrArrayIndexOf(sRoot, ['HKEY_CURRENT_USER', 'HKCU', |
||
931 | 'HKEY_LOCAL_MACHINE', 'HKLM', 'HKEY_USERS', 'HKU']) of |
||
932 | 0, 1: hkRoot := HKEY_CURRENT_USER; |
||
933 | 2, 3: hkRoot := HKEY_LOCAL_MACHINE; |
||
934 | 4, 5: hkRoot := HKEY_USERS; |
||
935 | else |
||
936 | hkRoot := 0; |
||
937 | end; |
||
938 | if (hkRoot <> 0) and (RegOpenKey(hkRoot, PChar(sPath), hkOpen) = |
||
939 | ERROR_SUCCESS) then |
||
940 | begin |
||
941 | SetLength(sData, MAX_PATH * 2); |
||
942 | c := Length(sData); |
||
943 | if RegQueryValueEx(hkOpen, PChar(sValue), nil, nil, PByte(PChar(sData)), |
||
944 | @c) = ERROR_SUCCESS then |
||
945 | begin |
||
946 | SetLength(sData, c - 1); // assumed to be reg_sz or reg_expand_sz |
||
947 | i := Pos(';', sData); |
||
948 | if i > 0 then |
||
949 | Delete(sData, i, MaxInt); |
||
950 | Result := AppendDirSeparator(PChar(sData)) + sSuffix; |
||
951 | end; |
||
952 | RegCloseKey(hkRoot); |
||
953 | end; |
||
954 | end; |
||
955 | end; |
||
956 | |||
957 | (*--------------------------------------------------------------------------*) |
||
958 | |||
959 | // expand path to include drive |
||
960 | function ExpandPath(const sRel: string): string; |
||
961 | var |
||
962 | p: PChar; |
||
963 | begin |
||
964 | SetLength(Result, MAX_PATH * 2); |
||
965 | SetLength(Result, GetFullPathName(PChar(sRel), Length(Result), PChar(Result), p)); |
||
966 | end; |
||
967 | |||
968 | (*--------------------------------------------------------------------------*) |
||
969 | |||
970 | // build a volatile path name (sfx_<unique name>) |
||
971 | function GetUniqueVolatilePath: string; |
||
972 | var |
||
973 | LStrDir: string; |
||
974 | LIntLoop: integer; |
||
975 | begin |
||
976 | VBool_CheckDeleteVolatilePath := False; |
||
977 | Result := AppendDirSeparator(ExpandEnv('%temp%')) + 'sfx'; |
||
978 | for LIntLoop := 0 to 99999 do // just 8 chars (dos conventions) |
||
979 | begin |
||
980 | LStrDir := Int2Str(LIntLoop, 0); |
||
981 | LStrDir := Copy('0000', 1, 5 - Length(LStrDir)) + LStrDir; |
||
982 | if not FileExists(Result + LStrDir) then |
||
983 | begin |
||
984 | Result := AppendDirSeparator(Result + LStrDir); |
||
985 | VBool_CheckDeleteVolatilePath := True; |
||
986 | VStr_VolatilePath := Result; // remember volatile path |
||
987 | VStr_VolatilePath_Unexpanded := 'sfx' + LStrDir; |
||
988 | Break; |
||
989 | end; |
||
990 | end; |
||
991 | end; |
||
992 | |||
993 | (*--------------------------------------------------------------------------*) |
||
994 | function PRIMARYLANGID(lang: LANGID): LANGID; inline; |
||
995 | begin |
||
996 | Result := WORD(lang) and $3FF; |
||
997 | end; |
||
998 | |||
999 | procedure ClearLang(var dest: PByte); |
||
1000 | begin |
||
1001 | ReAllocMem(dest, 0); |
||
1002 | VInt_CP := 0; |
||
1003 | end; |
||
1004 | |||
1005 | // MaxCSize protects agains overruns on invalid data |
||
1006 | function LoadStrings(var dest: PByte; MaxCSize: Integer): integer; |
||
1007 | var |
||
1008 | DHead: TSFXStringsData; |
||
1009 | begin |
||
1010 | // load strings |
||
1011 | Result := 0; |
||
1012 | ReAllocMem(dest, 0); |
||
1013 | CheckFRead(DHead, sizeof(TSFXStringsData)); |
||
1014 | if DHead.CSize > MaxCSize then |
||
1015 | Result := -1 // failed sanity check |
||
1016 | else |
||
1017 | begin |
||
1018 | ReAllocMem(dest, DHead.USize + 4); |
||
1019 | VP_SBuf := dest; |
||
1020 | VDW_CRC32Val := CRC_MASK; |
||
1021 | VInt_MaxWrite := DHead.USize; |
||
1022 | VInt_BytesToGo := DHead.CSize; |
||
1023 | InFlate(nil, 0); |
||
1024 | end; |
||
1025 | if (Result <> 0) or (DHead.CRC <> (VDW_CRC32Val xor $FFFFFFFF)) then |
||
1026 | begin |
||
1027 | ClearLang(dest); |
||
1028 | Result := -1; |
||
1029 | end; |
||
1030 | end; |
||
1031 | |||
1032 | |||
1033 | // Set language strings |
||
1034 | procedure SetLangStrings(hLC: hWnd); |
||
1035 | var |
||
1036 | UILang: LANGID; |
||
1037 | i, lng: integer; |
||
1038 | idx: cardinal; |
||
1039 | PHead: PSFX_LanguageData; |
||
1040 | tmp: PChar; |
||
1041 | begin |
||
1042 | if (hLC = 0) {or (VRec_SHeader.Count < 1) or (pl = nil)} then |
||
1043 | exit; |
||
1044 | UILang := GetUserDefaultLangID; |
||
1045 | idx := 0; |
||
1046 | |||
1047 | tmp := PChar(GetXBuf(256)); |
||
1048 | // add US (English) first |
||
1049 | // if GetLocaleInfo($0409, LOCALE_SNATIVELANGNAME, tmp, 120) <> 0 then |
||
1050 | // SendMessage(hLC, CB_ADDSTRING, 0, integer(tmp)); |
||
1051 | SendMessage(hLC, CB_ADDSTRING, 0, LPARAM(pChar('Default (US)'))); |
||
1052 | i := 1; |
||
1053 | PHead := LoadResource(SFX_LANG_BASE + i); |
||
1054 | while (PHead <> nil) and (PHead^.LangID <> 0) do |
||
1055 | begin |
||
1056 | lng := PHead^.LangID; |
||
1057 | if GetLocaleInfo(Lng, LOCALE_SNATIVELANGNAME, tmp, 120) <> 0 then |
||
1058 | begin |
||
1059 | SendMessage(hLC, CB_ADDSTRING, 0, LPARAM(tmp)); |
||
1060 | if PRIMARYLANGID(lng) = PRIMARYLANGID(UILang) then |
||
1061 | idx := i; |
||
1062 | end; |
||
1063 | inc(i); |
||
1064 | PHead := LoadResource(SFX_LANG_BASE + i); |
||
1065 | end; |
||
1066 | SendMessage(hLC, CB_SETCURSEL, idx, 0); // set default |
||
1067 | end; |
||
1068 | |||
1069 | |||
1070 | function LoadLang(var dest: PByte; resID: integer): integer; |
||
1071 | const |
||
1072 | MaxCSize = 10000; // ??? |
||
1073 | var |
||
1074 | PHead: PSFX_LanguageData; |
||
1075 | p: PAnsiChar; |
||
1076 | begin |
||
1077 | // load selected strings |
||
1078 | Result := 0; |
||
1079 | ClearLang(dest); |
||
1080 | if resID <= 0 then |
||
1081 | exit; // use default |
||
1082 | Result := -1; |
||
1083 | PHead := LoadResource(resID); |
||
1084 | if (PHead <> nil) and (PHead^.CSize < MaxCSize) then |
||
1085 | begin |
||
1086 | Result := PHead^.LangID; |
||
1087 | VInt_CP := DefCP(Result); |
||
1088 | ReAllocMem(dest, PHead.USize + 4); |
||
1089 | VP_SBuf := dest; |
||
1090 | VDW_CRC32Val := CRC_MASK; |
||
1091 | VInt_MaxWrite := PHead.USize; |
||
1092 | VInt_BytesToGo := PHead.CSize; |
||
1093 | p := PAnsiChar(PHead); |
||
1094 | inc(p, sizeof(TSFX_LanguageData)); // point to data |
||
1095 | InFlate(p ,PHead.CSize); |
||
1096 | end; |
||
1097 | if (Result <= 0) or (PHead.CRC <> (VDW_CRC32Val xor $FFFFFFFF)) then |
||
1098 | begin |
||
1099 | ClearLang(dest); |
||
1100 | Result := -1; |
||
1101 | end; |
||
1102 | VP_SBuf := nil; |
||
1103 | end; |
||
1104 | |||
1105 | procedure SetLanguage; |
||
1106 | var |
||
1107 | Def: LANGID; |
||
1108 | i, pri: integer; |
||
1109 | psd: PSFX_LanguageData; |
||
1110 | begin |
||
1111 | VRec_Strings := nil; |
||
1112 | // strings are optional |
||
1113 | psd := LoadResource(SFX_LANG_BASE + 1); |
||
1114 | if psd <> nil then |
||
1115 | begin |
||
1116 | // we have strings - load initial |
||
1117 | pri := -1; |
||
1118 | // try for 'default' language |
||
1119 | Def := GetUserDefaultLangID; |
||
1120 | if Def <> $0409 then |
||
1121 | begin |
||
1122 | i := 1;//0; |
||
1123 | while psd <> nil do |
||
1124 | begin |
||
1125 | if psd^.LangID = Def then |
||
1126 | break; |
||
1127 | if (PRIMARYLANGID(psd^.LangID) = PRIMARYLANGID(Def)) then |
||
1128 | pri := i; |
||
1129 | inc(i); |
||
1130 | psd := LoadResource(SFX_LANG_BASE + i); // try next |
||
1131 | end; |
||
1132 | if pri > 0 then |
||
1133 | LoadLang(VRec_Strings, SFX_LANG_BASE + pri); |
||
1134 | end; |
||
1135 | // Display the dialog |
||
1136 | if DialogBox(hInstance, Str_Dlg_Language, 0, @LanguageQueryDialogProc) = |
||
1137 | ID_BTN_NO then |
||
1138 | Halt; |
||
1139 | |||
1140 | // load selected strings |
||
1141 | if (VInt_CurLang <> pri) then |
||
1142 | begin |
||
1143 | if (VInt_CurLang > 0) then |
||
1144 | LoadLang(VRec_Strings, SFX_LANG_BASE + VInt_CurLang) |
||
1145 | else |
||
1146 | ClearLang(VRec_Strings); |
||
1147 | end; |
||
1148 | end; |
||
1149 | VP_SBuf := nil; |
||
1150 | end; |
||
1151 | |||
1152 | // Returns a boolean indicating whether or not we're running under XP or later. |
||
1153 | function WinVersion: integer; |
||
1154 | var |
||
1155 | osv: TOSVERSIONINFO; |
||
1156 | begin |
||
1157 | osv.dwOSVersionInfoSize := sizeOf(OSVERSIONINFO); |
||
1158 | GetVersionEx(osv); |
||
1159 | Result := (osv.dwMajorVersion *1000) + osv.dwMinorVersion; |
||
1160 | end; |
||
1161 | |||
1162 | // check manual override of AutoRun |
||
1163 | function Manual: Boolean; |
||
1164 | var |
||
1165 | cp: PChar; |
||
1166 | c0, c1, c2: Char; |
||
1167 | begin |
||
1168 | Result := False; |
||
1169 | cp := GetCommandLine; |
||
1170 | if cp = nil then |
||
1171 | Exit; |
||
1172 | c0 := #0; |
||
1173 | c1 := #0; |
||
1174 | c2 := #0; |
||
1175 | while cp^ <> #0 do |
||
1176 | begin |
||
1177 | c0 := c1; |
||
1178 | c1 := c2; |
||
1179 | c2 := cp^; |
||
1180 | cp := CharNext(cp); |
||
1181 | end; |
||
1182 | if c0 > ' ' then |
||
1183 | Exit; |
||
1184 | if c1 <> '/' then |
||
1185 | Exit; |
||
1186 | Result := (c2 = 'm') or (c2 = 'M'); |
||
1187 | end; |
||
1188 | |||
1189 | // read TSFXFileHeader from input file |
||
1190 | procedure GetDefParams; // reads the values from the special header |
||
1191 | type |
||
1192 | T_DetachedArgs = packed record |
||
1193 | Size: WORD; // size of full record including sig |
||
1194 | Pads: WORD; // number of bytes to keep DWORD aligned |
||
1195 | end; |
||
1196 | var |
||
1197 | Sig: cardinal; |
||
1198 | CmdStrs: PByte; |
||
1199 | PathSize: Integer; |
||
1200 | StartMsgSize: Integer; |
||
1201 | begin |
||
1202 | CmdStrs := nil; |
||
1203 | VInt_FileBegin := GetExeSize; |
||
1204 | VP_SBuf := nil; |
||
1205 | FSeek(VInt_FileBegin, FILE_BEGIN); |
||
1206 | |||
1207 | CheckFRead(VRec_SFXHeader, sizeof(VRec_SFXHeader)); |
||
1208 | |||
1209 | with VRec_SFXHeader do |
||
1210 | begin |
||
1211 | if (Signature <> SFX_HEADER_SIG) then |
||
1212 | ErrorHaltID(SFX_Err_ArchiveCorrupted); |
||
1213 | // get command strings |
||
1214 | if (so_CompressedCmd and Options) <> 0 then |
||
1215 | begin |
||
1216 | if LoadStrings(CmdStrs, VRec_SFXHeader.Size - sizeof(VRec_SFXHeader)) <> 0 then |
||
1217 | ErrorHaltID(SFX_Err_ArchiveCorrupted); |
||
1218 | VP_SBuf := nil; |
||
1219 | FSeek(VInt_FileBegin + VRec_SFXHeader.Size, FILE_BEGIN); |
||
1220 | end |
||
1221 | else |
||
1222 | begin |
||
1223 | ReAllocMem(CmdStrs, size - sizeof(TSFXFileHeader)); |
||
1224 | CheckFRead(CmdStrs^, size - sizeof(TSFXFileHeader)); |
||
1225 | end; |
||
1226 | // check for sfx header |
||
1227 | VInt_SpanType := SFXSpanTypeNone; // default |
||
1228 | |||
1229 | VStr_SFX_Caption := LoadSFXStr(CmdStrs, sc_Caption); |
||
1230 | if VStr_SFX_Caption = '' then |
||
1231 | VStr_SFX_Caption := SFXString(SFX_Cap_App); |
||
1232 | |||
1233 | VStr_SFX_Path := LoadSFXStr(CmdStrs, sc_Path); |
||
1234 | VStr_SFX_CmdLine := LoadSFXStr(CmdStrs, sc_CmdLine); |
||
1235 | VStr_SFX_RegFailPath := LoadSFXStr(CmdStrs, sc_RegFailPath); |
||
1236 | VStr_SFX_StartMsg := LoadSFXStr(CmdStrs, sc_StartMsg); |
||
1237 | ReAllocMem(CmdStrs, 0); // finished with it |
||
1238 | PathSize := Length(VStr_SFX_Path); |
||
1239 | StartMsgSize := Length(VStr_SFX_StartMsg); |
||
1240 | |||
1241 | //get the path from registry, added 10/10/98 ##FR |
||
1242 | if CompareText('HK', Copy(VStr_SFX_Path, 1, 2)) then |
||
1243 | begin |
||
1244 | VStr_SFX_Path := GetPathFromRegistry(VStr_SFX_Path); |
||
1245 | if VStr_SFX_Path = '' then |
||
1246 | begin |
||
1247 | if VStr_SFX_RegFailPath <> '' then |
||
1248 | VStr_SFX_Path := VStr_SFX_RegFailPath |
||
1249 | else |
||
1250 | VStr_SFX_Path := '><'; // substitue to temp path below |
||
1251 | end; |
||
1252 | end; |
||
1253 | |||
1254 | while Pos('><', VStr_SFX_Path) > 0 do |
||
1255 | VStr_SFX_Path := FmtStr1(VStr_SFX_Path, AppendDirSeparator(ExpandEnv('%temp%'))); |
||
1256 | |||
1257 | // added april 20, 2002: substitute environment variables |
||
1258 | if (so_ExpandVariables and Options) <> 0 then |
||
1259 | begin |
||
1260 | VStr_SFX_Path := ExpandEnv(VStr_SFX_Path); |
||
1261 | VStr_SFX_Caption := ExpandEnv(VStr_SFX_Caption); |
||
1262 | VStr_SFX_StartMsg := ExpandEnv(VStr_SFX_StartMsg); |
||
1263 | VStr_SFX_CmdLine := ExpandEnv(VStr_SFX_CmdLine); |
||
1264 | end; |
||
1265 | |||
1266 | if PathSize = 0 then // Stored path |
||
1267 | VStr_ExtractPath := GetCurDir |
||
1268 | else |
||
1269 | begin |
||
1270 | // aug 26, 2002: added support for volatile extract directory |
||
1271 | if CompareText(VStr_SFX_Path, '<VOLATILE>') then |
||
1272 | VStr_ExtractPath := GetUniqueVolatilePath |
||
1273 | else |
||
1274 | VStr_ExtractPath := ExpandPath(VStr_SFX_Path); |
||
1275 | end; |
||
1276 | |||
1277 | // shall we show the message ? |
||
1278 | if (StartMsgSize > 0) and (MsgBox(0, VStr_SFX_StartMsg, VStr_SFX_Caption, |
||
1279 | StartMsgType) in [idCancel, idAbort, idNo, IDCLOSE]) then |
||
1280 | Halt; |
||
1281 | |||
1282 | // check autorun flag |
||
1283 | if ((so_AutoRun or so_CheckAutoRunFileName) and Options) = |
||
1284 | (so_AutoRun or so_CheckAutoRunFileName) then |
||
1285 | begin |
||
1286 | if ((WinVersion >= 6000) and (nvVerifyTrust(VStr_ExeName) <> 0)) or Manual or |
||
1287 | (CompareText(ExtractFileName(VStr_ExeName), 'Setup.exe') or |
||
1288 | (ExtractFileName(VStr_ExeName)[1] = '!')) then |
||
1289 | Options := Options and (not so_AutoRun); |
||
1290 | end; |
||
1291 | end; |
||
1292 | |||
1293 | // at beginning of file or detached header |
||
1294 | // might have detached header |
||
1295 | CheckFRead(Sig, sizeof(Sig)); |
||
1296 | (*@@ |
||
1297 | if (Sig = SFX_DETACHED_HEADER_SIG) then |
||
1298 | begin |
||
1299 | // load detached name |
||
1300 | CheckFRead(DetArgs, sizeof(DetArgs)); |
||
1301 | i := DetArgs.Size - SizeOf(TSFXDetachedHeader) - DetArgs.Pads; |
||
1302 | ReadSFXString(VStr_DetachName, i); |
||
1303 | // skip pads |
||
1304 | if DetArgs.Pads > 0 then |
||
1305 | FSeek(DetArgs.Pads, FILE_CURRENT); |
||
1306 | CheckFRead(Sig, sizeof(Sig)); |
||
1307 | end; |
||
1308 | *) |
||
1309 | // check the signature following |
||
1310 | if Sig = ZipCentralHeaderSig then |
||
1311 | VInt_SpanType := SFXSpanTypeMultiVol; // is span but type unknown |
||
1312 | // reposition to before local/central signature |
||
1313 | VInt_FileBegin := FSeek(-sizeof(Sig), FILE_CURRENT); |
||
1314 | end; |
||
1315 | |||
1316 | (*--------------------------------------------------------------------------*) |
||
1317 | |||
1318 | //// get operating system type (nt/win) |
||
1319 | //function IsWinNT: boolean; |
||
1320 | //var |
||
1321 | // osvi: TOSVersionInfo; |
||
1322 | //begin |
||
1323 | // osvi.dwOSVersionInfoSize := SizeOf(OSvi); |
||
1324 | // Result := GetVersionEx(OSVI) and (osvi.dwPlatformID = VER_PLATFORM_WIN32_NT); |
||
1325 | //end; |
||
1326 | |||
1327 | (*--------------------------------------------------------------------------*) |
||
1328 | |||
1329 | //##FR execute inf-scripts using rundll, not nice but works! |
||
1330 | |||
1331 | function ExecInf(const Path: String): cardinal; |
||
1332 | (*var |
||
1333 | osvi: TOSVersionInfo;*) |
||
1334 | //var |
||
1335 | // cmd: AnsiString; |
||
1336 | // HINSTANCE: HINST; |
||
1337 | begin |
||
1338 | // HINSTANCE |
||
1339 | Result := ShellExecute(VH_MainWnd, PChar('open'), PChar('rundll32.exe'), |
||
1340 | PChar('SetupApi,InstallHinfSection DefaultInstall 132 ' + Path), |
||
1341 | nil, SW_SHOW); |
||
1342 | // Result := HINSTANCE;// > 32; |
||
1343 | (*if Param = '.ntx86' then Param := Param + ' ' |
||
1344 | else |
||
1345 | Param := ''; |
||
1346 | |||
1347 | if IsWinNT |
||
1348 | then |
||
1349 | Path := 'rundll32.exe setupapi.dll, |
||
1350 | InstallHinfSection DefaultInstall' + Param + '132 ' + Path |
||
1351 | else*) |
||
1352 | // cmd := 'rundll.exe setupapi.dll,InstallHinfSection DefaultInstall 132 ' |
||
1353 | // + AnsiString(Path); |
||
1354 | // Result := WinExec(PAnsiChar(cmd), SW_SHOW); |
||
1355 | // Result := WinExec(PAnsiChar( |
||
1356 | // 'rundll.exe setupapi.dll,InstallHinfSection DefaultInstall 132 ' |
||
1357 | // + Path), SW_SHOW); |
||
1358 | (*osvi.dwOSVersionInfoSize := SizeOf(OSvi); |
||
1359 | if GetVersionEx(OSVI) then |
||
1360 | begin |
||
1361 | case osvi.dwPlatformID of |
||
1362 | VER_PLATFORM_WIN32_WINDOWS: Path := |
||
1363 | 'rundll.exe setupx.dll,InstallHinfSection DefaultInstall 132 ' + Path; |
||
1364 | VER_PLATFORM_WIN32_NT: Path := |
||
1365 | 'rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall' + |
||
1366 | Param + '132 ' + Path; |
||
1367 | else |
||
1368 | // no win32 s |
||
1369 | end; |
||
1370 | Result := WinExec(PChar(Path), SW_SHOW); |
||
1371 | end;*) |
||
1372 | |||
1373 | end; |
||
1374 | |||
1375 | (*--------------------------------------------------------------------------*) |
||
1376 | |||
1377 | function Trim(s: string): string; |
||
1378 | // strip trailing #0 and double separators |
||
1379 | begin |
||
1380 | Result := PChar(s); |
||
1381 | while Pos('\\', Result) > 0 do |
||
1382 | Delete(Result, Pos('\\', Result), 1); |
||
1383 | end; |
||
1384 | |||
1385 | (*--------------------------------------------------------------------------*) |
||
1386 | |||
1387 | // remove extract directory next time a user logs on |
||
1388 | |||
1389 | procedure RemoveDirEx; |
||
1390 | var |
||
1391 | LStrCmd: string; |
||
1392 | LHKSub: HKEY; |
||
1393 | LBoolSuccess: boolean; |
||
1394 | begin |
||
1395 | // if IsWinNT then |
||
1396 | // if Win32Platform = VER_PLATFORM_WIN32_NT then |
||
1397 | if WinVersion >= 5000 then |
||
1398 | // the following does not work with all types of drives |
||
1399 | (*LStrCmd := 'cmd.exe /c @if exist "'+RemoveDirSeparator(VStr_VolatilePath)+ |
||
1400 | '\nul" rd /s /q "'+RemoveDirSeparator(VStr_VolatilePath)+'"'*) |
||
1401 | LStrCmd := 'cmd.exe /c @rd /s /q "%temp%\' + VStr_VolatilePath_Unexpanded + '">nul 2>nul' |
||
1402 | else |
||
1403 | // the following does not work with all types of drives |
||
1404 | (*LStrCmd := 'command.com /c @if exist "'+RemoveDirSeparator(VStr_VolatilePath)+ |
||
1405 | '\nul" deltree /y "'+RemoveDirSeparator(VStr_VolatilePath)+'"';*) |
||
1406 | LStrCmd := 'command.com /c deltree /y "%temp%\' + VStr_VolatilePath_Unexpanded + '">nul'; |
||
1407 | |||
1408 | if RegCreateKey(HKEY_LOCAL_MACHINE, |
||
1409 | 'Software\Microsoft\Windows\CurrentVersion\RunOnce', LHKSub) = ERROR_SUCCESS then |
||
1410 | begin |
||
1411 | LBoolSuccess := RegSetValueEx(LHKSub, PChar(VStr_VolatilePath_Unexpanded), |
||
1412 | 0, REG_SZ, PChar(LStrCmd), Length(LStrCmd) + 1) = ERROR_SUCCESS; |
||
1413 | RegCloseKey(LHKSub); |
||
1414 | end |
||
1415 | else |
||
1416 | LBoolSuccess := False; |
||
1417 | |||
1418 | // try current user if not successfull |
||
1419 | if (not LBoolSuccess) and (RegCreateKey(HKEY_CURRENT_USER, |
||
1420 | 'Software\Microsoft\Windows\CurrentVersion\RunOnce', LHKSub) = |
||
1421 | ERROR_SUCCESS) then |
||
1422 | begin |
||
1423 | RegSetValueEx(LHKSub, PChar(VStr_VolatilePath_Unexpanded), 0, |
||
1424 | REG_SZ, PChar(LStrCmd), Length(LStrCmd) + 1); |
||
1425 | RegCloseKey(LHKSub); |
||
1426 | end; |
||
1427 | end; |
||
1428 | |||
1429 | (*--------------------------------------------------------------------------*) |
||
1430 | |||
1431 | //##FR modified to enable inf-scripts |
||
1432 | |||
1433 | function ExecuteCMD: cardinal; |
||
1434 | // parses and executes the stored command line after extraction |
||
1435 | var |
||
1436 | sr1, sr2: string; |
||
1437 | srOld: string; |
||
1438 | begin |
||
1439 | Result := 0; |
||
1440 | sr1 := Trim(GetArgument(1)); |
||
1441 | sr2 := Trim(GetArgument(2)); |
||
1442 | srOld := GetCurDir; |
||
1443 | if Length(VStr_ExtractPath) <> 0 then |
||
1444 | ChDir(VStr_ExtractPath); |
||
1445 | if Length(sr1) > 4 then |
||
1446 | begin |
||
1447 | if TestForInf(sr1) then |
||
1448 | Result := ExecInf(sr1) //error if < 32 |
||
1449 | else |
||
1450 | Result := ShellExecute(0, 'open', PChar(sr1), PChar(sr2), |
||
1451 | PChar(VStr_ExtractPath), SW_SHOW); |
||
1452 | end; |
||
1453 | ChDir(srOld); |
||
1454 | // aug 26, 2002: added support for volatile extract path |
||
1455 | if (Result >= 32) and VBool_CheckDeleteVolatilePath and |
||
1456 | CompareText(RemoveDirSeparator(VStr_VolatilePath), |
||
1457 | RemoveDirSeparator(VStr_ExtractPath)) and |
||
1458 | DirectoryExists(RemoveDirSeparator(VStr_VolatilePath)) then |
||
1459 | RemoveDirEx; |
||
1460 | end; |
||
1461 | |||
1462 | (*--------------------------------------------------------------------------*) |
||
1463 | |||
1464 | |||
1465 | function FmtStrID1(id: integer; const arg1: string): string; |
||
1466 | begin |
||
1467 | Result := FmtStr1(SFXString(id), arg1); |
||
1468 | end; |
||
1469 | |||
1470 | function FmtStr1(const sFormat: string; const arg1: string): string; |
||
1471 | var |
||
1472 | j: integer; |
||
1473 | begin |
||
1474 | Result := sFormat; |
||
1475 | j := Pos('><', Result); |
||
1476 | if j > 0 then |
||
1477 | Result := Copy(Result, 1, j - 1) + arg1 + Copy(Result, j + 2, MaxInt); |
||
1478 | end; |
||
1479 | |||
1480 | function FmtStr2(const sFormat: string; const arg1, arg2: string): string; |
||
1481 | begin |
||
1482 | Result := FmtStr1(FmtStr1(sFormat, arg1), arg2); |
||
1483 | end; |
||
1484 | |||
1485 | (*--------------------------------------------------------------------------*) |
||
1486 | |||
1487 | function GetArgument(const iIndex: integer): string; |
||
1488 | // gets an argument from the stored command line |
||
1489 | // 1 : the part before the pipe (if there's no pipe, |
||
1490 | // returns the whole command line) |
||
1491 | // 2 : the part after the pipe (if no pipe, returns "") |
||
1492 | // all "><" will be replaced by the extraction path |
||
1493 | var |
||
1494 | pip: integer; |
||
1495 | begin |
||
1496 | VStr_ExtractPath := AppendDirSeparator(VStr_ExtractPath); |
||
1497 | Result := VStr_SFX_CmdLine; |
||
1498 | pip := Pos('|', Result); |
||
1499 | if pip = 0 then |
||
1500 | begin |
||
1501 | if iIndex = 2 then |
||
1502 | Result := ''; |
||
1503 | end |
||
1504 | else |
||
1505 | begin |
||
1506 | if iIndex = 1 then |
||
1507 | Result := Copy(Result, 1, pip - 1) |
||
1508 | else |
||
1509 | Result := Copy(Result, pip + 1, MAXINT); |
||
1510 | end; |
||
1511 | |||
1512 | while Pos('><', Result) > 0 do |
||
1513 | Result := FmtStr1(Result, VStr_ExtractPath); |
||
1514 | |||
1515 | // get the short (8+3)-filename (it seems that shellexecute has some problems with lfn) |
||
1516 | GetShortPathName(PChar(Result), PChar(Result), Length(Result)); |
||
1517 | end; |
||
1518 | |||
1519 | (*--------------------------------------------------------------------------*) |
||
1520 | |||
1521 | function TestForInf(const sr1: string): boolean; |
||
1522 | begin |
||
1523 | Result := CompareText('.inf', Copy(sr1, Length(sr1) - 3, 4)); |
||
1524 | end; |
||
1525 | |||
1526 | (*--------------------------------------------------------------------------*) |
||
1527 | |||
1528 | function GetRunString(const sRun, sInst: string): string; |
||
1529 | var |
||
1530 | sr1: string; |
||
1531 | begin |
||
1532 | sr1 := ExtractFileName(GetArgument(1)); |
||
1533 | if TestForInf(sr1) then |
||
1534 | Result := FmtStr2(sRun, sr1, ExtractFileName(GetArgument(2))) |
||
1535 | else |
||
1536 | begin |
||
1537 | if sr1 = '' then |
||
1538 | begin |
||
1539 | sr1 := GetArgument(1); |
||
1540 | if sr1 <> '' then |
||
1541 | sr1 := ExtractFileName(RemoveDirSeparator(sr1)); |
||
1542 | end; |
||
1543 | Result := FmtStr2(sInst, sr1, ExtractFileName(GetArgument(2))); |
||
1544 | end; |
||
1545 | end; |
||
1546 | |||
1547 | (*--------------------------------------------------------------------------*) |
||
1548 | |||
1549 | function GetRunCheckBoxText: string; |
||
1550 | begin |
||
1551 | Result := GetRunString(SFXString(SFX_Msg_RunCheckBox_Run), |
||
1552 | SFXString(SFX_Msg_RunCheckBox_Inst)); |
||
1553 | end; |
||
1554 | |||
1555 | (*--------------------------------------------------------------------------*) |
||
1556 | |||
1557 | // get an error message if ExcuteCMD failed |
||
1558 | function GetRunErrorMessage: string; |
||
1559 | begin |
||
1560 | Result := GetRunString(SFXString(SFX_Err_Run_Run), SFXString(SFX_Err_Run_Inst)); |
||
1561 | end; |
||
1562 | |||
1563 | (*--------------------------------------------------------------------------*) |
||
1564 | |||
1565 | |||
1566 | procedure ProcessMessages; |
||
1567 | var |
||
1568 | Msg: TMsg; |
||
1569 | begin |
||
1570 | { PeekMessage(Msg, 0, 0, 0, PM_REMOVE); |
||
1571 | TranslateMessage(Msg); |
||
1572 | DispatchMessage(Msg); } |
||
1573 | while (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) do |
||
1574 | begin |
||
1575 | if not IsDialogMessage(0, msg) then |
||
1576 | begin |
||
1577 | TranslateMessage(msg); |
||
1578 | DispatchMessage(msg); |
||
1579 | end; |
||
1580 | end; |
||
1581 | end; |
||
1582 | |||
1583 | (*--------------------------------------------------------------------------*) |
||
1584 | |||
1585 | procedure Make_CRC32Table; |
||
1586 | var |
||
1587 | i, j: word; |
||
1588 | r: cardinal; |
||
1589 | const |
||
1590 | CRCPOLY = $EDB88320; |
||
1591 | UCHAR_MAX = 255; |
||
1592 | CHAR_BIT = 8; |
||
1593 | begin |
||
1594 | for i := 0 to UCHAR_MAX do |
||
1595 | begin |
||
1596 | r := i; |
||
1597 | for j := CHAR_BIT downto 1 do |
||
1598 | if (r and 1) > 0 then |
||
1599 | r := (r shr 1) xor CRCPOLY |
||
1600 | else |
||
1601 | r := r shr 1; |
||
1602 | VArr_CRC32Table[i] := r; |
||
1603 | end; |
||
1604 | end; |
||
1605 | |||
1606 | (*--------------------------------------------------------------------------*) |
||
1607 | |||
1608 | // Update the encryption keys with the next byte of plain text |
||
1609 | |||
1610 | procedure UpdateKeys(c: byte); |
||
1611 | begin |
||
1612 | VArr_CryptKey[0] := UpdC32(c, VArr_CryptKey[0]); |
||
1613 | VArr_CryptKey[1] := VArr_CryptKey[1] + VArr_CryptKey[0] and $000000FF; |
||
1614 | VArr_CryptKey[1] := VArr_CryptKey[1] * 134775813 + 1; |
||
1615 | VArr_CryptKey[2] := UpdC32(HIBYTE(HIWORD(VArr_CryptKey[1])), VArr_CryptKey[2]); |
||
1616 | end; |
||
1617 | |||
1618 | (*--------------------------------------------------------------------------*) |
||
1619 | |||
1620 | // Initialize the encryption keys and the random header according to the given password. |
||
1621 | |||
1622 | procedure seedk(passwd: AnsiString); |
||
1623 | var |
||
1624 | i: byte; |
||
1625 | begin |
||
1626 | VArr_CryptKey[0] := 305419896; |
||
1627 | VArr_CryptKey[1] := 591751049; |
||
1628 | VArr_CryptKey[2] := 878082192; |
||
1629 | for i := 1 to LENGTH(passwd) do |
||
1630 | UpdateKeys(byte(passwd[i])); |
||
1631 | end; |
||
1632 | |||
1633 | (*--------------------------------------------------------------------------*) |
||
1634 | |||
1635 | // Return the next byte in the pseudo-random sequence |
||
1636 | |||
1637 | function decrypt_byte: integer; |
||
1638 | var |
||
1639 | temp: word; |
||
1640 | begin |
||
1641 | temp := word(VArr_CryptKey[2] or 2); |
||
1642 | Result := integer(word((temp * (temp xor 1)) shr 8) and $FF); |
||
1643 | end; |
||
1644 | |||
1645 | (*--------------------------------------------------------------------------*) |
||
1646 | |||
1647 | function decrypt_pw(Encrypt_Head: PAnsiChar; EncHead_len: byte; BitFlag: word; |
||
1648 | CRC, FileDate: longint; const sPassword: AnsiString): boolean; |
||
1649 | var |
||
1650 | i, c, b: byte; |
||
1651 | begin |
||
1652 | Result := False; |
||
1653 | if sPassword = '' then |
||
1654 | Exit; |
||
1655 | seedk(sPassword); |
||
1656 | for i := 0 to EncHead_len - 1 do |
||
1657 | begin |
||
1658 | c := byte(Encrypt_Head[i + EncHead_len]) xor decrypt_byte; |
||
1659 | UpdateKeys(c); |
||
1660 | Encrypt_Head[i] := AnsiChar(c); |
||
1661 | end; |
||
1662 | |||
1663 | (* version 2.0+ *) |
||
1664 | b := byte(Encrypt_Head[EncHead_len - 1]); |
||
1665 | |||
1666 | if not ((BitFlag and 8) = 8) then |
||
1667 | begin |
||
1668 | if b = HIBYTE(HIWORD(crc)) then |
||
1669 | Result := True; |
||
1670 | end |
||
1671 | else |
||
1672 | begin |
||
1673 | if b = LOWORD(FileDate) shr 8 then |
||
1674 | Result := True; |
||
1675 | end; |
||
1676 | end; |
||
1677 | |||
1678 | (*--------------------------------------------------------------------------*) |
||
1679 | |||
1680 | // added october 10, 1998 |
||
1681 | // enable/disable all children of the given parent window |
||
1682 | // this is used to disable all main dialog's controls during archive extraction |
||
1683 | // thanks to David - Kazuya david-kazuya@usa.net for report |
||
1684 | |||
1685 | procedure EnableChildren(const wnd: HWND; const bEnable: boolean); |
||
1686 | |||
1687 | function FindChE(wnd: HWND; lParam: LPARAM): Bool; stdcall; |
||
1688 | var |
||
1689 | pCH: array[0..64] of char; |
||
1690 | begin |
||
1691 | Result := True; |
||
1692 | GetClassName(wnd, @pCH, 63); |
||
1693 | if IsWindowVisible(wnd) and (pCH <> 'msctls_progress32') then |
||
1694 | EnableWindow(wnd, boolean(lParam)); |
||
1695 | end; |
||
1696 | |||
1697 | begin |
||
1698 | EnumChildWindows(wnd, @FindChE, integer(bEnable)); |
||
1699 | end; |
||
1700 | |||
1701 | (*--------------------------------------------------------------------------*) |
||
1702 | |||
1703 | // resize dialog/control |
||
1704 | |||
1705 | procedure ResizeControl(const wnd: HWND; const bReposition: boolean; yDiff: integer); |
||
1706 | var |
||
1707 | pl: TWindowPlacement; |
||
1708 | begin |
||
1709 | yDiff := MulDiv(yDiff, HIWORD(GetDialogBaseUnits), 8); |
||
1710 | pl.length := sizeof(pl); |
||
1711 | GetWindowPlacement(wnd, @pl); |
||
1712 | if bReposition then |
||
1713 | pl.rcNormalPosition.Top := |
||
1714 | pl.rcNormalPosition.Top + yDiff; |
||
1715 | pl.rcNormalPosition.Bottom := pl.rcNormalPosition.Bottom + yDiff; |
||
1716 | SetWindowPlacement(wnd, @pl); |
||
1717 | end; |
||
1718 | |||
1719 | (*--------------------------------------------------------------------------*) |
||
1720 | |||
1721 | // from Angus Johnson's TZip-SFX code: |
||
1722 | // get the executable's file size to get rid of caring about the exe size |
||
1723 | function GetExeSize: cardinal; |
||
1724 | {$ifdef DEBUG_SFX} |
||
1725 | begin |
||
1726 | Result := Test_Stub_Size; |
||
1727 | end; |
||
1728 | {$else} |
||
1729 | var |
||
1730 | p: PByte; |
||
1731 | i, NumSections: integer; |
||
1732 | const |
||
1733 | IMAGE_PE_SIGNATURE = $00004550; |
||
1734 | begin |
||
1735 | Result := 0; |
||
1736 | p := pointer(hinstance); |
||
1737 | if (PImageDosHeader(p).e_magic <> IMAGE_DOS_SIGNATURE) then |
||
1738 | exit; |
||
1739 | Inc(p, PImageDosHeader(p)._lfanew); |
||
1740 | if (PCardinal(p)^ <> IMAGE_PE_SIGNATURE) then |
||
1741 | exit; |
||
1742 | Inc(p, sizeof(cardinal)); |
||
1743 | NumSections := PImageFileHeader(p).NumberOfSections; |
||
1744 | Inc(p, sizeof(TImageFileHeader) + sizeof(TImageOptionalHeader)); |
||
1745 | for i := 1 to NumSections do |
||
1746 | begin |
||
1747 | with PImageSectionHeader(p)^ do |
||
1748 | if PointerToRawData + SizeOfRawData > Result then |
||
1749 | Result := PointerToRawData + SizeOfRawData; |
||
1750 | Inc(p, sizeof(TImageSectionHeader)); |
||
1751 | end; |
||
1752 | end; |
||
1753 | {$endif} |
||
1754 | (*--------------------------------------------------------------------------*) |
||
1755 | |||
1756 | const |
||
1757 | MAX_IDX = ($80000000 div sizeof(TZ64CentralEntry)) - 1; // 2G storage limit |
||
1758 | // storage for records in list view |
||
1759 | type |
||
1760 | PCentralRecords = ^TCentralRecords; |
||
1761 | TCentralRecords = packed array[0..MAX_IDX] of TZ64CentralEntry; |
||
1762 | |||
1763 | var |
||
1764 | p_Items: PCentralRecords = nil; |
||
1765 | cb_Items: cardinal = 0; |
||
1766 | |||
1767 | function AddToItemData(const rec: TZ64CentralEntry): cardinal; |
||
1768 | begin |
||
1769 | if (cb_Items and 63) = 0 then |
||
1770 | ReAllocMem(p_Items, sizeof(TZ64CentralEntry) * (cb_Items + 64)); |
||
1771 | |||
1772 | Inc(cb_Items); |
||
1773 | p_Items^[cb_Items - 1] := rec; |
||
1774 | Result := cb_Items - 1; |
||
1775 | end; |
||
1776 | |||
1777 | // add an entry to the list view |
||
1778 | procedure AddFileToList(const wndOwner: HWND; const sName: string; |
||
1779 | const Rec: TZ64CentralEntry; const IsDir: boolean); |
||
1780 | var |
||
1781 | recItem: TLVItem; |
||
1782 | wndLV: HWND; |
||
1783 | iiItem: integer; |
||
1784 | sfi: TSHFileInfo; |
||
1785 | s: string; |
||
1786 | begin |
||
1787 | wndLV := GetDlgItem(wndOwner, ID_LV_FILES); |
||
1788 | if not IsDir then |
||
1789 | SHGetFileInfo(PChar(ExtractFileName(sName)), FILE_ATTRIBUTE_NORMAL, sfi, |
||
1790 | sizeof(sfi), SHGFI_USEFILEATTRIBUTES or SHGFI_SMALLICON or SHGFI_SYSICONINDEX) |
||
1791 | else |
||
1792 | SHGetFileInfo(PChar(ExtractFileName(RemoveDirSeparator(sName))), |
||
1793 | FILE_ATTRIBUTE_DIRECTORY, sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES or |
||
1794 | SHGFI_SMALLICON or SHGFI_SYSICONINDEX); |
||
1795 | |||
1796 | with recItem do |
||
1797 | begin |
||
1798 | mask := LVIF_TEXT or LVIF_PARAM or LVIF_STATE or LVIF_IMAGE; |
||
1799 | iItem := MaxInt; |
||
1800 | iSubItem := 0; |
||
1801 | // select only if no file selection is allowed (just for visual feedback) |
||
1802 | if (so_AskFiles and VRec_SFXHeader.Options) = 0 then |
||
1803 | state := 0 |
||
1804 | else |
||
1805 | state := LVIS_SELECTED; |
||
1806 | stateMask := LVIS_SELECTED; |
||
1807 | pszText := PChar(sName); |
||
1808 | cchTextMax := Length(sName); |
||
1809 | iImage := sfi.iIcon; |
||
1810 | lParam := AddToItemData(Rec); |
||
1811 | end; |
||
1812 | iiItem := SendMessage(wndLV, LVM_INSERTITEM, 0, integer(@recItem)); |
||
1813 | |||
1814 | with recItem do |
||
1815 | begin |
||
1816 | mask := LVIF_TEXT;// or LVIF_PARAM; |
||
1817 | iItem := iiItem; |
||
1818 | iSubItem := 1; |
||
1819 | s := Int2Str(Rec.UnComprSize, 0); |
||
1820 | pszText := PChar(s); |
||
1821 | cchTextMax := Length(s); |
||
1822 | end; |
||
1823 | SendMessage(wndLV, LVM_SETITEM, 0, integer(@recItem)); |
||
1824 | end; |
||
1825 | |||
1826 | (*--------------------------------------------------------------------------*) |
||
1827 | |||
1828 | // retrieve an item from the list |
||
1829 | function GetFileFromList(const wndOwner: HWND; const iiItem: integer; |
||
1830 | var Rec: TZ64CentralEntry): string; |
||
1831 | var |
||
1832 | Item: TLVItem; |
||
1833 | wndLV: HWND; |
||
1834 | szBuf: array[0..MAX_PATH * 2] of char; |
||
1835 | begin |
||
1836 | wndLV := GetDlgItem(wndOwner, ID_LV_FILES); |
||
1837 | |||
1838 | // get lparam stored in routine above |
||
1839 | with Item do |
||
1840 | begin |
||
1841 | iItem := iiItem; |
||
1842 | iSubItem := 0; |
||
1843 | mask := LVIF_PARAM; |
||
1844 | end; |
||
1845 | SendMessage(wndLV, LVM_GETITEM, 0, integer(@Item)); |
||
1846 | Rec := p_Items^[Item.lParam]; |
||
1847 | |||
1848 | // path+file |
||
1849 | with Item do |
||
1850 | begin |
||
1851 | iItem := iiItem; |
||
1852 | iSubItem := 0; |
||
1853 | mask := LVIF_TEXT; |
||
1854 | pszText := @szBuf; |
||
1855 | cchTextMax := sizeof(szBuf); |
||
1856 | end; |
||
1857 | SetString(Result, Item.pszText, SendMessage(wndLV, LVM_GETITEMTEXT, |
||
1858 | iiItem, integer(@Item))); |
||
1859 | end; |
||
1860 | |||
1861 | (*--------------------------------------------------------------------------*) |
||
1862 | |||
1863 | procedure DeSelectInFilesListView(const wndDlg: HWND; const iItem: integer); |
||
1864 | var |
||
1865 | Item: TLVItem; |
||
1866 | begin |
||
1867 | with Item do |
||
1868 | begin |
||
1869 | stateMask := LVIS_SELECTED; |
||
1870 | state := 0; |
||
1871 | end; |
||
1872 | SendDlgItemMessage(wndDlg, ID_LV_FILES, LVM_SETITEMSTATE, iItem, longint(@Item)); |
||
1873 | end; |
||
1874 | |||
1875 | (*--------------------------------------------------------------------------*) |
||
1876 | |||
1877 | // may 11, 2002: show first selected item on extraction failure |
||
1878 | procedure ShowFirstSelected(const wndList: HWND); |
||
1879 | var |
||
1880 | i: integer; |
||
1881 | begin |
||
1882 | for i := 0 to Pred(SendMessage(wndList, LVM_GETITEMCOUNT, 0, 0)) do |
||
1883 | if SendMessage(wndList, LVM_GETITEMSTATE, i, LVIS_SELECTED) = LVIS_SELECTED then |
||
1884 | begin |
||
1885 | SendMessage(wndList, LVM_ENSUREVISIBLE, i, integer(False)); |
||
1886 | Break; |
||
1887 | end; |
||
1888 | end; |
||
1889 | |||
1890 | // check whether spanned or multivol archive |
||
1891 | procedure CheckSpan; |
||
1892 | var |
||
1893 | len: integer; |
||
1894 | sName: string; |
||
1895 | begin |
||
1896 | // prepare name using defaults unless supplied |
||
1897 | if VStr_DetachName = '' then |
||
1898 | VStr_DetachName := ExtractFileName(VStr_ExeName); |
||
1899 | len := Length(VStr_DetachName); |
||
1900 | while (len > 0) and (VStr_DetachName[len] <> '.') do |
||
1901 | dec(len); |
||
1902 | if (len > 0) then |
||
1903 | begin |
||
1904 | if VInt_SpanType = SFXSpanTypeUnknown then |
||
1905 | VStr_DetachExt := Copy(VStr_DetachName, len, 255) |
||
1906 | else |
||
1907 | VStr_DetachExt := '.zip'; |
||
1908 | VStr_DetachName := Copy(VStr_DetachName, 1, len -1); |
||
1909 | end |
||
1910 | else |
||
1911 | VStr_DetachExt := '.zip'; |
||
1912 | VStr_DetachName := AppendDirSeparator(ExtractFilePath(VStr_ExeName)) + |
||
1913 | VStr_DetachName; |
||
1914 | VInt_SpanType := SFXSpanTypeMultiVol; |
||
1915 | VStr_SourceDir := AppendDirSeparator(ExtractFilePath(VStr_ExeName)); |
||
1916 | if VStr_SourceDir = '' then |
||
1917 | begin |
||
1918 | len := GetCurrentDirectory(0, nil); |
||
1919 | if len > 0 then |
||
1920 | begin |
||
1921 | SetLength(sName, len + 5); |
||
1922 | GetCurrentDirectory(len + 2, pChar(sName)); |
||
1923 | VStr_SourceDir := AppendDirSeparator(pChar(sName)); |
||
1924 | end; |
||
1925 | end; |
||
1926 | VBool_FixedDrive := GetDriveType(PChar(VStr_SourceDir)) in |
||
1927 | [DRIVE_FIXED, DRIVE_REMOTE, DRIVE_RAMDISK]; |
||
1928 | if not VBool_FixedDrive then |
||
1929 | begin |
||
1930 | sName := DetachedName('001'); |
||
1931 | if not FileExists(sName) then |
||
1932 | VInt_SpanType := SFXSpanTypeSpanned; |
||
1933 | end; |
||
1934 | end; |
||
1935 | |||
1936 | (*---------------------------------------------------------------------------- |
||
1937 | 3.3.1.0 11 Aug 2007 RA difference for dir and nondir in AddFileTo List addded |
||
1938 | 3.3.0.0 24 Jan 2006 RA soCreateEmptyDirs added |
||
1939 | fill the list view |
||
1940 | *) |
||
1941 | procedure FillListView(wndOwner: hWnd); |
||
1942 | type |
||
1943 | PUString_Data = ^UString_Data; |
||
1944 | UString_Data = packed record |
||
1945 | // tag: word; |
||
1946 | // totsiz: word; |
||
1947 | version: byte; |
||
1948 | origcrc: DWORD; |
||
1949 | end; |
||
1950 | const |
||
1951 | PKZIPW25: Integer = 25;//(FS_FAT * 256) + 25; |
||
1952 | PKZIPW26 = 26;//(FS_FAT * 256) + 26; |
||
1953 | PKZIPW40 = 40;//(FS_FAT * 256) + 40; |
||
1954 | UNIXATTRS = $FFFF0000; |
||
1955 | WZIP = $0B32;//(FS_NTFS * 256) + 50; |
||
1956 | // FS_FAT: Integer = 0; |
||
1957 | // FS_HPFS: Integer = 6; |
||
1958 | // FS_NTFS: Integer = 11; |
||
1959 | // FLAG_UTF8_BIT = $1000; |
||
1960 | var |
||
1961 | eoc: TZipEndOfCentral; |
||
1962 | i, j: cardinal; |
||
1963 | cfh: TZipCentralHeader; |
||
1964 | buffer: array [0..MAX_PATH + 2] of AnsiChar; |
||
1965 | fn: string; |
||
1966 | p: PByte; |
||
1967 | x: integer; |
||
1968 | fnp: PAnsiChar; // source filename pointer; |
||
1969 | fnsz: integer; // source filename size |
||
1970 | fncp: integer; // source filename codepage |
||
1971 | |||
1972 | EOC64: TZipEOC64; |
||
1973 | Z64CFH: TZ64CentralEntry; |
||
1974 | EocPos, CenSize, TotalEntries: int64; |
||
1975 | HasEoc64: boolean; |
||
1976 | over, sz: integer; |
||
1977 | crc: cardinal; |
||
1978 | pp: PUString_Data; |
||
1979 | BadName: boolean; |
||
1980 | hasUPath: Boolean; |
||
1981 | begin |
||
1982 | EocPos := FSeek(FindEOCRecord, FILE_BEGIN); |
||
1983 | |||
1984 | CheckFRead(eoc, sizeof(eoc)); |
||
1985 | HasEoc64 := NeedEOC64(EOC); |
||
1986 | if (HasEoc64) then |
||
1987 | GetEOC64(EocPos, EOC64); |
||
1988 | //how far out the header offsets are from reality (due to sfx stub) |
||
1989 | if HasEoc64 and (EOC.CentralSize = MAX_UNSIGNED) then |
||
1990 | censize := EOC64.CentralSize |
||
1991 | else |
||
1992 | censize := EOC.CentralSize;// EOC64.CentralSize : EOC.CentralSize; |
||
1993 | VDW_OffsetDelta := EocPos - censize; |
||
1994 | if HasEoc64 and (EOC.CentralOffSet = MAX_UNSIGNED) then |
||
1995 | VDW_OffsetDelta := VDW_OffsetDelta - EOC64.CentralOffSet |
||
1996 | else |
||
1997 | VDW_OffsetDelta := VDW_OffsetDelta - EOC.CentralOffSet; |
||
1998 | if (HasEoc64) then |
||
1999 | VDW_OffsetDelta := VDW_OffsetDelta - EOC64.vsize + 12 + SizeOf(TZip64EOCLocator); |
||
2000 | if HasEOC64 then |
||
2001 | censize := censize + EOC64.vsize + 12 |
||
2002 | else |
||
2003 | censize := censize + SizeOf(EOC); |
||
2004 | FSeek(-censize, FILE_CURRENT); |
||
2005 | TotalEntries := EOC.TotalEntries; |
||
2006 | if (HasEoc64 and (TotalEntries = MAX_WORD)) then |
||
2007 | TotalEntries := EOC64.TotalEntries; |
||
2008 | |||
2009 | // is it multi-disk |
||
2010 | if EOC.ThisDiskNo <> 0 then |
||
2011 | CheckSpan; |
||
2012 | |||
2013 | //how far out the header offsets are from reality (due to sfx stub) |
||
2014 | for i := 0 to TotalEntries - 1 do |
||
2015 | begin |
||
2016 | CheckFRead(cfh, sizeof(cfh)); |
||
2017 | if (cfh.HeaderSig <> ZipCentralHeaderSig) or (cfh.FileNameLen = 0) or |
||
2018 | (cfh.FileNameLen > 500) then |
||
2019 | ErrorHaltID(SFX_Err_ArchiveCorrupted); |
||
2020 | |||
2021 | CheckFRead(buffer[0], cfh.FileNameLen); |
||
2022 | buffer[cfh.FileNameLen] := #0; |
||
2023 | // read extra data |
||
2024 | p := nil; |
||
2025 | over := 0; |
||
2026 | x := cfh.ExtraLen; |
||
2027 | if x > 0 then |
||
2028 | begin |
||
2029 | if x > 2048 then |
||
2030 | begin |
||
2031 | over := 2048 - x; |
||
2032 | x := 2048; |
||
2033 | end; |
||
2034 | p := GetXBuf(x); |
||
2035 | if p <> nil then |
||
2036 | xbuf^ := 0; |
||
2037 | if x > 0 then |
||
2038 | CheckFRead(p^, x); |
||
2039 | end; |
||
2040 | GetZ64Entry(cfh, Z64cfh); |
||
2041 | BadName := false; |
||
2042 | fnp := PAnsiChar(@buffer[0]); // filename source |
||
2043 | fnsz := cfh.FileNameLen;//-1; // filename source length |
||
2044 | fncp := 0; |
||
2045 | hasUPath := False; |
||
2046 | |||
2047 | if (p <> nil) and (cfh.VersionMadeBy0 >= 20) then |
||
2048 | begin |
||
2049 | sz := cfh.ExtraLen; |
||
2050 | if ExtraData(p, sz, UPath_Data_Tag) and |
||
2051 | (sz > sizeof(UString_Data)) then |
||
2052 | begin |
||
2053 | pp := PUString_Data(p);; |
||
2054 | crc := $FFFFFFFF; |
||
2055 | Crc32_Buf(@buffer[0], cfh.FileNameLen, crc); |
||
2056 | crc := crc xor $FFFFFFFF; |
||
2057 | if (pp^.version = 1) and (crc = pp^.origcrc) then |
||
2058 | begin |
||
2059 | sz := sz - sizeof(UString_Data); |
||
2060 | inc(p, sizeof(UString_Data)); |
||
2061 | if sz > 0 then |
||
2062 | begin |
||
2063 | fnp := PAnsiChar(p); |
||
2064 | fnsz := sz; |
||
2065 | fncp := CP_UTF8; |
||
2066 | hasUPath := True; |
||
2067 | end; |
||
2068 | end; |
||
2069 | end; |
||
2070 | end; |
||
2071 | |||
2072 | if not hasUPath then |
||
2073 | begin |
||
2074 | fncp := CP_ACP; |
||
2075 | if (cfh.Flag and FLAG_UTF8_BIT) <> 0 then |
||
2076 | fncp := CP_UTF8 |
||
2077 | else |
||
2078 | begin |
||
2079 | if (cfh.VersionMadeBy1 = FS_FAT) or |
||
2080 | (cfh.VersionMadeBy1 = FS_HPFS) or |
||
2081 | ((cfh.VersionMadeBy1 = FS_NTFS) and (cfh.VersionMadeBy0 = 50)) then |
||
2082 | fncp := CP_OEMCP; |
||
2083 | end; |
||
2084 | end; |
||
2085 | |||
2086 | fn := To_Str(fncp, fnp, fnsz, true, BadName); |
||
2087 | //swap slashes and get last char ... |
||
2088 | for J := 1 to Length(fn) do |
||
2089 | begin |
||
2090 | if fn[j] = '/' then |
||
2091 | fn[j] := Chr_DirSep; |
||
2092 | if fn[j] = '?' then |
||
2093 | BadName := True; |
||
2094 | end; |
||
2095 | |||
2096 | if BadName then |
||
2097 | begin |
||
2098 | fn := SFXString(SFX_Err_InvalidFileName) + ' "' + fn + '"'; |
||
2099 | x := MessageBox(wndOwner, pChar(fn), PChar(SFXString(SFX_Cap_Err)), |
||
2100 | MB_OKCANCEL or MB_ICONSTOP or MB_TASKMODAL); |
||
2101 | if x = IDOK then |
||
2102 | continue; |
||
2103 | break; |
||
2104 | end; |
||
2105 | |||
2106 | // skip directory entries |
||
2107 | if fn[Length(fn)] <> Chr_DirSep then |
||
2108 | begin |
||
2109 | //store each filename and absolute file offset of cfh record ... |
||
2110 | AddFileToList(wndOwner, fn, Z64cfh, False); |
||
2111 | end |
||
2112 | else |
||
2113 | // new 09/19/2005, recreate empty directories |
||
2114 | if (so_CreateEmptyDirs and VRec_SFXHeader.Options) <> 0 then |
||
2115 | AddFileToList(wndOwner, fn, Z64cfh, True); |
||
2116 | |||
2117 | if (over + cfh.FileComLen) <> 0 then |
||
2118 | FSeek(over + cfh.FileComLen, FILE_CURRENT); |
||
2119 | end; |
||
2120 | |||
2121 | end; |
||
2122 | |||
2123 | (*--------------------------------------------------------------------------*) |
||
2124 | |||
2125 | // close a handle, if not already closed |
||
2126 | function CheckCloseHandle(var H: THandle): boolean; |
||
2127 | begin |
||
2128 | if (H <> 0) and (H <> INVALID_HANDLE_VALUE) then |
||
2129 | Result := CloseHandle(H) |
||
2130 | else |
||
2131 | Result := True; |
||
2132 | H := INVALID_HANDLE_VALUE; |
||
2133 | end; |
||
2134 | |||
2135 | // create a 00x number string |
||
2136 | procedure Str_3(const i: integer; var S: string); |
||
2137 | begin |
||
2138 | S := Int2Str(i, 3); |
||
2139 | // Str(i, S); |
||
2140 | // while Length(s) < 3 do |
||
2141 | // s := '0' + s; |
||
2142 | end; |
||
2143 | |||
2144 | function IsRightDisk(DiskSeq: integer): boolean; |
||
2145 | var |
||
2146 | SSeq: string; |
||
2147 | Dummy1, Dummy2, DiskSerial: cardinal; |
||
2148 | VolName: array[0..MAX_PATH] of char; |
||
2149 | sTemp: string; |
||
2150 | begin |
||
2151 | Result := DiskSeq = VInt_LastSeq; |
||
2152 | if Result then |
||
2153 | exit; |
||
2154 | Str_3(DiskSeq + 1, SSeq); |
||
2155 | if VInt_SpanType = SFXSpanTypeSpanned then |
||
2156 | begin |
||
2157 | // get volume info |
||
2158 | GetVolumeInformation(PChar(VStr_SourceDir), VolName, MAX_PATH, @DiskSerial, Dummy1, |
||
2159 | Dummy2, nil, 0); |
||
2160 | STemp := VolName; |
||
2161 | // must be pkback# 00x |
||
2162 | Result := CompareText(STemp, 'PKBACK# ' + SSeq); |
||
2163 | if Result and (not CompareText(VStr_ExeName, DetachedName(''))) then |
||
2164 | begin |
||
2165 | if not CheckCloseHandle(VH_InFile) then |
||
2166 | ErrorHaltFmt(SFX_Err_CannotCloseFile, VStr_ExeName); |
||
2167 | VStr_ExeName := DetachedName(''); // use detached name |
||
2168 | // Open the input archive on this disk. |
||
2169 | VH_Infile := CreateFile(PChar(VStr_ExeName), GENERIC_READ, |
||
2170 | FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
||
2171 | if VH_Infile = INVALID_HANDLE_VALUE then |
||
2172 | ErrorHaltFmt(SFX_Err_CannotOpenFile, VStr_ExeName); |
||
2173 | // assume no shifted offset on detached archives |
||
2174 | VDW_OffsetDelta := 0; |
||
2175 | end; |
||
2176 | end |
||
2177 | else |
||
2178 | begin |
||
2179 | // multi volume, filename = xyz00x.(xyz) and Actual File |
||
2180 | Result := CompareText(VStr_ExeName, DetachedName(SSeq)); |
||
2181 | end; |
||
2182 | end; |
||
2183 | |||
2184 | procedure GetNewDisk(wndOwner: HWND; DiskSeq: integer); |
||
2185 | var |
||
2186 | SSeq: string; |
||
2187 | begin |
||
2188 | if not CheckCloseHandle(VH_InFile) then |
||
2189 | ErrorHaltFmt(SFX_Err_CannotCloseFile, VStr_ExeName); |
||
2190 | |||
2191 | Str_3(DiskSeq + 1, SSeq); |
||
2192 | repeat |
||
2193 | if not VBool_FixedDrive then |
||
2194 | begin |
||
2195 | if MsgBox(wndOwner, FmtStr2(SFXString(SFX_Msg_InsertDiskVolume), |
||
2196 | SSeq, VStr_SourceDir), VStr_SFX_Caption, MB_OKCANCEL) = idCancel then |
||
2197 | ErrorHalt(''); |
||
2198 | end; |
||
2199 | |||
2200 | if VInt_SpanType = SFXSpanTypeMultiVol then |
||
2201 | VStr_ExeName := DetachedName(SSeq) |
||
2202 | else |
||
2203 | VStr_ExeName := DetachedName(''); |
||
2204 | until IsRightDisk(DiskSeq); |
||
2205 | |||
2206 | // Open the input archive on this disk. |
||
2207 | VH_Infile := CreateFile(PChar(VStr_ExeName), GENERIC_READ, FILE_SHARE_READ, |
||
2208 | nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
||
2209 | if VH_Infile = INVALID_HANDLE_VALUE then |
||
2210 | ErrorHaltFmt(SFX_Err_CannotOpenFile, VStr_ExeName); |
||
2211 | // assume no shifted offset on detached archives |
||
2212 | VDW_OffsetDelta := 0; |
||
2213 | VInt_LastSeq := DiskSeq; |
||
2214 | end; |
||
2215 | |||
2216 | |||
2217 | (*---------------------------------------------------------------------------- |
||
2218 | added version 3.0 May 1, 2003 |
||
2219 | read data and copy in temp file if needed or skip to next local header *) |
||
2220 | procedure RWJoinData(wndOwner: HWND; var Buffer; ReadLen: integer; |
||
2221 | var DiskNbr: word; Copy: boolean); |
||
2222 | var |
||
2223 | SizeR, ToRead: integer; |
||
2224 | begin |
||
2225 | while ReadLen > 0 do |
||
2226 | begin |
||
2227 | ToRead := min(ReadLen, SFXBufSize); |
||
2228 | SizeR := FRead(Buffer, ToRead); |
||
2229 | if SizeR <> ToRead then |
||
2230 | begin |
||
2231 | // Check if we are at the end of a input disk. |
||
2232 | if (VInt_SpanType = SFXSpanTypeNone) or |
||
2233 | (FSeek(0, FILE_CURRENT) <> FSeek(0, FILE_END)) then |
||
2234 | ErrorHaltID(SFX_Err_ArchiveCorrupted); |
||
2235 | |||
2236 | // It seems we are at the end, so get a next disk. |
||
2237 | Inc(DiskNbr); |
||
2238 | GetNewDisk(wndOwner, DiskNbr); |
||
2239 | end; |
||
2240 | |||
2241 | if SizeR > 0 then |
||
2242 | begin |
||
2243 | if Copy then |
||
2244 | CheckFWrite(VH_TempFile, Buffer, SizeR, VStr_TempFile); |
||
2245 | ReadLen := ReadLen - SizeR; |
||
2246 | end; |
||
2247 | end; |
||
2248 | end; |
||
2249 | |||
2250 | // open the correct archive in spanned, multivolue or detached sfx's |
||
2251 | procedure OpenRightArchive(wndOwner: HWND; const DiskNumber: integer); |
||
2252 | begin |
||
2253 | if not IsRightDisk(DiskNumber) then |
||
2254 | GetNewDisk(wndOwner, DiskNumber); // we need another disk |
||
2255 | end; |
||
2256 | |||
2257 | |||
2258 | |||
2259 | // spanned archive, extract local header and file data to a temporary file |
||
2260 | procedure ExtractToTempFile(const wndOwner: HWND; var LocalOffset: cardinal; |
||
2261 | var OldHandle: THandle); |
||
2262 | var |
||
2263 | Buf: array[0..SFXBufSize] of Char; |
||
2264 | DataToCopy: cardinal; |
||
2265 | begin |
||
2266 | if VStr_TempFile = '' then |
||
2267 | begin |
||
2268 | ZeroMemory(@buf, sizeof(buf)); |
||
2269 | // create a temporaray filename |
||
2270 | SetLength(VStr_TempFile, MAX_PATH * 2); |
||
2271 | if GetTempFileName(PChar(AppendDirSeparator(ExpandEnv('%temp%'))), |
||
2272 | 'SFX', 0, Buf) <> 0 then |
||
2273 | begin |
||
2274 | VStr_TempFile := buf; |
||
2275 | DeleteFile(buf); // because created by GetTempFileName |
||
2276 | end |
||
2277 | else |
||
2278 | ErrorHaltFmt(SFX_Err_CannotOpenFile, VStr_TempFile); |
||
2279 | end; |
||
2280 | |||
2281 | // create temp file to copy the deflated file from the archive and prepare it for inflate |
||
2282 | VH_TempFile := CreateFile(PChar(VStr_TempFile), GENERIC_READ or |
||
2283 | GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0); |
||
2284 | |||
2285 | if VH_TEMPFILE = INVALID_HANDLE_VALUE then |
||
2286 | ErrorHaltFmt(SFX_Err_CannotWriteFile, VStr_TempFile); |
||
2287 | |||
2288 | FSeek(LocalOffset, FILE_BEGIN); |
||
2289 | // read the local header |
||
2290 | VInt_MaxWrite := sizeof(buf); // do not allow overlength |
||
2291 | RWJoinData(wndOwner, Buf, sizeof(TZipLocalHeader), VRec_ZipHeader.DiskStart, |
||
2292 | True); |
||
2293 | with PZipLocalHeader(@Buf)^ do |
||
2294 | begin |
||
2295 | if HeaderSig <> ZipLocalHeaderSig then |
||
2296 | BadArchive; |
||
2297 | DataToCopy := VRec_ZipHeader.ComprSize + FileNameLen + ExtraLen; |
||
2298 | // ext local header? |
||
2299 | if (Flag and 8) = 8 then |
||
2300 | DataToCopy := DataToCopy + sizeof(TZipExtLocalHeader); |
||
2301 | end; |
||
2302 | VInt_MaxWrite := DataToCopy; // do not allow overlength |
||
2303 | RWJoinData(wndOwner, Buf, DataToCopy, VRec_ZipHeader.DiskStart, True); |
||
2304 | OldHandle := VH_InFile; |
||
2305 | VH_InFile := VH_TempFile; |
||
2306 | LocalOffset := 0; |
||
2307 | end; |
||
2308 | |||
2309 | // reattach current archive and close tempfile |
||
2310 | procedure RollBackTempFile(const wndOwner: HWND; const OldHandle: THandle); |
||
2311 | begin |
||
2312 | VH_InFile := OldHandle; |
||
2313 | if not CheckCloseHandle(VH_TempFile) then |
||
2314 | ErrorMsgBoxFmt1(wndOwner, SFX_Err_CannotCloseFile, VStr_TempFile); |
||
2315 | DeleteFile(PChar(VStr_TempFile)); |
||
2316 | end; |
||
2317 | |||
2318 | function ExtractFile(wndOwner: hWnd; const Filename: string; |
||
2319 | const rec: TZ64CentralEntry; var bPasswordFailed: boolean): boolean; |
||
2320 | var |
||
2321 | EncryptHDR: PAnsiChar; |
||
2322 | i: integer; |
||
2323 | rLocal: TZipLocalHeader; |
||
2324 | bIsTempFile: boolean; |
||
2325 | clOffset: cardinal; |
||
2326 | oldH: THandle; |
||
2327 | begin |
||
2328 | bPasswordFailed := False; |
||
2329 | bIsTempFile := False; |
||
2330 | Result := False; |
||
2331 | // mst may 07, 2002: removed a sleep(100) where did this come from? |
||
2332 | VRec_ZipHeader := rec; |
||
2333 | with VRec_ZipHeader do |
||
2334 | begin |
||
2335 | if HeaderSig <> ZipCentralHeaderSig then |
||
2336 | BadArchive; |
||
2337 | if not (ComprMethod in [0, 8]) then |
||
2338 | ErrorMsgBoxFmt1(wndOwner, SFX_Err_ZipUnknownComp, '') |
||
2339 | else |
||
2340 | begin |
||
2341 | clOffset := RelOffLocal + VDW_OffsetDelta; |
||
2342 | if (VInt_SpanType <> SFXSpanTypeNone{0}) then |
||
2343 | begin |
||
2344 | // assure the right disk is opened |
||
2345 | OpenRightArchive(wndOwner, DiskStart); |
||
2346 | |||
2347 | // join the possibly split data in a temporary file |
||
2348 | ExtractToTempFile(wndOwner, clOffset, oldH); |
||
2349 | bIsTempFile := True; |
||
2350 | end; |
||
2351 | |||
2352 | try |
||
2353 | // goto beginning of local header... |
||
2354 | FSeek(clOffset, FILE_BEGIN); |
||
2355 | CheckFRead(rLocal, sizeof(rLocal)); |
||
2356 | if rLocal.HeaderSig <> ZipLocalHeaderSig then |
||
2357 | BadArchive; |
||
2358 | |||
2359 | // mst may 07, 2002: added extrafieldlen to go to correct position |
||
2360 | // e.g. for zipfiles created with infozip's zip.exe |
||
2361 | FSeek(rLocal.FileNameLen + rLocal.ExtraLen, FILE_CURRENT); |
||
2362 | VInt_BytesToGo := ComprSize; |
||
2363 | VInt_MaxWrite := UnComprSize; // do not allow overlength |
||
2364 | |||
2365 | //password stuff... |
||
2366 | if (Flag and 1) = 1 then //if a password used... |
||
2367 | begin |
||
2368 | Dec(VInt_BytesToGo, RAND_HEAD_LEN); |
||
2369 | GetMem(EncryptHDR, RAND_HEAD_LEN * 2); |
||
2370 | try |
||
2371 | CheckFRead(EncryptHDR[0], RAND_HEAD_LEN); |
||
2372 | //make a copy of encrypted header in upper half of buffer... |
||
2373 | Move(EncryptHDR[0], EncryptHDR[RAND_HEAD_LEN], RAND_HEAD_LEN); |
||
2374 | if VStr_Password = '' then |
||
2375 | bPasswordFailed := True |
||
2376 | else |
||
2377 | bPasswordFailed := |
||
2378 | not decrypt_pw(EncryptHDR, RAND_HEAD_LEN, Flag, |
||
2379 | CRC32, ModifTime, VStr_Password); |
||
2380 | if bPasswordFailed then |
||
2381 | for i := 0 to 2 do |
||
2382 | begin |
||
2383 | if DialogBox(hInstance, Str_Dlg_Password, wndOwner, |
||
2384 | @PasswordQueryDialogProc) <> idOk then |
||
2385 | Break; |
||
2386 | bPasswordFailed := |
||
2387 | not decrypt_pw(EncryptHDR, RAND_HEAD_LEN, Flag, |
||
2388 | CRC32, ModifTime, VStr_Password); |
||
2389 | if not bPasswordFailed then |
||
2390 | Break; |
||
2391 | Windows.Beep(0, 0); //it's a dud, ? try again... |
||
2392 | end; |
||
2393 | finally |
||
2394 | FreeMem(EncryptHDR); |
||
2395 | end; |
||
2396 | end; |
||
2397 | |||
2398 | if bPasswordFailed then |
||
2399 | Exit; |
||
2400 | |||
2401 | VDW_CRC32Val := CRC_MASK; |
||
2402 | ProcessMessages; |
||
2403 | if VBool_Cancelled then |
||
2404 | Exit; |
||
2405 | |||
2406 | VStr_OutFile := FileName; |
||
2407 | VH_OutFile := CreateFile(PChar(Filename), GENERIC_WRITE, |
||
2408 | FILE_SHARE_WRITE, nil, CREATE_ALWAYS, ExtFileAtt and $7F, 0); |
||
2409 | |||
2410 | if VH_OutFile = INVALID_HANDLE_VALUE then |
||
2411 | begin |
||
2412 | ErrorMsgBoxFmt1(wndOwner, SFX_Err_CannotWriteFile, VStr_OutFile); |
||
2413 | Exit; |
||
2414 | end; |
||
2415 | |||
2416 | try |
||
2417 | case ComprMethod of |
||
2418 | 0: Unstore; |
||
2419 | 8: Inflate(nil, 0); |
||
2420 | end; |
||
2421 | // set file time |
||
2422 | if CTime = 0 then |
||
2423 | FileSetDate(VH_OutFile, ModifTime + 65536 * ModifDate) |
||
2424 | else |
||
2425 | begin |
||
2426 | SetFileTime(VH_OutFile, @CTime, @ATime, @MTime); |
||
2427 | end; |
||
2428 | |||
2429 | // 01/13/04: do crc32 checking, bail a warning message |
||
2430 | // but do not stop if checksums do not match |
||
2431 | if rec.CRC32 <> (VDW_CRC32Val xor $FFFFFFFF) then |
||
2432 | begin |
||
2433 | ErrorMsgBoxFmt1(wndOwner, SFX_Err_CRC32, VStr_OutFile); |
||
2434 | Result := False; |
||
2435 | end |
||
2436 | else |
||
2437 | Result := True; |
||
2438 | |||
2439 | finally |
||
2440 | if not CheckCloseHandle(VH_OutFile) then |
||
2441 | begin |
||
2442 | ErrorMsgBoxFmt1(wndOwner, SFX_Err_CannotCloseFile, VStr_OutFile); |
||
2443 | Result := False; |
||
2444 | end; |
||
2445 | end; |
||
2446 | finally |
||
2447 | if bIsTempFile then |
||
2448 | RollBackTempFile(wndOwner, oldH); |
||
2449 | end; |
||
2450 | end; |
||
2451 | end; |
||
2452 | end; |
||
2453 | |||
2454 | (*--------------------------------------------------------------------------*) |
||
2455 | |||
2456 | function Extract(wndOwner: hWnd): boolean; |
||
2457 | var |
||
2458 | i, FileCount: longint; |
||
2459 | wndList: HWND; |
||
2460 | wndProgressBar: HWND; |
||
2461 | bExtracted, bPWFailed: boolean; |
||
2462 | recCentral: TZ64CentralEntry; |
||
2463 | begin |
||
2464 | wndList := GetDlgItem(wndOwner, ID_LV_FILES); |
||
2465 | wndProgressBar := GetDlgItem(wndOwner, ID_PRG_EXTRACT); |
||
2466 | FileCount := SendMessage(wndList, LVM_GETITEMCOUNT, 0, 0); |
||
2467 | SendMessage(wndProgressBar, PBM_SETRANGE, 0, FileCount shl 16); |
||
2468 | SendMessage(wndProgressBar, PBM_SETPOS, 0, 0); |
||
2469 | |||
2470 | VInt_LastSeq := -1; |
||
2471 | bPWFailed := False; |
||
2472 | bExtracted := False; |
||
2473 | for i := 0 to FileCount - 1 do |
||
2474 | begin |
||
2475 | ProcessMessages; |
||
2476 | if VBool_Cancelled then |
||
2477 | Break; |
||
2478 | |||
2479 | // update progres bar |
||
2480 | SendMessage(wndProgressBar, PBM_SETPOS, i + 1, 0); |
||
2481 | |||
2482 | if SendMessage(wndList, LVM_GETITEMSTATE, i, LVIS_SELECTED) = LVIS_SELECTED then |
||
2483 | //if selected then... |
||
2484 | begin |
||
2485 | //get the target filename... |
||
2486 | VStr_CurrentFile := AppendDirSeparator(VStr_ExtractPath) + |
||
2487 | GetFileFromList(wndOwner, i, recCentral); |
||
2488 | |||
2489 | if (VStr_CurrentFile <> '') and |
||
2490 | (VStr_CurrentFile[Length(VStr_CurrentFile)] = Chr_DirSep) then |
||
2491 | begin |
||
2492 | if (so_CreateEmptyDirs and VRec_SFXHeader.Options) <> 0 then |
||
2493 | begin |
||
2494 | if not ForceDirectories(RemoveDirSeparator(VStr_CurrentFile)) then |
||
2495 | begin |
||
2496 | ErrorMsgBoxFmt1(wndOwner, SFX_Err_Directory, |
||
2497 | RemoveDirSeparator(VStr_CurrentFile)); |
||
2498 | bExtracted := False; |
||
2499 | end |
||
2500 | else |
||
2501 | bExtracted := True; |
||
2502 | end |
||
2503 | else |
||
2504 | bExtracted := False; |
||
2505 | end |
||
2506 | else |
||
2507 | begin |
||
2508 | if not ForceDirectories(ExtractFilePath(VStr_CurrentFile)) then |
||
2509 | begin |
||
2510 | ErrorMsgBoxFmt1(wndOwner, SFX_Err_Directory, |
||
2511 | RemoveDirSeparator(VStr_CurrentFile)); |
||
2512 | Break; |
||
2513 | end; |
||
2514 | |||
2515 | if (Integer(VRec_SFXHeader.DefOVW) <> som_Overwrite) and |
||
2516 | FileExists(PChar(VStr_CurrentFile)) then |
||
2517 | begin |
||
2518 | if Integer(VRec_SFXHeader.DefOVW) = som_Skip then |
||
2519 | continue; |
||
2520 | case DialogBox(hInstance, Str_Dlg_FileExists, wndOwner, |
||
2521 | @FileExistsDialogProc) of |
||
2522 | ID_BTN_YES: ; |
||
2523 | ID_BTN_NO: continue; |
||
2524 | end; |
||
2525 | end; |
||
2526 | |||
2527 | // make sure the correct zip archive is open |
||
2528 | if (VInt_SpanType <> SFXSpanTypeNone{0}) then |
||
2529 | OpenRightArchive(wndOwner, recCentral.DiskStart); |
||
2530 | |||
2531 | bExtracted := ExtractFile(wndOwner, VStr_CurrentFile, recCentral, |
||
2532 | bPWFailed); |
||
2533 | end; |
||
2534 | |||
2535 | if bPWFailed then |
||
2536 | break //stop further processing!!! |
||
2537 | else |
||
2538 | if bExtracted then |
||
2539 | //unselect the file if successfully extracted with no errors... |
||
2540 | DeSelectInFilesListView(wndOwner, i); |
||
2541 | end; |
||
2542 | end; |
||
2543 | Result := SendMessage(wndList, LVM_GETSELECTEDCOUNT, 0, 0) = 0; |
||
2544 | if not Result then |
||
2545 | ShowFirstSelected(wndList); //may 11, 2002 : better visual feedback |
||
2546 | end; |
||
2547 | |||
2548 | (*--------------------------------------------------------------------------*) |
||
2549 | |||
2550 | procedure ErrorHaltFmt(id: integer; const arg1: string); |
||
2551 | begin |
||
2552 | ErrorHalt(FmtStrID1(id, arg1)); |
||
2553 | end; |
||
2554 | |||
2555 | procedure ErrorHaltID(id: integer); |
||
2556 | begin |
||
2557 | ErrorHalt(SFXString(id)); |
||
2558 | end; |
||
2559 | |||
2560 | // fatal error, exit |
||
2561 | procedure ErrorHalt(const sMsg: string); |
||
2562 | {$ifdef DEBUG_SFX} |
||
2563 | var err: DWORD; m: string; |
||
2564 | begin |
||
2565 | err := GetLastError; |
||
2566 | m := sMsg; |
||
2567 | if err <> 0 then |
||
2568 | m := m + ' ['+ IntToHex(err, 8) + ' '+ SysErrorMessage(err)+']'; |
||
2569 | if m <> '' then |
||
2570 | ErrorMsgBox(0, m{sMsg}); |
||
2571 | raise Exception.Create('Program halted'); |
||
2572 | // Halt(1); |
||
2573 | end; |
||
2574 | {$else} |
||
2575 | begin |
||
2576 | if sMsg <> '' then |
||
2577 | ErrorMsgBox(0, sMsg); |
||
2578 | Halt(1); |
||
2579 | end; |
||
2580 | {$endif} |
||
2581 | (*--------------------------------------------------------------------------*) |
||
2582 | |||
2583 | function StrGetEditText(wndPar: HWND): string; |
||
2584 | begin |
||
2585 | SetLength(Result, GetWindowTextLength(GetDlgItem(wndPar, ID_EDITBOX)) * 2); |
||
2586 | if Result <> '' then |
||
2587 | begin |
||
2588 | GetDlgItemText(wndPar, ID_EDITBOX, PChar(Result), Length(Result)); |
||
2589 | Result := PChar(Result); // match length |
||
2590 | end; |
||
2591 | end; |
||
2592 | |||
2593 | procedure AddFilesListViewCol(const wndDlg: HWND; const iIndex: integer; |
||
2594 | const szCaption: string; const iDirection, iWidth: integer); |
||
2595 | var |
||
2596 | wndLV: HWND; |
||
2597 | recCol: TLVColumn; |
||
2598 | begin |
||
2599 | wndLV := GetDlgItem(wndDlg, ID_LV_FILES); |
||
2600 | with recCol do |
||
2601 | begin |
||
2602 | mask := LVCF_FMT or LVCF_SUBITEM or LVCF_TEXT or LVCF_WIDTH; |
||
2603 | fmt := iDirection; |
||
2604 | cx := iWidth; |
||
2605 | pszText := PChar(szCaption); |
||
2606 | cchTextMax := Length(szCaption); |
||
2607 | iSubItem := iIndex; |
||
2608 | end; |
||
2609 | SendMessage(wndLV, LVM_INSERTCOLUMN, iIndex, integer(@recCol)); |
||
2610 | end; |
||
2611 | |||
2612 | procedure SelectAllInFilesListView(const wndDlg: HWND); |
||
2613 | var |
||
2614 | Item: TLVItem; |
||
2615 | begin |
||
2616 | with Item do |
||
2617 | begin |
||
2618 | stateMask := LVIS_SELECTED; |
||
2619 | state := LVIS_SELECTED; |
||
2620 | end; |
||
2621 | SendDlgItemMessage(wndDlg, ID_LV_FILES, LVM_SETITEMSTATE, -1, longint(@Item)); |
||
2622 | end; |
||
2623 | |||
2624 | // get current directory |
||
2625 | function GetCurDir: string; |
||
2626 | var |
||
2627 | szBuf: array[0..MAX_PATH] of char; |
||
2628 | begin |
||
2629 | SetString(Result, szBuf, GetCurrentDirectory(MAX_PATH, szBuf)); |
||
2630 | end; |
||
2631 | |||
2632 | function Int2Str(n: int64; wide: integer = -1): String; |
||
2633 | var |
||
2634 | rev: array[0..25] of Char; |
||
2635 | i, k: Integer; |
||
2636 | prev: PChar; |
||
2637 | begin |
||
2638 | i := 0; |
||
2639 | prev := @rev[25]; |
||
2640 | prev^ := #0; |
||
2641 | while n <> 0 do |
||
2642 | begin |
||
2643 | inc(i); |
||
2644 | dec(prev); |
||
2645 | k := n mod 10; |
||
2646 | prev^ := Char(Ord('0') + k); |
||
2647 | n := n div 10; |
||
2648 | end; |
||
2649 | while (i < wide) and (i < 24) do |
||
2650 | begin |
||
2651 | inc(i); |
||
2652 | dec(prev); |
||
2653 | prev^ := '0'; |
||
2654 | end; |
||
2655 | Result := String(prev); |
||
2656 | end; |
||
2657 | |||
2658 | // return the Detached name |
||
2659 | function DetachedName(const num: string): string; |
||
2660 | begin |
||
2661 | Result := VStr_DetachName; |
||
2662 | if num <> '' then |
||
2663 | Result := Result + num; |
||
2664 | Result := Result + VStr_DetachExt; |
||
2665 | end; |
||
2666 | |||
2667 | function LoadResource(id: integer): Pointer; |
||
2668 | var |
||
2669 | hFind, hRes: THandle; |
||
2670 | Begin |
||
2671 | Result := nil; |
||
2672 | hFind := Windows.FindResource(HInstance, PChar(id), RT_RCDATA); |
||
2673 | if hFind <> 0 then |
||
2674 | begin |
||
2675 | hRes := Windows.LoadResource(HInstance, hFind); |
||
2676 | if hRes <> 0 then |
||
2677 | Result := Windows.LockResource(hRes); |
||
2678 | end; |
||
2679 | End; |
||
2680 | |||
2681 | |||
2682 | procedure Finish; |
||
2683 | begin |
||
2684 | if xbuf <> nil then |
||
2685 | FreeMem(xbuf); |
||
2686 | // FreeMem(VRec_Langs); |
||
2687 | ReAllocMem(p_Items, 0); |
||
2688 | if not CheckCloseHandle(VH_InFile) then |
||
2689 | ErrorMsgBoxFmt1(0, SFX_Err_CannotCloseFile, VStr_ExeName); |
||
2690 | if not CheckCloseHandle(VH_TempFile) then |
||
2691 | ErrorMsgBoxFmt1(0, SFX_Err_CannotCloseFile, VStr_TempFile); |
||
2692 | if VStr_TempFile <> '' then |
||
2693 | DeleteFile(PChar(VStr_TempFile)); |
||
2694 | if not CheckCloseHandle(VH_OutFile) then |
||
2695 | ErrorMsgBoxFmt1(0, SFX_Err_CannotCloseFile, VStr_OutFile); |
||
2696 | FreeMem(VRec_Strings); |
||
2697 | FreeMem(VRec_DefStrings); |
||
2698 | end; |
||
2699 | |||
2700 | procedure Run; |
||
2701 | var |
||
2702 | sfi: TSHFileInfo; // to get shell image list handle |
||
2703 | {$IFNDEF DEBUG_SFX} |
||
2704 | pBuf: array[0..MAX_PATH] of Char; // buffer for paramstr(0) |
||
2705 | {$ENDIF} |
||
2706 | sVar: string; |
||
2707 | CCInfo: TCCInitCommonControlsEx; |
||
2708 | begin |
||
2709 | // may 11, 2002: added support for environment variable %TICKS% |
||
2710 | sVar := Int2Str(GetTickCount, 0); |
||
2711 | SetEnvironmentVariable('TICKS', PChar(sVar)); |
||
2712 | |||
2713 | // initialize common controls (for the progress bar and listview) |
||
2714 | CCInfo.dwICC := ICC_LISTVIEW_CLASSES or ICC_PROGRESS_CLASS or ICC_STANDARD_CLASSES; |
||
2715 | CCInfo.dwSize := sizeof(TCCInitCommonControlsEx); |
||
2716 | InitCommonControlsEx(@CCInfo); |
||
2717 | |||
2718 | // Created in the initialisation section of SFXDialogs.pas |
||
2719 | Make_CRC32Table; |
||
2720 | |||
2721 | // get default strings |
||
2722 | if LoadLang(VRec_DefStrings, SFX_LANG_BASE) <= 0 then |
||
2723 | ErrorHaltID(SFX_Err_Archive); |
||
2724 | VStr_SFX_Caption := SFXString(SFX_Cap_App); |
||
2725 | SetLanguage; |
||
2726 | VStr_SFX_Caption := SFXString(SFX_Cap_App); // may be diferent language |
||
2727 | |||
2728 | {$IFNDEF DEBUG_SFX} |
||
2729 | // needs less code than ParamStr(0) |
||
2730 | SetString(VStr_ExeName, pBuf, GetModuleFileName(0, pBuf, sizeof(pBuf))); |
||
2731 | {$ENDIF} |
||
2732 | |||
2733 | // open the archive file (i myself!) |
||
2734 | VH_InFile := CreateFile(PChar(VStr_ExeName), GENERIC_READ, FILE_SHARE_READ, nil, |
||
2735 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
||
2736 | |||
2737 | // If error, notify and abort |
||
2738 | if VH_InFile = INVALID_HANDLE_VALUE then |
||
2739 | ErrorHaltFmt(SFX_Err_Archive, VStr_ExeName); |
||
2740 | |||
2741 | // read the TSFXFileHeader record (and the appended strings) from the file |
||
2742 | GetDefParams; |
||
2743 | |||
2744 | // get the shell's image list handle |
||
2745 | FillChar(sfi, sizeof(sfi),0); |
||
2746 | VH_ShellImageList := SHGetFileInfo(PChar(VStr_ExeName), 0, sfi, sizeof(sfi), |
||
2747 | SHGFI_SYSICONINDEX or SHGFI_SMALLICON); |
||
2748 | |||
2749 | // Display the dialog |
||
2750 | DialogBox(hInstance, Str_Dlg_Main, 0, @MainDialogProc); |
||
2751 | end; |
||
2752 | |||
2753 | {$ifndef DEBUG_SFX} |
||
2754 | initialization |
||
2755 | VStr_SFX_Caption := '';//SFXString(SFX_Cap_App); |
||
2756 | |||
2757 | finalization |
||
2758 | // cleanup |
||
2759 | Finish; |
||
2760 | {$endif} |
||
2761 | end. |
||
2762 |