DEADSOFTWARE

dfwad: detect UTF-8
[d2df-editor.git] / src / shared / WADEDITOR_dfzip.pas
index 7412af8a12aea7c08fb4a57ed902829e9ec76c03..f9e54ad57f88f597a6a56fdf8e0fac7b8b1f4136 100644 (file)
@@ -6,7 +6,7 @@ unit WADEDITOR_dfzip;
 // - 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
@@ -62,7 +62,7 @@ interface
         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, Math, utils, zstream, crc, e_log;
 
   const
     ZIP_SIGN_CDR  = 'PK'#1#2;
@@ -127,9 +127,56 @@ implementation
 
   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_UTF8_MASK = (1 << 11);
+
+  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;
+
   procedure ToSectionFile(fname: AnsiString; out section, name: AnsiString); inline;
     var i: SizeInt;
   begin
@@ -382,7 +429,7 @@ implementation
     FSection := nil;
     FStream := nil;
     FLastError := DFWAD_NOERROR;
-    FVersion := ZIP_VERSION;
+    FVersion := 10;
     FreeWAD();
   end;
 
@@ -418,7 +465,7 @@ implementation
       FreeAndNil(FStream);
     end;
     FLastError := DFWAD_NOERROR;
-    FVersion := ZIP_VERSION;
+    FVersion := 10;
   end;
 
   function TZIPEditor.Preload(p: PResource): Boolean;
@@ -442,7 +489,6 @@ implementation
           Result := True;
         except
           s.Free();
-          raise;
         end;
       end;
     end;
@@ -541,10 +587,16 @@ implementation
               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:
@@ -557,20 +609,22 @@ implementation
                   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
@@ -710,7 +764,6 @@ implementation
   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;
@@ -718,6 +771,8 @@ implementation
     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);
@@ -760,9 +815,18 @@ implementation
         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
@@ -802,17 +866,26 @@ implementation
                   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);
                 finally
                   s.Seek(next, TSeekOrigin.soBeginning);
                   FreeMem(name);
@@ -940,7 +1013,7 @@ implementation
         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;
@@ -966,14 +1039,13 @@ implementation
           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
@@ -1005,9 +1077,8 @@ implementation
       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;
@@ -1029,49 +1100,133 @@ implementation
     end;
   end;
 
+  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; comp, crc, csize, usize: UInt32; const afname: AnsiString);
-    var fname: PChar; flen: UInt16;
+    var fname: PChar; version: UInt8; fnlen, flags: UInt16; mypos: UInt64;
   begin
+    mypos := s.Position;
     fname := PChar(afname);
-    flen := Length(fname);
+    fnlen := Length(fname);
+    flags := 0;
+    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 : $' + 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(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(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; version: UInt8; fnlen, flags: UInt16; mypos: UInt64;
   begin
+    mypos := s.Position;
     fname := PChar(afname);
-    flen := Length(fname);
+    fnlen := Length(fname);
+    flags := 0;
+    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 : $' + 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(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(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);
@@ -1079,6 +1234,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;
@@ -1119,7 +1275,7 @@ implementation
     end;
     // Write CDR headers
     count := 0;
-    loffset := start;
+    loffset := 0;
     offset := s.Position - start;
     if FSection <> nil then
     begin
@@ -1131,7 +1287,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;
@@ -1139,7 +1295,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;
@@ -1149,14 +1305,27 @@ 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);