diff --git a/7z.dll b/7z.dll new file mode 100644 index 0000000..b662e5e Binary files /dev/null and b/7z.dll differ diff --git a/readme.htm b/readme.htm new file mode 100644 index 0000000..772a4ee --- /dev/null +++ b/readme.htm @@ -0,0 +1,44 @@ + +Fragment +of main.html + + + +

7-zip +Delphi API

+

This API use the 7-zip dll (7z.dll) to read and write all 7-zip +supported archive formats.

- Autor: Henri Gourvest <hgourvest@progdigy.com>
- Licence: MPL1.1
- Date: 15/04/2009
- Version: 1.1

+

Reading archive:

+

Extract to path:

+
 with CreateInArchive(CLSID_CFormatZip) do
begin
OpenFile('c:\test.zip');
ExtractTo(
'c:\test');
end;

Get +file list:

+
 with CreateInArchive(CLSID_CFormat7z) do
begin
OpenFile('c:\test.7z');
for i := 0 to NumberOfItems - 1 do
if not ItemIsFolder[i] then
Writeln(ItemPath[i]);
end;

Extract +to stream

+
 with CreateInArchive(CLSID_CFormat7z) do
begin
OpenFile('c:\test.7z');
for i := 0 to NumberOfItems - 1 do
if not ItemIsFolder[i] then
ExtractItem(i, stream, false);
end;

Extract +"n" Items

+
function GetStreamCallBack(sender: Pointer; index: Cardinal;
var outStream: ISequentialOutStream): HRESULT; stdcall;
begin
case index of ...
outStream := T7zStream.Create(aStream, soReference);
Result := S_OK;
end;

procedure TMainForm.ExtractClick(Sender: TObject);
var
i: integer;
items:
array[0..2] of Cardinal;
begin
with CreateInArchive(CLSID_CFormat7z) do
begin
OpenFile('c:\test.7z');
// items must be sorted by index!
 items[0] := 0;
items[
1] := 1;
items[
2] := 2;
ExtractItems(@items, Length(items), false,
nil, GetStreamCallBack);
end;
end;

Open +stream

+
 with CreateInArchive(CLSID_CFormatZip) do
begin
OpenStream(T7zStream.Create(TFileStream.Create('c:\test.zip', fmOpenRead), soOwned));
OpenStream(aStream, soReference);
...
end;

Progress +bar

+
 function ProgressCallback(sender: Pointer; total: boolean; value: int64): HRESULT; stdcall;
begin
if total then
Mainform.ProgressBar.Max := value else
Mainform.ProgressBar.Position := value;
Result := S_OK;
end;

procedure TMainForm.ExtractClick(Sender: TObject);
begin
with CreateInArchive(CLSID_CFormatZip) do
begin
OpenFile('c:\test.zip');
SetProgressCallback(
nil, ProgressCallback);
...
end;
end;

Password

+
 function PasswordCallback(sender: Pointer; var password: WideString): HRESULT; stdcall;
begin
// call a dialog box ...
  password := 'password';
Result := S_OK;
end;

procedure TMainForm.ExtractClick(Sender: TObject);
begin
with CreateInArchive(CLSID_CFormatZip) do
begin
// using callback
SetPasswordCallback(nil, PasswordCallback);
// or setting password directly
SetPassword('password');
OpenFile(
'c:\test.zip');
...
end;
end;

Writing +archive

+
 procedure TMainForm.ExtractAllClick(Sender: TObject);
var
Arch: I7zOutArchive;
begin
Arch := CreateOutArchive(CLSID_CFormat7z);
// add a file
Arch.AddFile('c:\test.bin', 'folder\test.bin');
// add files using willcards and recursive search
Arch.AddFiles('c:\test', 'folder', '*.pas;*.dfm', true);
// add a stream
Arch.AddStream(aStream, soReference, faArchive, CurrentFileTime, CurrentFileTime, 'folder\test.bin', false, false);
// compression level
SetCompressionLevel(Arch, 5);
// compression method if <> LZMA
SevenZipSetCompressionMethod(Arch, m7BZip2);
// add a progress bar ...
Arch.SetProgressCallback(...);
// set a password if necessary
Arch.SetPassword('password');
// Save to file
Arch.SaveToFile('c:\test.zip');
// or a stream
Arch.SaveToStream(aStream);
end;
+
+ \ No newline at end of file diff --git a/sevenzip.pas b/sevenzip.pas new file mode 100644 index 0000000..5c1a1e5 --- /dev/null +++ b/sevenzip.pas @@ -0,0 +1,1644 @@ +(********************************************************************************) +(* 7-ZIP DELPHI API *) +(* *) +(* 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. *) +(* *) +(* Unit owner : Henri Gourvest *) +(* V1.1 *) +(********************************************************************************) + +unit sevenzip; +{$ALIGN ON} +{$MINENUMSIZE 4} +{$WARN SYMBOL_PLATFORM OFF} + +interface +uses SysUtils, Windows, ActiveX, Classes, Contnrs; + +type + PVarType = ^TVarType; + PCardArray = ^TCardArray; + TCardArray = array[0..MaxInt div SizeOf(Cardinal) - 1] of Cardinal; + +{$IFNDEF UNICODE} + UnicodeString = WideString; +{$ENDIF} + +//****************************************************************************** +// PropID.h +//****************************************************************************** + +const + kpidNoProperty = 0; + + kpidHandlerItemIndex = 2; + kpidPath = 3; // VT_BSTR + kpidName = 4; // VT_BSTR + kpidExtension = 5; // VT_BSTR + kpidIsFolder = 6; // VT_BOOL + kpidSize = 7; // VT_UI8 + kpidPackedSize = 8; // VT_UI8 + kpidAttributes = 9; // VT_UI4 + kpidCreationTime = 10; // VT_FILETIME + kpidLastAccessTime = 11; // VT_FILETIME + kpidLastWriteTime = 12; // VT_FILETIME + kpidSolid = 13; // VT_BOOL + kpidCommented = 14; // VT_BOOL + kpidEncrypted = 15; // VT_BOOL + kpidSplitBefore = 16; // VT_BOOL + kpidSplitAfter = 17; // VT_BOOL + kpidDictionarySize = 18; // VT_UI4 + kpidCRC = 19; // VT_UI4 + kpidType = 20; // VT_BSTR + kpidIsAnti = 21; // VT_BOOL + kpidMethod = 22; // VT_BSTR + kpidHostOS = 23; // VT_BSTR + kpidFileSystem = 24; // VT_BSTR + kpidUser = 25; // VT_BSTR + kpidGroup = 26; // VT_BSTR + kpidBlock = 27; // VT_UI4 + kpidComment = 28; // VT_BSTR + kpidPosition = 29; // VT_UI4 + kpidPrefix = 30; // VT_BSTR + kpidNumSubDirs = 31; // VT_UI4 + kpidNumSubFiles = 32; // VT_UI4 + kpidUnpackVer = 33; // VT_UI1 + kpidVolume = 34; // VT_UI4 + kpidIsVolume = 35; // VT_BOOL + kpidOffset = 36; // VT_UI8 + kpidLinks = 37; // VT_UI4 + kpidNumBlocks = 38; // VT_UI4 + kpidNumVolumes = 39; // VT_UI4 + kpidTimeType = 40; // + kpidBit64 = 41; // VT_BOOL + kpidBigEndian = 42; // VT_BOOL + kpidCpu = 43; // VT_BSTR + kpidPhySize = 44; // VT_UI8 + kpidHeadersSize = 45; // VT_UI8 + kpidChecksum = 46; // VT_UI4 + kpidCharacts = 47; // VT_BSTR + kpidVa = 48; // VT_UI8 + + + kpidTotalSize = $1100; // VT_UI8 + kpidFreeSpace = kpidTotalSize + 1; // VT_UI8 + kpidClusterSize = kpidFreeSpace + 1; // VT_UI8 + kpidVolumeName = kpidClusterSize + 1; // VT_BSTR + + kpidLocalName = $1200; // VT_BSTR + kpidProvider = kpidLocalName + 1; // VT_BSTR + + kpidUserDefined = $10000; + +//****************************************************************************** +// IProgress.h +//****************************************************************************** +type + IProgress = interface(IUnknown) + ['{23170F69-40C1-278A-0000-000000050000}'] + function SetTotal(total: Int64): HRESULT; stdcall; + function SetCompleted(completeValue: PInt64): HRESULT; stdcall; + end; + +//****************************************************************************** +// IPassword.h +//****************************************************************************** + + ICryptoGetTextPassword = interface(IUnknown) + ['{23170F69-40C1-278A-0000-000500100000}'] + function CryptoGetTextPassword(var password: TBStr): HRESULT; stdcall; + end; + + ICryptoGetTextPassword2 = interface(IUnknown) + ['{23170F69-40C1-278A-0000-000500110000}'] + function CryptoGetTextPassword2(passwordIsDefined: PInteger; var password: TBStr): HRESULT; stdcall; + end; + +//****************************************************************************** +// IStream.h +// "23170F69-40C1-278A-0000-000300xx0000" +//****************************************************************************** + + ISequentialInStream = interface(IUnknown) + ['{23170F69-40C1-278A-0000-000300010000}'] + function Read(data: Pointer; size: Cardinal; processedSize: PCardinal): HRESULT; stdcall; + (* + Out: if size != 0, return_value = S_OK and (*processedSize == 0), + then there are no more bytes in stream. + if (size > 0) && there are bytes in stream, + this function must read at least 1 byte. + This function is allowed to read less than number of remaining bytes in stream. + You must call Read function in loop, if you need exact amount of data + *) + end; + + ISequentialOutStream = interface(IUnknown) + ['{23170F69-40C1-278A-0000-000300020000}'] + function Write(data: Pointer; size: Cardinal; processedSize: PCardinal): HRESULT; stdcall; + (* + if (size > 0) this function must write at least 1 byte. + This function is allowed to write less than "size". + You must call Write function in loop, if you need to write exact amount of data + *) + end; + + IInStream = interface(ISequentialInStream) + ['{23170F69-40C1-278A-0000-000300030000}'] + function Seek(offset: Int64; seekOrigin: Cardinal; newPosition: PInt64): HRESULT; stdcall; + end; + + IOutStream = interface(ISequentialOutStream) + ['{23170F69-40C1-278A-0000-000300040000}'] + function Seek(offset: Int64; seekOrigin: Cardinal; newPosition: PInt64): HRESULT; stdcall; + function SetSize(newSize: Int64): HRESULT; stdcall; + end; + + IStreamGetSize = interface(IUnknown) + ['{23170F69-40C1-278A-0000-000300060000}'] + function GetSize(size: PInt64): HRESULT; stdcall; + end; + + IOutStreamFlush = interface(IUnknown) + ['{23170F69-40C1-278A-0000-000300070000}'] + function Flush: HRESULT; stdcall; + end; + +//****************************************************************************** +// IArchive.h +//****************************************************************************** + +// MIDL_INTERFACE("23170F69-40C1-278A-0000-000600xx0000") +//#define ARCHIVE_INTERFACE_SUB(i, base, x) \ +//DEFINE_GUID(IID_ ## i, \ +//0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x06, 0x00, x, 0x00, 0x00); \ +//struct i: public base + +//#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x) + +type +// NFileTimeType + NFileTimeType = ( + kWindows = 0, + kUnix, + kDOS + ); + +// NArchive:: + NArchive = ( + kName = 0, // string + kClassID, // GUID + kExtension, // string zip rar gz + kAddExtension, // sub archive: tar + kUpdate, // bool + kKeepName, // bool + kStartSignature, // string[4] ex: PK.. 7z.. Rar! + kFinishSignature, + kAssociate + ); + +// NArchive::NExtract::NAskMode + NAskMode = ( + kExtract = 0, + kTest, + kSkip + ); + +// NArchive::NExtract::NOperationResult + NExtOperationResult = ( + kOK = 0, + kUnSupportedMethod, + kDataError, + kCRCError + ); + +// NArchive::NUpdate::NOperationResult + NUpdOperationResult = ( + kOK_ = 0, + kError + ); + + IArchiveOpenCallback = interface + ['{23170F69-40C1-278A-0000-000600100000}'] + function SetTotal(files, bytes: PInt64): HRESULT; stdcall; + function SetCompleted(files, bytes: PInt64): HRESULT; stdcall; + end; + + IArchiveExtractCallback = interface(IProgress) + ['{23170F69-40C1-278A-0000-000600200000}'] + function GetStream(index: Cardinal; var outStream: ISequentialOutStream; + askExtractMode: NAskMode): HRESULT; stdcall; + // GetStream OUT: S_OK - OK, S_FALSE - skeep this file + function PrepareOperation(askExtractMode: NAskMode): HRESULT; stdcall; + function SetOperationResult(resultEOperationResult: NExtOperationResult): HRESULT; stdcall; + end; + + IArchiveOpenVolumeCallback = interface + ['{23170F69-40C1-278A-0000-000600300000}'] + function GetProperty(propID: PROPID; var value: OleVariant): HRESULT; stdcall; + function GetStream(const name: PWideChar; var inStream: IInStream): HRESULT; stdcall; + end; + + IInArchiveGetStream = interface + ['{23170F69-40C1-278A-0000-000600400000}'] + function GetStream(index: Cardinal; var stream: ISequentialInStream ): HRESULT; stdcall; + end; + + IArchiveOpenSetSubArchiveName = interface + ['{23170F69-40C1-278A-0000-000600500000}'] + function SetSubArchiveName(name: PWideChar): HRESULT; stdcall; + end; + + IInArchive = interface + ['{23170F69-40C1-278A-0000-000600600000}'] + function Open(stream: IInStream; const maxCheckStartPosition: PInt64; + openArchiveCallback: IArchiveOpenCallback): HRESULT; stdcall; + function Close: HRESULT; stdcall; + function GetNumberOfItems(var numItems: CArdinal): HRESULT; stdcall; + function GetProperty(index: Cardinal; propID: PROPID; var value: OleVariant): HRESULT; stdcall; + function Extract(indices: PCardArray; numItems: Cardinal; + testMode: Integer; extractCallback: IArchiveExtractCallback): HRESULT; stdcall; + // indices must be sorted + // numItems = 0xFFFFFFFF means all files + // testMode != 0 means "test files operation" + + function GetArchiveProperty(propID: PROPID; var value: OleVariant): HRESULT; stdcall; + + function GetNumberOfProperties(numProperties: PCardinal): HRESULT; stdcall; + function GetPropertyInfo(index: Cardinal; + name: PBSTR; propID: PPropID; varType: PVarType): HRESULT; stdcall; + + function GetNumberOfArchiveProperties(var numProperties: Cardinal): HRESULT; stdcall; + function GetArchivePropertyInfo(index: Cardinal; + name: PBSTR; propID: PPropID; varType: PVARTYPE): HRESULT; stdcall; + end; + + IArchiveUpdateCallback = interface(IProgress) + ['{23170F69-40C1-278A-0000-000600800000}'] + function GetUpdateItemInfo(index: Cardinal; + newData: PInteger; // 1 - new data, 0 - old data + newProperties: PInteger; // 1 - new properties, 0 - old properties + indexInArchive: PCardinal // -1 if there is no in archive, or if doesn't matter + ): HRESULT; stdcall; + function GetProperty(index: Cardinal; propID: PROPID; var value: OleVariant): HRESULT; stdcall; + function GetStream(index: Cardinal; var inStream: ISequentialInStream): HRESULT; stdcall; + function SetOperationResult(operationResult: Integer): HRESULT; stdcall; + end; + + IArchiveUpdateCallback2 = interface(IArchiveUpdateCallback) + ['{23170F69-40C1-278A-0000-000600820000}'] + function GetVolumeSize(index: Cardinal; size: PInt64): HRESULT; stdcall; + function GetVolumeStream(index: Cardinal; var volumeStream: ISequentialOutStream): HRESULT; stdcall; + end; + + IOutArchive = interface + ['{23170F69-40C1-278A-0000-000600A00000}'] + function UpdateItems(outStream: ISequentialOutStream; numItems: Cardinal; + updateCallback: IArchiveUpdateCallback): HRESULT; stdcall; + function GetFileTimeType(type_: PCardinal): HRESULT; stdcall; + end; + + ISetProperties = interface + ['{23170F69-40C1-278A-0000-000600030000}'] + function SetProperties(names: PPWideChar; values: PPROPVARIANT; numProperties: Integer): HRESULT; stdcall; + end; + +//****************************************************************************** +// ICoder.h +// "23170F69-40C1-278A-0000-000400xx0000" +//****************************************************************************** + + ICompressProgressInfo = interface + ['{23170F69-40C1-278A-0000-000400040000}'] + function SetRatioInfo(inSize, outSize: PInt64): HRESULT; stdcall; + end; + + ICompressCoder = interface + ['{23170F69-40C1-278A-0000-000400050000}'] + function Code(inStream, outStream: ISequentialInStream; + inSize, outSize: PInt64; + progress: ICompressProgressInfo): HRESULT; stdcall; + end; + + ICompressCoder2 = interface + ['{23170F69-40C1-278A-0000-000400180000}'] + function Code(var inStreams: ISequentialInStream; + var inSizes: PInt64; + numInStreams: Cardinal; + var outStreams: ISequentialOutStream; + var outSizes: PInt64; + numOutStreams: Cardinal; + progress: ICompressProgressInfo): HRESULT; stdcall; + end; + +const +//NCoderPropID:: + kDictionarySize = $400; + kUsedMemorySize = kDictionarySize + 1; + kOrder = kUsedMemorySize + 1; + kPosStateBits = $440; + kLitContextBits = kPosStateBits + 1; + kLitPosBits = kLitContextBits + 1; + kNumFastBytes = $450; + kMatchFinder = kNumFastBytes + 1; + kMatchFinderCycles = kMatchFinder + 1; + kNumPasses = $460; + kAlgorithm = $470; + kMultiThread = $480; + kNumThreads = kMultiThread + 1; + kEndMarker = $490; + +type + ICompressSetCoderProperties = interface + ['{23170F69-40C1-278A-0000-000400200000}'] + function SetCoderProperties(propIDs: PPropID; + properties: PROPVARIANT; numProperties: Cardinal): HRESULT; stdcall; + end; + +(* +CODER_INTERFACE(ICompressSetCoderProperties, 0x21) +{ + STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE; +}; +*) + + ICompressSetDecoderProperties2 = interface + ['{23170F69-40C1-278A-0000-000400220000}'] + function SetDecoderProperties2(data: PByte; size: Cardinal): HRESULT; stdcall; + end; + + ICompressWriteCoderProperties = interface + ['{23170F69-40C1-278A-0000-000400230000}'] + function WriteCoderProperties(outStreams: ISequentialOutStream): HRESULT; stdcall; + end; + + ICompressGetInStreamProcessedSize = interface + ['{23170F69-40C1-278A-0000-000400240000}'] + function GetInStreamProcessedSize(value: PInt64): HRESULT; stdcall; + end; + + ICompressSetCoderMt = interface + ['{23170F69-40C1-278A-0000-000400250000}'] + function SetNumberOfThreads(numThreads: Cardinal): HRESULT; stdcall; + end; + + ICompressGetSubStreamSize = interface + ['{23170F69-40C1-278A-0000-000400300000}'] + function GetSubStreamSize(subStream: Int64; value: PInt64): HRESULT; stdcall; + end; + + ICompressSetInStream = interface + ['{23170F69-40C1-278A-0000-000400310000}'] + function SetInStream(inStream: ISequentialInStream): HRESULT; stdcall; + function ReleaseInStream: HRESULT; stdcall; + end; + + ICompressSetOutStream = interface + ['{23170F69-40C1-278A-0000-000400320000}'] + function SetOutStream(outStream: ISequentialOutStream): HRESULT; stdcall; + function ReleaseOutStream: HRESULT; stdcall; + end; + + ICompressSetInStreamSize = interface + ['{23170F69-40C1-278A-0000-000400330000}'] + function SetInStreamSize(inSize: PInt64): HRESULT; stdcall; + end; + + ICompressSetOutStreamSize = interface + ['{23170F69-40C1-278A-0000-000400340000}'] + function SetOutStreamSize(outSize: PInt64): HRESULT; stdcall; + end; + + ICompressFilter = interface + ['{23170F69-40C1-278A-0000-000400400000}'] + function Init: HRESULT; stdcall; + function Filter(data: PByte; size: Cardinal): Cardinal; stdcall; + // Filter return outSize (Cardinal) + // if (outSize <= size): Filter have converted outSize bytes + // if (outSize > size): Filter have not converted anything. + // and it needs at least outSize bytes to convert one block + // (it's for crypto block algorithms). + end; + + ICryptoProperties = interface + ['{23170F69-40C1-278A-0000-000400800000}'] + function SetKey(Data: PByte; size: Cardinal): HRESULT; stdcall; + function SetInitVector(data: PByte; size: Cardinal): HRESULT; stdcall; + end; + + ICryptoSetPassword = interface + ['{23170F69-40C1-278A-0000-000400900000}'] + function CryptoSetPassword(data: PByte; size: Cardinal): HRESULT; stdcall; + end; + + ICryptoSetCRC = interface + ['{23170F69-40C1-278A-0000-000400A00000}'] + function CryptoSetCRC(crc: Cardinal): HRESULT; stdcall; + end; + +////////////////////// +// It's for DLL file +//NMethodPropID:: + NMethodPropID = ( + kID = 0, + kName_, + kDecoder, + kEncoder, + kInStreams, + kOutStreams, + kDescription + ); + +//****************************************************************************** +// CLASSES +//****************************************************************************** + + T7zPasswordCallback = function(sender: Pointer; var password: UnicodeString): HRESULT; stdcall; + T7zGetStreamCallBack = function(sender: Pointer; index: Cardinal; + var outStream: ISequentialOutStream): HRESULT; stdcall; + T7zProgressCallback = function(sender: Pointer; total: boolean; value: int64): HRESULT; stdcall; + + I7zInArchive = interface + ['{022CF785-3ECE-46EF-9755-291FA84CC6C9}'] + procedure OpenFile(const filename: string); stdcall; + procedure OpenStream(stream: IInStream); stdcall; + procedure Close; stdcall; + function GetNumberOfItems: Cardinal; stdcall; + function GetItemPath(const index: integer): UnicodeString; stdcall; + function GetItemName(const index: integer): UnicodeString; stdcall; + function GetItemSize(const index: integer): Cardinal; stdcall; + function GetItemIsFolder(const index: integer): boolean; stdcall; + function GetInArchive: IInArchive; + procedure ExtractItem(const item: Cardinal; Stream: TStream; test: longbool); stdcall; + procedure ExtractItems(items: PCardArray; count: cardinal; test: longbool; + sender: pointer; callback: T7zGetStreamCallBack); stdcall; + procedure ExtractAll(test: longbool; sender: pointer; callback: T7zGetStreamCallBack); stdcall; + procedure ExtractTo(const path: string); stdcall; + procedure SetPasswordCallback(sender: Pointer; callback: T7zPasswordCallback); stdcall; + procedure SetPassword(const password: UnicodeString); stdcall; + procedure SetProgressCallback(sender: Pointer; callback: T7zProgressCallback); stdcall; + procedure SetClassId(const classid: TGUID); + function GetClassId: TGUID; + property ClassId: TGUID read GetClassId write SetClassId; + property NumberOfItems: Cardinal read GetNumberOfItems; + property ItemPath[const index: integer]: UnicodeString read GetItemPath; + property ItemName[const index: integer]: UnicodeString read GetItemName; + property ItemSize[const index: integer]: Cardinal read GetItemSize; + property ItemIsFolder[const index: integer]: boolean read GetItemIsFolder; + property InArchive: IInArchive read GetInArchive; + end; + + I7zOutArchive = interface + ['{BAA9D5DC-9FF4-4382-9BFD-EC9065BD0125}'] + procedure AddStream(Stream: TStream; Ownership: TStreamOwnership; Attributes: Cardinal; + CreationTime, LastWriteTime: TFileTime; const Path: UnicodeString; + IsFolder, IsAnti: boolean); stdcall; + procedure AddFile(const Filename: TFileName; const Path: UnicodeString); stdcall; + procedure AddFiles(const Dir, Path, Willcards: string; recurse: boolean); stdcall; + procedure SaveToFile(const FileName: TFileName); stdcall; + procedure SaveToStream(stream: TStream); stdcall; + procedure SetProgressCallback(sender: Pointer; callback: T7zProgressCallback); stdcall; + procedure CrearBatch; stdcall; + procedure SetPassword(const password: UnicodeString); stdcall; + procedure SetPropertie(name: UnicodeString; value: OleVariant); stdcall; + procedure SetClassId(const classid: TGUID); + function GetClassId: TGUID; + property ClassId: TGUID read GetClassId write SetClassId; + end; + + I7zCodec = interface + ['{AB48F772-F6B1-411E-907F-1567DB0E93B3}'] + + end; + + + T7zStream = class(TInterfacedObject, IInStream, IStreamGetSize, + ISequentialOutStream, ISequentialInStream, IOutStream, IOutStreamFlush) + private + FStream: TStream; + FOwnership: TStreamOwnership; + protected + function Read(data: Pointer; size: Cardinal; processedSize: PCardinal): HRESULT; stdcall; + function Seek(offset: Int64; seekOrigin: Cardinal; newPosition: Pint64): HRESULT; stdcall; + function GetSize(size: PInt64): HRESULT; stdcall; + function SetSize(newSize: Int64): HRESULT; stdcall; + function Write(data: Pointer; size: Cardinal; processedSize: PCardinal): HRESULT; stdcall; + function Flush: HRESULT; stdcall; + public + constructor Create(Stream: TStream; Ownership: TStreamOwnership = soReference); + destructor Destroy; override; + end; + + // I7zOutArchive property setters +type + TZipCompressionMethod = (mzCopy, mzDeflate, mzDeflate64, mzBZip2); + T7zCompressionMethod = (m7Copy, m7LZMA, m7BZip2, m7PPMd, m7Deflate, m7Deflate64); + // ZIP 7z GZIP BZ2 + procedure SetCompressionLevel(Arch: I7zOutArchive; level: Cardinal); // X X X X + procedure SetMultiThreading(Arch: I7zOutArchive; ThreadCount: Cardinal); // X X X + + procedure SetCompressionMethod(Arch: I7zOutArchive; method: TZipCompressionMethod); // X + procedure SetDictionnarySize(Arch: I7zOutArchive; size: Cardinal); // < 32 // X X + procedure SetDeflateNumPasses(Arch: I7zOutArchive; pass: Cardinal); // X X X + procedure SetNumFastBytes(Arch: I7zOutArchive; fb: Cardinal); // X X + procedure SetNumMatchFinderCycles(Arch: I7zOutArchive; mc: Cardinal); // X X + + procedure SevenZipSetCompressionMethod(Arch: I7zOutArchive; method: T7zCompressionMethod); // X + procedure SevenZipSetBindInfo(Arch: I7zOutArchive; const bind: UnicodeString); // X + procedure SevenZipSetSolidSettings(Arch: I7zOutArchive; solid: boolean); // X + procedure SevenZipRemoveSfxBlock(Arch: I7zOutArchive; remove: boolean); // X + procedure SevenZipAutoFilter(Arch: I7zOutArchive; auto: boolean); // X + procedure SevenZipCompressHeaders(Arch: I7zOutArchive; compress: boolean); // X + procedure SevenZipCompressHeadersFull(Arch: I7zOutArchive; compress: boolean); // X + procedure SevenZipEncryptHeaders(Arch: I7zOutArchive; Encrypt: boolean); // X + procedure SevenZipVolumeMode(Arch: I7zOutArchive; Mode: boolean); // X + + // filetime util functions + function DateTimeToFileTime(dt: TDateTime): TFileTime; + function FileTimeToDateTime(ft: TFileTime): TDateTime; + function CurrentFileTime: TFileTime; + + // constructors + + function CreateInArchive(const classid: TGUID): I7zInArchive; + function CreateOutArchive(const classid: TGUID): I7zOutArchive; + +const + CLSID_CFormatZip : TGUID = '{23170F69-40C1-278A-1000-000110010000}'; + CLSID_CFormatBZ2 : TGUID = '{23170F69-40C1-278A-1000-000110020000}'; + CLSID_CFormatRar : TGUID = '{23170F69-40C1-278A-1000-000110030000}'; + CLSID_CFormatArj : TGUID = '{23170F69-40C1-278A-1000-000110040000}'; + CLSID_CFormatZ : TGUID = '{23170F69-40C1-278A-1000-000110050000}'; + CLSID_CFormatLzh : TGUID = '{23170F69-40C1-278A-1000-000110060000}'; + CLSID_CFormat7z : TGUID = '{23170F69-40C1-278A-1000-000110070000}'; + CLSID_CFormatCab : TGUID = '{23170F69-40C1-278A-1000-000110080000}'; + CLSID_CFormatNsis : TGUID = '{23170F69-40C1-278A-1000-000110090000}'; + CLSID_CFormatLzma : TGUID = '{23170F69-40C1-278A-1000-0001100A0000}'; + CLSID_CFormatPe : TGUID = '{23170F69-40C1-278A-1000-000110DD0000}'; + CLSID_CFormatElf : TGUID = '{23170F69-40C1-278A-1000-000110DE0000}'; + CLSID_CFormatMacho : TGUID = '{23170F69-40C1-278A-1000-000110DF0000}'; + CLSID_CFormatUdf : TGUID = '{23170F69-40C1-278A-1000-000110E00000}'; + CLSID_CFormatXar : TGUID = '{23170F69-40C1-278A-1000-000110E10000}'; + CLSID_CFormatMub : TGUID = '{23170F69-40C1-278A-1000-000110E20000}'; + CLSID_CFormatHfs : TGUID = '{23170F69-40C1-278A-1000-000110E30000}'; + CLSID_CFormatDmg : TGUID = '{23170F69-40C1-278A-1000-000110E40000}'; + CLSID_CFormatCompound : TGUID = '{23170F69-40C1-278A-1000-000110E50000}'; + CLSID_CFormatWim : TGUID = '{23170F69-40C1-278A-1000-000110E60000}'; + CLSID_CFormatIso : TGUID = '{23170F69-40C1-278A-1000-000110E70000}'; + CLSID_CFormatBkf : TGUID = '{23170F69-40C1-278A-1000-000110E80000}'; + CLSID_CFormatChm : TGUID = '{23170F69-40C1-278A-1000-000110E90000}'; + CLSID_CFormatSplit : TGUID = '{23170F69-40C1-278A-1000-000110EA0000}'; + CLSID_CFormatRpm : TGUID = '{23170F69-40C1-278A-1000-000110EB0000}'; + CLSID_CFormatDeb : TGUID = '{23170F69-40C1-278A-1000-000110EC0000}'; + CLSID_CFormatCpio : TGUID = '{23170F69-40C1-278A-1000-000110ED0000}'; + CLSID_CFormatTar : TGUID = '{23170F69-40C1-278A-1000-000110EE0000}'; + CLSID_CFormatGZip : TGUID = '{23170F69-40C1-278A-1000-000110EF0000}'; + + +implementation + +const + MAXCHECK : int64 = (1 shl 20); + ZipCompressionMethod: array[TZipCompressionMethod] of UnicodeString = ('COPY', 'DEFLATE', 'DEFLATE64', 'BZIP2'); + SevCompressionMethod: array[T7zCompressionMethod] of UnicodeString = ('COPY', 'LZMA', 'BZIP2', 'PPMD', 'DEFLATE', 'DEFLATE64'); + +function DateTimeToFileTime(dt: TDateTime): TFileTime; +var + st: TSystemTime; +begin + DateTimeToSystemTime(dt, st); + if not (SystemTimeToFileTime(st, Result) and LocalFileTimeToFileTime(Result, Result)) + then RaiseLastOSError; +end; + +function FileTimeToDateTime(ft: TFileTime): TDateTime; +var + st: TSystemTime; +begin + if not (FileTimeToLocalFileTime(ft, ft) and FileTimeToSystemTime(ft, st)) then + RaiseLastOSError; + Result := SystemTimeToDateTime(st); +end; + +function CurrentFileTime: TFileTime; +begin + GetSystemTimeAsFileTime(Result); +end; + +procedure RINOK(const hr: HRESULT); +begin + if hr <> S_OK then + raise Exception.Create(SysErrorMessage(hr)); +end; + +procedure SetCardinalProperty(arch: I7zOutArchive; const name: UnicodeString; card: Cardinal); +var + value: OleVariant; +begin + TPropVariant(value).vt := VT_UI4; + TPropVariant(value).ulVal := card; + arch.SetPropertie(name, value); +end; + +procedure SetBooleanProperty(arch: I7zOutArchive; const name: UnicodeString; bool: boolean); +begin + case bool of + true: arch.SetPropertie(name, 'ON'); + false: arch.SetPropertie(name, 'OFF'); + end; +end; + + +procedure SetCompressionLevel(Arch: I7zOutArchive; level: Cardinal); +begin + SetCardinalProperty(arch, 'X', level); +end; + +procedure SetMultiThreading(Arch: I7zOutArchive; ThreadCount: Cardinal); +begin + SetCardinalProperty(arch, 'MT', ThreadCount); +end; + +procedure SetCompressionMethod(Arch: I7zOutArchive; method: TZipCompressionMethod); +begin + Arch.SetPropertie('M', ZipCompressionMethod[method]); +end; + +procedure SetDictionnarySize(Arch: I7zOutArchive; size: Cardinal); +begin + SetCardinalProperty(arch, 'D', size); +end; + +procedure SetDeflateNumPasses(Arch: I7zOutArchive; pass: Cardinal); +begin + SetCardinalProperty(arch, 'PASS', pass); +end; + +procedure SetNumFastBytes(Arch: I7zOutArchive; fb: Cardinal); +begin + SetCardinalProperty(arch, 'FB', fb); +end; + +procedure SetNumMatchFinderCycles(Arch: I7zOutArchive; mc: Cardinal); +begin + SetCardinalProperty(arch, 'MC', mc); +end; + +procedure SevenZipSetCompressionMethod(Arch: I7zOutArchive; method: T7zCompressionMethod); +begin + Arch.SetPropertie('0', SevCompressionMethod[method]); +end; + +procedure SevenZipSetBindInfo(Arch: I7zOutArchive; const bind: UnicodeString); +begin + arch.SetPropertie('B', bind); +end; + +procedure SevenZipSetSolidSettings(Arch: I7zOutArchive; solid: boolean); +begin + SetBooleanProperty(Arch, 'S', solid); +end; + +procedure SevenZipRemoveSfxBlock(Arch: I7zOutArchive; remove: boolean); +begin + SetBooleanProperty(arch, 'RSFX', remove); +end; + +procedure SevenZipAutoFilter(Arch: I7zOutArchive; auto: boolean); +begin + SetBooleanProperty(arch, 'F', auto); +end; + +procedure SevenZipCompressHeaders(Arch: I7zOutArchive; compress: boolean); +begin + SetBooleanProperty(arch, 'HC', compress); +end; + +procedure SevenZipCompressHeadersFull(Arch: I7zOutArchive; compress: boolean); +begin + SetBooleanProperty(arch, 'HCF', compress); +end; + +procedure SevenZipEncryptHeaders(Arch: I7zOutArchive; Encrypt: boolean); +begin + SetBooleanProperty(arch, 'HE', Encrypt); +end; + +procedure SevenZipVolumeMode(Arch: I7zOutArchive; Mode: boolean); +begin + SetBooleanProperty(arch, 'V', Mode); +end; + +type + T7zPlugin = class(TInterfacedObject) + private + FHandle: THandle; + FCreateObject: function(const clsid, iid :TGUID; var outObject): HRESULT; stdcall; + public + constructor Create(const lib: string); virtual; + destructor Destroy; override; + procedure CreateObject(const clsid, iid :TGUID; var obj); + end; + + T7zCodec = class(T7zPlugin, I7zCodec, ICompressProgressInfo) + private + FGetMethodProperty: function(index: Cardinal; propID: NMethodPropID; var value: OleVariant): HRESULT; stdcall; + FGetNumberOfMethods: function(numMethods: PCardinal): HRESULT; stdcall; + function GetNumberOfMethods: Cardinal; + function GetMethodProperty(index: Cardinal; propID: NMethodPropID): OleVariant; + function GetName(const index: integer): string; + protected + function SetRatioInfo(inSize, outSize: PInt64): HRESULT; stdcall; + public + function GetDecoder(const index: integer): ICompressCoder; + function GetEncoder(const index: integer): ICompressCoder; + constructor Create(const lib: string); override; + property MethodProperty[index: Cardinal; propID: NMethodPropID]: OleVariant read GetMethodProperty; + property NumberOfMethods: Cardinal read GetNumberOfMethods; + property Name[const index: integer]: string read GetName; + end; + + T7zArchive = class(T7zPlugin) + private + FGetHandlerProperty: function(propID: NArchive; var value: OleVariant): HRESULT; stdcall; + FClassId: TGUID; + procedure SetClassId(const classid: TGUID); + function GetClassId: TGUID; + public + function GetHandlerProperty(const propID: NArchive): OleVariant; + function GetLibStringProperty(const Index: NArchive): string; + function GetLibGUIDProperty(const Index: NArchive): TGUID; + constructor Create(const lib: string); override; + property HandlerProperty[const propID: NArchive]: OleVariant read GetHandlerProperty; + property Name: string index kName read GetLibStringProperty; + property ClassID: TGUID read GetClassId write SetClassId; + property Extension: string index kExtension read GetLibStringProperty; + end; + + T7zInArchive = class(T7zArchive, I7zInArchive, IProgress, IArchiveOpenCallback, + IArchiveExtractCallback, ICryptoGetTextPassword, IArchiveOpenVolumeCallback, + IArchiveOpenSetSubArchiveName) + private + FInArchive: IInArchive; + FPasswordCallback: T7zPasswordCallback; + FPasswordSender: Pointer; + FProgressCallback: T7zProgressCallback; + FProgressSender: Pointer; + FStream: TStream; + FPasswordIsDefined: Boolean; + FPassword: UnicodeString; + FSubArchiveMode: Boolean; + FSubArchiveName: UnicodeString; + FExtractCallBack: T7zGetStreamCallBack; + FExtractSender: Pointer; + FExtractPath: string; + function GetInArchive: IInArchive; + function GetItemProp(const Item: Cardinal; prop: PROPID): OleVariant; + protected + // I7zInArchive + procedure OpenFile(const filename: string); stdcall; + procedure OpenStream(stream: IInStream); stdcall; + procedure Close; stdcall; + function GetNumberOfItems: Cardinal; stdcall; + function GetItemPath(const index: integer): UnicodeString; stdcall; + function GetItemName(const index: integer): UnicodeString; stdcall; + function GetItemSize(const index: integer): Cardinal; stdcall; stdcall; + function GetItemIsFolder(const index: integer): boolean; stdcall; + procedure ExtractItem(const item: Cardinal; Stream: TStream; test: longbool); stdcall; + procedure ExtractItems(items: PCardArray; count: cardinal; test: longbool; sender: pointer; callback: T7zGetStreamCallBack); stdcall; + procedure SetPasswordCallback(sender: Pointer; callback: T7zPasswordCallback); stdcall; + procedure SetProgressCallback(sender: Pointer; callback: T7zProgressCallback); stdcall; + procedure ExtractAll(test: longbool; sender: pointer; callback: T7zGetStreamCallBack); stdcall; + procedure ExtractTo(const path: string); stdcall; + procedure SetPassword(const password: UnicodeString); stdcall; + // IArchiveOpenCallback + function SetTotal(files, bytes: PInt64): HRESULT; overload; stdcall; + function SetCompleted(files, bytes: PInt64): HRESULT; overload; stdcall; + // IProgress + function SetTotal(total: Int64): HRESULT; overload; stdcall; + function SetCompleted(completeValue: PInt64): HRESULT; overload; stdcall; + // IArchiveExtractCallback + function GetStream(index: Cardinal; var outStream: ISequentialOutStream; + askExtractMode: NAskMode): HRESULT; overload; stdcall; + function PrepareOperation(askExtractMode: NAskMode): HRESULT; stdcall; + function SetOperationResult(resultEOperationResult: NExtOperationResult): HRESULT; overload; stdcall; + // ICryptoGetTextPassword + function CryptoGetTextPassword(var password: TBStr): HRESULT; stdcall; + // IArchiveOpenVolumeCallback + function GetProperty(propID: PROPID; var value: OleVariant): HRESULT; overload; stdcall; + function GetStream(const name: PWideChar; var inStream: IInStream): HRESULT; overload; stdcall; + // IArchiveOpenSetSubArchiveName + function SetSubArchiveName(name: PWideChar): HRESULT; stdcall; + + public + constructor Create(const lib: string); override; + destructor Destroy; override; + property InArchive: IInArchive read GetInArchive; + end; + + T7zOutArchive = class(T7zArchive, I7zOutArchive, IArchiveUpdateCallback, ICryptoGetTextPassword2) + private + FOutArchive: IOutArchive; + FBatchList: TObjectList; + FProgressCallback: T7zProgressCallback; + FProgressSender: Pointer; + FPassword: UnicodeString; + function GetOutArchive: IOutArchive; + protected + // I7zOutArchive + procedure AddStream(Stream: TStream; Ownership: TStreamOwnership; + Attributes: Cardinal; CreationTime, LastWriteTime: TFileTime; + const Path: UnicodeString; IsFolder, IsAnti: boolean); stdcall; + procedure AddFile(const Filename: TFileName; const Path: UnicodeString); stdcall; + procedure AddFiles(const Dir, Path, Willcards: string; recurse: boolean); stdcall; + procedure SaveToFile(const FileName: TFileName); stdcall; + procedure SaveToStream(stream: TStream); stdcall; + procedure SetProgressCallback(sender: Pointer; callback: T7zProgressCallback); stdcall; + procedure CrearBatch; stdcall; + procedure SetPassword(const password: UnicodeString); stdcall; + procedure SetPropertie(name: UnicodeString; value: OleVariant); stdcall; + // IProgress + function SetTotal(total: Int64): HRESULT; stdcall; + function SetCompleted(completeValue: PInt64): HRESULT; stdcall; + // IArchiveUpdateCallback + function GetUpdateItemInfo(index: Cardinal; + newData: PInteger; // 1 - new data, 0 - old data + newProperties: PInteger; // 1 - new properties, 0 - old properties + indexInArchive: PCardinal // -1 if there is no in archive, or if doesn't matter + ): HRESULT; stdcall; + function GetProperty(index: Cardinal; propID: PROPID; var value: OleVariant): HRESULT; stdcall; + function GetStream(index: Cardinal; var inStream: ISequentialInStream): HRESULT; stdcall; + function SetOperationResult(operationResult: Integer): HRESULT; stdcall; + // ICryptoGetTextPassword2 + function CryptoGetTextPassword2(passwordIsDefined: PInteger; var password: TBStr): HRESULT; stdcall; + public + constructor Create(const lib: string); override; + destructor Destroy; override; + property OutArchive: IOutArchive read GetOutArchive; + end; + +function CreateInArchive(const classid: TGUID): I7zInArchive; +begin + Result := T7zInArchive.Create('7z.dll'); + Result.ClassId := classid; +end; + +function CreateOutArchive(const classid: TGUID): I7zOutArchive; +begin + Result := T7zOutArchive.Create('7z.dll'); + Result.ClassId := classid; +end; + + +{ T7zPlugin } + +constructor T7zPlugin.Create(const lib: string); +begin + FHandle := LoadLibrary(PChar(lib)); + if FHandle = 0 then + raise exception.CreateFmt('Error loading library %s', [lib]); + FCreateObject := GetProcAddress(FHandle, 'CreateObject'); + if not (Assigned(FCreateObject)) then + begin + FreeLibrary(FHandle); + raise Exception.CreateFmt('%s is not a 7z library', [lib]); + end; +end; + +destructor T7zPlugin.Destroy; +begin + FreeLibrary(FHandle); + inherited; +end; + +procedure T7zPlugin.CreateObject(const clsid, iid: TGUID; var obj); +var + hr: HRESULT; +begin + hr := FCreateObject(clsid, iid, obj); + if failed(hr) then + raise Exception.Create(SysErrorMessage(hr)); +end; + +{ T7zCodec } + +constructor T7zCodec.Create(const lib: string); +begin + inherited; + FGetMethodProperty := GetProcAddress(FHandle, 'GetMethodProperty'); + FGetNumberOfMethods := GetProcAddress(FHandle, 'GetNumberOfMethods'); + if not (Assigned(FGetMethodProperty) and Assigned(FGetNumberOfMethods)) then + begin + FreeLibrary(FHandle); + raise Exception.CreateFmt('%s is not a codec library', [lib]); + end; +end; + +function T7zCodec.GetDecoder(const index: integer): ICompressCoder; +var + v: OleVariant; +begin + v := MethodProperty[index, kDecoder]; + CreateObject(TPropVariant(v).puuid^, ICompressCoder, Result); +end; + +function T7zCodec.GetEncoder(const index: integer): ICompressCoder; +var + v: OleVariant; +begin + v := MethodProperty[index, kEncoder]; + CreateObject(TPropVariant(v).puuid^, ICompressCoder, Result); +end; + +function T7zCodec.GetMethodProperty(index: Cardinal; + propID: NMethodPropID): OleVariant; +var + hr: HRESULT; +begin + hr := FGetMethodProperty(index, propID, Result); + if Failed(hr) then + raise Exception.Create(SysErrorMessage(hr)); +end; + +function T7zCodec.GetName(const index: integer): string; +begin + Result := MethodProperty[index, kName_]; +end; + +function T7zCodec.GetNumberOfMethods: Cardinal; +var + hr: HRESULT; +begin + hr := FGetNumberOfMethods(@Result); + if Failed(hr) then + raise Exception.Create(SysErrorMessage(hr)); +end; + + +function T7zCodec.SetRatioInfo(inSize, outSize: PInt64): HRESULT; +begin + Result := S_OK; +end; + +{ T7zInArchive } + +procedure T7zInArchive.Close; stdcall; +begin + FPasswordIsDefined := false; + FSubArchiveMode := false; + FInArchive.Close; + FInArchive := nil; +end; + +constructor T7zInArchive.Create(const lib: string); +begin + inherited; + FPasswordCallback := nil; + FPasswordSender := nil; + FPasswordIsDefined := false; + FSubArchiveMode := false; + FExtractCallBack := nil; + FExtractSender := nil; +end; + +destructor T7zInArchive.Destroy; +begin + FInArchive := nil; + inherited; +end; + +function T7zInArchive.GetInArchive: IInArchive; +begin + if FInArchive = nil then + CreateObject(ClassID, IInArchive, FInArchive); + Result := FInArchive; +end; + +function T7zInArchive.GetItemPath(const index: integer): UnicodeString; stdcall; +begin + Result := UnicodeString(GetItemProp(index, kpidPath)); +end; + +function T7zInArchive.GetNumberOfItems: Cardinal; stdcall; +begin + RINOK(FInArchive.GetNumberOfItems(Result)); +end; + +procedure T7zInArchive.OpenFile(const filename: string); stdcall; +begin + RINOK( + InArchive.Open( + T7zStream.Create(TFileStream.Create(filename, fmOpenRead or fmShareDenyNone), soOwned), + @MAXCHECK, self as IArchiveOpenCallBack + ) + ); +end; + +procedure T7zInArchive.OpenStream(stream: IInStream); stdcall; +begin + RINOK(InArchive.Open(stream, @MAXCHECK, self as IArchiveOpenCallBack)); +end; + +function T7zInArchive.GetItemIsFolder(const index: integer): boolean; stdcall; +begin + Result := Boolean(GetItemProp(index, kpidIsFolder)); +end; + +function T7zInArchive.GetItemProp(const Item: Cardinal; + prop: PROPID): OleVariant; +begin + FInArchive.GetProperty(Item, prop, Result); +end; + +procedure T7zInArchive.ExtractItem(const item: Cardinal; Stream: TStream; test: longbool); stdcall; +begin + FStream := Stream; + try + if test then + RINOK(FInArchive.Extract(@item, 1, 1, self as IArchiveExtractCallback)) else + RINOK(FInArchive.Extract(@item, 1, 0, self as IArchiveExtractCallback)); + finally + FStream := nil; + end; +end; + +function T7zInArchive.GetStream(index: Cardinal; + var outStream: ISequentialOutStream; askExtractMode: NAskMode): HRESULT; +var + path: string; +begin + if askExtractMode = kExtract then + if FStream <> nil then + outStream := T7zStream.Create(FStream, soReference) as ISequentialOutStream else + if assigned(FExtractCallback) then + begin + Result := FExtractCallBack(FExtractSender, index, outStream); + Exit; + end else + if FExtractPath <> '' then + begin + if not GetItemIsFolder(index) then + begin + path := FExtractPath + GetItemPath(index); + ForceDirectories(ExtractFilePath(path)); + outStream := T7zStream.Create(TFileStream.Create(path, fmCreate), soOwned); + end; + end; + Result := S_OK; +end; + +function T7zInArchive.PrepareOperation(askExtractMode: NAskMode): HRESULT; +begin + Result := S_OK; +end; + +function T7zInArchive.SetCompleted(completeValue: PInt64): HRESULT; +begin + if Assigned(FProgressCallback) and (completeValue <> nil) then + Result := FProgressCallback(FProgressSender, false, completeValue^) else + Result := S_OK; +end; + +function T7zInArchive.SetCompleted(files, bytes: PInt64): HRESULT; +begin + Result := S_OK; +end; + +function T7zInArchive.SetOperationResult( + resultEOperationResult: NExtOperationResult): HRESULT; +begin + Result := S_OK; +end; + +function T7zInArchive.SetTotal(total: Int64): HRESULT; +begin + if Assigned(FProgressCallback) then + Result := FProgressCallback(FProgressSender, true, total) else + Result := S_OK; +end; + +function T7zInArchive.SetTotal(files, bytes: PInt64): HRESULT; +begin + Result := S_OK; +end; + +function T7zInArchive.CryptoGetTextPassword(var password: TBStr): HRESULT; +var + wpass: UnicodeString; +begin + if FPasswordIsDefined then + begin + password := SysAllocString(PWideChar(FPassword)); + Result := S_OK; + end else + if Assigned(FPasswordCallback) then + begin + Result := FPasswordCallBack(FPasswordSender, wpass); + if Result = S_OK then + begin + password := SysAllocString(PWideChar(wpass)); + FPasswordIsDefined := True; + FPassword := wpass; + end; + end else + Result := S_FALSE; +end; + +function T7zInArchive.GetProperty(propID: PROPID; + var value: OleVariant): HRESULT; +begin + Result := S_OK; +end; + +function T7zInArchive.GetStream(const name: PWideChar; + var inStream: IInStream): HRESULT; +begin + Result := S_OK; +end; + +procedure T7zInArchive.SetPasswordCallback(sender: Pointer; + callback: T7zPasswordCallback); stdcall; +begin + FPasswordSender := sender; + FPasswordCallback := callback; +end; + +function T7zInArchive.SetSubArchiveName(name: PWideChar): HRESULT; +begin + FSubArchiveMode := true; + FSubArchiveName := name; + Result := S_OK; +end; + +function T7zInArchive.GetItemName(const index: integer): UnicodeString; stdcall; +begin + Result := UnicodeString(GetItemProp(index, kpidName)); +end; + +function T7zInArchive.GetItemSize(const index: integer): Cardinal; stdcall; +begin + Result := Cardinal(GetItemProp(index, kpidSize)); +end; + +procedure T7zInArchive.ExtractItems(items: PCardArray; count: cardinal; test: longbool; + sender: pointer; callback: T7zGetStreamCallBack); stdcall; +begin + FExtractCallBack := callback; + FExtractSender := sender; + try + if test then + RINOK(FInArchive.Extract(items, count, 1, self as IArchiveExtractCallback)) else + RINOK(FInArchive.Extract(items, count, 0, self as IArchiveExtractCallback)); + finally + FExtractCallBack := nil; + FExtractSender := nil; + end; +end; + +procedure T7zInArchive.SetProgressCallback(sender: Pointer; + callback: T7zProgressCallback); stdcall; +begin + FProgressSender := sender; + FProgressCallback := callback; +end; + +procedure T7zInArchive.ExtractAll(test: longbool; sender: pointer; + callback: T7zGetStreamCallBack); +begin + FExtractCallBack := callback; + FExtractSender := sender; + try + if test then + RINOK(FInArchive.Extract(nil, $FFFFFFFF, 1, self as IArchiveExtractCallback)) else + RINOK(FInArchive.Extract(nil, $FFFFFFFF, 0, self as IArchiveExtractCallback)); + finally + FExtractCallBack := nil; + FExtractSender := nil; + end; +end; + +procedure T7zInArchive.ExtractTo(const path: string); +begin + FExtractPath := IncludeTrailingPathDelimiter(path); + try + RINOK(FInArchive.Extract(nil, $FFFFFFFF, 0, self as IArchiveExtractCallback)); + finally + FExtractPath := ''; + end; +end; + +procedure T7zInArchive.SetPassword(const password: UnicodeString); +begin + FPassword := password; + FPasswordIsDefined := FPassword <> ''; +end; + +{ T7zArchive } + +constructor T7zArchive.Create(const lib: string); +begin + inherited; + FGetHandlerProperty := GetProcAddress(FHandle, 'GetHandlerProperty'); + if not Assigned(FGetHandlerProperty) then + begin + FreeLibrary(FHandle); + raise Exception.CreateFmt('%s is not a Format library', [lib]); + end; + FClassId := GUID_NULL; +end; + +function T7zArchive.GetClassId: TGUID; +begin + Result := FClassId; +end; + +function T7zArchive.GetHandlerProperty(const propID: NArchive): OleVariant; +var + hr: HRESULT; +begin + hr := FGetHandlerProperty(propID, Result); + if Failed(hr) then + raise Exception.Create(SysErrorMessage(hr)); +end; + +function T7zArchive.GetLibGUIDProperty(const Index: NArchive): TGUID; +var + v: OleVariant; +begin + v := HandlerProperty[index]; + Result := TPropVariant(v).puuid^; +end; + +function T7zArchive.GetLibStringProperty(const Index: NArchive): string; +begin + Result := HandlerProperty[Index]; +end; + +procedure T7zArchive.SetClassId(const classid: TGUID); +begin + FClassId := classid; +end; + +{ T7zStream } + +constructor T7zStream.Create(Stream: TStream; Ownership: TStreamOwnership); +begin + inherited Create; + FStream := Stream; + FOwnership := Ownership; +end; + +destructor T7zStream.destroy; +begin + if FOwnership = soOwned then + begin + FStream.Free; + FStream := nil; + end; + inherited; +end; + +function T7zStream.Flush: HRESULT; +begin + Result := S_OK; +end; + +function T7zStream.GetSize(size: PInt64): HRESULT; +begin + if size <> nil then + size^ := FStream.Size; + Result := S_OK; +end; + +function T7zStream.Read(data: Pointer; size: Cardinal; + processedSize: PCardinal): HRESULT; +var + len: integer; +begin + len := FStream.Read(data^, size); + if processedSize <> nil then + processedSize^ := len; + Result := S_OK; +end; + +function T7zStream.Seek(offset: Int64; seekOrigin: Cardinal; + newPosition: PInt64): HRESULT; +begin + FStream.Seek(offset, seekOrigin); + if newPosition <> nil then + newPosition^ := FStream.Position; + Result := S_OK; +end; + +function T7zStream.SetSize(newSize: Int64): HRESULT; +begin + FStream.Size := newSize; + Result := S_OK; +end; + +function T7zStream.Write(data: Pointer; size: Cardinal; + processedSize: PCardinal): HRESULT; +var + len: integer; +begin + len := FStream.Write(data^, size); + if processedSize <> nil then + processedSize^ := len; + Result := S_OK; +end; + +type + TSourceMode = (smStream, smFile); + + T7zBatchItem = class + SourceMode: TSourceMode; + Stream: TStream; + Attributes: Cardinal; + CreationTime, LastWriteTime: TFileTime; + Path: UnicodeString; + IsFolder, IsAnti: boolean; + FileName: TFileName; + Ownership: TStreamOwnership; + Size: Cardinal; + destructor Destroy; override; + end; + +destructor T7zBatchItem.Destroy; +begin + if (Ownership = soOwned) and (Stream <> nil) then + Stream.Free; + inherited; +end; + +{ T7zOutArchive } + +procedure T7zOutArchive.AddFile(const Filename: TFileName; const Path: UnicodeString); +var + item: T7zBatchItem; + Handle: THandle; +begin + if not FileExists(Filename) then exit; + item := T7zBatchItem.Create; + Item.SourceMode := smFile; + item.Stream := nil; + item.FileName := Filename; + item.Path := Path; + Handle := FileOpen(Filename, fmOpenRead or fmShareDenyNone); + GetFileTime(Handle, @item.CreationTime, nil, @item.LastWriteTime); + item.Size := GetFileSize(Handle, nil); + CloseHandle(Handle); + item.Attributes := GetFileAttributes(PChar(Filename)); + item.IsFolder := false; + item.IsAnti := False; + item.Ownership := soOwned; + FBatchList.Add(item); +end; + +procedure T7zOutArchive.AddFiles(const Dir, Path, Willcards: string; recurse: boolean); +var + lencut: integer; + willlist: TStringList; + zedir: string; + procedure Traverse(p: string); + var + f: TSearchRec; + i: integer; + item: T7zBatchItem; + begin + if recurse then + begin + if FindFirst(p + '*.*', faDirectory, f) = 0 then + repeat + if (f.Name[1] <> '.') then + Traverse(IncludeTrailingPathDelimiter(p + f.Name)); + until FindNext(f) <> 0; + SysUtils.FindClose(f); + end; + + for i := 0 to willlist.Count - 1 do + begin + if FindFirst(p + willlist[i], faReadOnly or faHidden or faSysFile or faArchive, f) = 0 then + repeat + item := T7zBatchItem.Create; + Item.SourceMode := smFile; + item.Stream := nil; + item.FileName := p + f.Name; + item.Path := copy(item.FileName, lencut, length(item.FileName) - lencut + 1); + if path <> '' then + item.Path := IncludeTrailingPathDelimiter(path) + item.Path; + item.CreationTime := f.FindData.ftCreationTime; + item.LastWriteTime := f.FindData.ftLastWriteTime; + item.Attributes := f.FindData.dwFileAttributes; + item.Size := f.Size; + item.IsFolder := false; + item.IsAnti := False; + item.Ownership := soOwned; + FBatchList.Add(item); + until FindNext(f) <> 0; + SysUtils.FindClose(f); + end; + end; +begin + willlist := TStringList.Create; + try + willlist.Delimiter := ';'; + willlist.DelimitedText := Willcards; + zedir := IncludeTrailingPathDelimiter(Dir); + lencut := Length(zedir) + 1; + Traverse(zedir); + finally + willlist.Free; + end; +end; + +procedure T7zOutArchive.AddStream(Stream: TStream; Ownership: TStreamOwnership; + Attributes: Cardinal; CreationTime, LastWriteTime: TFileTime; + const Path: UnicodeString; IsFolder, IsAnti: boolean); stdcall; +var + item: T7zBatchItem; +begin + item := T7zBatchItem.Create; + Item.SourceMode := smStream; + item.Attributes := Attributes; + item.CreationTime := CreationTime; + item.LastWriteTime := LastWriteTime; + item.Path := Path; + item.IsFolder := IsFolder; + item.IsAnti := IsAnti; + item.Stream := Stream; + item.Size := Stream.Size; + item.Ownership := Ownership; + FBatchList.Add(item); +end; + +procedure T7zOutArchive.CrearBatch; +begin + FBatchList.Clear; +end; + +constructor T7zOutArchive.Create(const lib: string); +begin + inherited; + FBatchList := TObjectList.Create; + FProgressCallback := nil; + FProgressSender := nil; +end; + +function T7zOutArchive.CryptoGetTextPassword2(passwordIsDefined: PInteger; + var password: TBStr): HRESULT; +begin + if FPassword <> '' then + begin + passwordIsDefined^ := 1; + password := SysAllocString(PWideChar(FPassword)); + end else + passwordIsDefined^ := 0; + Result := S_OK; +end; + +destructor T7zOutArchive.Destroy; +begin + FOutArchive := nil; + FBatchList.Free; + inherited; +end; + +function T7zOutArchive.GetOutArchive: IOutArchive; +begin + if FOutArchive = nil then + CreateObject(ClassID, IOutArchive, FOutArchive); + Result := FOutArchive; +end; + +function T7zOutArchive.GetProperty(index: Cardinal; propID: PROPID; + var value: OleVariant): HRESULT; +var + item: T7zBatchItem; +begin + item := T7zBatchItem(FBatchList[index]); + case propID of + kpidAttributes: + begin + TPropVariant(Value).vt := VT_UI4; + TPropVariant(Value).ulVal := item.Attributes; + end; + kpidLastWriteTime: + begin + TPropVariant(value).vt := VT_FILETIME; + TPropVariant(value).filetime := item.LastWriteTime; + end; + kpidPath: + begin + if item.Path <> '' then + value := item.Path; + end; + kpidIsFolder: Value := item.IsFolder; + kpidSize: + begin + TPropVariant(Value).vt := VT_UI8; + TPropVariant(Value).uhVal.QuadPart := item.Size; + end; + kpidCreationTime: + begin + TPropVariant(value).vt := VT_FILETIME; + TPropVariant(value).filetime := item.CreationTime; + end; + kpidIsAnti: value := item.IsAnti; + else + // beep(0,0); + end; + Result := S_OK; +end; + +function T7zOutArchive.GetStream(index: Cardinal; + var inStream: ISequentialInStream): HRESULT; +var + item: T7zBatchItem; +begin + item := T7zBatchItem(FBatchList[index]); + case item.SourceMode of + smFile: inStream := T7zStream.Create(TFileStream.Create(item.FileName, fmOpenRead or fmShareDenyNone), soOwned); + smStream: + begin + item.Stream.Seek(0, soFromBeginning); + inStream := T7zStream.Create(item.Stream); + end; + end; + Result := S_OK; +end; + +function T7zOutArchive.GetUpdateItemInfo(index: Cardinal; newData, + newProperties: PInteger; indexInArchive: PCardinal): HRESULT; +begin + newData^ := 1; + newProperties^ := 1; + indexInArchive^ := CArdinal(-1); + Result := S_OK; +end; + +procedure T7zOutArchive.SaveToFile(const FileName: TFileName); +var + f: TFileStream; +begin + f := TFileStream.Create(FileName, fmCreate); + try + SaveToStream(f); + finally + f.free; + end; +end; + +procedure T7zOutArchive.SaveToStream(stream: TStream); +begin + RINOK(OutArchive.UpdateItems(T7zStream.Create(stream), FBatchList.Count, self as IArchiveUpdateCallback)) +end; + +function T7zOutArchive.SetCompleted(completeValue: PInt64): HRESULT; +begin + if Assigned(FProgressCallback) and (completeValue <> nil) then + Result := FProgressCallback(FProgressSender, false, completeValue^) else + Result := S_OK; +end; + +function T7zOutArchive.SetOperationResult( + operationResult: Integer): HRESULT; +begin + Result := S_OK; +end; + +procedure T7zOutArchive.SetPassword(const password: UnicodeString); +begin + FPassword := password; +end; + +procedure T7zOutArchive.SetProgressCallback(sender: Pointer; + callback: T7zProgressCallback); +begin + FProgressCallback := callback; + FProgressSender := sender; +end; + +procedure T7zOutArchive.SetPropertie(name: UnicodeString; + value: OleVariant); +var + intf: ISetProperties; + p: PWideChar; +begin + intf := OutArchive as ISetProperties; + p := PWideChar(name); + RINOK(intf.SetProperties(@p, @TPropVariant(value), 1)); +end; + +function T7zOutArchive.SetTotal(total: Int64): HRESULT; +begin + if Assigned(FProgressCallback) then + Result := FProgressCallback(FProgressSender, true, total) else + Result := S_OK; +end; + +end.