X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fshared%2FWADEDITOR_dfzip.pas;h=7f310d4ea4877588aa5308d5724166c923f92c46;hb=b5cff7c2adac12d222e098a74583bf99dd531e98;hp=f7abf9e9bb1d8ac3a7532870861d4040d5f9247d;hpb=952e5c9c629e44e260c55f2756d72a199d8d9052;p=d2df-editor.git diff --git a/src/shared/WADEDITOR_dfzip.pas b/src/shared/WADEDITOR_dfzip.pas index f7abf9e..7f310d4 100644 --- a/src/shared/WADEDITOR_dfzip.pas +++ b/src/shared/WADEDITOR_dfzip.pas @@ -56,13 +56,13 @@ interface function Preload(p: PResource): Boolean; function GetSourceStream(p: PResource): TStream; - function ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc: UInt32): Boolean; - function ReadCDR(s: TStream): Boolean; + procedure ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc: UInt32); + procedure ReadCDR(s: TStream; cdrid: Integer); function FindEOCD(s: TStream): Boolean; - function ReadEOCD(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 WriteCDR(s: TStream; comp, crc, csize, usize, eattr, offset: UInt32; const afname: AnsiString; cdrid: Integer); procedure SaveToStream(s: TStream); public @@ -92,7 +92,7 @@ interface implementation - uses SysUtils, StrUtils, zstream, crc, e_log; + uses SysUtils, StrUtils, utils, zstream, crc, e_log; const ZIP_SIGN_CDR = 'PK'#1#2; @@ -100,8 +100,30 @@ implementation ZIP_SIGN_EOCD = 'PK'#5#6; const - ZIP_COMP_STORE = 0; - ZIP_COMP_DEFLATE = 8; + ZIP_COMP_STORE = 0; + ZIP_COMP_SHRUNK = 1; + ZIP_COMP_REDUCE1 = 2; + ZIP_COMP_REDUCE2 = 3; + ZIP_COMP_REDUCE3 = 4; + ZIP_COMP_REDUCE4 = 5; + ZIP_COMP_IMPLODE = 6; + ZIP_COMP_TOKENIZED = 7; + ZIP_COMP_DEFLATE = 8; + ZIP_COMP_DEFLATE64 = 9; + ZIP_COMP_TERSE1 = 10; + ZIP_COMP_BZIP2 = 12; + ZIP_COMP_LZMA = 14; + ZIP_COMP_CMPSC = 16; + ZIP_COMP_TERSE2 = 18; + ZIP_COMP_LZ77 = 19; + ZIP_COMP_ZSTD1 = 20; + ZIP_COMP_ZSTD2 = 93; + ZIP_COMP_MP3 = 94; + ZIP_COMP_XZ = 95; + ZIP_COMP_JPEG = 96; + ZIP_COMP_WAVPACK = 97; + ZIP_COMP_PPMD = 98; + ZIP_COMP_AE = 99; const ZIP_SYSTEM = 0; // DOS / FAT @@ -332,7 +354,7 @@ implementation Result := False; FLastError := DFWAD_ERROR_READWAD; try - s := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite); + s := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try GetMem(ptr, s.Size); try @@ -345,8 +367,13 @@ implementation finally s.Free(); end; - except on e: EFOpenError do - FLastError := DFWAD_ERROR_CANTOPENWAD; + except + on e: EFOpenError do + begin + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('DFZIP: AddResource: failed to open file ' + FileName, MSG_NOTIFY); + FLastError := DFWAD_ERROR_CANTOPENWAD; + end; end; end; @@ -415,7 +442,6 @@ implementation Result := True; except s.Free(); - raise; end; end; end; @@ -426,10 +452,14 @@ implementation begin if FStream = nil then begin + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + e_WriteLog('DFZIP: CreateImage: File not assigned', MSG_NOTIFY); FLastError := DFWAD_ERROR_WADNOTLOADED; end else if FStream is TMemoryStream then begin + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + e_WriteLog('DFZIP: CreateImage: Memory stream', MSG_NOTIFY); FLastError := DFWAD_NOERROR; end else @@ -444,6 +474,8 @@ implementation begin if Preload(@FSection[i].list[j]) = False then begin + if gWADEditorLogLevel >= DFWAD_LOG_WARN then + e_WriteLog('DFZIP: CreateImage: failed to preload resource [' + FSection[i].name + '][' + FSection[i].list[j].name + ']', MSG_WARNING); FLastError := DFWAD_ERROR_CANTOPENWAD; exit; end; @@ -459,7 +491,7 @@ implementation procedure TZIPEditor.AddSection(Name: String); begin if InsertSection(Name) = nil then - raise Exception.Create('ZIP: AddSection: failed to add section'); + raise Exception.Create('DFZIP: AddSection[' + Name + ']: failed to insert'); end; function TZIPEditor.HaveResource(Section, Resource: String): Boolean; @@ -504,18 +536,24 @@ implementation begin case p.comp of ZIP_COMP_STORE: - if p.csize = p.usize then begin + 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: - begin + try tmp := TDecompressionStream.Create(src, True); try GetMem(ptr, p.usize); @@ -524,15 +562,28 @@ implementation Result := True; except FreeMem(ptr); + raise; end; finally tmp.Free(); end; + except + on e: EStreamError do + begin + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('DFZIP: Failed to decompress DEFLATEd data, reason: ' + e.Message, MSG_WARNING); + raise e; + end; end; + otherwise + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('DFZIP: Unsupported compression method: ' + IntToStr(p.comp), MSG_WARNING); end; end else begin + if gWADEditorLogLevel >= DFWAD_LOG_WARN then + e_WriteLog('DFZIP: No available source for file data', MSG_WARNING); FLastError := DFWAD_ERROR_WADNOTLOADED; end; if Result = True then @@ -548,12 +599,16 @@ implementation end else begin + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('DFZIP: File integrity check failed: expected CRC32 $' + IntToHex(p.chksum, 8) + ', calculated CRC32 $' + IntToHex(crc, 8), MSG_WARNING); FreeMem(ptr); end; end; end else begin + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + e_WriteLog('DFZIP: Resource not found', MSG_NOTIFY); FLastError := DFWAD_ERROR_RESOURCENOTFOUND; end; end; @@ -587,21 +642,23 @@ implementation end; end; - function TZIPEditor.ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc: UInt32): Boolean; + procedure TZIPEditor.ReadLFH(s: TStream; fname: AnsiString; xcsize, xusize, xcomp, xcrc: UInt32); var sig: packed array [0..3] of Char; - var v, flags, comp: UInt16; + var va, vb, flags, comp: UInt16; var mtime, crc, csize, usize: UInt32; var fnlen, extlen: UInt16; - var datapos: UInt64; + var mypos, datapos: UInt64; var section, name: AnsiString; + var p: Pointer; begin - Result := False; - if s.Position + 30 <= s.Size then + mypos := s.Position; + if mypos + 30 <= s.Size then begin s.ReadBuffer(sig[0], 4); if sig = ZIP_SIGN_LFH then begin - v := LEtoN(s.ReadWord()); + va := s.ReadByte(); // Min Version + vb := s.ReadByte(); // Min System flags := LEtoN(s.ReadWord()); comp := LEtoN(s.ReadWord()); mtime := LEtoN(s.ReadDWord()); @@ -611,36 +668,73 @@ implementation fnlen := LEtoN(s.ReadWord()); extlen := LEtoN(s.ReadWord()); datapos := s.Position + fnlen + extlen; - if datapos + xcsize <= s.Size then + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then begin - // Valid Record Size - ToSectionFile(fname, section, name); - if name = '' then - Result := InsertSection(section) <> nil + e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Min Version : ' + IntToStr(va), MSG_NOTIFY); + 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) + ': 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(extlen), MSG_NOTIFY); + e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': : $' + IntToHex(datapos, 8), MSG_NOTIFY); + end; + if (va >= 10) and (va <= ZIP_MAXVERSION) then + begin + if datapos + xcsize <= s.Size then + begin + ToSectionFile(fname, section, name); + if name = '' then + begin + p := FindSectionRAW(section, True); + if p = nil then + p := InsertSectionRAW(section) + end + else + begin + p := InsertFileInfo(section, name, datapos, xcsize, xusize, xcomp, xcrc); + end; + if p = nil then + raise Exception.Create('Failed to register resource [' + fname + ']'); + end else - Result := InsertFileInfo(section, name, datapos, xcsize, xusize, xcomp, xcrc) <> nil; + raise Exception.Create('Invalid LFH size (corrupted file?)'); + end + else + begin + FLastError := DFWAD_ERROR_WRONGVERSION; + raise Exception.Create('Unsupported CDR version ' + IntToStr(va) + ', not in range [10..' + IntToStr(ZIP_MAXVERSION) + ']'); end; - end; - end; + end + else + raise Exception.Create('Invalid LFH signature $' +IntToHex(Ord(sig[0]), 2) + ' $' +IntToHex(Ord(sig[1]), 2) + ' $' +IntToHex(Ord(sig[2]), 2) + ' $' +IntToHex(Ord(sig[3]), 2) + ' (corrupted file?)'); + end + else + raise Exception.Create('Invalid LFH size (corrupted file?)'); end; - function TZIPEditor.ReadCDR(s: TStream): Boolean; + 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 v, va, vb, flags, comp: UInt16; + var vva, vvb, va, vb, flags, comp: UInt16; var mtime, crc, csize, usize: UInt32; var fnlen, extlen, comlen, disk, iattr: UInt16; var eattr, offset: UInt32; - var next: UInt64; + var mypos, next: UInt64; var name: PChar; begin - Result := False; + mypos := s.Position; s.ReadBuffer(sig[0], 4); if sig = ZIP_SIGN_CDR then begin // Valid Central Directory Signature - v := LEtoN(s.ReadWord()); - va := s.ReadByte(); // Min Version - vb := s.ReadByte(); // Min System + vva := s.ReadByte(); // Writer Version + vvb := s.ReadByte(); // Writer System + va := s.ReadByte(); // Min Version + vb := s.ReadByte(); // Min System flags := LEtoN(s.ReadWord()); comp := LEtoN(s.ReadWord()); mtime := LEtoN(s.ReadDWord()); @@ -656,51 +750,107 @@ implementation offset := LEtoN(s.ReadDWord()); next := s.Position + fnlen + extlen + comlen; FVersion := va; - if va <= ZIP_MAXVERSION then + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then begin - if (flags and ((1 << 0) or (1 << 6) or (1 << 13))) = 0 then + e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer Version : ' + IntToStr(vva), MSG_NOTIFY); + e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer System : ' + IntToStr(vvb), MSG_NOTIFY); + e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min Version : ' + IntToStr(va), MSG_NOTIFY); + 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) + ': 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(extlen), 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(eattr, 8), MSG_NOTIFY); + e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': LFH Offset : $' + IntToHex(offset, 8), MSG_NOTIFY); + end; + if (va >= 10) and (va <= ZIP_MAXVERSION) then + begin + if (flags and ZIP_ENCRYPTION_MASK) = 0 then begin - // TODO: check bit 11 (UTF8 name and comment) if (csize <> $ffffffff) and (usize <> $ffffffff) and (disk <> $ffff) and (offset <> $ffffffff) then begin - // Old Style ZIP if disk = 0 then begin - // Single Volume ZIP if (next <= s.Size) and (fnlen > 0) then begin - // Valid Central Directory Entry + case comp of + ZIP_COMP_STORE: + if csize <> usize then + raise Exception.Create('Compressed size ' + IntToStr(csize) + ' != Descompressed size ' + IntToStr(usize) + 'for STORE method (corrupted file?)'); + ZIP_COMP_SHRUNK, + ZIP_COMP_REDUCE1, + ZIP_COMP_REDUCE2, + ZIP_COMP_REDUCE3, + ZIP_COMP_REDUCE4, + ZIP_COMP_IMPLODE, + ZIP_COMP_DEFLATE, + ZIP_COMP_DEFLATE64, + ZIP_COMP_TERSE1, + ZIP_COMP_BZIP2, + ZIP_COMP_LZMA, + ZIP_COMP_CMPSC, + ZIP_COMP_TERSE2, + ZIP_COMP_LZ77, + ZIP_COMP_ZSTD1, + ZIP_COMP_ZSTD2, + ZIP_COMP_MP3, + ZIP_COMP_XZ, + ZIP_COMP_JPEG, + ZIP_COMP_WAVPACK, + ZIP_COMP_PPMD: + ; // ok + ZIP_COMP_AE: + raise Exception.Create('Encrypted archives not supported'); + otherwise + 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; + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name : "' + name + '"', MSG_NOTIFY); s.Seek(offset, TSeekOrigin.soBeginning); - Result := ReadLFH(s, name, csize, usize, comp, crc); + ReadLFH(s, name, csize, usize, comp, crc); finally s.Seek(next, TSeekOrigin.soBeginning); FreeMem(name); end; - end; - end; + end + else + raise Exception.Create('Empty files names not supported'); + end + else + raise Exception.Create('Splitted archives not supported'); end else begin - // ZIP64 FLastError := DFWAD_ERROR_WRONGVERSION; + raise Exception.Create('ZIP64 not supported'); end; end else begin - // Encrypted file FLastError := DFWAD_ERROR_READWAD; + raise Exception.Create('Encrypted archives not supported'); end; end else begin - // Unsupported version FLastError := DFWAD_ERROR_WRONGVERSION; + raise Exception.Create('Unsupported CDR version ' + IntToStr(va) + ', not in range [10..' + IntToStr(ZIP_MAXVERSION) + ']'); end; - end; + end + else + raise Exception.Create('Invalid CDR signature $' + IntToHex(Ord(sig[0]), 2) + ' $' +IntToHex(Ord(sig[1]), 2) + ' $' +IntToHex(Ord(sig[2]), 2) + ' $' +IntToHex(Ord(sig[3]), 2) + ' (corrupted file?)'); end; function TZIPEditor.FindEOCD(s: TStream): Boolean; @@ -724,12 +874,12 @@ implementation end; end; - function TZIPEditor.ReadEOCD(s: TStream): Boolean; + procedure TZIPEditor.ReadEOCD(s: TStream); var sig: packed array [0..3] of Char; var idisk, ndisk, nrec, total, comlen: UInt16; var csize, cpos, i: UInt32; + var mypos: UInt64; begin - Result := False; FLastError := DFWAD_ERROR_FILENOTWAD; FVersion := 0; s.ReadBuffer(sig[0], 4); @@ -739,6 +889,7 @@ implementation begin // End of Central Directory found FLastError := DFWAD_ERROR_READWAD; + mypos := s.Position - 4; idisk := LEtoN(s.ReadWord()); ndisk := LEtoN(s.ReadWord()); nrec := LEtoN(s.ReadWord()); @@ -746,43 +897,57 @@ implementation csize := LEtoN(s.ReadDWord()); cpos := LEtoN(s.ReadDWord()); comlen := LEtoN(s.ReadWord()); + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + begin + e_WriteLog('==============================================', MSG_NOTIFY); + e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Disk ID : ' + IntToStr(idisk), MSG_NOTIFY); + e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Disk ID with CD : ' + IntToStr(ndisk), MSG_NOTIFY); + e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Available CDR''s : ' + IntToStr(nrec), MSG_NOTIFY); + e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Total CDR''s : ' + IntToStr(total), MSG_NOTIFY); + e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': CD Length : ' + IntToStr(csize), MSG_NOTIFY); + e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': CD Offset : $' + IntToHex(cpos, 8), MSG_NOTIFY); + e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(comlen), MSG_NOTIFY); + end; if (idisk <> $ffff) and (ndisk <> $ffff) and (nrec <> $ffff) and (total <> $ffff) and (csize <> $ffffffff) and (cpos <> $ffffffff) then begin - // Old Style ZIP if s.Position + comlen = s.Size then begin - // Valid End of Central Directory size (located exactly at the end of file) if (idisk = 0) and (ndisk = 0) and (nrec = total) then begin - // Single volume ZIP - if (UInt64(cpos) + csize <= s.Size) then + if (nrec * 46 <= csize) and (UInt64(cpos) + csize <= s.Size) then begin - // Valid Cental Directry Record position and size - Result := True; if total > 0 then begin - // At least one Central Directry present i := 0; s.Seek(cpos, TSeekOrigin.soBeginning); - while (i < nrec) and (Result = True) do + while i < nrec do begin - Result := ReadCDR(s); + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + e_WriteLog('==============================================', MSG_NOTIFY); + ReadCDR(s, i); Inc(i); end; - // if Result = False then - // writeln('Invalid Central Directory #', i - 1); + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + e_WriteLog('==============================================', MSG_NOTIFY); end; - end; - end; - end; + end + else + raise Exception.Create('Central Directory too big (corrupted file?)'); + end + else + raise Exception.Create('Splitted archives not supported'); + end + else + raise Exception.Create('EOCD too big (corrupted file?)'); end else - begin - // ZIP64 - FLastError := DFWAD_ERROR_WRONGVERSION; - end; - end; - end; + raise Exception.Create('ZIP64 not supported'); + end + else + raise Exception.Create('EOCD not found (corrupted file?)'); + end + else + raise Exception.Create('Not DFZIP formated file'); end; function TZIPEditor.ReadFile2(FileName: String): Boolean; @@ -791,27 +956,35 @@ implementation FreeWAD(); Result := False; try - s := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite); try - Result := ReadEOCD(s); - if Result = True then - begin + s := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + ReadEOCD(s); FStream := s; FLastError := DFWAD_NOERROR; - end - else - begin - FStream := nil; + Result := True; + except s.Free(); + raise; end; except - s.Free(); + on e: Exception do + begin + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('ZIP: Failed to read ZIP from file ' + FileName + ', reason: ' + e.Message, MSG_WARNING); + FreeWAD(); + end; + end; + except + on e: EFOpenError do + begin + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('DFZIP: Failed to open file ' + FileName + ', reason: ' + e.Message, MSG_WARNING); + if FileExists(FileName) then + FLastError := DFWAD_ERROR_CANTOPENWAD + else + FLastError := DFWAD_ERROR_WADNOTFOUND; end; - except on e: EFOpenError do - if FileExists(FileName) then - FLastError := DFWAD_ERROR_CANTOPENWAD - else - FLastError := DFWAD_ERROR_WADNOTFOUND; end; end; @@ -820,25 +993,27 @@ implementation begin FreeWAD(); Result := False; - s := TMemoryStream.Create; try - s.SetSize(Len); - s.WriteBuffer(PByte(Data)[0], Len); - s.Seek(0, soBeginning); - Result := ReadEOCD(s); - if Result = True then - begin + s := TMemoryStream.Create; + try + s.SetSize(Len); + s.WriteBuffer(PByte(Data)[0], Len); + s.Seek(0, soBeginning); + ReadEOCD(s); FStream := s; FLastError := DFWAD_NOERROR; - end - else - begin - FStream := nil; + Result := True; + except s.Free(); + raise; end; except - s.Free(); - raise; + on e: Exception do + begin + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('DFZIP: Failed to read ZIP from memory, reason: ' + e.Message, MSG_WARNING); + FreeWAD(); + end; end; end; @@ -860,48 +1035,87 @@ implementation end; procedure TZIPEditor.WriteLFH(s: TStream; comp, crc, csize, usize: UInt32; const afname: AnsiString); - var fname: PChar; flen: UInt16; + var fname: PChar; fnlen: UInt16; mypos: UInt64; begin + mypos := s.Position; fname := PChar(afname); - flen := Length(fname); + fnlen := Length(fname); + if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then + begin + e_WriteLog('==============================================', MSG_NOTIFY); + e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Min Version : ' + IntToStr(ZIP_VERSION), MSG_NOTIFY); + e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(ZIP_SYSTEM), MSG_NOTIFY); + e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Flags : $' + IntToHex(0, 4), MSG_NOTIFY); + e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Compression : ' + IntToStr(comp), MSG_NOTIFY); + e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Modification Time : $' + IntToHex(0, 8), 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(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(0)); // Flags + WriteInt(s, UInt16(comp)); // Compression method + WriteInt(s, UInt32(0)); // 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; comp, crc, csize, usize, eattr, offset: UInt32; const afname: AnsiString; cdrid: Integer); + var fname: PChar; fnlen: UInt16; mypos: UInt64; begin + mypos := s.Position; fname := PChar(afname); - flen := Length(fname); + fnlen := Length(fname); + 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(ZIP_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(0, 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(0, 8), 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(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(0)); // Flags + WriteInt(s, UInt16(comp)); // Compression method + WriteInt(s, UInt32(0)); // 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); @@ -909,6 +1123,7 @@ implementation 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; @@ -936,7 +1151,7 @@ implementation end else begin - raise Exception.Create('ZIP: SaveToStream: No data source available'); + raise Exception.Create('No data source available (somethig very wrong)'); end; end; end @@ -949,7 +1164,7 @@ implementation end; // Write CDR headers count := 0; - loffset := start; + loffset := 0; offset := s.Position - start; if FSection <> nil then begin @@ -961,7 +1176,7 @@ implementation 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.comp, p.chksum, p.csize, p.usize, $00, loffset, afname, i); loffset := loffset + 30 + Length(afname) + p.csize; Inc(count); end; @@ -969,7 +1184,7 @@ implementation else begin afname := GetFileName(FSection[i].name, ''); - WriteCDR(s, ZIP_COMP_STORE, zcrc, 0, 0, $10, loffset - start, afname); + WriteCDR(s, ZIP_COMP_STORE, zcrc, 0, 0, $10, loffset, afname, i); loffset := loffset + 30 + Length(afname) + 0; Inc(count); end; @@ -979,24 +1194,46 @@ implementation 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); var s: TFileStream; begin - s := TFileStream.Create(FileName, fmCreate); try - SaveToStream(s); - finally - s.Free(); + s := TFileStream.Create(FileName, fmCreate); + try + SaveToStream(s); + finally + s.Free(); + end; + except + on e: Exception do + begin + if gWADEditorLogLevel >= DFWAD_LOG_INFO then + e_WriteLog('ZIP: Failed to create file ' + FileName + ', reason: ' + e.Message, MSG_WARNING); + raise e; + end; end; end; @@ -1016,7 +1253,7 @@ implementation DFWAD_ERROR_WADNOTLOADED: Result := 'DFZIP file is not loaded'; DFWAD_ERROR_READRESOURCE: Result := 'Read resource error'; DFWAD_ERROR_READWAD: Result := 'Read DFZIP error'; - otherwise Result := ''; + otherwise Result := IntToStr(FLastError); end; end;