index 7412af8a12aea7c08fb4a57ed902829e9ec76c03..f250e2c0a05c8fc3fe1a2ce98b9debc9092c0392 100644 (file)
// - File must start with LFH or EOCD signature
// - EOCD must be located strictly at the end of file
// - Multi-disk ZIP files are not supported
-// - UTF-8 not supported yet, expected WIN1251 encoding
+// - Expect UTF-8 or CP1251 encoded names
// - ZIP64 not supported
// - Encryption not supported
// - Zero-length file names not supported
usize: UInt32;
comp: UInt32;
chksum: UInt32;
+ mtime: UInt32;
+ flags: UInt32;
stream: TMemoryStream;
end;
TSection = record
name: AnsiString;
+ mtime: UInt32;
list: array of TResource;
end;
function FindSectionIDRAW(name: AnsiString; caseSensitive: Boolean): Integer;
function FindSectionRAW(name: AnsiString; caseSensitive: Boolean): PSection;
- function InsertSectionRAW(name: AnsiString): PSection;
+ function InsertSectionRAW(name: AnsiString; mtime: UInt32): PSection;
function FindSectionID(name: AnsiString): Integer;
function FindSection(name: AnsiString): PSection;
- function InsertSection(name: AnsiString): PSection;
+ function InsertSection(name: AnsiString; mtime: UInt32): PSection;
- function InsertFileInfo(const section, name: AnsiString; pos, csize, usize, comp, crc: UInt32): PResource;
+ function InsertFileInfo(const section, name: AnsiString; pos, csize, usize, comp, crc, mtime, flags: UInt32): PResource;
function Preload(p: PResource): Boolean;
function GetSourceStream(p: PResource): TStream;
- procedure ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc: UInt32);
+ procedure ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc, xtime, xflags: UInt32);
procedure ReadCDR(s: TStream; cdrid: Integer);
function FindEOCD(s: TStream): Boolean;
procedure ReadEOCD(s: TStream);
- procedure WriteLFH(s: TStream; comp, crc, csize, usize: UInt32; const afname: AnsiString);
- procedure WriteCDR(s: TStream; comp, crc, csize, usize, attr, offset: UInt32; const afname: AnsiString);
+ procedure WriteLFH(s: TStream; flags, comp, mtime, crc, csize, usize: UInt32; const afname: AnsiString);
+ procedure WriteCDR(s: TStream; flags, comp, mtime, crc, csize, usize, eattr, offset: UInt32; const afname: AnsiString; cdrid: Integer);
procedure SaveToStream(s: TStream);
public
implementation
- uses SysUtils, StrUtils, zstream, crc, e_log;
+ uses SysUtils, StrUtils, DateUtils, Math, utils, zstream, crc, e_log;
const
ZIP_SIGN_CDR = 'PK'#1#2;
const
ZIP_SYSTEM = 0; // DOS / FAT
- ZIP_VERSION = 20; // Min version
ZIP_MAXVERSION = 63; // Max supported version
+ const
+ ZIP_ENCRYPTION_MASK = (1 << 0) or (1 << 6) or (1 << 13);
+ ZIP_COMP_MASK = (1 << 1) or (1 << 2) or (1 << 4) or (1 << 12);
+ ZIP_DATA_MASK = (1 << 3);
+ ZIP_PATCH_MASK = (1 << 5);
+ ZIP_UTF8_MASK = (1 << 11);
+ ZIP_STREAM_MASK = (1 << 14);
+
+ function IsASCII(const s: AnsiString): Boolean;
+ var i: Integer;
+ begin
+ for i := 1 to Length(s) do
+ begin
+ if s[i] >= #$80 then
+ begin
+ Result := False;
+ exit;
+ end;
+ end;
+ Result := True;
+ end;
+
+ function IsUTF8(const s: AnsiString): Boolean;
+ var i, j, len: Integer;
+ begin
+ Result := False;
+ i := 1; len := Length(s);
+ while i <= len do
+ begin
+ case Ord(s[i]) of
+ $00..$7F: j := 0;
+ $80..$BF: exit; // invalid encoding
+ $C0..$DF: j := 1;
+ $E0..$EF: j := 2;
+ $F0..$F7: j := 3;
+ otherwise exit; // invalid encoding
+ end;
+ Inc(i);
+ while j > 0 do
+ begin
+ if i > len then exit; // invlid length
+ case Ord(s[i]) of
+ $80..$BF: ; // ok
+ else exit; // invalid encoding
+ end;
+ Inc(i);
+ Dec(j);
+ end;
+ end;
+ Result := True;
+ end;
+
+ function DosToStr(dostime: UInt32): AnsiString;
+ begin
+ try
+ DateTimeToString(Result, 'yyyy/mm/dd hh:nn:ss', DosDateTimeToDateTime(dostime));
+ except on e: EConvertError do
+ Result := 'INVALID ($' + IntToHex(dostime, 8) + ')';
+ end;
+ end;
+
procedure ToSectionFile(fname: AnsiString; out section, name: AnsiString); inline;
var i: SizeInt;
begin
Result := nil;
end;
- function TZIPEditor.InsertSectionRAW(name: AnsiString): PSection;
+ function TZIPEditor.InsertSectionRAW(name: AnsiString; mtime: UInt32): PSection;
var i: Integer;
begin
if FSection = nil then i := 0 else i := Length(FSection);
SetLength(FSection, i + 1);
FSection[i] := Default(TSection);
FSection[i].name := name;
+ FSection[i].mtime := mtime;
Result := @FSection[i];
end;
Result := FindSectionRAW(fixName, False); // CASENAME
end;
- function TZIPEditor.InsertSection(name: AnsiString): PSection;
+ function TZIPEditor.InsertSection(name: AnsiString; mtime: UInt32): PSection;
begin
Result := FindSection(name);
if Result = nil then
- Result := InsertSectionRAW(name);
+ Result := InsertSectionRAW(name, mtime);
end;
- function TZIPEditor.InsertFileInfo(const section, name: AnsiString; pos, csize, usize, comp, crc: UInt32): PResource;
+ function TZIPEditor.InsertFileInfo(const section, name: AnsiString; pos, csize, usize, comp, crc, mtime, flags: UInt32): PResource;
var p: PSection; i: Integer;
begin
p := FindSectionRAW(section, True);
if p = nil then
- p := InsertSectionRAW(section);
+ p := InsertSectionRAW(section, mtime);
if p.list = nil then i := 0 else i := Length(p.list);
SetLength(p.list, i + 1);
p.list[i] := Default(TResource);
p.list[i].usize := usize;
p.list[i].comp := comp;
p.list[i].chksum := crc;
+ p.list[i].mtime := mtime;
+ p.list[i].flags := flags;
p.list[i].stream := nil;
Result := @p.list[i];
end;
var s: TMemoryStream; cs: TCompressionStream; p: PResource;
var comp, crc: UInt32;
begin
+ Name := win2utf(Name);
+ Section := win2utf(Section);
Result := False;
if Name <> '' then
begin
end;
crc := crc32(0, nil, 0);
crc := crc32(crc, data, len);
- p := InsertFileInfo(Section, Name, $ffffffff, s.Size, Len, comp, crc);
+ p := InsertFileInfo(Section, Name, $ffffffff, s.Size, Len, comp, crc, DateTimeToDosDateTime(Now()), 0);
p.stream := s;
Result := True;
except
FSection := nil;
FStream := nil;
FLastError := DFWAD_NOERROR;
- FVersion := ZIP_VERSION;
+ FVersion := 10;
FreeWAD();
end;
FreeAndNil(FStream);
end;
FLastError := DFWAD_NOERROR;
- FVersion := ZIP_VERSION;
+ FVersion := 10;
end;
function TZIPEditor.Preload(p: PResource): Boolean;
Result := True;
except
s.Free();
- raise;
end;
end;
end;
procedure TZIPEditor.AddSection(Name: String);
begin
- if InsertSection(Name) = nil then
+ Name := win2utf(Name);
+ if InsertSection(Name, DateTimeToDosDateTime(Now())) = nil then
raise Exception.Create('DFZIP: AddSection[' + Name + ']: failed to insert');
end;
function TZIPEditor.HaveResource(Section, Resource: String): Boolean;
begin
+ Section := win2utf(Section);
+ Resource := win2utf(Resource);
Result := FindResource(FindSection(Section), Resource) <> nil;
end;
function TZIPEditor.HaveSection(Section: String): Boolean;
begin
+ Section := win2utf(Section);
Result := FindSection(Section) <> nil;
end;
function TZIPEditor.GetResource(Section, Resource: String; var pData: Pointer; var Len: Integer): Boolean;
var p: PResource; ptr: PByte; src: TStream; tmp: TDecompressionStream; crc: UInt32;
begin
+ Section := win2utf(Section);
+ Resource := win2utf(Resource);
FLastError := DFWAD_ERROR_CANTOPENWAD;
Result := False;
pData := nil;
Assert(p.csize = p.usize);
GetMem(ptr, p.usize);
try
- src.ReadBuffer(ptr[0], p.usize);
- Result := True;
- except
- FreeMem(ptr);
+ try
+ src.ReadBuffer(ptr[0], p.usize);
+ Result := True;
+ except
+ FreeMem(ptr);
+ raise;
+ end;
+ except on e: EReadError do
+ if gWADEditorLogLevel >= DFWAD_LOG_WARN then
+ e_WriteLog('DFZIP: Failed to read STOREd data, reason: ' + e.Message, MSG_WARNING);
end;
end;
ZIP_COMP_DEFLATE:
Result := True;
except
FreeMem(ptr);
+ raise;
end;
finally
tmp.Free();
end;
except
- on e: Exception do
+ on e: EStreamError do
begin
if gWADEditorLogLevel >= DFWAD_LOG_INFO then
- e_WriteLog('DFZIP: Failed to decompress by DEFLATE method, reason: ' + e.Message, MSG_WARNING);
+ e_WriteLog('DFZIP: Failed to decompress DEFLATEd data, reason: ' + e.Message, MSG_WARNING);
raise e;
end;
end;
otherwise
- raise Exception.Create('Unknown compression method: ' + IntToStr(p.comp));
+ if gWADEditorLogLevel >= DFWAD_LOG_INFO then
+ e_WriteLog('DFZIP: Unsupported compression method: ' + IntToStr(p.comp), MSG_WARNING);
end;
end
else
function TZIPEditor.GetResourcesList(Section: String): SArray;
var p: PSection; i: Integer;
begin
+ Section := win2utf(Section);
Result := nil;
p := FindSection(Section);
if (p <> nil) and (p.list <> nil) then
SetLength(Result, Length(p.list));
for i := 0 to High(p.list) do
begin
- Result[i] := p.list[i].name;
+ Result[i] := utf2win(p.list[i].name);
end;
end;
end;
SetLength(Result, Length(FSection));
for i := 0 to High(FSection) do
begin
- Result[i] := FSection[i].name;
+ Result[i] := utf2win(FSection[i].name);
end;
end;
end;
- procedure TZIPEditor.ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc: UInt32);
+ procedure TZIPEditor.ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc, xtime, xflags: UInt32);
var sig: packed array [0..3] of Char;
var va, vb, flags, comp: UInt16;
var mtime, crc, csize, usize: UInt32;
e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(vb), MSG_NOTIFY);
e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Flags : $' + IntToHex(flags, 4), MSG_NOTIFY);
e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Compression : ' + IntToStr(comp), MSG_NOTIFY);
- e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Modification Time : $' + IntToHex(mtime, 8), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': CRC-32 : $' + IntToHex(crc, 8), MSG_NOTIFY);
e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
begin
p := FindSectionRAW(section, True);
if p = nil then
- p := InsertSectionRAW(section)
+ p := InsertSectionRAW(section, xtime);
end
else
begin
- p := InsertFileInfo(section, name, datapos, xcsize, xusize, xcomp, xcrc);
+ p := InsertFileInfo(section, name, datapos, xcsize, xusize, xcomp, xcrc, xtime, xflags and ZIP_COMP_MASK);
end;
if p = nil then
raise Exception.Create('Failed to register resource [' + fname + ']');
end;
procedure TZIPEditor.ReadCDR(s: TStream; cdrid: Integer);
- const ZIP_ENCRYPTION_MASK = (1 << 0) or (1 << 6) or (1 << 13);
var sig: packed array [0..3] of Char;
var vva, vvb, va, vb, flags, comp: UInt16;
var mtime, crc, csize, usize: UInt32;
var eattr, offset: UInt32;
var mypos, next: UInt64;
var name: PChar;
+ var aname: AnsiString;
+ var cvtbug, utf8: Boolean;
begin
mypos := s.Position;
s.ReadBuffer(sig[0], 4);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(vb), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Flags : $' + IntToHex(flags, 4), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compression : ' + IntToStr(comp), MSG_NOTIFY);
- e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Modification Time : $' + IntToHex(mtime, 8), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': CRC-32 : $' + IntToHex(crc, 8), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(comlen), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Disk : ' + IntToStr(disk), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Internal Attrib : $' + IntToHex(iattr, 4), MSG_NOTIFY);
- e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': External Attrib : $' + IntToHex(iattr, 8), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': External Attrib : $' + IntToHex(eattr, 8), MSG_NOTIFY);
e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': LFH Offset : $' + IntToHex(offset, 8), MSG_NOTIFY);
end;
+ cvtbug := False;
+ if (vva = $10) and (vvb = $0A) and (va = $10) and (vb = $00) and (flags = (1 << 10)) and (mtime = 0) and (iattr = 0) and (eattr = 0) then
+ begin
+ // HACK: Editor and wadcvt for long time sets incorrent flag for UTF-8
+ flags := ZIP_UTF8_MASK;
+ cvtbug := True;
+ end;
+ if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': WADCVT BUG : ' + BoolToStr(cvtbug, True), MSG_NOTIFY);
if (va >= 10) and (va <= ZIP_MAXVERSION) then
begin
if (flags and ZIP_ENCRYPTION_MASK) = 0 then
ZIP_COMP_AE:
raise Exception.Create('Encrypted archives not supported');
otherwise
- raise Exception.Create('Unsupported compression method ' + IntToStr(comp));
+ raise Exception.Create('Unknown compression method ' + IntToStr(comp));
end;
- // TODO: check bit 11 (UTF8 name and comment)
GetMem(name, UInt32(fnlen) + 1);
try
s.ReadBuffer(name[0], fnlen);
name[fnlen] := #0;
+ aname := name;
+ utf8 := True;
+ if (flags and ZIP_UTF8_MASK = 0) and (IsUTF8(name) = False) then
+ begin
+ aname := win2utf(aname);
+ utf8 := False;
+ end;
if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
- e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name : "' + name + '"', MSG_NOTIFY);
+ begin
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': UTF-8 Comatible : ' + BoolToStr(utf8, True), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name : "' + aname + '"', MSG_NOTIFY);
+ end;
s.Seek(offset, TSeekOrigin.soBeginning);
- ReadLFH(s, name, csize, usize, comp, crc);
+ ReadLFH(s, aname, csize, usize, comp, crc, mtime, flags);
finally
s.Seek(next, TSeekOrigin.soBeginning);
FreeMem(name);
raise Exception.Create('EOCD not found (corrupted file?)');
end
else
- raise Exception.Create('Not DFZIP file');
+ raise Exception.Create('Not DFZIP formated file');
end;
function TZIPEditor.ReadFile2(FileName: String): Boolean;
if gWADEditorLogLevel >= DFWAD_LOG_INFO then
e_WriteLog('ZIP: Failed to read ZIP from file ' + FileName + ', reason: ' + e.Message, MSG_WARNING);
FreeWAD();
- raise e;
end;
end;
except
on e: EFOpenError do
begin
if gWADEditorLogLevel >= DFWAD_LOG_INFO then
- e_WriteLog('ZIP: Failed to open file ' + FileName + ', reason: ' + e.Message, MSG_WARNING);
+ e_WriteLog('DFZIP: Failed to open file ' + FileName + ', reason: ' + e.Message, MSG_WARNING);
if FileExists(FileName) then
FLastError := DFWAD_ERROR_CANTOPENWAD
else
on e: Exception do
begin
if gWADEditorLogLevel >= DFWAD_LOG_INFO then
- e_WriteLog('ZIP: Failed to read ZIP from memory, reason: ' + e.Message, MSG_WARNING);
+ e_WriteLog('DFZIP: Failed to read ZIP from memory, reason: ' + e.Message, MSG_WARNING);
FreeWAD();
- raise e;
end;
end;
end;
procedure TZIPEditor.RemoveResource(Section, Resource: String);
var p: PSection; i: Integer;
begin
+ Section := win2utf(Section);
+ Resource := win2utf(Resource);
p := FindSection(Section);
i := FindResourceID(p, Resource);
if i >= 0 then
end;
end;
- procedure TZIPEditor.WriteLFH(s: TStream; comp, crc, csize, usize: UInt32; const afname: AnsiString);
- var fname: PChar; flen: UInt16;
+ function GetZIPVersion(const afname: AnsiString; flags, comp: UInt16): UInt8;
+ var version: UInt8;
+ begin
+ version := 10; // Base version
+ case comp of
+ ZIP_COMP_STORE: version := 10;
+ ZIP_COMP_SHRUNK: version := 10;
+ ZIP_COMP_REDUCE1: version := 10;
+ ZIP_COMP_REDUCE2: version := 10;
+ ZIP_COMP_REDUCE3: version := 10;
+ ZIP_COMP_REDUCE4: version := 10;
+ ZIP_COMP_IMPLODE: version := 10;
+ ZIP_COMP_TOKENIZED: version := 20;
+ ZIP_COMP_DEFLATE: version := 20;
+ ZIP_COMP_DEFLATE64: version := 21;
+ ZIP_COMP_TERSE1: version := 25; // PKWARE DCL Implode
+ ZIP_COMP_BZIP2: version := 46;
+ ZIP_COMP_LZMA: version := 63;
+ ZIP_COMP_CMPSC: version := 63;
+ ZIP_COMP_TERSE2: version := 63;
+ ZIP_COMP_LZ77: version := 63;
+ ZIP_COMP_ZSTD1: version := 63;
+ ZIP_COMP_ZSTD2: version := 63;
+ ZIP_COMP_MP3: version := 63;
+ ZIP_COMP_XZ: version := 63;
+ ZIP_COMP_JPEG: version := 63;
+ ZIP_COMP_WAVPACK: version := 63;
+ ZIP_COMP_PPMD: version := 63;
+ ZIP_COMP_AE: version := 63;
+ end;
+ if afname[Length(afname)] = '/' then
+ version := Max(20, version); // Folder
+ if flags and ZIP_UTF8_MASK <> 0 then
+ version := Max(63, version); // UTF-8 name
+ Result := version;
+ end;
+
+ procedure TZIPEditor.WriteLFH(s: TStream; flags, comp, mtime, crc, csize, usize: UInt32; const afname: AnsiString);
+ var fname: PChar; version: UInt8; fnlen: UInt16; mypos: UInt64;
begin
+ mypos := s.Position;
fname := PChar(afname);
- flen := Length(fname);
+ fnlen := Length(fname);
+ if IsASCII(afname) = False then
+ flags := flags or ZIP_UTF8_MASK;
+ version := GetZIPVersion(afname, flags, comp);
+ if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
+ begin
+ e_WriteLog('==============================================', MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Min Version : ' + IntToStr(version), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(ZIP_SYSTEM), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Flags : $' + IntToHex(flags, 4), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Compression : ' + IntToStr(comp), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': CRC-32 : $' + IntToHex(crc, 8), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Name Length : ' + IntToStr(fnlen), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Extension Length : ' + IntToStr(0), MSG_NOTIFY);
+ e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Name : "' + fname + '"', MSG_NOTIFY);
+ end;
s.WriteBuffer(ZIP_SIGN_LFH, 4); // LFH Signature
- s.WriteByte(ZIP_VERSION); // Min version
+ s.WriteByte(version); // Min version
s.WriteByte(ZIP_SYSTEM); // System
- s.WriteWord(NtoLE(0)); // Flags
- s.WriteWord(NtoLE(comp)); // Compression method
- s.WriteDWord(NtoLE(0)); // Modification time/date
- s.WriteDWord(NtoLE(crc)); // CRC-32
- s.WriteDWord(NtoLE(csize)); // Compressed size
- s.WriteDWord(NtoLE(usize)); // Decompressed size
- s.WriteWord(NtoLE(flen)); // Name field length
- s.WriteWord(NtoLE(0)); // Extra field length
- s.WriteBuffer(fname[0], flen); // File Name
+ WriteInt(s, UInt16(flags)); // Flags
+ WriteInt(s, UInt16(comp)); // Compression method
+ WriteInt(s, UInt32(mtime)); // Modification time/date
+ WriteInt(s, UInt32(crc)); // CRC-32
+ WriteInt(s, UInt32(csize)); // Compressed size
+ WriteInt(s, UInt32(usize)); // Decompressed size
+ WriteInt(s, UInt16(fnlen)); // Name field length
+ WriteInt(s, UInt16(0)); // Extra field length
+ s.WriteBuffer(fname[0], fnlen); // File Name
end;
- procedure TZIPEditor.WriteCDR(s: TStream; comp, crc, csize, usize, attr, offset: UInt32; const afname: AnsiString);
- var fname: PChar; flen: UInt16;
+ procedure TZIPEditor.WriteCDR(s: TStream; flags, comp, mtime, crc, csize, usize, eattr, offset: UInt32; const afname: AnsiString; cdrid: Integer);
+ var fname: PChar; version: UInt8; fnlen: UInt16; mypos: UInt64;
begin
+ mypos := s.Position;
fname := PChar(afname);
- flen := Length(fname);
+ fnlen := Length(fname);
+ if IsASCII(afname) = False then
+ flags := flags or ZIP_UTF8_MASK;
+ version := GetZIPVersion(afname, flags, comp);
+ if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
+ begin
+ e_WriteLog('==============================================', MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer Version : ' + IntToStr(ZIP_MAXVERSION), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer System : ' + IntToStr(ZIP_SYSTEM), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min Version : ' + IntToStr(version), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(ZIP_SYSTEM), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Flags : $' + IntToHex(flags, 4), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compression : ' + IntToStr(comp), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': CRC-32 : $' + IntToHex(crc, 8), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name Length : ' + IntToStr(fnlen), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Extension Length : ' + IntToStr(0), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(0), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Disk : ' + IntToStr(0), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Internal Attrib : $' + IntToHex(0, 4), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': External Attrib : $' + IntToHex(eattr, 8), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': LFH Offset : $' + IntToHex(offset, 8), MSG_NOTIFY);
+ e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name : "' + fname + '"', MSG_NOTIFY);
+ end;
s.WriteBuffer(ZIP_SIGN_CDR, 4); // CDR Signature
s.WriteByte(ZIP_MAXVERSION); // Used version
s.WriteByte(ZIP_SYSTEM); // Used system
- s.WriteByte(ZIP_VERSION); // Min version
+ s.WriteByte(version); // Min version
s.WriteByte(ZIP_SYSTEM); // Min system
- s.WriteWord(NtoLE(0)); // Flags
- s.WriteWord(NtoLE(comp)); // Compression method
- s.WriteDWord(NtoLE(0)); // Modification time/date
- s.WriteDWord(NtoLE(crc)); // CRC-32
- s.WriteDWord(NtoLE(csize)); // Compressed size
- s.WriteDWord(NtoLE(usize)); // Decompressed size
- s.WriteWord(NtoLE(flen)); // Name field length
- s.WriteWord(NtoLE(0)); // Extra field length
- s.WriteWord(NtoLE(0)); // Comment field length
- s.WriteWord(NtoLE(0)); // Disk
- s.WriteWord(NtoLE(0)); // Internal attributes
- s.WriteDWord(NtoLE(attr)); // External attributes
- s.WriteDWord(NtoLE(offset)); // LFH offset
- s.WriteBuffer(fname[0], flen); // File Name
+ WriteInt(s, UInt16(flags)); // Flags
+ WriteInt(s, UInt16(comp)); // Compression method
+ WriteInt(s, UInt32(mtime)); // Modification time/date
+ WriteInt(s, UInt32(crc)); // CRC-32
+ WriteInt(s, UInt32(csize)); // Compressed size
+ WriteInt(s, UInt32(usize)); // Decompressed size
+ WriteInt(s, UInt16(fnlen)); // Name field length
+ WriteInt(s, UInt16(0)); // Extra field length
+ WriteInt(s, UInt16(0)); // Comment field length
+ WriteInt(s, UInt16(0)); // Disk
+ WriteInt(s, UInt16(0)); // Internal attributes
+ WriteInt(s, UInt32(eattr)); // External attributes
+ WriteInt(s, UInt32(offset)); // LFH offset
+ s.WriteBuffer(fname[0], fnlen); // File Name
end;
procedure TZIPEditor.SaveToStream(s: TStream);
var start, offset, loffset, size, zcrc, count: UInt32;
var p: PResource;
var afname: AnsiString;
+ var mypos: UInt64;
begin
// Write LFH headers and data
start := s.Position;
begin
p := @FSection[i].list[j];
afname := GetFileName(FSection[i].name, p.name);
- WriteLFH(s, p.comp, p.chksum, p.csize, p.usize, afname);
+ WriteLFH(s, p.flags, p.comp, p.mtime, p.chksum, p.csize, p.usize, afname);
if p.stream <> nil then
begin
Assert(p.stream.Size = p.csize);
else
begin
afname := GetFileName(FSection[i].name, '');
- WriteLFH(s, ZIP_COMP_STORE, zcrc, 0, 0, afname);
+ WriteLFH(s, 0, ZIP_COMP_STORE, FSection[i].mtime, zcrc, 0, 0, afname);
end;
end;
end;
// Write CDR headers
count := 0;
- loffset := start;
+ loffset := 0;
offset := s.Position - start;
if FSection <> nil then
begin
begin
p := @FSection[i].list[j];
afname := GetFileName(FSection[i].name, p.name);
- WriteCDR(s, p.comp, p.chksum, p.csize, p.usize, 0, loffset - start, afname);
+ WriteCDR(s, p.flags, p.comp, p.mtime, p.chksum, p.csize, p.usize, $00, loffset, afname, i);
loffset := loffset + 30 + Length(afname) + p.csize;
Inc(count);
end;
else
begin
afname := GetFileName(FSection[i].name, '');
- WriteCDR(s, ZIP_COMP_STORE, zcrc, 0, 0, $10, loffset - start, afname);
+ WriteCDR(s, 0, ZIP_COMP_STORE, FSection[i].mtime, zcrc, 0, 0, $10, loffset, afname, i);
loffset := loffset + 30 + Length(afname) + 0;
Inc(count);
end;
Assert(count < $ffff);
size := s.Position - start - offset;
// Write EOCD header
+ mypos := s.Position;
+ if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
+ begin
+ e_WriteLog('==============================================', MSG_NOTIFY);
+ e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Disk ID : ' + IntToStr(0), MSG_NOTIFY);
+ e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Disk ID with CD : ' + IntToStr(0), MSG_NOTIFY);
+ e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Available CDR''s : ' + IntToStr(count), MSG_NOTIFY);
+ e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Total CDR''s : ' + IntToStr(count), MSG_NOTIFY);
+ e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': CD Length : ' + IntToStr(size), MSG_NOTIFY);
+ e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': CD Offset : $' + IntToHex(offset, 8), MSG_NOTIFY);
+ e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(0), MSG_NOTIFY);
+ e_WriteLog('==============================================', MSG_NOTIFY);
+ end;
s.WriteBuffer(ZIP_SIGN_EOCD, 4); // EOCD Signature
- s.WriteWord(NtoLE(0)); // Disk
- s.WriteWord(NtoLE(0)); // Num of Disks
- s.WriteWord(NtoLE(count)); // Num of CDRs
- s.WriteWord(NtoLE(count)); // Total CDR entries
- s.WriteDWord(NtoLE(size)); // Central Directory size
- s.WriteDWord(NtoLE(offset)); // Central Directory offset
- s.WriteWord(NtoLE(0)); // Comment field length
+ WriteInt(s, UInt16(0)); // Disk
+ WriteInt(s, UInt16(0)); // Num of Disks
+ WriteInt(s, UInt16(count)); // Num of CDRs
+ WriteInt(s, UInt16(count)); // Total CDR entries
+ WriteInt(s, UInt32(size)); // Central Directory size
+ WriteInt(s, UInt32(offset)); // Central Directory offset
+ WriteInt(s, UInt16(0)); // Comment field length
end;
procedure TZIPEditor.SaveTo(FileName: String);