(* ***** 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.