BSOne.SFC/Tocsg.Lib/VCL/Tocsg.AIP.pas

350 lines
11 KiB
Plaintext

{*******************************************************}
{ }
{ Tocsg.AIP }
{ }
{ Copyright (C) 2024 kku }
{ }
{*******************************************************}
unit Tocsg.AIP;
interface
uses
System.SysUtils, System.Classes, Winapi.ActiveX;
const
SIGN_AIP_DRM: array [0..23] of Byte = ($2E, $70, $66, $69, $6C, $65, $03, $00,
$00, $00, $00, $00, $00, $00, $8C, $01,
$00, $00, $0D, $0A, $0D, $0A, $0D, $0A); // .pfile 로 시작
function IsAipEncrytedPDF(sPath: String): Boolean;
function GetAipLabelNameFromPDF(sPath: String): String;
function IsAipEncrytedOldOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
function GetAipLabelNameFromOldOfficeDoc(sPath: String): String;
function IsAipEncrytedOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
function GetAipLabelNameFromOfficeDoc(sPath: String): String;
function CheckMsPfileExt(sPath: String): Boolean;
function CheckAipEncSign(sPath: String): Boolean;
function IsAipEncryted(sPath: String; sTempDir: String = ''; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
function ConvAipEncExt(sPath: String): String;
implementation
uses
Tocsg.Exception, Tocsg.Hex, Winapi.Windows, Tocsg.Strings, Tocsg.Safe,
AbUnzper, System.Zip, Tocsg.Path, Tocsg.OLE.Stg, Tocsg.Files;
function IsAipEncrytedPDF(sPath: String): Boolean;
var
fs: TFileStream;
pBuf: TBytes;
sDelPath: String;
begin
Result := false;
try
sDelPath := 'C:\ProgramData\HE\AEN\';
if sPath.ToUpper.StartsWith(sDelPath.ToUpper) then
exit;
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncrytedPDF() .. Path=%s, TempDir=%s', [sPath, sDelPath]));
if ForceDirectories(sDelPath) then
begin
sDelPath := sDelPath + '$' + ExtractFileName(sPath);
if CopyFile(PChar(sPath), PChar(sDelPath), false) then
begin
try
Guard(fs, TFileStream.Create(sDelPath, fmOpenRead or fmShareDenyNone));
SetLength(pBuf, 2048);
if fs.Read(pBuf[0], 2048) <> 2048 then
exit;
Result := PosBin(TEncoding.UTF8.GetBytes('MicrosoftIRMServices Protected PDF'), pBuf) <> -1;
finally
if sDelPath <> '' then
DeleteFileForce(sDelPath);
end;
end;
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. IsAipEncryted()');
end;
end;
function GetAipLabelNameFromPDF(sPath: String): String;
//const
// p: array [0..13] of Byte = ($FE, $FF, $C7, $7C, $BC, $18, $00, $20, $B8, $08, $C7, $74, $BE, $14); // "일반 레이블"
var
fs: TFileStream;
pBuf, pLabel: TBytes;
nBufLen, nPos, nEnd, nLabelLen: Integer;
begin
Result := 'Unknown';
try
if not FileExists(sPath) then
exit;
nBufLen := 1024;
SetLength(pBuf, nBufLen);
fs := TFileStream.Create(sPath, fmOpenRead or fmShareDenyNone);
// 암호화 레이블로 적용되었는지 확인
if fs.Read(pBuf[0], nBufLen) <> nBufLen then
exit;
if PosBin(TEncoding.UTF8.GetBytes('MicrosoftIRMServices Protected PDF'), pBuf) <> -1 then
begin
// 암호화된 레이블 정보 위치
fs.Seek(27440, soBeginning);
fs.Read(pBuf[0], nBufLen);
end else begin
// 일반 레이블 정보 위치
fs.Seek(-1024, soEnd);
fs.Read(pBuf[0], nBufLen);
end;
nPos := PosBin(TEncoding.UTF8.GetBytes('/MSIP_Label_'), pBuf);
if nPos > -1 then
begin
nPos := PosBin(TEncoding.UTF8.GetBytes('_Name ('), pBuf, nPos);
if nPos > -1 then
begin
Inc(nPos, 7);
nEnd := PosBin(TEncoding.UTF8.GetBytes(')'), pBuf, nPos);
nLabelLen := nEnd - nPos;
if (nEnd > -1) and (nLabelLen > 0) then
begin
SetLength(pLabel, nLabelLen);
CopyMemory(pLabel, @pBuf[nPos], nLabelLen);
if pLabel[0] = $FE then
Result := TEncoding.BigEndianUnicode.GetString(pLabel)
else
Result := TEncoding.ANSI.GetString(pLabel);
end;
end;
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. GetAipLabelNameFromPDF()');
end;
end;
function IsAipEncrytedOldOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
var
// fs: TFileStream;
// pBuf: TBytes;
// nBufLen: Integer;
pvStg: IStorage;
sData: WideString;
enum: IEnumStatStg;
elt: TStatStg;
sDelPath: String;
begin
Result := false;
try
if sPath.ToUpper.StartsWith(sTempDir.ToUpper) then
exit;
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncrytedOldOfficeDoc() .. Path=%s, TempDir=%s', [sPath, sTempDir]));
pvStg := nil;
sDelPath := '';
try
// 쉘 익스텐션 GetIconLocation() 에선 STGM_SHARE_EXCLUSIVE 모드 사용 시 스톱되서 아래처럼 처리 25_0122 14:03:25 kku
if not StgStorageFileOpen(sPath, pvStg, nMode) then
begin
if (sTempDir <> '') and ForceDirectories(sTempDir) then
begin
// MS 파일은 사용중이면 안열려서 이렇게 처리 24_1114 09:24:47 kku
sDelPath := sTempDir + '$' + ExtractFileName(sPath);
if CopyFile(PChar(sPath), PChar(sDelPath), false) then
begin
if not StgStorageFileOpen(sDelPath, pvStg) then
exit;
end else exit;
end else exit;
end;
if pvStg = nil then
exit;
enum := nil;
if StgGetEnumElements(pvStg, enum) then
Result := StgGetStatStgLike(enum, 'DRMContent', elt);
finally
enum := nil;
pvStg := nil;
if sDelPath <> '' then
DeleteFileForce(sDelPath);
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. IsAipEncrytedOldOfficeDoc()');
end;
end;
function GetAipLabelNameFromOldOfficeDoc(sPath: String): String;
begin
Result := 'Unknown';
end;
function IsAipEncrytedOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
var
pvStg: IStorage;
sData: WideString;
sDelPath: String;
begin
Result := false;
try
if sPath.ToUpper.StartsWith(sTempDir.ToUpper) then
exit;
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncrytedOfficeDoc() .. Path=%s, TempDir=%s', [sPath, sTempDir]));
pvStg := nil;
sDelPath := '';
try
// 쉘 익스텐션 GetIconLocation() 에선 STGM_SHARE_EXCLUSIVE 모드 사용 시 스톱되서 아래처럼 처리 25_0122 14:03:25 kku
if not StgStorageFileOpen(sPath, pvStg, nMode) then
begin
// MS 파일은 사용중이면 안열려서 이렇게 처리 24_1114 09:24:47 kku
if (sTempDir <> '') and ForceDirectories(sTempDir) then
begin
// MS 파일은 사용중이면 안열려서 이렇게 처리 24_1114 09:24:47 kku
sDelPath := sTempDir + '$' + ExtractFileName(sPath);
if CopyFile(PChar(sPath), PChar(sDelPath), false) then
begin
if not StgStorageFileOpen(sDelPath, pvStg) then
exit;
end else exit;
end else exit;
end;
if pvStg = nil then
exit;
Result := StgGetStreamToText(pvStg, 'EncryptedPackage', sData);
finally
pvStg := nil;
if sDelPath <> '' then
DeleteFileForce(sDelPath);
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. IsAipEncrytedOldOfficeDoc()');
end;
end;
function GetAipLabelNameFromOfficeDoc(sPath: String): String;
begin
Result := 'Unknown';
end;
// MS문서 중 .pfile로 변경 가능성이 있는 확장자인지 체크 25_1222 17:52:57 kku
function CheckMsPfileExt(sPath: String): Boolean;
var
sExt: String;
begin
sExt := GetFileExt(sPath).ToUpper;
Result := (sExt = 'DOC') or (sExt = 'XLS') or (sExt = 'PPT') or
(sExt = 'DOT') or (sExt = 'PPS') or (sExt = 'POT') or
(sExt = 'XLT') or (sExt = 'XLTM') or (sExt = 'XLTX') or
(sExt = 'XPS') or (sExt = 'DOTM') or (sExt = 'PPSM') or
(sExt = 'PPSX') or (sExt = 'PPTM') or (sExt = 'XPS');
end;
function CheckAipEncSign(sPath: String): Boolean;
begin
Result := false;
try
if not FileExists(sPath) then
exit;
Result := CheckSign(sPath, @SIGN_AIP_DRM[0], 24);
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. CheckAipEncSign()');
end;
end;
function IsAipEncryted(sPath: String; sTempDir: String = ''; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
var
sExt: String;
begin
Result := false;
try
if not FileExists(sPath) then
exit;
if sPath.ToUpper.StartsWith(sTempDir.ToUpper) then
exit;
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncryted() .. Path=%s, TempDir=%s', [sPath, sTempDir]));
Result := CheckAipEncSign(sPath);
if not Result then
begin
sExt := GetFileExt(sPath).ToUpper;
if sExt = 'PDF' then
begin
Result := IsAipEncrytedPDF(sPath);
end else
if CheckMsPfileExt(sPath) then
begin
Result := IsAipEncrytedOldOfficeDoc(sPath, sTempDir, nMode);
if not Result then
Result := IsAipEncrytedOfficeDoc(sPath, sTempDir, nMode);
end else
if (sExt = 'DOCX') or (sExt = 'XLSX') or (sExt = 'PPTX') or
(sExt = 'DOCM') or (sExt = 'DOTX') or (sExt = 'XLSM') or
(sExt = 'XLSB') then
begin
Result := IsAipEncrytedOfficeDoc(sPath, sTempDir, nMode);
end;
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. IsAipEncryted()');
end;
end;
function ConvAipEncExt(sPath: String): String;
var
sExt, sPathNoExt: String;
begin
Result := sPath;
if sPath = '' then
exit;
sExt := GetFileExt(sPath).ToUpper;
sPathNoExt := CutFileExt(sPath);
if sExt = 'TXT' then
Result := sPathNoExt + '.ptxt'
else if sExt = 'XML' then
Result := sPathNoExt + '.pxml'
else if sExt = 'PNG' then
Result := sPathNoExt + '.ppng'
else if sExt = 'BMP' then
Result := sPathNoExt + '.pbmp'
else if sExt = 'JPG' then
Result := sPathNoExt + '.pjpg'
else if sExt = 'JPEG' then
Result := sPathNoExt + '.pjpeg'
else if (sExt <> 'DOCX') and (sExt <> 'XLSX') and
(sExt <> 'PPTX') and (sExt <> 'PDF') and
(sExt <> 'XLSB') and (sExt <> 'XLSM') and
(sExt <> 'DOTX') and (sExt <> 'DOCM') and
(sExt <> 'DOC') and (sExt <> 'XLS') and
(sExt <> 'PPT') and (sExt <> 'DOT') and
(sExt <> 'PPS') and (sExt <> 'POT') and
(sExt <> 'XLT') and (sExt <> 'XLTM') and (sExt <> 'XLTX') and
(sExt <> 'XPS') and (sExt <> 'DOTM') and (sExt <> 'PPSM') and
(sExt <> 'PPSX') and (sExt <> 'PPTM') and (sExt <> 'XPS') then
begin
Result := sPath + '.pfile';
end;
end;
end.