BSOne.SFC/Tocsg.Module/KvFilter/Tocsg.KvFilter.pas

507 lines
14 KiB
Plaintext

{*******************************************************}
{ }
{ Tocsg.KvFilter }
{ }
{ Copyright (C) 2022 kku }
{ }
{*******************************************************}
unit Tocsg.KvFilter;
interface
{$IFNDEF _HE_}
{$DEFINE _IMG_PARSER_}
{$ENDIF}
uses
{$IFDEF _IMG_PARSER_}
imageen, iexMetaHelpers,
{$ENDIF}
Tocsg.Obj, System.SysUtils, System.Classes, WinAPI.Windows,
Tocsg.KvFilter.Types, Tocsg.KvFilter.adinfo, Tocsg.Thread;
const
DLL_KVFILTER = 'kvfilter.dll';
DLL_KVHWP = 'kvhvp.dll';
EXE_KV_TASK = 'kvoop.exe';
EXE_KV_HWP = 'KvCttSchw.exe';
// * KeyView Filter interface revision. To be assigned to KV_GetFilterInterfaceEx().
KVFLTINTERFACE_REVISION = 6;
type
// KvSetTimeout() 때문에 필요없어짐 22_0720 10:20:35 kku
// TThdKvFilterTimeout = class(TTgThread)
// protected
// nTOMilSec_: Integer;
// dwResetTick_: DWORD;
// procedure Execute; override;
// public
// Constructor Create(nTOSec: Integer);
//
// procedure ResetTimeout;
// procedure EndTimeout;
// end;
TKvFilter = class(TTgObject)
private
{$IFDEF _IMG_PARSER_}
bDoFree_: Boolean;
ImgEn_: TImageEn;
{$ENDIF}
nLastError_: Integer;
hKvFilter_: THandle;
KvCtrl_: TKvFltInterfaceEx;
MemAllocator_: TKVMemoryStream;
pFilter_: Pointer;
FnKV_GetFilterInterfaceEx_: TKV_GetFilterInterfaceEx;
FnKV_GetKvErrorCodeEx_: TKV_GetKvErrorCodeEx;
FnKV_FilterConfig_: TKV_FilterConfig;
nFilterTOSec_: Integer;
bUseHwpDll_: Boolean;
// ThdTimeout_: TThdKvFilterTimeout;
sKvBinDir_,
sKvHwpExe_: String;
bProcAnsi_: Boolean; // 영문윈도우에서 한글 깨지는 현상 보완을 위함 24_0514 09:17:24 kku
public
Constructor Create(sDllDir: String = ''; nFilterTOSec: Integer = 0); // nFilterTOSec 필터 타임아웃 추가 22_0720 07:43:25 kku
Destructor Destroy; override;
procedure DoSummaryInfo(sSrcFile: String; aList: TStrings);
function GetDocInfoFile(sSrcFile: String): TAdDocInfo;
function FilterFile(sSrcFile, sDstFile: String): KVErrorCode;
property FilterTOSec: Integer write nFilterTOSec_;
property UseHwpDll: Boolean write bUseHwpDll_;
property KvBinDir: String read sKvBinDir_;
property KvLastError: Integer read nLastError_;
end;
implementation
uses
CttSchDefine,
Tocsg.Exception, Tocsg.Convert, Tocsg.DateTime, Tocsg.Process, Tocsg.Path,
superobject, Tocsg.Files, GlobalDefine;
function _Malloc(pX: Pointer{PKvMemoryStream}; cb: LONGLONG): Pointer; pascal;
begin
Result := AllocMem(cb);
// GetMem(Result, cb);
end;
procedure _Free(pX: Pointer{PKvMemoryStream}; ptr: Pointer); pascal;
begin
FreeMem(ptr);
end;
function _Realloc(pX: Pointer{PKvMemoryStream}; ptr: Pointer; cb: LONGLONG): Pointer; pascal;
begin
ReallocMem(ptr, cb);
Result := ptr;
// Result := ReallocMemory(ptr, cb);
end;
function _Calloc(pX: Pointer{PKvMemoryStream}; ne, s: LONGLONG): Pointer; pascal;
begin
Result := AllocMem(ne);
ZeroMemory(Result, s);
// GetMem(Result, ne);
// ZeroMemory(Result, s);
end;
{ TThdKvFilterTimeout }
//Constructor TThdKvFilterTimeout.Create(nTOSec: Integer);
//begin
// Inherited Create;
// nTOMilSec_ := nTOSec * 1000;
// dwResetTick_ := 0;
// StartThread;
//end;
//
//procedure TThdKvFilterTimeout.ResetTimeout;
//begin
// Lock;
// try
// dwResetTick_ := GetTickCount;
// finally
// Unlock;
// end;
//end;
//
//procedure TThdKvFilterTimeout.EndTimeout;
//begin
// Lock;
// try
// dwResetTick_ := 0;
// finally
// Unlock;
// end;
//end;
//
//procedure TThdKvFilterTimeout.Execute;
//var
// dwResetTick: DWORD;
//begin
// while not Terminated and not GetWorkStop do
// begin
// if nTOMilSec_ > 0 then
// begin
// try
// Lock;
// try
// dwResetTick := dwResetTick_;
// finally
// Unlock;
// end;
//
// if dwResetTick > 0 then
// begin
// if (GetTickCount - dwResetTick) > nTOMilSec_ then
// begin
// // 두번 죽여야 됨 22_0720 08:54:56 kku
// TerminateProcessByName(EXE_KV_TASK);
// Sleep(1000);
// TerminateProcessByName(EXE_KV_TASK);
// EndTimeout;
// end;
// end;
// except
// on E: Exception do
// ETgException.TraceException(Self, E, 'Fail .. Execute()');
// end;
// end;
// Sleep(1000);
// end;
//end;
{$IFDEF _IMG_PARSER_}
function ImgToTxtFile(sSrcPath: String; sDstPath: String): Boolean;
var
sOcr: String;
StrList: TStringList;
begin
Result := false;
sOcr := GetRunExePathDir + DIR_CONF + EXE_OCR;
if not FileExists(sOcr) then
sOcr := GetRunExePathDir + EXE_OCR;
if FileExists(sOcr) then
begin
if ForceDirectories(ExtractFilePath(sDstPath)) then
begin
ExecuteAppWaitUntilTerminate(sOcr, Format('"%s" "%s"', [sSrcPath, sDstPath]), SW_HIDE);
Result := FileExists(sDstPath);
end;
end;
end;
{$ENDIF}
{ TKvFilter}
Constructor TKvFilter.Create(sDllDir: String = ''; nFilterTOSec: Integer = 0);
procedure InitProcedure;
var
sDllPath: String;
nResult: KVErrorCode;
begin
if sDllDir = '' then
begin
sDllDir := GetRunExePathDir;
if not FileExists(sDllDir + DLL_KVFILTER) then
sDllDir := sDllDir + 'bin\';
end else
sDllDir := IncludeTrailingPathDelimiter(sDllDir);
sDllPath := sDllDir + DLL_KVFILTER;
if FileExists(sDllDir + DLL_KVHWP) and
FileExists(GetRunExePathDir + EXE_KV_HWP) then
sKvHwpExe_ := GetRunExePathDir + EXE_KV_HWP;
hKvFilter_ := LoadLibrary(PChar(sDllPath));
if hKvFilter_ = 0 then
begin
_Trace('Fail .. LoadLibrary(), Path="%s"', [sDllPath]);
nLastError_ := KVERR_DLLNotFound;
exit;
end;
sKvBinDir_ := sDllPath;
FnKV_GetFilterInterfaceEx_ := GetProcAddress(hKvFilter_, 'KV_GetFilterInterfaceEx');
if not Assigned(FnKV_GetFilterInterfaceEx_) then
begin
_Trace('Fail .. KV_GetFilterInterfaceEx() is NULL, Path="%s"', [sDllPath]);
nLastError_ := KVERR_General;
exit;
end;
FnKV_GetKvErrorCodeEx_ := GetProcAddress(hKvFilter_, 'KV_GetKvErrorCodeEx');
if not Assigned(FnKV_GetKvErrorCodeEx_) then
begin
_Trace('Fail .. KV_GetKvErrorCodeEx() is NULL, Path="%s"', [sDllPath]);
nLastError_ := KVERR_General;
exit;
end;
FnKV_FilterConfig_ := GetProcAddress(hKvFilter_, 'KV_FilterConfig');
if not Assigned(FnKV_FilterConfig_) then
begin
_Trace('Fail .. KV_FilterConfig() is NULL, Path="%s"', [sDllPath]);
nLastError_ := KVERR_General;
exit;
end;
nResult := FnKV_GetFilterInterfaceEx_(@KvCtrl_, KVFLTINTERFACE_REVISION);
if nResult <> KVERR_Success then
begin
_Trace('Fail .. KV_GetFilterInterfaceEx() .. ErrCode=%d, Path="%s"', [nResult, sDllPath]);
nLastError_ := nResult;
exit;
end;
MemAllocator_.pMemoryStreamPrivateData := nil;
MemAllocator_.KvMalloc := _Malloc;
MemAllocator_.KvFree := _Free;
MemAllocator_.KvRealloc := _Realloc;
MemAllocator_.KvCalloc := _Calloc;
pFilter_ := KvCtrl_.KvInit(@MemAllocator_, nil, PAnsiChar(AnsiString(sDllDir)), KVCS_UTF8, 0);
end;
begin
Inherited Create;
bProcAnsi_ := GetUserDefaultLangID <> 1042;
sKvHwpExe_ := '';
nLastError_ := 0;
nFilterTOSec_ := nFilterTOSec;
if nFilterTOSec_ = 0 then
nFilterTOSec_ := 7;
ZeroMemory(@KvCtrl_, SizeOf(KvCtrl_));
pFilter_ := nil;
bUseHwpDll_ := true;
InitProcedure;
if pFilter_ <> nil then
KvCtrl_.KvSetTimeout(pFilter_, nFilterTOSec_);
{$IFDEF _IMG_PARSER_}
ImgEn_ := TImageEn.Create(nil);
bDoFree_ := true;
// bDoFree_ := false;
// if aImgEn <> nil then
// begin
// ImgEn_ := aImgEn;
// end else begin
// ImgEn_ := nil;
//// ImgEn_ := TImageEn.Create(nil);
//// bDoFree_ := true;
// end;
{$ENDIF}
// ThdTimeout_ := TThdKvFilterTimeout.Create(nFilterTOSec_);
end;
Destructor TKvFilter.Destroy;
begin
// TerminateProcessByName(EXE_KV_TASK); // 이거 하고 두번째 TKvFilter.Destroy() 시 KvShutdown() 에서 크러쉬 됨 22_0720 10:28:30 kku
// FreeAndNil(ThdTimeout_);
try
// 여기서 크러쉬가 나는데... 원인을 찾을때까지는 봉인한다.
// 해제 시 앱이 강제종료 되는 치면적인 문제 있음
// 이거 안하면 릭이 발생함... 22_0712 16:06:12 kku
// if (pFilter_ <> nil) and Assigned(KvCtrl_.KvShutdown) then
// KvCtrl_.KvShutdown(pFilter_);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. Destroy() - KvShutdown()');
end;
if hKvFilter_ <> 0 then
FreeLibrary(hKvFilter_);
// KvShutdown() 처리를 안하면 kvoop.exe가 남아 있다.. 그래서 처리 추가 22_0720 10:37:07 kku
TerminateProcessByName(EXE_KV_TASK);
{$IFDEF _IMG_PARSER_}
if (ImgEn_ <> nil) and bDoFree_ then
FreeAndNil(ImgEn_);
{$ENDIF}
Inherited;
end;
procedure TKvFilter.DoSummaryInfo(sSrcFile: String; aList: TStrings);
var
si: TKVSummaryInfoEx;
i: Integer;
sInfo: String;
pEnt: PKvSumInfoElemEx;
ft: TFileTime;
begin
aList.Clear;
try
if (pFilter_ <> nil) and
Assigned(KvCtrl_.KvGetOLESummaryInfoFile) and
Assigned(KvCtrl_.KvFreeOLESummaryInfo) then
begin
ZeroMemory(@si, SizeOf(si));
if KvCtrl_.KvGetOLESummaryInfoFile(pFilter_, PAnsiChar(AnsiString(sSrcFile)), @si) <> KVERR_Success then
begin
_Trace('Fail .. DoSummaryInfo() .. 1');
exit;
end;
try
if si.nElem = 0 then
exit;
for i := 0 to si.nElem - 1 do
begin
pEnt := PKvSumInfoElemEx(NativeInt(si.pElem) + (SizeOf(TKvSumInfoElemEx) * i));
if pEnt.nIsValid = 0 then
continue;
sInfo := Format('%d %d ', [pEnt.nIsValid, pEnt.nType]);
case pEnt.nType of
KV_String : sInfo := sInfo + Format('"%s"', [PUTF8Char(pEnt.pData)]);
KV_Int4 : sInfo := sInfo + Format('%d', [Integer(pEnt.pData)]);
KV_DateTime :
begin
CopyMemory(@ft, pEnt.pData, 8);
if i = 9 then
begin
sInfo := sInfo + Format('%d Minutes', [LONGLONG(ft) div 600000000]);
end else begin
sInfo := sInfo + DateTimeToStr(ConvFileTimeToDateTime(ft));
end;
end;
KV_ClipBoard : sInfo := sInfo + 'Clipboard data';
KV_Bool : sInfo := sInfo + BooleanToStr(Integer(pEnt.pData) <> 0, 'true', 'false');
KV_Unicode : sInfo := sInfo + Format('U"%s"', [PChar(pEnt.pData)]);
KV_IEEE8 : sInfo := sInfo + Format('%f', [pEnt.pData]);
KV_Other : sInfo := sInfo + 'Other';
else sInfo := sInfo + Format('Bad element type! - %d', [pEnt.nType]);
end;
aList.Add(sInfo + Format(' %s', [BooleanToStr(pEnt.nIsValid = 1, AnsiString(pEnt.pcType), '(null)')]));
end;
finally
KvCtrl_.KvFreeOLESummaryInfo(pFilter_, @si);
end;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. DoSummaryInfo()');
end;
end;
function TKvFilter.GetDocInfoFile(sSrcFile: String): TAdDocInfo;
begin
ZeroMemory(@Result, SizeOf(Result));
if (pFilter_ <> nil) and Assigned(KvCtrl_.KvGetDocInfoFile) then
KvCtrl_.KvGetDocInfoFile(pFilter_, PAnsiChar(AnsiString(sSrcFile)), @Result);
end;
function TKvFilter.FilterFile(sSrcFile, sDstFile: String): KVErrorCode;
var
sExt,
sTemp: String;
begin
// _Trace('FilterFile() .. Path=%s', [sSrcFile]);
// if not FileExists(sSrcFile) then
// begin
// Result := -2;
// exit;
// end;
Result := -1;
try
sExt := GetFileExt(sSrcFile).ToUpper;
if (sExt = 'TXT') or (sExt = 'LOG') or (sExt = 'HTML') or
(sExt = 'HTM') or (sExt = 'XML') or (sExt = 'JSON') or
(sExt = 'CSV') or (sExt = 'INI') then
begin
if CopyFile(PChar(sSrcFile), PChar(sDstFile), false) then
Result := KVERR_Success
else
Result := KVERR_CreateOutputFileFailed;
end else
{$IFDEF _IMG_PARSER_}
if (sExt = 'DCM') and (ImgEn_ <> nil) and ImgEn_.IO.LoadFromFile(sSrcFile) then
begin
var StrList: TStringList := TStringList.Create;
try
ImgEn_.IO.Params.Dicom_WriteToStrings(StrList, [diProprietary, diChildTags]);
if StrList.Text <> '' then
begin
StrList.SaveToFile(sDstFile, TEncoding.UTF8);
Result := KVERR_Success;
end;
finally
FreeAndNil(StrList);
end;
end else
if (Pos(sExt, OCR_IMG_EXTS) > 0) and ImgToTxtFile(sSrcFile, sDstFile) then
begin
Result := KVERR_Success;
end else
{$ENDIF}
if (pFilter_ <> nil) and Assigned(KvCtrl_.KvFilterFile) then
begin
if bUseHwpDll_ and (sKvHwpExe_ <> '') and
(sExt = 'HWP') or (sExt = 'HWPX') then
begin
Result := -2;
sTemp := GetRunExePathDir + '$KvHvpInfo.j$on';
var O: ISuperObject := SO;
O.S['Src'] := sSrcFile;
O.S['Dest'] := sDstFile;
if SaveJsonObjToFile(O, sTemp) then
begin
ExecuteAppWaitUntilTerminate(sKvHwpExe_, Format('"%s"', [sTemp]), SW_HIDE, 5000);
if FileExists(sDstFile) then
Result := KVERR_Success;
end;
end else begin
// ThdTimeout_.ResetTimeout;
// Result := KvCtrl_.KvFilterFile(pFilter_, PAnsiChar(AnsiString(sSrcFile)), PAnsiChar(AnsiString(sDstFile)), nil);
// ThdTimeout_.EndTimeout;
if bProcAnsi_ then
begin
var sBkPath: UTF8String := 'C:\ProgramData\HE\kvansi\';
if ForceDirectories(sBkPath) then
begin
sBkPath := sBkPath + IntToStr(GetTickCount);
try
Result := KvCtrl_.KvFilterFile(pFilter_, PUTF8Char(UTF8String(sSrcFile)), PUTF8Char(UTF8String(sBkPath)), nil);
if Result = KVERR_Success then
MoveFile_wait(sBkPath, sDstFile);
finally
if FileExists(sBkPath) then
DeleteFileA(PAnsiChar(sBkPath));
end;
end;
end else
Result := KvCtrl_.KvFilterFile(pFilter_, PUTF8Char(UTF8String(sSrcFile)), PUTF8Char(UTF8String(sDstFile)), nil);
end;
end;
except
on E: Exception do
begin
ETgException.TraceException(Self, E, 'Fail .. FilterFile()');
Result := -99;
end;
end;
end;
end.