[delphizip] Re: AddStreamToFile file date

  • From: Russell Peters <rpeters@xxxxxxxxxxxxx>
  • To: delphizip@xxxxxxxxxxxxx
  • Date: Wed, 30 Sep 2015 08:41:29 +1000

On 29/09/2015 5:52 PM, Han van Eekelen wrote:

-----Oorspronkelijk bericht-----
Van: delphizip-bounce@xxxxxxxxxxxxx
[mailto:delphizip-bounce@xxxxxxxxxxxxx]
Namens Russell Peters
Verzonden: dinsdag 29 september 2015 02:34
Aan: delphizip@xxxxxxxxxxxxx
Onderwerp: [delphizip] Re: AddStreamToFile file date

On 28/09/2015 9:41 PM, Han van Eekelen wrote:
I am puzzled with the use of the FileDate parameter of AddStreamToFile.
I see different results depending on which viewer/extractor I use.
Passing 0 as FileDate today gave me a date of 3193-10-07 in 7-Zip,
PeaZip
and WinRar.
WinZip reports an error on opening the archive and then hangs.
The Windows shell reports the correct date and time as does the
included
ZipDemo1 project. Is there a way to set the date in a compatible
manner for the other programs? Is there a way to set the NTFS created
and modified time stamps?


---
Han van Eekelen

-----------
To unsubscribe from this list, send an empty e-mail message to:
delphizip-request@xxxxxxxxxxxxx
and put the word unsubscribe in the subject.
I did some testing and WinZip, 7-Zip and ZipMaster itself all give the
same
(correct) time.

It is possible to set the NTFS times though it is a bit involved

// the following from jclDateTime
function DateTimeToFileTime(DateTime: TDateTime): TFileTime; const
FileTimeBase = -109205.0;
FileTimeStep: Extended = 24.0 * 60.0 * 60.0 * 1000.0 * 1000.0 * 10.0;
// 100
nSek per Day var
E: Extended;
F64: Int64;
begin
E := (DateTime - FileTimeBase) * FileTimeStep;
F64 := Round(E);
Result := TFileTime(F64);
end;

function LocalDateTimeToFileTime(DateTime: TDateTime): FileTime; var
LocalFileTime: TFileTime;
begin
LocalFileTime := DateTimeToFileTime(DateTime);
Result.dwHighDateTime := 0;
Result.dwLowDateTime := 0;
// ResultCheck(LocalFileTimeToFileTime(LocalFileTime, Result));
if not LocalFileTimeToFileTime(LocalFileTime, Result) then
raise Exception.Create('Date conversion error');
{ TODO : daylight saving time }
end;
// the end of extracts from jclDateTime
var
NTFS: TNTFS_Header;

procedure TForm1.ZipMaster1FileExtra(Sender: TObject; const ForFile:
string;
var Data: TZMRawBytes; var IsChanged: Boolean); begin
SetLength(Data, sizeof(TNTFS_Header));
// copy the structure
Move(NTFS, (@Data[1])^, sizeof(TNTFS_Header));
IsChanged := True;
end;

procedure TForm1.Button10Click(Sender: TObject); const destfile =
'e:\temp\test.zip'; var
S: string;
begin
LoadDll;
// prepare the NTFS structure
ZeroMemory(@NTFS, sizeof(TNTFS_Header));
NTFS.Head.Tag := NTFS_data_tag;
NTFS.Head.Vsize := sizeof(TNTFS_Header) - sizeof(TNTFS_Header_Head);
// 32
NTFS.Tg1 := 1;
NTFS.Sz1 := sizeof(TNTFS_Times); // 24
NTFS.Times.MTime := LocalDateTimeToFileTime(Now);
NTFS.Times.ATime := LocalDateTimeToFileTime(Now);
NTFS.Times.CTime := LocalDateTimeToFileTime(Now);
// set event handler
ZipMaster1.OnFileExtra := ZipMaster1FileExtra;
ZipMaster1.Trace := True;
// force it to make clean
if FileExists(destfile) then
DeleteFile(destfile);
ZipMaster1.ZipFileName := destfile;
ZipMaster1.AddOptions := [];
ZipMaster1.FSpecArgs.Clear;
ZipMaster1.FSpecArgsExcl.Clear;
ZipMaster1.ZipStream.LoadFromFile('C:\TestFiles\ZMTestFiles\deploy.txt');
// Memo1.Lines.Add('size of stream = ' +
IntToStr(ZipMaster1.ZipStream.Size));
ZipMaster1.ZipStream.Position := 0;
ZipMaster1.AddStreamToFile('Deploy.txt', 0, 0);
Memo1.Lines.Add(Format('%d: %s', [ZipMaster1.ErrCode,
ZipMaster1.ErrMessage]));
if ZipMaster1.Count > 0 then
begin
// verify
ZipMaster1.ExtrOptions := [extrTest];
ZipMaster1.Extract;
Memo1.Lines.Add(Format('Verify gives: %d: %s', [ZipMaster1.ErrCode,
ZipMaster1.ErrMessage]));
S := ZipMaster1[0].FileName + ' ' + DateTimeToStr(
ZipMaster1[0].DateStamp);
Memo1.Lines.Add(' ' + S);
end;
end;

The various structures and constants are in ZMStructs.pas.
Note: for the purpose of this quick example I 'borrowed'
LocalDateTimeToFileTime() from JCLDateTime.pas.
Note2: the function LoadDll() just loads the appropriate dll (32/64
debug/release) for my tests.

I hope the above makes sense and is helpful (no matter how crude it is).
Russell Peters
-----------
To unsubscribe from this list, send an empty e-mail message to:
delphizip-request@xxxxxxxxxxxxx
and put the word unsubscribe in the subject.
Thanks.
Perhaps locale plays a role in this?
Anyway I will try and set the NTFS times.

---
Han van Eekelen

-----------
To unsubscribe from this list, send an empty e-mail
message to:
delphizip-request@xxxxxxxxxxxxx
and put the word unsubscribe in the subject.
I updated the example to also directly show the set NTFS times (if they
exist).

// the following from jclDateTime
const
FileTimeBase = -109205.0;
FileTimeStep: Extended = 24.0 * 60.0 * 60.0 * 1000.0 * 1000.0 * 10.0;
// 100 nSek per Day

function DateTimeToFileTime(DateTime: TDateTime): TFileTime;
var
E: Extended;
F64: Int64;
begin
E := (DateTime - FileTimeBase) * FileTimeStep;
F64 := Round(E);
Result := TFileTime(F64);
end;

function LocalDateTimeToFileTime(DateTime: TDateTime): FileTime;
var
LocalFileTime: TFileTime;
begin
LocalFileTime := DateTimeToFileTime(DateTime);
Result.dwHighDateTime := 0;
Result.dwLowDateTime := 0;
// ResultCheck(LocalFileTimeToFileTime(LocalFileTime, Result));
if not LocalFileTimeToFileTime(LocalFileTime, Result) then
raise Exception.Create('Date conversion error');
{ TODO : daylight saving time }
end;

function FileTimeToDateTime(const FileTime: TFileTime): TDateTime;
begin
Result := Int64(FileTime) / FileTimeStep;
Result := Result + FileTimeBase;
end;

function FileTimeToLocalDateTime(const FileTime: TFileTime): TDateTime;
var
LocalFileTime: TFileTime;
begin
LocalFileTime.dwHighDateTime := 0;
LocalFileTime.dwLowDateTime := 0;
// ResultCheck(FileTimeToLocalFileTime(FileTime, LocalFileTime));
if not FileTimeToLocalFileTime(FileTime, LocalFileTime) then
raise Exception.Create('Date conversion error');
Result := FileTimeToDateTime(LocalFileTime);
{ TODO : daylight saving time }
end;
// the end of extracts from jclDateTime
var
NTFS: TNTFS_Header;

procedure TForm1.ZipMaster1FileExtra(Sender: TObject; const ForFile: string;
var Data: TZMRawBytes; var IsChanged: Boolean);
begin
SetLength(Data, sizeof(TNTFS_Header));
// copy the structure
Move(NTFS, (@Data[1])^, sizeof(TNTFS_Header));
IsChanged := True;
end;

procedure TForm1.Button10Click(Sender: TObject);
const destfile = 'e:\temp\test.zip';
var
Entry: TZMDirEntry;
Raw: TZMRawBytes;
S: string;
TempNTFS: TNTFS_Header;
begin
LoadDll;
// prepare the NTFS structure
ZeroMemory(@NTFS, sizeof(TNTFS_Header));
NTFS.Head.Tag := NTFS_data_tag;
NTFS.Head.Vsize := sizeof(TNTFS_Header) - sizeof(TNTFS_Header_Head);
// 32
NTFS.Tg1 := 1;
NTFS.Sz1 := sizeof(TNTFS_Times); // 24
NTFS.Times.MTime := LocalDateTimeToFileTime(Now);
NTFS.Times.ATime := LocalDateTimeToFileTime(Now);
NTFS.Times.CTime := LocalDateTimeToFileTime(Now);
// set event handler
ZipMaster1.OnFileExtra := ZipMaster1FileExtra;
ZipMaster1.Trace := True;
// force it to make clean
if FileExists(destfile) then
DeleteFile(destfile);
ZipMaster1.ZipFileName := destfile;
ZipMaster1.AddOptions := [];
ZipMaster1.FSpecArgs.Clear;
ZipMaster1.FSpecArgsExcl.Clear;
ZipMaster1.ZipStream.LoadFromFile('C:\TestFiles\ZMTestFiles\deploy.txt');
ZipMaster1.ZipStream.Position := 0;
ZipMaster1.AddStreamToFile('Deploy.txt', 0, 0);
Memo1.Lines.Add(Format('%d: %s', [ZipMaster1.ErrCode,
ZipMaster1.ErrMessage]));
if ZipMaster1.Count > 0 then
begin
// verify
Entry := ZipMaster1[0];
S := Entry.FileName + ' ' + DateTimeToStr(Entry.DateStamp);
Memo1.Lines.Add(' ' + S);
Raw := Entry.ExtraData[NTFS_data_tag];
if Length(Raw) = (sizeof(TNTFS_Header) - sizeof(TNTFS_Header_Head))
then
begin
Move((@Raw[1])^, TempNTFS.Rsrvd, sizeof(TNTFS_Header) -
sizeof(TNTFS_Header_Head));
Memo1.Lines.Add(' ATime = ' +
DateTimeToStr(FileTimeToLocalDateTime(TempNTFS.Times.ATime)));
Memo1.Lines.Add(' MTime = ' +
DateTimeToStr(FileTimeToLocalDateTime(TempNTFS.Times.MTime)));
Memo1.Lines.Add(' CTime = ' +
DateTimeToStr(FileTimeToLocalDateTime(TempNTFS.Times.CTime)));
end
else
Memo1.Lines.Add('no NTFS data found');

ZipMaster1.ExtrOptions := [extrTest];
ZipMaster1.Extract;
Memo1.Lines.Add(Format('Verify gives: %d: %s', [ZipMaster1.ErrCode,
ZipMaster1.ErrMessage]));
end;
end;

- I must try to remember to add the example to the help.
Russell Peters
-----------
To unsubscribe from this list, send an empty e-mail
message to:
delphizip-request@xxxxxxxxxxxxx
and put the word unsubscribe in the subject.

Other related posts: