diff --git a/readme.htm b/readme.htm deleted file mode 100644 index 772a4ee..0000000 --- a/readme.htm +++ /dev/null @@ -1,44 +0,0 @@ - -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/readme.txt b/readme.txt new file mode 100644 index 0000000..02a0ecf --- /dev/null +++ b/readme.txt @@ -0,0 +1,156 @@ +官网已经找不到了。 +这个地址比较新 +https://github.com/zedalaye/d7zip +在这个基础上 融合了 +SevenZip.pas BUG修改版 - 20160613 - 堕落恶魔 - 博客园 +https://www.cnblogs.com/hs-kill/p/3876160.html +然后再加了一些小的修改。 + +最后,提供一个比较全面的 例子。 +【Delphi】从内存读取或解压压缩文件(RAR、ZIP、TAR、GZIP等)(一) - 峋山隐修会 - 博客园 +http://www.cnblogs.com/caibirdy1985/archive/2013/05/13/4232949.html +【Delphi】从内存读取或解压压缩文件(RAR、ZIP、TAR、GZIP等)(二) - 峋山隐修会 - 博客园 +http://www.cnblogs.com/caibirdy1985/archive/2013/05/14/4232948.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 +- Licence: MPL1.1 +- Date: 15/04/2009 +- Version: 1.2 + +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, 'Formats\7z.dll') 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, 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; diff --git a/sevenzip.pas b/sevenzip.pas index 1d7eea9..5872043 100644 --- a/sevenzip.pas +++ b/sevenzip.pas @@ -13,13 +13,66 @@ (* V1.2 *) (********************************************************************************) +//V1.1.1(aka 1.2.1) + +(* +2017-06-08 刘志林 修改 + +BUG修改: +1.对于文件名中带有空格的文件, 无法压缩, 原因是1743行, 压缩调用的是TStringList.Delimiter 来拆分文件字符串, 而空格是默认分行符, 导致文件名错误 +2.解压缩函数, 如果目标文件已存在并且为只读属性时, 报错, 原因是1383行 创建文件流的时候直接使用了TFileStream.Create(path, fmCreate)导致 +3.解压缩函数, 解决如果是空文件夹不会被创建的问题 + +功能增加: +1.增加了一个WorkPath变量, 用于指定7z.dll文件的绝对路径 +2.增加了一个解压缩过程中文件释放失败时的回调T7zProgressExceptCallback, 支持忽略/重试/取消 + +*) + + +//V1.2.2 +//新增对 callback 处理错误。 +//fix by flying wang. + +//V1.2.3 +//新增解压文件的属性设置。 +//add IncludeEmptyDir +//add support Int64 for file size +//fix by flying wang. + +//V1.2.5 +//add some IFDEF MSWINDOWS +//add ExtractItemToPath from ekot1 +//fix by flying wang. + +//also you can use JclCompression instead of this. + unit sevenzip; {$ALIGN ON} {$MINENUMSIZE 4} -{$WARN SYMBOL_PLATFORM OFF} +{$WARN SYMBOL_PLATFORM OFF} interface -uses SysUtils, Windows, ActiveX, Classes, Contnrs; +uses +{$IFDEF MSWINDOWS} + Windows, ActiveX, +{$ENDIF MSWINDOWS} +{$IFDEF POSIX} + Posix.Dlfcn, Posix.Fcntl, +{$ENDIF POSIX} + SysUtils, Classes, Contnrs; + +var + //fix by 刘志林 + G_7zWorkPath: string; {工作路径,查找dll用} + +const + //fix by flying wang. + kCallBackError = $0FFFFFFF; + kCallbackCANCEL = $0FFFFFFE; + kCallbackIGNORE = $0FFFFFFD; + + type PVarType = ^TVarType; @@ -710,6 +763,13 @@ interface T7zGetStreamCallBack = function(sender: Pointer; index: Cardinal; var outStream: ISequentialOutStream): HRESULT; stdcall; T7zProgressCallback = function(sender: Pointer; total: boolean; value: int64): HRESULT; stdcall; + //fix by 刘志林 + NECallBack = ( + EC_RETRY = 0, + EC_IGNORE, + EC_CANCEL + ); + T7zProgressExceptCallback = function(sender: Pointer; AFile: string): NECallBack; stdcall; I7zInArchive = interface ['{022CF785-3ECE-46EF-9755-291FA84CC6C9}'] @@ -719,10 +779,18 @@ interface 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 GetItemSize(const index: integer): Int64; stdcall; + //fix by flying wang. + function GetItemCompressedSize(const index: integer): Int64; stdcall; +{$IFDEF MSWINDOWS} + function GetItemFileTime(const index: integer): TFileTime; stdcall; +{$ENDIF MSWINDOWS} + function GetItemDataTime(const index: integer): TDateTime; stdcall; function GetItemIsFolder(const index: integer): boolean; stdcall; function GetInArchive: IInArchive; procedure ExtractItem(const item: Cardinal; Stream: TStream; test: longbool); stdcall; + //fix or add by ekot1 + procedure ExtractItemToPath(const item: Cardinal; const path: string; 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; @@ -730,13 +798,21 @@ interface procedure SetPasswordCallback(sender: Pointer; callback: T7zPasswordCallback); stdcall; procedure SetPassword(const password: UnicodeString); stdcall; procedure SetProgressCallback(sender: Pointer; callback: T7zProgressCallback); stdcall; + //fix by 刘志林 + procedure SetProgressExceptCallback(sender: Pointer; callback: T7zProgressExceptCallback); 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 ItemSize[const index: integer]: Int64 read GetItemSize; + //fix by flying wang. + property ItemCompressedSize[const index: integer]: Int64 read GetItemCompressedSize; +{$IFDEF MSWINDOWS} + property ItemFileTime[const index: integer]: TFileTime read GetItemFileTime; +{$ENDIF MSWINDOWS} + property ItemDataTime[const index: integer]: TDateTime read GetItemDataTime; property ItemIsFolder[const index: integer]: boolean read GetItemIsFolder; property InArchive: IInArchive read GetInArchive; end; @@ -747,7 +823,7 @@ interface CreationTime, LastWriteTime: TFileTime; const Path: UnicodeString; IsFolder, IsAnti: boolean); stdcall; procedure AddFile(const Filename: TFileName; const Path: UnicodeString); stdcall; - procedure AddFiles(const Dir, Path, Wildcard: string; recurse: boolean); stdcall; + procedure AddFiles(const Dir, Path, Wildcard: string; recurse, IncludeEmptyDir: boolean); stdcall; procedure SaveToFile(const FileName: TFileName); stdcall; procedure SaveToStream(stream: TStream); stdcall; procedure SetProgressCallback(sender: Pointer; callback: T7zProgressCallback); stdcall; @@ -810,15 +886,24 @@ T7zStream = class(TInterfacedObject, IInStream, IStreamGetSize, procedure SevenZipEncryptHeaders(Arch: I7zOutArchive; Encrypt: boolean); // X procedure SevenZipVolumeMode(Arch: I7zOutArchive; Mode: boolean); // X +{$IFDEF MSWINDOWS} // filetime util functions function DateTimeToFileTime(dt: TDateTime): TFileTime; function FileTimeToDateTime(ft: TFileTime): TDateTime; function CurrentFileTime: TFileTime; +{$ENDIF MSWINDOWS} // constructors +const +{$IFDEF MSWINDOWS} + C_7zDllName = '7z.dll'; +{$ENDIF MSWINDOWS} +{$IFDEF POSIX} + C_7zDllName = 'lib7z.so'; +{$ENDIF POSIX} - function CreateInArchive(const classid: TGUID; const lib: string = '7z.dll'): I7zInArchive; - function CreateOutArchive(const classid: TGUID; const lib: string = '7z.dll'): I7zOutArchive; + function CreateInArchive(const classid: TGUID; const lib: string = C_7zDllName): I7zInArchive; + function CreateOutArchive(const classid: TGUID; const lib: string = C_7zDllName): I7zOutArchive; const CLSID_CFormatZip : TGUID = '{23170F69-40C1-278A-1000-000110010000}'; // [OUT] zip jar xpi @@ -877,6 +962,64 @@ T7zStream = class(TInterfacedObject, IInStream, IStreamGetSize, CLSID_CFormatTar : TGUID = '{23170F69-40C1-278A-1000-000110EE0000}'; // [OUT] tar CLSID_CFormatGZip : TGUID = '{23170F69-40C1-278A-1000-000110EF0000}'; // [OUT] gz gzip tgz tpz +//fix or copy from Jedi JCL +// ZipHandlerOut.cpp +const + kDeflateAlgoX1 = 0 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kLzAlgoX1' {$ENDIF} {$ENDIF}; + kLzAlgoX1 = 0; + kDeflateAlgoX5 = 1 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kLzAlgoX5' {$ENDIF} {$ENDIF}; + kLzAlgoX5 = 1; + + kDeflateNumPassesX1 = 1; + kDeflateNumPassesX7 = 3; + kDeflateNumPassesX9 = 10; + + kNumFastBytesX1 = 32 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kDeflateNumFastBytesX1' {$ENDIF} {$ENDIF}; + kDeflateNumFastBytesX1 = 32; + kNumFastBytesX7 = 64 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kDeflateNumFastBytesX7' {$ENDIF} {$ENDIF}; + kDeflateNumFastBytesX7 = 64; + kNumFastBytesX9 = 128 {$IFDEF SUPPORTS_DEPRECATED} deprecated {$IFDEF SUPPORTS_DEPRECATED_DETAILS} 'Use kDeflateNumFastBytesX9' {$ENDIF} {$ENDIF}; + kDeflateNumFastBytesX9 = 128; + + kLzmaNumFastBytesX1 = 32; + kLzmaNumFastBytesX7 = 64; + + kBZip2NumPassesX1 = 1; + kBZip2NumPassesX7 = 2; + kBZip2NumPassesX9 = 7; + + kBZip2DicSizeX1 = 100000; + kBZip2DicSizeX3 = 500000; + kBZip2DicSizeX5 = 900000; + +// HandlerOut.cpp +const + kLzmaAlgoX1 = 0; + kLzmaAlgoX5 = 1; + + kLzmaDicSizeX1 = 1 shl 16; + kLzmaDicSizeX3 = 1 shl 20; + kLzmaDicSizeX5 = 1 shl 24; + kLzmaDicSizeX7 = 1 shl 25; + kLzmaDicSizeX9 = 1 shl 26; + + kLzmaFastBytesX1 = 32; + kLzmaFastBytesX7 = 64; + + kPpmdMemSizeX1 = (1 shl 22); + kPpmdMemSizeX5 = (1 shl 24); + kPpmdMemSizeX7 = (1 shl 26); + kPpmdMemSizeX9 = (192 shl 20); + + kPpmdOrderX1 = 4; + kPpmdOrderX5 = 6; + kPpmdOrderX7 = 16; + kPpmdOrderX9 = 32; + + kDeflateFastBytesX1 = 32; + kDeflateFastBytesX7 = 64; + kDeflateFastBytesX9 = 128; + implementation const @@ -885,6 +1028,7 @@ implementation ZipEncryptionMethod: array[TZipEncryptionMethod] of UnicodeString = ('AES128', 'AES192', 'AES256', 'ZIPCRYPTO'); SevCompressionMethod: array[T7zCompressionMethod] of UnicodeString = ('COPY', 'LZMA', 'BZIP2', 'PPMD', 'DEFLATE', 'DEFLATE64'); +{$IFDEF MSWINDOWS} function DateTimeToFileTime(dt: TDateTime): TFileTime; var st: TSystemTime; @@ -907,9 +1051,20 @@ function CurrentFileTime: TFileTime; begin GetSystemTimeAsFileTime(Result); end; +{$ENDIF MSWINDOWS} procedure RINOK(const hr: HRESULT); begin + //fix by flying wang. + if hr = kCallBackError then + begin + raise Exception.Create('Callback error.'); + exit; + end; + if (hr = kCallbackCANCEL) or (hr = kCallbackIGNORE) then + begin + exit; + end; if hr <> S_OK then raise Exception.Create(SysErrorMessage(hr)); end; @@ -1021,6 +1176,50 @@ procedure SevenZipVolumeMode(Arch: I7zOutArchive; Mode: boolean); SetBooleanProperty(arch, 'V', Mode); end; +function LoadModule(FileName: string): THandle; +{$IFDEF MSWINDOWS} +begin + Result := SafeLoadLibrary(FileName); +end; +{$ENDIF MSWINDOWS} +{$IFDEF POSIX} +begin + Result := dlopen(PChar(FileName), RTLD_NOW); +end; +{$ENDIF POSIX} + +procedure UnloadModule(var Module: THandle); +{$IFDEF MSWINDOWS} +begin + if Module <> 0 then + FreeLibrary(Module); + Module := 0; +end; +{$ENDIF MSWINDOWS} +{$IFDEF POSIX} +begin + if Module <> 0 then + dlclose(Pointer(Module)); + Module := 0; +end; +{$ENDIF POSIX} + +function GetModuleSymbol(Module: THandle; SymbolName: string): Pointer; +{$IFDEF MSWINDOWS} +begin + Result := nil; + if Module <> 0 then + Result := GetProcAddress(Module, PChar(SymbolName)); +end; +{$ENDIF MSWINDOWS} +{$IFDEF POSIX} +begin + Result := nil; + if Module <> 0 then + Result := dlsym(Module, PChar(SymbolName)); +end; +{$ENDIF POSIX} + type T7zPlugin = class(TInterfacedObject) private @@ -1071,11 +1270,18 @@ T7zInArchive = class(T7zArchive, I7zInArchive, IProgress, IArchiveOpenCallback IArchiveExtractCallback, ICryptoGetTextPassword, IArchiveOpenVolumeCallback, IArchiveOpenSetSubArchiveName) private + //fix by flying wang. + FLastWriteFileAttr: Cardinal; + FLastWriteFileDataTime: TDateTime; + FLastWriteFile: string; FInArchive: IInArchive; FPasswordCallback: T7zPasswordCallback; FPasswordSender: Pointer; FProgressCallback: T7zProgressCallback; FProgressSender: Pointer; + //fix by 刘志林 + FProgressExceptCallback: T7zProgressExceptCallback; + FProgressExceptSender: Pointer; FStream: TStream; FPasswordIsDefined: Boolean; FPassword: UnicodeString; @@ -1086,6 +1292,8 @@ T7zInArchive = class(T7zArchive, I7zInArchive, IProgress, IArchiveOpenCallback FExtractPath: string; function GetInArchive: IInArchive; function GetItemProp(const Item: Cardinal; prop: PROPID): OleVariant; + //fix by flying wang. + procedure ResetLastFileInfo; protected // I7zInArchive procedure OpenFile(const filename: string); stdcall; @@ -1094,12 +1302,22 @@ T7zInArchive = class(T7zArchive, I7zInArchive, IProgress, IArchiveOpenCallback 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 GetItemSize(const index: integer): Int64; stdcall; stdcall; + //fix by flying wang. + function GetItemCompressedSize(const index: integer): Int64; stdcall; +{$IFDEF MSWINDOWS} + function GetItemFileTime(const index: integer): TFileTime; stdcall; +{$ENDIF MSWINDOWS} + function GetItemDataTime(const index: integer): TDateTime; stdcall; function GetItemIsFolder(const index: integer): boolean; stdcall; procedure ExtractItem(const item: Cardinal; Stream: TStream; test: longbool); stdcall; + //fix or add by ekot1 + procedure ExtractItemToPath(const item: Cardinal; const path: string; 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; + //fix by 刘志林 + procedure SetProgressExceptCallback(sender: Pointer; callback: T7zProgressExceptCallback); stdcall; procedure ExtractAll(test: longbool; sender: pointer; callback: T7zGetStreamCallBack); stdcall; procedure ExtractTo(const path: string); stdcall; procedure SetPassword(const password: UnicodeString); stdcall; @@ -1142,7 +1360,7 @@ T7zOutArchive = class(T7zArchive, I7zOutArchive, IArchiveUpdateCallback, ICryp 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, Wildcard: string; recurse: boolean); stdcall; + procedure AddFiles(const Dir, Path, Wildcard: string; recurse, IncludeEmptyDir: boolean); stdcall; procedure SaveToFile(const FileName: TFileName); stdcall; procedure SaveToStream(stream: TStream); stdcall; procedure SetProgressCallback(sender: Pointer; callback: T7zProgressCallback); stdcall; @@ -1171,13 +1389,13 @@ T7zOutArchive = class(T7zArchive, I7zOutArchive, IArchiveUpdateCallback, ICryp function CreateInArchive(const classid: TGUID; const lib: string): I7zInArchive; begin - Result := T7zInArchive.Create(lib); + Result := T7zInArchive.Create(G_7zWorkPath + lib); Result.ClassId := classid; end; function CreateOutArchive(const classid: TGUID; const lib: string): I7zOutArchive; begin - Result := T7zOutArchive.Create(lib); + Result := T7zOutArchive.Create(G_7zWorkPath + lib); Result.ClassId := classid; end; @@ -1186,10 +1404,20 @@ Result.ClassId := classid; constructor T7zPlugin.Create(const lib: string); begin - FHandle := LoadLibrary(PChar(lib)); + inherited Create; + FHandle := LoadModule(PChar(lib)); if FHandle = 0 then - raise exception.CreateFmt('Error loading library %s', [lib]); - FCreateObject := GetProcAddress(FHandle, 'CreateObject'); + begin + try + RaiseLastOSError; + except + on E: Exception do + begin + raise Exception.CreateFmt('Error loading library %s' + sLineBreak + 'Error Message: ' + E.Message, [lib]); + end; + end; + end; + FCreateObject := GetModuleSymbol(FHandle, 'CreateObject'); if not (Assigned(FCreateObject)) then begin FreeLibrary(FHandle); @@ -1199,7 +1427,7 @@ constructor T7zPlugin.Create(const lib: string); destructor T7zPlugin.Destroy; begin - FreeLibrary(FHandle); + UnloadModule(FHandle); inherited; end; @@ -1217,8 +1445,8 @@ procedure T7zPlugin.CreateObject(const clsid, iid: TGUID; var obj); constructor T7zCodec.Create(const lib: string); begin inherited; - FGetMethodProperty := GetProcAddress(FHandle, 'GetMethodProperty'); - FGetNumberOfMethods := GetProcAddress(FHandle, 'GetNumberOfMethods'); + FGetMethodProperty := GetModuleSymbol(FHandle, 'GetMethodProperty'); + FGetNumberOfMethods := GetModuleSymbol(FHandle, 'GetNumberOfMethods'); if not (Assigned(FGetMethodProperty) and Assigned(FGetNumberOfMethods)) then begin FreeLibrary(FHandle); @@ -1276,6 +1504,8 @@ function T7zCodec.SetRatioInfo(inSize, outSize: PInt64): HRESULT; procedure T7zInArchive.Close; stdcall; begin + //fix by flying wang. + ResetLastFileInfo; FPasswordIsDefined := false; FSubArchiveMode := false; FInArchive.Close; @@ -1285,6 +1515,8 @@ procedure T7zInArchive.Close; stdcall; constructor T7zInArchive.Create(const lib: string); begin inherited; + //fix by flying wang. + ResetLastFileInfo; FPasswordCallback := nil; FPasswordSender := nil; FPasswordIsDefined := false; @@ -1299,6 +1531,14 @@ destructor T7zInArchive.Destroy; inherited; end; +procedure T7zInArchive.ResetLastFileInfo; +begin + //fix by flying wang. + FLastWriteFileAttr := faNormal; + FLastWriteFileDataTime := MinDateTime; + FLastWriteFile := ''; +end; + function T7zInArchive.GetInArchive: IInArchive; begin if FInArchive = nil then @@ -1320,6 +1560,8 @@ procedure T7zInArchive.OpenFile(const filename: string); stdcall; var strm: IInStream; begin + //fix by flying wang. + ResetLastFileInfo; strm := T7zStream.Create(TFileStream.Create(filename, fmOpenRead or fmShareDenyNone), soOwned); try RINOK( @@ -1335,6 +1577,8 @@ procedure T7zInArchive.OpenFile(const filename: string); stdcall; procedure T7zInArchive.OpenStream(stream: IInStream); stdcall; begin + //fix by flying wang. + ResetLastFileInfo; RINOK(InArchive.Open(stream, @MAXCHECK, self as IArchiveOpenCallBack)); end; @@ -1361,10 +1605,26 @@ procedure T7zInArchive.ExtractItem(const item: Cardinal; Stream: TStream; test: end; end; +//fix or add by ekot1 +procedure T7zInArchive.ExtractItemToPath(const item: Cardinal; const path: string; test: longbool); stdcall; +begin + FExtractPath := IncludeTrailingPathDelimiter(path); + try + if test then + RINOK(FInArchive.Extract(@item, 1, 1, self as IArchiveExtractCallback)) else + RINOK(FInArchive.Extract(@item, 1, 0, self as IArchiveExtractCallback)); + finally + FExtractPath := ''; + end; +end; + function T7zInArchive.GetStream(index: Cardinal; var outStream: ISequentialOutStream; askExtractMode: NAskMode): HRESULT; var path: string; + //fix by 刘志林 + nFileStream: TFileStream; + nECR: NECallBack; begin if askExtractMode = kExtract then if FStream <> nil then @@ -1376,11 +1636,58 @@ function T7zInArchive.GetStream(index: Cardinal; end else if FExtractPath <> '' then begin - if not GetItemIsFolder(index) then + //fix by 刘志林 and flying wang. + if GetItemIsFolder(index) then + begin + path := FExtractPath + GetItemPath(index); + ForceDirectories(path); + end + else begin path := FExtractPath + GetItemPath(index); ForceDirectories(ExtractFilePath(path)); - outStream := T7zStream.Create(TFileStream.Create(path, fmCreate), soOwned); + FLastWriteFileAttr := 0; + if FileExists(path) then + begin + FLastWriteFileAttr := FileGetAttr(path); + if FLastWriteFileAttr <> faNormal then + FileSetAttr(path, faNormal); + end; + + nFileStream := nil; + repeat + try + //能写入即可。 + nFileStream := TFileStream.Create(Path, fmCreate or fmOpenReadWrite or fmShareDenyWrite); + //建立文件大小。 + nFileStream.Size := GetItemSize(index); + nFileStream.Position := 0; + except + FreeAndNil(nFileStream); + if not Assigned(FProgressExceptCallback) then + nECR := EC_CANCEL + else + nECR := FProgressExceptCallback(FProgressExceptSender, Path); + end; + until (nFileStream <> nil) or (nECR <> EC_RETRY); + if nFileStream = nil then + begin + if nECR = EC_CANCEL then + begin + Result := kCallbackCANCEL; + Exit; + end; + end + else + begin + FreeAndNil(nFileStream); + FLastWriteFileDataTime := GetItemDataTime(index); + FLastWriteFile := path; + if (FLastWriteFileAttr <> 0) and (FLastWriteFileAttr <> faNormal) then + FileSetAttr(FLastWriteFile, FLastWriteFileAttr); + FileSetDate(FLastWriteFile, DateTimeToFileDate(FLastWriteFileDataTime)); + outStream := T7zStream.Create(TFileStream.Create(path, fmCreate), soOwned); + end; end; end; Result := S_OK; @@ -1393,6 +1700,8 @@ function T7zInArchive.PrepareOperation(askExtractMode: NAskMode): HRESULT; function T7zInArchive.SetCompleted(completeValue: PInt64): HRESULT; begin + //fix by flying wang. + Result := kCallBackError; if Assigned(FProgressCallback) and (completeValue <> nil) then Result := FProgressCallback(FProgressSender, false, completeValue^) else Result := S_OK; @@ -1406,11 +1715,21 @@ function T7zInArchive.SetCompleted(files, bytes: PInt64): HRESULT; function T7zInArchive.SetOperationResult( resultEOperationResult: NExtOperationResult): HRESULT; begin + //fix by flying wang. + if FileExists(FLastWriteFile) then + begin + if (FLastWriteFileAttr <> 0) and (FLastWriteFileAttr <> faNormal) then + FileSetAttr(FLastWriteFile, FLastWriteFileAttr); + FileSetDate(FLastWriteFile, DateTimeToFileDate(FLastWriteFileDataTime)); + end; + ResetLastFileInfo; Result := S_OK; end; function T7zInArchive.SetTotal(total: Int64): HRESULT; begin + //fix by flying wang. + Result := kCallBackError; if Assigned(FProgressCallback) then Result := FProgressCallback(FProgressSender, true, total) else Result := S_OK; @@ -1432,6 +1751,8 @@ function T7zInArchive.CryptoGetTextPassword(var password: TBStr): HRESULT; end else if Assigned(FPasswordCallback) then begin + //fix by flying wang. + Result := kCallBackError; Result := FPasswordCallBack(FPasswordSender, wpass); if Result = S_OK then begin @@ -1474,9 +1795,37 @@ function T7zInArchive.GetItemName(const index: integer): UnicodeString; stdcall; Result := UnicodeString(GetItemProp(index, kpidName)); end; -function T7zInArchive.GetItemSize(const index: integer): Cardinal; stdcall; +function T7zInArchive.GetItemSize(const index: integer): Int64; stdcall; +begin + Result := Int64(GetItemProp(index, kpidSize)); +end; + +//fix by flying wang. +function T7zInArchive.GetItemCompressedSize(const index: integer): Int64; stdcall; +begin + Result := Int64(GetItemProp(index, kpidPackSize)); +end; + +{$IFDEF MSWINDOWS} +function T7zInArchive.GetItemFileTime(const index: integer): TFileTime; stdcall; +var + value: OleVariant; +begin + value := GetItemProp(index, kpidMTime); + if TPropVariant(value).vt = VT_FILETIME then + begin + Result := TPropVariant(value).filetime; + end; +end; +{$ENDIF MSWINDOWS} + +function T7zInArchive.GetItemDataTime(const index: integer): TDateTime; stdcall; +var + A: TFileTime; begin - Result := Cardinal(GetItemProp(index, kpidSize)); + Result := MinDateTime; + A := GetItemFileTime(index); + Result := FileTimeToDateTime(A); end; procedure T7zInArchive.ExtractItems(items: PCardArray; count: cardinal; test: longbool; @@ -1501,6 +1850,14 @@ procedure T7zInArchive.SetProgressCallback(sender: Pointer; FProgressCallback := callback; end; +//fix by 刘志林 +procedure T7zInArchive.SetProgressExceptCallback(sender: Pointer; + callback: T7zProgressExceptCallback); +begin + FProgressExceptSender := sender; + FProgressExceptCallback := callback; +end; + procedure T7zInArchive.ExtractAll(test: longbool; sender: pointer; callback: T7zGetStreamCallBack); begin @@ -1537,7 +1894,7 @@ procedure T7zInArchive.SetPassword(const password: UnicodeString); constructor T7zArchive.Create(const lib: string); begin inherited; - FGetHandlerProperty := GetProcAddress(FHandle, 'GetHandlerProperty'); + FGetHandlerProperty := GetModuleSymbol(FHandle, 'GetHandlerProperty'); if not Assigned(FGetHandlerProperty) then begin FreeLibrary(FHandle); @@ -1658,7 +2015,7 @@ T7zBatchItem = class IsFolder, IsAnti: boolean; FileName: TFileName; Ownership: TStreamOwnership; - Size: Cardinal; + Size: Int64; destructor Destroy; override; end; @@ -1675,6 +2032,8 @@ procedure T7zOutArchive.AddFile(const Filename: TFileName; const Path: UnicodeSt var item: T7zBatchItem; Handle: THandle; + TempSize: Int64; + TempSizeHi: Cardinal; begin if not FileExists(Filename) then exit; item := T7zBatchItem.Create; @@ -1684,16 +2043,20 @@ procedure T7zOutArchive.AddFile(const Filename: TFileName; const Path: UnicodeSt item.Path := Path; Handle := FileOpen(Filename, fmOpenRead or fmShareDenyNone); GetFileTime(Handle, @item.CreationTime, nil, @item.LastWriteTime); - item.Size := GetFileSize(Handle, nil); + Int64Rec(TempSize).Lo := GetFileSize(Handle, @TempSizeHi); + Int64Rec(TempSize).Hi := TempSizeHi; + item.Size := TempSize; CloseHandle(Handle); - item.Attributes := GetFileAttributes(PChar(Filename)); + //item.Attributes := GetFileAttributes(PChar(Filename)); + //fix By Flying Wang. + item.Attributes := FileGetAttr(Filename); item.IsFolder := false; item.IsAnti := False; item.Ownership := soOwned; FBatchList.Add(item); end; -procedure T7zOutArchive.AddFiles(const Dir, Path, Wildcard: string; recurse: boolean); +procedure T7zOutArchive.AddFiles(const Dir, Path, Wildcard: string; recurse, IncludeEmptyDir: boolean); var lencut: integer; willlist: TStringList; @@ -1703,6 +2066,7 @@ procedure T7zOutArchive.AddFiles(const Dir, Path, Wildcard: string; recurse: boo f: TSearchRec; i: integer; item: T7zBatchItem; + IsEmpty: Boolean; begin if recurse then begin @@ -1716,8 +2080,10 @@ procedure T7zOutArchive.AddFiles(const Dir, Path, Wildcard: string; recurse: boo for i := 0 to willlist.Count - 1 do begin + IsEmpty := True; if FindFirst(p + willlist[i], faReadOnly or faHidden or faSysFile or faArchive, f) = 0 then repeat + IsEmpty := False; item := T7zBatchItem.Create; Item.SourceMode := smFile; item.Stream := nil; @@ -1735,6 +2101,24 @@ procedure T7zOutArchive.AddFiles(const Dir, Path, Wildcard: string; recurse: boo FBatchList.Add(item); until FindNext(f) <> 0; SysUtils.FindClose(f); + if IncludeEmptyDir and IsEmpty and (not FileExists(p)) and DirectoryExists(p) then + begin + item := T7zBatchItem.Create; + Item.SourceMode := smFile; + item.Stream := nil; + item.FileName := p; + 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 := True; + item.IsAnti := False; + item.Ownership := soOwned; + FBatchList.Add(item); + end; end; end; begin @@ -1842,6 +2226,21 @@ function T7zOutArchive.GetProperty(index: Cardinal; propID: PROPID; TPropVariant(value).vt := VT_FILETIME; TPropVariant(value).filetime := item.CreationTime; end; + //add by flying wang. + kpidATime: + begin + TPropVariant(value).vt := VT_FILETIME; + TPropVariant(value).filetime := item.LastWriteTime; + end; + kpidTimeType: + begin + TPropVariant(value).vt := VT_UI4; +{$IFDEF MSWINDOWS} + TPropVariant(value).ulVal := Integer(kWindows); +{$ELSE MSWINDOWS} + TPropVariant(value).ulVal := Integer(kUnix); +{$ENDIF MSWINDOWS} + end; kpidIsAnti: value := item.IsAnti; else // beep(0,0); @@ -1901,6 +2300,8 @@ procedure T7zOutArchive.SaveToStream(stream: TStream); function T7zOutArchive.SetCompleted(completeValue: PInt64): HRESULT; begin + //fix by flying wang. + Result := kCallBackError; if Assigned(FProgressCallback) and (completeValue <> nil) then Result := FProgressCallback(FProgressSender, false, completeValue^) else Result := S_OK; @@ -1937,9 +2338,17 @@ procedure T7zOutArchive.SetPropertie(name: UnicodeString; function T7zOutArchive.SetTotal(total: Int64): HRESULT; begin + //fix by flying wang. + Result := kCallBackError; if Assigned(FProgressCallback) then Result := FProgressCallback(FProgressSender, true, total) else Result := S_OK; end; +initialization + G_7zWorkPath := ''; + +//finalization + + end.