1038 lines
24 KiB
C++
1038 lines
24 KiB
C++
/*---------------------------------------------------------------------------*/
|
|
// Author : hiyohiyo
|
|
// Mail : hiyohiyo@crystalmark.info
|
|
// Web : https://crystalmark.info/
|
|
// License : MIT License
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include "stdafx.h"
|
|
#include "UtilityFx.h"
|
|
|
|
#include <io.h>
|
|
#pragma comment(lib,"version.lib")
|
|
|
|
////------------------------------------------------
|
|
// Debug
|
|
////------------------------------------------------
|
|
|
|
static const DWORD DEBUG_MODE_NONE = 0;
|
|
static const DWORD DEBUG_MODE_LOG = 1;
|
|
static const DWORD DEBUG_MODE_MESSAGE = 2;
|
|
|
|
static DWORD debugMode = DEBUG_MODE_NONE;
|
|
|
|
void SetDebugMode(DWORD mode)
|
|
{
|
|
if (mode <= DEBUG_MODE_MESSAGE)
|
|
{
|
|
debugMode = mode;
|
|
}
|
|
else
|
|
{
|
|
debugMode = DEBUG_MODE_NONE;
|
|
}
|
|
}
|
|
|
|
void DebugPrint(CString cstr)
|
|
{
|
|
static BOOL flag = TRUE;
|
|
static TCHAR file[MAX_PATH] = _T("");
|
|
static DWORD first = (DWORD)GetTickCountFx();
|
|
CString output;
|
|
|
|
output.Format(_T("%08d "), (DWORD)GetTickCountFx() - first);
|
|
output += cstr;
|
|
output.Append(_T("\n"));
|
|
output.Replace(_T("\r"), _T(""));
|
|
|
|
if (flag)
|
|
{
|
|
TCHAR* ptrEnd;
|
|
::GetModuleFileName(NULL, file, MAX_PATH);
|
|
if ((ptrEnd = _tcsrchr(file, '.')) != NULL)
|
|
{
|
|
*ptrEnd = '\0';
|
|
#if _MSC_VER <= 1310
|
|
_tcscat(file, _T(".log"));
|
|
#else
|
|
_tcscat_s(file, MAX_PATH, _T(".log"));
|
|
#endif
|
|
}
|
|
DeleteFile(file);
|
|
flag = FALSE;
|
|
}
|
|
|
|
if (debugMode == DEBUG_MODE_NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FILE* fp = NULL;
|
|
#if _MSC_VER <= 1310
|
|
fp = _tfopen(file, _T("ac"));
|
|
#else
|
|
_tfopen_s(&fp, file, _T("ac"));
|
|
#endif
|
|
|
|
if (fp != NULL)
|
|
{
|
|
_ftprintf(fp, _T("%s"), (LPCTSTR)output);
|
|
fflush(fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
if (debugMode == DEBUG_MODE_MESSAGE)
|
|
{
|
|
AfxMessageBox(output);
|
|
}
|
|
}
|
|
|
|
////------------------------------------------------
|
|
// File Information
|
|
////------------------------------------------------
|
|
|
|
int GetFileVersion(const TCHAR* file, TCHAR* version)
|
|
{
|
|
ULONG reserved = 0;
|
|
VS_FIXEDFILEINFO vffi = { 0 };
|
|
TCHAR* buf = NULL;
|
|
int Locale = 0;
|
|
TCHAR str[256] = { 0 };
|
|
|
|
UINT size = GetFileVersionInfoSize((TCHAR*)file, &reserved);
|
|
TCHAR* vbuf = new TCHAR[size];
|
|
if (GetFileVersionInfo((TCHAR*)file, 0, size, vbuf))
|
|
{
|
|
VerQueryValue(vbuf, _T("\\"), (void**)&buf, &size);
|
|
CopyMemory(&vffi, buf, sizeof(VS_FIXEDFILEINFO));
|
|
|
|
VerQueryValue(vbuf, _T("\\VarFileInfo\\Translation"), (void**)&buf, &size);
|
|
CopyMemory(&Locale, buf, sizeof(int));
|
|
wsprintf(str, _T("\\StringFileInfo\\%04X%04X\\%s"),
|
|
LOWORD(Locale), HIWORD(Locale), _T("FileVersion"));
|
|
VerQueryValue(vbuf, str, (void**)&buf, &size);
|
|
|
|
#if _MSC_VER <= 1310
|
|
_tcscpy(str, buf);
|
|
#else
|
|
_tcscpy_s(str, 256, buf);
|
|
#endif
|
|
|
|
if (version != NULL)
|
|
{
|
|
#if _MSC_VER <= 1310
|
|
_tcscpy(version,buf);
|
|
#else
|
|
_tcscpy_s(version, 256, buf);
|
|
#endif
|
|
}
|
|
}
|
|
delete[] vbuf;
|
|
|
|
if (_tcscmp(str, _T("")) != 0)
|
|
{
|
|
return int(_tstof(str) * 100);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void GetFileVersionEx(const TCHAR* file, CString& version)
|
|
{
|
|
ULONG reserved = 0;
|
|
VS_FIXEDFILEINFO vffi = { 0 };
|
|
TCHAR* buf = NULL;
|
|
int Locale = 0;
|
|
TCHAR str[256] = { 0 };
|
|
|
|
UINT size = GetFileVersionInfoSize((TCHAR*)file, &reserved);
|
|
TCHAR* vbuf = new TCHAR[size];
|
|
if (GetFileVersionInfo((TCHAR*)file, 0, size, vbuf))
|
|
{
|
|
VerQueryValue(vbuf, _T("\\"), (void**)&buf, &size);
|
|
CopyMemory(&vffi, buf, sizeof(VS_FIXEDFILEINFO));
|
|
|
|
if (vffi.dwSignature == 0xfeef04bd)
|
|
{
|
|
version.Format(_T("%d.%d.%d.%d"),
|
|
HIWORD(vffi.dwFileVersionMS),
|
|
LOWORD(vffi.dwFileVersionMS),
|
|
HIWORD(vffi.dwFileVersionLS),
|
|
LOWORD(vffi.dwFileVersionLS));
|
|
}
|
|
}
|
|
delete[] vbuf;
|
|
}
|
|
|
|
BOOL IsFileExist(const TCHAR* path)
|
|
{
|
|
FILE* fp = NULL;
|
|
|
|
#if _MSC_VER <= 1310
|
|
fp = _tfopen(path, _T("rb"));
|
|
if (fp == NULL)
|
|
#else
|
|
errno_t err = 0;
|
|
err = _tfopen_s(&fp, path, _T("rb"));
|
|
if (err != 0 || fp == NULL)
|
|
#endif
|
|
{
|
|
return FALSE;
|
|
}
|
|
fclose(fp);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CanWriteFile(const TCHAR* path)
|
|
{
|
|
HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) { return FALSE; }
|
|
const char* testData = "1";
|
|
DWORD bytesWritten;
|
|
BOOL writeResult = WriteFile(hFile, testData, (DWORD)strlen(testData), &bytesWritten, NULL);
|
|
CloseHandle(hFile);
|
|
|
|
return writeResult;
|
|
}
|
|
|
|
|
|
////------------------------------------------------
|
|
// Utility
|
|
////------------------------------------------------
|
|
|
|
typedef ULONGLONG(WINAPI* FuncGetTickCount64)();
|
|
|
|
ULONGLONG GetTickCountFx()
|
|
{
|
|
HMODULE hModule = GetModuleHandle(_T("kernel32.dll"));
|
|
FuncGetTickCount64 pGetTickCount64 = NULL;
|
|
if (hModule)
|
|
{
|
|
pGetTickCount64 = (FuncGetTickCount64)GetProcAddress(hModule, "GetTickCount64");
|
|
}
|
|
|
|
if (pGetTickCount64)
|
|
{
|
|
return (ULONGLONG)pGetTickCount64();
|
|
}
|
|
else
|
|
{
|
|
#if _MSC_VER <= 1310
|
|
return (ULONGLONG)GetTickCount();
|
|
#else
|
|
return _Pragma("warning(suppress: 28159)") (ULONGLONG)GetTickCount();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ULONG64 B8toB64(BYTE b0, BYTE b1, BYTE b2, BYTE b3, BYTE b4, BYTE b5, BYTE b6, BYTE b7)
|
|
{
|
|
ULONG64 data =
|
|
((ULONG64)b7 << 56)
|
|
+ ((ULONG64)b6 << 48)
|
|
+ ((ULONG64)b5 << 40)
|
|
+ ((ULONG64)b4 << 32)
|
|
+ ((ULONG64)b3 << 24)
|
|
+ ((ULONG64)b2 << 16)
|
|
+ ((ULONG64)b1 << 8)
|
|
+ ((ULONG64)b0 << 0);
|
|
|
|
return data;
|
|
}
|
|
|
|
DWORD B8toB32(BYTE b0, BYTE b1, BYTE b2, BYTE b3)
|
|
{
|
|
DWORD data =
|
|
((DWORD)b3 << 24)
|
|
+ ((DWORD)b2 << 16)
|
|
+ ((DWORD)b1 << 8)
|
|
+ ((DWORD)b0 << 0);
|
|
|
|
return data;
|
|
}
|
|
|
|
void SplitCString(const CString& str, const CString& delimiter, CStringArray& arr)
|
|
{
|
|
int startPos = 0;
|
|
while (startPos >= 0)
|
|
{
|
|
int endPos = str.Find(delimiter, startPos);
|
|
if (endPos == -1)
|
|
{
|
|
arr.Add(str.Mid(startPos));
|
|
break;
|
|
}
|
|
arr.Add(str.Mid(startPos, endPos - startPos));
|
|
startPos = endPos + lstrlen(delimiter);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#if _MSC_VER > 1310
|
|
// ---------------------------------------------------------
|
|
// 20260123: Safe for unaligned/page-boundary (Using memcpy for atomic-like MOV) >>>
|
|
|
|
// Environment Validation (Compile-time) >
|
|
static_assert(sizeof(USHORT) == 2, "! (sizeof(USHORT) == 2)");
|
|
static_assert(sizeof(INT) == 4, "! (sizeof(INT) == 4)");
|
|
static_assert(sizeof(DWORD) == 4, "! (sizeof(DWORD) == 4)");
|
|
static_assert(sizeof(ULONG64) == 8, "! (sizeof(ULONG64) == 8)");
|
|
|
|
// Boundary-Safe Loaders >
|
|
|
|
NODISCARD ULONG64 B8toB64le_ptr(_In_reads_(8) const BYTE* v) noexcept {
|
|
ULONG64 u64;
|
|
::memcpy(&u64, v, sizeof(u64));
|
|
return u64;
|
|
}
|
|
NODISCARD DWORD B8toB32le_ptr(_In_reads_(4) const BYTE* v) noexcept {
|
|
return ((static_cast<DWORD>(v[0]))
|
|
| (static_cast<DWORD>(v[1]) << 8)
|
|
| (static_cast<DWORD>(v[2]) << 16)
|
|
| (static_cast<DWORD>(v[3]) << 24));
|
|
}
|
|
NODISCARD INT B8toINTle_ptr(_In_reads_(4) const BYTE* v) noexcept {
|
|
return static_cast<INT>((static_cast<DWORD>(v[0]))
|
|
| (static_cast<DWORD>(v[1]) << 8)
|
|
| (static_cast<DWORD>(v[2]) << 16)
|
|
| (static_cast<DWORD>(v[3]) << 24));
|
|
}
|
|
NODISCARD USHORT B8toB16le_ptr(_In_reads_(2) const BYTE* v) noexcept {
|
|
return static_cast<USHORT>((static_cast<USHORT>(v[0]))
|
|
| (static_cast<USHORT>(v[1]) << 8));
|
|
}
|
|
NODISCARD SHORT B8toSHORTle_ptr(_In_reads_(2) const BYTE* v) noexcept {
|
|
return static_cast<SHORT>((static_cast<USHORT>(v[0]))
|
|
| (static_cast<USHORT>(v[1]) << 8));
|
|
}
|
|
NODISCARD ULONG64 B8toB64le(const BYTE(&v)[6]) noexcept {
|
|
return ((static_cast<ULONG64>(v[0]))
|
|
| (static_cast<ULONG64>(v[1]) << 8)
|
|
| (static_cast<ULONG64>(v[2]) << 16)
|
|
| (static_cast<ULONG64>(v[3]) << 24)
|
|
| (static_cast<ULONG64>(v[4]) << 32)
|
|
| (static_cast<ULONG64>(v[5]) << 40));
|
|
}
|
|
NODISCARD DWORD B8toB32le(const BYTE(&v)[6]) noexcept {
|
|
return ((static_cast<DWORD>(v[0]))
|
|
| (static_cast<DWORD>(v[1]) << 8)
|
|
| (static_cast<DWORD>(v[2]) << 16)
|
|
| (static_cast<DWORD>(v[3]) << 24));
|
|
}
|
|
NODISCARD INT B8toINTle(const BYTE(&v)[6]) noexcept {
|
|
return static_cast<INT>((static_cast<DWORD>(v[0]))
|
|
| (static_cast<DWORD>(v[1]) << 8)
|
|
| (static_cast<DWORD>(v[2]) << 16)
|
|
| (static_cast<DWORD>(v[3]) << 24));
|
|
}
|
|
NODISCARD USHORT B8toB16le(const BYTE(&v)[6]) noexcept {
|
|
return ((static_cast<USHORT>(v[0]))
|
|
| (static_cast<USHORT>(v[1]) << 8));
|
|
}
|
|
|
|
// 20260123: Safe for unaligned/page-boundary <<<
|
|
// ---------------------------------------------------------
|
|
#endif
|
|
|
|
|
|
////------------------------------------------------
|
|
// .ini support function
|
|
////------------------------------------------------
|
|
|
|
DWORD GetPrivateProfileStringFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName)
|
|
{
|
|
DWORD result = 0;
|
|
CString key = lpKeyName;
|
|
key.Replace(_T("="), _T("%#3D"));
|
|
key.Replace(_T("\""), _T("%#22"));
|
|
result = GetPrivateProfileString(lpAppName, key, lpDefault, lpReturnedString, nSize, lpFileName);
|
|
|
|
CString value = lpReturnedString;
|
|
value.Replace(_T("%#3D"), _T("="));
|
|
value.Replace(_T("%#22"), _T("\""));
|
|
|
|
#if _MSC_VER <= 1310
|
|
_tcscpy(lpReturnedString, (LPCTSTR)value);
|
|
#else
|
|
_tcscpy_s(lpReturnedString, nSize, (LPCTSTR)value);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
UINT GetPrivateProfileIntFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName)
|
|
{
|
|
CString key = lpKeyName;
|
|
key.Replace(_T("="), _T("%#3D"));
|
|
key.Replace(_T("\""), _T("%#22"));
|
|
|
|
return GetPrivateProfileInt(lpAppName, key, nDefault, lpFileName);
|
|
}
|
|
|
|
BOOL WritePrivateProfileStringFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName)
|
|
{
|
|
CString key = lpKeyName;
|
|
key.Replace(_T("="), _T("%#3D"));
|
|
key.Replace(_T("\""), _T("%#22"));
|
|
|
|
CString value = lpString;
|
|
value.Replace(_T("="), _T("%#3D"));
|
|
value.Replace(_T("\""), _T("%#22"));
|
|
|
|
value = _T("\"" + value + _T("\""));
|
|
|
|
return WritePrivateProfileString(lpAppName, key, value, lpFileName);
|
|
}
|
|
|
|
////------------------------------------------------
|
|
// Check CodeSign
|
|
////------------------------------------------------
|
|
#if _MSC_VER > 1310
|
|
#include <Softpub.h>
|
|
#pragma comment(lib, "Wintrust.lib")
|
|
#pragma comment(lib, "Crypt32.lib")
|
|
|
|
BOOL CheckCodeSign(LPCWSTR certName, LPCWSTR filePath)
|
|
{
|
|
#ifdef _DEBUG
|
|
return TRUE;
|
|
#endif
|
|
|
|
// check sign
|
|
|
|
WINTRUST_FILE_INFO FileData = { sizeof(WINTRUST_FILE_INFO) };
|
|
FileData.pcwszFilePath = filePath;
|
|
|
|
GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
|
WINTRUST_DATA WinTrustData = { sizeof(WinTrustData) };
|
|
WinTrustData.dwUIChoice = WTD_UI_NONE;
|
|
WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
|
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
|
|
WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
|
|
WinTrustData.pFile = &FileData;
|
|
|
|
const LONG ret = WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
|
|
|
|
bool cert_chk = false;
|
|
|
|
if (ret == ERROR_SUCCESS) {
|
|
// retreive the signer certificate and display its information
|
|
CRYPT_PROVIDER_DATA const* psProvData = NULL;
|
|
CRYPT_PROVIDER_SGNR* psProvSigner = NULL;
|
|
CRYPT_PROVIDER_CERT* psProvCert = NULL;
|
|
|
|
psProvData = WTHelperProvDataFromStateData(WinTrustData.hWVTStateData);
|
|
if (psProvData) {
|
|
psProvSigner = WTHelperGetProvSignerFromChain((PCRYPT_PROVIDER_DATA)psProvData, 0, FALSE, 0);
|
|
if (psProvSigner) {
|
|
psProvCert = WTHelperGetProvCertFromChain(psProvSigner, 0);
|
|
if (psProvCert) {
|
|
wchar_t szCertName[200] = {0};
|
|
DWORD dwStrType = CERT_X500_NAME_STR;
|
|
CertGetNameStringW(psProvCert->pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, &dwStrType, szCertName, 200);
|
|
cert_chk = !(szCertName[0] == '\0' || wcscmp(szCertName, certName) != 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
|
|
(void)WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
|
|
if (!cert_chk) return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
////------------------------------------------------
|
|
// Play Sound
|
|
////------------------------------------------------
|
|
|
|
#include <mmsystem.h>
|
|
#include "digitalv.h"
|
|
|
|
#pragma comment(lib, "winmm.lib")
|
|
|
|
/*
|
|
void ShowMciError(DWORD error)
|
|
{
|
|
TCHAR errorBuf[MAXERRORLENGTH];
|
|
|
|
if (mciGetErrorString(error, (LPTSTR)errorBuf, MAXERRORLENGTH))
|
|
{
|
|
AfxMessageBox(errorBuf);
|
|
}
|
|
else
|
|
{
|
|
AfxMessageBox(_T("Unknown Error");
|
|
}
|
|
}
|
|
*/
|
|
|
|
BOOL AlertSound(const CString& alertSoundPath, int volume)
|
|
{
|
|
#if _MSC_VER <= 1310
|
|
PlaySound(alertSoundPath, NULL, SND_SYNC);
|
|
#else
|
|
|
|
static MCI_OPEN_PARMS mop = { 0 };
|
|
static MCI_PLAY_PARMS mpp = { 0 };
|
|
static MCI_GENERIC_PARMS mgp = { 0 };
|
|
MCIERROR error = 0;
|
|
|
|
if (mop.wDeviceID != 0)
|
|
{
|
|
// Stop and close
|
|
error = mciSendCommandW(mop.wDeviceID, MCI_STOP, 0, 0);
|
|
error = mciSendCommandW(mop.wDeviceID, MCI_CLOSE, 0, 0);
|
|
mop.wDeviceID = 0;
|
|
ZeroMemory(&mop, sizeof(MCI_OPEN_PARMS));
|
|
if (error)
|
|
{
|
|
// ShowMciError(error);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (alertSoundPath.Compare(_T("")) == 0) {
|
|
// Close
|
|
error = mciSendCommandW(mop.wDeviceID, MCI_CLOSE, 0, 0);
|
|
if (error)
|
|
{
|
|
// ShowMciError(error);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Open
|
|
mop.lpstrElementName = (LPCTSTR)alertSoundPath;
|
|
mop.lpstrDeviceType = _T("MPEGVideo");
|
|
error = mciSendCommandW(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD_PTR)(&mop));
|
|
|
|
if (error)
|
|
{
|
|
// ShowMciError(error);
|
|
return FALSE;
|
|
}
|
|
|
|
// Set volume
|
|
if (volume < 0 || volume > 100) { volume = 80; }
|
|
|
|
MCI_DGV_SETAUDIO_PARMS parms = { 0 };
|
|
parms.dwItem = MCI_DGV_SETAUDIO_VOLUME;
|
|
parms.dwValue = volume * 10; // 0-1000
|
|
error = mciSendCommand(mop.wDeviceID, MCI_SETAUDIO, MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE, (DWORD_PTR)&parms);
|
|
if (error)
|
|
{
|
|
// ShowMciError(error);
|
|
return FALSE;
|
|
}
|
|
// Seek
|
|
error = mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, reinterpret_cast<DWORD_PTR>(&mgp));
|
|
if (error)
|
|
{
|
|
// ShowMciError(error);
|
|
return FALSE;
|
|
}
|
|
|
|
// Play
|
|
error = mciSendCommandW(mop.wDeviceID, MCI_PLAY, 0, reinterpret_cast<DWORD_PTR>(&mpp));
|
|
if (error)
|
|
{
|
|
// ShowMciError(error);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
////------------------------------------------------
|
|
// Hash
|
|
////------------------------------------------------
|
|
|
|
#if _MSC_VER > 1310
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
CStringA MD5(const CStringA& str)
|
|
{
|
|
HCRYPTPROV hProv = 0;
|
|
HCRYPTHASH hHash = 0;
|
|
BYTE hash[16];
|
|
DWORD hashLen = 16;
|
|
CStringA hashStr;
|
|
|
|
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
|
return "";
|
|
}
|
|
|
|
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
|
|
CryptReleaseContext(hProv, 0);
|
|
return "";
|
|
}
|
|
|
|
std::string utf8Str(str);
|
|
|
|
if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(utf8Str.c_str()), (DWORD)utf8Str.size(), 0)) {
|
|
CryptDestroyHash(hHash);
|
|
CryptReleaseContext(hProv, 0);
|
|
return "";
|
|
}
|
|
|
|
if (!CryptGetHashParam(hHash, HP_HASHVAL, hash, &hashLen, 0)) {
|
|
CryptDestroyHash(hHash);
|
|
CryptReleaseContext(hProv, 0);
|
|
return "";
|
|
}
|
|
|
|
for (DWORD i = 0; i < hashLen; ++i) {
|
|
CString temp;
|
|
temp.Format(_T("%02x"), hash[i]);
|
|
hashStr += temp;
|
|
}
|
|
|
|
CryptDestroyHash(hHash);
|
|
CryptReleaseContext(hProv, 0);
|
|
|
|
return hashStr;
|
|
}
|
|
#else
|
|
#include "md5.h"
|
|
CStringA MD5(const CStringA& str)
|
|
{
|
|
char* input = (char*)(LPCSTR)str;
|
|
uint8_t result[16] = { 0 };
|
|
md5String(input, result);
|
|
|
|
CStringA hashStr;
|
|
for (int i = 0; i < 16; ++i)
|
|
{
|
|
CStringA byteStr;
|
|
byteStr.Format("%02x", result[i]);
|
|
hashStr += byteStr;
|
|
}
|
|
|
|
return hashStr;
|
|
}
|
|
#endif
|
|
|
|
////------------------------------------------------
|
|
// Character Converter
|
|
////------------------------------------------------
|
|
|
|
CStringA URLEncode(const CStringA& str)
|
|
{
|
|
CStringA encoded;
|
|
for (int i = 0; i < str.GetLength(); i++)
|
|
{
|
|
if (isalnum((BYTE)str[i]) || str[i] == '-' || str[i] == '_' || str[i] == '.' || str[i] == '~')
|
|
{
|
|
encoded += str[i];
|
|
}
|
|
else
|
|
{
|
|
encoded.AppendFormat("%%%02X", (BYTE)str[i]);
|
|
}
|
|
}
|
|
return encoded;
|
|
}
|
|
|
|
#if _MSC_VER <= 1310
|
|
|
|
// https://github.com/roytam1/RetroZilla/commit/e44dd98dbf2effeff3305430835e889d76ec73b4#diff-065242b491de972d8519dbbae0c4c8dfb6a1a3c3eb8b9936d56a4c1ad63ec7abR126-R282
|
|
/*** UTF16<-->UTF8 functions minicking MultiByteToWideChar/WideCharToMultiByte ***/
|
|
int utf8GetMaskIndex(unsigned char n) {
|
|
if ((unsigned char)(n + 2) < 0xc2) return 1; // 00~10111111, fe, ff
|
|
if (n < 0xe0) return 2; // 110xxxxx
|
|
if (n < 0xf0) return 3; // 1110xxxx
|
|
if (n < 0xf8) return 4; // 11110xxx
|
|
if (n < 0xfc) return 5; // 111110xx
|
|
return 6; // 1111110x
|
|
}
|
|
|
|
int wc2Utf8Len(wchar_t** n, int* len) {
|
|
wchar_t* ch = *n, ch2;
|
|
int qch;
|
|
if ((0xD800 <= *ch && *ch <= 0xDBFF) && *len) {
|
|
ch2 = *(ch + 1);
|
|
if (0xDC00 <= ch2 && ch2 <= 0xDFFF) {
|
|
qch = 0x10000 + (((*ch - 0xD800) & 0x3ff) << 10) + ((ch2 - 0xDC00) & 0x3ff);
|
|
(*n)++;
|
|
(*len)--;
|
|
}
|
|
}
|
|
else
|
|
qch = (int)*ch;
|
|
|
|
if (qch <= 0x7f) return 1;
|
|
else if (qch <= 0x7ff) return 2;
|
|
else if (qch <= 0xffff) return 3;
|
|
else if (qch <= 0x1fffff) return 4;
|
|
else if (qch <= 0x3ffffff) return 5;
|
|
else return 6;
|
|
}
|
|
|
|
int Utf8ToWideChar(unsigned int unused1, unsigned long unused2, char* sb, int ss, wchar_t* wb, int ws) {
|
|
static const unsigned char utf8mask[] = { 0, 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
|
|
char* p = (char*)(sb);
|
|
char* e = (char*)(sb + ss);
|
|
wchar_t* w = wb;
|
|
int cnt = 0, t, qch;
|
|
|
|
if (ss < 1) {
|
|
ss = lstrlenA(sb);
|
|
e = (char*)(sb + ss);
|
|
}
|
|
|
|
if (wb && ws) {
|
|
for (; p < e; ++w) {
|
|
t = utf8GetMaskIndex(*p);
|
|
qch = (*p++ & utf8mask[t]);
|
|
while (p < e && --t)
|
|
qch <<= 6, qch |= (*p++) & 0x3f;
|
|
if (qch < 0x10000) {
|
|
if (cnt <= ws)
|
|
*w = (wchar_t)qch;
|
|
cnt++;
|
|
}
|
|
else {
|
|
if (cnt + 2 <= ws) {
|
|
*w++ = (wchar_t)(0xD800 + (((qch - 0x10000) >> 10) & 0x3ff)),
|
|
*w = (wchar_t)(0xDC00 + (((qch - 0x10000)) & 0x3ff));
|
|
}
|
|
cnt += 2;
|
|
}
|
|
}
|
|
if (cnt < ws) {
|
|
*(wb + cnt) = 0;
|
|
return cnt;
|
|
}
|
|
else {
|
|
*(wb + ws) = 0;
|
|
return ws;
|
|
}
|
|
}
|
|
else {
|
|
for (t; p < e;) {
|
|
t = utf8GetMaskIndex(*p);
|
|
qch = (*p++ & utf8mask[t]);
|
|
while (p < e && --t)
|
|
qch <<= 6, qch |= (*p++) & 0x3f;
|
|
if (qch < 0x10000)
|
|
cnt++;
|
|
else
|
|
cnt += 2;
|
|
}
|
|
return cnt + 1;
|
|
}
|
|
}
|
|
|
|
int WideCharToUtf8(unsigned int unused1, unsigned long unused2, wchar_t* wb, int ws, char* sb, int ss) {
|
|
wchar_t* p = (wchar_t*)(wb);
|
|
wchar_t* e = (wchar_t*)(wb + ws);
|
|
wchar_t* oldp;
|
|
char* s = sb;
|
|
int cnt = 0, qch, t;
|
|
|
|
if (ws < 1) {
|
|
ws = lstrlenW(wb);
|
|
e = (wchar_t*)(wb + ws);
|
|
}
|
|
|
|
if (sb && ss) {
|
|
for (t; p < e; ++p) {
|
|
oldp = p;
|
|
t = wc2Utf8Len(&p, &ws);
|
|
|
|
if (p != oldp) { /* unicode surrogates encountered */
|
|
qch = 0x10000 + (((*oldp - 0xD800) & 0x3ff) << 10) + ((*p - 0xDC00) & 0x3ff);
|
|
}
|
|
else
|
|
qch = *p;
|
|
|
|
if (qch <= 0x7f)
|
|
*s++ = (char)(qch),
|
|
cnt++;
|
|
else if (qch <= 0x7ff)
|
|
*s++ = 0xc0 | (char)(qch >> 6),
|
|
*s++ = 0x80 | (char)(qch & 0x3f),
|
|
cnt += 2;
|
|
else if (qch <= 0xffff)
|
|
*s++ = 0xe0 | (char)(qch >> 12),
|
|
*s++ = 0x80 | (char)((qch >> 6) & 0x3f),
|
|
*s++ = 0x80 | (char)(qch & 0x3f),
|
|
cnt += 3;
|
|
else if (qch <= 0x1fffff)
|
|
*s++ = 0xf0 | (char)(qch >> 18),
|
|
*s++ = 0x80 | (char)((qch >> 12) & 0x3f),
|
|
*s++ = 0x80 | (char)((qch >> 6) & 0x3f),
|
|
*s++ = 0x80 | (char)(qch & 0x3f),
|
|
cnt += 4;
|
|
else if (qch <= 0x3ffffff)
|
|
*s++ = 0xf8 | (char)(qch >> 24),
|
|
*s++ = 0x80 | (char)((qch >> 18) & 0x3f),
|
|
*s++ = 0x80 | (char)((qch >> 12) & 0x3f),
|
|
*s++ = 0x80 | (char)((qch >> 6) & 0x3f),
|
|
*s++ = 0x80 | (char)(qch & 0x3f),
|
|
cnt += 5;
|
|
else
|
|
*s++ = 0xfc | (char)(qch >> 30),
|
|
*s++ = 0x80 | (char)((qch >> 24) & 0x3f),
|
|
*s++ = 0x80 | (char)((qch >> 18) & 0x3f),
|
|
*s++ = 0x80 | (char)((qch >> 12) & 0x3f),
|
|
*s++ = 0x80 | (char)((qch >> 6) & 0x3f),
|
|
*s++ = 0x80 | (char)(qch & 0x3f),
|
|
cnt += 6;
|
|
}
|
|
if (cnt < ss) {
|
|
*(sb + cnt) = 0;
|
|
return cnt;
|
|
}
|
|
else {
|
|
*(sb + ss) = 0;
|
|
return ss;
|
|
}
|
|
}
|
|
else {
|
|
for (t; p < e; ++p) {
|
|
t = wc2Utf8Len(&p, &ws);
|
|
cnt += t;
|
|
}
|
|
return cnt + 1;
|
|
}
|
|
}
|
|
/*** Ends ***/
|
|
|
|
#ifdef UNICODE
|
|
CStringA UTF16toUTF8(const CStringW& utf16str)
|
|
{
|
|
if (IsNT3() || IsNT4())
|
|
{
|
|
CStringA utf8str;
|
|
WCHAR* utf16string = new WCHAR[(utf16str.GetLength() + 1) * 2];
|
|
wsprintf(utf16string, L"%s", utf16str);
|
|
int utf16Length = utf16str.GetLength();
|
|
int utf8Length = WideCharToUtf8(CP_UTF8, 0, utf16string, -1, NULL, 0);
|
|
if (utf8Length <= 0) { return ""; }
|
|
WideCharToUtf8(CP_UTF8, 0, utf16string, -1, utf8str.GetBuffer(utf8Length), utf8Length);
|
|
utf8str.ReleaseBuffer();
|
|
delete utf16string;
|
|
return utf8str;
|
|
}
|
|
else
|
|
{
|
|
CStringA utf8str;
|
|
int utf8Length = WideCharToMultiByte(CP_UTF8, 0, utf16str, -1, NULL, 0, NULL, NULL);
|
|
if (utf8Length <= 0) { return ""; }
|
|
WideCharToMultiByte(CP_UTF8, 0, utf16str, -1, utf8str.GetBuffer(utf8Length), utf8Length, NULL, NULL);
|
|
utf8str.ReleaseBuffer();
|
|
return utf8str;
|
|
}
|
|
}
|
|
|
|
CStringW UTF8toUTF16(const CStringA& utf8str)
|
|
{
|
|
CStringW utf16str;
|
|
CHAR* utf8string = new CHAR[(utf8str.GetLength() + 1) * 2];
|
|
sprintf(utf8string, "%s", utf8str);
|
|
int utf8Length = utf8str.GetLength();
|
|
int utf16Length = Utf8ToWideChar(1200, 0, utf8string, -1, NULL, 0);
|
|
if (utf16Length <= 0) { return L""; }
|
|
Utf8ToWideChar(1200, 0, utf8string, -1, utf16str.GetBuffer(utf16Length), utf16Length);
|
|
utf16str.ReleaseBuffer();
|
|
delete utf8string;
|
|
return utf16str;
|
|
}
|
|
|
|
#else
|
|
CStringA ANSItoUTF8(const CStringA& ansiStr)
|
|
{
|
|
int utf16Length = MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, NULL, 0);
|
|
if (utf16Length <= 0) { return ""; }
|
|
CStringW utf16str;
|
|
MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, utf16str.GetBuffer(utf16Length), utf16Length);
|
|
utf16str.ReleaseBuffer();
|
|
|
|
CStringA utf8str;
|
|
int utf8Length = WideCharToUtf8(CP_UTF8, 0, utf16str.GetBuffer(utf16Length), -1, NULL, 0);
|
|
if (utf8Length <= 0) { return ""; }
|
|
WideCharToUtf8(CP_UTF8, 0, utf16str.GetBuffer(utf16Length), -1, utf8str.GetBuffer(utf8Length), utf8Length);
|
|
utf8str.ReleaseBuffer();
|
|
return utf8str;
|
|
}
|
|
#endif
|
|
#else
|
|
|
|
CStringA UTF16toUTF8(const CStringW& utf16str)
|
|
{
|
|
CStringA utf8str(CW2A(utf16str, CP_UTF8));
|
|
return utf8str;
|
|
}
|
|
|
|
CStringW UTF8toUTF16(const CStringA& utf8str)
|
|
{
|
|
CStringW utf16str;
|
|
utf16str = CA2W(utf8str);
|
|
return utf16str;
|
|
}
|
|
#endif
|
|
|
|
#ifdef UNICODE
|
|
CStringA UE(const CStringW& utf16str)
|
|
{
|
|
return URLEncode(UTF16toUTF8(utf16str));
|
|
}
|
|
#else
|
|
CStringA UE(const CStringA& ansiStr)
|
|
{
|
|
return URLEncode(ANSItoUTF8(ansiStr));
|
|
}
|
|
#endif
|
|
////------------------------------------------------
|
|
// Clipboard
|
|
////------------------------------------------------
|
|
|
|
void SetClipboardText(CString clip)
|
|
{
|
|
if (OpenClipboard(NULL))
|
|
{
|
|
HGLOBAL clipbuffer;
|
|
TCHAR* buffer = NULL;
|
|
EmptyClipboard();
|
|
clipbuffer = GlobalAlloc(GMEM_DDESHARE, sizeof(TCHAR) * (clip.GetLength() + 1));
|
|
if (clipbuffer != NULL)
|
|
{
|
|
buffer = (TCHAR*)GlobalLock(clipbuffer);
|
|
if (buffer != NULL)
|
|
{
|
|
#if _MSC_VER <= 1310
|
|
_tcscpy(buffer, LPCTSTR(clip));
|
|
#else
|
|
_tcscpy_s(buffer, clip.GetLength() + 1, LPCTSTR(clip));
|
|
#endif
|
|
}
|
|
GlobalUnlock(clipbuffer);
|
|
#ifdef UNICODE
|
|
SetClipboardData(CF_UNICODETEXT, clipbuffer);
|
|
#else
|
|
SetClipboardData(CF_TEXT, clipbuffer);
|
|
#endif
|
|
}
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
|
|
////------------------------------------------------
|
|
// SHLWAPI.DLL compatible functions
|
|
////------------------------------------------------
|
|
#if _MSC_VER <= 1310
|
|
BOOL PathRemoveFileSpecFxA(char* path)
|
|
{
|
|
char* filespec = path;
|
|
BOOL modified = FALSE;
|
|
|
|
if (!path || !*path) { return FALSE; }
|
|
if (*path == '\\') { filespec = ++path; }
|
|
if (*path == '\\') { filespec = ++path; }
|
|
|
|
while (*path)
|
|
{
|
|
if (*path == '\\')
|
|
{
|
|
filespec = path;
|
|
}
|
|
else if (*path == ':')
|
|
{
|
|
filespec = ++path;
|
|
if (*path == '\\') { filespec++; }
|
|
}
|
|
path = CharNextA(path);
|
|
}
|
|
|
|
if (*filespec)
|
|
{
|
|
*filespec = '\0';
|
|
modified = TRUE;
|
|
}
|
|
|
|
return modified;
|
|
}
|
|
|
|
BOOL PathRemoveFileSpecFxW(WCHAR* path)
|
|
{
|
|
WCHAR* filespec = path;
|
|
BOOL modified = FALSE;
|
|
|
|
if (!path || !*path) { return FALSE; }
|
|
if (*path == '\\') { filespec = ++path; }
|
|
if (*path == '\\') { filespec = ++path; }
|
|
|
|
while (*path)
|
|
{
|
|
if (*path == '\\')
|
|
{
|
|
filespec = path;
|
|
}
|
|
else if (*path == ':')
|
|
{
|
|
filespec = ++path;
|
|
if (*path == '\\') { filespec++; }
|
|
}
|
|
path++;
|
|
}
|
|
|
|
if (*filespec)
|
|
{
|
|
*filespec = '\0';
|
|
modified = TRUE;
|
|
}
|
|
|
|
return modified;
|
|
}
|
|
|
|
char* PathFindFileNameFxA(const char* path)
|
|
{
|
|
const char* p = path;
|
|
const char* name = NULL;
|
|
while (*p)
|
|
{
|
|
if (*p == '\\' || *p == '/')
|
|
{
|
|
name = p + 1;
|
|
}
|
|
p = CharNextA(p);
|
|
}
|
|
if (name)
|
|
{
|
|
return (char*)name;
|
|
}
|
|
return (char*)path;
|
|
}
|
|
|
|
WCHAR* PathFindFileNameFxW(const WCHAR* path)
|
|
{
|
|
const WCHAR* p = path;
|
|
const WCHAR* name = NULL;
|
|
while (*p)
|
|
{
|
|
if (*p == '\\' || *p == '/')
|
|
{
|
|
name = p + 1;
|
|
}
|
|
p++;
|
|
}
|
|
if (name)
|
|
{
|
|
return (WCHAR*)name;
|
|
}
|
|
return (WCHAR*)path;
|
|
}
|
|
#endif |