{*******************************************************} { } { ProcessDecompress } { } { Copyright (C) 2023 kku } { } {*******************************************************} unit ProcessDecompress; interface uses System.SysUtils, System.Classes, AbArcTyp, AbZipTyp, AbUtils; const SIG_CANCEL = '*CANCEL$'; DLL_7Z = '7z.dll'; function DecompressFile(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent; aEvtNeedPass: TAbNeedPasswordEvent): string; procedure ExtractZip(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent; aEvtNeedPass: TAbNeedPasswordEvent); procedure ExtractCab(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent); procedure ExtractTar(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent); function ExtractGzip(sSrcPath, sExportPath: String; IsGzippedTar: Boolean; aEvtProg: TAbArchiveProgressEvent): string; function ExtractBzip2(sSrcPath, sExportPath: String; bIsBzippedTar: Boolean; aEvtProg: TAbArchiveProgressEvent): string; function Extract7zip(ArcType: TAbArchiveType; sSrcPath, sExportPath: String): string; implementation uses AbUnzper, AbCabExt, AbCabTyp, AbGzTyp, AbBzip2Typ, AbTarTyp, AbUnzPrc, ProcessAlzip, Process7zip, Tocsg.Exception, Tocsg.Trace, Tocsg.Safe, Tocsg.Files, Tocsg.Path; function DecompressFile(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent; aEvtNeedPass: TAbNeedPasswordEvent): string; var fs: TFileStream; ArcType: TAbArchiveType; nEggType: Integer; FileList: TStringList; begin try if not FileExists(sSrcPath) then begin TTgTrace.T('DecompressFile() .. Not found file.. Path="%s"', [sSrcPath]); exit; end; if EGG_IsValidArchive(PWideChar(sSrcPath), @nEggType) = EGG_ERROR_SUCCESS then begin Guard(FileList, TStringList.Create); ExtractAlzipData(sSrcPath, sExportPath, FileList); exit; end; try fs := TFileStream.Create(sSrcPath, fmOpenRead); except on E: Exception do begin ETgException.TraceException(E, 'DecompressFile() .. Fail .. open file..'); Result:= 'unable to analysis to open file'; exit; end; end; ArcType := atUnknown; try fs.Position := 0; ArcType := VerifyZip(fs); // if ArcType = atUnknown then // begin // fs.Position := 0; // ArcType := VerifyCab(fs); // 여기서 AV 오류가 발생한다.. 23_0602 10:39:42 kku // end; if ArcType = atUnknown then begin fs.Position := 0; try ArcType := VerifyTar(fs); except // .. end; end; if ArcType = atUnknown then begin fs.Position := 0; try ArcType := VerifyGzip(fs); except // .. end; end; if ArcType = atUnknown then begin fs.Position := 0; try ArcType := VerifyBzip2(fs); except // .. end; end; finally FreeAndNil(fs); end; TTgTrace.T('[MGKIM].. ArcType : %d', [Integer(ArcType)]); case ArcType of // atUnknown : ; //atZip : ExtractZip(sSrcPath, sExportPath, aEvtProg, aEvtNeedPass); //atSpannedZip : ExtractZip(sSrcPath, sExportPath, aEvtProg, aEvtNeedPass); // atSelfExtZip : ; //atTar : ExtractTar(sSrcPath, sExportPath, aEvtProg); //atGzip : ExtractGzip(sSrcPath, sExportPath, false, aEvtProg); atGzippedTar : ExtractGzip(sSrcPath, sExportPath, true, aEvtProg); //atCab : ExtractCab(sSrcPath, sExportPath, aEvtProg); atBzip2 : ExtractBzip2(sSrcPath, sExportPath, false, aEvtProg); atBzippedTar : ExtractBzip2(sSrcPath, sExportPath, true, aEvtProg); else Result:= Extract7zip(ArcType, sSrcPath, sExportPath); end; except on E: Exception do begin ETgException.TraceException(E, 'Fail .. DecompressFile() .. DoDecompress'); Result:= 'unable to analysis to decompress file'; end; end; end; type TZipErrorHelper = class public HasError: Boolean; procedure OnFailure(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); end; procedure TZipErrorHelper.OnFailure(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); begin if ProcessType = ptExtract then HasError := True; end; procedure ExtractZip(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent; aEvtNeedPass: TAbNeedPasswordEvent); var zip: TAbUnZipper; begin if DirectoryExists(sExportPath) then DeleteDir(sExportPath); if not ForceDirectories(sExportPath) then exit; sExportPath := IncludeTrailingPathDelimiter(sExportPath); Guard(zip, TAbUnzipper.Create(nil)); zip.FileName := sSrcPath; zip.ExtractOptions := [eoCreateDirs, eoRestorePath]; zip.BaseDirectory := sExportPath; zip.OnArchiveProgress := aEvtProg; zip.OnNeedPassword := aEvtNeedPass; try zip.ExtractFiles('*.*'); TTgTrace.T('[MGKIM] ExtractZip() .. ok', []); except on E: Exception do // DeleteDir(sExportPath); TTgTrace.T('[MGKIM] ExtractZip() .. Fail extract compress file.. Path=%s, E.Message : %s', [sSrcPath, E.Message]); end; // 패스워드 입력중 취소 할 경우 추출경로 삭제 if zip.Password = SIG_CANCEL then DeleteDir(sExportPath); end; procedure ExtractCab(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent); var cab: TAbCabExtractor; begin if DirectoryExists(sExportPath) then DeleteDir(sExportPath); if not ForceDirectories(sExportPath) then exit; sExportPath := IncludeTrailingPathDelimiter(sExportPath); Guard(cab, TAbCabExtractor.Create(nil)); cab.FileName := sSrcPath; cab.ExtractOptions := [eoCreateDirs, eoRestorePath]; cab.BaseDirectory := sExportPath; cab.OnArchiveProgress := aEvtProg; try cab.ExtractFiles('*.*'); except // DeleteDir(sExportPath); TTgTrace.T('ExtractCab() .. Fail extract zip file.. Path="%s"', [sSrcPath]); end; end; procedure ExtractTar(sSrcPath, sExportPath: String; aEvtProg: TAbArchiveProgressEvent); var tar: TAbTarArchive; begin if DirectoryExists(sExportPath) then DeleteDir(sExportPath); if not ForceDirectories(sExportPath) then exit; sExportPath := IncludeTrailingPathDelimiter(sExportPath); Guard(tar, TAbTarArchive.Create(sSrcPath, WORD(fmOpenRead))); tar.ExtractOptions := [eoCreateDirs, eoRestorePath]; tar.BaseDirectory := sExportPath; tar.OnArchiveProgress := aEvtProg; try tar.Load; tar.ExtractFiles('*.*'); except on E: Exception do // DeleteDir(sExportPath); TTgTrace.T('ExtractGzip() .. Fail extract zip file.. Path="%s"', [sSrcPath]); end; end; function ExtractGzip(sSrcPath, sExportPath: String; IsGzippedTar: Boolean; aEvtProg: TAbArchiveProgressEvent): string; var gzip: TAbGzipArchive; i: Integer; sUnknownExt, sUnknownName: String; zHelper: TZipErrorHelper; begin Result := ''; if DirectoryExists(sExportPath) then DeleteDir(sExportPath); if not ForceDirectories(sExportPath) then exit; sExportPath := IncludeTrailingPathDelimiter(sExportPath); try Guard(gzip, TAbGzipArchive.Create(sSrcPath, WORD(fmOpenRead))); zHelper := TZipErrorHelper.Create; zHelper.HasError := False; try gzip.TarAutoHandle := true; gzip.IsGzippedTar := IsGzippedTar; gzip.ExtractOptions := [eoCreateDirs, eoRestorePath]; gzip.BaseDirectory := sExportPath; gzip.OnArchiveProgress := aEvtProg; gzip.OnProcessItemFailure := zHelper.OnFailure; // 파일명 정보가 존재하지 않을때 반디집처럼 압축 파일이름(.gz 제외 한)으로 대체 되도록 보완 sUnknownName := ExtractFileName(CutFileExt(sSrcPath)); // 경로와 .gz 빼줌 sUnknownExt := ExtractFileExt(sUnknownName); sUnknownName := CutFileExt(sUnknownName); gzip.Load; for i := 0 to gzip.Count - 1 do begin if gzip.Items[i].FileName = 'unknown' then begin if i = 0 then gzip.Items[i].FileName := sUnknownName + sUnknownExt else gzip.Items[i].FileName := Format('%s (%d)%s', [sUnknownName, i + 1, sUnknownExt]); // gzip.Items[i].FileName := gzip.Items[i].FileName + IntToStr(i); end; end; gzip.ExtractFiles('*.*'); if zHelper.HasError then begin Result := 'unable to analysis'; end; except // DeleteDir(sExportPath); TTgTrace.T('ExtractGzip() .. Fail extract zip file.. Path="%s"', [sSrcPath]); Result := 'unable to analysis'; end; finally zHelper.Free; end; end; function ExtractBzip2(sSrcPath, sExportPath: String; bIsBzippedTar: Boolean; aEvtProg: TAbArchiveProgressEvent): string; var bzip2: TAbBzip2Archive; zHelper: TZipErrorHelper; begin Result:= ''; if DirectoryExists(sExportPath) then DeleteDir(sExportPath); if not ForceDirectories(sExportPath) then exit; sExportPath := IncludeTrailingPathDelimiter(sExportPath); zHelper := TZipErrorHelper.Create; zHelper.HasError := False; Guard(bzip2, TAbBzip2Archive.Create(sSrcPath, WORD(fmOpenRead))); try bzip2.TarAutoHandle := true; bzip2.IsBzippedTar := bIsBzippedTar; bzip2.ExtractOptions := [eoCreateDirs, eoRestorePath]; bzip2.BaseDirectory := sExportPath; bzip2.OnProcessItemFailure := zHelper.OnFailure; try bzip2.Load; bzip2.ExtractFiles('*.*'); if zHelper.HasError then begin Result := 'unable to analysis'; // 에러 상태 반환 end; except // DeleteDir(sExportPath); TTgTrace.T('ExtractBzip2() .. Fail extract zip file.. Path="%s"', [sSrcPath]); Result := 'unable to analysis'; end; finally zHelper.Free; end; end; function Extract7zip(ArcType: TAbArchiveType; sSrcPath, sExportPath: String): string; const SIG_7Z: array[0..4] of Byte = ($37, $7A, $BC, $AF, $27); // 7z... SIG_RAR: array[0..4] of Byte = ($52, $61, $72, $21, $1A); // Rar!. SIG_LZH: array[0..4] of Byte = ($00, $00, $2D, $6C, $68); // Offset: 2 Bytes, Sizet: 3 Bytes var s7zDll: String; fs: TFileStream; pSigBuf: TBytes; SvZip: I7zInArchive; TId: TGUID; state: NExtOperationResult; begin Result:= ''; s7zDll := GetRunExePathDir + DLL_7Z; if not FileExists(s7zDll) then exit; if ArcType = atUnknown then begin try fs := TFileStream.Create(sSrcPath, fmOpenRead); except on E: Exception do begin ETgException.TraceException(E, 'Extract7zip() .. Fail .. open file..'); Result:= 'unalbe to analysis to open file'; exit; end; end; try if fs.Size < 10 then exit; SetLength(pSigBuf, 10); fs.Read(pSigBuf[0], 10); finally fs.Free; end; if CompareMem(@pSigBuf[0], @SIG_7Z[0], 5) then begin TId := CLSID_CFormat7z; end else if CompareMem(@pSigBuf[0], @SIG_RAR[0], 5) then begin TId := CLSID_CFormatRar; end else if CompareMem(@pSigBuf[2], @SIG_LZH[2], 3) then begin TId := CLSID_CFormatLzh; end else exit; end else begin case ArcType of // atUnknown : ; atZip , atSpannedZip : TId := CLSID_CFormatZip; atTar : TId := CLSID_CFormatTar; atGzip : TId := CLSID_CFormatGZip; atCab : TId := CLSID_CFormatCab; else Exit; end; end; try SvZip := CreateInArchive(Tid, s7zDll); SvZip.OpenFile(sSrcPath); SvZip.SetPassword('1234'); state:= SvZip.ExtractTo(sExportPath); if state <> kOK then begin TTgTrace.T('[MGKIM] Extract7zip() .. Fail, state: %d', [Integer(state)]); case state of // kDataError, // kUnavailable, // kUnexpectedEnd, // kDataAfterEnd, // kIsNotArc, // kHeadersError: Result:= 'unalbe to analysis'; kWrongPassword: Result:= 'unable to analysis to password'; else Result:= Format('unable to analysis(%d)', [Integer(state)]); end; end; except on E: Exception do begin TTgTrace.T('[MGKIM] Extract7zip() .. Fail extract compress file.. Path=%s, E.Message : %s', [sSrcPath, E.Message]); Result:= 'unable to analysis to decompress file'; end; end; end; end.