From 4610b7309140898dc25ffb55259a3114c18d4e96 Mon Sep 17 00:00:00 2001 From: drewski207 Date: Mon, 20 Feb 2012 03:10:38 +0000 Subject: [PATCH] Added zlibar to components. based on 0.2.3. older versions of zlibar have no revision history git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2301 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/zlibar/docs/makedocs.sh | 23 + components/zlibar/docs/zlibar.chm | Bin 0 -> 33940 bytes components/zlibar/docs/zlibar.xml | 725 +++++++++++++++++++++++ components/zlibar/zlibar.pas | 843 +++++++++++++++++++++++++++ components/zlibar/zlibar_package.lpk | 43 ++ components/zlibar/zlibar_package.pas | 14 + 6 files changed, 1648 insertions(+) create mode 100644 components/zlibar/docs/makedocs.sh create mode 100644 components/zlibar/docs/zlibar.chm create mode 100755 components/zlibar/docs/zlibar.xml create mode 100755 components/zlibar/zlibar.pas create mode 100755 components/zlibar/zlibar_package.lpk create mode 100755 components/zlibar/zlibar_package.pas diff --git a/components/zlibar/docs/makedocs.sh b/components/zlibar/docs/makedocs.sh new file mode 100644 index 000000000..5147cd3b5 --- /dev/null +++ b/components/zlibar/docs/makedocs.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# change these as needed +BASE_XCT_DIR=/home/andrew/programming/help/ + +RTL_XCT=$BASE_XCT_DIR"rtl.xct" +FCL_XCT=$BASE_XCT_DIR"fcl.xct" + +CSS=/home/andrew/programming/lazarus-svn/docs/html/fpdoc.css +TITLE="ZLib Archive Component" + +fpdoc --package=zlibar \ +--format=chm \ +--descr=zlibar.xml \ +--hide-protected \ +--output=zlibar.chm \ +--input=../zlibar.pas \ +--auto-toc \ +--auto-index \ +--make-searchable \ +--import=$RTL_XCT,ms-its:rtl.chm::/ \ +--import=$FCL_XCT,ms-its:fcl.chm::/ \ +--css-file=$CSS \ +--chm-title="$TITLE" diff --git a/components/zlibar/docs/zlibar.chm b/components/zlibar/docs/zlibar.chm new file mode 100644 index 0000000000000000000000000000000000000000..a0fba50b476bbeab8dc8ae02746958da0e4fcd89 GIT binary patch literal 33940 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used internally + This holds temporarily the compressed size if a stream and it's MD5 checksum. + + + + The compressed size of a stream + + + + The TMD5Digest of the original uncompressed stream. + + + + Used to store the list of files to be compressed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Add a File to be compressed + Should be a fully qualified filename. Stored in the archive as just the filename without paths. To set a releative path for the file use AddPath. + + + + + + + + The index of the filename in the list + + + + Fully qualified FileName to be added + + + + Adds a FileName and a relative path + + + + + + + Index of added file name in the list + + + + Fully qualified filename to be compressed + + + + Relative path to be decompressed to + + + + Used to insert a file to be compressed into the list at a specific index + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deletes the filename at index from the list + + + + Index of the filename to be removed + + + + Removes all files from the list of files to be compressed + + + + Number of files in the list to be compressed + Zero based so to do a loop using Count you must do Count-1 + + + + The number of files in the list + + + + Used to retrieve the fully qualified filename that is to be compressed + + + + Index of the filename you wish to retrieve the FileName from. + + + + Used to retrieve the releative path the file should be extracted to + + + + Index of the filename you wish to retrieve the relative path from. + + + + Used internally to obtain the compressed size of the file + Only usefull after the file has been compressed + + + + + + + Index of the filename you wish to retrieve the TFileInfo from. + + + + The information at the beggining of a TZlibArchive + Contains vital information about the archive. + +Major Minor and Micro hold the version of the archive. + + + + The file identifier + The first four bytes of the file. Z A R #0. Used to verify the type of file. + + + + + + + + + + + + + + + + + + + + + + Length of the table of contents. + Used internally to be able to determine the lenght of the TOC + + + + Checksum of the uncompressed TOC + The table of contents is stored compressed in the archive. This is used to ensure that the TOC is intact. + + + + + + + + + + The structure of a table of contents entry + Used to manage various information about the size and position of a file in the TZlibArchive + + + + The file name only + This contains no path information. + + + + The desired relative path for the file to be extracted to. + + + + The position of the compressed stream in the TZLibArchive stream. + + + + The size of a compressed file + + + + The checksum used to verify the file is the same as the original + + + + Callback used to follow the progress of overall and current progress + Used to provide feedback to the user of the progress of compression. + + + + TZlibWriteArchive Object + + + + Index of the current file that is being compressed. + + + + + + + Total size of the InStream to be compressed + + + + Amount of the InStream that has been compressed. + + + + Callback for progress during decompression + + + + TZlibReadArchive object + + + + Total size of the InStream + + + + Current position of the InStream + + + + Error Callback + Used to catch error before an exception is raised. + + + + TZlibReadArchive or TZlibWriteArchive object + + + + Error code that has occured + Set to 0 to avoid an exception + + + + Description of the error. + + + + Object used to create ZibArchive files. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates an instance of the TZlibWriteArchive object + + + + + + + + + + + Compresses and write all the files in the list to OutStream + The Stream is written to starting from the beginning. The Previos contents of the stream are lost. + + + + True if successful False otherwise + + + + Callback used to intercept errors before an exception is raised + + + + Callback used to imform the user of the compression progress + + + + + + + Stream the compressed archive it written to + If this is not assigned a TMemoryStream is automatically created and assigned to OutStream. + + + + List of files to be compressed + + + + + + + Object to read and extract files made with TZLibWriteArchive + A TZlibReadArchive object is not capable of writing or changing an archive. You must use a TZLibWriteArchive object to do that. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a TZlibReadArchive object and opens an archive from a TStream + + + + Creates an instance of the object + + + + Stream that you wish to be opened + + + + + + + + + + + Extract the file at Index to a user provided stream + + + + Index of the file to be extracted + + + + User provided stream for the compressed file to be decompressed into + + + + Retrieves the header of the file + + + + Contains information about the file in the archive + + + + + + + Index of the file you want information about + + + + Number of files in the archive + + + + Callback to intercept errors before they trigger an Exception + + + + + + + Callback used to monitor the progress of a file as it is being extracted + + + + + + + TStream that is currently loaded + Set to nil to close the file + + + + + + + + + + + + + + + + + + + + + + + + + + + + Error Code + The table of contents has been corrupted. A MD5 checksum is made before the TOC is compressed. If the checksum of the extracted TOC does not match this error occurs. + + + + Error Code + The file you are trying to open does not have the correct header, or is not a recognized file format. + + + + Error Code + The file you are trying to compress does not match the checksum of the original file before it was compressed. + + + + + + + + + + Compresses InStream into OutStream + Generic independant function to compress InStream into OutStream. + + + + + + + The size of the compressed stream in bytes + + + + The TStream that you wish to be compressed + InStream is read from the begining of InStream. + + + + The compressed stream + OutStream is written to from the current position of OutStream.Position. + + + + Decompresses InStream to OutStream + Decompresses InStream to OutStream. + + + + The Size of OutStream in bytes + + + + The Stream that you wish to compress + InStream is read from position 0 to the end. + + + + The stream that the decompressed data will be written into + OutStream is written to at the current position it happens to be in the stream. + + + + Creates a TMD5Digest from a TMemoryStream + Use this to create a TMD5Digest from a Stream. This is used to ensure that a file matches in every way by comparing it to a previous TMD5Digest. + + + + Returns a TMd5Digest + + + + The stream you wish to be scanned + + + + + diff --git a/components/zlibar/zlibar.pas b/components/zlibar/zlibar.pas new file mode 100755 index 000000000..55ecab830 --- /dev/null +++ b/components/zlibar/zlibar.pas @@ -0,0 +1,843 @@ +{ zlibar.pas can create and read a file that contains many compressed files +Copyright (C) 2005 Andrew Haines + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +} +{ + See also the file COPYING.modifiedLGPL included with this file +} +unit zlibar; + +// This Unit Provides methods to compress multiple files into an archive of one file and retrieve them +// Also you can use CompressStream and ExtractStream to just compress and decompress a tmemorystream + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, paszlib, md5; + +type + + PFileInfo = ^TFileInfo; + TFileInfo = record + CompressedSize: Int64; + Md5Sum: TMD5Digest; + end; + + { TZlibFilesList } + TZlibFilesList = class(TObject) + private + FFileList: TFpList; + FPathList: TFpList; + FFileInfoList: TFpList; + function GetFileName(AIndex: Integer): String; + function GetPath(AIndex: Integer): String; + procedure SetFileName(AIndex: Integer; AFIleName: String); + procedure SetPath(AIndex: Integer; APath: String); + function GetFileInfo(AIndex: Integer): TFileInfo; + procedure SetFileInfo(AIndex: Integer; AFileInfo: TFileInfo); + public + constructor Create; + destructor Destroy; override; + public + function Add(AFileName: String): Integer; + function AddPath(AFileName: String; APath: String): Integer; + function Insert(AIndex: Integer; AFileName: String): Integer; + function InsertPath(AIndex: Integer; AFileName: String; APath: String): Integer; + procedure Delete(AIndex: Integer); + procedure Clear; + function Count: Integer; + public + // this contains the full path to the file name on the current filesystem + property FileName[Index: Integer]: String read GetFileName write SetFileName; + // this is the relative path that you would like the file extracted to + property Path[Index: Integer]: String read GetPath write SetPath; + // used internally + property FileInfo[Index: Integer]: TFileInfo read GetFileInfo write SetFileInfo; + end; + TZlibArchiveHeader = packed record + FileType: array [0..3] of char;// = ('Z','A','R', 0); + MajorVersion, + MinorVersion, + MicroVersion: LongInt; + TOCLength: Int64; // overkill? :) + TOCMD5Sum: TMD5Digest; + end; + + PTOCEntry = ^TTOCEntry; + TTOCEntry = packed record + FileName: String; + FilePath: String; + Position: Int64; + CompressedSize: Int64; + Md5sum: TMD5Digest; + end; + (* + A TOC Entry will stored like so: + 1. Write File Name to be in archive + 2 Write Empty Byte. + 3. Write File Path + 4. Write Empty Byte + 5. Write File Position (Int64) 8 bytes + 6. Write File Compressed Size(Int64) + 7. Write md5sum (TMD5Digest) + Repeat 1-4 + *) + + TZlibCompressProgProc = procedure (Sender: TObject; FileIndex: Integer; FileSize, FilePos: Int64) of object; + + TZlibExtractProgProc = procedure (Sender: TObject; FileSize, FilePos: Int64) of object; + + TZlibErrorProc = procedure(Sender: TObject; var ErrorCode: Integer; ErrorStr: String) of object; + + { TZlibArchive } + + { TZlibWriteArchive } + + TZlibWriteArchive = class(TObject) + private + fInputFiles: TZlibFilesList; + fOnCompress: TZlibCompressProgProc; + fOnError: TZlibErrorProc; + fStream: TStream; + fStreamOwner: Boolean; + procedure WriteHeader(AHeader: TZlibArchiveHeader); + procedure WriteTOCEntry(Entry: TTOCEntry; TOCStream: TStream); + procedure CheckStreamAssigned; + procedure DoError(ErrorCode: Integer; ErrorString: String); + function InternalCompressStream(FileIndex: Integer; InStream: TStream; OutStream: TStream): Integer; + procedure SetStream(AValue: TStream); + public + constructor Create; + destructor Destroy; override; + public + function CreateArchive: boolean; + property OnError: TZlibErrorProc read fOnError write fOnError; + property OnCompress : TZlibCompressProgProc read fOnCompress write fOnCompress; + published + property OutStream: TStream read fStream write SetStream; + property InputFiles: TZlibFilesList read fInputFiles; + end; + + { TZLibReadArchive } + + TZLibReadArchive = class(TObject) + private + fTOCList: TFpList; + fOnError: TZlibErrorProc; + fOnExtract: TZlibExtractProgProc; + fHeader: TZlibArchiveHeader; + fStream: TStream; + fFileName: String; + procedure SetStream(AStream: TStream); + procedure VerifyFile; + procedure ReadTOC; + procedure FreeTOC; + function GetCount: Integer; + function GetTOCEntry(AIndex: Integer): TTOCEntry; + procedure DoError(ErrorCode: Integer; ErrorString: String); + function InternalExtractStream(InStream: TStream;var OutStream: TStream): Integer; + function FindFilePath(const AFilePath: String): Integer; + public + constructor Create; + constructor Create(InStream: TStream); + destructor Destroy; override; + public + procedure ExtractFileToStream(AIndex: Integer; Stream: TStream); + procedure ExtractFileToStream(const AFileName: String; Stream: TStream); + procedure ExtractFileToStream(const AFileName , APath: String; Stream: TStream); + property Header: TZlibArchiveHeader read fHeader; + property FilesInArchive[Index: Integer]: TTOCEntry read GetTOCEntry; + property Count: Integer read GetCount; + property OnError: TZlibErrorProc read fOnError write fOnError; + property OnExtract: TZlibExtractProgProc read fOnExtract write fOnExtract; + published + property InStream: TStream read fStream write SetStream; + end; +const + ZLibFileType: array [0..3] of char = ('Z','A','R', #0); + + ZAR_MAJOR_VERSION : LongInt = 1; + ZAR_MINOR_VERSION : LongInt = 0; + ZAR_MICRO_VERSION : LongInt = 0; + + ERR_CORRUPT_TOC = 1; + ERR_CORRUPT_FILE = 2; + ERR_CHECKSUM_FAILED = 3; + ERR_FILENAME_NOT_FOUND = 4; + ERR_UNKOWN_ERROR = 6; + +function CompressStream(InStream: TStream; OutStream: TStream): Integer; //returns size of compressed file +function ExtractStream(InStream: TStream; OutStream: TStream): Integer; +function StreamMD5(Stream: TStream): TMD5Digest; // creates a md5digest from a tstream + +implementation + +/////////////////////////////////// +// Generic Functions // +/////////////////////////////////// + +{******************************************************************************* +* This performs an md5 sum on the file and returns it as a TMD5Digest * +* * +*******************************************************************************} +function StreamMD5(Stream: TStream): TMD5Digest; +var + Buf : array [0..1023] of byte; + Context: TMD5Context; + Count : Longint; +begin + Stream.Position := 0; + MD5Init(Context); + repeat + Count := 1024; + Count := Stream.Read(Buf, Count); + If (Count>0) then + MD5Update(Context, Buf, Count); + until (Count<1024); + MD5Final(Context, Result); +end; + +{******************************************************************************* +* This decompresses the data from InStream and Writes the decompressed data * +* to OutputStream * +*******************************************************************************} +function ExtractStream(InStream: TStream; OutStream: TStream): Integer; +var + err : integer; + z : TZstream; +const + MAX_IN_BUF_SIZE = 1024; + MAX_OUT_BUF_SIZE = 1024; +var + input_buffer : array[0..MAX_IN_BUF_SIZE-1] of byte; + output_buffer : array[0..MAX_OUT_BUF_SIZE-1] of byte; + FlushType: LongInt; +begin + Result := 0; + + FillChar(z, SizeOf(z), 0); + + FillChar(input_buffer, SizeOf(input_buffer), 0); + err := inflateInit(z); + InStream.Position := 0; + + while InStream.Position < InStream.Size do + begin + z.next_in := @input_buffer; + z.avail_in := InStream.Read(input_buffer, MAX_IN_BUF_SIZE); + + // wouldn't work for files > 2GB + //z.next_in := TMemoryStream(InStream).Memory; + //z.avail_in := InStream.Size; + if InStream.Position = InStream.Size then + FlushType := Z_FINISH + else + FlushType := Z_SYNC_FLUSH; + repeat + z.next_out := @output_buffer; + z.avail_out := MAX_OUT_BUF_SIZE; + + err := inflate(z, FlushType); + Result += OutStream.Write(output_buffer, MAX_OUT_BUF_SIZE - z.avail_out); + if err = Z_STREAM_END then Break; + until Z.avail_out > 0; + if (err <> Z_OK) and (err <> Z_BUF_ERROR) then begin + break; + end; + end; + err := inflateEnd(z); +end; + +{******************************************************************************* +* This compresses the data from InStream and Writes the compressed data * +* to OutputStream * +*******************************************************************************} +function CompressStream(InStream: TStream; OutStream: TStream): Integer; +var + err : integer; + z : TZstream; + +const + MAX_IN_BUF_SIZE = 1024; + MAX_OUT_BUF_SIZE = 1024; +var + input_buffer : array[0..MAX_IN_BUF_SIZE-1] of byte; + output_buffer : array[0..MAX_OUT_BUF_SIZE-1] of byte; + FlushType: LongInt; +begin + Result := 0; + + FillChar(input_buffer, SizeOf(input_buffer), 0); + err := deflateInit(z, -1); //default + InStream.Position := 0; + + while InStream.Position < InStream.Size do + begin + z.next_in := @input_buffer; + z.avail_in := InStream.Read(input_buffer, MAX_IN_BUF_SIZE); + + // wouldn't work for files > 2 gb :( + //z.next_in := TMemoryStream(InStream).Memory; + //z.avail_in := InStream.Size; + if InStream.Position = InStream.Size then + FlushType := Z_FINISH + else + FlushType := Z_NO_FLUSH; + repeat + z.next_out := @output_buffer; + z.avail_out := MAX_OUT_BUF_SIZE; + err := deflate(z, FlushType); + Result += OutStream.Write(output_buffer, MAX_OUT_BUF_SIZE - z.avail_out); + until Z.avail_out > 0; + + if (err <> Z_OK) and (err <> Z_BUF_ERROR) then begin + break; + end; + end; + + err := deflateEnd(z); +end; + +//////////////////////////////// +// Objects // +//////////////////////////////// + +{ TZlibArchive } + +procedure TZlibWriteArchive.WriteHeader(AHeader: TZlibArchiveHeader); +var +X: Integer; +CompressedTOCStream: TMemoryStream; +TOCStream: TMemoryStream; +Position: Int64; +TOCEntry: TTOCEntry; +FileInfo:TFileInfo; +begin + try + CheckStreamAssigned; + TOCStream := TMemoryStream.Create; + Position := 0; + OutStream.Position := 0; + for X := 0 to fInputFiles.Count-1 do begin + TOCEntry.FileName := fInputFiles.FileName[X]; + TOCEntry.FilePath := fInputFiles.Path[X]; + TOCEntry.Position := Position; + FileInfo := fInputFiles.FileInfo[X]; + TOCEntry.CompressedSize := FileInfo.CompressedSize; + TocEntry.Md5sum := FileInfo.Md5Sum; + WriteTOCEntry(TOCEntry, TOCStream); + Position += TOCEntry.CompressedSize; + end; + CompressedTOCStream:= TMemoryStream.Create; + CompressStream(TOCStream, CompressedTOCStream); + CompressedTOCStream.Position := 0; + AHeader.TOCLength := NtoLE(CompressedTOCStream.Size); + AHeader.TOCMd5Sum := StreamMd5(TOCStream); + OutStream.Write(AHeader, SizeOf(TZlibArchiveHeader)); + OutStream.CopyFrom(CompressedTOCStream, CompressedTOCStream.Size); + finally + TOCStream.Free; + CompressedTOCStream.Free; + end; +end; + +procedure TZlibWriteArchive.WriteTOCEntry(Entry: TTOCEntry; TOCStream: TStream); +var +Str: array [0..255]of char; +EmptyByte: Byte =0; +begin + Str := ExtractFileName(Entry.FileName); + TOCStream.Write(Str, Length(Trim(Str))); + TOCStream.WriteByte(EmptyByte); + Str := Entry.FilePath; + TOCStream.Write(Str, Length(Trim(Str))); + TOCStream.WriteByte(EmptyByte); + Entry.Position := NtoLE(Entry.Position); + TOCStream.Write(Entry.Position, SizeOf(Int64)); + Entry.CompressedSize := NtoLE(Entry.CompressedSize); + TOCStream.Write(Entry.CompressedSize, SizeOf(Int64)); + TOCStream.Write(Entry.Md5sum, SizeOf(TMD5Digest)); + +end; + + +procedure TZlibWriteArchive.CheckStreamAssigned; +begin + if fStream = nil then begin + fStream := TMemoryStream.Create; + fStreamOwner := True; + end; +end; + +procedure TZlibWriteArchive.DoError(ErrorCode: Integer; ErrorString: String); +var +fErrCode: Integer; +begin + fErrCode := ErrorCode; + if Assigned(fOnError) then fOnError(Self, fErrCode, ErrorString); + if fErrCode <> 0 then Raise Exception.Create('ZLibError('+IntToStr(fErrCode)+') '+ErrorString); +end; + +function TZlibWriteArchive.InternalCompressStream(FileIndex: Integer; + InStream: TStream; OutStream: TStream): Integer; +var + err : integer; + z : TZstream; + +const + MAX_IN_BUF_SIZE = 1024; + MAX_OUT_BUF_SIZE = 1024; +var + input_buffer : array[0..MAX_IN_BUF_SIZE-1] of byte; + output_buffer : array[0..MAX_OUT_BUF_SIZE-1] of byte; + FlushType: LongInt; +begin + Result := 0; + + FillChar(z, 0 , SizeOf(z)); + + FillChar(input_buffer, SizeOf(input_buffer), 0); + err := deflateInit(z, -1); //default + InStream.Position := 0; + + while InStream.Position < InStream.Size do + begin + z.next_in := @input_buffer; + z.avail_in := InStream.Read(input_buffer, MAX_IN_BUF_SIZE); + + // wouldn't work for files > 2 gb :( + //z.next_in := TMemoryStream(InStream).Memory; + //z.avail_in := InStream.Size; + if InStream.Position = InStream.Size then + FlushType := Z_FINISH + else + FlushType := Z_NO_FLUSH; + repeat + z.next_out := @output_buffer; + z.avail_out := MAX_OUT_BUF_SIZE; + err := deflate(z, FlushType); + Result += OutStream.Write(output_buffer, MAX_OUT_BUF_SIZE - z.avail_out); + until Z.avail_out > 0; + if fOnCompress <> nil then fOnCompress(Self, FileIndex, InStream.Size, InStream.Position); + if (err <> Z_OK) and (err <> Z_BUF_ERROR) then begin + break; + end; + end; + + err := deflateEnd(z); +end; + +procedure TZlibWriteArchive.SetStream(AValue: TStream); +begin + if AValue <> fStream then fStreamOwner := False; + fStream := AValue; +end; + +constructor TZlibWriteArchive.Create; +begin + fInputFiles := TZlibFilesList.Create; + fStream := nil; +end; + +destructor TZlibWriteArchive.Destroy; +begin + fInputFiles.Free; + if fStreamOwner then fStream.Free; + inherited Destroy; +end; + +function TZlibWriteArchive.CreateArchive: boolean; +var +X: Integer; +AHeader: TZlibArchiveHeader; +TmpStream: TMemoryStream; // this holds all the compressed files temporarily +//TmpFile: TMemoryStream; // this holds the current file to be added to TmpStream +TmpFile: TFileStream; // this holds the current file to be added to TmpStream +FileInfo: TFileInfo; +begin + Result := False; + try + CheckStreamAssigned; + TmpStream := TMemoryStream.Create; + + AHeader.FileType := ZLibFileType; + AHeader.MajorVersion := NtoLE(ZAR_MAJOR_VERSION); + AHeader.MinorVersion := NtoLE(ZAR_MINOR_VERSION); + AHeader.MicroVersion := NtoLE(ZAR_MICRO_VERSION); + + for X := 0 to fInputFiles.Count-1 do begin + if FileExists(fInputFiles.FileName[X]) then begin + try + TmpFile := TFileStream.Create(fInputFiles.FileName[X],fmOpenRead or fmShareDenyNone); + FileInfo.CompressedSize := InternalCompressStream(X, TmpFile, TmpStream); + FileInfo.Md5Sum := StreamMD5(TmpFile); + fInputFiles.FileInfo[X] := FileInfo;//records the compressed length/size + finally + TmpFile.Free; + end; + end; + end; + //Write file header and Table of contents + WriteHeader(AHeader); + //WriteFiles + TmpStream.Position := 0; + + OutStream.CopyFrom(TmpStream, TmpStream.Size); + Result := True; + finally + TmpStream.Free; + end; +end; + +{ TZLibReadArchive } + +procedure TZLibReadArchive.SetStream(AStream: TStream); +begin + fStream := AStream; + if AStream <> nil then begin + fStream.Position := 0; + fStream.Read(fHeader,SizeOf(TZlibArchiveHeader)); + fHeader.MajorVersion := LEtoN(Header.MajorVersion); + fHeader.MinorVersion := LEtoN(Header.MinorVersion); + fHeader.MicroVersion := LetoN(Header.MicroVersion); + fHeader.TOCLength := LEtoN(Header.TOCLength); + VerifyFile; + ReadTOC; + end + else begin + FreeTOC; + end; +end; + +procedure TZLibReadArchive.VerifyFile; +begin + if (fHeader.FileType <> ZLibFileType) then DoError(ERR_CORRUPT_FILE,'corrupt file or not a correct file type'); +end; + +procedure TZLibReadArchive.ReadTOC; +var +Entry: PTOCEntry; +PositionOffset: Int64; +fChar: Char; +TmpStream: TMemoryStream; // used to temporarily hold the compressed TOC +TOCStream: TMemoryStream; // the TOC will be extracted into this +begin + TmpStream:= TMemoryStream.Create; + TOCStream := TMemoryStream.Create; + try + fStream.Position := SizeOf(fHeader); + //Read The Compressed TOC into the TmpStream from the main fStream + TmpStream.CopyFrom(fStream, fHeader.TOCLength); + //Decompress TOC into TOCStream + ExtractStream(TmpStream, TOCStream); + if MD5Match(fHeader.TOCMD5Sum, StreamMd5(TOCStream)) = False then DoError(ERR_CORRUPT_TOC, 'corrupted table of contents'); + + TOCStream.Position := 0; + PositionOffset := fHeader.TOCLength + SizeOf(fHeader); + while TOCStream.Position <> TOCStream.Size do begin + Entry := New(pTocEntry); + fTOCList.Add(Entry); + // Read FileName + fChar := Char(TOCStream.ReadByte); + while fChar <> #0 do begin + Entry^.FileName += fChar; + fChar := Char(TOCStream.ReadByte); + end; + //Read FilePath + fChar := Char(TOCStream.ReadByte); + while fChar <> #0 do begin + Entry^.FilePath += fChar; + fChar := Char(TOCStream.ReadByte); + end; + //Read Position + TOCStream.Read(Entry^.Position, SizeOf(Int64)); + Entry^.Position := LEtoN(Entry^.Position) + PositionOffset; + //Read Compressed Size + TOCStream.Read(Entry^.CompressedSize, SizeOf(Int64)); + Entry^.CompressedSize := LEtoN(Entry^.CompressedSize); + //Read Md5sum + TOCStream.Read(Entry^.Md5sum, SizeOf(TMD5Digest)); + end; + finally + TmpStream.Free; + end; +end; + +procedure TZLibReadArchive.FreeTOC; +var +X: Integer; +begin + for X := 0 to fTOCList.Count-1 do begin + Dispose(PTOCEntry(fTocList.Items[X])); + fTocList.Items[X] := nil; + end; + fTOCList.Clear; +end; + +function TZLibReadArchive.GetCount: Integer; +begin + Result := fTOCList.Count; +end; + +function TZLibReadArchive.GetTOCEntry(AIndex: Integer): TTOCEntry; +begin + Result := PTOCEntry(fTOCList.Items[AIndex])^; +end; + +procedure TZLibReadArchive.DoError(ErrorCode: Integer; ErrorString: String); +var +fErrCode: Integer; +begin + fErrCode := ErrorCode; + if Assigned(fOnError) then fOnError(Self, fErrCode, ErrorString); + if fErrCode <> 0 then Raise Exception.Create('ZLibError('+IntToStr(fErrCode)+') '+ErrorString); +end; + +function TZLibReadArchive.InternalExtractStream(InStream: TStream; + var OutStream: TStream): Integer; +var + err : integer; + z : TZstream; +const + MAX_IN_BUF_SIZE = 1024; + MAX_OUT_BUF_SIZE = 1024; +var + input_buffer : array[0..MAX_IN_BUF_SIZE-1] of byte; + output_buffer : array[0..MAX_OUT_BUF_SIZE-1] of byte; + FlushType: LongInt; +begin + Result := 0; + + FillChar(z, 0 , SizeOf(z)); + + FillChar(input_buffer, SizeOf(input_buffer), 0); + err := inflateInit(z); + InStream.Position := 0; + while InStream.Position < InStream.Size do + begin + z.next_in := @input_buffer; + z.avail_in := InStream.Read(input_buffer, MAX_IN_BUF_SIZE); + + // wouldn't work for files > 2GB + //z.next_in := TMemoryStream(InStream).Memory; + //z.avail_in := InStream.Size; + if InStream.Position = InStream.Size then + FlushType := Z_FINISH + else + FlushType := Z_SYNC_FLUSH; + repeat + z.next_out := @output_buffer; + z.avail_out := MAX_OUT_BUF_SIZE; + + err := inflate(z, FlushType); + Result += OutStream.Write(output_buffer, MAX_OUT_BUF_SIZE - z.avail_out); + if err = Z_STREAM_END then Break; + until Z.avail_out > 0; + if fOnExtract <> nil then fOnExtract(Self, InStream.Size, InStream.Position); + if (err <> Z_OK) and (err <> Z_BUF_ERROR) then begin + break; + end; + end; + err := inflateEnd(z); +end; + +function TZLibReadArchive.FindFilePath(const AFilePath: String): Integer; +var + i: Integer; +begin + Result:= -1; + for i:= 0 to fTOCList.Count - 1 do begin + if AFilePath = PTOCEntry(fTOCList[i])^.FilePath+PTOCEntry(fTOCList[i])^.FileName then + begin + Result:=i; + Break; + end; + end; +end; + +constructor TZLibReadArchive.Create; +begin + fStream := TMemoryStream.Create; + fFileName := ''; + fTOCList := TFpList.Create; +end; + +constructor TZLibReadArchive.Create(InStream: TStream); +begin + Create; + SetStream(InStream); +end; + +destructor TZLibReadArchive.Destroy; +begin + FreeTOC; + fTOCList.Free; + inherited Destroy; +end; + +procedure TZLibReadArchive.ExtractFileToStream(AIndex: Integer; Stream: TStream); +var +TmpStream: TMemoryStream; +Md5Sum: TMD5Digest; +begin + if Stream = nil then Stream := TMemoryStream.Create; + Stream.Position := 0; + Stream.Size := 0; + TmpStream := TMemoryStream.Create; + try + // Move to the position of the compressed file in the archive + fStream.Position := FilesInArchive[AIndex].Position; + // read the compressed file into a temp stream + TmpStream.CopyFrom(fStream, FilesInArchive[AIndex].CompressedSize); + // decompress the tmp stream into the output stream + InternalExtractStream(TmpStream, Stream); + //Check Md5 sum + Md5Sum := StreamMD5(Stream); + if not MD5Match(Md5Sum, FilesInArchive[AIndex].Md5sum) then begin + DoError(ERR_CHECKSUM_FAILED, 'Saved=' + MD5Print(FilesInArchive[AIndex].Md5sum) +' Found='+ MD5Print(Md5sum)); + end; + finally + TmpStream.Free; + end; + +end; + +procedure TZLibReadArchive.ExtractFileToStream(const AFileName: String; Stream: TStream); +begin + ExtractFileToStream(AFileName,'/',Stream); +end; + +procedure TZLibReadArchive.ExtractFileToStream(const AFileName, APath: String; Stream: TStream); +var + i: Integer; +begin + i:=FindFilePath(APath+AFileName); + if i <> -1 then + ExtractFileToStream(i,Stream) + else + DoError(ERR_FILENAME_NOT_FOUND,'Could not find '+APath+AFileName+' in '+fFileName); +end; + +{ TZlibFilesList } + +function TZlibFilesList.GetFileName(AIndex: Integer): String; +begin + Result := PString(FFileList.Items[AIndex])^; +end; + +function TZlibFilesList.GetPath(AIndex: Integer): String; +begin + Result := PString(FPathList.Items[AIndex])^; +end; + +procedure TZlibFilesList.SetFileName(AIndex: Integer; AFIleName: String); +begin + PString(FFileList.Items[AIndex])^ := AFileName; +end; + +procedure TZlibFilesList.SetPath(AIndex: Integer; APath: String); +begin + PString(FPathList.Items[AIndex])^ := APath; +end; + +function TZlibFilesList.GetFileInfo(AIndex: Integer): TFileInfo; +begin + Result := PFileInfo(FFileInfoList.Items[AIndex])^; +end; + +procedure TZlibFilesList.SetFileInfo(AIndex: Integer; AFileInfo: TFileInfo); +begin + PFileInfo(FFileInfoList.Items[AIndex])^ := AFileInfo; +end; + +constructor TZlibFilesList.Create; +begin + FFileList := TFpList.Create; + FPathList := TFpList.Create; + FFileInfoList := TFpList.Create; +end; + +destructor TZlibFilesList.Destroy; +begin + Clear; + Inherited Destroy; +end; + +function TZlibFilesList.Add(AFileName: String): Integer; +begin + Result := InsertPath(Count, AFileName,'/'); +end; + +function TZlibFilesList.AddPath(AFileName: String; APath: String): Integer; +begin + Result := InsertPath(Count, AFileName, APath); +end; + +function TZlibFilesList.Insert(AIndex: Integer; AFileName: String): Integer; +begin + Result := InsertPath(AIndex, AFileName, '/'); +end; + +function TZlibFilesList.InsertPath(AIndex: Integer; AFileName: String; + APath: String): Integer; +var +FFile, +FPath: PString; +FFileInfo: PFileInfo; +begin + Result := 0; + if AIndex > Count then Result := Count + else Result := AIndex; + + FFile := New(PString); + FPath := New(PString); + FFileInfo := New(PFileInfo); + + FFile^ := AFileName; + FPath^ := APAth; + + FFileList.Insert(AIndex, FFile); + FPathList.Insert(AIndex, FPath); + FFileInfoList.Insert(AIndex, FFileInfo); +end; + +procedure TZlibFilesList.Delete(AIndex: Integer); +begin + Dispose(PString(FFileList.Items[AIndex])); + Dispose(PString(FPathList.Items[AIndex])); + Dispose(PFileInfo(FFileInfoList.Items[AIndex])); + + FFileList.Delete(AIndex); + FPathList.Delete(AIndex); + FFileInfoList.Delete(AIndex); +end; + +procedure TZlibFilesList.Clear; +begin + While Count > 0 do + Delete(Count-1); +end; + +function TZlibFilesList.Count: Integer; +begin + Result := FFileList.Count; +end; + +end. + + diff --git a/components/zlibar/zlibar_package.lpk b/components/zlibar/zlibar_package.lpk new file mode 100755 index 000000000..64ff5bace --- /dev/null +++ b/components/zlibar/zlibar_package.lpk @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/zlibar/zlibar_package.pas b/components/zlibar/zlibar_package.pas new file mode 100755 index 000000000..ac09b61d8 --- /dev/null +++ b/components/zlibar/zlibar_package.pas @@ -0,0 +1,14 @@ +{ This file was automatically created by Lazarus. Do not edit! +This source is only used to compile and install the package. + } + +unit zlibar_package; + +interface + +uses + zlibar; + +implementation + +end.