📄 abgztyp.pas
字号:
(* ***** 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: AbGzTyp.pas 3.05 *}{*********************************************************}{* ABBREVIA: TAbGzipArchive, TAbGzipItem classes *}{*********************************************************}{* Misc. constants, types, and routines for working *}{* with GZip files *}{* See: RFC 1952 *}{* "GZIP file format specification version 4.3" *}{* for more information on GZip *}{*********************************************************}{$I AbDefine.inc}unit AbGzTyp;interfaceuses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LINUX} {$IFNDEF NOQT} QDialogs, {$ENDIF} {$ENDIF} SysUtils, Classes, AbConst, AbExcept, AbUtils, AbArcTyp, AbTarTyp, AbDfBase, AbDfDec, AbDfEnc, AbVMStrm, AbBitBkt, AbSpanSt;type { pre-defined "operating system" (really more FILE system) types for the Gzip header } TAbGzFileSystem = (osFat, osAmiga, osVMS, osUnix, osVM_CMS, osAtariTOS, osHPFS, osMacintosh, osZSystem, osCP_M, osTOPS20, osNTFS, osQDOS, osAcornRISCOS, osUnknown, osUndefined);type PAbGzHeader = ^TAbGzHeader; TAbGzHeader = packed record { SizeOf(TGzHeader) = 10} ID1 : Byte; { ID Byte, should always be $1F} ID2 : Byte; { ID Byte, should always be $8B} CompMethod : Byte; { compression method used} { 0..7 reserved, 8 = deflate, others undefined as of this writing (4/27/2001)} Flags : Byte; { misc flags} { Bit 0: FTEXT compressed file contains text, can be used for} { cross platform line termination translation} { Bit 1: FHCRC header data includes CRC16 for header after} { Extra Data, FileName, and Comment, if any} { Bit 2: FEXTRA header data contains Extra Data, starts immediately} { after header proper} { Bit 3: FNAME header data contains FileName, null terminated} { string starting immediately after Extra Data (if any)} { Bit 4: FCOMMENT header data contains Comment, null terminated string} { starting immediately after FileName (if any)} { Bits 5..7 are undefined and reserved as of this writing (4/27/2001)} ModTime : LongInt; { File Modification (Creation) time,} { UNIX cdate format} XtraFlags : Byte; { additional flags} { XtraFlags = 2 -- Deflate compressor used maximum compression algorithm} { XtraFlags = 4 -- Deflate compressor used fastest algorithm} OS : Byte; { Operating system that created file,} { see GZOsToStr routine for values} end; TAbGzTailRec = packed record CRC32 : LongInt; { crc for uncompressed data } ISize : LongInt; { size of uncompressed data } end;type TAbGzipItem = class(TAbArchiveItem) private FCRC32: LongInt; protected {private} FGZHeader : TAbGzHeader; FIsText : Boolean; FCRC16 : ShortInt; FXLen : ShortInt; FExtraField, FFileComment : string; FIncludeHeaderCrc: Boolean; protected function GetExtraField: string; function GetFileSystem: TAbGzFileSystem; function GetFileComment: string; function GetHeaderCRC: Word; function GetHasExtraField: Boolean; function GetHasFileComment: Boolean; function GetHasHeaderCRC: Boolean; function GetHasFileName: Boolean; function GetIsText: Boolean; procedure SetExtraField(const Value: string); procedure SetFileComment(Value : string); procedure SetFileSystem(const Value: TAbGzFileSystem); procedure SetIsText(const Value: Boolean); function GetCompressedSize : LongInt; override; function GetExternalFileAttributes : LongInt; override; function GetIsEncrypted : Boolean; override; function GetLastModFileDate : Word; override; function GetLastModFileTime : Word; override; function GetUncompressedSize : LongInt; override; procedure SetCompressedSize(const Value : LongInt); override; procedure SetExternalFileAttributes( Value : LongInt ); override; procedure SetFileName(Value : string); override; procedure SetIsEncrypted(Value : Boolean); override; procedure SetLastModFileDate(const Value : Word); override; procedure SetLastModFileTime(const Value : Word); override; procedure SetUncompressedSize(const Value : LongInt); override; procedure SaveGzHeaderToStream(AStream : TStream); procedure LoadGzHeaderFromStream(AStream : TStream); public property CRC32 : LongInt read FCRC32 write FCRC32; property CompressionMethod : Byte read FGZHeader.CompMethod write FGZHeader.CompMethod; property ExtraFlags : Byte {Default: 2} read FGZHeader.XtraFlags write FGZHeader.XtraFlags; property Flags : Byte read FGZHeader.Flags write FGZHeader.Flags; property FileComment : string read GetFileComment write SetFileComment; property FileSystem : TAbGzFileSystem {Default: osFat (Windows); osUnix (Linux)} read GetFileSystem write SetFileSystem; property ExtraField : string read GetExtraField write SetExtraField; property HeaderCRC : Word read GetHeaderCRC; property IsEncrypted : Boolean read GetIsEncrypted; property HasExtraField : Boolean read GetHasExtraField; property HasFileName : Boolean read GetHasFileName; property HasFileComment : Boolean read GetHasFileComment; property HasHeaderCRC : Boolean read GetHasHeaderCRC; property IsText : Boolean read GetIsText write SetIsText; property GZHeader : TAbGzHeader read FGZHeader write FGZHeader; property IncludeHeaderCrc : Boolean read FIncludeHeaderCrc write FIncludeHeaderCrc; constructor Create; end; TAbGzipStreamHelper = class(TAbArchiveStreamHelper) private function GetGzCRC: LongInt; function GetFileSize: LongInt; protected {private} FItem : TAbGzipItem; FTail : TAbGzTailRec; public constructor Create(AStream : TStream); destructor Destroy; override; procedure ExtractItemData(AStream : TStream); override; function FindFirstItem : Boolean; override; function FindNextItem : Boolean; override; function SeekItem(Index : Integer): Boolean; override; procedure SeekToItemData; procedure WriteArchiveHeader; override; procedure WriteArchiveItem(AStream : TStream); override; procedure WriteArchiveTail; override; function GetItemCount : Integer; override; procedure ReadHeader; override; procedure ReadTail; override; property CRC : LongInt read GetGzCRC; property FileSize : LongInt read GetFileSize; property TailCRC : LongInt read FTail.CRC32; property TailSize : LongInt read FTail.ISize; end; TAbGzipArchiveState = (gsGzip, gsTar); TAbGzipArchive = class(TAbTarArchive) private FGZStream : TStream; { stream for GZip file} FGZItem : TAbArchiveList; { item in Gzip (only one, but need polymorphism of class)} FTarStream : TStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FTarLoaded : Boolean; FState : TAbGzipArchiveState; FIsGzippedTar : Boolean; procedure SetTarAutoHandle(const Value: Boolean); function GetIsGzippedTar: Boolean; procedure SwapToGzip; procedure SwapToTar; protected function CreateItem(const FileSpec : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const NewName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function FixName(Value : string) : string; override; function GetItem(Index: Integer): TAbGzipItem; {!!.03} procedure PutItem(Index: Integer; const Value: TAbGzipItem); {!!.03} public {methods} constructor Create(FileName : string; Mode : Word); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsGzippedTar : Boolean read GetIsGzippedTar write FIsGzippedTar; property Items[Index : Integer] : TAbGzipItem {!!.03} read GetItem {!!.03} write PutItem; default; {!!.03} end;function VerifyGZip(Strm : TStream) : TAbArchiveType;function GZOsToStr(OS: Byte) : string;implementationconst { Header Signature Values} AB_GZ_HDR_ID1 = $1F; AB_GZ_HDR_ID2 = $8B; { Test bits for TGzHeader.Flags field } AB_GZ_FLAG_FTEXT = $01; AB_GZ_FLAG_FHCRC = $02; AB_GZ_FLAG_FEXTRA = $04; AB_GZ_FLAG_FNAME = $08; AB_GZ_FLAG_FCOMMENT = $10; { GZip OS source flags } AB_GZ_OS_ID_FAT = 0; AB_GZ_OS_ID_Amiga = 1; AB_GZ_OS_ID_VMS = 2; AB_GZ_OS_ID_Unix = 3; AB_GZ_OS_ID_VM_CMS = 4; AB_GZ_OS_ID_AtariTOS = 5; AB_GZ_OS_ID_HPFS = 6; AB_GZ_OS_ID_Macintosh = 7; AB_GZ_OS_ID_Z_System = 8; AB_GZ_OS_ID_CP_M = 9; AB_GZ_OS_ID_TOPS20 = 10; AB_GZ_OS_ID_NTFS = 11; AB_GZ_OS_ID_QDOS = 12; AB_GZ_OS_ID_AcornRISCOS = 13; AB_GZ_OS_ID_unknown = 255;function GZOsToStr(OS: Byte) : string;{Return a descriptive string for TGzHeader.OS field}begin case OS of AB_GZ_OS_ID_FAT : Result := AbGzOsFat; AB_GZ_OS_ID_Amiga : Result := AbGzOsAmiga; AB_GZ_OS_ID_VMS : Result := AbGzOsVMS; AB_GZ_OS_ID_Unix : Result := AbGzOsUnix; AB_GZ_OS_ID_VM_CMS : Result := AbGzOsVM_CMS; AB_GZ_OS_ID_AtariTOS : Result := AbGzOsAtari; AB_GZ_OS_ID_HPFS : Result := AbGzOsHPFS; AB_GZ_OS_ID_Macintosh : Result := AbGzOsMacintosh; AB_GZ_OS_ID_Z_System : Result := AbGzOsZ_System; AB_GZ_OS_ID_CP_M : Result := AbGzOsCP_M; AB_GZ_OS_ID_TOPS20 : Result := AbGzOsTOPS_20; AB_GZ_OS_ID_NTFS : Result := AbGzOsNTFS; AB_GZ_OS_ID_QDOS : Result := AbGzOsQDOS; AB_GZ_OS_ID_AcornRISCOS : Result := AbGzOsAcornRISCOS; AB_GZ_OS_ID_unknown : Result := AbGzOsunknown; else Result := AbGzOsUndefined; end;end;function VerifyHeader(Header : TAbGzHeader) : Boolean;begin { check id fields and if deflated (only handle deflate anyway)} Result := (Header.ID1 = AB_GZ_HDR_ID1) and (Header.ID2 = AB_GZ_HDR_ID2) and (Header.CompMethod = 8 {deflate});end;function VerifyGZip(Strm : TStream) : TAbArchiveType;var{ Hdr : TAbGzHeader; } GHlp : TAbGzipStreamHelper; Hlpr : TAbDeflateHelper; PartialTarData : TMemoryStream; CurPos : LongInt;begin Result := atUnknown; CurPos := Strm.Position; Strm.Seek(0, soFromBeginning); {prepare for the try..finally} Hlpr := nil; PartialTarData := nil; GHlp := TAbGzipStreamHelper.Create(Strm); try {create the stream helper and read the item header} GHlp.ReadHeader; { check id fields and if deflated (only handle deflate anyway)} if VerifyHeader(GHlp.FItem.FGZHeader) then begin Result := atGZip; { provisional } { check if is actually a Gzipped Tar } { partial extract contents, verify vs. Tar } PartialTarData := TMemoryStream.Create; GHlp.SeekToItemData; Hlpr := TAbDeflateHelper.Create; Hlpr.PartialSize := 512; PartialTarData.SetSize(512 * 2); Inflate(Strm, PartialTarData, Hlpr); {set to beginning of extracted data} PartialTarData.Position := 0; if (VerifyTar(PartialTarData) = atTar) then Result := atGZippedTar; end; finally GHlp.Free; Hlpr.Free; PartialTarData.Free; Strm.Position := CurPos; end;end;{ TAbGzipStreamHelper }constructor TAbGzipStreamHelper.Create(AStream : TStream);begin inherited Create(AStream); FItem := TAbGzipItem.Create;end;destructor TAbGzipStreamHelper.Destroy;begin FItem.Free; inherited;end;procedure SeekToStringEndInStream(AStream: TStream);{locate next instance of a null character in a streamleaves stream positioned just past that,or at end of stream if not found or null is last byte in stream.}const BuffSiz = 1024;var Buff : array [0..BuffSiz-1] of AnsiChar; Len, StartPos, DataRead, TotalRead : LongInt; Done : Boolean;begin{ basically what this is supposed to do is...}{ repeat AStream.Read(C, 1); until (AStream.Position = AStream.Size) or (C = #0);} StartPos := AStream.Position; Done := False; TotalRead := 0; while not Done do begin DataRead := AStream.Read(Buff, BuffSiz - 1); if DataRead = 0 then Done := True else begin Buff[DataRead] := #0; Len := StrLen(Buff); if Len < DataRead then begin Done := True; AStream.Seek(StartPos + TotalRead + Len + 1, soFromBeginning); end else TotalRead := TotalRead + DataRead; end; end;end;procedure TAbGzipStreamHelper.SeekToItemData;{find end of header data, including FileName etc.}begin {** Seek to Compressed Data **} FStream.Seek(0, soFromBeginning); FItem.LoadGzHeaderFromStream(FStream);end;procedure TAbGzipStreamHelper.ExtractItemData(AStream: TStream);var Helper : TAbDeflateHelper;begin Helper := TAbDeflateHelper.Create; try SeekToItemData; if (AStream is TAbBitBucketStream) then Helper.Options := Helper.Options or dfc_TestOnly; FItem.CRC32 := Inflate(FStream, AStream, Helper); FItem.UncompressedSize := AStream.Size{Helper.NormalSize}; finally Helper.Free; end;end;function TAbGzipStreamHelper.FindFirstItem: Boolean;var
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -