1d319af191172c33d437120e2721cb470044225b
1 {$INCLUDE ../shared/a_modes.inc}
5 // Implementation restrictions:
6 // - File must start with LFH or EOCD signature
7 // - EOCD must be located strictly at the end of file
8 // - Multi-disk ZIP files are not supported
9 // - Expect UTF-8 or CP1251 encoded names
10 // - ZIP64 not supported
11 // - Encryption not supported
12 // - Zero-length file names not supported
13 // - CDR holds most actual data about file, LFH mostly ignored
14 // - Attributes, comments and extra data are ignored and not saved
15 // - Store and Deflate compression supported
19 uses Classes
, WADEDITOR
;
29 stream
: TMemoryStream
;
34 list
: array of TResource
;
37 PResource
= ^TResource
;
40 TZIPEditor
= class sealed(WADEDITOR
.TWADEditor
)
42 FSection
: array of TSection
;
47 function FindSectionIDRAW(name
: AnsiString; caseSensitive
: Boolean): Integer;
48 function FindSectionRAW(name
: AnsiString; caseSensitive
: Boolean): PSection
;
49 function InsertSectionRAW(name
: AnsiString): PSection
;
51 function FindSectionID(name
: AnsiString): Integer;
52 function FindSection(name
: AnsiString): PSection
;
53 function InsertSection(name
: AnsiString): PSection
;
55 function InsertFileInfo(const section
, name
: AnsiString; pos
, csize
, usize
, comp
, crc
: UInt32
): PResource
;
56 function Preload(p
: PResource
): Boolean;
57 function GetSourceStream(p
: PResource
): TStream
;
59 procedure ReadLFH(s
: TStream
; fname
: AnsiString; xcsize
, xusize
, xcomp
, xcrc
: UInt32
);
60 procedure ReadCDR(s
: TStream
; cdrid
: Integer);
61 function FindEOCD(s
: TStream
): Boolean;
62 procedure ReadEOCD(s
: TStream
);
64 procedure WriteLFH(s
: TStream
; comp
, crc
, csize
, usize
: UInt32
; const afname
: AnsiString);
65 procedure WriteCDR(s
: TStream
; comp
, crc
, csize
, usize
, eattr
, offset
: UInt32
; const afname
: AnsiString; cdrid
: Integer);
66 procedure SaveToStream(s
: TStream
);
70 destructor Destroy(); override;
71 procedure FreeWAD(); override;
72 function ReadFile2(FileName
: string): Boolean; override;
73 function ReadMemory(Data
: Pointer; Len
: LongWord): Boolean; override;
74 procedure CreateImage(); override;
75 function AddResource(Data
: Pointer; Len
: LongWord; Name
, Section
: String): Boolean; override; overload
;
76 function AddResource(FileName
, Name
, Section
: String): Boolean; override; overload
;
77 function AddAlias(Res
, Alias
: String): Boolean; override;
78 procedure AddSection(Name
: String); override;
79 procedure RemoveResource(Section
, Resource
: String); override;
80 procedure SaveTo(FileName
: String); override;
81 function HaveResource(Section
, Resource
: String): Boolean; override;
82 function HaveSection(Section
: string): Boolean; override;
83 function GetResource(Section
, Resource
: String; var pData
: Pointer; var Len
: Integer): Boolean; override;
84 function GetSectionList(): SArray
; override;
85 function GetResourcesList(Section
: String): SArray
; override;
87 function GetLastError
: Integer; override;
88 function GetLastErrorStr
: String; override;
89 function GetResourcesCount
: Word; override;
90 function GetVersion
: Byte; override;
95 uses SysUtils
, StrUtils
, Math
, utils
, zstream
, crc
, e_log
;
98 ZIP_SIGN_CDR
= 'PK'#1#2;
99 ZIP_SIGN_LFH
= 'PK'#3#4;
100 ZIP_SIGN_EOCD
= 'PK'#5#6;
105 ZIP_COMP_REDUCE1
= 2;
106 ZIP_COMP_REDUCE2
= 3;
107 ZIP_COMP_REDUCE3
= 4;
108 ZIP_COMP_REDUCE4
= 5;
109 ZIP_COMP_IMPLODE
= 6;
110 ZIP_COMP_TOKENIZED
= 7;
111 ZIP_COMP_DEFLATE
= 8;
112 ZIP_COMP_DEFLATE64
= 9;
113 ZIP_COMP_TERSE1
= 10;
117 ZIP_COMP_TERSE2
= 18;
124 ZIP_COMP_WAVPACK
= 97;
129 ZIP_SYSTEM
= 0; // DOS / FAT
130 ZIP_MAXVERSION
= 63; // Max supported version
133 ZIP_ENCRYPTION_MASK
= (1 << 0) or (1 << 6) or (1 << 13);
134 ZIP_UTF8_MASK
= (1 << 11);
136 function IsASCII(const s
: AnsiString): Boolean;
139 for i
:= 1 to Length(s
) do
150 procedure ToSectionFile(fname
: AnsiString; out section
, name
: AnsiString); inline;
153 i
:= LastDelimiter('/', fname
);
154 section
:= Copy(fname
, 1, i
- 1);
155 name
:= Copy(fname
, i
+ 1)
158 function GetFileName(const Section
, Name
: AnsiString): AnsiString; inline;
163 Result
:= Section
+ '/' + Name
;
166 function PrepString(const s
: AnsiString; caseSensitive
, extSensitive
: Boolean): AnsiString; inline;
170 if caseSensitive
= False then
172 Result
:= UpperCase(Result
);
174 if extSensitive
= False then
176 i
:= Pos('.', Result
); // fix dotfiles
178 SetLength(Result
, i
- 1);
182 function FindResourceIDRAW(p
: PSection
; name
: AnsiString; caseSensitive
, extSensitive
: Boolean): Integer;
183 var i
: Integer; pname
: AnsiString;
187 pname
:= PrepString(name
, caseSensitive
, extSensitive
);
188 for i
:= 0 to High(p
.list
) do
190 if PrepString(p
.list
[i
].name
, caseSensitive
, extSensitive
) = pname
then
200 function FindResourceID(p
: PSection
; name
: AnsiString): Integer;
203 i
:= FindResourceIDRAW(p
, name
, True, True); // CaSeNaMe.Ext
206 i
:= FindResourceIDRAW(p
, name
, False, True); // CASENAME.EXT
209 i
:= FindResourceIDRAW(p
, name
, True, False); // CaSeNaMe
212 i
:= FindResourceIDRAW(p
, name
, False, False); // CASENAME
219 function FindResource(p
: PSection
; name
: AnsiString): PResource
;
222 i
:= FindResourceID(p
, name
);
231 function TZIPEditor
.FindSectionIDRAW(name
: AnsiString; caseSensitive
: Boolean): Integer;
232 var i
: Integer; pname
: AnsiString;
234 if FSection
<> nil then
236 pname
:= PrepString(name
, caseSensitive
, True);
237 for i
:= 0 to High(FSection
) do
239 if PrepString(FSection
[i
].name
, caseSensitive
, True) = pname
then
249 function TZIPEditor
.FindSectionRAW(name
: AnsiString; caseSensitive
: Boolean): PSection
;
252 i
:= FindSectionIDRAW(name
, caseSensitive
);
254 Result
:= @FSection
[i
]
259 function TZIPEditor
.InsertSectionRAW(name
: AnsiString): PSection
;
262 if FSection
= nil then i
:= 0 else i
:= Length(FSection
);
263 SetLength(FSection
, i
+ 1);
264 FSection
[i
] := Default(TSection
);
265 FSection
[i
].name
:= name
;
266 Result
:= @FSection
[i
];
271 function TZIPEditor
.FindSectionID(name
: AnsiString): Integer;
272 var fixName
: AnsiString;
274 fixName
:= StringReplace(name
, '\', '/', [rfReplaceAll
], TStringReplaceAlgorithm
.sraManySmall
);
275 Result
:= FindSectionIDRAW(fixName
, True); // CaSeNaMe
277 Result
:= FindSectionIDRAW(fixName
, False); // CASENAME
280 function TZIPEditor
.FindSection(name
: AnsiString): PSection
;
281 var fixName
: AnsiString;
283 fixName
:= StringReplace(name
, '\', '/', [rfReplaceAll
], TStringReplaceAlgorithm
.sraManySmall
);
284 Result
:= FindSectionRAW(fixName
, True); // CaSeNaMe
286 Result
:= FindSectionRAW(fixName
, False); // CASENAME
289 function TZIPEditor
.InsertSection(name
: AnsiString): PSection
;
291 Result
:= FindSection(name
);
293 Result
:= InsertSectionRAW(name
);
298 function TZIPEditor
.InsertFileInfo(const section
, name
: AnsiString; pos
, csize
, usize
, comp
, crc
: UInt32
): PResource
;
299 var p
: PSection
; i
: Integer;
301 p
:= FindSectionRAW(section
, True);
303 p
:= InsertSectionRAW(section
);
304 if p
.list
= nil then i
:= 0 else i
:= Length(p
.list
);
305 SetLength(p
.list
, i
+ 1);
306 p
.list
[i
] := Default(TResource
);
307 p
.list
[i
].name
:= name
;
308 p
.list
[i
].pos
:= pos
;
309 p
.list
[i
].csize
:= csize
;
310 p
.list
[i
].usize
:= usize
;
311 p
.list
[i
].comp
:= comp
;
312 p
.list
[i
].chksum
:= crc
;
313 p
.list
[i
].stream
:= nil;
314 Result
:= @p
.list
[i
];
319 function TZIPEditor
.AddAlias(Res
, Alias
: String): Boolean;
321 // Hard-links not supported in ZIP
322 // However, they never created by editor
326 function TZIPEditor
.AddResource(Data
: Pointer; Len
: LongWord; Name
, Section
: String): Boolean;
327 const compress
: Boolean = True;
328 const level
: TCompressionLevel
= TCompressionLevel
.clMax
;
329 var s
: TMemoryStream
; cs
: TCompressionStream
; p
: PResource
;
330 var comp
, crc
: UInt32
;
335 s
:= TMemoryStream
.Create();
337 if compress
and (Len
> 0) then
339 cs
:= TCompressionStream
.Create(level
, s
, True);
341 cs
.WriteBuffer(PByte(Data
)[0], Len
);
343 comp
:= ZIP_COMP_DEFLATE
;
348 if (Len
= 0) or (compress
= False) or (s
.Size
>= Len
) then
350 s
.Seek(0, TSeekOrigin
.soBeginning
);
352 s
.WriteBuffer(PByte(Data
)[0], Len
);
353 comp
:= ZIP_COMP_STORE
;
354 Assert(s
.Size
= Len
);
356 crc
:= crc32(0, nil, 0);
357 crc
:= crc32(crc
, data
, len
);
358 p
:= InsertFileInfo(Section
, Name
, $ffffffff, s
.Size
, Len
, comp
, crc
);
368 function TZIPEditor
.AddResource(FileName
, Name
, Section
: String): Boolean;
369 var s
: TFileStream
; ptr
: PByte;
372 FLastError
:= DFWAD_ERROR_READWAD
;
374 s
:= TFileStream
.Create(FileName
, fmOpenRead
or fmShareDenyWrite
);
378 s
.ReadBuffer(ptr
[0], s
.Size
);
379 Result
:= AddResource(ptr
, s
.Size
, Name
, Section
);
380 if Result
= True then FLastError
:= DFWAD_NOERROR
;
390 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
391 e_WriteLog('DFZIP: AddResource: failed to open file ' + FileName
, MSG_NOTIFY
);
392 FLastError
:= DFWAD_ERROR_CANTOPENWAD
;
397 constructor TZIPEditor
.Create();
401 FLastError
:= DFWAD_NOERROR
;
406 destructor TZIPEditor
.Destroy();
412 procedure TZIPEditor
.FreeWAD();
415 if FSection
<> nil then
417 for i
:= 0 to High(FSection
) do
419 if FSection
[i
].list
<> nil then
421 for j
:= 0 to High(FSection
[i
].list
) do
423 if FSection
[i
].list
[j
].stream
<> nil then
425 FreeAndNil(FSection
[i
].list
[j
].stream
);
428 SetLength(FSection
[i
].list
, 0);
431 SetLength(FSection
, 0);
433 if FStream
<> nil then
437 FLastError
:= DFWAD_NOERROR
;
441 function TZIPEditor
.Preload(p
: PResource
): Boolean;
442 var s
: TMemoryStream
;
447 Result
:= p
.stream
<> nil;
448 if (p
.stream
= nil) and (FStream
<> nil) then
450 s
:= TMemoryStream
.Create();
454 FStream
.Seek(p
.pos
, TSeekOrigin
.soBeginning
);
455 s
.CopyFrom(FStream
, p
.csize
);
457 Assert(s
.Size
= p
.csize
); // wtf, random size if copied zero bytes!
467 procedure TZIPEditor
.CreateImage();
470 if FStream
= nil then
472 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
473 e_WriteLog('DFZIP: CreateImage: File not assigned', MSG_NOTIFY
);
474 FLastError
:= DFWAD_ERROR_WADNOTLOADED
;
476 else if FStream
is TMemoryStream
then
478 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
479 e_WriteLog('DFZIP: CreateImage: Memory stream', MSG_NOTIFY
);
480 FLastError
:= DFWAD_NOERROR
;
484 if FSection
<> nil then
486 for i
:= 0 to High(FSection
) do
488 if FSection
[i
].list
<> nil then
490 for j
:= 0 to High(FSection
[i
].list
) do
492 if Preload(@FSection
[i
].list
[j
]) = False then
494 if gWADEditorLogLevel
>= DFWAD_LOG_WARN
then
495 e_WriteLog('DFZIP: CreateImage: failed to preload resource [' + FSection
[i
].name
+ '][' + FSection
[i
].list
[j
].name
+ ']', MSG_WARNING
);
496 FLastError
:= DFWAD_ERROR_CANTOPENWAD
;
504 FLastError
:= DFWAD_NOERROR
;
508 procedure TZIPEditor
.AddSection(Name
: String);
510 if InsertSection(Name
) = nil then
511 raise Exception
.Create('DFZIP: AddSection[' + Name
+ ']: failed to insert');
514 function TZIPEditor
.HaveResource(Section
, Resource
: String): Boolean;
516 Result
:= FindResource(FindSection(Section
), Resource
) <> nil;
519 function TZIPEditor
.HaveSection(Section
: String): Boolean;
521 Result
:= FindSection(Section
) <> nil;
524 function TZIPEditor
.GetSourceStream(p
: PResource
): TStream
;
528 if p
.stream
<> nil then
531 src
.Seek(0, TSeekOrigin
.soBeginning
);
533 else if FStream
<> nil then
536 src
.Seek(p
.pos
, TSeekOrigin
.soBeginning
);
541 function TZIPEditor
.GetResource(Section
, Resource
: String; var pData
: Pointer; var Len
: Integer): Boolean;
542 var p
: PResource
; ptr
: PByte; src
: TStream
; tmp
: TDecompressionStream
; crc
: UInt32
;
544 FLastError
:= DFWAD_ERROR_CANTOPENWAD
;
548 p
:= FindResource(FindSection(Section
), Resource
);
551 src
:= GetSourceStream(p
);
557 Assert(p
.csize
= p
.usize
);
558 GetMem(ptr
, p
.usize
);
561 src
.ReadBuffer(ptr
[0], p
.usize
);
567 except on e
: EReadError
do
568 if gWADEditorLogLevel
>= DFWAD_LOG_WARN
then
569 e_WriteLog('DFZIP: Failed to read STOREd data, reason: ' + e
.Message, MSG_WARNING
);
574 tmp
:= TDecompressionStream
.Create(src
, True);
576 GetMem(ptr
, p
.usize
);
578 tmp
.ReadBuffer(ptr
[0], p
.usize
);
588 on e
: EStreamError
do
590 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
591 e_WriteLog('DFZIP: Failed to decompress DEFLATEd data, reason: ' + e
.Message, MSG_WARNING
);
596 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
597 e_WriteLog('DFZIP: Unsupported compression method: ' + IntToStr(p
.comp
), MSG_WARNING
);
602 if gWADEditorLogLevel
>= DFWAD_LOG_WARN
then
603 e_WriteLog('DFZIP: No available source for file data', MSG_WARNING
);
604 FLastError
:= DFWAD_ERROR_WADNOTLOADED
;
606 if Result
= True then
608 crc
:= crc32(0, nil, 0);
609 crc
:= crc32(crc
, ptr
, p
.usize
);
610 Result
:= crc
= p
.chksum
;
611 if Result
= True then
615 FLastError
:= DFWAD_NOERROR
;
619 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
620 e_WriteLog('DFZIP: File integrity check failed: expected CRC32 $' + IntToHex(p
.chksum
, 8) + ', calculated CRC32 $' + IntToHex(crc
, 8), MSG_WARNING
);
627 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
628 e_WriteLog('DFZIP: Resource not found', MSG_NOTIFY
);
629 FLastError
:= DFWAD_ERROR_RESOURCENOTFOUND
;
633 function TZIPEditor
.GetResourcesList(Section
: String): SArray
;
634 var p
: PSection
; i
: Integer;
637 p
:= FindSection(Section
);
638 if (p
<> nil) and (p
.list
<> nil) then
640 SetLength(Result
, Length(p
.list
));
641 for i
:= 0 to High(p
.list
) do
643 Result
[i
] := p
.list
[i
].name
;
648 function TZIPEditor
.GetSectionList(): SArray
;
652 if FSection
<> nil then
654 SetLength(Result
, Length(FSection
));
655 for i
:= 0 to High(FSection
) do
657 Result
[i
] := FSection
[i
].name
;
662 procedure TZIPEditor
.ReadLFH(s
: TStream
; fname
: AnsiString; xcsize
, xusize
, xcomp
, xcrc
: UInt32
);
663 var sig
: packed array [0..3] of Char;
664 var va
, vb
, flags
, comp
: UInt16
;
665 var mtime
, crc
, csize
, usize
: UInt32
;
666 var fnlen
, extlen
: UInt16
;
667 var mypos
, datapos
: UInt64;
668 var section
, name
: AnsiString;
672 if mypos
+ 30 <= s
.Size
then
674 s
.ReadBuffer(sig
[0], 4);
675 if sig
= ZIP_SIGN_LFH
then
677 va
:= s
.ReadByte(); // Min Version
678 vb
:= s
.ReadByte(); // Min System
679 flags
:= LEtoN(s
.ReadWord());
680 comp
:= LEtoN(s
.ReadWord());
681 mtime
:= LEtoN(s
.ReadDWord());
682 crc
:= LEtoN(s
.ReadDWord());
683 csize
:= LEtoN(s
.ReadDWord());
684 usize
:= LEtoN(s
.ReadDWord());
685 fnlen
:= LEtoN(s
.ReadWord());
686 extlen
:= LEtoN(s
.ReadWord());
687 datapos
:= s
.Position
+ fnlen
+ extlen
;
688 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
690 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Min Version : ' + IntToStr(va
), MSG_NOTIFY
);
691 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Min System : ' + IntToStr(vb
), MSG_NOTIFY
);
692 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Flags : $' + IntToHex(flags
, 4), MSG_NOTIFY
);
693 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Compression : ' + IntToStr(comp
), MSG_NOTIFY
);
694 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Modification Time : $' + IntToHex(mtime
, 8), MSG_NOTIFY
);
695 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': CRC-32 : $' + IntToHex(crc
, 8), MSG_NOTIFY
);
696 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Compressed size : ' + IntToStr(csize
), MSG_NOTIFY
);
697 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Decompressed size : ' + IntToStr(usize
), MSG_NOTIFY
);
698 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Name Length : ' + IntToStr(fnlen
), MSG_NOTIFY
);
699 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Extension Length : ' + IntToStr(extlen
), MSG_NOTIFY
);
700 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': <DATA OFFSET> : $' + IntToHex(datapos
, 8), MSG_NOTIFY
);
702 if (va
>= 10) and (va
<= ZIP_MAXVERSION
) then
704 if datapos
+ xcsize
<= s
.Size
then
706 ToSectionFile(fname
, section
, name
);
709 p
:= FindSectionRAW(section
, True);
711 p
:= InsertSectionRAW(section
)
715 p
:= InsertFileInfo(section
, name
, datapos
, xcsize
, xusize
, xcomp
, xcrc
);
718 raise Exception
.Create('Failed to register resource [' + fname
+ ']');
721 raise Exception
.Create('Invalid LFH size (corrupted file?)');
725 FLastError
:= DFWAD_ERROR_WRONGVERSION
;
726 raise Exception
.Create('Unsupported CDR version ' + IntToStr(va
) + ', not in range [10..' + IntToStr(ZIP_MAXVERSION
) + ']');
730 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?)');
733 raise Exception
.Create('Invalid LFH size (corrupted file?)');
736 procedure TZIPEditor
.ReadCDR(s
: TStream
; cdrid
: Integer);
737 var sig
: packed array [0..3] of Char;
738 var vva
, vvb
, va
, vb
, flags
, comp
: UInt16
;
739 var mtime
, crc
, csize
, usize
: UInt32
;
740 var fnlen
, extlen
, comlen
, disk
, iattr
: UInt16
;
741 var eattr
, offset
: UInt32
;
742 var mypos
, next
: UInt64;
744 var aname
: AnsiString;
747 s
.ReadBuffer(sig
[0], 4);
748 if sig
= ZIP_SIGN_CDR
then
750 // Valid Central Directory Signature
751 vva
:= s
.ReadByte(); // Writer Version
752 vvb
:= s
.ReadByte(); // Writer System
753 va
:= s
.ReadByte(); // Min Version
754 vb
:= s
.ReadByte(); // Min System
755 flags
:= LEtoN(s
.ReadWord());
756 comp
:= LEtoN(s
.ReadWord());
757 mtime
:= LEtoN(s
.ReadDWord());
758 crc
:= LEtoN(s
.ReadDWord());
759 csize
:= LEtoN(s
.ReadDWord());
760 usize
:= LEtoN(s
.ReadDWord());
761 fnlen
:= LEtoN(s
.ReadWord());
762 extlen
:= LEtoN(s
.ReadWord());
763 comlen
:= LEtoN(s
.ReadWord());
764 disk
:= LEtoN(s
.ReadWord());
765 iattr
:= LEtoN(s
.ReadWord());
766 eattr
:= LEtoN(s
.ReadDWord());
767 offset
:= LEtoN(s
.ReadDWord());
768 next
:= s
.Position
+ fnlen
+ extlen
+ comlen
;
770 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
772 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Writer Version : ' + IntToStr(vva
), MSG_NOTIFY
);
773 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Writer System : ' + IntToStr(vvb
), MSG_NOTIFY
);
774 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Min Version : ' + IntToStr(va
), MSG_NOTIFY
);
775 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Min System : ' + IntToStr(vb
), MSG_NOTIFY
);
776 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Flags : $' + IntToHex(flags
, 4), MSG_NOTIFY
);
777 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Compression : ' + IntToStr(comp
), MSG_NOTIFY
);
778 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Modification Time : $' + IntToHex(mtime
, 8), MSG_NOTIFY
);
779 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': CRC-32 : $' + IntToHex(crc
, 8), MSG_NOTIFY
);
780 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Compressed size : ' + IntToStr(csize
), MSG_NOTIFY
);
781 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Decompressed size : ' + IntToStr(usize
), MSG_NOTIFY
);
782 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Name Length : ' + IntToStr(fnlen
), MSG_NOTIFY
);
783 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Extension Length : ' + IntToStr(extlen
), MSG_NOTIFY
);
784 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Comment Length : ' + IntToStr(comlen
), MSG_NOTIFY
);
785 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Disk : ' + IntToStr(disk
), MSG_NOTIFY
);
786 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Internal Attrib : $' + IntToHex(iattr
, 4), MSG_NOTIFY
);
787 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': External Attrib : $' + IntToHex(eattr
, 8), MSG_NOTIFY
);
788 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': LFH Offset : $' + IntToHex(offset
, 8), MSG_NOTIFY
);
790 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
792 // HACK: Editor and wadcvt for long time sets incorrent flag for UTF-8
793 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
794 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': WADCVT BUG : YES', MSG_NOTIFY
);
795 flags
:= ZIP_UTF8_MASK
;
797 if (va
>= 10) and (va
<= ZIP_MAXVERSION
) then
799 if (flags
and ZIP_ENCRYPTION_MASK
) = 0 then
801 if (csize
<> $ffffffff) and (usize
<> $ffffffff) and (disk
<> $ffff) and (offset
<> $ffffffff) then
805 if (next
<= s
.Size
) and (fnlen
> 0) then
809 if csize
<> usize
then
810 raise Exception
.Create('Compressed size ' + IntToStr(csize
) + ' != Descompressed size ' + IntToStr(usize
) + 'for STORE method (corrupted file?)');
834 raise Exception
.Create('Encrypted archives not supported');
836 raise Exception
.Create('Unknown compression method ' + IntToStr(comp
));
838 GetMem(name
, UInt32(fnlen
) + 1);
840 s
.ReadBuffer(name
[0], fnlen
);
843 if (flags
and ZIP_UTF8_MASK
= 0) and (IsASCII(name
) = False) then
845 // TODO: Detect UTF-8
846 // Older or invalid packers does not set bit 11
847 // Some newer packers may write UTF-8 names into extended data
848 if gWADEditorLogLevel
>= DFWAD_LOG_WARN
then
849 e_WriteLog('ZIP: Non UTF-8 encoded name, threat it as CP1251', MSG_WARNING
);
850 aname
:= win2utf(aname
);
852 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
853 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Name : "' + aname
+ '"', MSG_NOTIFY
);
854 s
.Seek(offset
, TSeekOrigin
.soBeginning
);
855 ReadLFH(s
, aname
, csize
, usize
, comp
, crc
);
857 s
.Seek(next
, TSeekOrigin
.soBeginning
);
862 raise Exception
.Create('Empty files names not supported');
865 raise Exception
.Create('Splitted archives not supported');
869 FLastError
:= DFWAD_ERROR_WRONGVERSION
;
870 raise Exception
.Create('ZIP64 not supported');
875 FLastError
:= DFWAD_ERROR_READWAD
;
876 raise Exception
.Create('Encrypted archives not supported');
881 FLastError
:= DFWAD_ERROR_WRONGVERSION
;
882 raise Exception
.Create('Unsupported CDR version ' + IntToStr(va
) + ', not in range [10..' + IntToStr(ZIP_MAXVERSION
) + ']');
886 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?)');
889 function TZIPEditor
.FindEOCD(s
: TStream
): Boolean;
890 const maxedir
= 20; // end of central directory entry
891 const maxecdir
= maxedir
+ 65536; // + comment
892 var sig
: packed array [0..3] of Char; off
, lim
: Int64;
895 if s
.Size
>= maxedir
then
897 if s
.Size
< maxecdir
then lim
:= s
.Size
else lim
:= maxecdir
;
898 lim
:= lim
- maxedir
;
900 while (off
<= lim
) and (Result
= False) do
902 s
.Seek(s
.Size
- off
, TSeekOrigin
.soBeginning
);
903 s
.ReadBuffer(sig
[0], 4);
904 Result
:= sig
= ZIP_SIGN_EOCD
;
910 procedure TZIPEditor
.ReadEOCD(s
: TStream
);
911 var sig
: packed array [0..3] of Char;
912 var idisk
, ndisk
, nrec
, total
, comlen
: UInt16
;
913 var csize
, cpos
, i
: UInt32
;
916 FLastError
:= DFWAD_ERROR_FILENOTWAD
;
918 s
.ReadBuffer(sig
[0], 4);
919 if (sig
= ZIP_SIGN_LFH
) or (sig
= ZIP_SIGN_EOCD
) then
923 // End of Central Directory found
924 FLastError
:= DFWAD_ERROR_READWAD
;
925 mypos
:= s
.Position
- 4;
926 idisk
:= LEtoN(s
.ReadWord());
927 ndisk
:= LEtoN(s
.ReadWord());
928 nrec
:= LEtoN(s
.ReadWord());
929 total
:= LEtoN(s
.ReadWord());
930 csize
:= LEtoN(s
.ReadDWord());
931 cpos
:= LEtoN(s
.ReadDWord());
932 comlen
:= LEtoN(s
.ReadWord());
933 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
935 e_WriteLog('==============================================', MSG_NOTIFY
);
936 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Disk ID : ' + IntToStr(idisk
), MSG_NOTIFY
);
937 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Disk ID with CD : ' + IntToStr(ndisk
), MSG_NOTIFY
);
938 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Available CDR''s : ' + IntToStr(nrec
), MSG_NOTIFY
);
939 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Total CDR''s : ' + IntToStr(total
), MSG_NOTIFY
);
940 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': CD Length : ' + IntToStr(csize
), MSG_NOTIFY
);
941 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': CD Offset : $' + IntToHex(cpos
, 8), MSG_NOTIFY
);
942 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Comment Length : ' + IntToStr(comlen
), MSG_NOTIFY
);
944 if (idisk
<> $ffff) and (ndisk
<> $ffff) and (nrec
<> $ffff) and (total
<> $ffff) and (csize
<> $ffffffff) and (cpos
<> $ffffffff) then
946 if s
.Position
+ comlen
= s
.Size
then
948 if (idisk
= 0) and (ndisk
= 0) and (nrec
= total
) then
950 if (nrec
* 46 <= csize
) and (UInt64(cpos
) + csize
<= s
.Size
) then
955 s
.Seek(cpos
, TSeekOrigin
.soBeginning
);
958 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
959 e_WriteLog('==============================================', MSG_NOTIFY
);
963 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
964 e_WriteLog('==============================================', MSG_NOTIFY
);
968 raise Exception
.Create('Central Directory too big (corrupted file?)');
971 raise Exception
.Create('Splitted archives not supported');
974 raise Exception
.Create('EOCD too big (corrupted file?)');
977 raise Exception
.Create('ZIP64 not supported');
980 raise Exception
.Create('EOCD not found (corrupted file?)');
983 raise Exception
.Create('Not DFZIP formated file');
986 function TZIPEditor
.ReadFile2(FileName
: String): Boolean;
993 s
:= TFileStream
.Create(FileName
, fmOpenRead
or fmShareDenyWrite
);
997 FLastError
:= DFWAD_NOERROR
;
1006 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
1007 e_WriteLog('ZIP: Failed to read ZIP from file ' + FileName
+ ', reason: ' + e
.Message, MSG_WARNING
);
1012 on e
: EFOpenError
do
1014 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
1015 e_WriteLog('DFZIP: Failed to open file ' + FileName
+ ', reason: ' + e
.Message, MSG_WARNING
);
1016 if FileExists(FileName
) then
1017 FLastError
:= DFWAD_ERROR_CANTOPENWAD
1019 FLastError
:= DFWAD_ERROR_WADNOTFOUND
;
1024 function TZIPEditor
.ReadMemory(Data
: Pointer; Len
: LongWord): Boolean;
1025 var s
: TMemoryStream
;
1030 s
:= TMemoryStream
.Create
;
1033 s
.WriteBuffer(PByte(Data
)[0], Len
);
1034 s
.Seek(0, soBeginning
);
1037 FLastError
:= DFWAD_NOERROR
;
1046 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
1047 e_WriteLog('DFZIP: Failed to read ZIP from memory, reason: ' + e
.Message, MSG_WARNING
);
1053 procedure TZIPEditor
.RemoveResource(Section
, Resource
: String);
1054 var p
: PSection
; i
: Integer;
1056 p
:= FindSection(Section
);
1057 i
:= FindResourceID(p
, Resource
);
1060 if p
.list
[i
].stream
<> nil then
1061 FreeAndNil(p
.list
[i
].stream
);
1062 for i
:= i
+ 1 to High(p
.list
) do
1064 p
.list
[i
- 1] := p
.list
[i
];
1066 SetLength(p
.list
, High(p
.list
));
1070 function GetZIPVersion(const afname
: AnsiString; flags
, comp
: UInt16
): UInt8
;
1073 version
:= 10; // Base version
1075 ZIP_COMP_STORE
: version
:= 10;
1076 ZIP_COMP_SHRUNK
: version
:= 10;
1077 ZIP_COMP_REDUCE1
: version
:= 10;
1078 ZIP_COMP_REDUCE2
: version
:= 10;
1079 ZIP_COMP_REDUCE3
: version
:= 10;
1080 ZIP_COMP_REDUCE4
: version
:= 10;
1081 ZIP_COMP_IMPLODE
: version
:= 10;
1082 ZIP_COMP_TOKENIZED
: version
:= 20;
1083 ZIP_COMP_DEFLATE
: version
:= 20;
1084 ZIP_COMP_DEFLATE64
: version
:= 21;
1085 ZIP_COMP_TERSE1
: version
:= 25; // PKWARE DCL Implode
1086 ZIP_COMP_BZIP2
: version
:= 46;
1087 ZIP_COMP_LZMA
: version
:= 63;
1088 ZIP_COMP_CMPSC
: version
:= 63;
1089 ZIP_COMP_TERSE2
: version
:= 63;
1090 ZIP_COMP_LZ77
: version
:= 63;
1091 ZIP_COMP_ZSTD1
: version
:= 63;
1092 ZIP_COMP_ZSTD2
: version
:= 63;
1093 ZIP_COMP_MP3
: version
:= 63;
1094 ZIP_COMP_XZ
: version
:= 63;
1095 ZIP_COMP_JPEG
: version
:= 63;
1096 ZIP_COMP_WAVPACK
: version
:= 63;
1097 ZIP_COMP_PPMD
: version
:= 63;
1098 ZIP_COMP_AE
: version
:= 63;
1100 if afname
[Length(afname
)] = '/' then
1101 version
:= Max(20, version
); // Folder
1102 if flags
and ZIP_UTF8_MASK
<> 0 then
1103 version
:= Max(63, version
); // UTF-8 name
1107 procedure TZIPEditor
.WriteLFH(s
: TStream
; comp
, crc
, csize
, usize
: UInt32
; const afname
: AnsiString);
1108 var fname
: PChar; version
: UInt8
; fnlen
, flags
: UInt16
; mypos
: UInt64;
1110 mypos
:= s
.Position
;
1111 fname
:= PChar(afname
);
1112 fnlen
:= Length(fname
);
1114 if IsASCII(afname
) = False then
1115 flags
:= flags
or ZIP_UTF8_MASK
;
1116 version
:= GetZIPVersion(afname
, flags
, comp
);
1117 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
1119 e_WriteLog('==============================================', MSG_NOTIFY
);
1120 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Min Version : ' + IntToStr(version
), MSG_NOTIFY
);
1121 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Min System : ' + IntToStr(ZIP_SYSTEM
), MSG_NOTIFY
);
1122 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Flags : $' + IntToHex(flags
, 4), MSG_NOTIFY
);
1123 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Compression : ' + IntToStr(comp
), MSG_NOTIFY
);
1124 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Modification Time : $' + IntToHex(0, 8), MSG_NOTIFY
);
1125 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': CRC-32 : $' + IntToHex(crc
, 8), MSG_NOTIFY
);
1126 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Compressed size : ' + IntToStr(csize
), MSG_NOTIFY
);
1127 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Decompressed size : ' + IntToStr(usize
), MSG_NOTIFY
);
1128 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Name Length : ' + IntToStr(fnlen
), MSG_NOTIFY
);
1129 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Extension Length : ' + IntToStr(0), MSG_NOTIFY
);
1130 e_WriteLog('LFH @' + IntToHex(mypos
, 8) + ': Name : "' + fname
+ '"', MSG_NOTIFY
);
1132 s
.WriteBuffer(ZIP_SIGN_LFH
, 4); // LFH Signature
1133 s
.WriteByte(version
); // Min version
1134 s
.WriteByte(ZIP_SYSTEM
); // System
1135 WriteInt(s
, UInt16(flags
)); // Flags
1136 WriteInt(s
, UInt16(comp
)); // Compression method
1137 WriteInt(s
, UInt32(0)); // Modification time/date
1138 WriteInt(s
, UInt32(crc
)); // CRC-32
1139 WriteInt(s
, UInt32(csize
)); // Compressed size
1140 WriteInt(s
, UInt32(usize
)); // Decompressed size
1141 WriteInt(s
, UInt16(fnlen
)); // Name field length
1142 WriteInt(s
, UInt16(0)); // Extra field length
1143 s
.WriteBuffer(fname
[0], fnlen
); // File Name
1146 procedure TZIPEditor
.WriteCDR(s
: TStream
; comp
, crc
, csize
, usize
, eattr
, offset
: UInt32
; const afname
: AnsiString; cdrid
: Integer);
1147 var fname
: PChar; version
: UInt8
; fnlen
, flags
: UInt16
; mypos
: UInt64;
1149 mypos
:= s
.Position
;
1150 fname
:= PChar(afname
);
1151 fnlen
:= Length(fname
);
1153 if IsASCII(afname
) = False then
1154 flags
:= flags
or ZIP_UTF8_MASK
;
1155 version
:= GetZIPVersion(afname
, flags
, comp
);
1156 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
1158 e_WriteLog('==============================================', MSG_NOTIFY
);
1159 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Writer Version : ' + IntToStr(ZIP_MAXVERSION
), MSG_NOTIFY
);
1160 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Writer System : ' + IntToStr(ZIP_SYSTEM
), MSG_NOTIFY
);
1161 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Min Version : ' + IntToStr(version
), MSG_NOTIFY
);
1162 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Min System : ' + IntToStr(ZIP_SYSTEM
), MSG_NOTIFY
);
1163 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Flags : $' + IntToHex(flags
, 4), MSG_NOTIFY
);
1164 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Compression : ' + IntToStr(comp
), MSG_NOTIFY
);
1165 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Modification Time : $' + IntToHex(0, 8), MSG_NOTIFY
);
1166 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': CRC-32 : $' + IntToHex(crc
, 8), MSG_NOTIFY
);
1167 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Compressed size : ' + IntToStr(csize
), MSG_NOTIFY
);
1168 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Decompressed size : ' + IntToStr(usize
), MSG_NOTIFY
);
1169 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Name Length : ' + IntToStr(fnlen
), MSG_NOTIFY
);
1170 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Extension Length : ' + IntToStr(0), MSG_NOTIFY
);
1171 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Comment Length : ' + IntToStr(0), MSG_NOTIFY
);
1172 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Disk : ' + IntToStr(0), MSG_NOTIFY
);
1173 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Internal Attrib : $' + IntToHex(0, 4), MSG_NOTIFY
);
1174 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': External Attrib : $' + IntToHex(eattr
, 8), MSG_NOTIFY
);
1175 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': LFH Offset : $' + IntToHex(offset
, 8), MSG_NOTIFY
);
1176 e_WriteLog('CDR#' + IntToStr(cdrid
) + ' @' + IntToHex(mypos
, 8) + ': Name : "' + fname
+ '"', MSG_NOTIFY
);
1178 s
.WriteBuffer(ZIP_SIGN_CDR
, 4); // CDR Signature
1179 s
.WriteByte(ZIP_MAXVERSION
); // Used version
1180 s
.WriteByte(ZIP_SYSTEM
); // Used system
1181 s
.WriteByte(version
); // Min version
1182 s
.WriteByte(ZIP_SYSTEM
); // Min system
1183 WriteInt(s
, UInt16(flags
)); // Flags
1184 WriteInt(s
, UInt16(comp
)); // Compression method
1185 WriteInt(s
, UInt32(0)); // Modification time/date
1186 WriteInt(s
, UInt32(crc
)); // CRC-32
1187 WriteInt(s
, UInt32(csize
)); // Compressed size
1188 WriteInt(s
, UInt32(usize
)); // Decompressed size
1189 WriteInt(s
, UInt16(fnlen
)); // Name field length
1190 WriteInt(s
, UInt16(0)); // Extra field length
1191 WriteInt(s
, UInt16(0)); // Comment field length
1192 WriteInt(s
, UInt16(0)); // Disk
1193 WriteInt(s
, UInt16(0)); // Internal attributes
1194 WriteInt(s
, UInt32(eattr
)); // External attributes
1195 WriteInt(s
, UInt32(offset
)); // LFH offset
1196 s
.WriteBuffer(fname
[0], fnlen
); // File Name
1199 procedure TZIPEditor
.SaveToStream(s
: TStream
);
1201 var start
, offset
, loffset
, size
, zcrc
, count
: UInt32
;
1203 var afname
: AnsiString;
1206 // Write LFH headers and data
1207 start
:= s
.Position
;
1208 zcrc
:= crc32(0, nil, 0);
1209 if FSection
<> nil then
1211 for i
:= 0 to High(FSection
) do
1213 if FSection
[i
].list
<> nil then
1215 for j
:= 0 to High(FSection
[i
].list
) do
1217 p
:= @FSection
[i
].list
[j
];
1218 afname
:= GetFileName(FSection
[i
].name
, p
.name
);
1219 WriteLFH(s
, p
.comp
, p
.chksum
, p
.csize
, p
.usize
, afname
);
1220 if p
.stream
<> nil then
1222 Assert(p
.stream
.Size
= p
.csize
);
1223 p
.stream
.SaveToStream(s
);
1225 else if FStream
<> nil then
1227 FStream
.Seek(p
.pos
, TSeekOrigin
.soBeginning
);
1228 s
.CopyFrom(FStream
, p
.csize
);
1232 raise Exception
.Create('No data source available (somethig very wrong)');
1238 afname
:= GetFileName(FSection
[i
].name
, '');
1239 WriteLFH(s
, ZIP_COMP_STORE
, zcrc
, 0, 0, afname
);
1243 // Write CDR headers
1246 offset
:= s
.Position
- start
;
1247 if FSection
<> nil then
1249 for i
:= 0 to High(FSection
) do
1251 if FSection
[i
].list
<> nil then
1253 for j
:= 0 to High(FSection
[i
].list
) do
1255 p
:= @FSection
[i
].list
[j
];
1256 afname
:= GetFileName(FSection
[i
].name
, p
.name
);
1257 WriteCDR(s
, p
.comp
, p
.chksum
, p
.csize
, p
.usize
, $00, loffset
, afname
, i
);
1258 loffset
:= loffset
+ 30 + Length(afname
) + p
.csize
;
1264 afname
:= GetFileName(FSection
[i
].name
, '');
1265 WriteCDR(s
, ZIP_COMP_STORE
, zcrc
, 0, 0, $10, loffset
, afname
, i
);
1266 loffset
:= loffset
+ 30 + Length(afname
) + 0;
1271 Assert(loffset
= offset
);
1272 Assert(count
< $ffff);
1273 size
:= s
.Position
- start
- offset
;
1274 // Write EOCD header
1275 mypos
:= s
.Position
;
1276 if gWADEditorLogLevel
>= DFWAD_LOG_DEBUG
then
1278 e_WriteLog('==============================================', MSG_NOTIFY
);
1279 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Disk ID : ' + IntToStr(0), MSG_NOTIFY
);
1280 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Disk ID with CD : ' + IntToStr(0), MSG_NOTIFY
);
1281 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Available CDR''s : ' + IntToStr(count
), MSG_NOTIFY
);
1282 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Total CDR''s : ' + IntToStr(count
), MSG_NOTIFY
);
1283 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': CD Length : ' + IntToStr(size
), MSG_NOTIFY
);
1284 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': CD Offset : $' + IntToHex(offset
, 8), MSG_NOTIFY
);
1285 e_WriteLog('EOCD @' + IntToHex(mypos
, 8) + ': Comment Length : ' + IntToStr(0), MSG_NOTIFY
);
1286 e_WriteLog('==============================================', MSG_NOTIFY
);
1288 s
.WriteBuffer(ZIP_SIGN_EOCD
, 4); // EOCD Signature
1289 WriteInt(s
, UInt16(0)); // Disk
1290 WriteInt(s
, UInt16(0)); // Num of Disks
1291 WriteInt(s
, UInt16(count
)); // Num of CDRs
1292 WriteInt(s
, UInt16(count
)); // Total CDR entries
1293 WriteInt(s
, UInt32(size
)); // Central Directory size
1294 WriteInt(s
, UInt32(offset
)); // Central Directory offset
1295 WriteInt(s
, UInt16(0)); // Comment field length
1298 procedure TZIPEditor
.SaveTo(FileName
: String);
1302 s
:= TFileStream
.Create(FileName
, fmCreate
);
1311 if gWADEditorLogLevel
>= DFWAD_LOG_INFO
then
1312 e_WriteLog('ZIP: Failed to create file ' + FileName
+ ', reason: ' + e
.Message, MSG_WARNING
);
1318 function TZIPEditor
.GetLastError
: Integer;
1320 Result
:= FLastError
;
1323 function TZIPEditor
.GetLastErrorStr
: String;
1326 DFWAD_NOERROR
: Result
:= '';
1327 DFWAD_ERROR_WADNOTFOUND
: Result
:= 'DFZIP file not found';
1328 DFWAD_ERROR_CANTOPENWAD
: Result
:= 'Can''t open DFZIP file';
1329 DFWAD_ERROR_RESOURCENOTFOUND
: Result
:= 'Resource not found';
1330 DFWAD_ERROR_FILENOTWAD
: Result
:= 'File is not DFZIP';
1331 DFWAD_ERROR_WADNOTLOADED
: Result
:= 'DFZIP file is not loaded';
1332 DFWAD_ERROR_READRESOURCE
: Result
:= 'Read resource error';
1333 DFWAD_ERROR_READWAD
: Result
:= 'Read DFZIP error';
1334 otherwise Result
:= IntToStr(FLastError
);
1338 function TZIPEditor
.GetResourcesCount
: Word;
1342 if FSection
<> nil then
1344 Result
:= Result
+ Length(FSection
);
1345 for i
:= 0 to High(FSection
) do
1346 if FSection
[i
].list
<> nil then
1347 Result
:= Result
+ Length(FSection
[i
].list
);
1351 function TZIPEditor
.GetVersion
: Byte;
1357 gWADEditorFactory
.RegisterEditor('DFZIP', TZIPEditor
);