home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2002 September
/
Chip_2002-09_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d2345
/
JBZIP32.ZIP
/
jbZip.pas
< prev
Wrap
Pascal/Delphi Source File
|
2002-05-31
|
122KB
|
3,482 lines
{.$D-,L-}
unit jbZip;
{Components for ZIPing a UNZIPing compatible with PkZip v1.1 }
{Now is they compatible with WinZip and can you use longnames too }
{Based on source (c) A.Byrne by old source }
{Convert to component (c) Jaro Benes }
{All right reserved }
{History and changes: }
{Modification to TP5.5 by Jaro Benes 1993 }
{Modification to TPro V.5.21 by Jaro Benes 1995 }
{Modification to Delphi 1 and changes by Jaro Benes 1996 }
{Encapsulated as component for Delphi 1 by Jaro Benes 1997 }
{Partially portation to Win32 (without assembler) Jaro Benes 1998 }
{Indication errors and connect to TGauge by Jaro Benes 1999 }
{Note J.B. 16.7.1999}
{Components are free using under Delphi 1..5 }
{Portation to Win32 finished, big thanks to Ivan Pavelka }
{1.12.1999 }
{last changes by J.B. }
{31.8.2001 fix getZipList }
{31.5.2002 Fix size of CentralDir for fully compatibility with Winzip }
{for use under Delphi 1 can you use assembler code for packing speed }
{Please, send me any changes and improvement in code copy to my E-mail }
{mailto:JBenes@micrel.cz }
{in code is used my library jbStr (c) Jaro Benes }
interface
uses
SysUtils, WinTypes, WinProcs, Dialogs, Classes;
Type
TZipProgress = procedure (Sender: TObject; AProgress: Smallint) of object;
TZipError = procedure (Sender: TObject; Const ErrorMsg: String) of object;
TZip = class(TComponent)
private
FName:String;
FParam:String;
FOverWrite:Boolean;
FOnProgress:TZipProgress;
FOnError:TZipError;
{ Private declarations }
protected
{ Protected declarations }
Procedure SetFName(Name:String);
Procedure SetParameters(Prm:String);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
Function Execute:Boolean;
Procedure Crunch(PrmLine: String);
published
{ Published declarations }
Property ArcName:String Read FName Write SetFName;
Property Files:String Read FParam Write SetParameters;
Property Overwrite:Boolean Read FOverWrite Write FOverWrite;
Property OnProgress:TZipProgress Read FOnProgress Write FOnProgress;
Property OnError:TZipError Read FOnError Write FOnError;
end {Zip};
TUnZip = class(TComponent)
private
FName:String;
FExtrPath:String;
FParam:String;
FOverWrite:Boolean;
FOnProgress:TZipProgress;
FOnError:TZipError;
{ Private declarations }
protected
{ Protected declarations }
Procedure SetFName(Name:String);
Procedure SetExtrPath(Path:String);
Procedure SetParameters(Prm:String);
Procedure UnCrunch(Const PrmLine: String);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
Function Execute:Boolean;
Procedure GetZipList(Const iFileName:String;Var A:TStringList);
published
{ Published declarations }
Property ArcName:String Read FName Write SetFName;
Property ExtrPath:String Read FExtrPath Write SetExtrPath;
Property Files:String Read FParam Write SetParameters;
Property Overwrite:Boolean Read FOverWrite Write FOverWrite;
Property OnProgress:TZipProgress Read FOnProgress Write FOnProgress;
Property OnError:TZipError Read FOnError Write FOnError;
end {Zip};
procedure Register;
implementation
Uses jbStr;
Const Spacer=#1;
Function SameName(Const N1, N2 : String) : Boolean;
{
Function to compare filespecs.
Wildcards allowed in either name.
Filenames should be compared seperately from filename extensions by using
seperate calls to this function
e.g. FName1.Ex1
FName2.Ex2
are they the same?
they are if SameName(FName1, FName2) AND SameName(Ex1, Ex2)
Wildcards work the way DOS should've let them work (eg. *XX.DAT doesn't
match just any file...only those with 'XX' as the last two characters of
the name portion and 'DAT' as the extension).
This routine calls itself recursively to resolve wildcard matches.
}
Var
P1, P2 : Smallint;
Match : Boolean;
Begin
P1 := 1;
P2 := 1;
Match := True;
If (Length(N1) = 0) And (Length(N2) = 0) Then
Match := True
Else
If Length(N1) = 0 Then
If N2[1] = '*' Then
Match := True
Else
Match := False
Else
If Length(N2) = 0 Then
If N1[1] = '*' Then
Match := True
Else
Match := False;
While (Match = True) And (P1 <= Length(N1)) And (P2 <= Length(N2)) Do
If (N1[P1] = '?') Or (N2[P2] = '?') Then Begin
Inc(P1);
Inc(P2);
End {then}
Else
If N1[P1] = '*' Then Begin
Inc(P1);
If P1 <= Length(N1) Then Begin
While (P2 <= Length(N2)) And Not SameName(Copy(N1,P1,Length(N1)-P1+1), Copy(N2,P2,Length(N2)-P2+1)) Do
Inc(P2);
If P2 > Length(N2) Then
Match := False
Else Begin
P1 := Succ(Length(N1));
P2 := Succ(Length(N2));
End {if};
End {then}
Else
P2 := Succ(Length(N2));
End {then}
Else
If N2[P2] = '*' Then Begin
Inc(P2);
If P2 <= Length(N2) Then Begin
While (P1 <= Length(N1)) And Not SameName(Copy(N1,P1,Length(N1)-P1+1), Copy(N2,P2,Length(N2)-P2+1)) Do
Inc(P1);
If P1 > Length(N1) Then
Match := False
Else Begin
P1 := Succ(Length(N1));
P2 := Succ(Length(N2));
End {if};
End {then}
Else
P1 := Succ(Length(N1));
End {then}
Else
If UpCase(N1[P1]) = UpCase(N2[P2]) Then Begin
Inc(P1);
Inc(P2);
End {then}
Else
Match := False;
If P1 > Length(N1) Then Begin
While (P2 <= Length(N2)) And (N2[P2] = '*') Do
Inc(P2);
If P2 <= Length(N2) Then
Match := False;
End {if};
If P2 > Length(N2) Then Begin
While (P1 <= Length(N1)) And (N1[P1] = '*') Do
Inc(P1);
If P1 <= Length(N1) Then
Match := False;
End {if};
SameName := Match;
End {SameName};
{ ---------------------------------------------------------------------------- }
Function SameFile(Const File1, File2 : String) : Boolean;
Var
Path1, Path2 : String;
Begin
{File1 := ExpandFileName(File1);
File2 := ExpandFileName(File2);}
Path1 := JustPathName(File1);
Path2 := JustPathName(File2);
SameFile := SameName(JustName(File1), JustName(File2)) And
SameName(JustExtension(File1), JustExtension(File2)) And (Path1 = Path2);
End {SameFile};
Const
Crc_32_Tab : Array[0..255] Of {$IfNDef VER130}LongInt{$Else}DWord{$EndIf} = (
$00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3,
$0edb8832, $79dcb8a4, $e0D5e91e, $97D2D988, $09b64c2b, $7eb17cbd, $e7b82D07, $90bf1D91,
$1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47D, $6ddde4eb, $f4D4b551, $83D385c7,
$136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3D63, $8D080df5,
$3b6e20c8, $4c69105e, $D56041e4, $a2677172, $3c03e4D1, $4b04D447, $D20D85fd, $a50ab56b,
$35b5a8fa, $42b2986c, $dbbbc9D6, $acbcf940, $32D86ce3, $45df5c75, $dcd60dcf, $abd13D59,
$26D930ac, $51de003a, $c8D75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
$2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662D3D,
$76dc4190, $01db7106, $98D220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8D433,
$7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086D3D2D, $91646c97, $e6635c01,
$6b6b51f4, $1c6c6162, $856530D8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
$65b0D9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2D49, $8cd37cf3, $fbd44c65,
$4db26158, $3ab551ce, $a3bc0074, $D4bb30e2, $4adfa541, $3dd895D7, $a4D1c46D, $D3D6f4fb,
$4369e96a, $346ed9fc, $ad678846, $da60b8D0, $44042D73, $33031de5, $aa0a4c5f, $dd0D7cc9,
$5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966D409, $ce61e49f,
$5edef90e, $29D9c998, $b0D09822, $c7D7a8b4, $59b33D17, $2eb40D81, $b7bd5c3b, $c0ba6cad,
$edb88320, $9abfb3b6, $03b6e20c, $74b1D29a, $ead54739, $9dd277af, $04db2615, $73dc1683,
$e3630b12, $94643b84, $0D6D6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9D, $0a00ae27, $7D079eb1,
$f00f9344, $8708a3D2, $1e01f268, $6906c2fe, $f762575D, $806567cb, $196c3671, $6e6b06e7,
$fed41b76, $89D32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
$D6D6a3e8, $a1D1937e, $38D8c2c4, $4fdff252, $D1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
$D80D2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79,
$cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f,
$c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2D7ffa7, $b5D0cf31, $2cd99e8b, $5bdeae1D,
$9b64c2b0, $ec63f226, $756aa39c, $026D930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
$95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92D28e9b, $e5D5be0D, $7cdcefb7, $0bdbdf21,
$86D3D2D4, $f1D4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
$88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45,
$a00ae278, $D70dd2ee, $4e048354, $3903b3c2, $a7672661, $D06016f7, $4969474D, $3e6e77db,
$aed16a4a, $D9D65adc, $40df0b66, $37D83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
$bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23D967bf,
$b3667a2e, $c4614ab8, $5D681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2D02ef8D
);
Procedure TZip.Crunch(PrmLine: String);
Const
MaxFilesSpesc = 21; { Maximum souboru pouzito }
BufSize = 10240; { Use 10K file buffers }
MINBITS = 9; { Starting code size of 9 bits }
MAXBITS = 13; { Maximum code size of 13 bits }
TABLESIZE = 8191; { We'll need 4K entries in table }
SPECIAL = 256; { Special function code }
INCSIZE = 1; { Code indicating a jump in code size }
CLEARCODE = 2; { Code indicating code table has been cleared }
FIRSTENTRY = 257; { First available table entry }
UNUSED = -1; { Prefix indicating an unused code table entry }
STDATTR = $23; { Standard file attribute for DOS Find First/Next }
Const
LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
Type
Local_File_Header_Type = packed Record {by IvanP}
Signature : LongInt;
Extract_Version_Reqd : Word;
Bit_Flag : Word;
Compress_Method : Word;
Last_Mod_Time : Word;
Last_Mod_Date : Word;
Crc32 : LongInt;
Compressed_Size : LongInt;
Uncompressed_Size : LongInt;
Filename_Length : Word;
Extra_Field_Length : Word;
End;
{ Define the Central Directory record types }
Const
CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
Type
Central_File_Header_Type = packed Record {by IvanP}
Signature : LongInt;
MadeBy_Version : Word;
Extract_Version_Reqd : Word;
Bit_Flag : Word;
Compress_Method : Word;
Last_Mod_Time : Word;
Last_Mod_Date : Word;
Crc32 : LongInt;
Compressed_Size : LongInt;
Uncompressed_Size : LongInt;
Filename_Length : Word;
Extra_Field_Length : Word;
File_Comment_Length : Word;
Starting_Disk_Num : Word;
Internal_Attributes : Word;
External_Attributes : LongInt;
Local_Header_Offset : LongInt;
End;
Const
END_OF_CENTRAL_DIR_SIGNATURE = $06054B50;
Type
End_of_Central_Dir_Type = packed Record
Signature : LongInt;
Disk_Number : Word;
Central_Dir_Start_Disk : Word;
Entries_This_Disk : Word;
Total_Entries : Word;
Central_Dir_Size : LongInt;
Start_Disk_Offset : LongInt;
ZipFile_Comment_Length : Word;
End;
Type
{ Define data types needed to implement a code table for LZW compression }
CodeRec = Record{ Code Table record format... }
Child : Smallint; { Addr of 1st suffix for this prefix }
Sibling : Smallint; { Addr of next suffix in chain }
Suffix : Byte; { Suffix character }
End {CodeRec};
CodeArray = Array[0..TABLESIZE] Of CodeRec; { Define the code table }
TablePtr = ^CodeArray; { Allocate dynamically }
{ Define data types needed to implement a free node list }
FreeListPtr = ^FreeListArray;
FreeListArray = Array[FIRSTENTRY..TABLESIZE] Of Word;
{ Define data types needed to implement input and output file buffers }
BufArray = Array[1..BufSize] Of Byte;
BufPtr = ^BufArray;
{ Define the structure of a DOS Disk Transfer Area (DTA) }
DTARec = Packed Record {J.B.}
Filler : Array[1..21] Of Byte;
Attr : Byte;
Time : Word;
Date : Word;
Size : LongInt;
Name : String[{$IfNDef VER80}128{$Else}12{$EndIf}];
End {DtaRec};
//type
//TFileName = string;
//TSearchRec = record
// Time: Integer;
// Size: Integer;
// Attr: Integer;
// Name: TFileName;
// ExcludeAttr: Integer;
// FindHandle: THandle;
// FindData: TWin32FindData;
//end;
{ Define data types needed to implement a sorted singly linked list to }
{ hold the names of all files to be compressed }
NameStr = String[80]; {12} {IvanP}
PathStr = String[80]; {64} {IvanP}
NodePtr = ^NameList;
NameList = Record { Linked list node structure... }
Path : PathStr; { Path of input file }
Name : NameStr; { Name of input file }
Size : LongInt; { Size in bytes of input file }
Date : Word; { Date stamp of input file }
Time : Word; { Time stamp of input file }
Next : NodePtr; { Next node in linked list }
End {NameList};
Type TNameFileSpec = Array[1..20] Of String;
Var
OutFileName : String; { Name of resulting Zip file }
InFile, { I/O file variables }
OutFile : File;
InBuf, { I/O buffers }
OutBuf : BufPtr;
InBufIdx, { Points to next char in buffer to be read }
OutBufIdx : Word; { Points to next free space in output buffer }
MaxInBufIdx : integer; { Count of valid chars in input buffer }
InputEof : Boolean; { End of file indicator }
Crc32Val : LongInt; { CRC calculation variable }
CodeTable : TablePtr; { Points to code table for LZW compression }
FreeList : FreeListPtr; { Table of free code table entries }
NextFree : Word; { Index into free list table }
ClearList : Array[0..1023] Of Byte; { Bit mapped structure used in }
{ during adaptive resets }
CodeSize : Byte; { Size of codes (in bits) currently being written }
MaxCode : Word; { Largest code that can be written in CodeSize bits }
LocalHdr : Local_File_Header_Type;
LocalHdrOfs : LongInt; { Offset within output file of the local header }
CentralHdr : Central_File_Header_Type;
EndHdr : End_of_Central_Dir_Type;
FirstCh : Boolean; { Flag indicating the START of a shrink operation }
TableFull : Boolean; { Flag indicating a full symbol table }
SaveByte : Byte; { Output code buffer }
BitsUsed : Byte; { Index into output code buffer }
BytesIn : LongInt; { Count of input file bytes processed }
BytesOut : LongInt; { Count of output bytes }
ListHead : NodePtr; { Pointer to head of linked list }
TenPercent : LongInt;
Procedure Fatal(Msg : String);
Begin
If AsSigned(FOnError) Then FOnError(Self,Msg)
Else
MessageDlg(Msg, mtWarning, [mbOk], 0);
End;
{ --------------------------------------------------------------------------- }
Procedure AddToList(PathSpec : PathStr; DTA : DTARec);
{ Add an entry to a linked list of filenames to be crunched. Maintain }
{ sorted order (standard ASCII collating sequence) by filename }
Var
//MemError : Word;
NewNode : NodePtr;
Done : Boolean;
ListNode : NodePtr;
Begin
{ Allocate a new node }
try
GetMem(NewNode, SizeOf(NewNode^))
except
on EOutOfMemory do
Begin
Fatal('Not enough memory to process all filenames!');
Exit
End;
end;
// Odstranil IvanP
// If MemAvail>SizeOf(NewNode^) Then GetMem(NewNode, SizeOf(NewNode^))
// Else Begin
// Fatal('Nenφ dodstatek pam∞ti ke zpracovßnφ vÜech soubor∙!');
// Exit
// End;
{MemError := Malloc(NewNode, SizeOf(NewNode^));
If MemError <> 0 then Fatal('Not enough memory to process all filenames!');}
{ Populate the fields of the new node }
NewNode^.Path := PathSpec;
NewNode^.Name := DTA.Name;
NewNode^.Size := DTA.Size;
NewNode^.Date := DTA.Date;
NewNode^.Time := DTA.Time;
NewNode^.Next := Nil;
{ Find the proper location in the list at which to insert the new node }
If ListHead = Nil
Then ListHead := NewNode
Else
If DTA.Name < ListHead^.Name
Then
Begin // zalozi se novy zaznam
NewNode^.Next := ListHead;
ListHead := NewNode;
End {then}
Else
Begin
Done := False;
ListNode := ListHead;
While Not Done Do
Begin
If ListNode^.Name = DTA.Name
Then
Begin
ListNode^.Path := PathSpec;
FreeMem(NewNode, SizeOf(NewNode^));
{MemError := Dalloc(NewNode);}
Done := True;
End {then}
Else
If ListNode^.Next = Nil
Then
Begin
ListNode^.Next := NewNode;
Done := True;
End {then}
Else
If ListNode^.Next^.Name > DTA.Name Then Begin
NewNode^.Next := ListNode^.Next;
ListNode^.Next := NewNode;
Done := True;
End {then}
Else
ListNode := ListNode^.Next;
End {while};
End {if};
End {AddToList};
{ --------------------------------------------------------------------------- }
// procedura pridana IvanP
procedure SRecToDTARec(SearchRec:TSearchRec;var DosDTA:DTARec);
Var vx:Array [1..2] of Word;
Begin
Move(SearchRec.Time,vx,SizeOf(SearchRec.Time));
DosDTA.Attr:= SearchRec.Attr AND $FF;
DosDTA.Time:= vx[1]{SearchRec.Time};//datum a cas je slozeny, jmeno klame
DosDTA.Date:= vx[2]{0}; //musi se rozlozit J.B.
DosDTA.Size:= (SearchRec.FindData.nFileSizeHigh shl 8) +
(SearchRec.FindData.nFileSizeLow);
DosDTA.Name:= SearchRec.Name;
// Showmessage(format('Attr: %d'#13 +
// 'time: %d'#13 +
// 'date: %d'#13 +
// 'size: %d'#13 +
// 'name: %s',[DosDTA.Attr,DosDTA.Time,DosDTA.Date,
// DosDTA.Size,DosDTA.Name]));
End;
Procedure GetNames(MaxSpecs:Word;Var InFileSpecs:TNameFileSpec);
{ Expand input file specifications. Store the name of each file to be }
{ compressed in a sorted, singly linked list }
Var
DosDTA : DTARec;
ActRec : TSearchRec;
I : Word;
InPath : String;
Begin
ListHead := Nil;
For I := 1 To MaxSpecs Do Begin { Loop through all input file specs }
InPath := AddLastChar('\',StrUpCase(JustPathName(InFileSpecs[I])));
If SysUtils.FindFirst(InFileSpecs[I], STDATTR, ActRec) = 0 Then
Repeat
If (Not SameFile(ExpandFileName(InPath + ActRec.Name), ExpandFileName(OutFileName)))
then
// nahradil IvanP
Begin
SRecToDTARec(ActRec,DosDTA);
// ShowMessage(InPath);
AddToList(InPath, DosDTA);
end;
// AddToList(InPath, DTARec(ActRec));
Until SysUtils.FindNext(ActRec)<>0;
Sysutils.FindClose(ActRec);
End {for};
End {GetNames};
{ --------------------------------------------------------------------------- }
Function ParamCheck(Const ParamLine:String; OverWrite:Boolean) : Boolean;
{Verify all command line parameters}
Var
SearchBuf : TSearchRec;
//OutPath : String; {asi cesta pro extrekci }
//CH : Char;
I : Word;
InFileSpecs : TNameFileSpec; {Input file specifications}
MaxSpecs : Word; {Total number of filespecs to be Zipped}
Begin
ParamCheck := False;
I:=WordCount(ParamLine,[Spacer]);
If I < 1 Then Exit;
{Syntax;}
If I > MaxFilesSpesc Then Begin
Fatal('P°φliÜ mnoho vstupnφch parametr∙ !');
Exit;
End {if};
OutFileName := ExtractWord(1,ParamLine,[Spacer]);
If JustExtension(OutFileName)='' Then
OutFileName:=ForceExtension(OutFileName,'ZIP');
If Sysutils.FindFirst(OutFileName, STDATTR, SearchBuf)=0 Then Begin
If Not OverWrite Then Exit;
End {if};
Sysutils.FindClose(SearchBuf);
If WordCount(ParamLine,[Spacer]) = 1 Then Begin
InFileSpecs[1] := '*.*';
MaxSpecs := 1;
End {then}
Else
For I := 2 To WordCount(ParamLine,[Spacer]) Do Begin
// Showmessage('Infile: '+ ExtractWord(I,ParamLine,[Spacer]));
InFilespecs[Pred(I)] := Trim(ExtractWord(I,ParamLine,[Spacer]));
MaxSpecs := Pred(I);
End {for};
GetNames(MaxSpecs,InFileSpecs);
ParamCheck:=True;
End {ParamCheck};
{ --------------------------------------------------------------------------- }
{ Running 32 Bit CRC update function }
{ --------------------------------------------------------------------------- }
Function UpdC32(Octet: Byte; Crc: LongInt) : LongInt;
Var
L : LongInt;
W : Array[1..4] Of Byte Absolute L;
Begin
UpdC32 := Crc_32_Tab[Byte(Crc XOr LongInt(Octet))] XOr ((Crc ShR 8) And $00FFFFFF);
End {UpdC32};
{ --------------------------------------------------------------------------- }
{ I/O Support routines }
{ --------------------------------------------------------------------------- }
Function GetBuffers:Boolean;
{ Allocate Input and Output buffers }
//Var
// MemError : Word;
Begin
Result:=False;
{MemError := Malloc(InBuf, Sizeof(InBuf^));}
// predelal IvanP
try
GetMem(InBuf, SizeOf(InBuf^))
except
on EOutOfMemory do
Exit;
end;
// If MemAvail>SizeOf(InBuf^)
// Then GetMem(InBuf, SizeOf(InBuf^))
// Else Exit;
{MemError := Malloc(OutBuf, SizeOf(OutBuf^));}
try
GetMem(OutBuf, SizeOf(OutBuf^))
except
on EOutOfMemory do
Begin
FreeMem(InBuf, SizeOf(InBuf^));
Exit
End;
end;
// If MemAvail>SizeOf(OutBuf^) Then GetMem(OutBuf, SizeOf(OutBuf^))
// Else Begin
// FreeMem(InBuf, SizeOf(InBuf^));
// Exit
// End;
Result := True;
End {GetBuffers};
{ --------------------------------------------------------------------------- }
Procedure DropBuffers;
{ Deallocate input and output buffers }
//Var
// MemError : Word;
Begin
{MemError := Dalloc(InBuf);}
FreeMem(InBuf, SizeOf(InBuf^));
{MemError := Dalloc(OutBuf);}
FreeMem(OutBuf, SizeOf(OutBuf^))
end {DropBuffers};
Procedure OpenOutput;
Var
RC : Smallint;
Begin
AssignFile(OutFile, OutFileName);
FileMode := 66; {fmShareDenyNone or fmOpenReadWrite}
{$I-} Rewrite(OutFile, 1); {$I+}
RC := IOResult;
If RC <> 0 Then
Fatal('Chyba p°i otevφtßnφ souboru');
End {OpenOutput};
{ --------------------------------------------------------------------------- }
Function OpenInput(InFileName : String) : Boolean;
//Var
// RC : Smallint;
Begin
AssignFile(InFile, InFileName);
FileMode := 64;{fmShareDenyNone or fmOpenRead}
{$I-} Reset(InFile, 1); {$I+}
OpenInput := (IOResult = 0);
End {OpenInput};
{ --------------------------------------------------------------------------- }
Procedure CloseOutput;
Var
RC : Smallint;
Begin
{$I-} CloseFile(OutFile) {$I+};
RC := IOResult;
End {CloseOutput};
{ --------------------------------------------------------------------------- }
Procedure CloseInput;
Var
RC : Smallint;
Begin
{$I-} CloseFile(InFile) {$I+};
RC := IOResult;
End {CloseInput};
{ --------------------------------------------------------------------------- }
Procedure Read_Block;
{ Read a "block" of data into our our input buffer }
Begin
BlockRead(InFile, InBuf^[1], SizeOf(InBuf^), MaxInBufIdx);
If MaxInBufIdx = 0 Then
InputEof := True
Else
InputEOF := False;
InBufIdx := 1;
End {Read_Block};
{ --------------------------------------------------------------------------- }
Procedure Write_Block;
{ Write a block of data from the output buffer to our output file }
Begin
BlockWrite(OutFile, OutBuf^[1], Pred(OutBufIdx));
OutBufIdx := 1;
End {Write_Block};
{ --------------------------------------------------------------------------- }
Procedure PutChar(B : Byte);
{ Put one character into our output buffer }
Begin
OutBuf^[OutBufIdx] := B;
Inc(OutBufIdx);
If OutBufIdx > SizeOf(OutBuf^) Then
Write_Block;
Inc(BytesOut);
End {PutChar};
{ --------------------------------------------------------------------------- }
Procedure FlushOutput;
{ Write any data sitting in our output buffer to the output file }
Begin
If OutBufIdx > 1 Then
Write_Block;
End {FlushOutput};
{--------------------------------------------------------------------------- }
Procedure PutCodePas(Code:Smallint);
{kod pro nahradu assembleru}
Var Mask:Word;
Agent:Byte;
Var iSaveByte,
iBitsUsed:Byte;
iCodeSize:Byte;
//B:Byte;
Begin
iSaveByte:=SaveByte;
iBitsUsed:=BitsUsed;
iCodeSize:=CodeSize;
If Code=-1 Then Begin
If iBitsUsed<>0 Then PutChar(SaveByte)
End
Else Begin
Mask:=$0001;{%00000000000000001}
Repeat
Agent:=0;
If (Code And Mask)<>0 Then Inc(Agent);
Mask := Mask Shl 1;{%0000000000000010}
Agent := Agent Shl iBitsUsed;
Inc(iBitsUsed);
iSaveByte:= iSaveByte Or Agent;
If iBitsUsed=8 Then Begin
PutChar(iSaveByte);
iSaveByte:=0;
Agent:=0;
iBitsUsed:=0;
End;
Dec(iCodeSize);
Until iCodeSize=0;
SaveByte := iSaveByte;
BitsUsed := iBitsUsed;
End;
End;
Procedure PutCode(Code : Smallint);
{ Assemble coded bytes for output }
{$IFDEF WIN32}
Begin
PutCodePas(Code);
{$ELSE}
Var
PutCharAddr : Pointer;
Begin
PutCharAddr := @PutChar;
Inline(
{; Register useage:}
{;}
{; AX - holds Code}
{; BX - BH is a work register, BL holds SaveByte}
{; CX - holds our loop counter CodeSize}
{; DX - holds BitsUsed}
{;}
$8B/$46/<Code/ { mov ax,[bp+<Code]}
$31/$DB/ { xor bx,bx}
$89/$D9/ { mov cx,bx}
$89/$DA/ { mov dx,bx}
$8A/$1E/>SaveByte/ { mov bl,[>SaveByte]}
$8A/$0E/>CodeSize/ { mov cl,[>CodeSize]}
$8A/$16/>BitsUsed/ { mov dl,[>BitsUsed]}
$3D/$FF/$FF/ { cmp ax,-1 ;Any work to do?}
$75/$0D/ { jnz Repeat ;Yup, go do it}
$80/$FA/$00/ { cmp dl,0 ;Any leftovers?}
$74/$3A/ { jz AllDone ;Nope, we're done}
$53/ { push bx ;Yup...push leftovers}
$0E/ { push cs}
$FF/$96/>PutCharAddr/ { call [bp+>PutCharAddr] ; and send to output}
$EB/$32/ { jmp short AllDone}
{;}
$30/$FF/ {Repeat: xor bh,bh ;Zero out BH}
$D1/$D8/ { rcr ax,1 ;Get low order bit into CY flag}
$73/$02/ { jnc SkipBit ;Was the bit set?}
$FE/$C7/ { inc bh ;Yes, xfer to BH}
$87/$D1/ {SkipBit: xchg cx,dx ;Swap CX & DX}
$D2/$E7/ { shl bh,cl ;Shift bit over}
$87/$D1/ { xchg cx,dx ;Put CX & DX back where they were}
$42/ { inc dx ;Bump count of bit positions used}
$08/$FB/ { or bl,bh ;Transfer bit to output byte (SaveByte)}
$83/$FA/$08/ { cmp dx,8 ;Full byte yet?}
$72/$12/ { jb GetNext ;Nope, go get more code bits}
$50/ { push ax ;Yup, save regs in preparation}
$53/ { push bx ; for call to output routine}
$51/ { push cx}
$52/ { push dx}
$53/ { push bx ;Push byte to output onto stack}
$0E/ { push cs}
$FF/$96/>PutCharAddr/ { call [bp+>PutCharAddr] ; and call the output routine}
$5A/ { pop dx}
$59/ { pop cx}
$5B/ { pop bx}
$58/ { pop ax}
$31/$DB/ { xor bx,bx ;Prepare SaveByte for next byte}
$89/$DA/ { mov dx,bx ;Set BitsUsed to zero}
$E2/$D6/ {GetNext: loop Repeat ;Repeat for all code bits}
{;}
$88/$1E/>SaveByte/ { mov [>SaveByte],bl ;Put SaveByte and BitsUsed}
$88/$16/>BitsUsed); { mov [>BitsUsed],dl ; back in memory}
{;}
{AllDone:}
{$ENDIF}
End {Putcode};
{ --------------------------------------------------------------------------- }
{ The following routines are used to allocate, initialize, and de-allocate }
{ various dynamic memory structures used by the LZW compression algorithm }
{ --------------------------------------------------------------------------- }
Function Build_Data_Structures:Boolean;
//Var
// Code : Word;
Begin
Result := False;
// predelal IvanP
try
GetMem(CodeTable, SizeOf(CodeTable^))
except
on EOutOfMemory do
begin
MessageDlg('Not enough memory to allocate LZW data structures!',
mtError,[mbAbort], 0);
Exit;
end;
end;
try
GetMem(FreeList, SizeOf(FreeList^ ))
except
on EOutOfMemory do
begin
MessageDlg('Not enough memory to allocate LZW data structures!',
mtError,[mbAbort], 0);
FreeMem(CodeTable, SizeOf(CodeTable^));
Exit;
end;
end;
// If MemAvail>SizeOf(CodeTable^) Then GetMem(CodeTable, SizeOf(CodeTable^))
// Else Exit;
// If MemAvail>SizeOf(FreeList^ ) Then GetMem(FreeList, SizeOf(FreeList^ ))
// Else Begin
// FreeMem(CodeTable, SizeOf(CodeTable^));
// Exit
// End;
{Code := Malloc(CodeTable, SizeOf(CodeTable^)) OR
Malloc(FreeList, SizeOf(FreeList^ ));
If Code <> 0 then
Fatal('Not enough memory to allocate LZW data structures!');}
Result := True;
End {Build_Data_Structures};
{ --------------------------------------------------------------------------- }
Procedure Destroy_Data_Structures;
//Var
// Code : Word;
Begin
{Code := Dalloc(CodeTable);}
FreeMem(CodeTable, SizeOf(CodeTable^));
{Code := Dalloc(FreeList);}
FreeMem(FreeList, SizeOf(FreeList^ ));
end {Destroy_Data_Structures};
Procedure Initialize_Data_Structures;
Var
I : Word;
Begin
For I := 0 To TableSize Do Begin
With CodeTable^[I] Do Begin
Child := -1;
Sibling := -1;
If I <= 255 Then
Suffix := I;
End {with};
If I >= 257 Then
FreeList^[I] := I;
End {for};
NextFree := FIRSTENTRY;
TableFull := False;
End {Initialize_Data_Structures};
{ --------------------------------------------------------------------------- }
{ The following routines handle manipulation of the LZW Code Table }
{ --------------------------------------------------------------------------- }
Procedure Prune(Parent : Word);
{ Prune leaves from a subtree - Note: this is a recursive procedure }
Var
CurrChild : Smallint;
NextSibling : Smallint;
Begin
CurrChild := CodeTable^[Parent].Child;
{ Find first Child that has descendants .. clear any that don't }
While (CurrChild <> -1) And (CodeTable^[CurrChild].Child = -1) Do Begin
CodeTable^[Parent].Child := CodeTable^[CurrChild].Sibling;
CodeTable^[CurrChild].Sibling := -1;
{ Turn on ClearList bit to indicate a cleared entry }
ClearList[CurrChild Div 8] := (ClearList[CurrChild Div 8] Or (1 ShL (CurrChild Mod 8)));
CurrChild := CodeTable^[Parent].Child;
End {while};
If CurrChild <> -1 Then Begin { If there are any children left ...}
Prune(CurrChild);
NextSibling := CodeTable^[CurrChild].Sibling;
While NextSibling <> -1 Do Begin
If CodeTable^[NextSibling].Child = -1 Then Begin
CodeTable^[CurrChild].Sibling := CodeTable^[NextSibling].Sibling;
CodeTable^[NextSibling].Sibling := -1;
{ Turn on ClearList bit to indicate a cleared entry }
ClearList[NextSibling Div 8] := (ClearList[NextSibling Div 8] Or (1 ShL (NextSibling Mod 8)));
NextSibling := CodeTable^[CurrChild].Sibling;
End {then}
Else Begin
CurrChild := NextSibling;
Prune(CurrChild);
NextSibling := CodeTable^[CurrChild].Sibling;
End {if};
End {while};
End {if};
End {Prune};
{ --------------------------------------------------------------------------- }
Procedure Clear_Table;
Var
Node : Word;
Begin
FillChar(ClearList, SizeOf(ClearList), $00);
{ Remove all leaf nodes by recursively pruning subtrees}
For Node := 0 To 255 Do
Prune(Node);
{ Next, re-initialize our list of free table entries }
NextFree := Succ(TABLESIZE);
For Node := TABLESIZE Downto FIRSTENTRY Do Begin
If (ClearList[Node Div 8] And (1 ShL (Node Mod 8))) <> 0 Then Begin
Dec(NextFree);
FreeList^[NextFree] := Node;
End {if};
End {for};
If NextFree <= TABLESIZE Then
TableFull := False;
End {Clear_Table};
{ --------------------------------------------------------------------------- }
Procedure Table_Add(Prefix : Word; Suffix : Byte);
Var
FreeNode : Word;
Begin
If NextFree <= TABLESIZE Then Begin
FreeNode := FreeList^[NextFree];
Inc(NextFree);
CodeTable^[FreeNode].Child := -1;
CodeTable^[FreeNode].Sibling := -1;
CodeTable^[FreeNode].Suffix := Suffix;
If CodeTable^[Prefix].Child = -1 Then
CodeTable^[Prefix].Child := FreeNode
Else Begin
Prefix := CodeTable^[Prefix].Child;
While CodeTable^[Prefix].Sibling <> -1 Do
Prefix := CodeTable^[Prefix].Sibling;
CodeTable^[Prefix].Sibling := FreeNode;
End {if};
End {if};
If NextFree > TABLESIZE Then
TableFull := True;
End {Table_Add};
{ --------------------------------------------------------------------------- }
{$IFDEF WIN32}
Function Table_Lookup(TargetPrefix:Smallint;TargetSuffix:Byte;
Var FoundAt:Smallint):Boolean;
Label Loop;
Var TempChild:Smallint;
Begin
Table_Lookup := False;
FoundAt:=-1;
If CodeTable^[TargetPrefix].Child=-1 Then Exit;{not found}
TempChild:=CodeTable^[TargetPrefix].Child;
Loop:
With CodeTable^[TempChild] Do Begin
If Suffix=TargetSuffix Then Begin {found}
FoundAt:=TempChild;
Table_Lookup:=True;
Exit
End;
If Sibling=-1 Then Exit;{not found}
TempChild:=Sibling;
End;
GoTo Loop;
End;
{$ELSE}
Function Table_Lookup( TargetPrefix : Smallint;
TargetSuffix : Byte;
Var FoundAt : Smallint ) : Boolean;
{ --------------------------------------------------------------------------- }
{ Search for a Prefix:Suffix pair in our Symbol table. If found, return the }
{ index value where found. If not found, return FALSE and set the VAR parm }
{ FoundAt to -1. }
{ --------------------------------------------------------------------------- }
Begin
Inline(
{;}
{; Lookup an entry in the Hash Table. If found, return TRUE and set the VAR}
{; parameter FoundAt with the index of the entry at which the match was found.}
{; If not found, return FALSE and plug a -1 into the FoundAt var.}
{;}
{;}
{; Register usage:}
{; AX - varies BL - holds target suffix character}
{; BH - If search fails, determines how to}
{; add the new entry}
{; CX - not used DX - holds size of 1 table entry (5)}
{; DI - varies SI - holds offset of 1st table entry}
{; ES - seg addr of hash table DS - program's data segment}
{;}
{;}
$8A/$5E/<TargetSuffix/ { mov byte bl,[bp+<TargetSuffix] ;Target Suffix character}
$8B/$46/<TargetPrefix/ { mov word ax,[bp+<TargetPrefix] ;Index into table}
$BA/$05/$00/ { mov dx,5 ;5 byte table entries}
$F7/$E2/ { mul dx ;AX now an offset into table}
$C4/$3E/>CodeTable/ { les di,[>CodeTable] ;Hash table address}
$89/$FE/ { mov si,di ;save offset in SI}
$01/$C7/ { add di,ax ;es:di points to table entry}
{;}
$B7/$00/ { mov bh,0 ;Chain empty flag (0=empty)}
$26/$83/$3D/$FF/ { es: cmp word [di],-1 ;Anything on the chain?}
$74/$33/ { jz NotFound ;Nope, search fails}
$B7/$01/ { mov bh,1 ;Chain empty flag (1=not empty)}
{;}
$26/$8B/$05/ { es: mov word ax,[di] ;Get index of 1st entry in chain}
$89/$46/<TargetPrefix/ {Loop: mov word [bp+<TargetPrefix],ax ;Save index for later}
$BA/$05/$00/ { mov dx,5}
$F7/$E2/ { mul dx ;convert index to offset}
$89/$F7/ { mov di,si ;es:di points to start of table}
$01/$C7/ { add di,ax ;es:di points to table entry}
{;}
$26/$3A/$5D/$04/ { es: cmp byte bl,[di+4] ;match on suffix?}
$74/$0D/ { jz Found ;Yup, search succeeds}
{;}
$26/$83/$7D/$02/$FF/ { es: cmp word [di+2],-1 ;any more entries in chain?}
$74/$15/ { jz NotFound ;nope, search fails}
{;}
$26/$8B/$45/$02/ { es: mov word ax,[di+2] ;get index of next chain entry}
$EB/$E1/ { jmp short Loop ; and keep searching}
{;}
$C6/$46/$FF/$01/ {Found: mov byte [bp-1],1 ;return TRUE}
$C4/$7E/<FoundAt/ { les di,[bp+<FoundAt] ;get address of Var parameter}
$8B/$46/<TargetPrefix/ { mov word ax,[bp+<TargetPrefix] ;get index of entry where found}
$26/$89/$05/ { es: mov [di],ax ;and store it}
$EB/$0C/ { jmp short Done}
{;}
$C6/$46/$FF/$00/ {NotFound: mov byte [bp-1],0 ;return FALSE}
$C4/$7E/<FoundAt/ { les di,[bp+<FoundAt] ;get address of Var parameter}
$26/$C7/$05/$FF/$FF); { es: mov word [di],-1 ;and store a -1 in it}
{;}
{Done:}
{;}
End {Table_Lookup};
{$ENDIF}
{ --------------------------------------------------------------------------- }
{ These routines build the Header structures for the ZIP file }
{ --------------------------------------------------------------------------- }
Procedure Begin_ZIP(ListPtr : NodePtr);
{ Write a dummy header to the zip. Include as much info as is currently }
{ known (we'll come back and fill in the rest later...) }
Begin
LocalHdrOfs := FilePos(OutFile); { Save file position for later use }
With LocalHdr Do Begin
Signature := LOCAL_FILE_HEADER_SIGNATURE;
Extract_Version_Reqd := 10;
Bit_Flag := 0;
Compress_Method := 1;
Last_Mod_Time := ListPtr^.Time;
Last_Mod_Date := ListPtr^.Date;
Crc32 := 0;
Compressed_Size := 0;
Uncompressed_Size := ListPtr^.Size;
FileName_Length := Length(ListPtr^.Name);
Extra_Field_Length := 0;
End {with};
Move(LocalHdr, OutBuf^, SizeOf(LocalHdr)); { Put header into output buffer }
OutBufIdx := Succ(SizeOf(LocalHdr)); {...adjust buffer index accordingly }
Move(ListPtr^.Name[1], OutBuf^[OutBufIdx], Length(ListPtr^.Name));
Inc(OutBufIdx, Length(ListPtr^.Name));
FlushOutput; { Write it now }
End {Begin_ZIP};
{ --------------------------------------------------------------------------- }
Procedure Update_ZIP_Header(ListPtr : NodePtr);
{ Update the zip's local header with information that we now possess. Check }
{ to make sure that our shrinker actually produced a smaller file. If not, }
{ scrap the shrunk data, modify the local header accordingly, and just copy }
{ the input file to the output file (compress method 0 - Storing). }
Var
EndPos : LongInt;
Redo : Boolean;
Begin
Redo := False; { Set REDO flag to false }
EndPos := FilePos(OutFile); { Save current file position }
Seek(OutFile, LocalHdrOfs); { Rewind back to file header }
With LocalHdr Do Begin
{ Update compressed size field }
Compressed_Size := EndPos - LocalHdrOfs - SizeOf(LocalHdr) - Filename_Length;
Crc32 := Crc32Val; { Update CRC value }
{ Have we compressed the file? }
Redo := (Compressed_Size >= Uncompressed_Size);
If Redo Then Begin { No... }
Compress_Method := 0; { ...change stowage type }
Compressed_Size := Uncompressed_Size; { ...update compressed size }
End {if};
End {with};
Move(LocalHdr, OutBuf^, SizeOf(LocalHdr)); { Put header into output buffer }
OutBufIdx := Succ(SizeOf(LocalHdr)); {...adjust buffer index accordingly }
Move(ListPtr^.Name[1], OutBuf^[OutBufIdx], Length(ListPtr^.Name));
Inc(OutBufIdx, Length(ListPtr^.Name));
FlushOutput; { Write it now }
If Redo Then Begin
{ If compression didn't make a smaller file, then ... }
Seek(InFile, 0); { Rewind the input file }
InputEof := False; { Reset EOF indicator }
Read_Block; { Prime the input buffer }
While Not InputEof Do Begin { Copy input to output }
BlockWrite(OutFile, InBuf^, MaxInBufIdx);
Read_Block;
End {while};
Truncate(Outfile); { Truncate output file }
End {then}
Else Begin
{ Compression DID make a smaller file ... }
Seek(OutFile, FileSize(OutFile)); { Move output file pos back to eof }
End {if};
End {Update_ZIP_Header};
{ --------------------------------------------------------------------------- }
Procedure Build_Central_Dir;
{ Revisit each local file header to build the Central Directory. When done, }
{ build the End of Central Directory record. }
Var
BytesRead : Integer;
SavePos : LongInt;
HdrPos : LongInt;
CenDirPos : LongInt;
pom,
Entries : Word;
FileName : String;
pomStr : array[0..255] of char; {integer}
tpmCDSize : LongInt;
Begin
tpmCDSize := 0;
Entries := 0;
CenDirPos := FilePos(Outfile);
Seek(OutFile, 0); { Rewind output file }
HdrPos := FilePos(OutFile);
BlockRead(OutFile, LocalHdr, SizeOf(LocalHdr), BytesRead);
Repeat
BlockRead(OutFile, pomstr, LocalHdr.FileName_Length, BytesRead);
pom:=LocalHdr.FileName_Length;
if pom>255 then pom:=255;
pomstr[pom]:=#0;
FileName:=Strpas(pomstr);
// BlockRead(OutFile, FileName[1], LocalHdr.FileName_Length, BytesRead);
// FileName[0] := Chr(LocalHdr.FileName_Length);
// pom:=LocalHdr.FileName_Length;
// if pom >= 256 then pom:=255;
// SetLength(FileName,pom);
SavePos := FilePos(OutFile);
With CentralHdr Do Begin
Signature := CENTRAL_FILE_HEADER_SIGNATURE;
MadeBy_Version := LocalHdr.Extract_Version_Reqd;
Move(LocalHdr.Extract_Version_Reqd, Extract_Version_Reqd, 26);
File_Comment_Length := 0;
Starting_Disk_Num := 0;
Internal_Attributes := 0;
External_Attributes := faARCHIVE;
Local_Header_Offset := HdrPos;
Seek(OutFile, FileSize(OutFile));
BlockWrite(Outfile, CentralHdr, SizeOf(CentralHdr));
BlockWrite(OutFile, FileName[1], Length(FileName));
Inc(tpmCDSize,SizeOf(CentralHdr)+Length(FileName));
Inc(Entries);
End {with};
Seek(OutFile, SavePos + LocalHdr.Compressed_Size);
HdrPos := FilePos(OutFile);
BlockRead(OutFile, LocalHdr, SizeOf(LocalHdr), BytesRead);
Until LocalHdr.Signature = CENTRAL_FILE_HEADER_SIGNATURE;
Seek(OutFile, FileSize(OutFile));
With EndHdr Do Begin
Signature := END_OF_CENTRAL_DIR_SIGNATURE;
Disk_Number := 0;
Central_Dir_Start_Disk := 0;
Entries_This_Disk := Entries;
Total_Entries := Entries;
Central_Dir_Size := {CenDirPos - FileSize(OutFile)}tpmCDSize;{fix 31.5.2002 by J.B.}
Start_Disk_Offset := CenDirPos;
ZipFile_Comment_Length := 0;
BlockWrite(Outfile, EndHdr, SizeOf(EndHdr));
End {with};
End {Build_Central_Dir};
{ --------------------------------------------------------------------------- }
{ The actual Crunching algorithm }
{ --------------------------------------------------------------------------- }
Procedure Shrink(Suffix : Smallint);
Const
LastCode : Smallint = 0; { Typed constant, so value retained across calls }
Var
WhereFound : Smallint;
// CrunchRatio : LongInt;
Begin
If FirstCh Then Begin { If just getting started ... }
SaveByte := $00; { Initialize our output code buffer }
BitsUsed := 0;
CodeSize := MINBITS; { Initialize code size to minimum }
MaxCode := (1 ShL CodeSize) - 1;
LastCode := Suffix; { get first character from input, }
FirstCh := False; { and reset the first char flag. }
End {then}
Else Begin
If Suffix <> -1 Then Begin { If there's work to do ... }
If TableFull Then Begin
{ Ok, lets clear the code table (adaptive reset) }
Putcode(LastCode);
PutCode(SPECIAL);
Putcode(CLEARCODE);
Clear_Table;
Table_Add(LastCode, Suffix);
LastCode := Suffix;
End {then}
Else Begin
If Table_Lookup(LastCode, Suffix, WhereFound) Then Begin
{ If LastCode:Suffix pair is found in the code table, then ... }
{ ... set LastCode to the entry where the pair is located }
LastCode := WhereFound;
End {then}
Else Begin
{ Not in table }
PutCode(LastCode); { Write current LastCode code }
Table_Add(LastCode, Suffix); { Attempt to add to code table }
LastCode := Suffix; { Reset LastCode code for new char }
If (FreeList^[NextFree] > MaxCode) And (CodeSize < MaxBits) Then Begin
{ Time to increase the code size and change the max. code }
PutCode(SPECIAL);
PutCode(INCSIZE);
Inc(CodeSize);
MaxCode := (1 ShL CodeSize) -1;
End {if};
End {if};
End {if};
End {then}
Else Begin { Nothing to crunch...must be EOF on input }
PutCode(LastCode); { Write last prefix code }
PutCode(-1); { Tell putcode to flush remaining bits }
FlushOutput; { Flush our output buffer }
End {if};
End {if};
End {Crunch};
{ --------------------------------------------------------------------------- }
Procedure Process_Input(Source : String);
Var
I : Word;
PctDone : Smallint;
// Smsg : String;
Begin
If Source = '' Then
Shrink(-1)
Else
For I := 1 To Length(Source) Do Begin
Inc(BytesIn);
{If (Pred(BytesIn) Mod TenPercent) = 0 Then }Begin
PctDone := Round( 100 * ( BytesIn / FileSize(InFile)));
{nove hlaseni stavu}
{Smsg := Turn(PadCh (CharStr (' ', (100-PctDone+10) DIV 10), ' ', 10));}
If AsSigned(FOnProgress) Then
FOnProgress(Self,PctDone);
End {if};
CRC32Val := UpdC32(Ord(Source[I]), CRC32Val);
Shrink(Ord(Source[I]));
End {for};
End {Process_Input};
{ --------------------------------------------------------------------------- }
{ This routine handles processing for one input file }
{ --------------------------------------------------------------------------- }
Procedure Process_One_File;
Var
OneString : {$IfNDef Win32}ShortString{$Else}String{$EndIf};
Remaining : Word;
pom : array[0..255] of char; {integer}
Begin
Read_Block; { Prime the input buffer }
FirstCh := True; { 1st character flag for Crunch procedure }
Crc32Val := $FFFFFFFF;
TenPercent := FileSize(InFile) Div 10;
While Not InputEof Do Begin
Remaining := Succ(MaxInBufIdx - InBufIdx);
If Remaining > 255
Then Remaining := 255;
If Remaining = 0
Then Read_Block
Else
Begin
// predelal IvanP
(*
Move(InBuf^[InBufIdx], pom, Remaining);
pom[remaining]:=#0;
OneString:=StrPas(pom);
*)
OneString:=Space(Remaining);
Move(InBuf^[InBufIdx], OneString[1], Remaining);
//Setlength(OneString,Remaining);
//
Inc(InBufIdx, Remaining);
Process_Input(OneString);
End {if};
End {while};
Crc32Val := Not Crc32Val;
Process_Input(''); { This forces EOF processing }
End {Process_One_File};
{ --------------------------------------------------------------------------- }
Procedure Process_All_Files;
Var
// InPath : String;
ComprPct : Word;
ListNode : NodePtr;
Begin
If ListHead = Nil Then Begin
Fatal('Nejsou ₧ßdnΘ soubory k smrsknutφ !');
Exit
End {if};
OpenOutput;
ListNode := ListHead;
While ListNode <> Nil Do
Begin
// Showmessage('concate '+ListNode^.Path+', '+ ListNode^.Name + ' .'); {*****}
If OpenInput(Concat(ListNode^.Path, ListNode^.Name))
Then
Begin
BytesIn := 1; BytesOut := 1;
TenPercent := FileSize(InFile) Div 10;
Initialize_Data_Structures;
Begin_ZIP(ListNode);
Process_One_File;
Update_ZIP_Header(ListNode);
CloseInput;
If LocalHdr.Uncompressed_Size > 0
Then
ComprPct := Round((100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size)
Else
ComprPct := 0;
End {then}
Else
Fatal('Nejde otev°φt '+ListNode^.Name+'. P°ekraΦuji ...');
ListNode := ListNode^.Next;
End {while};
Build_Central_Dir;
CloseOutput;
End {Process_All_Files};
{ Main Program (driver) }
Begin
If ParamCheck(StrUpCase(PrmLine),True) Then Begin
If Not GetBuffers Then Exit; { Allocate input and output buffers ...}
If Not Build_Data_Structures Then Exit; { ... and other data structures required }
Try
Process_All_Files; { Crunch the file }
Finally
DropBuffers; { Be polite and de-allocate Buffer memory and }
Destroy_Data_Structures; { other allocated data structures }
End;
End {if};
End;
Procedure TUnZip.UnCrunch(Const PrmLine: String);
{Const SignWork:String[10]='Rozbaluji';}
Const
MAXNAMES = 20;
GloMem:Pointer=Nil;
Var
InFileSpecs : Array [1..MAXNAMES] Of String; { Input file specifications }
MaxSpecs : Word; { Total number of entries in InFileSpecs array }
OutPath : String; { Output path specification }
TenPercent : LongInt;
{ Define ZIP file header types }
Const
LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
Type
Local_File_Header_Type = packed Record
{ Signature : LongInt; }
Extract_Version_Reqd : Word;
Bit_Flag : Word;
Compress_Method : Word;
Last_Mod_Time : Word;
Last_Mod_Date : Word;
Crc32 : LongInt;
Compressed_Size : LongInt;
Uncompressed_Size : LongInt;
Filename_Length : Word;
Extra_Field_Length : Word;
End;
Const
CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
Type
Central_File_Header_Type = packed Record
{ Signature : LongInt; }
MadeBy_Version : Word;
Extract_Version_Reqd : Word;
Bit_Flag : Word;
Compress_Method : Word;
Last_Mod_Time : Word;
Last_Mod_Date : Word;
Crc32 : LongInt;
Compressed_Size : LongInt;
Uncompressed_Size : LongInt;
Filename_Length : Word;
Extra_Field_Length : Word;
File_Comment_Length : Word;
Starting_Disk_Num : Word;
Internal_Attributes : Word;
External_Attributes : LongInt;
Local_Header_Offset : LongInt;
End;
Const
END_OF_CENTRAL_DIR_SIGNATURE = $06054B50;
Type
End_of_Central_Dir_Type = packed Record
{ Signature : LongInt; }
Disk_Number : Word;
Central_Dir_Start_Disk : Word;
Entries_This_Disk : Word;
Total_Entries : Word;
Central_Dir_Size : LongInt;
Start_Disk_Offset : LongInt;
ZipFile_Comment_Length : Word;
End;
Const
BufSize = 8192; { Size of buffers for I/O }
Type
BufPtr = ^BufType;
BufType = Array [1..BufSize] Of Byte;
Var
ZipName : String; { Name of Zip file to be processed }
ZipFile : File; { Zip file variable }
EndFile : Boolean; { End of file indicator for ZipFile }
ZipBuf : BufPtr; { Input buffer for ZipFile }
ZipPtr : Word; { Index for ZipFile input buffer }
ZipCount : integer; { Count of bytes in ZipFile input buffer }
ExtFile : File; { Output file variable }
ExtBuf : BufPtr; { Output buffer for ExtFile }
ExtPtr : Word; { Index for ExtFile output buffer }
ExtCount : LongInt; { Count of characters written to output }
LocalHdr : Local_File_Header_Type; { Storage for a local file hdr }
Hdr_FileName : String;
Hdr_ExtraField : String;
Hdr_Comment : String;
Crc32Val : LongInt; { Running CRC (32 bit) value }
Bytes_To_Go : LongInt; { Bytes left to process in compressed file }
{ Stuff needed for unSHRINKing }
Const
MINCODESIZE = 9;
MAXCODESIZE = 13;
SPECIAL = 256;
FIRSTFREE = 257;
LZW_TABLE_SIZE = (1 ShL MAXCODESIZE) - 1; { 0..8191 }
LZW_STACK_SIZE = (1 ShL MAXCODESIZE) - 1; { 0..8191 }
Type
LZW_Table_Rec = Record
Prefix : Smallint;
Suffix : Byte;
ChildCount : Word; { If ChildCount = 0 then leaf node }
End;
LZW_Table_Ptr = ^LZW_Table_Type;
LZW_Table_Type = Array [0..LZW_TABLE_SIZE] Of LZW_Table_Rec;
FreeListPtr = ^FreeListArray;
FreeListArray = Array [FIRSTFREE..LZW_TABLE_SIZE] Of Word;
StackPtr = ^StackType;
StackType = Array [0..LZW_STACK_SIZE] Of Word;
Var
LZW_Table : LZW_Table_Ptr; { Code table for LZW decoding }
FreeList : FreeListPtr; { List of free table entries }
NextFree : Word; { Index for free list array }
{ FreeList^[NextFree] always contains the }
{ index of the next available entry in }
{ the LZW Prefix:Suffix table (LZW_Table^) }
LZW_Stack : StackPtr; { A stack used to build decoded strings }
StackIdx : Word; { Stack array index variable }
{ StackIdx always points to the next }
{ available entry in the stack }
SaveByte : Byte; { Our input code buffer - 1 byte long }
BitsLeft : Byte; { Unprocessed bits in the input code buffer }
FirstCh : Boolean; { Flag indicating first char being processed }
{ Stuff needed for unREDUCEing }
Const
MAXDICTSIZE = 8192; { size will be 4096 for unreduce and either }
{ 4096 or 8192 for exploding }
Type
FollowerSet = Record
SetSize : Word;
FSet : Array [0..31] Of Byte;
End;
FollowerPtr = ^FollowerArray;
FollowerArray = Array [0..255] Of FollowerSet;
DictPtr = ^DictArray;
DictArray = Array [0..MAXDICTSIZE - 1] Of Byte;
Var
Followers : FollowerPtr;
Dictionary : DictPtr; { The sliding dictionary }
DictIdx : Word; { Always points to next pos. to be filled }
DictSize : Word; { size (in bytes) of sliding dictionary }
State : Byte;
Len : Word;
V : Byte;
{ Stuff needed for unIMPLODEing }
Const
MAX_SF_TREE_SIZE = 511;
LITERAL_TREE_ROOT = 511;
DISTANCE_TREE_ROOT = 127;
LENGTH_TREE_ROOT = 127;
Type
{ The following structures are used to define the Shannon-Fano trees used }
{ in decoding an imploded file }
SF_Node = Record
LChild : Smallint;
RChild : Smallint;
End;
SF_Literal_Ptr = ^SF_Literal_Array;
SF_Distance_Ptr = ^SF_Distance_Array;
SF_Length_Ptr = ^SF_Length_Array;
SF_Literal_Array = Array [0..LITERAL_TREE_ROOT] Of SF_Node;
SF_Distance_Array = Array [0..DISTANCE_TREE_ROOT] Of SF_Node;
SF_Length_Array = Array [0..LENGTH_TREE_ROOT] Of SF_Node;
{ The Shannon-Fano data that is stored at the beginning of the compressed }
{ file is itself compressed. The following structures are used to decode }
{ that data and build the required Shannon-Fano trees }
SF_BuildRec = Record
Len : Byte;
Val : Byte;
Code : Word;
End;
SF_BuildPtr = ^SF_BuildArray;
SF_BuildArray = Array [0..255] Of SF_BuildRec;
Var
SF_Literal : SF_Literal_Ptr; { These are the 3 Shannon-Fano }
SF_Distance : SF_Distance_Ptr; { trees that are used to implode }
SF_Length : SF_Length_Ptr; { a file. }
NextFreeLiteral : Word; { Free node pointers used while trees }
NextFreeLength : Word; { are being constructed }
NextFreeDistance : Word;
SF_Build : SF_BuildPtr; { Array used in building the }
{ Shannon-Fano trees needed to }
{ decode the imploded file }
SF_Build_Idx : Byte; { Index var for SF_Build array }
NumOfTrees : Byte; { the # of SF trees needed (2 or 3) }
MinMatchLen : Byte; { minimum dictionary match length (2 or 3)}
{ --------------------------------------------------------------------------- }
Procedure Abort (Msg : String);
Begin
If AsSigned(FOnError) Then FOnError(Self,Msg)
Else
MessageDlg(Msg, mtWarning, [mbOk], 0);
End {Abort} ;
{ --------------------------------------------------------------------------- }
Procedure Syntax;
Begin
Abort('ChybnΘ volßnφ, chybnΘ parametry')
End;
{ --------------------------------------------------------------------------- }
Function HexLInt (L : LongInt) : String;
Type
HexType = Array [0..15] Of Char;
Const
HexChar : HexType =
('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
Begin
Result := HexChar [ (L And $F0000000) ShR 28] +
HexChar [ (L And $0F000000) ShR 24] +
HexChar [ (L And $00F00000) ShR 20] +
HexChar [ (L And $000F0000) ShR 16] +
HexChar [ (L And $0000F000) ShR 12] +
HexChar [ (L And $00000F00) ShR 8] +
HexChar [ (L And $000000F0) ShR 4] +
HexChar [ (L And $0000000F) ] +
'h';
End {HexLInt} ;
{ --------------------------------------------------------------------------- }
Function IO_Test : Boolean;
Var
ErrorCode : Word;
// CodeStr : String;
Ok : Boolean;
Begin
Ok := True;
ErrorCode := IOResult;
If ErrorCode <> 0 Then Begin
Ok := False;
Case ErrorCode Of
2 : Abort('Soubor nebyl nalezen');
3 : Abort('Cesta nenφ platnß/nebyla nalezana');
5 : Abort('Chyba souboru/cesty/syntaxe');
101 : Abort('Disk je pln²');
Else Abort('Vstupn∞/v²stupnφ chyba '+Long2Str(ErrorCode));
End {Case} ;
End {if} ;
Result := Ok;
End {IO_Test} ;
{ --------------------------------------------------------------------------- }
Function Load_Parms (PrmLine: String):Boolean;
Var
I : Word;
Name : String;
SearchRec : TSearchRec;
Begin
Result:=False; {prvni parametr je zipname}
I := WordCount (PrmLine, [Spacer] ) {ParamCount} ;
If I < 1
Then
Begin
Syntax;
Exit;
End;
ZipName := ExtractWord (1, PrmLine, [Spacer] ) {ParamStr(1)} ;
ZipName := StrUpCase(ZipName);
{FOR I := 1 TO LENGTH (ZipName) DO
ZipName [I] := UPCASE (ZipName [I] );}
If Pos ('.', ZipName) = 0 Then ZipName := ZipName + '.ZIP';
MaxSpecs := 0;
OutPath := '';
I := 1;
// Showmessage(Prmline); {*****}
While I < WordCount (PrmLine, [Spacer] ) {ParamCount} Do
Begin
Inc (I);
Name := Trim(ExtractWord (I, PrmLine, [Spacer] )) {ParamStr(I)} ;
If Name [Length (Name) ] = '\' Then Delete (Name, Length (Name), 1);
{U adresß°e se odstranφ koncovΘ lomφtko}
{Change specification for disk only example A:\ or Z:\ on entry JB}
If (I=2) And ((Name[1] In ['A'..'Z']) And (Name[2]=':')
And (Length(Name)=2)) {JB}
Then OutPath:=Name+'\' {JB}
// pokud je jen jmeno disku, lomφtko se naopak doplnφ a definuje se OutPath.
Else //jinak se zjistuje, zda jde o soubor nebo adresar
Begin {JB}
If SysUtils.FindFirst (Name, faDirectory, SearchRec)=0
Then //jmeno bylo spravne nalezeno jako adresar
Begin { outpath spec? }
If (SearchRec. Attr And faDirectory) <> 0
Then // je to adresar
Begin { yup }
OutPath := Name;
If OutPath [Length (OutPath) ] <> '\'
Then OutPath := OutPath + '\';
End {then}
Else // je to soubor
Begin
If MaxSpecs < MAXNAMES
Then
Begin // tak jej ulozim do InFileSpecs
Inc (MaxSpecs); {sem se uklßdajφ dalÜφ parametry}
InFileSpecs [MaxSpecs] := Name;
End {if} ;
End {if} ;
End {then}
Else // jmeno nebylo spravne nalezeno jako adresar
Begin
If MaxSpecs < MAXNAMES
Then
Begin // tak budu predpokladat, ze je to jmeno souboru
Inc (MaxSpecs);
InFileSpecs [MaxSpecs] := Name;
End {if} ;
End; {if}
SysUtils.FindClose(SearchRec);
End; {JB}
End {while} ;
If MaxSpecs = 0 Then
Begin
MaxSpecs := 1;
InFileSpecs [1] := '*.*';
End {if} ;
Result:=True;
End {Load_Parms} ;
{ --------------------------------------------------------------------------- }
Function Initialize:Boolean;
//Var
// Code : Smallint;
Begin
ZipBuf:=Nil;
ExtBuf:=Nil;
Result := False;
// predelal IvanP
try
GetMem(ZipBuf,SizeOf (ZipBuf^))
except
on EOutOfMemory do
begin
MessageDlg('Not enough memory to allocate LZW data structures!',
mtError,[mbAbort], 0);
Exit;
end;
end;
try
GetMem(ExtBuf,SizeOf (ExtBuf^))
except
on EOutOfMemory do
begin
MessageDlg('Not enough memory to allocate LZW data structures!',
mtError,[mbAbort], 0);
FreeMem(ZipBuf,SizeOf (ZipBuf^));
Exit;
end;
end;
// If MaxAvail > SizeOf (ZipBuf^) Then GetMem(ZipBuf,SizeOf (ZipBuf^))
// Else Exit;
// If MaxAvail > SizeOf (ExtBuf^) Then GetMem(ExtBuf,SizeOf (ExtBuf^))
// Else Begin
// FreeMem(ZipBuf,SizeOf (ZipBuf^));
// Exit;
// End;
Result := True;
End {Initialize} ;
Procedure Finalize;
Begin
If ZipBuf<>Nil Then FreeMem(ZipBuf,SizeOf (ZipBuf^));
If ExtBuf<>Nil Then FreeMem(ExtBuf,SizeOf (ExtBuf^));
End;
{ --------------------------------------------------------------------------- }
{ Converted to Turbo Pascal (tm) V4.0 March, 1988 by J.R.Louvau }
{ COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or }
{ code or tables extracted from it, as desired without restriction. }
{ }
{ First, the polynomial itself and its table of feedback terms. The }
{ polynomial is }
{ X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 }
{ }
{ Note that we take it "backwards" and put the highest-order term in }
{ the lowest-order bit. The X^32 term is "implied"; the LSB is the }
{ X^31 term, etc. The X^0 term (usually shown as "+1") results in }
{ the MSB being 1. }
{ }
{ Note that the usual hardware shift register implementation, which }
{ is what we're using (we're merely optimizing it by doing eight-bit }
{ chunks at a time) shifts bits into the lowest-order term. In our }
{ implementation, that means shifting towards the right. Why do we }
{ do it this way? Because the calculated CRC must be transmitted in }
{ order from highest-order term to lowest-order term. UARTs transmit }
{ characters in order from LSB to MSB. By storing the CRC this way, }
{ we hand it to the UART in the order low-byte to high-byte; the UART }
{ sends each low-bit to hight-bit; and the result is transmission bit }
{ by bit from highest- to lowest-order term without requiring any bit }
{ shuffling on our part. Reception works similarly. }
{ }
{ The feedback terms table consists of 256, 32-bit entries. Notes: }
{ }
{ The table can be generated at runtime if desired; code to do so }
{ is shown later. It might not be obvious, but the feedback }
{ terms simply represent the results of eight shift/xor opera- }
{ tions for all combinations of data and CRC register values. }
{ }
{ The values must be right-shifted by eight bits by the "updcrc" }
{ logic; the shift must be unsigned (bring in zeroes). On some }
{ hardware you could probably optimize the shift in assembler by }
{ using byte-swap instructions. }
{ polynomial $edb88320 }
{ }
Function UpdC32 (Octet: Byte; Crc: LongInt) : LongInt;
Var
L : LongInt;
W : Array [1..4] Of Byte Absolute L;
Begin
Result := CRC_32_TAB [Byte (Crc XOr LongInt (Octet) ) ] XOr ( (Crc ShR 8) And $00FFFFFF);
End {UpdC32} ;
{ --------------------------------------------------------------------------- }
Procedure Read_Zip_Block;
Begin
BlockRead (ZipFile, ZipBuf^, BufSize, ZipCount);
If ZipCount = 0 Then EndFile := True;
ZipPtr := 1;
End {Read_Zip_Block} ;
{ --------------------------------------------------------------------------- }
Procedure Write_Ext_Block;
Begin
If ExtPtr > 1 Then Begin
BlockWrite (ExtFile, ExtBuf^, Pred (ExtPtr) );
If Not IO_Test Then {Halt};
ExtPtr := 1;
End {if} ;
End {Write_Ext_Block} ;
{ --------------------------------------------------------------------------- }
Procedure Open_Zip;
Begin
AssignFile (ZipFile, ZipName);
FileMode := 64; {fmShareDenyNone or fmOpenRead}
{$I-} Reset (ZipFile, 1) {$I+} ;
If Not IO_Test Then {Halt};
EndFile := False;
Read_Zip_Block;
End {Open_Zip} ;
{ --------------------------------------------------------------------------- }
Function Open_Ext : Boolean;
Begin
AssignFile (ExtFile, OutPath + Hdr_FileName);
FileMode := 66; {fmShareDenyNone or fmOpenReadWrite}
{$I-} Rewrite (ExtFile, 1) {$I+} ;
If Not IO_Test Then Result := False
Else Begin
ExtPtr := 1;
Result := True;
End {if} ;
End {Open_Ext} ;
{ --------------------------------------------------------------------------- }
Function Get_Zip : Smallint;
Begin
If ZipPtr > ZipCount Then Read_Zip_Block;
If EndFile Then Result := - 1
Else Begin
Result := ZipBuf^ [ZipPtr];
Inc (ZipPtr);
End {if} ;
End {Get_Zip} ;
{ --------------------------------------------------------------------------- }
Procedure Put_Ext (C : Byte);
Begin
Crc32Val := UpdC32 (C, Crc32Val);
ExtBuf^ [ExtPtr] := C;
Inc (ExtPtr);
Inc (ExtCount);
If ExtPtr > BufSize Then Write_Ext_Block;
End {Put_Ext} ;
{ --------------------------------------------------------------------------- }
Procedure Close_Zip;
Begin
{$I-} CloseFile (Zipfile) {$I+} ;
If IO_Test Then ;
End {Close_Zip} ;
{ --------------------------------------------------------------------------- }
Procedure Close_Ext;
Type
TimeDateRec = Record
Time : Word;
Date : Word;
End {record} ;
Var
TimeDate : TimeDateRec;
TimeDateStamp : LongInt Absolute TimeDate;
Begin
Write_Ext_Block;
TimeDate. Time := LocalHdr. Last_Mod_Time;
TimeDate. Date := LocalHdr. Last_Mod_Date;
{SetFileTime (ExtFile, TimeDateStamp);}
FileSetDate(TFileRec(ExtFile).Handle, TimeDateStamp);
{$I-} System.Close (ExtFile) {$I+} ;
If IO_Test Then ;
End {Close_Ext} ;
{ --------------------------------------------------------------------------- }
Procedure FSkip (Offset : LongInt);
Var
Rec : LongInt;
Begin
If (Offset + ZipPtr) <= ZipCount Then Inc (ZipPtr, Offset)
Else Begin
Rec := FilePos (ZipFile) + (Offset - (ZipCount - ZipPtr) - 1);
{$I-} Seek (ZipFile, Rec) {$I+} ;
If Not IO_Test Then {Halt};
Read_Zip_Block;
End {if} ;
End {FSkip} ;
{ --------------------------------------------------------------------------- }
Procedure FReadOld (Var Buf; RecLen : Word);
Var
I : Word;
B : Array [1..MaxInt] Of Byte Absolute Buf;
Begin
For I := 1 To RecLen Do B [I] := Get_Zip;
End {FRead} ;
Procedure FRead (Var Buf; RecLen : Word);
Type TB = Array [1..MaxInt] Of Byte;
Var
I : Word;
pB : ^TB;
Begin
pB:=@Buf;
For I := 1 To RecLen Do begin pB^[i]:= Get_Zip; end;
End {FRead} ;
Procedure FReadStr (Var Buf :string; RecLen : Word);
Var
I : Word;
ch : char;
Begin
Buf:='';
For I := 1 To RecLen Do
begin
ch:=chr(Get_Zip);
if i<=255 then Buf:=Buf + ch;
end;
End {FRead} ;
{ --------------------------------------------------------------------------- }
Function Read_Local_Hdr : Boolean;
Var
Sig : LongInt;
Begin
If EndFile Then Result := False
Else Begin
FRead (Sig, SizeOf (Sig) );
If Sig = CENTRAL_FILE_HEADER_SIGNATURE Then Begin
Result := False;
EndFile := True;
End {then}
Else Begin
If Sig <> LOCAL_FILE_HEADER_SIGNATURE Then
Abort ('Hlava chybφ nebo je poÜkozena u ' + ZipName);
FRead (LocalHdr, SizeOf (LocalHdr) );
With LocalHdr Do
Begin
If LocalHdr.FileName_Length > 255 Then
Abort ({$IFNDEF English}'JmΘno je chybnΘ !'{$ELSE}'Invalid file name !'{$ENDIF});
FReadStr (Hdr_FileName, LocalHdr.FileName_Length);
If LocalHdr.Extra_Field_Length > 255 Then
Abort ({$IFNDEF English}'JmΘno je chybnΘ !'{$ELSE}'Invalid file name !'{$ENDIF});
FReadStr (Hdr_ExtraField, LocalHdr.Extra_Field_Length);
End {with} ;
Result := True;
End {if} ;
End {if} ;
End {Read_Local_Hdr} ;
{ --------------------------------------------------------------------------- }
Function Get_Compressed : Smallint;
Var
PctDone : Smallint;
{Smsg : String;}
Begin
If Bytes_To_Go = 0 Then Result := - 1
Else Begin
Result := Get_Zip;
{If Bytes_To_Go Mod TenPercent = 0 Then }Begin
PctDone := 100 - Round ( 100 * (Bytes_To_Go / LocalHdr. Compressed_Size) );
{zde je volana udalost pro upravu nejakeho meridla}
If AsSigned(FOnProgress) Then
FOnProgress(Self,PctDone);
{Smsg := PadCh (CharStr (' ', (PctDone+10) Div 10), ' ', 10);}
End {if} ;
Dec (Bytes_To_Go);
End {if} ;
End {Get_Compressed} ;
{ --------------------------------------------------------------------------- }
Function LZW_Init : Boolean;
Var
// RC : Word;
I : Word;
Begin
{ Initialize LZW Table }
try
GetMem(LZW_Table, SizeOf (LZW_Table^))
except
on EOutOfMemory do
Begin
Result := False;
Exit;
End {if} ;
end;
// If MaxAvail > SizeOf (LZW_Table^) Then GetMem(LZW_Table, SizeOf (LZW_Table^))
// Else Begin
// Result := False;
// Exit;
// End {if} ;
For I := 0 To LZW_TABLE_SIZE Do With LZW_Table^ [I] Do Begin
Prefix := - 1;
If I < 256 Then Suffix := I Else Suffix := 0;
ChildCount := 0;
End {with-for} ;
// predelal IvanP
try
GetMem(FreeList, SizeOf (FreeList^))
except
on EOutOfMemory do
Begin
{pripadne alokovanou tabulku uvolni}
FreeMem(LZW_Table, SizeOf (LZW_Table^));
Exit;
End {if} ;
end;
// If MaxAvail > SizeOf (FreeList^) Then GetMem(FreeList, SizeOf (FreeList^))
// Else Begin
// Result := False;
// {pripadne alokovanou tabulku uvolni}
// FreeMem(LZW_Table, SizeOf (LZW_Table^));
// Exit;
// End {if} ;
For I := FIRSTFREE To LZW_TABLE_SIZE Do FreeList^ [I] := I;
NextFree := FIRSTFREE;
{ Initialize the LZW Character Stack }
// Dodelal IvanP
try
GetMem(LZW_Stack,SizeOf(LZW_Stack^))
except
on EOutOfMemory do
Begin
{pripadne alokovanou tabulku uvolni}
FreeMem(LZW_Table, SizeOf (LZW_Table^));
FreeMem(FreeList, SizeOf (FreeList^));
Exit;
End {if} ;
end;
// If MaxAvail > SizeOf (LZW_Stack^) Then GetMem(LZW_Stack,SizeOf(LZW_Stack^))
// Else Begin
// Result := False;
// {pripadne alokovanou tabulku uvolni}
// FreeMem(LZW_Table, SizeOf (LZW_Table^));
// FreeMem(FreeList, SizeOf (FreeList^));
// Exit;
// End {if} ;
StackIdx := 0;
Result := True;
End {LZW_Init} ;
{ --------------------------------------------------------------------------- }
Procedure LZW_Cleanup;
//Var
// Code : Word;
Begin
FreeMem(LZW_Table,SizeOf (LZW_Table^));
FreeMem(FreeList,SizeOf (FreeList^));
FreeMem(LZW_Stack,SizeOf (LZW_Stack^));
End {LZW_Cleanup} ;
{ --------------------------------------------------------------------------- }
Procedure Clear_LZW_Table;
Var
I : Word;
Begin
StackIdx := 0;
For I := FIRSTFREE To LZW_TABLE_SIZE Do Begin { Find all leaf nodes }
If LZW_Table^ [I].ChildCount = 0 Then Begin
LZW_Stack^ [StackIdx] := I; { and put each on stack }
Inc (StackIdx);
End {if} ;
End {for} ;
NextFree := Succ (LZW_TABLE_SIZE);
While StackIdx > 0 Do Begin { clear all leaf nodes }
Dec (StackIdx);
I := LZW_Stack^ [StackIdx];
With LZW_Table^ [I] Do Begin
If LZW_Table^ [I].Prefix <> - 1 Then
Dec (LZW_Table^ [Prefix].ChildCount);
Prefix := - 1;
Suffix := 0;
ChildCount := 0;
End {with} ;
Dec (NextFree); { add cleared nodes to freelist }
FreeList^ [NextFree] := I;
End {while} ;
End {Clear_LZW_Table} ;
{ --------------------------------------------------------------------------- }
Procedure Add_To_LZW_Table (Prefix : Smallint; Suffix : Byte);
Var
I : Word;
Begin
If NextFree <= LZW_TABLE_SIZE Then Begin
I := FreeList^ [NextFree];
Inc (NextFree);
LZW_Table^ [I].Prefix := Prefix;
LZW_Table^ [I].Suffix := Suffix;
Inc (LZW_Table^ [Prefix].ChildCount);
End {if} ;
End {Add_To_LZW_Table} ;
{ --------------------------------------------------------------------------- }
Function GetCode (CodeSize : Byte) : Smallint;
Const
Mask : Array [1..8] Of Byte = ($01,$03,$07,$0F,$1F,$3F,$7F,$FF);
TmpInt : Smallint = 0;
Var
BitsNeeded : Byte;
HowMany : Byte;
HoldCode : Smallint;
Label
Exit;
Begin
If FirstCh Then Begin { If first time through ... }
TmpInt := Get_Compressed; { ... then prime the code buffer }
If TmpInt = - 1 Then Begin { If EOF on fill attempt ... }
GetCode := - 1; { ... then return EOF indicator ... }
Goto Exit; { ... and return to caller. }
End {if} ;
SaveByte := TmpInt;
BitsLeft := 8; { there's now 8 bits in our buffer }
FirstCh := False;
End {if} ;
BitsNeeded := CodeSize;
HoldCode := 0;
While (BitsNeeded > 0) And (TmpInt <> - 1) Do Begin
If BitsNeeded >= BitsLeft Then HowMany := BitsLeft{ HowMany <-- Min(BitsLeft, BitsNeeded) }
Else HowMany := BitsNeeded;
HoldCode := HoldCode Or ( (SaveByte And Mask [HowMany] ) ShL (CodeSize - BitsNeeded) );
SaveByte := SaveByte ShR HowMany;
Dec (BitsNeeded, HowMany);
Dec (BitsLeft, HowMany);
If BitsLeft <= 0 Then Begin { If no bits left in buffer ... }
TmpInt := Get_Compressed; { ... then attempt to get 8 more. }
If TmpInt = - 1 Then
Goto Exit;
SaveByte := TmpInt;
BitsLeft := 8;
End {if} ;
End {while} ;
Exit:
If (BitsNeeded = 0) Then { If we got what we came for ... }
GetCode := HoldCode { ... then return it }
Else
GetCode := - 1; { ... Otherwise, return EOF }
End {GetCode} ;
{ --------------------------------------------------------------------------- }
Procedure UnShrink;
Var
// CH : Char;
CodeSize : Byte; { Current size (in bits) of codes coming in }
CurrCode : Smallint;
SaveCode : Smallint;
PrevCode : Smallint;
BaseChar : Byte;
Begin
CodeSize := MINCODESIZE; { Start with the smallest code size }
PrevCode := GetCode (CodeSize); { Get first code from file }
If PrevCode = - 1 Then { If EOF already, then ... }
Exit; { ... just exit without further ado }
BaseChar := PrevCode;
Put_Ext (BaseChar); { Unpack the first character }
CurrCode := GetCode (CodeSize); { Get next code to prime the while loop }
While CurrCode <> - 1 Do Begin { Repeat for all compressed bytes }
If CurrCode = SPECIAL Then Begin { If we've got a "special" code ... }
CurrCode := GetCode (CodeSize);
Case CurrCode Of
1: Begin { ... and if followed by a 1 ... }
Inc (CodeSize); { ... then increase code size }
End {1} ;
2: Begin { ... and if followed by a 2 ... }
Clear_LZW_Table; { ... clear leaf nodes in the table }
End {2} ;
Else Begin { ... if neither 1 or 2, discard }
Abort('K≤d Üpatn∞ navazuje ! PokraΦujem...');
End {else} ;
End {case} ;
End {then}
Else Begin { Not a "special" code }
SaveCode := CurrCode; { Save this code someplace safe... }
If CurrCode > LZW_TABLE_SIZE Then
Abort('K≤d se jevφ chybn² !');
If (CurrCode >= FIRSTFREE) And (LZW_Table^ [CurrCode].Prefix = - 1) Then Begin
If StackIdx > LZW_STACK_SIZE Then Begin
Write_Ext_Block;
Abort('Promi≥te, p°etekl mi zßsobnφk ('+Long2Str(StackIdx)+')!');
Exit;{musis vystoupit}
End {if} ;
LZW_Stack^ [StackIdx] := BaseChar;
Inc (StackIdx);
CurrCode := PrevCode;
End {if} ;
While CurrCode >= FIRSTFREE Do Begin
If StackIdx > LZW_STACK_SIZE Then Begin
Write_Ext_Block;
Abort('Promi≥te, p°etekl mi zßsobnφk ('+Long2Str(StackIdx)+')!');
Exit;{musis vystoupit}
End {if} ;
LZW_Stack^ [StackIdx] := LZW_Table^ [CurrCode].Suffix;
Inc (StackIdx);
CurrCode := LZW_Table^ [CurrCode].Prefix;
End {while} ;
BaseChar := LZW_Table^ [CurrCode].Suffix; { Get last character ... }
Put_Ext (BaseChar);
While (StackIdx > 0) Do Begin
Dec (StackIdx);
Put_Ext (LZW_Stack^ [StackIdx] );
End {while} ; { ... until there are none left }
Add_to_LZW_Table (PrevCode, BaseChar); { Add new entry to table }
PrevCode := SaveCode;
End {if} ;
CurrCode := GetCode (CodeSize); { Get next code from input stream }
End {while} ;
End {UnShrink} ;
{ --------------------------------------------------------------------------- }
Function Init_UnReduce : Boolean;
//Var
// Code : Word;
Begin
// Dodelal IvanP
Result := False;
try
GetMem(Followers, SizeOf (Followers^))
except
on EOutOfMemory do
Begin
Exit;
End {if} ;
end;
DictSize := 4096;
try
GetMem(Dictionary,DictSize)
except
on EOutOfMemory do
Begin
{uvolni jiz alokovane tabulky}
FreeMem(Followers, SizeOf (Followers^));
Exit;
End {if} ;
end;
// If MaxAvail > SizeOf (Followers^) Then GetMem(Followers, SizeOf (Followers^))
// Else Begin
// Result := False;
// Exit;
// End {if} ;
//
// DictSize := 4096;
// If MaxAvail > DictSize Then GetMem(Dictionary,DictSize)
// Else Begin
// Result := False;
// {uvolni jiz alokovane tabulky}
// FreeMem(Followers, SizeOf (Followers^));
// Exit;
// End {if} ;
Result := True;
End {Init_UnReduce} ;
{ --------------------------------------------------------------------------- }
Procedure Cleanup_UnReduce;
//Var
// Code : Word;
Begin
FreeMem(Followers,SizeOf (Followers^));
FreeMem(Dictionary,DictSize);
End {Cleanup_UnReduce} ;
{ --------------------------------------------------------------------------- }
Function D (X, Y : Byte) : Word;
Var
tmp : LongInt;
Begin
X := X ShR (8 - Pred (LocalHdr. Compress_Method) );
Tmp := X * 256;
D := Tmp + Y + 1;
End {D} ;
{ --------------------------------------------------------------------------- }
Function F (X : Word) : Byte;
Const
TestVal : Array [1..4] Of Byte = (127, 63, 31, 15);
Begin
If X = TestVal [Pred (LocalHdr. Compress_Method) ] Then F := 2 Else F := 3;
End {F} ;
{ --------------------------------------------------------------------------- }
Function L (X : Byte) : Byte;
Const
Mask : Array [1..4] Of Byte = ($7F, $3F, $1F, $0F);
Begin
L := X And Mask [Pred (LocalHdr. Compress_Method) ];
End {L} ;
{ --------------------------------------------------------------------------- }
Procedure UpdateDictionary (C : Byte);
Begin
Put_Ext (C);
Dictionary^ [DictIdx] := C;
DictIdx := Succ (DictIdx) Mod DictSize;
End {UpdateDictionary} ;
{ --------------------------------------------------------------------------- }
Procedure DictionaryInit;
Begin
State := 0;
FillChar (Dictionary^ [0], DictSize, $00);
DictIdx := 0;
End {DictionaryInit} ;
{ --------------------------------------------------------------------------- }
Procedure UnScrnch (C : Byte);
Const
DLE = $90;
Var
S : Smallint;
Count : Word;
OneByte : Byte;
Tmp1 : LongInt;
Begin
Case State Of
0:If C = DLE Then State := 1 Else UpdateDictionary (C);
1: Begin
If C = 0 Then Begin
UpdateDictionary (DLE);
State := 0;
End {then}
Else Begin
V := C;
Len := L (V);
State := F (Len);
End {if} ;
End {1} ;
2: Begin
Inc (Len, C);
State := 3;
End {2} ;
3: Begin
Tmp1 := D (V, C);
S := DictIdx - Tmp1;
If S < 0 Then
S := S + DictSize;
Count := Len + 3;
While Count > 0 Do Begin
OneByte := Dictionary^ [S];
UpdateDictionary (OneByte);
S := Succ (S) Mod DictSize;
Dec (Count);
End {while} ;
State := 0;
End {3} ;
End {case} ;
End {UnScrnch} ;
{ --------------------------------------------------------------------------- }
Function MinBits (Val : Byte) : Byte;
Begin
Dec (Val);
Case Val Of
0..1 : MinBits := 1;
2..3 : MinBits := 2;
4..7 : MinBits := 3;
8..15 : MinBits := 4;
16..31: MinBits := 5;
Else
MinBits := 6;
End {case} ;
End {MinBits} ;
{ --------------------------------------------------------------------------- }
Procedure UnReduce;
Var
LastChar : Byte;
N : Byte;
I, J : Word;
Code : Smallint;
// CH : Char;
Begin
For I := 255 Downto 0 Do Begin { Load follower sets }
N := GetCode (6); { Get size of 1st set }
Followers^ [I].SetSize := N;
If N > 0 Then
For J := 0 To Pred (N) Do
Followers^ [I].FSet [J] := GetCode (8);
End {for} ;
DictionaryInit;
LastChar := 0;
Repeat
If Followers^ [LastChar].SetSize = 0 Then Begin
Code := GetCode (8);
UnScrnch (Code);
LastChar := Code;
End {then}
Else Begin
Code := GetCode (1);
If Code <> 0 Then Begin
Code := GetCode (8);
UnScrnch (Code);
LastChar := Code;
End {then}
Else Begin
I := MinBits (Followers^ [LastChar].SetSize);
Code := GetCode (I);
UnScrnch (Followers^ [LastChar].FSet [Code] );
LastChar := Followers^ [LastChar].FSet [Code];
End {if} ;
End {if} ;
Until (ExtCount = LocalHdr. Uncompressed_Size);
FreeMem(Followers,SizeOf (Followers^))
{Code := Dalloc (Followers);}
End {UnReduce} ;
{ --------------------------------------------------------------------------- }
Function Init_Explode: Boolean;
{ Get ready to unimplode }
//Var
// RC : Word;
Begin
Result := False;
{ Extract pertinent info from the general purpose bit flag }
DictSize := ( ( (LocalHdr. Bit_Flag ShR 1) And $01) * 4096) + 4096;
NumOfTrees := ( ( LocalHdr. Bit_Flag ShR 2) And $01) + 2;
MinMatchLen := NumOfTrees;
{ Allocate memory for the Length & Distance Shannon-Fano trees }
// Dodelal IvanP
try
GetMem(SF_Length,SizeOf(SF_Length^))
except
on EOutOfMemory do exit
end;
try
GetMem(SF_Distance,SizeOf(SF_Distance^))
except
on EOutOfMemory do
Begin
FreeMem(SF_Length,SizeOf(SF_Length^)); {uvolni jiz alokovane tabulky}
Exit;
End;
end;
// If MaxAvail > SizeOf(SF_Length^) Then GetMem(SF_Length,SizeOf(SF_Length^))
// Else Exit;
// If MaxAvail > SizeOf(SF_Distance^) Then GetMem(SF_Distance,SizeOf(SF_Distance^))
// Else Begin
// {uvolni jiz alokovane tabulky}
// FreeMem(SF_Length,SizeOf(SF_Length^));
// Exit;
// End;
{ Initialize Length & Distance nodes to all -1's and set the Next Free }
{ Node pointers for each }
FillChar (SF_Length^, SizeOf (SF_Length^), $FF);
NextFreeLength := Pred (LENGTH_TREE_ROOT);
FillChar (SF_Distance^, SizeOf (SF_Distance^), $FF);
NextFreeDistance := Pred (DISTANCE_TREE_ROOT);
{ If we need a literal tree, then allocate the memory , initialize the }
{ nodes to all -1's, and set the Next Free Node pointer }
SF_Literal:=Nil;{indikace nepouziti}
If NumOfTrees = 3 Then Begin
// Dodelal IvanP
try
GetMem(SF_Literal,SizeOf(SF_Literal^))
except
on EOutOfMemory do
Begin
{uvolni jiz alokovane tabulky}
FreeMem(SF_Length,SizeOf(SF_Length^));
FreeMem(SF_Distance,SizeOf(SF_Distance^));
Exit;
End;
end;
FillChar (SF_Literal^, SizeOf (SF_Literal^), $FF);
NextFreeLiteral := Pred (LITERAL_TREE_ROOT);
End {if} ;
// If MaxAvail > SizeOf(SF_Literal^) Then GetMem(SF_Literal,SizeOf(SF_Literal^))
// Else Begin
// {uvolni jiz alokovane tabulky}
// FreeMem(SF_Length,SizeOf(SF_Length^));
// FreeMem(SF_Distance,SizeOf(SF_Distance^));
// Exit;
// End;
{ Allocate memory for the sliding dictionary }
// Dodelal IvanP
try
GetMem(Dictionary,DictSize)
except
on EOutOfMemory do
Begin
{uvolni jiz alokovane tabulky}
FreeMem(SF_Length,SizeOf(SF_Length^));
FreeMem(SF_Distance,SizeOf(SF_Distance^));
If SF_Literal<>Nil Then FreeMem(SF_Literal,SizeOf(SF_Literal^));
Exit;
End;
end;
// If MaxAvail > DictSize Then GetMem(Dictionary,DictSize)
// Else Begin
// {uvolni jiz alokovane tabulky}
// FreeMem(SF_Length,SizeOf(SF_Length^));
// FreeMem(SF_Distance,SizeOf(SF_Distance^));
// If SF_Literal<>Nil Then FreeMem(SF_Literal,SizeOf(SF_Literal^));
// Exit;
// End;
{RC := Malloc (Dictionary, DictSize);
Failure := Failure OR (RC <> 0);}
{ Allocate memory for the array used in building the SF-Trees }
// Dodelal IvanP
try
GetMem(SF_Build,SizeOf(SF_Build^))
except
on EOutOfMemory do
Begin
{uvolni jiz alokovane tabulky}
FreeMem(SF_Length,SizeOf(SF_Length^));
FreeMem(SF_Distance,SizeOf(SF_Distance^));
If SF_Literal<>Nil Then FreeMem(SF_Literal,SizeOf(SF_Literal^));
FreeMem(Dictionary,DictSize);
Exit;
End;
end;
// If MaxAvail > SizeOf(SF_Build^) Then GetMem(SF_Build,SizeOf(SF_Build^))
// Else Begin
// {uvolni jiz alokovane tabulky}
// FreeMem(SF_Length,SizeOf(SF_Length^));
// FreeMem(SF_Distance,SizeOf(SF_Distance^));
// If SF_Literal<>Nil Then FreeMem(SF_Literal,SizeOf(SF_Literal^));
// FreeMem(Dictionary,DictSize);
// Exit;
// End;
{ If any memory allocations failed, deallocate any memory that may have }
{ been successfully allocated. }
{ Return either success or failure }
Result := True;
End { Init_Explode } ;
{ --------------------------------------------------------------------------- }
Procedure Cleanup_Explode;
{ Clean things up after unimploding a file }
//Var
// RC : Word;
Begin
FreeMem(SF_Length,SizeOf(SF_Length^));
FreeMem(SF_Distance,SizeOf(SF_Distance^));
If SF_Literal<>Nil Then FreeMem(SF_Literal,SizeOf(SF_Literal^));
FreeMem(Dictionary,DictSize);
FreeMem(SF_Build,SizeOf(SF_Build^))
End { Cleanup_Explode } ;
{ --------------------------------------------------------------------------- }
Procedure Bad_SF_Tree;
Begin
{Chybn² Shannon-Fano dek≤dovacφ strom !}
Abort ('Chybn² dek≤dovacφ strom !');
End { Bad_SF_Tree } ;
{ --------------------------------------------------------------------------- }
Procedure Add_SF_SubTree ( Var SF_Tree;
Var SF_NextFree : Word;
SF_Root : Word;
SF_Code : Word;
SF_Code_Length : Byte;
SF_Value : Byte );
{ Add the subtree defined by SF_Code to a Shannon-Fano tree }
Var
SF_Array : Array [0..MAX_SF_TREE_SIZE] Of SF_Node Absolute SF_Tree;
CurrNode : Word;
LastLeaf : Word;
I : Byte;
Begin
{ The Shannon-Fano tree is implemented as an array of records. Each }
{ record contains both left and right pointers (ie. this is a binary }
{ tree). The root of the tree is the last array element. The first N }
{ elements (0..N-1) are defined to be the "leaves" of the tree (ie. they }
{ represent the characters that the decode algorithm will generate). N }
{ may be 64 (for the length tree), 128 (for the distance tree), or 256 }
{ (for the Literal tree). The remaining elements of the array are used to }
{ represent the non-leaf and non-root nodes of the tree. }
CurrNode := SF_Root;
LastLeaf := Pred (Succ (SF_Root) Div 2);
{ All bits in the code except the least significant define non-leaf nodes }
{ in the tree. Process these first. }
For I := Pred (SF_Code_Length) Downto 1 Do Begin
If CurrNode <= LastLeaf Then Bad_SF_Tree;
If Boolean ( (SF_Code ShR I) And $0001) Then Begin { if the bit is a 1 }
If SF_Array [CurrNode].RChild = - 1 Then Begin { no RChild yet }
SF_Array [CurrNode].RChild := SF_NextFree;
Dec (SF_NextFree);
End {if} ;
CurrNode := SF_Array [CurrNode].RChild; { on 1 bits, follow the }
{ right subtree }
End { then }
Else Begin { the bit is a 0 }
If SF_Array [CurrNode].LChild = - 1 Then Begin { no LChild yet }
SF_Array [CurrNode].LChild := SF_NextFree;
Dec (SF_NextFree);
End {if} ;
CurrNode := SF_Array [CurrNode].LChild; { on 0 bits, follow the }
{ left subtree }
End { if } ;
End { for } ;
{ All that's left now is to process the least significant bit of the code. }
{ This will define a leaf node. The leaf node to be linked is defined by }
{ the SF_Value that is passed to the procedure. }
If Boolean (SF_Code And $0001) Then
If SF_Array [CurrNode].RChild <> - 1 Then
Bad_SF_Tree
Else
SF_Array [CurrNode].RChild := SF_Value
Else
If SF_Array [CurrNode].LChild <> - 1 Then
Bad_SF_Tree
Else
SF_Array [CurrNode].LChild := SF_Value;
End { Add_SF_SubTree } ;
{ --------------------------------------------------------------------------- }
Procedure Sort_SF_Build_Array ( Count : Word );
Procedure Exchange (Var Node1, Node2 : SF_BuildRec);
Var
Node3 : SF_BuildRec;
Begin
Node3.Len := Node1.Len;
Node3.Val := Node1.Val;
{ Node3.Code := Node1.Code; } { the Code field is irrelevant at this point }
Node1.Len := Node2.Len;
Node1.Val := Node2.Val;
{ Node1.Code := Node2.Code; } { ditto }
Node2.Len := Node3.Len;
Node2.Val := Node3.Val;
{ Node2.Code := Node3.Code; } { ditto again }
End { Exchange } ;
Function ShouldSwap ( P1, P2 : SF_BuildRec ) : Boolean;
Begin
ShouldSwap := (P1.Len>P2.Len) Or ((P1.Len=P2.Len) And (P1.Val>P2.Val))
End { ShouldSwap } ;
Procedure Sort (lb, ub : Smallint);
(***** BUBBLE SORT **************************************************)
(* The list is scanned repeatedly, and adjacent items that are out of
order are swapped. When a pass occurs with no swaps, the list is
sorted. *)
Var
swapped : Boolean;
cell : Smallint;
Begin
Repeat
swapped := False;
For cell := lb To ub - 1 Do Begin
If ShouldSwap (SF_Build^ [cell], SF_Build^ [cell + 1] ) Then Begin
Exchange (SF_Build^ [cell], SF_Build^ [cell + 1] );
swapped := True;
End;
End;
Until (swapped = False);
End;
Begin
Sort (0, Count);
End { Sort_SF_Build_Array } ;
{ --------------------------------------------------------------------------- }
Procedure Build_SF_Trees;
{ Extract SF data from an imploded file and build the required SF trees }
Var
OneByte : Byte; { These "misc" variables are also used in }
CodeLen : Byte; { building the SF trees }
CodeCount : Byte;
SF_Table_Codes : Word; { # of bytes representing SF tree data - 1}
BuildCount : Word; { total entries in SF_Build array }
Code : Word; { These three variables used in }
CodeIncrement : Word; { constructing the Shannon-Fano codes }
LastBitLength : Word; { that will be used to build the SF trees }
WhichTree : Word; { Counter indicating which SF tree is }
{ currently under construction }
SF_Tree : Pointer;
SF_NextFree : Word;
SF_Root : Word;
I, J : Word; { Generic loop counter }
Begin
For WhichTree := 1 To NumOfTrees Do Begin
{ Before we go any further, determine which subtree-add procedure }
{ parameters will be needed on the call to Add_SF_SubTree }
Case NumOfTrees Of
2:
Case WhichTree Of
1: Begin
SF_Tree := SF_Length;
SF_NextFree := NextFreeLength;
SF_Root := LENGTH_TREE_ROOT;
End { 1 } ;
2: Begin
SF_Tree := SF_Distance;
SF_NextFree := NextFreeDistance;
SF_Root := DISTANCE_TREE_ROOT;
End { 2 } ;
End { case whichtree } ;
3:
Case WhichTree Of
1: Begin
SF_Tree := SF_Literal;
SF_NextFree := NextFreeLiteral;
SF_Root := LITERAL_TREE_ROOT;
End { 1 } ;
2: Begin
SF_Tree := SF_Length;
SF_NextFree := NextFreeLength;
SF_Root := LENGTH_TREE_ROOT;
End { 2 } ;
3: Begin
SF_Tree := SF_Distance;
SF_NextFree := NextFreeDistance;
SF_Root := DISTANCE_TREE_ROOT;
End { 3 } ;
End { case whichtree } ;
End { case numoftrees } ;
{ Build the Shannon-Fano tree }
SF_Build_Idx := 0;
BuildCount := 0;
SF_Table_Codes := GetCode (8);
For I := 0 To SF_Table_Codes Do Begin
{ Load the SF_Build array with data from the compressed file }
OneByte := GetCode (8);
CodeLen := (OneByte And $0F) + 1;
CodeCount := (OneByte ShR 4);
For J := 0 To CodeCount Do Begin
SF_Build^ [SF_Build_Idx].Len := CodeLen;
SF_Build^ [SF_Build_Idx].Val := SF_Build_Idx;
Inc (SF_Build_Idx);
End { for J } ;
End { for I } ;
BuildCount := Pred (SF_Build_Idx);
{ Sort the SF_Build Array based on the Len field }
Sort_SF_Build_Array (BuildCount);
{ Generate the SF codes that will be used to grow the SF tree using the }
{ algorithm outlined in the AppNote.Txt file (as distributed within the }
{ PKZip v1.0 self extracting ZIP archive). }
Code := 0;
CodeIncrement := 0;
LastBitLength := 0;
For I := BuildCount Downto 0 Do Begin
Inc (Code, CodeIncrement);
If SF_Build^ [I].Len <> LastBitLength Then Begin
LastBitLength := SF_Build^ [I].Len;
CodeIncrement := 1 ShL (16 - LastBitLength);
End {if} ;
SF_Build^ [I].Code := Code ShR (16 - SF_Build^ [I].Len);
{ Ok, we've got a value and a code. This represents a subtree in }
{ the Shannon-Fano tree structure. Add it to the appropriate tree. }
Add_SF_SubTree(SF_Tree^,SF_NextFree,SF_Root,SF_Build^[I].Code,
SF_Build^[I].Len,SF_Build^[I].Val);
End { for buildcount } ;
End { for whichtree } ;
End { Build_SF_Trees } ;
{ --------------------------------------------------------------------------- }
Procedure Bad_SF_Data;
Begin
{Chybn² Shannon-Fano k≤d !}
Abort ('┌pln∞ chybnΘ k≤dovßnφ !');
End { Bad_SF_Tree } ;
{ --------------------------------------------------------------------------- }
Function Decode_SF_Data(Var SF_Tree;SF_Root : Word ) : Byte;
{ Read bits from the input file and decode them using one of the 3 possible }
{ Shannon-Fano trees. The method is idential to that used in decoding files }
{ encoded with the Huffman method (popularaly known as "squeezing") in that }
{ the tree is traced from the root to either the right or left depending on }
{ the last bit read until finally, one encounteres a leaf node. }
Var
SF_Array : Array [0..MAX_SF_TREE_SIZE] Of SF_Node Absolute SF_Tree;
OneBit : Byte;
CurrNode : Word;
LastLeaf : Word;
Begin
CurrNode := SF_Root; { We start traversing the tree from it's root node }
LastLeaf := Pred (Succ (SF_Root) Div 2);
While CurrNode > LastLeaf Do Begin
{ Walk the tree until you hit a leaf node }
OneBit := GetCode (1);
If Boolean (OneBit And $01) Then { if the bit is a 1 ... }
If SF_Array [CurrNode].RChild = - 1 Then
Bad_SF_Data
Else
CurrNode := SF_Array [CurrNode].RChild
Else
If SF_Array [CurrNode].LChild = - 1 Then
Bad_SF_Data
Else
CurrNode := SF_Array [CurrNode].LChild
End { while } ;
Decode_SF_Data := CurrNode;
End { Decode_SF_Data } ;
{ --------------------------------------------------------------------------- }
Procedure Explode;
Var
OneByte : Byte;
Literal : Byte;
Length : Word;
DistVal : Word;
Distance : Word;
DictStart : Smallint;
Begin
Build_SF_Trees;
DictionaryInit;
Repeat
OneByte := GetCode (1);
If OneByte <> 0 Then Begin
{ This is literal data ... no dictionary lookup involved }
If NumOfTrees = 3 Then
Literal := Decode_SF_Data (SF_Literal^, LITERAL_TREE_ROOT)
Else
Literal := GetCode (8);
UpdateDictionary (Literal);
End { then }
Else Begin
{ Data for output will come from the sliding dictionary }
If DictSize = 8192 Then Begin
Distance := GetCode (7);
DistVal := Decode_SF_Data (SF_Distance^, DISTANCE_TREE_ROOT);
Distance := (Distance Or (DistVal ShL 7) ) And $1FFF;
End {then}
Else Begin
Distance := GetCode (6);
DistVal := Decode_SF_Data (SF_Distance^, DISTANCE_TREE_ROOT);
Distance := (Distance Or (DistVal ShL 6) ) And $0FFF;
End {if} ;
Length := Decode_SF_Data ( SF_Length^, LENGTH_TREE_ROOT );
If Length = 63 Then
Length := Length + GetCode (8);
Length := Length + MinMatchLen;
DictStart := DictIdx - (Distance + 1);
If DictStart < 0 Then
DictStart := DictStart + DictSize;
While Length > 0 Do Begin
UpdateDictionary (Dictionary^ [DictStart] );
DictStart := Succ (DictStart) Mod DictSize;
Dec (Length);
End {while} ;
End {if} ;
Until (ExtCount >= LocalHdr. Uncompressed_Size);
End { Explode } ;
{ --------------------------------------------------------------------------- }
Procedure UnShrinkProc;
Begin
If Not LZW_Init Then Begin
Abort('Nenφ dost pam∞ti k rozmrsknutφ ! P°ekraΦuji ...');
FSkip (LocalHdr. Compressed_Size);
Crc32Val := Not LocalHdr. Crc32;
Exit;
End;
Try
UnShrink
Finally
LZW_Cleanup;
End;
End;
Procedure UnReduceProc;
Begin
If Not Init_UnReduce Then Begin
Abort('Nenφ dost pam∞ti k rozvinutφ ! P°ekraΦuji ...');
FSkip (LocalHdr. Compressed_Size);
Crc32Val := Not LocalHdr. Crc32;
Exit;
End;
Try
UnReduce
Finally
Cleanup_UnReduce;
End;
End;
Procedure UnExplodeProc;
Begin
If Not Init_Explode Then Begin
Abort('Nenφ dost pam∞ti k rozpnutφ ! P°ekraΦuji ...');
FSkip (LocalHdr. Compressed_Size);
Crc32Val := Not LocalHdr. Crc32;
Exit;
End;
Try
Explode
Finally
Cleanup_Explode;
End;
End;
Procedure UnZipex;
//Var
// C : Smallint;
// PP : Pointer;
Begin
Crc32Val := $FFFFFFFF;
Bytes_To_Go := LocalHdr. Compressed_Size;
FirstCh := True;
ExtCount := 0;
TenPercent := LocalHdr. Compressed_Size{ Div 10};
{If TenPercent = 0 Then TenPercent := 1;}
Case LocalHdr. Compress_Method Of
0: Begin
While Bytes_to_go > 0 Do
Put_Ext (Get_Compressed);
End {0 = Stored} ;
1: Begin
UnShrinkProc
End {1 = shrunk} ;
2..5 : Begin
UnReduceProc
End {2..5} ;
6 : Begin
UnExplodeProc
End {6} ;
Else Begin
Abort('Neznßmß svinovacφ metoda u₧itß na '+'['+ZipName+']: '+Hdr_FileName+'. P°ekraΦuji ...');
FSkip (LocalHdr. Compressed_Size);
Crc32Val := Not LocalHdr. Crc32;
End {else} ;
End {case} ;
Crc32Val := Not Crc32Val;
If Crc32Val <> LocalHdr. Crc32 Then Begin
Abort('Soubor '+ OutPath + Hdr_FileName +' mß chybnΘ CRC ! Ulo₧en² CRC = '+
HexLInt (LocalHdr. Crc32)+' VypoΦten² CRC = '+HexLInt (Crc32Val))
End {if} ;
End {UnZipex} ;
{ --------------------------------------------------------------------------- }
Procedure Extract_File(OverWrite:Boolean);
Var
// YesNo : Char;
DosDTA : TSearchRec;
Begin
If SysUtils.FindFirst (OutPath + Hdr_FileName, faAnyFile, DosDTA)= 0 Then Begin
If Not OverWrite Then Begin
FSkip (LocalHdr. Compressed_Size);
Exit;
End {if} ;
End {if} ;
If Open_Ext Then Begin
UnZipex;
Close_Ext;
End {then}
Else Begin
FSkip (LocalHdr. Compressed_Size);
End {If} ;
End {Extract_File} ;
{ --------------------------------------------------------------------------- }
Procedure Extract_Zip;
Var
Match : Boolean;
I : Word;
Begin
Open_Zip;
While Read_Local_Hdr Do Begin
Match := False;
I := 1;
Repeat
If SameFile (ExpandFileName(InFileSpecs [I]), ExpandFileName(Hdr_FileName)) Then Match := True;
Inc (I);
Until Match Or (I > MaxSpecs);
If Match Then
Extract_File(True) {tj. prepis vsechny}
Else
FSkip (LocalHdr. Compressed_Size);
End {while} ;
Close_Zip;
End;
{ --------------------------------------------------------------------------- }
Begin
{If Signum <> '' Then SignWork:=Signum;}
{ Showmessage(Prmline); {*****}
If Not Load_Parms (PrmLine) Then Exit; { get command line parameters }
If Not Initialize Then Exit; { one-time initialization }
Try
Extract_Zip; { de-arc the file }
Finally
Finalize
End
End;
constructor TZip.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
destructor TZip.Destroy;
begin
inherited Destroy;
end;
Procedure TZip.SetFName(Name:String);
Begin
FName := Name;
End;
Procedure TZip.SetParameters(Prm:String);
Begin
FParam:=Prm;
End;
Function TZip.Execute:Boolean;
Begin
{Screen.Cursor:=crHourGlass;}
Crunch(FName+Spacer+FParam);
{Screen.Cursor:=crDefault;}
End;
{-----------------------------------------------------------------}
constructor TUnZip.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
destructor TUnZip.Destroy;
begin
inherited Destroy;
end;
Procedure TUnZip.SetFName(Name:String);
Begin
FName := Name;
End;
Procedure TUnZip.SetExtrPath(Path:String);
Begin
FExtrPath:=Path;
If FExtrPath<>'' Then
If FExtrPath[Length(FExtrPath)]<>'\' Then
FExtrPath := FExtrPath +'\';
End;
Procedure TUnZip.SetParameters(Prm:String);
Begin
FParam:=Prm;
End;
Function TUnZip.Execute:Boolean;
//var O : smallint;
// i : Smallint;
// s : string;
Begin
Result := True;
Try
{Screen.Cursor:=crHourGlass;}
UnCrunch(FName+Spacer+FExtrPath+Spacer+FParam);
{Screen.Cursor:=crDefault;}
Except
Result := False
End;
End;
Procedure TUnZip.GetZipList(Const iFileName:String;Var A:TStringList);
{ve stringlistu je navracen seznam souboru ze zipu}
{volani Zip.GetZipList(Zip.FName,FList);}
Const
lf_signature = $4034b50;
f_signature = $2014b50;
e_signature = $6054b50;
Type
L_f_head = Packed Record { A. Local file header:}
Signature : LongInt; { local file header signature 4 bytes }
{ (0x04034b50) }
Unp_ver, { version needed to extract 2 bytes }
Gen_pur, { general purpose bit flag 2 bytes }
Compr_met, { compression method 2 bytes }
File_time, { last mod file time 2 bytes }
File_date : Word; { last mod file date 2 bytes }
CRC, { crc-32 4 bytes }
Comp_size, { compressed size 4 bytes }
full_size : LongInt; { uncompressed size 4 bytes }
Name_len, { filename length 2 bytes }
Eks_len : Word; { extra field length 2 bytes }
{ filename (variable size) }
{ extra field (variable size) }
End;
{ B. Central directory structure: }
{ [file header] . . . end of central dir record }
F_header = Packed Record { File header: }
Signature : LongInt; { central file header signature 4 bytes }
{ (0x02014b50) }
Com_ver, { version made by 2 bytes }
Unp_ver, { version needed to extract 2 bytes }
Gen_pur, { general purpose bit flag 2 bytes }
compr_met, { compression method 2 bytes }
File_time, { last mod file time 2 bytes }
File_date : Word; { last mod file date 2 bytes }
CRC, { crc-32 4 bytes }
Comp_size, { compressed size 4 bytes }
full_size : LongInt; { uncompressed size 4 bytes }
Name_len, { filename length 2 bytes }
Eks_len, { extra field length 2 bytes }
Com_len, { file comment length 2 bytes }
Disk_start, { disk number start 2 bytes }
Int_att : Word; { internal file attributes 2 bytes }
ext_att, { external file attributes 4 bytes }
L_h_ofs : LongInt; { relative offset of local header 4 bytes }
{ filename (variable size) }
{ extra field (variable size) }
{ file comment (variable size) }
End;
End_cd = Packed Record { End of central dir record: }
Signature : LongInt; { end of central dir signature 4 bytes }
{ (0x06054b50) }
Disk_nr, { number of this disk 2 bytes }
{ number of the disk with the }
Start_nr, { start of the central directory 2 bytes }
{ total number of entries in }
CD_entrys, { the central dir on this disk 2 bytes }
{ total number of entries in }
Tot_cd_ent : Word; { the central dir 2 bytes }
CD_size, { size of the central directory 4 bytes }
{ offset of start of central }
{ directory with respect to }
CD_start_ofs: LongInt; { the starting disk number 4 bytes }
Com_leng : Word { zipfile comment length 2 bytes }
{ zipfile comment (variable size) }
End;
Streng = String [80];
P_l_head = Packed Record
zip_head : L_f_head;
Name,
comment : streng;
End;
Const
buffsize = 2*4095;{14.2.1996}
Var
fil : File;
Buffer : ^Word;
laest : Word;
hoved : p_l_head;
Function read_headder ( Var head : P_l_head) : Boolean;
Var
//i : Word;
ok : Boolean;
l, len:Integer;
Begin
ok:=True;
With head Do Begin
If laest<SizeOf(zip_head) Then Begin
l:=SizeOf(zip_head);
BlockRead(fil,Pointer(LongInt(Buffer)+laest)^,l,len);
ok:= (len=(SizeOf(zip_head)-laest));
Inc(laest,len);
End;
Move(Buffer^,zip_head,SizeOf(zip_head));
ok:=ok And (zip_head.signature=lf_signature);
If ok Then Begin
BlockRead(fil,Name[1],zip_head.name_len,len);
Name[0]:=Chr(len);
BlockRead(fil,comment,zip_head.eks_len,len);
comment[0]:=Chr(len);
ok:= (len=zip_head.eks_len) And (zip_head.signature=lf_signature);
End;
End;
read_headder:=ok;
End;
Function skip ( leng : LongInt) : Boolean;
Var
len : Integer;
ok : Boolean;
Begin
ok:=True;
Repeat
If (leng>buffsize) Then Begin
BlockRead(fil,Buffer^,buffsize,len);
Dec(leng,buffsize);
If len<buffsize Then ok:=False;
End
Else Begin
len:=leng;
BlockRead(fil,Buffer^,len,len);
If len<leng Then ok:=False;
End;
Until Not ok Or (leng<buffsize);
skip:=ok;
laest:=0;
End;
Function timestring ( tiden : LongInt) : streng;
{$IfDef USEjbDTM}
Var
date,time:LongInt;
Begin
{tohle je pro prizpusobeni pri konverzich na D-T modul a konfiguraci}
ConvertFDate(tiden, Date, Time);
With Cfgr^.Fi Do
result:=Date2StrDate('dd'+FiDateChar+'mm'+FiDateChar+'yyyy',Date)+#9+
Time2StrTime('hh'+FiTimeChar+'mm'+FiTimeChar+'ss',Time);
{$Else}
Var DT:TDateTime;
Begin
{tohle je klasicky}
DT := FileDateToDateTime(tiden);
Result := FormatDateTime('dd'+DateSeparator+'mm'+DateSeparator+'yyyy"'+#9+'"hh'+TimeSeparator+'mm'+TimeSeparator+'ss',DT)
{$EndIf}
End;
Const maxpollin=100;{maxpollin}
Var
ok: Boolean;
t_len,t_size: LongInt;
antal: Word;
{temp,}navn: streng;
stamp,latest: LongInt;
S: String[60];
pocet:Word;
Procedure Init;
Begin
laest:=0; antal:=0;
t_size:=0; t_len:=0;
latest:=0;stamp:=0;
ok:=True;
End;
Begin { Zipview }
GetMem(Buffer,buffsize);
try
navn:=iFileName;
Init;
Assignfile(fil,navn);
Reset(fil,1);
try
pocet := 0;
While ok And read_headder(hoved) Do With hoved,zip_head Do
Begin
Inc(pocet);
ok:= skip(zip_head.comp_size);
Inc(t_len,full_size);
Inc(t_size,comp_size);
If stamp>latest Then latest:=stamp;
End;
Init;
Reset(fil,1);
While ok And read_headder(hoved) Do With hoved,zip_head Do Begin
Inc(antal);
S := Name;
stamp:=LongInt(zip_head.file_date) ShL 16 Or zip_head.file_time;
S := S+#9+Long2Str(full_size)+#9+Long2Str(comp_size)+#9+
Trim(Real2Str(-1*(100-(comp_size/full_size*100)),5,0))+'%'+#9+timestring(stamp);
A.Add(S);{<----- vlozi retezec do seznamu}
ok:= skip(zip_head.comp_size);
Inc(t_len,full_size);
Inc(t_size,comp_size);
If stamp>latest Then latest:=stamp;
End;
finally
Close(fil);
end;
finally
FreeMem(Buffer,buffsize);
end;
End;
procedure Register;
begin
RegisterComponents('Library', [TZip,TUnZip]);
end;
end.