Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit ZMWrkr19; |
2 | |||
3 | (* |
||
4 | ZMWrkr19.pas - Does most of the work |
||
5 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht, |
||
6 | Eric W. Engler and Chris Vleghert. |
||
7 | |||
8 | This file is part of TZipMaster Version 1.9. |
||
9 | |||
10 | TZipMaster is free software: you can redistribute it and/or modify |
||
11 | it under the terms of the GNU Lesser General Public License as published by |
||
12 | the Free Software Foundation, either version 3 of the License, or |
||
13 | (at your option) any later version. |
||
14 | |||
15 | TZipMaster is distributed in the hope that it will be useful, |
||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 | GNU Lesser General Public License for more details. |
||
19 | |||
20 | You should have received a copy of the GNU Lesser General Public License |
||
21 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
22 | |||
23 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
24 | updates: http://www.delphizip.org |
||
25 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
26 | |||
27 | modified 2010-06-20 |
||
28 | ---------------------------------------------------------------------------*) |
||
29 | |||
30 | {$I '.\ZipVers19.inc'} |
||
31 | {$IFDEF VER180} |
||
32 | {$WARN SYMBOL_DEPRECATED OFF} |
||
33 | {$ENDIF} |
||
34 | |||
35 | interface |
||
36 | |||
37 | uses |
||
38 | SysUtils, Windows, Classes, Graphics, |
||
39 | ZipMstr19, ZMCompat19, ZMCore19, ZMWAUX19, ZMZipFile19; |
||
40 | |||
41 | //------------------------------------------------------------------------ |
||
42 | |||
43 | type |
||
44 | TSFXOps = (sfoNew, sfoZip, sfoExe); |
||
45 | |||
46 | type |
||
47 | TZMWorker = class(TZMWAux) |
||
48 | private |
||
49 | function AddZippedFilesWrite(DstZip: TZMZipFile; DstCnt: Integer; SrcZip: |
||
50 | TZMZipFile; SrcCnt: Integer): integer; |
||
51 | function Prepare(MustExist: Boolean; SafePart: boolean = false): TZMZipFile; |
||
52 | protected |
||
53 | function Delete1: integer; |
||
54 | function IsDetachedSFX(const fn: String): Boolean; |
||
55 | //1 Rewrite via an intermediate |
||
56 | function Remake(CurZip: TZMZipFile; ReqCnt: Integer; All: boolean): Integer; |
||
57 | procedure ResolveMerge(Merge: TZMMergeOpts; SrcZip, DstZip: TZMZipFile; var |
||
58 | SrcCnt, DstCnt: Integer); |
||
59 | procedure VerifySource(SrcZip: TZMZipFile); |
||
60 | public |
||
61 | procedure AddZippedFiles(SrcWorker: TZMWorker; Merge: TZMMergeOpts); |
||
62 | function AddZippedFilesAppend(DstZip, SrcZip: TZMZipFile; Last: Integer): |
||
63 | integer; |
||
64 | procedure AfterConstruction; override; |
||
65 | procedure BeforeDestruction; override; |
||
66 | function ChangeFileDetails(func: TZMChangeFunction; var data): Integer; |
||
67 | procedure Clear; override; |
||
68 | procedure CopyZippedFiles(DestWorker: TZMWorker; DeleteFromSource: boolean; |
||
69 | OverwriteDest: TZMMergeOpts); overload; |
||
70 | procedure Delete; |
||
71 | function ForEach(func: TZMForEachFunction; var data): Integer; |
||
72 | function IsDestWritable(const fname: String; AllowEmpty: Boolean): Boolean; |
||
73 | procedure List; |
||
74 | procedure Rename(RenameList: TList; NewDateTime: Integer; How: TZMRenameOpts = |
||
75 | htrDefault); |
||
76 | procedure Set_ZipComment(const zComment: AnsiString); |
||
77 | procedure StartUp; override; |
||
78 | property TotalSizeToProcess: Int64 read GetTotalSizeToProcess; |
||
79 | end; |
||
80 | |||
81 | implementation |
||
82 | |||
83 | uses |
||
84 | Dialogs, ZMStructs19, ZMDelZip19, ZMXcpt19, ZMUtils19, ZMDlg19, ZMCtx19, |
||
85 | ZMMsgStr19, ZMMsg19, ZMWorkFile19, ZMDrv19, ZMMatch19, ZMIRec19, ZMEOC19; |
||
86 | |||
87 | const |
||
88 | BufSize = 10240; |
||
89 | //8192; // Keep under 12K to avoid Winsock problems on Win95. |
||
90 | // If chunks are too large, the Winsock stack can |
||
91 | // lose bytes being sent or received. |
||
92 | |||
93 | type |
||
94 | pRenData = ^TRenData; |
||
95 | |||
96 | TRenData = record |
||
97 | Owner: TZMCore; |
||
98 | RenList: TList; |
||
99 | DTime: Integer; |
||
100 | How: TZMRenameOpts; |
||
101 | cnt: Integer; |
||
102 | end; |
||
103 | |||
104 | // 'ForEach' function to rename files |
||
105 | function RenFunc(rec: TZMDirRec; var data): Integer; |
||
106 | var |
||
107 | ChangeName: boolean; |
||
108 | FileName: String; |
||
109 | How: TZMRenameOpts; |
||
110 | i: Integer; |
||
111 | k: Integer; |
||
112 | ncomment: String; |
||
113 | newname: String; |
||
114 | newStamp: integer; |
||
115 | pData: pRenData; |
||
116 | pRenRec: PZMRenameRec; |
||
117 | RenSource: TZMString; |
||
118 | begin |
||
119 | filename := rec.FileName; |
||
120 | pData := @data; |
||
121 | How := pData.How; |
||
122 | Result := 0; |
||
123 | for i := 0 to pData^.RenList.Count - 1 do |
||
124 | begin |
||
125 | pRenRec := PZMRenameRec(pData^.RenList[i]); |
||
126 | RenSource := pRenRec.Source; |
||
127 | newname := pRenRec.Dest; |
||
128 | ncomment := pRenRec.Comment; |
||
129 | newStamp := pRenRec.DateTime; |
||
130 | ChangeName := (newname <> '|') and (CompareStr(filename, newname) <> 0); |
||
131 | if How = htrFull then |
||
132 | begin |
||
133 | if pData^.Owner.FNMatch(pRenRec.Source, FileName) then |
||
134 | k := -1 |
||
135 | else |
||
136 | k := 0; |
||
137 | end |
||
138 | else |
||
139 | begin |
||
140 | k := Pos(UpperCase(RenSource), UpperCase(FileName)); |
||
141 | end; |
||
142 | if k <> 0 then |
||
143 | begin |
||
144 | inc(pData^.cnt); // I am selected |
||
145 | if not ChangeName then |
||
146 | Result := 0 |
||
147 | else |
||
148 | begin |
||
149 | if k > 0 then |
||
150 | begin |
||
151 | newname := FileName; |
||
152 | System.Delete(newname, k, Length(RenSource)); |
||
153 | Insert(pRenRec.Dest, newname, k); |
||
154 | end; |
||
155 | Result := rec.ChangeName(newname); |
||
156 | if Result = 0 then |
||
157 | filename := rec.FileName; |
||
158 | end; |
||
159 | if Result = 0 then |
||
160 | begin |
||
161 | if ncomment <> '' then |
||
162 | begin |
||
163 | if ncomment[1] = #0 then |
||
164 | ncomment := ''; |
||
165 | Result := rec.ChangeComment(ncomment); |
||
166 | end; |
||
167 | end; |
||
168 | if Result = 0 then |
||
169 | begin |
||
170 | if newStamp = 0 then |
||
171 | newStamp := pData^.DTime; |
||
172 | if newStamp <> 0 then |
||
173 | Result := rec.ChangeDate(newStamp); |
||
174 | end; |
||
175 | if How <> htrDefault then |
||
176 | break; |
||
177 | end; |
||
178 | end; |
||
179 | end; |
||
180 | |||
181 | (* TZMWorker.AddZippedFiles |
||
182 | Add zipped files from source ZipMaster selected from source FSpecArgs |
||
183 | When finished |
||
184 | FSpecArgs will contain source files copied |
||
185 | FSpecArgsExcl will contain source files skipped |
||
186 | *) |
||
187 | procedure TZMWorker.AddZippedFiles(SrcWorker: TZMWorker; Merge: TZMMergeOpts); |
||
188 | var |
||
189 | BadSkip: Boolean; |
||
190 | DstCnt: Integer; |
||
191 | DstZip: TZMZipFile; |
||
192 | idx: Integer; |
||
193 | res: Integer; |
||
194 | SrcCnt: Integer; |
||
195 | SrcZip: TZMZipFile; |
||
196 | begin |
||
197 | ShowProgress := zspNone; |
||
198 | ClearErr; |
||
199 | // Are source and destination different? |
||
200 | SrcZip := SrcWorker.CentralDir.Current; |
||
201 | VerifySource(SrcZip); // make sure we have some valid |
||
202 | DstZip := Prepare(false, true); |
||
203 | if (SrcWorker = Self) or IsSameFile(ZipFileName, SrcWorker.ZipFileName) then |
||
204 | raise EZipMaster.CreateResDisp(CF_SourceIsDest, true); |
||
205 | |||
206 | if (SrcZip.WorkDrive.DriveLetter = DstZip.WorkDrive.DriveLetter) and |
||
207 | (not DstZip.WorkDrive.DriveIsFixed) and |
||
208 | (DstZip.MultiDisk or SrcZip.MultiDisk or (zwoDiskSpan in WriteOptions)) |
||
209 | then |
||
210 | raise EZipMaster.CreateResDisp(AZ_SameAsSource, true); |
||
211 | |||
212 | BadSkip := false; |
||
213 | FSpecArgs.Clear; |
||
214 | SrcCnt := SrcZip.SelectFiles(SrcWorker.FSpecArgs, SrcWorker.FSpecArgsExcl, |
||
215 | FSpecArgs); |
||
216 | FSpecArgsExcl.Clear; // will contain source files not copied |
||
217 | if SrcCnt > 0 then |
||
218 | begin |
||
219 | // copy the list of not found specs adding the correct error |
||
220 | for idx := 0 to FSpecArgs.Count - 1 do |
||
221 | begin |
||
222 | FSpecArgsExcl.AddObject(FSpecArgs[idx], pointer(stNotFound)); |
||
223 | if ReportSkipping(FSpecArgs[idx], 0, stNotFound) then |
||
224 | BadSkip := true; |
||
225 | end; |
||
226 | end; |
||
227 | FSpecArgs.Clear; // will contain files copied from source |
||
228 | if BadSkip then |
||
229 | raise EZipMaster.CreateResDisp(GE_NoSkipping, true); |
||
230 | if SrcCnt < 1 then |
||
231 | raise EZipMaster.CreateResDisp(AZ_NothingToDo, true); |
||
232 | |||
233 | DstCnt := DstZip.Select('*', zzsSet); // initial want all |
||
234 | if DstCnt > 0 then |
||
235 | begin |
||
236 | // Resolve merge conflicts |
||
237 | // Src files to be copied are appended to FSpecArgs |
||
238 | // Dst files to be copied instead of Src files appended to FSpecArgsExcl |
||
239 | ResolveMerge(Merge, SrcZip, DstZip, SrcCnt, DstCnt); |
||
240 | end; |
||
241 | if SrcCnt < 1 then |
||
242 | raise EZipMaster.CreateResDisp(AZ_NothingToDo, true); |
||
243 | // write the results |
||
244 | res := AddZippedFilesWrite(DstZip, DstCnt, SrcZip, SrcCnt); |
||
245 | CentralDir.Current := nil; // must reload |
||
246 | if res < 0 then |
||
247 | raise EZipMaster.CreateResDisp(-res, res <> -GE_Abort); |
||
248 | // Update the Zip Directory by calling List method |
||
249 | // for spanned exe avoid swapping to last disk |
||
250 | if not IsDetachedSFX(ZipFileName) then |
||
251 | List; |
||
252 | end; |
||
253 | |||
254 | function TZMWorker.AddZippedFilesAppend(DstZip, SrcZip: TZMZipFile; Last: |
||
255 | Integer): integer; |
||
256 | var |
||
257 | r: Integer; |
||
258 | Zip: TZMZipCopy; |
||
259 | TruncPosn: Int64; |
||
260 | begin |
||
261 | DstZip.File_Close; |
||
262 | Zip := TZMZipCopy.Create(Self); |
||
263 | try |
||
264 | Zip.Replicate(DstZip, Last); |
||
265 | Zip.DiskNr := 0; |
||
266 | Zip.ShowProgress := zspFull; |
||
267 | Result := 0; |
||
268 | r := Zip.Count; |
||
269 | // add copied entries |
||
270 | r := r + Zip.AffixZippedFiles(SrcZip, false); |
||
271 | if r > 0 then |
||
272 | begin |
||
273 | Result := SrcZip.Reopen(fmOpenRead); |
||
274 | if (Result >= 0) then |
||
275 | begin |
||
276 | if Last >= 0 then |
||
277 | begin |
||
278 | // we must append |
||
279 | Result := Zip.Reopen(fmOpenReadWrite); |
||
280 | if Result >= 0 then |
||
281 | begin |
||
282 | // get truncate position |
||
283 | if (Last + 1) >= DstZip.Count then |
||
284 | TruncPosn := DstZip.CentralOffset // at SOC |
||
285 | else |
||
286 | TruncPosn := DstZip[Last + 1].RelOffLocal; // at start of next local |
||
287 | if Zip.Seek(TruncPosn, 0) <> TruncPosn then |
||
288 | Result := -DS_SeekError |
||
289 | else |
||
290 | if not Zip.SetEndOfFile then |
||
291 | Result := -DS_SeekError; |
||
292 | end; |
||
293 | if Result >= 0 then |
||
294 | begin |
||
295 | Diag('Append to zip'); |
||
296 | Result := Zip.CommitAppend(Last, zwoZipTime in WriteOptions); |
||
297 | end; |
||
298 | end |
||
299 | else |
||
300 | begin |
||
301 | // new zip |
||
302 | Diag('Write new zip'); |
||
303 | if not Zip.File_Create(Zip.FileName) then |
||
304 | Result := -DS_FileError |
||
305 | else |
||
306 | Result := Zip.Commit(zwoZipTime in WriteOptions); |
||
307 | end; |
||
308 | end; |
||
309 | end; |
||
310 | SrcZip.File_Close; |
||
311 | Zip.File_Close; |
||
312 | if Result >= 0 then |
||
313 | begin |
||
314 | if Zip.Count <> r then |
||
315 | Result := AZ_InternalError; |
||
316 | SuccessCnt := Zip.Count; // number of remaining files |
||
317 | end; |
||
318 | finally |
||
319 | FreeAndNil(Zip); |
||
320 | end; |
||
321 | end; |
||
322 | |||
323 | function TZMWorker.AddZippedFilesWrite(DstZip: TZMZipFile; DstCnt: Integer; |
||
324 | SrcZip: TZMZipFile; SrcCnt: Integer): integer; |
||
325 | var |
||
326 | CanAppend: boolean; |
||
327 | existed: boolean; |
||
328 | FirstReplaced: Integer; |
||
329 | Intermed: TZMZipCopy; |
||
330 | LastKept: Integer; |
||
331 | r: Integer; |
||
332 | WillSpilt: boolean; |
||
333 | I: Integer; |
||
334 | begin |
||
335 | existed := (zfi_Loaded and DstZip.info) <> 0; |
||
336 | WillSpilt := DstZip.MultiDisk or ((not existed) and (zwoDiskSpan in DstZip.WriteOptions)); |
||
337 | |||
338 | if (not WillSpilt) and not (existed and (AddSafe in DstZip.AddOptions)) then |
||
339 | begin |
||
340 | // check can append |
||
341 | LastKept := -1; |
||
342 | FirstReplaced := -1; |
||
343 | for I := 0 to DstZip.Count - 1 do |
||
344 | begin |
||
345 | if DstZip[I].Selected then |
||
346 | begin |
||
347 | LastKept := I; |
||
348 | if FirstReplaced >= 0 then |
||
349 | Break; // cannot append |
||
350 | end |
||
351 | else |
||
352 | if FirstReplaced < 0 then |
||
353 | FirstReplaced := I; |
||
354 | end; |
||
355 | CanAppend :=(FirstReplaced < 0) or (LastKept < FirstReplaced); |
||
356 | if (Verbosity >= zvVerbose) and CanAppend then |
||
357 | Diag('Should be able to append starting after index: '+ IntToStr(LastKept)); |
||
358 | if CanAppend then |
||
359 | begin |
||
360 | Result := AddZippedFilesAppend(DstZip, SrcZip, LastKept); |
||
361 | Exit; |
||
362 | end; |
||
363 | end; |
||
364 | // write to intermediate |
||
365 | Intermed := TZMZipCopy.Create(self); |
||
366 | try |
||
367 | if WillSpilt then |
||
368 | Intermed.File_CreateTemp(PRE_INTER, '') |
||
369 | else |
||
370 | Intermed.File_CreateTemp(PRE_INTER, DstZip.FileName); // initial temporary destination |
||
371 | if not WillSpilt then |
||
372 | begin |
||
373 | if assigned(DstZip.stub) and DstZip.UseSFX then |
||
374 | begin |
||
375 | Intermed.AssignStub(DstZip); |
||
376 | Intermed.UseSFX := true; |
||
377 | end; |
||
378 | Intermed.DiskNr := 0; |
||
379 | Intermed.ZipComment := DstZip.ZipComment; // keep orig |
||
380 | end; |
||
381 | Intermed.ShowProgress := zspFull; |
||
382 | Result := 0; |
||
383 | r := 0; |
||
384 | if DstCnt > 0 then |
||
385 | r := Intermed.AffixZippedFiles(DstZip, false); |
||
386 | r := r + Intermed.AffixZippedFiles(SrcZip, false); |
||
387 | if r > 0 then |
||
388 | begin |
||
389 | Result := SrcZip.Reopen(fmOpenRead); |
||
390 | if (Result >= 0) and (DstCnt > 0) then |
||
391 | Result := DstZip.Reopen(fmOpenRead); |
||
392 | if Result >= 0 then |
||
393 | Result := Intermed.Commit(zwoZipTime in DstZip.WriteOptions); |
||
394 | end; |
||
395 | SrcZip.File_Close; |
||
396 | DstZip.File_Close; |
||
397 | Intermed.File_Close; |
||
398 | if Result >= 0 then |
||
399 | begin |
||
400 | if Intermed.Count <> r then |
||
401 | Result := -AZ_InternalError |
||
402 | else |
||
403 | begin |
||
404 | SuccessCnt := Intermed.Count; // number of remaining files |
||
405 | // all correct so Recreate source |
||
406 | Result := Recreate(Intermed, DstZip); |
||
407 | end; |
||
408 | end; |
||
409 | finally |
||
410 | FreeAndNil(Intermed); |
||
411 | end; |
||
412 | end; |
||
413 | |||
414 | procedure TZMWorker.AfterConstruction; |
||
415 | begin |
||
416 | inherited; |
||
417 | fIsDestructing := False; |
||
418 | end; |
||
419 | |||
420 | (*? TZMWorker.BeforeDestruction |
||
421 | 1.73 3 July 2003 RP stop callbacks |
||
422 | *) |
||
423 | procedure TZMWorker.BeforeDestruction; |
||
424 | begin |
||
425 | fIsDestructing := True; // stop callbacks |
||
426 | inherited; |
||
427 | end; |
||
428 | |||
429 | (* TZMWorker.ChangeFileDetails |
||
430 | Add zipped files from source ZipMaster selected from source FSpecArgs |
||
431 | When finished |
||
432 | FSpecArgs will contain source files copied |
||
433 | FSpecArgsExcl will contain source files skipped (data = error code) |
||
434 | *) |
||
435 | function TZMWorker.ChangeFileDetails(func: TZMChangeFunction; var data): |
||
436 | Integer; |
||
437 | var |
||
438 | Changes: Integer; |
||
439 | CurZip: TZMZipFile; |
||
440 | idx: Integer; |
||
441 | rec: TZMIRec; |
||
442 | SelCnt: Integer; |
||
443 | SkipCnt: Integer; |
||
444 | SkippedFiles: TStringList; |
||
445 | begin |
||
446 | ClearErr; |
||
447 | Result := 0; |
||
448 | SuccessCnt := 0; |
||
449 | SkippedFiles := TStringList.Create; |
||
450 | try |
||
451 | if Verbosity >= zvVerbose then |
||
452 | Diag('StartUp ChangeFileDetails'); |
||
453 | CurZip := Prepare(true); // prepare the current zip |
||
454 | SelCnt := CurZip.SelectFiles(FSpecArgs, FSpecArgsExcl, SkippedFiles); |
||
455 | FSpecArgs.Clear; // will contain files processed |
||
456 | FSpecArgsExcl.Clear; // will contain source files skipped |
||
457 | SkipCnt := SkippedFiles.Count; |
||
458 | for idx := 0 to SkippedFiles.Count - 1 do |
||
459 | begin |
||
460 | FSpecArgsExcl.AddObject(SkippedFiles[idx], pointer(stNotFound)); |
||
461 | if ReportSkipping(SkippedFiles[idx], 0, stNotFound) then |
||
462 | Result := -GE_NoSkipping |
||
463 | else |
||
464 | Dec(SkipCnt); // user chose to ignore |
||
465 | end; |
||
466 | if (Result = 0) and ((SelCnt <= 0) or (SkipCnt <> 0)) then |
||
467 | begin |
||
468 | if Verbosity >= zvVerbose then |
||
469 | Diag('nothing selected'); |
||
470 | ShowZipMessage(AZ_NothingToDo, ''); |
||
471 | Result := -AZ_NothingToDo; |
||
472 | end; |
||
473 | finally |
||
474 | SkippedFiles.Free; |
||
475 | end; |
||
476 | // process selected files |
||
477 | Changes := 0; |
||
478 | idx := -1; // from beginning |
||
479 | try |
||
480 | while Result = 0 do |
||
481 | begin |
||
482 | idx := CurZip.NextSelected(idx); |
||
483 | if idx < 0 then |
||
484 | break; // no more - finished |
||
485 | rec := CurZip[idx]; |
||
486 | if Verbosity >= zvVerbose then |
||
487 | Diag('Changing: ' + rec.FileName); |
||
488 | Result := func(rec, data); |
||
489 | if Result <> 0 then |
||
490 | begin |
||
491 | if Verbosity >= zvVerbose then |
||
492 | Diag(Format('error [%d] for: %s',[Result, rec.FileName])); |
||
493 | |||
494 | FSpecArgsExcl.AddObject(rec.FileName, pointer(Result)); |
||
495 | if ReportSkipping(rec.FileName, Result, stCannotDo) then |
||
496 | Result := -GE_NoSkipping |
||
497 | else |
||
498 | Result := 0; // ignore error |
||
499 | end; |
||
500 | if Result = 0 then |
||
501 | begin |
||
502 | FSpecArgs.Add(rec.FileName); |
||
503 | if rec.HasChanges then |
||
504 | begin |
||
505 | if Verbosity >= zvVerbose then |
||
506 | Diag('Changed: ' + rec.FileName); |
||
507 | inc(Changes); |
||
508 | end; |
||
509 | CheckCancel; |
||
510 | end; |
||
511 | end; |
||
512 | except |
||
513 | on E: EZipMaster do |
||
514 | begin |
||
515 | Result := -E.ResId; |
||
516 | end; |
||
517 | on E: Exception do |
||
518 | Result := -GE_ExceptErr; |
||
519 | end; |
||
520 | if (Result = 0) and (Changes > 0) then |
||
521 | begin |
||
522 | if Verbosity >= zvVerbose then |
||
523 | Diag('saving changes'); |
||
524 | Remake(CurZip, -1, True); |
||
525 | SuccessCnt := Changes; |
||
526 | CentralDir.Current := nil; |
||
527 | // Update the Zip Directory by calling List method |
||
528 | // for spanned exe avoid swapping to last disk |
||
529 | if not IsDetachedSFX(ZipFileName) then |
||
530 | List; |
||
531 | end; |
||
532 | if Verbosity >= zvVerbose then |
||
533 | Diag('finished ChangeFileDetails'); |
||
534 | end; |
||
535 | |||
536 | (*? TZMWorker.Clear |
||
537 | Clears lists and strings |
||
538 | *) |
||
539 | procedure TZMWorker.Clear; |
||
540 | begin |
||
541 | Cancel := -1; |
||
542 | SuccessCnt := 0; |
||
543 | inherited; |
||
544 | end; |
||
545 | |||
546 | (* |
||
547 | Enter FSpecArgs and FSpecArgsExcl specify files to be copied |
||
548 | Exit FSpecArgs = files copied |
||
549 | FSpecArgsExcl = files skipped |
||
550 | *) |
||
551 | procedure TZMWorker.CopyZippedFiles(DestWorker: TZMWorker; DeleteFromSource: |
||
552 | boolean; OverwriteDest: TZMMergeOpts); |
||
553 | var |
||
554 | DestName: string; |
||
555 | DstZip: TZMZipFile; |
||
556 | DstCnt: Integer; |
||
557 | I: Integer; |
||
558 | idx: Integer; |
||
559 | SavedDone: TStringList; |
||
560 | res: integer; |
||
561 | Skipped: TStringList; |
||
562 | SrcCnt: Integer; |
||
563 | SrcZip: TZMZipFile; |
||
564 | begin |
||
565 | ShowProgress := zspNone; |
||
566 | ClearErr; |
||
567 | res := 0; |
||
568 | SrcZip := CurrentZip(True, False); |
||
569 | // validate dest |
||
570 | DestName := DestWorker.ZipFileName; |
||
571 | if DestName = '' then |
||
572 | raise EZipMaster.CreateResDisp(GE_NoZipSpecified, true); |
||
573 | // Are source and destination different? |
||
574 | if IsSameFile(ZipFileName, DestName) then |
||
575 | raise EZipMaster.CreateResDisp(CF_SourceIsDest, true); |
||
576 | DstZip := DestWorker.CentralDir.Current; |
||
577 | if DstZip.FileName = '' then |
||
578 | begin |
||
579 | // creating new file |
||
580 | DstZip.FileName := DestName; |
||
581 | DstZip.ReqFileName := DestName; |
||
582 | end; |
||
583 | if (zfi_Cancelled and DstZip.info) <> 0 then |
||
584 | begin |
||
585 | if DstZip.AskAnotherDisk(DestName) = idCancel then |
||
586 | raise EZipMaster.CreateResDisp(GE_Abort, false); |
||
587 | DstZip.info := 0; // clear error |
||
588 | end; |
||
589 | |||
590 | VerifySource(SrcZip); // make sure we have some valid |
||
591 | Skipped := TStringList.Create; |
||
592 | try |
||
593 | SrcCnt := SrcZip.SelectFiles(FSpecArgs, FSpecArgsExcl, Skipped); |
||
594 | FSpecArgsExcl.Clear; // will contain source files not copied |
||
595 | if SrcCnt > 0 then |
||
596 | begin |
||
597 | // copy the list of not found specs adding the correct error |
||
598 | for idx := 0 to Skipped.Count - 1 do |
||
599 | begin |
||
600 | FSpecArgsExcl.AddObject(Skipped[idx], pointer(stNotFound)); |
||
601 | if ReportSkipping(FSpecArgs[idx], 0, stNotFound) then |
||
602 | res := -GE_NoSkipping; |
||
603 | end; |
||
604 | end; |
||
605 | finally |
||
606 | Skipped.Free; |
||
607 | end; |
||
608 | FSpecArgs.Clear; // will contain files copied from source |
||
609 | if (res = 0) and (SrcCnt < 1) then |
||
610 | res := -AZ_NothingToDo; |
||
611 | // we now know what files are selected to be merged |
||
612 | if res = 0 then |
||
613 | begin |
||
614 | DstZip.Boss := Self; |
||
615 | if res >= 0 then |
||
616 | begin |
||
617 | DstCnt := DstZip.Select('*', zzsSet); // initial want all |
||
618 | if DstCnt > 0 then |
||
619 | begin |
||
620 | // Resolve merge conflicts |
||
621 | // Src files to be copied are appended to FSpecArgs |
||
622 | // Dst files to be copied instead of Src files appended to FSpecArgsExcl |
||
623 | ResolveMerge(OverwriteDest, SrcZip, DstZip, SrcCnt, DstCnt); |
||
624 | end; |
||
625 | // Write the resulting zip |
||
626 | if SrcCnt < 1 then |
||
627 | res := -AZ_NothingToDo |
||
628 | else |
||
629 | res := AddZippedFilesWrite(DstZip, DstCnt, SrcZip, SrcCnt); |
||
630 | // did it work? |
||
631 | if res = 0 then |
||
632 | begin |
||
633 | if not IsDetachedSFX(DestName) then |
||
634 | begin |
||
635 | // try to load the destination |
||
636 | DstZip.FileName := DestName; |
||
637 | res := DstZip.Open(False, False); |
||
638 | end; |
||
639 | end; |
||
640 | end; |
||
641 | end; |
||
642 | if (res = 0) and DeleteFromSource then |
||
643 | begin |
||
644 | // delete the copied files |
||
645 | Skipped := nil; |
||
646 | SavedDone := TStringList.Create; |
||
647 | try |
||
648 | // save done and skipped files |
||
649 | SavedDone.AddStrings(FSpecArgs); |
||
650 | Skipped := TStringList.Create; |
||
651 | for I := 0 to FSpecArgsExcl.Count - 1 do |
||
652 | Skipped.AddObject(FSpecArgsExcl.Strings[I], FSpecArgsExcl.Objects[i]); |
||
653 | FSpecArgsExcl.Clear; |
||
654 | res := Delete1; // delete from current zip |
||
655 | FSpecArgs.Assign(SavedDone); // restore done files |
||
656 | for I := 0 to Skipped.Count - 1 do |
||
657 | FSpecArgsExcl.AddObject(Skipped.Strings[I], Skipped.Objects[i]); |
||
658 | finally |
||
659 | SavedDone.Free; |
||
660 | if Skipped <> nil then |
||
661 | Skipped.Free; |
||
662 | end; |
||
663 | CentralDir.Current := nil; // must reload |
||
664 | // Update the Zip Directory by calling List method |
||
665 | // for spanned exe avoid swapping to last disk |
||
666 | if not IsDetachedSFX(ZipFileName) then |
||
667 | List; |
||
668 | end; |
||
669 | if res < 0 then |
||
670 | raise EZipMaster.CreateResDisp(-res, res <> -GE_Abort); |
||
671 | SuccessCnt := FSpecArgs.Count; |
||
672 | end; |
||
673 | |||
674 | (*? TZMWorker.Delete |
||
675 | Deletes files specified in FSpecArgs from current Zip |
||
676 | exit: FSpecArgs = files deleted, |
||
677 | FSpecArgsExcl = files skipped |
||
678 | SuccessCnt = number of files deleted |
||
679 | *) |
||
680 | procedure TZMWorker.Delete; |
||
681 | var |
||
682 | res: integer; |
||
683 | begin |
||
684 | ClearErr; |
||
685 | if {(not assigned(CentralDir.Current)) or} (CentralDir.Current.Count < 1) or |
||
686 | (FSpecArgs.Count = 0) then |
||
687 | res := -DL_NothingToDel |
||
688 | else |
||
689 | res := Delete1; |
||
690 | if res < 0 then |
||
691 | ShowZipMessage(-res, '') |
||
692 | else |
||
693 | SuccessCnt := res; |
||
694 | // Update the Zip Directory by calling List method |
||
695 | // for spanned exe avoid swapping to last disk |
||
696 | if (res <> -DL_NothingToDel) and not IsDetachedSFX(ZipFileName) then |
||
697 | List; |
||
698 | end; |
||
699 | |||
700 | (*? TZMWorker.Delete1 |
||
701 | Deletes files specified in FSpecArgs from current Zip |
||
702 | exit: FSpecArgs = files deleted, |
||
703 | FSpecArgsExcl = files skipped |
||
704 | Result = >=0 number of files deleted, <0 error |
||
705 | *) |
||
706 | function TZMWorker.Delete1: integer; |
||
707 | var |
||
708 | BeforeCnt: Integer; |
||
709 | CurZip: TZMZipFile; |
||
710 | DelCnt: Integer; |
||
711 | idx: Integer; |
||
712 | SkippedFiles: TStringList; |
||
713 | begin |
||
714 | CurZip := Prepare(true); // prepare the Current zip |
||
715 | Result := 0; |
||
716 | SkippedFiles := TStringList.Create; |
||
717 | try |
||
718 | DelCnt := CurZip.SelectFiles(FSpecArgs, FSpecArgsExcl, SkippedFiles); |
||
719 | FSpecArgs.Clear; // will contain files deleted |
||
720 | FSpecArgsExcl.Clear; // will contain files skipped |
||
721 | for idx := 0 to SkippedFiles.Count - 1 do |
||
722 | begin |
||
723 | FSpecArgsExcl.AddObject(SkippedFiles[idx], pointer(stNotFound)); |
||
724 | if ReportSkipping(SkippedFiles[idx], 0, stNotFound) then |
||
725 | Result := - GE_NoSkipping; |
||
726 | end; |
||
727 | finally |
||
728 | SkippedFiles.Free; |
||
729 | end; |
||
730 | if (Result = 0) and (DelCnt <= 0) then |
||
731 | Result := -DL_NothingToDel; |
||
732 | if Result = 0 then |
||
733 | begin |
||
734 | ASSERT(DelCnt = CurZip.SelCount, 'selcount wrong 1'); |
||
735 | DelCnt := CurZip.Count - DelCnt; |
||
736 | if DelCnt < 1 then |
||
737 | begin |
||
738 | // no files left |
||
739 | CurZip.File_Close; |
||
740 | SysUtils.DeleteFile(CurZip.FileName); |
||
741 | Result := DelCnt; // number of files deleted |
||
742 | end |
||
743 | else |
||
744 | begin |
||
745 | idx := -1; // from beginning |
||
746 | while true do |
||
747 | begin |
||
748 | idx := CurZip.NextSelected(idx); |
||
749 | if idx < 0 then |
||
750 | break; // no more - finished |
||
751 | FSpecArgs.Add(CurZip[idx].FileName); |
||
752 | end; |
||
753 | BeforeCnt := CurZip.Count; |
||
754 | CurZip.Select('*', zzsToggle); // select entries to keep |
||
755 | ASSERT(DelCnt = CurZip.SelCount, 'selcount wrong 2'); |
||
756 | // write the result |
||
757 | Result := Remake(CurZip, DelCnt, False); |
||
758 | if Result >= 0 then |
||
759 | Result := BeforeCnt - Result; // if no error |
||
760 | end; |
||
761 | end; |
||
762 | CurZip.Invalidate; |
||
763 | CentralDir.Current := nil; // force reload |
||
764 | end; |
||
765 | |||
766 | function TZMWorker.ForEach(func: TZMForEachFunction; var data): Integer; |
||
767 | var |
||
768 | BadSkip: Boolean; |
||
769 | CurZip: TZMZipFile; |
||
770 | good: Integer; |
||
771 | i: Integer; |
||
772 | idx: Integer; |
||
773 | rec: TZMDirEntry; |
||
774 | SelCnt: Integer; |
||
775 | SkippedFiles: TStringList; |
||
776 | begin |
||
777 | ClearErr; |
||
778 | Result := 0; |
||
779 | SuccessCnt := 0; |
||
780 | good := 0; |
||
781 | SkippedFiles := TStringList.Create; |
||
782 | try |
||
783 | if Verbosity >= zvVerbose then |
||
784 | Diag('StartUp ForEach'); |
||
785 | CurZip := CurrentZip(True); |
||
786 | SelCnt := CurZip.SelectFiles(FSpecArgs, FSpecArgsExcl, SkippedFiles); |
||
787 | if SelCnt <= 0 then |
||
788 | begin |
||
789 | if Verbosity >= zvVerbose then |
||
790 | Diag('nothing selected'); |
||
791 | ShowZipMessage(AZ_NothingToDo, ''); |
||
792 | Exit; |
||
793 | end; |
||
794 | FSpecArgs.Clear; // will contain files processed |
||
795 | FSpecArgsExcl.Clear; // will contain files skipped |
||
796 | BadSkip := False; |
||
797 | for idx := 0 to SkippedFiles.Count - 1 do |
||
798 | begin |
||
799 | FSpecArgsExcl.AddObject(SkippedFiles[idx], pointer(stNotFound)); |
||
800 | if ReportSkipping(SkippedFiles[idx], 0, stNotFound) then |
||
801 | BadSkip := True; |
||
802 | end; |
||
803 | finally |
||
804 | SkippedFiles.Free; |
||
805 | end; |
||
806 | if BadSkip then |
||
807 | begin |
||
808 | ShowZipMessage(GE_NoSkipping, ''); |
||
809 | Exit; |
||
810 | end; |
||
811 | i := -1; |
||
812 | while True do |
||
813 | begin |
||
814 | i := CurZip.NextSelected(i); |
||
815 | if i < 0 then |
||
816 | break; |
||
817 | rec := CurZip[i]; |
||
818 | if Verbosity >= zvVerbose then |
||
819 | Diag('Processing: ' + rec.FileName); |
||
820 | Result := func(rec, data); |
||
821 | if Result <> 0 then |
||
822 | begin |
||
823 | FSpecArgsExcl.Add(rec.FileName); |
||
824 | break; |
||
825 | end; |
||
826 | inc(good); |
||
827 | FSpecArgs.Add(rec.FileName); |
||
828 | CheckCancel; |
||
829 | end; |
||
830 | SuccessCnt := good; |
||
831 | if Verbosity >= zvVerbose then |
||
832 | Diag('finished ForEach'); |
||
833 | end; |
||
834 | |||
835 | (*? TZMWorker.IsDestWritable |
||
836 | 1.79 2005 Jul 9 |
||
837 | *) |
||
838 | function TZMWorker.IsDestWritable(const fname: String; AllowEmpty: Boolean): |
||
839 | Boolean; |
||
840 | var |
||
841 | hFile: Integer; |
||
842 | sr: TSearchRec; |
||
843 | wd: TZMWorkDrive; |
||
844 | xname: String; |
||
845 | begin |
||
846 | Result := False; |
||
847 | wd := TZMWorkDrive.Create; |
||
848 | try |
||
849 | xname := ExpandUNCFileName(fname); |
||
850 | // test if destination can be written |
||
851 | wd.DriveStr := xname; |
||
852 | if not wd.HasMedia(false) then |
||
853 | begin |
||
854 | Result := AllowEmpty and (wd.DriveType = DRIVE_REMOVABLE); |
||
855 | // assume can put in writable disk |
||
856 | exit; |
||
857 | end; |
||
858 | if WinXP or (wd.DriveType <> DRIVE_CDROM) then |
||
859 | begin |
||
860 | if sysUtils.FindFirst(xname, faAnyFile, sr) = 0 then |
||
861 | begin |
||
862 | Result := (sr.Attr and faReadOnly) = 0; |
||
863 | sysUtils.FindClose(sr); |
||
864 | if Result then |
||
865 | begin |
||
866 | // exists and is not read-only - test locked |
||
867 | hFile := SysUtils.FileOpen(xname, fmOpenWrite); |
||
868 | Result := hFile > -1; |
||
869 | if Result then |
||
870 | SysUtils.FileClose(hFile); |
||
871 | end; |
||
872 | exit; |
||
873 | end; |
||
874 | // file did not exist - try to create it |
||
875 | hFile := FileCreate(xname); |
||
876 | if hFile > -1 then |
||
877 | begin |
||
878 | Result := True; |
||
879 | FileClose(hFile); |
||
880 | SysUtils.DeleteFile(xname); |
||
881 | end; |
||
882 | end; |
||
883 | finally |
||
884 | wd.Free; |
||
885 | end; |
||
886 | end; |
||
887 | |||
888 | function TZMWorker.IsDetachedSFX(const fn: String): Boolean; |
||
889 | var |
||
890 | ext: String; |
||
891 | wz: TZMZipFile; |
||
892 | begin |
||
893 | Result := False; |
||
894 | ext := ExtractFileExt(fn); |
||
895 | if AnsiSameText(ext, '.exe') then |
||
896 | begin |
||
897 | wz := TZMZipFile.Create(self); |
||
898 | try |
||
899 | wz.FileName := fn; |
||
900 | if (wz.OpenEOC(true) >= 0) and IsDetachSFX(wz) then |
||
901 | Result := true; |
||
902 | finally |
||
903 | wz.Free; |
||
904 | end; |
||
905 | end; |
||
906 | end; |
||
907 | |||
908 | procedure TZMWorker.List; |
||
909 | begin |
||
910 | LoadZip(ZipFileName, false); |
||
911 | end; |
||
912 | |||
913 | (* TZMWorker.Prepare |
||
914 | Prepare destination and get SFX stub as needed |
||
915 | *) |
||
916 | function TZMWorker.Prepare(MustExist: Boolean; SafePart: boolean = false): |
||
917 | TZMZipFile; |
||
918 | begin |
||
919 | Result := CurrentZip(MustExist, SafePart); |
||
920 | if Unattended and not Result.WorkDrive.DriveIsFixed then |
||
921 | raise EZipMaster.CreateResDisp(DS_NoUnattSpan, true); |
||
922 | if (Uppercase(ExtractFileExt(Result.ReqFileName)) = EXT_EXE) then |
||
923 | begin |
||
924 | Result.UseSFX := true; |
||
925 | Result.Stub := NewSFXStub; |
||
926 | Result.UseSFX := true; |
||
927 | end; |
||
928 | end; |
||
929 | |||
930 | // write to intermediate then recreate as original |
||
931 | function TZMWorker.Remake(CurZip: TZMZipFile; ReqCnt: Integer; All: boolean): |
||
932 | Integer; |
||
933 | var |
||
934 | Intermed: TZMZipCopy; |
||
935 | Res: Integer; |
||
936 | begin |
||
937 | Result := 0; |
||
938 | Intermed := TZMZipCopy.Create(self); |
||
939 | try |
||
940 | if not Intermed.File_CreateTemp(PRE_INTER, '') then |
||
941 | raise EZipMaster.CreateResDisp(DS_NoOutFile, True); |
||
942 | Intermed.ShowProgress := zspFull; |
||
943 | Intermed.ZipComment := CurZip.ZipComment; |
||
944 | CurZip.Reopen(fmOpenRead); |
||
945 | Res := Intermed.WriteFile(CurZip, All); |
||
946 | CurZip.File_Close; |
||
947 | Intermed.File_Close; |
||
948 | if Res < 0 then |
||
949 | raise EZipMaster.CreateResDisp(-Res, true); |
||
950 | Result := Intermed.Count; // number of remaining files |
||
951 | if (ReqCnt >= 0) and (Result <> ReqCnt) then |
||
952 | raise EZipMaster.CreateResDisp(AZ_InternalError, true); |
||
953 | // Recreate like orig |
||
954 | Res := Recreate(Intermed, CurZip); |
||
955 | if Res < 0 then |
||
956 | raise EZipMaster.CreateResDisp(-Res, true); |
||
957 | finally |
||
958 | Intermed.Free; // also delete temp file |
||
959 | end; |
||
960 | end; |
||
961 | |||
962 | (*? TZMWorker.Rename |
||
963 | Function to read a Zip archive and change one or more file specifications. |
||
964 | Source and Destination should be of the same type. (path or file) |
||
965 | If NewDateTime is 0 then no change is made in the date/time fields. |
||
966 | *) |
||
967 | procedure TZMWorker.Rename(RenameList: TList; NewDateTime: Integer; How: |
||
968 | TZMRenameOpts = htrDefault); |
||
969 | var |
||
970 | i: Integer; |
||
971 | RenDat: TRenData; |
||
972 | RenRec: PZMRenameRec; |
||
973 | res: Integer; |
||
974 | begin |
||
975 | for i := 0 to RenameList.Count - 1 do |
||
976 | begin |
||
977 | RenRec := RenameList.Items[i]; |
||
978 | if IsWild(RenRec.Source) then |
||
979 | raise EZipMaster.CreateResDisp(AD_InvalidName, true); |
||
980 | RenRec^.Source := SetSlash(RenRec^.Source, psdExternal); |
||
981 | RenRec^.Dest := SetSlash(RenRec^.Dest, psdExternal); |
||
982 | end; |
||
983 | RenDat.Owner := Self; |
||
984 | RenDat.RenList := RenameList; |
||
985 | RenDat.DTime := NewDateTime; |
||
986 | RenDat.How := How; |
||
987 | RenDat.cnt := 0; |
||
988 | if FSpecArgs.Count < 1 then |
||
989 | FSpecArgs.Add('*.*'); |
||
990 | res := ChangeFileDetails(@RenFunc, RenDat); |
||
991 | if res < 0 then |
||
992 | raise EZipMaster.CreateResDisp(-res, true); |
||
993 | SuccessCnt := RenDat.cnt; |
||
994 | end; |
||
995 | |||
996 | (* |
||
997 | Resolve merge conflicts |
||
998 | Src files to be copied are appended to FSpecArgs |
||
999 | Dst files to be copied instead of Src files appended to FSpecArgsExcl |
||
1000 | *) |
||
1001 | procedure TZMWorker.ResolveMerge(Merge: TZMMergeOpts; SrcZip, DstZip: |
||
1002 | TZMZipFile; var SrcCnt, DstCnt: Integer); |
||
1003 | var |
||
1004 | DstRec: TZMIRec; |
||
1005 | i: Integer; |
||
1006 | idx: Integer; |
||
1007 | k: Cardinal; |
||
1008 | SrcRec: TZMIRec; |
||
1009 | tmpCopyZippedOverwrite: TZMCopyZippedOverwriteEvent; |
||
1010 | WantSrc: Boolean; |
||
1011 | begin |
||
1012 | i := -1; // from beginning |
||
1013 | k := 0; |
||
1014 | while true do |
||
1015 | begin |
||
1016 | i := SrcZip.NextSelected(i); |
||
1017 | if i < 0 then |
||
1018 | break; |
||
1019 | Inc(k); |
||
1020 | if (k and 127) = 0 then |
||
1021 | CheckCancel; |
||
1022 | SrcRec := SrcZip[i]; |
||
1023 | // check conflicts |
||
1024 | idx := -1; |
||
1025 | DstRec := nil; // keep compiler happy |
||
1026 | if DstCnt > 0 then |
||
1027 | DstRec := DstZip.FindName(SrcRec.FileName, idx); |
||
1028 | if idx < 0 then |
||
1029 | begin |
||
1030 | FSpecArgs.Add(SrcRec.FileName); // ext name |
||
1031 | continue; |
||
1032 | end; |
||
1033 | if Verbosity >= zvVerbose then |
||
1034 | Diag('file conflict: ' + SrcRec.FileName); |
||
1035 | // file exists in both |
||
1036 | WantSrc := false; |
||
1037 | case Merge of |
||
1038 | zmoConfirm: |
||
1039 | begin |
||
1040 | // Do we have a event assigned for this then don't ask. |
||
1041 | tmpCopyZippedOverwrite := Master.OnCopyZippedOverwrite; |
||
1042 | if Assigned(tmpCopyZippedOverwrite) then |
||
1043 | tmpCopyZippedOverwrite(Master, SrcRec, DstRec, WantSrc) |
||
1044 | else if ZipMessageDlgEx('', Format(ZipLoadStr(CF_OverwriteYN), |
||
1045 | [SrcZip.FileName, DstZip.FileName]), |
||
1046 | zmtConfirmation + DHC_CpyZipOvr, [mbYes, mbNo]) = idYes then |
||
1047 | WantSrc := true; |
||
1048 | end; |
||
1049 | zmoAlways: |
||
1050 | WantSrc := true; |
||
1051 | zmoNewer: |
||
1052 | WantSrc := SrcRec.ModifDateTime > DstRec.ModifDateTime; |
||
1053 | zmoOlder: |
||
1054 | WantSrc := SrcRec.ModifDateTime < DstRec.ModifDateTime; |
||
1055 | zmoNever: |
||
1056 | WantSrc := false; |
||
1057 | end; |
||
1058 | if WantSrc then |
||
1059 | begin |
||
1060 | if Verbosity >= zvVerbose then |
||
1061 | Diag('to copy source'); |
||
1062 | DstRec.ClearStatusBit(zsbSelected); |
||
1063 | dec(DstCnt); |
||
1064 | FSpecArgs.Add(SrcRec.FileName); |
||
1065 | end |
||
1066 | else |
||
1067 | begin |
||
1068 | if Verbosity >= zvVerbose then |
||
1069 | Diag('to copy destination'); |
||
1070 | SrcRec.ClearStatusBit(zsbSelected); |
||
1071 | dec(SrcCnt); |
||
1072 | FSpecArgsExcl.Add(SrcRec.FileName); |
||
1073 | end; |
||
1074 | end; |
||
1075 | end; |
||
1076 | |||
1077 | procedure TZMWorker.Set_ZipComment(const zComment: AnsiString); |
||
1078 | var |
||
1079 | EOC: TZipEndOfCentral; |
||
1080 | len: Integer; |
||
1081 | wz: TZMZipFile; |
||
1082 | zcom: AnsiString; |
||
1083 | begin |
||
1084 | wz := TZMZipFile.Create(self); |
||
1085 | try |
||
1086 | try |
||
1087 | if Length(ZipFileName) <> 0 then |
||
1088 | begin |
||
1089 | wz.SpanOptions := wz.SpanOptions - [spExactName]; |
||
1090 | wz.FileName := ZipFileName; |
||
1091 | wz.Open(true, true);// ignore errors |
||
1092 | end |
||
1093 | else |
||
1094 | raise EZipMaster.CreateResDisp(GE_NoZipSpecified, true); |
||
1095 | ZipComment := zComment; |
||
1096 | // opened by OpenEOC() only for Read |
||
1097 | if wz.IsOpen then // file exists |
||
1098 | begin |
||
1099 | wz.File_Close; |
||
1100 | if wz.ZipComment <> zComment then |
||
1101 | begin // change it |
||
1102 | // must reopen for read/write |
||
1103 | zcom := zComment; |
||
1104 | len := Length(zCom); |
||
1105 | wz.File_Open(fmShareDenyWrite or fmOpenReadWrite); |
||
1106 | if not wz.IsOpen then |
||
1107 | raise EZipMaster.CreateResDisp(DS_FileOpen, True); |
||
1108 | if wz.MultiDisk and (wz.StampDate = 0) then |
||
1109 | wz.StampDate := wz.LastWritten; // keep date of set |
||
1110 | wz.CheckSeek(wz.EOCOffset, 0, DS_FailedSeek); |
||
1111 | wz.CheckRead(EOC, SizeOf(EOC), DS_EOCBadRead); |
||
1112 | if (EOC.HeaderSig <> EndCentralDirSig) then |
||
1113 | raise EZipMaster.CreateResDisp(DS_EOCBadRead, True); |
||
1114 | EOC.ZipCommentLen := len; |
||
1115 | wz.CheckSeek(-Sizeof(EOC), 1, DS_FailedSeek); |
||
1116 | wz.CheckWrite(EOC, sizeof(EOC), DS_EOCBadWrite); |
||
1117 | if len > 0 then |
||
1118 | wz.CheckWrite(zCom[1], len, DS_EOCBadWrite); |
||
1119 | // if SetEOF fails we get garbage at the end of the file, not nice but |
||
1120 | // also not important. |
||
1121 | wz.SetEndOfFile; |
||
1122 | end; |
||
1123 | end; |
||
1124 | except |
||
1125 | on ews: EZipMaster do |
||
1126 | begin |
||
1127 | ShowExceptionError(ews); |
||
1128 | ZipComment := ''; |
||
1129 | end; |
||
1130 | on EOutOfMemory do |
||
1131 | begin |
||
1132 | ShowZipMessage(GE_NoMem, ''); |
||
1133 | ZipComment := ''; |
||
1134 | end; |
||
1135 | end; |
||
1136 | finally |
||
1137 | wz.Free; |
||
1138 | end; |
||
1139 | // Update the Zip Directory by calling List method |
||
1140 | // for spanned exe avoid swapping to last disk |
||
1141 | if not IsDetachedSFX(ZipFileName) then |
||
1142 | List |
||
1143 | end; |
||
1144 | |||
1145 | (*? TZMWorker.StartUp |
||
1146 | *) |
||
1147 | procedure TZMWorker.StartUp; |
||
1148 | var |
||
1149 | CurZip: TZMZipFile; |
||
1150 | begin |
||
1151 | SuccessCnt := 0; |
||
1152 | CentralDir.IgnoreDirOnly := not Master.UseDirOnlyEntries; |
||
1153 | inherited; |
||
1154 | // update values that may have changed since CurZip was made |
||
1155 | CurZip := CentralDir.Current; |
||
1156 | CurZip.AddOptions := AddOptions; |
||
1157 | CurZip.SpanOptions := SpanOptions; |
||
1158 | CurZip.WriteOptions := WriteOptions; |
||
1159 | CurZip.IgnoreDirOnly := IgnoreDirOnly; |
||
1160 | CurZip.Encoding := Encoding; |
||
1161 | CurZip.EncodeAs := EncodeAs; |
||
1162 | CurZip.Encoding_CP := Encoding_CP; |
||
1163 | end; |
||
1164 | |||
1165 | procedure TZMWorker.VerifySource(SrcZip: TZMZipFile); |
||
1166 | begin |
||
1167 | if not assigned(SrcZip) then |
||
1168 | raise EZipMaster.CreateResDisp(AZ_NothingToDo, true); |
||
1169 | if (SrcZip.info and zfi_Cancelled) <> 0 then |
||
1170 | raise EZipMaster.CreateResDisp(DS_Canceled, true); |
||
1171 | if (SrcZip.info and zfi_loaded) = 0 then |
||
1172 | raise EZipMaster.CreateResDisp(AD_InvalidZip, true); |
||
1173 | end; |
||
1174 | |||
1175 | end. |