You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
483 lines
9.7 KiB
C++
483 lines
9.7 KiB
C++
#include "stdafx.h"
|
|
#include "../FormaConversion/DFDConversion.h"
|
|
#include "FileUtility.h"
|
|
|
|
// 不能修改,否则打开文件会有问题
|
|
static const char KEV_XORKEY[] = "VersionRamanujan";
|
|
|
|
/**
|
|
* @brief 异或加密
|
|
*
|
|
* @param data
|
|
* @param key
|
|
*/
|
|
void XorEncrypt(LPTSTR lpData, DWORD len, LPCTSTR lpKey) {
|
|
size_t key_len = strlen(lpKey);
|
|
for (size_t i = 0; i < len; i++) {
|
|
lpData[i] ^= lpKey[i % key_len];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 异或加密指定文件.
|
|
*
|
|
* @param lpFilePath
|
|
* @return
|
|
*/
|
|
BOOL XorEncryptFile(LPCTSTR lpFilePath)
|
|
{
|
|
HANDLE hDstFile = CreateFile(lpFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hDstFile == INVALID_HANDLE_VALUE) {
|
|
TRACE("Failed to open destination file, error code: %d\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwFileSizeHigh = 0;
|
|
DWORD dwFileSizeLow = GetFileSize(hDstFile, &dwFileSizeHigh);
|
|
HANDLE hMapping = CreateFileMapping(hDstFile, NULL, PAGE_READWRITE, dwFileSizeHigh, dwFileSizeLow, NULL);
|
|
if (hMapping == NULL) {
|
|
TRACE("Failed to create file mapping, error code: %d\n", GetLastError());
|
|
CloseHandle(hDstFile);
|
|
return FALSE;
|
|
}
|
|
LPVOID lpMapping = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
|
if (lpMapping == NULL) {
|
|
TRACE("Failed to map view of file, error code: %d\n", GetLastError());
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hDstFile);
|
|
return FALSE;
|
|
}
|
|
|
|
LARGE_INTEGER large_integer;
|
|
GetFileSizeEx(hDstFile, &large_integer);
|
|
XorEncrypt((LPTSTR)lpMapping, large_integer.QuadPart, KEV_XORKEY);
|
|
|
|
UnmapViewOfFile(lpMapping);
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hDstFile);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief 创建临时加密文件.
|
|
*
|
|
* @param lpSrcFilePath 指定的源文件
|
|
* @param lpDstFilePath 指定的临时文件
|
|
* @return
|
|
*/
|
|
BOOL XorEncryptFile(LPCTSTR lpSrcFilePath, LPCTSTR lpDstFilePath)
|
|
{
|
|
bool ret = false;
|
|
if (!CheckAndCreateDirectory(GetTempDirectory()))
|
|
{
|
|
return false;
|
|
}
|
|
if (lpDstFilePath != NULL && strcmp(lpSrcFilePath, lpDstFilePath) != 0)
|
|
{
|
|
ret = CopyLargeFileByMapping(lpSrcFilePath, lpDstFilePath);
|
|
if (!ret)
|
|
{
|
|
return false;
|
|
}
|
|
ret = XorEncryptFile(lpDstFilePath);
|
|
}
|
|
else {
|
|
ret = XorEncryptFile(lpSrcFilePath);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief 文件映射内存拷贝
|
|
*
|
|
* @param lpSrcFilePath
|
|
* @param lpDstFilePath
|
|
* @return
|
|
*/
|
|
BOOL CopyLargeFileByMapping(LPCTSTR lpSrcFilePath, LPCTSTR lpDstFilePath)
|
|
{
|
|
HANDLE hSrcFile = CreateFile(lpSrcFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
if (hSrcFile == INVALID_HANDLE_VALUE) {
|
|
TRACE("Failed to open source file, error code: %d\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwFileSizeHigh = 0, dwFileSizeLow = GetFileSize(hSrcFile, &dwFileSizeHigh);
|
|
if (dwFileSizeLow == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) {
|
|
TRACE("Failed to get the size of source file, error code: %d\n", GetLastError());
|
|
CloseHandle(hSrcFile);
|
|
return FALSE;
|
|
}
|
|
|
|
HANDLE hDstFile = CreateFile(lpDstFilePath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hDstFile == INVALID_HANDLE_VALUE) {
|
|
TRACE("Failed to create destination file, error code: %d\n", GetLastError());
|
|
CloseHandle(hSrcFile);
|
|
return FALSE;
|
|
}
|
|
|
|
HANDLE hMapping = CreateFileMapping(hSrcFile, NULL, PAGE_READONLY, dwFileSizeHigh, dwFileSizeLow, NULL);
|
|
if (hMapping == NULL) {
|
|
TRACE("Failed to create file mapping, error code: %d\n", GetLastError());
|
|
CloseHandle(hDstFile);
|
|
CloseHandle(hSrcFile);
|
|
return FALSE;
|
|
}
|
|
|
|
LPVOID lpMapping = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
|
|
if (lpMapping == NULL) {
|
|
TRACE("Failed to map view of file, error code: %d\n", GetLastError());
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hDstFile);
|
|
CloseHandle(hSrcFile);
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwBytesWritten = 0;
|
|
if (!WriteFile(hDstFile, lpMapping, dwFileSizeLow, &dwBytesWritten, NULL) || dwBytesWritten != dwFileSizeLow) {
|
|
TRACE("Failed to write to destination file, error code: %d\n", GetLastError());
|
|
UnmapViewOfFile(lpMapping);
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hDstFile);
|
|
CloseHandle(hSrcFile);
|
|
return FALSE;
|
|
}
|
|
|
|
UnmapViewOfFile(lpMapping);
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hDstFile);
|
|
CloseHandle(hSrcFile);
|
|
|
|
TRACE("Successfully copied the file!\n");
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief 判断是否是UNICODE文件.
|
|
*
|
|
* @param filename
|
|
* @return
|
|
*/
|
|
bool IsUnicodeTextFile(const char *filename) {
|
|
HANDLE fileHandle = CreateFile(
|
|
filename, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
perror("Failed to open file");
|
|
return false;
|
|
}
|
|
|
|
DWORD fileSize = GetFileSize(fileHandle, NULL);
|
|
if (fileSize == INVALID_FILE_SIZE) {
|
|
CloseHandle(fileHandle);
|
|
perror("Failed to get file size");
|
|
return false;
|
|
}
|
|
|
|
HANDLE mappingHandle = CreateFileMapping(
|
|
fileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
if (mappingHandle == NULL) {
|
|
CloseHandle(fileHandle);
|
|
perror("Failed to create file mapping");
|
|
return false;
|
|
}
|
|
|
|
LPVOID fileBuffer = MapViewOfFile(mappingHandle, FILE_MAP_READ, 0, 0, fileSize);
|
|
if (fileBuffer == NULL) {
|
|
CloseHandle(mappingHandle);
|
|
CloseHandle(fileHandle);
|
|
perror("Failed to map view of file");
|
|
return false;
|
|
}
|
|
|
|
bool isText = IsTextUnicode(fileBuffer, fileSize, NULL);
|
|
|
|
UnmapViewOfFile(fileBuffer);
|
|
CloseHandle(mappingHandle);
|
|
CloseHandle(fileHandle);
|
|
|
|
return isText;
|
|
}
|
|
|
|
/**
|
|
* @brief 是否是二进制文件.
|
|
*
|
|
* @param file
|
|
* @return
|
|
*/
|
|
bool IsBinaryFile(CString filePath)
|
|
{
|
|
FILE* file = fopen(filePath, "rb");
|
|
if (file == NULL)
|
|
{
|
|
return false; // 打开文件失败,默认认为不是二进制文件
|
|
}
|
|
|
|
int isBinary = false;
|
|
unsigned char buffer[512];
|
|
size_t bytesRead = fread(buffer, 1, sizeof(buffer), file);
|
|
|
|
if (bytesRead > 0)
|
|
{
|
|
for (size_t i = 0; i < bytesRead; i++)
|
|
{
|
|
if (buffer[i] <= 8 || buffer[i] == 11 || buffer[i] == 12 || buffer[i] == 14 || buffer[i] == 15)
|
|
{
|
|
isBinary = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(file);
|
|
return isBinary;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief 获取文件首行.
|
|
*
|
|
* @param filePath
|
|
* @return
|
|
*/
|
|
CString GetFirstLineOfFile(const CString& filePath)
|
|
{
|
|
CStdioFile file;
|
|
if (!file.Open(filePath, CFile::modeRead))
|
|
{
|
|
return ""; // 打开文件失败,返回空字符串
|
|
}
|
|
|
|
TCHAR firstLine[256];
|
|
file.ReadString(firstLine, sizeof(firstLine) / sizeof(TCHAR) - 1);
|
|
file.Close();
|
|
|
|
return CString(firstLine);
|
|
}
|
|
|
|
/**
|
|
* @brief 预处理文件.
|
|
*
|
|
* @param filePath
|
|
* @return 临时文件
|
|
*/
|
|
CString PreprocessFile(CString& filePath)
|
|
{
|
|
CString path = filePath;
|
|
path.MakeLower();
|
|
CSplitPath sp(path);
|
|
CString ext = sp.GetExtension();
|
|
if (!CheckAndCreateDirectory(GetTempDirectory()))
|
|
{
|
|
return false;
|
|
}
|
|
if (ext == ".kev")
|
|
{
|
|
if (!IsBinaryFile(filePath))
|
|
{
|
|
return filePath;
|
|
}
|
|
else
|
|
{
|
|
CString tmpPath = generateTempFile(filePath);
|
|
if (XorEncryptFile(filePath, tmpPath))
|
|
{
|
|
return tmpPath;
|
|
}
|
|
else
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
else if (ext == ".dfd")
|
|
{
|
|
CString ver = GetFirstLineOfFile(filePath);
|
|
ver.Trim();
|
|
if (ver.CompareNoCase("Version 2022") <= 0)
|
|
{
|
|
return filePath;
|
|
}
|
|
else if (ver.CompareNoCase("Version 2022") > 0 && ver.CompareNoCase("Version 2032") <= 0)
|
|
{
|
|
CString tmpPath = generateTempFile(filePath);
|
|
int ret = FromDFDToDFD4(filePath.GetBuffer(), tmpPath.GetBuffer());
|
|
if (ret == 0)
|
|
{
|
|
return "";
|
|
}
|
|
else
|
|
{
|
|
return tmpPath;
|
|
}
|
|
}
|
|
else {
|
|
return "";
|
|
}
|
|
}
|
|
return filePath;
|
|
}
|
|
|
|
/**
|
|
* @brief 后处理文件.
|
|
*
|
|
* @param filePath
|
|
* @return
|
|
*/
|
|
void PostProcessFile(CString& filePath)
|
|
{
|
|
CString path = filePath;
|
|
path.MakeLower();
|
|
CSplitPath sp(path);
|
|
CString ext = sp.GetExtension();
|
|
if (ext == ".kev")
|
|
{
|
|
XorEncryptFile(filePath);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 清除文件夹内的所有内容.
|
|
*
|
|
* @param folderPath
|
|
*/
|
|
void ClearFolder(const CString& folderPath)
|
|
{
|
|
try
|
|
{
|
|
// 搜索指定文件夹下的所有文件和文件夹
|
|
CString searchPath = folderPath + _T("\\*.*");
|
|
CFileFind finder;
|
|
BOOL bWorking = finder.FindFile(searchPath);
|
|
|
|
while (bWorking)
|
|
{
|
|
bWorking = finder.FindNextFile();
|
|
|
|
if (finder.IsDots())
|
|
continue;
|
|
|
|
CString filePath = finder.GetFilePath();
|
|
|
|
if (finder.IsDirectory())
|
|
{
|
|
// 递归删除子文件夹
|
|
ClearFolder(filePath);
|
|
RemoveDirectory(filePath);
|
|
}
|
|
else
|
|
{
|
|
// 删除文件
|
|
DeleteFile(filePath);
|
|
}
|
|
}
|
|
finder.Close();
|
|
}
|
|
catch (const std::exception&)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 清空临时文件夹.
|
|
*
|
|
*/
|
|
void ClearTempFolder()
|
|
{
|
|
ClearFolder(GetTempDirectory());
|
|
}
|
|
|
|
/**
|
|
* @brief 检测并创建目录.
|
|
*
|
|
* @param path
|
|
* @return
|
|
*/
|
|
BOOL CheckAndCreateDirectory(const CString& path)
|
|
{
|
|
if (!PathFileExists(path))
|
|
{
|
|
CFileFind finder;
|
|
BOOL bFound = finder.FindFile(path);
|
|
|
|
if (!bFound)
|
|
{
|
|
// 目录不存在,创建目录
|
|
if (CreateDirectory(path, NULL))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// 创建目录失败
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
// 目录已存在
|
|
return TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief 产生GUID字符串.
|
|
*
|
|
* @param guidStr
|
|
*/
|
|
void generateGUID(char* pGuidStr) {
|
|
GUID guid;
|
|
CoCreateGuid(&guid);
|
|
|
|
sprintf(pGuidStr, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
guid.Data1, guid.Data2, guid.Data3,
|
|
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
|
|
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
|
}
|
|
|
|
/**
|
|
* @brief 存临时文件目录产生临时文件.
|
|
*
|
|
* @return 临时文件路径
|
|
*/
|
|
CString generateTempFile(CString& filePath)
|
|
{
|
|
CSplitPath sp(filePath);
|
|
CString ext = sp.GetExtension();
|
|
CString tmpPath = GetTempDirectory();
|
|
char uuidStr[37];
|
|
generateGUID(uuidStr);
|
|
tmpPath.Append(uuidStr);
|
|
tmpPath.Append(ext);
|
|
return tmpPath;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取可执行文件所在目录.
|
|
*
|
|
* @return 当前应用目录
|
|
*/
|
|
CString GetTempDirectory()
|
|
{
|
|
CString tempDir = GetExecutableDirectory();
|
|
tempDir.Append("\\temp\\");
|
|
return tempDir;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取可执行文件所在目录.
|
|
*
|
|
* @return 当前应用目录
|
|
*/
|
|
CString GetExecutableDirectory()
|
|
{
|
|
TCHAR buffer[MAX_PATH] = { 0 };
|
|
GetModuleFileName(NULL, buffer, MAX_PATH);
|
|
|
|
PathRemoveFileSpec(buffer);
|
|
|
|
return CString(buffer);
|
|
}
|
|
|