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.