316 lines
8.5 KiB
ObjectPascal
316 lines
8.5 KiB
ObjectPascal
(* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is TurboPower Abbrevia
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* TurboPower Software
|
|
*
|
|
* Portions created by the Initial Developer are Copyright (C) 1997-2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* ***** END LICENSE BLOCK ***** *)
|
|
|
|
{*********************************************************}
|
|
{* ABBREVIA: AbZLTyp.pas *}
|
|
{*********************************************************}
|
|
{* ABBREVIA: TAbZlItem class *}
|
|
{*********************************************************}
|
|
{* Misc. constants, types, and routines for working *}
|
|
{* with ZLib compressed data *}
|
|
{* See: RFC 1950 *}
|
|
{* "ZLIB Compressed Data Format Specification *}
|
|
{* version 3.3" for more information on ZLib *}
|
|
{*********************************************************}
|
|
|
|
unit AbZLTyp;
|
|
|
|
{$I AbDefine.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, AbUtils, AbArcTyp, AbZipPrc, AbDfBase, AbDfDec, AbDfEnc;
|
|
|
|
const
|
|
AB_ZL_PRESET_DICT = $20;
|
|
|
|
AB_ZL_DEF_COMPRESSIONMETHOD = $8; { Deflate }
|
|
AB_ZL_DEF_COMPRESSIONINFO = $7; { 32k window for Deflate }
|
|
|
|
AB_ZL_FASTEST_COMPRESSION = $0;
|
|
AB_ZL_FAST_COMPRESSION = $1;
|
|
AB_ZL_DEFAULT_COMPRESSION = $2;
|
|
AB_ZL_MAXIMUM_COMPRESSION = $3;
|
|
|
|
AB_ZL_FCHECK_MASK = $1F;
|
|
AB_ZL_CINFO_MASK = $F0; { mask out leftmost 4 bits }
|
|
AB_ZL_FLEVEL_MASK = $C0; { mask out leftmost 2 bits }
|
|
AB_ZL_CM_MASK = $0F; { mask out rightmost 4 bits }
|
|
|
|
|
|
type
|
|
TAbZLHeader = packed record
|
|
CMF : Byte;
|
|
FLG : Byte;
|
|
end;
|
|
|
|
TAbZLItem = class(TAbArchiveItem)
|
|
private
|
|
function GetCompressionInfo: Byte;
|
|
function GetCompressionLevel: Byte;
|
|
function GetIsPresetDictionaryPresent: Boolean;
|
|
procedure SetCompressionInfo(Value: Byte);
|
|
procedure SetCompressionLevel(Value: Byte);
|
|
function GetCompressionMethod: Byte;
|
|
procedure SetCompressionMethod(Value: Byte);
|
|
function GetFCheck: Byte;
|
|
procedure MakeFCheck;
|
|
protected { private }
|
|
FZLHeader : TAbZlHeader;
|
|
FAdler32 : LongInt;
|
|
public
|
|
constructor Create;
|
|
|
|
property IsPresetDictionaryPresent : Boolean
|
|
read GetIsPresetDictionaryPresent;
|
|
property CompressionLevel : Byte
|
|
read GetCompressionLevel write SetCompressionLevel;
|
|
property CompressionInfo : Byte
|
|
read GetCompressionInfo write SetCompressionInfo;
|
|
|
|
property CompressionMethod : Byte
|
|
read GetCompressionMethod write SetCompressionMethod;
|
|
property Adler32 : LongInt
|
|
read FAdler32 write FAdler32;
|
|
|
|
property FCheck : Byte
|
|
read GetFCheck;
|
|
|
|
procedure SaveZLHeaderToStream(AStream : TStream);
|
|
procedure ReadZLHeaderFromStream(AStream : TStream);
|
|
end;
|
|
|
|
TAbZLStreamHelper = class(TAbArchiveStreamHelper)
|
|
protected { private }
|
|
FItem : TAbZLItem;
|
|
public
|
|
constructor Create(AStream : TStream);
|
|
destructor Destroy; override;
|
|
|
|
property Item : TAbZLItem
|
|
read FItem;
|
|
|
|
procedure ExtractItemData(AStream : TStream); override;
|
|
function FindFirstItem : Boolean; override;
|
|
function FindNextItem : Boolean; override;
|
|
procedure ReadHeader; override;
|
|
procedure ReadTail; override;
|
|
function SeekItem(Index : Integer): Boolean; override;
|
|
procedure WriteArchiveHeader; override;
|
|
procedure WriteArchiveItem(AStream : TStream); override;
|
|
procedure WriteArchiveTail; override;
|
|
function GetItemCount : Integer; override;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
{ TAbZLStreamHelper }
|
|
|
|
constructor TAbZLStreamHelper.Create(AStream: TStream);
|
|
begin
|
|
inherited Create(AStream);
|
|
FItem := TAbZLItem.Create;
|
|
end;
|
|
|
|
destructor TAbZLStreamHelper.Destroy;
|
|
begin
|
|
FItem.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TAbZLStreamHelper.ExtractItemData(AStream: TStream);
|
|
{ assumes already positioned appropriately }
|
|
var
|
|
Hlpr : TAbDeflateHelper;
|
|
begin
|
|
Hlpr := TAbDeflateHelper.Create;
|
|
Hlpr.Options := Hlpr.Options or dfc_UseAdler32;
|
|
if not FItem.IsPresetDictionaryPresent then
|
|
Inflate(FStream, AStream, Hlpr)
|
|
else
|
|
raise Exception.Create('preset dictionaries unsupported');
|
|
Hlpr.Free;
|
|
end;
|
|
|
|
function TAbZLStreamHelper.FindFirstItem: Boolean;
|
|
var
|
|
ZLH : TAbZLHeader;
|
|
begin
|
|
FStream.Seek(0, soBeginning);
|
|
Result := FStream.Read(ZLH, SizeOf(TAbZLHeader)) = SizeOf(TAbZLHeader);
|
|
FItem.FZLHeader := ZLH;
|
|
FStream.Seek(0, soBeginning);
|
|
end;
|
|
|
|
function TAbZLStreamHelper.FindNextItem: Boolean;
|
|
begin
|
|
{ only one item in a ZLib Stream }
|
|
Result := FindFirstItem;
|
|
end;
|
|
|
|
function TAbZLStreamHelper.GetItemCount: Integer;
|
|
begin
|
|
{ only one item in a ZLib Stream }
|
|
Result := 1;
|
|
end;
|
|
|
|
procedure TAbZLStreamHelper.ReadHeader;
|
|
{ assumes already positioned appropriately }
|
|
var
|
|
ZLH : TAbZLHeader;
|
|
begin
|
|
FStream.Read(ZLH, SizeOf(TAbZlHeader));
|
|
FItem.FZLHeader := ZLH;
|
|
end;
|
|
|
|
procedure TAbZLStreamHelper.ReadTail;
|
|
{ assumes already positioned appropriately }
|
|
var
|
|
Adler: LongInt;
|
|
begin
|
|
FStream.Read(Adler, SizeOf(LongInt));
|
|
FItem.Adler32 := Adler;
|
|
end;
|
|
|
|
function TAbZLStreamHelper.SeekItem(Index: Integer): Boolean;
|
|
begin
|
|
{ only one item in a ZLib Stream }
|
|
if Index <> 1 then
|
|
Result := False
|
|
else
|
|
Result := FindFirstItem;
|
|
end;
|
|
|
|
procedure TAbZLStreamHelper.WriteArchiveHeader;
|
|
begin
|
|
Item.SaveZLHeaderToStream(FStream);
|
|
end;
|
|
|
|
procedure TAbZLStreamHelper.WriteArchiveItem(AStream: TStream);
|
|
var
|
|
Hlpr : TAbDeflateHelper;
|
|
begin
|
|
{ Compress file }
|
|
Hlpr := TAbDeflateHelper.Create;
|
|
Hlpr.Options := Hlpr.Options or dfc_UseAdler32;
|
|
Item.Adler32 := AbDfEnc.Deflate(AStream, FStream, Hlpr);
|
|
Hlpr.Free;
|
|
end;
|
|
|
|
procedure TAbZLStreamHelper.WriteArchiveTail;
|
|
var
|
|
Ad32 : LongInt;
|
|
begin
|
|
Ad32 := AbSwapLongEndianness(Item.Adler32);
|
|
FStream.Write(Ad32, SizeOf(LongInt));
|
|
end;
|
|
|
|
{ TAbZLItem }
|
|
|
|
constructor TAbZLItem.Create;
|
|
begin
|
|
{ Set default Values for fields }
|
|
FillChar(FZLHeader, SizeOf(TAbZlHeader), #0);
|
|
FZLHeader.CMF := (AB_ZL_DEF_COMPRESSIONINFO shl 4); { 32k Window size }
|
|
FZLHeader.CMF := FZLHeader.CMF or AB_ZL_DEF_COMPRESSIONMETHOD; { Deflate }
|
|
FZLHeader.FLG := FZLHeader.FLG and not AB_ZL_PRESET_DICT; { no preset dictionary}
|
|
FZLHeader.FLG := FZLHeader.FLG or (AB_ZL_DEFAULT_COMPRESSION shl 6); { assume default compression }
|
|
MakeFCheck;
|
|
end;
|
|
|
|
function TAbZLItem.GetCompressionInfo: Byte;
|
|
begin
|
|
Result := FZLHeader.CMF shr 4;
|
|
end;
|
|
|
|
function TAbZLItem.GetCompressionLevel: Byte;
|
|
begin
|
|
Result := FZLHeader.FLG shr 6;
|
|
end;
|
|
|
|
function TAbZLItem.GetCompressionMethod: Byte;
|
|
begin
|
|
Result := FZLHeader.CMF and AB_ZL_CM_MASK;
|
|
end;
|
|
|
|
function TAbZLItem.GetFCheck: Byte;
|
|
begin
|
|
Result := FZLHeader.FLG and AB_ZL_FCHECK_MASK;
|
|
end;
|
|
|
|
function TAbZLItem.GetIsPresetDictionaryPresent: Boolean;
|
|
begin
|
|
Result := (FZLHeader.FLG and AB_ZL_PRESET_DICT) = AB_ZL_PRESET_DICT;
|
|
end;
|
|
|
|
procedure TAbZLItem.MakeFCheck;
|
|
{ create the FCheck value for the current Header }
|
|
var
|
|
zlh : Word;
|
|
begin
|
|
FZLHeader.FLG := FZLHeader.FLG and not AB_ZL_FCHECK_MASK;
|
|
zlh := (FZLHeader.CMF * 256) + FZLHeader.FLG;
|
|
Inc(FZLHeader.FLG, 31 - (zlh mod 31));
|
|
end;
|
|
|
|
procedure TAbZLItem.ReadZLHeaderFromStream(AStream: TStream);
|
|
begin
|
|
AStream.Read(FZLHeader, SizeOf(TAbZLHeader));
|
|
end;
|
|
|
|
procedure TAbZLItem.SaveZLHeaderToStream(AStream: TStream);
|
|
begin
|
|
MakeFCheck;
|
|
AStream.Write(FZLHeader, SizeOf(TAbZlHeader));
|
|
end;
|
|
|
|
procedure TAbZLItem.SetCompressionInfo(Value: Byte);
|
|
begin
|
|
FZLHeader.CMF := FZLHeader.CMF and not AB_ZL_CINFO_MASK;
|
|
FZLHeader.CMF := FZLHeader.CMF or (Value shl 4); { shift value and add to bit field }
|
|
end;
|
|
|
|
procedure TAbZLItem.SetCompressionLevel(Value: Byte);
|
|
var
|
|
Temp : Byte;
|
|
begin
|
|
Temp := Value;
|
|
if not Temp in [AB_ZL_FASTEST_COMPRESSION..AB_ZL_MAXIMUM_COMPRESSION] then
|
|
Temp := AB_ZL_DEFAULT_COMPRESSION;
|
|
FZLHeader.FLG := FZLHeader.FLG and not AB_ZL_FLEVEL_MASK;
|
|
FZLHeader.FLG := FZLHeader.FLG or (Temp shl 6); { shift value and add to bit field }
|
|
end;
|
|
|
|
procedure TAbZLItem.SetCompressionMethod(Value: Byte);
|
|
begin
|
|
if Value > AB_ZL_CM_MASK then Value := (Value shl 4) shr 4;
|
|
FZLHeader.CMF := FZLHeader.CMF and not AB_ZL_CM_MASK;
|
|
FZLHeader.CMF := FZLHeader.CMF or Value;
|
|
end;
|
|
|
|
end.
|