2
$Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
3
This file is part of the Free Component Library (FCL)
4
Copyright (c) 1999-2000 by the Free Pascal development team
6
See the file COPYING.FPC, included in this distribution,
7
for details about the copyright.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
**********************************************************************}
21
SysUtils,Classes,Contnrs,ZStream;
26
{$ifdef FPC_BIG_ENDIAN}
27
END_OF_CENTRAL_DIR_SIGNATURE = $504B0506;
28
LOCAL_FILE_HEADER_SIGNATURE = $504B0304;
29
CENTRAL_FILE_HEADER_SIGNATURE = $504B0102;
30
{$else FPC_BIG_ENDIAN}
31
END_OF_CENTRAL_DIR_SIGNATURE = $06054B50;
32
LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
33
CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
34
{$endif FPC_BIG_ENDIAN}
37
Local_File_Header_Type = Packed Record
39
Extract_Version_Reqd : Word;
41
Compress_Method : Word;
45
Compressed_Size : LongInt;
46
Uncompressed_Size : LongInt;
47
Filename_Length : Word;
48
Extra_Field_Length : Word;
51
{ Define the Central Directory record types }
53
Central_File_Header_Type = Packed Record
55
MadeBy_Version : Word;
56
Extract_Version_Reqd : Word;
58
Compress_Method : Word;
62
Compressed_Size : LongInt;
63
Uncompressed_Size : LongInt;
64
Filename_Length : Word;
65
Extra_Field_Length : Word;
66
File_Comment_Length : Word;
67
Starting_Disk_Num : Word;
68
Internal_Attributes : Word;
69
External_Attributes : LongInt;
70
Local_Header_Offset : LongInt;
73
End_of_Central_Dir_Type = Packed Record
76
Central_Dir_Start_Disk : Word;
77
Entries_This_Disk : Word;
79
Central_Dir_Size : LongInt;
80
Start_Disk_Offset : LongInt;
81
ZipFile_Comment_Length : Word;
85
Crc_32_Tab : Array[0..255] of LongWord = (
86
$00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3,
87
$0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
88
$1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
89
$136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
90
$3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
91
$35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
92
$26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
93
$2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
94
$76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
95
$7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
96
$6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
97
$65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
98
$4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
99
$4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
100
$5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
101
$5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
102
$edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683,
103
$e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
104
$f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7,
105
$fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
106
$d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
107
$d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79,
108
$cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f,
109
$c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
110
$9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
111
$95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
112
$86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
113
$88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45,
114
$a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db,
115
$aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
116
$bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf,
117
$b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d
122
TZipItem = Class(TObject)
126
DateTime : TDateTime;
130
TProgressEvent = Procedure(Sender : TObject; Const Pct : Double) of object;
131
TOnEndOfFileEvent = Procedure(Sender : TObject; Const Ratio : Double) of object;
132
TOnStartFileEvent = Procedure(Sender : TObject; Const AFileName : String) of object;
137
TCompressor = Class(TObject)
139
FInFile : TStream; { I/O file variables }
141
FCrc32Val : LongWord; { CRC calculation variable }
142
FBufferSize : LongWord;
143
FOnPercent : Integer;
144
FOnProgress : TProgressEvent;
145
Procedure UpdC32(Octet: Byte);
147
Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
148
Procedure Compress; Virtual; Abstract;
149
Class Function ZipID : Word; virtual; Abstract;
150
Property BufferSize : LongWord read FBufferSize;
151
Property OnPercent : Integer Read FOnPercent Write FOnPercent;
152
Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
153
Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
157
TDeCompressor = Class(TObject)
159
FInFile : TStream; { I/O file variables }
161
FCrc32Val : LongWord; { CRC calculation variable }
162
FBufferSize : LongWord;
163
FOnPercent : Integer;
164
FOnProgress : TProgressEvent;
165
Procedure UpdC32(Octet: Byte);
167
Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
168
Procedure DeCompress; Virtual; Abstract;
169
Class Function ZipID : Word; virtual; Abstract;
170
Property BufferSize : LongWord read FBufferSize;
171
Property OnPercent : Integer Read FOnPercent Write FOnPercent;
172
Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
173
Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
183
CodeRec = Packed Record
188
CodeArray = Array[0..TABLESIZE] of CodeRec;
189
TablePtr = ^CodeArray;
191
FreeListPtr = ^FreeListArray;
192
FreeListArray = Array[FIRSTENTRY..TABLESIZE] of Word;
196
TShrinker = Class(TCompressor)
199
MaxInBufIdx : LongWord; { Count of valid chars in input buffer }
200
InputEof : Boolean; { End of file indicator }
201
CodeTable : TablePtr; { Points to code table for LZW compression }
202
FreeList : FreeListPtr; { Table of free code table entries }
203
NextFree : Word; { Index into free list table }
205
ClearList : Array[0..1023] of Byte; { Bit mapped structure used in }
206
{ during adaptive resets }
207
CodeSize : Byte; { Size of codes (in bits) currently being written }
208
MaxCode : Word; { Largest code that can be written in CodeSize bits }
209
InBufIdx, { Points to next char in buffer to be read }
210
OutBufIdx : LongWord; { Points to next free space in output buffer }
211
InBuf, { I/O buffers }
213
FirstCh : Boolean; { Flag indicating the START of a shrink operation }
214
TableFull : Boolean; { Flag indicating a full symbol table }
215
SaveByte : Byte; { Output code buffer }
216
BitsUsed : Byte; { Index into output code buffer }
217
BytesIn : LongInt; { Count of input file bytes processed }
218
BytesOut : LongInt; { Count of output bytes }
220
Procedure FillInputBuffer;
221
Procedure WriteOutputBuffer;
222
Procedure FlushOutput;
223
Procedure PutChar(B : Byte);
224
procedure PutCode(Code : Smallint);
225
Procedure InitializeCodeTable;
226
Procedure Prune(Parent : Word);
227
Procedure Clear_Table;
228
Procedure Table_Add(Prefix : Word; Suffix : Byte);
229
function Table_Lookup(TargetPrefix : Smallint;
231
Out FoundAt : Smallint) : Boolean;
232
Procedure Shrink(Suffix : Smallint);
233
Procedure ProcessLine(Const Source : String);
234
Procedure DoOnProgress(Const Pct : Double); Virtual;
236
Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); override;
237
Destructor Destroy; override;
238
Procedure Compress; override;
239
Class Function ZipID : Word; override;
244
TDeflater = Class(TCompressor)
246
FCompressionLevel: TCompressionlevel;
248
Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
249
Procedure Compress; override;
250
Class Function ZipID : Word; override;
251
Property CompressionLevel : TCompressionlevel Read FCompressionLevel Write FCompressionLevel;
256
TInflater = Class(TDeCompressor)
258
Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
259
Procedure DeCompress; override;
260
Class Function ZipID : Word; override;
265
TZipper = Class(TObject)
269
FFileName : String; { Name of resulting Zip file }
271
FInMemSize : Integer;
272
FOutFile : TFileStream;
273
FInFile : TFileStream; { I/O file variables }
274
LocalHdr : Local_File_Header_Type;
275
CentralHdr : Central_File_Header_Type;
276
EndHdr : End_of_Central_Dir_Type;
277
FOnPercent : LongInt;
278
FOnProgress : TProgressEvent;
279
FOnEndOfFile : TOnEndOfFileEvent;
280
FOnStartFile : TOnStartFileEvent;
282
Procedure OpenOutput;
283
Procedure CloseOutput;
284
Procedure CloseInput;
285
Procedure StartZipFile(Item : TZipItem);
286
Function UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord;AMethod : Word) : Boolean;
287
Procedure BuildZipDirectory;
288
Procedure DoEndOfFile;
289
Procedure ZipOneFile(Item : TZipItem); virtual;
290
Function OpenInput(InFileName : String) : Boolean;
291
Procedure GetFileInfo;
292
Procedure SetBufSize(Value : LongWord);
293
Procedure SetFileName(Value : String);
294
Function CreateCompressor(Item : TZipItem; AinFile,AZipStream : TStream) : TCompressor; virtual;
297
Destructor Destroy;override;
298
Procedure ZipAllFiles; virtual;
299
Procedure ZipFiles(AFileName : String; FileList : TStrings);
302
Property BufferSize : LongWord Read FBufSize Write SetBufSize;
303
Property OnPercent : Integer Read FOnPercent Write FOnPercent;
304
Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
305
Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
306
Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
307
Property FileName : String Read FFileName Write SetFileName;
308
Property Files : TStrings Read FFiles;
309
Property InMemSize : Integer Read FInMemSize Write FInMemSize;
316
TUnZipper = Class(TObject)
318
FUnZipping : Boolean;
320
FFileName : String; { Name of resulting Zip file }
321
FOutputPath : String;
323
FZipEntries : TFPObjectList;
324
FOutFile : TFileStream;
325
FZipFile : TFileStream; { I/O file variables }
326
LocalHdr : Local_File_Header_Type;
327
CentralHdr : Central_File_Header_Type;
328
EndHdr : End_of_Central_Dir_Type;
330
FOnPercent : LongInt;
331
FOnProgress : TProgressEvent;
332
FOnEndOfFile : TOnEndOfFileEvent;
333
FOnStartFile : TOnStartFileEvent;
336
Procedure CloseOutput;
337
Procedure CloseInput;
338
Procedure ReadZipHeader(Item : TZipItem; out ACRC : LongWord;out AMethod : Word);
339
Procedure ReadZipDirectory;
340
Procedure DoEndOfFile;
341
Procedure UnZipOneFile(Item : TZipItem); virtual;
342
Function OpenOutput(OutFileName : String) : Boolean;
343
Procedure SetBufSize(Value : LongWord);
344
Procedure SetFileName(Value : String);
345
Procedure SetOutputPath(Value:String);
346
Function CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor; virtual;
349
Destructor Destroy;override;
350
Procedure UnZipAllFiles; virtual;
351
Procedure UnZipFiles(AFileName : String; FileList : TStrings);
352
Procedure UnZipAllFiles(AFileName : String);
355
Property BufferSize : LongWord Read FBufSize Write SetBufSize;
356
Property OnPercent : Integer Read FOnPercent Write FOnPercent;
357
Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
358
Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
359
Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
360
Property FileName : String Read FFileName Write SetFileName;
361
Property OutputPath : String Read FOutputPath Write SetOutputPath;
362
Property Files : TStrings Read FFiles;
365
EZipError = Class(Exception);
370
SErrBufsizeChange = 'Changing buffer size is not allowed while (un)zipping';
371
SErrFileChange = 'Changing output file name is not allowed while (un)zipping';
372
SErrInvalidCRC = 'Invalid CRC checksum while unzipping %s';
373
SErrCorruptZIP = 'Corrupt ZIP file %s';
374
SErrUnsupportedCompressionFormat = 'Unsupported compression format %d';
376
{ ---------------------------------------------------------------------
378
---------------------------------------------------------------------}
380
Procedure DateTimeToZipDateTime(DT : TDateTime; out ZD,ZT : Word);
383
Y,M,D,H,N,S,MS : Word;
386
DecodeDate(DT,Y,M,D);
387
DecodeTime(DT,H,N,S,MS);
389
ZD:=d+(32*M)+(512*Y);
390
ZT:=(S div 2)+(32*N)+(2048*h);
393
Procedure ZipDateTimeToDateTime(ZD,ZT : Word;out DT : TDateTime);
396
Y,M,D,H,N,S,MS : Word;
400
S:=(ZT and 31) shl 1;
401
N:=(ZT shr 5) and 63;
402
H:=(ZT shr 12) and 31;
404
M:=(ZD shr 5) and 15;
405
Y:=((ZD shr 9) and 127)+1980;
406
DT:=ComposeDateTime(EncodeDate(Y,M,D),EncodeTime(H,N,S,MS));
409
{ ---------------------------------------------------------------------
411
---------------------------------------------------------------------}
414
Procedure TDeCompressor.UpdC32(Octet: Byte);
417
FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
420
constructor TDeCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
424
FBufferSize:=ABufSize;
429
{ ---------------------------------------------------------------------
431
---------------------------------------------------------------------}
434
Procedure TCompressor.UpdC32(Octet: Byte);
437
FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
440
constructor TCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
444
FBufferSize:=ABufSize;
449
{ ---------------------------------------------------------------------
451
---------------------------------------------------------------------}
453
constructor TDeflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
456
FCompressionLevel:=clDefault;
460
procedure TDeflater.Compress;
464
I,Count,NewCount : Integer;
465
C : TCompressionStream;
469
Buf:=GetMem(FBufferSize);
471
C:=TCompressionStream.Create(FCompressionLevel,FOutFile,True);
474
Count:=FInFile.Read(Buf^,FBufferSize);
475
For I:=0 to Count-1 do
478
While (NewCount>0) do
479
NewCount:=NewCount-C.Write(Buf^,NewCount);
487
Crc32Val:=NOT Crc32Val;
490
class function TDeflater.ZipID: Word;
495
{ ---------------------------------------------------------------------
497
---------------------------------------------------------------------}
499
constructor TInflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
505
procedure TInflater.DeCompress;
510
C : TDeCompressionStream;
514
Buf:=GetMem(FBufferSize);
516
C:=TDeCompressionStream.Create(FInFile,True);
519
Count:=C.Read(Buf^,FBufferSize);
520
For I:=0 to Count-1 do
522
FOutFile.Write(Buf^,Count);
530
Crc32Val:=NOT Crc32Val;
533
class function TInflater.ZipID: Word;
539
{ ---------------------------------------------------------------------
541
---------------------------------------------------------------------}
544
DefaultInMemSize = 256*1024; { Files larger than 256k are processed on disk }
545
DefaultBufSize = 16384; { Use 16K file buffers }
546
MINBITS = 9; { Starting code size of 9 bits }
547
MAXBITS = 13; { Maximum code size of 13 bits }
548
SPECIAL = 256; { Special function code }
549
INCSIZE = 1; { Code indicating a jump in code size }
550
CLEARCODE = 2; { Code indicating code table has been cleared }
551
STDATTR = $23; { Standard file attribute for DOS Find First/Next }
553
constructor TShrinker.Create(AInFile, AOutFile : TStream; ABufSize : LongWord);
557
InBuf:=GetMem(FBUFSIZE);
558
OutBuf:=GetMem(FBUFSIZE);
559
CodeTable:=GetMem(SizeOf(CodeTable^));
560
FreeList:=GetMem(SizeOf(FreeList^));
563
destructor TShrinker.Destroy;
572
Procedure TShrinker.Compress;
585
FOnBytes:=Round((FInFile.Size * FOnPercent) / 100);
586
While NOT InputEof do
588
Remaining:=Succ(MaxInBufIdx - InBufIdx);
589
If Remaining>255 then
595
SetLength(OneString,Remaining);
596
Move(InBuf[InBufIdx], OneString[1], Remaining);
597
Inc(InBufIdx, Remaining);
598
ProcessLine(OneString);
601
Crc32Val := NOT Crc32Val;
605
class function TShrinker.ZipID: Word;
611
Procedure TShrinker.DoOnProgress(Const Pct: Double);
614
If Assigned(FOnProgress) then
615
FOnProgress(Self,Pct);
619
Procedure TShrinker.FillInputBuffer;
622
MaxInbufIDx:=FInfile.Read(InBuf[0], FBufSize);
623
If MaxInbufIDx=0 then
631
Procedure TShrinker.WriteOutputBuffer;
633
FOutFile.WriteBuffer(OutBuf[0], OutBufIdx);
638
Procedure TShrinker.PutChar(B : Byte);
641
OutBuf[OutBufIdx] := B;
643
If OutBufIdx>=FBufSize then
648
Procedure TShrinker.FlushOutput;
655
procedure TShrinker.PutCode(Code : Smallint);
669
ACode := Longint(Code);
670
XSize := CodeSize+BitsUsed;
671
ACode := (ACode shl BitsUsed) or SaveByte;
672
while (XSize div 8) > 0 do
675
ACode := ACode shr 8;
679
SaveByte := Lo(ACode);
684
Procedure TShrinker.InitializeCodeTable;
689
For I := 0 to TableSize do
691
With CodeTable^[I] do
701
NextFree := FIRSTENTRY;
706
Procedure TShrinker.Prune(Parent : Word);
709
CurrChild : Smallint;
710
NextSibling : Smallint;
712
CurrChild := CodeTable^[Parent].Child;
713
{ Find first Child that has descendants .. clear any that don't }
714
While (CurrChild <> -1) AND (CodeTable^[CurrChild].Child = -1) do
716
CodeTable^[Parent].Child := CodeTable^[CurrChild].Sibling;
717
CodeTable^[CurrChild].Sibling := -1;
718
{ Turn on ClearList bit to indicate a cleared entry }
719
ClearList[CurrChild DIV 8] := (ClearList[CurrChild DIV 8] OR (1 SHL (CurrChild MOD 8)));
720
CurrChild := CodeTable^[Parent].Child;
722
If CurrChild <> -1 then
723
begin { If there are any children left ...}
725
NextSibling := CodeTable^[CurrChild].Sibling;
726
While NextSibling <> -1 do
728
If CodeTable^[NextSibling].Child = -1 then
730
CodeTable^[CurrChild].Sibling := CodeTable^[NextSibling].Sibling;
731
CodeTable^[NextSibling].Sibling := -1;
732
{ Turn on ClearList bit to indicate a cleared entry }
733
ClearList[NextSibling DIV 8] := (ClearList[NextSibling DIV 8] OR (1 SHL (NextSibling MOD 8)));
734
NextSibling := CodeTable^[CurrChild].Sibling;
738
CurrChild := NextSibling;
740
NextSibling := CodeTable^[CurrChild].Sibling;
747
Procedure TShrinker.Clear_Table;
751
FillChar(ClearList, SizeOf(ClearList), $00);
752
For Node := 0 to 255 do
754
NextFree := Succ(TABLESIZE);
755
For Node := TABLESIZE downto FIRSTENTRY do
757
If (ClearList[Node DIV 8] AND (1 SHL (Node MOD 8))) <> 0 then
760
FreeList^[NextFree] := Node;
763
If NextFree <= TABLESIZE then
768
Procedure TShrinker.Table_Add(Prefix : Word; Suffix : Byte);
772
If NextFree <= TABLESIZE then
774
FreeNode := FreeList^[NextFree];
776
CodeTable^[FreeNode].Child := -1;
777
CodeTable^[FreeNode].Sibling := -1;
778
CodeTable^[FreeNode].Suffix := Suffix;
779
If CodeTable^[Prefix].Child = -1 then
780
CodeTable^[Prefix].Child := FreeNode
783
Prefix := CodeTable^[Prefix].Child;
784
While CodeTable^[Prefix].Sibling <> -1 do
785
Prefix := CodeTable^[Prefix].Sibling;
786
CodeTable^[Prefix].Sibling := FreeNode;
789
if NextFree > TABLESIZE then
793
function TShrinker.Table_Lookup( TargetPrefix : Smallint;
795
Out FoundAt : Smallint ) : Boolean;
797
var TempPrefix : Smallint;
800
TempPrefix := TargetPrefix;
801
Table_lookup := False;
802
if CodeTable^[TempPrefix].Child <> -1 then
804
TempPrefix := CodeTable^[TempPrefix].Child;
806
if CodeTable^[TempPrefix].Suffix = TargetSuffix then
808
Table_lookup := True;
811
if CodeTable^[TempPrefix].Sibling = -1 then
813
TempPrefix := CodeTable^[TempPrefix].Sibling;
817
FoundAt := TempPrefix
822
Procedure TShrinker.Shrink(Suffix : Smallint);
825
LastCode : Smallint = 0;
828
WhereFound : Smallint;
836
MaxCode := (1 SHL CodeSize) - 1;
850
Table_Add(LastCode, Suffix);
855
If Table_Lookup(LastCode, Suffix, WhereFound) then
857
LastCode := WhereFound;
862
Table_Add(LastCode, Suffix);
864
If (FreeList^[NextFree] > MaxCode) and (CodeSize < MaxBits) then
869
MaxCode := (1 SHL CodeSize) -1;
883
Procedure TShrinker.ProcessLine(Const Source : String);
892
For I := 1 to Length(Source) do
895
If (Pred(BytesIn) MOD FOnBytes) = 0 then
896
DoOnProgress(100 * ( BytesIn / FInFile.Size));
897
UpdC32(Ord(Source[I]));
898
Shrink(Ord(Source[I]));
902
{ ---------------------------------------------------------------------
904
---------------------------------------------------------------------}
907
Procedure TZipper.GetFileInfo;
916
For I := 0 to FFiles.Count-1 do
918
If FindFirst(FFiles[I], STDATTR, Info)=0 then
920
NewNode:=TZipItem.Create;
921
NewNode.Path := ExtractFilePath(FFiles[i]);
922
NewNode.Name := Info.Name;
923
NewNode.Size := Info.Size;
924
NewNode.DateTime:=FileDateToDateTime(Info.Time);
925
FFiles.Objects[i]:=NewNode;
932
Procedure TZipper.OpenOutput;
935
FOutFile:=TFileStream.Create(FFileName,fmCreate);
939
Function TZipper.OpenInput(InFileName : String) : Boolean;
942
FInFile:=TFileStream.Create(InFileName,fmOpenRead);
944
If Assigned(FOnStartFile) then
945
FOnStartFile(Self,InFileName);
949
Procedure TZipper.CloseOutput;
952
FreeAndNil(FOutFile);
956
Procedure TZipper.CloseInput;
963
Procedure TZipper.StartZipFile(Item : TZipItem);
966
FillChar(LocalHdr,SizeOf(LocalHdr),0);
969
Signature := LOCAL_FILE_HEADER_SIGNATURE;
970
Extract_Version_Reqd := 10;
972
Compress_Method := 1;
973
DateTimeToZipDateTime(Item.DateTime,Last_Mod_Date,Last_Mod_Time);
975
Compressed_Size := 0;
976
Uncompressed_Size := Item.Size;
977
FileName_Length := 0;
978
Extra_Field_Length := 0;
983
Function TZipper.UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord; AMethod : Word) : Boolean;
985
ZFileName : ShortString;
987
ZFileName:=Item.Path+Item.Name;
990
FileName_Length := Length(ZFileName);
991
Compressed_Size := FZip.Size;
993
Compress_method:=AMethod;
994
Result:=Not (Compressed_Size >= Uncompressed_Size);
997
Compress_Method := 0; { ...change stowage type }
998
Compressed_Size := Uncompressed_Size; { ...update compressed size }
1001
FOutFile.WriteBuffer(LocalHdr,SizeOf(LocalHdr));
1002
FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
1006
Procedure TZipper.BuildZipDirectory;
1011
CenDirPos : LongInt;
1013
ZFileName : ShortString;
1017
CenDirPos := FOutFile.Position;
1018
FOutFile.Seek(0,soFrombeginning); { Rewind output file }
1019
HdrPos := FOutFile.Position;
1020
FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
1022
SetLength(ZFileName,LocalHdr.FileName_Length);
1023
FOutFile.ReadBuffer(ZFileName[1], LocalHdr.FileName_Length);
1024
SavePos := FOutFile.Position;
1025
FillChar(CentralHdr,SizeOf(CentralHdr),0);
1028
Signature := CENTRAL_FILE_HEADER_SIGNATURE;
1029
MadeBy_Version := LocalHdr.Extract_Version_Reqd;
1030
Move(LocalHdr.Extract_Version_Reqd, Extract_Version_Reqd, 26);
1031
Last_Mod_Time:=localHdr.Last_Mod_Time;
1032
Last_Mod_Date:=localHdr.Last_Mod_Date;
1033
File_Comment_Length := 0;
1034
Starting_Disk_Num := 0;
1035
Internal_Attributes := 0;
1036
External_Attributes := faARCHIVE;
1037
Local_Header_Offset := HdrPos;
1039
FOutFile.Seek(0,soFromEnd);
1040
FOutFile.WriteBuffer(CentralHdr,SizeOf(CentralHdr));
1041
FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
1043
FOutFile.Seek(SavePos + LocalHdr.Compressed_Size,soFromBeginning);
1044
HdrPos:=FOutFile.Position;
1045
FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
1046
Until LocalHdr.Signature = CENTRAL_FILE_HEADER_SIGNATURE;
1047
FOutFile.Seek(0,soFromEnd);
1048
FillChar(EndHdr,SizeOf(EndHdr),0);
1051
Signature := END_OF_CENTRAL_DIR_SIGNATURE;
1053
Central_Dir_Start_Disk := 0;
1054
Entries_This_Disk := Entries;
1055
Total_Entries := Entries;
1056
Central_Dir_Size := FOutFile.Size-CenDirPos;
1057
Start_Disk_Offset := CenDirPos;
1058
ZipFile_Comment_Length := 0;
1059
FOutFile.WriteBuffer(EndHdr, SizeOf(EndHdr));
1063
Function TZipper.CreateCompressor(Item : TZipItem; AInFile,AZipStream : TStream) : TCompressor;
1066
Result:=TDeflater.Create(AinFile,AZipStream,FBufSize);
1069
Procedure TZipper.ZipOneFile(Item : TZipItem);
1074
ZipStream : TStream;
1075
TmpFileName : String;
1078
OpenInput(Item.Path+Item.Name);
1081
If (FInfile.Size<=FInMemSize) then
1082
ZipStream:=TMemoryStream.Create
1085
TmpFileName:=ChangeFileExt(FFileName,'.tmp');
1086
ZipStream:=TFileStream.Create(TmpFileName,fmCreate);
1089
With CreateCompressor(Item, FinFile,ZipStream) do
1091
OnProgress:=Self.OnProgress;
1092
OnPercent:=Self.OnPercent;
1099
If UpdateZipHeader(Item,ZipStream,CRC,ZMethod) then
1100
// Compressed file smaller than original file.
1101
FOutFile.CopyFrom(ZipStream,0)
1104
// Original file smaller than compressed file.
1105
FInfile.Seek(0,soFromBeginning);
1106
FOutFile.CopyFrom(FInFile,0);
1110
If (TmpFileName<>'') then
1111
DeleteFile(TmpFileName);
1118
Procedure TZipper.ZipAllFiles;
1124
if FFiles.Count=0 then
1132
For I:=0 to FFiles.Count-1 do
1134
Item:=FFiles.Objects[i] as TZipItem;
1135
if assigned(Item) then
1152
Procedure TZipper.SetBufSize(Value : LongWord);
1156
Raise EZipError.Create(SErrBufsizeChange);
1157
If Value>=DefaultBufSize then
1161
Procedure TZipper.SetFileName(Value : String);
1165
Raise EZipError.Create(SErrFileChange);
1169
Procedure TZipper.ZipFiles(AFileName : String; FileList : TStrings);
1172
FFiles.Assign(FileList);
1173
FFileName:=AFileName;
1177
Procedure TZipper.DoEndOfFile;
1183
If (LocalHdr.Uncompressed_Size>0) then
1184
ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
1187
If Assigned(FOnEndOfFile) then
1188
FOnEndOfFile(Self,ComprPct);
1191
Constructor TZipper.Create;
1194
FBufSize:=DefaultBufSize;
1195
FInMemSize:=DefaultInMemSize;
1196
FFiles:=TStringList.Create;
1197
TStringlist(FFiles).Sorted:=True;
1201
Procedure TZipper.Clear;
1207
For I:=0 to FFiles.Count-1 do
1208
FFiles.Objects[i].Free;
1212
Destructor TZipper.Destroy;
1221
{ ---------------------------------------------------------------------
1223
---------------------------------------------------------------------}
1225
Procedure TUnZipper.OpenInput;
1228
FZipFile:=TFileStream.Create(FFileName,fmOpenRead);
1232
Function TUnZipper.OpenOutput(OutFileName : String) : Boolean;
1235
FOutFile:=TFileStream.Create(OutFileName,fmCreate);
1237
If Assigned(FOnStartFile) then
1238
FOnStartFile(Self,OutFileName);
1242
Procedure TUnZipper.CloseOutput;
1245
FreeAndNil(FOutFile);
1249
Procedure TUnZipper.CloseInput;
1252
FreeAndNil(FZipFile);
1256
Procedure TUnZipper.ReadZipHeader(Item : TZipItem; out ACRC : LongWord; out AMethod : Word);
1259
FZipFile.Seek(Item.HdrPos,soFromBeginning);
1260
FZipFile.ReadBuffer(LocalHdr,SizeOf(LocalHdr));
1263
SetLength(Item.Name,Filename_Length);
1264
FZipFile.ReadBuffer(Item.Name[1],Filename_Length);
1265
FZipFile.Seek(Extra_Field_Length,soCurrent);
1266
Item.Size:=Uncompressed_Size;
1267
ZipDateTimeToDateTime(Last_Mod_Date,Last_Mod_Time,Item.DateTime);
1269
AMethod:=Compress_method;
1274
Procedure TUnZipper.ReadZipDirectory;
1279
CenDirPos : LongInt;
1282
EndHdrPos:=FZipFile.Size-SizeOf(EndHdr);
1283
if EndHdrPos < 0 then
1284
raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
1285
FZipFile.Seek(EndHdrPos,soFromBeginning);
1286
FZipFile.ReadBuffer(EndHdr, SizeOf(EndHdr));
1289
if Signature <> END_OF_CENTRAL_DIR_SIGNATURE then
1290
raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
1291
CenDirPos:=Start_Disk_Offset;
1293
FZipFile.Seek(CenDirPos,soFrombeginning);
1294
for i:=0 to EndHdr.Entries_This_Disk-1 do
1296
FZipFile.ReadBuffer(CentralHdr, SizeOf(CentralHdr));
1299
if Signature<>CENTRAL_FILE_HEADER_SIGNATURE then
1300
raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
1301
NewNode:=TZipItem.Create;
1302
NewNode.HdrPos := Local_Header_Offset;
1303
SetLength(NewNode.Name,Filename_Length);
1304
FZipFile.ReadBuffer(NewNode.Name[1],Filename_Length);
1305
FZipFile.Seek(Extra_Field_Length+File_Comment_Length,soCurrent);
1306
FZipEntries.Add(NewNode);
1311
Function TUnZipper.CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor;
1317
Result:=TInflater.Create(AZipFile,AOutFile,FBufSize);
1319
raise EZipError.CreateFmt(SErrUnsupportedCompressionFormat,[AMethod]);
1323
Procedure TUnZipper.UnZipOneFile(Item : TZipItem);
1329
OutputFileName : string;
1332
ReadZipHeader(Item,CRC,ZMethod);
1333
OutputFileName:=Item.Name;
1334
if FOutputPath<>'' then
1335
OutputFileName:=IncludeTrailingPathDelimiter(FOutputPath)+OutputFileName;
1336
OpenOutput(OutputFileName);
1339
Count:=FOutFile.CopyFrom(FZipFile,LocalHdr.Compressed_Size);
1340
{$warning TODO: Implement CRC Check}
1343
With CreateDecompressor(Item, ZMethod, FZipFile, FOutFile) do
1345
OnProgress:=Self.OnProgress;
1346
OnPercent:=Self.OnPercent;
1348
if CRC<>Crc32Val then
1349
raise EZipError.CreateFmt(SErrInvalidCRC,[Item.Name]);
1359
Procedure TUnZipper.UnZipAllFiles;
1370
For I:=0 to FZipEntries.Count-1 do
1372
Item:=FZipEntries[i] as TZipItem;
1374
(FFiles.IndexOf(Item.Name)<>-1) then
1386
Procedure TUnZipper.SetBufSize(Value : LongWord);
1390
Raise EZipError.Create(SErrBufsizeChange);
1391
If Value>=DefaultBufSize then
1395
Procedure TUnZipper.SetFileName(Value : String);
1399
Raise EZipError.Create(SErrFileChange);
1403
Procedure TUnZipper.SetOutputPath(Value:String);
1406
Raise EZipError.Create(SErrFileChange);
1410
Procedure TUnZipper.UnZipFiles(AFileName : String; FileList : TStrings);
1413
FFiles.Assign(FileList);
1414
FFileName:=AFileName;
1418
Procedure TUnZipper.UnZipAllFiles(AFileName : String);
1421
FFileName:=AFileName;
1425
Procedure TUnZipper.DoEndOfFile;
1431
If (LocalHdr.Uncompressed_Size>0) then
1432
ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
1435
If Assigned(FOnEndOfFile) then
1436
FOnEndOfFile(Self,ComprPct);
1439
Constructor TUnZipper.Create;
1442
FBufSize:=DefaultBufSize;
1443
FFiles:=TStringList.Create;
1444
FZipEntries:=TFPObjectList.Create(true);
1445
TStringlist(FFiles).Sorted:=True;
1449
Procedure TUnZipper.Clear;
1455
For I:=0 to FFiles.Count-1 do
1456
FFiles.Objects[i].Free;
1461
Destructor TUnZipper.Destroy;
1466
FreeAndNil(FZipEntries);