Win32 / C++ ini配置文件解析类(支持简易加解密)
Win32 api 的 ini 读写每次都是解析整个文件, 如果需要大量操作, 那么性能将会比较差, 于是实现了一个ini解析类, 支持自适应 utf-8, utf16, ansi 编码, 此外, 也可以简单进行数据加解密, 如果不想让比尔看到明文配置的话.
CIniHelperX.h
#pragma once#include <string>
#include <tchar.h>
#include <vector>
#include <windows.h>#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endifusing _tstring_list = std::vector<_tstring>;typedef struct _INI_CFG_VALUE
{_tstring ValueName; // 值名_tstring ValueNameRaw; // 原始值名_tstring ValueData; // 值数据_tstring ValueDataRaw; // 原始值数据_tstring_list ValueComment; // 注释_INI_CFG_VALUE(const _tstring& name = _T(""), const _tstring& content = _T(""), const std::vector<_tstring>& comment = {}):ValueName(name),ValueData(content),ValueComment(comment){}bool operator == (const _INI_CFG_VALUE& r) const{return this->ValueName == r.ValueName;}}INI_CFG_VALUE;using INI_VALUE_LIST = std::vector<INI_CFG_VALUE>;typedef struct _INI_CFG_SECTION
{_tstring SectionName; // 值名_tstring SrctionNameRaw; // 原始值名_tstring_list SectionComment; // 注释INI_VALUE_LIST ValueList; // 值列表_INI_CFG_SECTION(const _tstring& name = _T(""), const INI_VALUE_LIST& value = {}, const std::vector<_tstring>& comment = {}):SectionName(name),ValueList(value),SectionComment(comment){}bool operator == (const _INI_CFG_SECTION& r) const{return this->SectionName == r.SectionName;}}INI_CFG_SECTION;using INI_SECTION_LIST = std::vector<INI_CFG_SECTION>;// 文本编码
enum eTextEncoding
{eTextAuto, // 自动识别eTextAnsi, // Ansi编码eTextUtf8, // UTF-8eTextUtf8BOM, // UTF-8 带字节序eTextUtf16LEBOM, // UTF16 小端字节序eTextUtf16BEBOM // UTF16 大端字节序
};// Ini配置辅助类
class CIniHelperX
{
public:CIniHelperX(const _tstring& strPath = _T(""), bool fLoad = true, bool fAutoSave = false, bool fEncrypt = false);~CIniHelperX();// 加载bool Load();bool LoadFromFile(const _tstring& strFileName);// 保存bool Save(eTextEncoding enc = eTextEncoding::eTextAuto);bool SaveToFile(const _tstring& strFileName, eTextEncoding enc = eTextEncoding::eTextAuto);// 清空void Clear();// 是否自动加密bool IsEncrypt() const;// 设置自动加密void SetEncrypt(bool fEnable = true);// 是否自动保存bool IsAutoSave() const;// 设置自动保存void SetAutoSave(bool fEnable = true);// 从数据加载bool LoadFromData(LPCVOID lpData, DWORD nSize);// 读写字符串_tstring GetString(const _tstring& strSec, const _tstring& strKey, const _tstring& strDefault = _T("")) const;bool SetString(const _tstring& strSec, const _tstring& strKey, const _tstring& strVal);// 读写布尔值bool GetBool(const _tstring& strSec, const _tstring& strKey, bool fDefault = false) const;bool SetBool(const _tstring& strSec, const _tstring& strKey, bool fValue);// 读写整数int64_t GetInt(const _tstring& strSec, const _tstring& strKey, int64_t dwDefault = 0, int radix = 10) const;bool SetInt(const _tstring& strSec, const _tstring& strKey, int64_t dwNumber, int radix = 10);// 读写浮点数double GetFloat(const _tstring& strSec, const _tstring& strKey, double dDefault = 0.0f) const;bool SetFloat(const _tstring& strSec, const _tstring& strKey, double dNumber);// 删除配置节bool DeleteSection(const _tstring& strSec);// 删除配置值bool DeleteValue(const _tstring& strSec, const _tstring& strKey = _T(""));// 导出文本std::wstring DumpWStr() const;std::string DumpAStr() const;std::string DumpU8Str() const;_tstring Dump() const;// 数据是否加密virtual bool IsEncrypted(const uint8_t* pData, size_t nSize);// 获取加密后数据virtual std::vector<uint8_t> GetEncryptData(const uint8_t* pData, size_t nSize);// 获取解密后数据virtual std::vector<uint8_t> GetDecryptData(const uint8_t* pData, size_t nSize);private:std::vector<_tstring> SplitStringLine(const _tstring& str);_tstring _GetTextList(const std::vector<_tstring>& strList) const;bool _Parse(const _tstring& strCfg);_tstring _Dump(const INI_SECTION_LIST& mapData) const;private:INI_SECTION_LIST m_SectionList; // 节列表_tstring m_strFilePath; // 文件路径_tstring m_strCRLF; // 转行控制符std::vector<_tstring> EndTextList; // 末尾文本eTextEncoding m_TextEncoding; // 文本编码bool m_fAutoSave; // 自动保存(启用后设置数值时转储到文件)bool m_fEncrypt; // 加解密
};
CIniHelperX.cpp
#include "CIniHelperX.h"
#include <windows.h>
#include <strsafe.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")#define FROFILE_EXTERN_NAME _T(".ini")// UTF-8 Byte count table
unsigned char g_utf8_bytes_count_table[0x100] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x00,0x00,
};// UTF-8 Data mask table
unsigned char g_utf8_data_mask_table[0x100] = {0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x03,0x03,0x03,0x03,0x01,0x01,0x00,0x00,
};#define CRC32_POLY (0xEDB88320L) // CRC32标准
#define CRC32_TABLE_SIZE (256) // CRC查询表大小
#define CRC32_BLOCK_SIZE (1024 * 1024 * 64) // CRC缓冲块大小#define ENCRYPTED_ID (0x20250325) // 加密文件标识#define _count_of(_array) (sizeof(_array) / sizeof(_array[0]))typedef struct _INI_ENCRYPTED_HEADER
{uint32_t magic; // 加密文件标识uint32_t crc_data; // 加密后数据校验码uint32_t crc_raw; // 加密前数据校验码uint32_t data_size; // 数据大小uint8_t data[0]; // 数据起始
}INI_ENCRYPTED_HEADER, * PINI_ENCRYPTED_HEADER;static uint32_t g_Crc32Table[CRC32_TABLE_SIZE] = { 0 }; // CRC查询表
static bool g_bInitFlag = false; // CRC查询表初始化标记static void _InitCrc32Table(void);
static uint32_t GetCrc32(const uint8_t* lpData, size_t byteSize);
static uint32_t GetCrc32Data(uint32_t crcInit, const uint8_t* lpData, size_t byteSize);uint32_t GetCrc32Value(const void* lpData, size_t nSize)
{if (!g_bInitFlag){_InitCrc32Table();g_bInitFlag = true;}return GetCrc32((uint8_t*)lpData, nSize);
}uint32_t GetPartCrc32(uint32_t crcInit, const void* lpData, size_t byteSize)
{if (0 == byteSize){return crcInit;}if (!g_bInitFlag){_InitCrc32Table();g_bInitFlag = true;}return GetCrc32Data(crcInit, (uint8_t*)lpData, byteSize);
}void _InitCrc32Table(void)
{for (uint32_t i = 0; i < _count_of(g_Crc32Table); i++){uint32_t crc = i;for (int j = 0; j < 8; j++){if (crc & 0x00000001L)crc = (crc >> 1) ^ CRC32_POLY;elsecrc = crc >> 1;}g_Crc32Table[i] = crc;}
}uint32_t GetCrc32(const uint8_t* lpData, size_t byteSize)
{uint32_t dwCrc32 = 0;size_t nBlockSize = byteSize > CRC32_BLOCK_SIZE ? CRC32_BLOCK_SIZE : byteSize;uint8_t* lpBase = (uint8_t*)lpData;while (byteSize > 0){dwCrc32 = GetCrc32Data(dwCrc32, lpBase, nBlockSize);lpBase += nBlockSize;byteSize -= nBlockSize;nBlockSize = byteSize > CRC32_BLOCK_SIZE ? CRC32_BLOCK_SIZE : byteSize;}return dwCrc32;
}uint32_t GetCrc32Data(uint32_t crcInit, const uint8_t* lpData, size_t byteSize)
{uint32_t crc = crcInit ^ 0xffffffff;while (byteSize--){crc = (crc >> 8) ^ g_Crc32Table[(crc & 0xff) ^ *lpData++];}return crc ^ 0xffffffff;
}std::string _WStrToMultiStr(UINT CodePage, const std::wstring& str)
{int cbMultiByte = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);std::string strResult(cbMultiByte, 0);size_t nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size(), NULL, NULL);strResult.resize(nConverted);return strResult;
}std::wstring _MultiStrToWStr(UINT CodePage, const std::string& str)
{int cchWideChar = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);std::wstring strResult(cchWideChar, 0);size_t nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size());strResult.resize(nConverted);return strResult;
}std::string WStrToAStr(const std::wstring& str)
{return _WStrToMultiStr(CP_ACP, str);
}std::string WStrToU8Str(const std::wstring& str)
{return _WStrToMultiStr(CP_UTF8, str);
}_tstring WStrToTStr(const std::wstring& str)
{
#ifdef _UNICODEreturn str;
#elsereturn _WStrToMultiStr(CP_ACP, str);
#endif
}std::wstring AStrToWStr(const std::string& str)
{return _MultiStrToWStr(CP_ACP, str);
}std::string AStrToU8Str(const std::string& str)
{return WStrToU8Str(AStrToWStr(str));
}_tstring AStrToTStr(const std::string& str)
{
#ifdef _UNICODEreturn _MultiStrToWStr(CP_ACP, str);
#elsereturn str;
#endif
}std::wstring U8StrToWStr(const std::string& str)
{return _MultiStrToWStr(CP_UTF8, str);
}std::string U8StrToAStr(const std::string& str)
{return WStrToAStr(U8StrToWStr(str));
}_tstring U8StrToTStr(const std::string& str)
{
#ifdef _UNICODEreturn _MultiStrToWStr(CP_UTF8, str);
#elsereturn WStrToAStr(U8StrToWStr(str));
#endif
}std::string TStrToAStr(const _tstring& str)
{
#ifdef _UNICODEreturn _WStrToMultiStr(CP_ACP, str);
#elsereturn str;
#endif
}std::wstring TStrToWStr(const _tstring& str)
{
#ifdef _UNICODEreturn str;
#elsereturn AStrToWStr(str);
#endif
}std::string TStrToU8Str(const _tstring& str)
{
#ifdef _UNICODEreturn WStrToU8Str(str);
#elsereturn WStrToU8Str(AStrToWStr(str));
#endif
}_tstring GetCurrentModulePath()
{TCHAR szCurPath[MAX_PATH] = { 0 };::GetModuleFileName(NULL, szCurPath, _countof(szCurPath));_tstring strDir = szCurPath;return strDir;
}_tstring GetCurrentModuleDir()
{_tstring strDir = GetCurrentModulePath();strDir.resize(strDir.find_last_of(_T('\\')));return strDir;
}_tstring GetCurrentModuleName(bool bHasExt/* = false*/)
{_tstring strDir = GetCurrentModulePath();size_t nIndex = strDir.find_last_of(_T('\\'));if (nIndex != _tstring::npos){strDir = strDir.substr(nIndex + 1);}if (!bHasExt){nIndex = strDir.find_last_of(_T('.'));if (nIndex != _tstring::npos){strDir.resize(nIndex);}}return strDir;
}_tstring GetFileDir(const _tstring& strPath)
{_tstring strDir = strPath;for (auto& ch : strDir){if (_T('/') == ch){ch = _T('\\');}}_tstring strResult;size_t nIndex = strDir.find_last_of(_T('\\'));if (nIndex != _tstring::npos){strResult = strDir.substr(0, nIndex);}return strResult;
}bool IsDirectory(const _tstring& strPath)
{DWORD dwAttr = ::GetFileAttributes(strPath.c_str());if (INVALID_FILE_ATTRIBUTES == dwAttr){return false;}return FILE_ATTRIBUTE_DIRECTORY == (FILE_ATTRIBUTE_DIRECTORY & dwAttr);
}bool CreateDir(const _tstring& strPath)
{_tstring strDriver; //驱动器号, 如 D:_tstring strSubPath = strPath; //路径, 如 Test\1\2\3if (strPath.empty()){return false;}//获取盘符do{size_t nFindIndex = strPath.find_first_of(':'); //检查是否有驱动器号if (nFindIndex == _tstring::npos){break;}strDriver = strPath.substr(0, nFindIndex + 1); //得到驱动器号, 如 D:nFindIndex = strPath.find(_T("\\"), nFindIndex);if (nFindIndex == _tstring::npos){break;}strSubPath = strPath.substr(nFindIndex + 1); //得到路径, 如 Test\1\2\3} while (false);_tstring strDestDir;size_t nFindBegin = 0;size_t nFindIndex = 0;do{nFindIndex = strSubPath.find(_T("\\"), nFindBegin);if (nFindIndex != _tstring::npos){strDestDir = strSubPath.substr(0, nFindIndex);nFindBegin = nFindIndex + 1;}else{strDestDir = strSubPath;}if (!strDriver.empty()){strDestDir = strDriver + _T("\\") + strDestDir;}if (!::CreateDirectory(strDestDir.c_str(), NULL) && ERROR_ALREADY_EXISTS != ::GetLastError()){return false;}} while (nFindIndex != _tstring::npos);return true;
}int GetUtf8Count(const void* data_ptr, size_t size/* = -1*/)
{const uint8_t* data_pos = (const uint8_t*)data_ptr;size_t size_count = size;uint32_t code_point = 0;int32_t byte_count = 0;int32_t char_count = 0;bool result_flag = true;while ((0 != *data_pos) && (0 != size_count)){uint8_t ch = *data_pos;// ASCII 范围if (ch < 0x7F){code_point = ch;char_count++;}else{if (0 == byte_count){code_point = 0;if (ch >= 0xC0){// 获取字符编码字节数byte_count = g_utf8_bytes_count_table[ch];// 获取首字节码点code_point = ch & g_utf8_data_mask_table[ch];if (0 == byte_count){result_flag = false;break;}byte_count--;}else{result_flag = false;break;}}else{// 非首字节码点字节掩码检查if (0x80 != (ch & 0xC0)){result_flag = false;break;}// 码点组合code_point = code_point << 6;code_point |= ch & 0x3F;byte_count--;// 统计字符计数, 忽略字节顺序标记(BOM)if ((0 == byte_count) && (0xFEFF != code_point)){char_count++;}}}data_pos++;if (-1 != size_count){size_count--;}}if (!result_flag){return -1;}return char_count;
}int32_t GetUtf16Count(const void* data_ptr, size_t size/* = -1*/, bool* big_endian_ptr = nullptr)
{const uint16_t* data_pos = (const uint16_t*)data_ptr;size_t size_count = size;uint32_t code_point = 0;uint16_t code_point_high = 0;uint16_t code_point_low = 0;uint16_t code_point_tmp = 0;int32_t byte_count = 0;int32_t char_count = 0;bool big_endian_flag = false;bool little_endian_flag = false;bool result_flag = true;if (-1 != size_count){if ((size_count < 2) || (0 != (size_count % 2))){return -1;}}while ((0 != *data_pos) && (0 != size_count)){code_point_tmp = *data_pos;// 检查字节序if (0xFFFE == code_point_tmp || 0xFEFF == code_point_tmp){if (0 == byte_count){// 小端序if (0xFFFE == code_point_tmp){big_endian_flag = true;}// 大端序if (0xFEFF == code_point_tmp){little_endian_flag = true;}}else{result_flag = false;break;}// 不可能同时存在小端序和大端序if (big_endian_flag && little_endian_flag){result_flag = false;break;}data_pos++;if (-1 != size_count){size_count -= 2;}continue;}//字节序转换if (big_endian_flag){code_point_tmp = ((code_point_tmp >> 8) | (code_point_tmp << 8));}// 代理区检查if (!(code_point_tmp >= 0xD800 && code_point_tmp <= 0xDFFF)){if (code_point_high > 0){result_flag = false;break;}code_point = code_point_tmp;char_count++;}else{if (0 == byte_count){// 高位代理(高10位)if (code_point_tmp >= 0xD800 && code_point_tmp <= 0xDBFF){code_point_high = (code_point_tmp - 0xD800);byte_count = 1;}else{result_flag = false;break;}}else{if (1 == byte_count){// 低位代理(低10位)if ((code_point_tmp >= 0xDC00) && (code_point_tmp <= 0xDFFF)){code_point_low = (code_point_tmp - 0xDC00);code_point = 0x10000 + ((uint32_t)code_point_high << 10 | code_point_low);code_point_low = 0;code_point_high = 0;}else{result_flag = false;break;}}byte_count--;if (0 == byte_count){char_count++;}}}data_pos++;if (-1 != size_count){size_count -= 2;}}if (!result_flag){return -1;}if (big_endian_ptr){*big_endian_ptr = big_endian_flag;}return char_count;
}CIniHelperX::CIniHelperX(const _tstring& strPath/* = _T("")*/, bool fLoad/* = true*/, bool fAutoSave/* = false*/, bool fEncrypt/* = true*/):m_strFilePath(GetCurrentModuleDir()),m_fAutoSave(fAutoSave),m_fEncrypt(fEncrypt),m_strCRLF(_T("\r\n")),m_TextEncoding(eTextEncoding::eTextUtf8)
{m_strFilePath += _T("\\");m_strFilePath += GetCurrentModuleName(false);m_strFilePath += FROFILE_EXTERN_NAME;if (!strPath.empty()){if (::PathIsRelative(strPath.c_str())){m_strFilePath = GetCurrentModuleDir();m_strFilePath += _T("\\");m_strFilePath += strPath;}else{m_strFilePath = strPath;}}if (fLoad){Load();}
}CIniHelperX::~CIniHelperX()
{}bool CIniHelperX::LoadFromFile(const _tstring& strFileName)
{HANDLE hFile = INVALID_HANDLE_VALUE;bool bSuccess = true;_tstring strFilePath = strFileName;if (strFileName.empty()){strFilePath += GetCurrentModuleDir();strFilePath += _T("\\");strFilePath += GetCurrentModuleName(false);strFilePath += FROFILE_EXTERN_NAME;}hFile = ::CreateFile(strFilePath.c_str(),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (INVALID_HANDLE_VALUE == hFile){return false;}m_SectionList.clear();LPBYTE lpData = nullptr;// 读取文本do{LARGE_INTEGER liSize = { 0 };if (!::GetFileSizeEx(hFile, &liSize)){break;}lpData = (LPBYTE)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)liSize.QuadPart + 2);if (nullptr == lpData){break;}DWORD nBytesToRead = 0;if (!::ReadFile(hFile, (LPVOID)lpData, liSize.LowPart, &nBytesToRead, NULL)){break;}bSuccess = LoadFromData(lpData, liSize.LowPart);} while (false);if (nullptr != lpData){::HeapFree(::GetProcessHeap(), 0, (LPVOID)lpData);}if (INVALID_HANDLE_VALUE != hFile){::CloseHandle(hFile);}return bSuccess;
}bool CIniHelperX::Load()
{return LoadFromFile(m_strFilePath);
}bool CIniHelperX::Save(eTextEncoding enc/* = eTextEncoding::eAuto*/)
{return SaveToFile(m_strFilePath, enc);
}void CIniHelperX::Clear()
{m_SectionList.clear();
}bool CIniHelperX::SaveToFile(const _tstring& strFileName, eTextEncoding enc/* = eTextEncoding::eAuto*/)
{HANDLE hFile = INVALID_HANDLE_VALUE;bool bSuccess = true;_tstring strFilePath = strFileName;if (strFileName.empty()){strFilePath += GetCurrentModuleDir();strFilePath += _T("\\");strFilePath += GetCurrentModuleName(false);strFilePath += FROFILE_EXTERN_NAME;}do{std::string strMulBytes;std::wstring strWideBytes;bool fWideByte = false;_tstring strDirectory = GetFileDir(strFilePath);if (!IsDirectory(strDirectory)){CreateDir(strDirectory);}hFile = ::CreateFile(strFilePath.c_str(),GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);if (INVALID_HANDLE_VALUE == hFile){return false;}if (enc == eTextEncoding::eTextAuto){enc = m_TextEncoding;}if (enc == eTextEncoding::eTextAnsi){_tstring strDump = _Dump(m_SectionList);strMulBytes += TStrToAStr(strDump);}else if (enc == eTextEncoding::eTextUtf8){_tstring strDump = _Dump(m_SectionList);strMulBytes += TStrToU8Str(strDump);}else if (enc == eTextEncoding::eTextUtf8BOM){strMulBytes = "\xEF\xBB\xBF";_tstring strDump = _Dump(m_SectionList);strMulBytes += TStrToU8Str(strDump);}else if (enc == eTextEncoding::eTextUtf16LEBOM){strWideBytes += wchar_t(0xFEFF);_tstring strDump = _Dump(m_SectionList);strWideBytes += TStrToWStr(strDump);fWideByte = true;}else if (enc == eTextEncoding::eTextUtf16BEBOM){strWideBytes += wchar_t(0xFEFF);_tstring strDump = _Dump(m_SectionList);strWideBytes += TStrToWStr(strDump);fWideByte = true;for (auto& ch : strWideBytes){ch = ((ch & 0x00FF) << 8) | ((ch & 0xFF00) >> 8);}}if (m_fEncrypt){if (fWideByte){std::vector<uint8_t> vData = GetEncryptData((uint8_t*)strWideBytes.c_str(), strWideBytes.size() * sizeof(wchar_t));bSuccess = ::WriteFile(hFile, vData.data(), vData.size(), nullptr, nullptr);}else{std::vector<uint8_t> vData = GetEncryptData((uint8_t*)strMulBytes.c_str(), strMulBytes.size());bSuccess = ::WriteFile(hFile, vData.data(), vData.size(), nullptr, nullptr);}if (!bSuccess){break;}}else{if (fWideByte){bSuccess = ::WriteFile(hFile, strWideBytes.data(), strWideBytes.size() * sizeof(wchar_t), nullptr, nullptr);}else{bSuccess = ::WriteFile(hFile, strMulBytes.data(), strMulBytes.size(), nullptr, nullptr);}if (!bSuccess){break;}}} while (false);if (INVALID_HANDLE_VALUE != hFile){::CloseHandle(hFile);}return bSuccess;
}bool CIniHelperX::LoadFromData(LPCVOID lpData, DWORD nSize)
{_tstring strContent;std::vector<uint8_t> DecryptData;uint8_t* pBytesData = (uint8_t*)lpData;size_t nDataSize = nSize;bool fBigEndian = false;if (IsEncrypted((uint8_t*)pBytesData, nSize)){DecryptData = GetDecryptData((uint8_t*)pBytesData, nDataSize);pBytesData = DecryptData.data();nDataSize = DecryptData.size();}// 编码自动转换if (GetUtf8Count(pBytesData, nDataSize) >= 0){// UTF8 -> UTF16std::string strUtf8((const char*)pBytesData, nDataSize);m_TextEncoding = eTextEncoding::eTextUtf8;// 去除字节序标识while (strUtf8.size() >= 3 && (0xEF == (uint8_t)strUtf8[0] && 0xBB == (uint8_t)strUtf8[1] && 0xBF == (uint8_t)strUtf8[2])){m_TextEncoding = eTextEncoding::eTextUtf8BOM;strUtf8 = strUtf8.substr(3);}strContent = U8StrToTStr(strUtf8);}else if (GetUtf16Count(pBytesData, nDataSize, &fBigEndian) >= 0){// UTF16 -> Textstd::wstring strUtf16((const wchar_t*)pBytesData, nDataSize / sizeof(wchar_t));m_TextEncoding = eTextEncoding::eTextUtf16LEBOM;if (fBigEndian){m_TextEncoding = eTextEncoding::eTextUtf16BEBOM;}if (eTextEncoding::eTextUtf16BEBOM == m_TextEncoding){for (auto& ch : strUtf16){ch = ((ch & 0x00FF) << 8) | ((ch & 0xFF00) >> 8);}}// 去除字节序标识while (!strUtf16.empty() && 0xFEFF == strUtf16[0]){strUtf16 = strUtf16.substr(1);}strContent = WStrToTStr(strUtf16);}else{m_TextEncoding = eTextEncoding::eTextAnsi;std::string strAnsi((const char*)pBytesData, nDataSize);strContent = AStrToTStr(strAnsi);}// 去除字节序标识while (!strContent.empty() && 0xFEFF == strContent[0]){strContent = strContent.substr(1);}if (!strContent.empty()){_Parse(strContent);}return true;
}std::wstring CIniHelperX::DumpWStr() const
{return TStrToWStr(_Dump(m_SectionList));
}std::string CIniHelperX::DumpAStr() const
{return TStrToAStr(_Dump(m_SectionList));
}std::string CIniHelperX::DumpU8Str() const
{return TStrToU8Str(_Dump(m_SectionList));
}_tstring CIniHelperX::Dump() const
{return _Dump(m_SectionList);
}bool CIniHelperX::IsEncrypt() const
{return m_fEncrypt;
}void CIniHelperX::SetEncrypt(bool fEnable/* = true*/)
{m_fEncrypt = fEnable;
}bool CIniHelperX::IsAutoSave() const
{return m_fAutoSave;
}void CIniHelperX::SetAutoSave(bool fEnable/* = true*/)
{m_fAutoSave = fEnable;
}std::vector<_tstring> CIniHelperX::SplitStringLine(const _tstring& str)
{std::vector<_tstring> splitOut;m_strCRLF = _T("\r\n");if (_tstring::npos != str.find(_T("\r\n"))){m_strCRLF = _T("\r\n");}else if (_tstring::npos != str.find(_T("\r"))){m_strCRLF = _T("\r");}else if (_tstring::npos != str.find(_T("\n"))){m_strCRLF = _T("\n");}size_t iStart = 0;size_t iEnd = 0;while (_tstring::npos != (iEnd = str.find(m_strCRLF, iEnd))){_tstring strLine = str.substr(iStart, iEnd - iStart);splitOut.push_back(strLine);iEnd += m_strCRLF.size();iStart = iEnd;}if (iStart != iEnd){_tstring strLine = str.substr(iStart, iEnd - iStart);if (!strLine.empty() && _T('\r') == strLine.back()){strLine.resize(strLine.size() - 1);}splitOut.push_back(strLine);}return splitOut;
}bool _IsSection(const _tstring& strContent)
{if (strContent.empty()){return false;}if (((_T('[') == strContent.front() && _T(']') == strContent.back()))){return true;}return false;
}bool _IsComment(const _tstring& strContent)
{if (strContent.empty()){return false;}if (((_T('#') == strContent[0] || _T(';') == strContent[0]))){return true;}return false;
}_tstring RemoveStringSpaces(_tstring& strValue, bool fLeft, bool fRight)
{LPCTSTR lpBegin = strValue.data();LPCTSTR lpEnd = strValue.data() + strValue.size();if (fLeft){while (lpBegin < lpEnd){if (_T(' ') == *lpBegin){lpBegin++;}else{break;}}}if (fRight){while (lpEnd > lpBegin){if (_T(' ') == *(lpEnd - 1)){lpEnd--;}else{break;}}}return _tstring(lpBegin, lpEnd - lpBegin);
}bool CIniHelperX::_Parse(const _tstring& strCfg)
{INI_CFG_SECTION iniAppInfo;_tstring strSection;std::vector<_tstring> vTestLine = SplitStringLine(strCfg);std::vector<_tstring> vComment;for (auto& item : vTestLine){//查找到配置节if (_IsSection(item)){//插入节配置if (!strSection.empty()){iniAppInfo.SectionName = strSection;m_SectionList.push_back(iniAppInfo);iniAppInfo.ValueList.clear();}strSection = item.substr(1, item.size() - 2);iniAppInfo.SectionName = RemoveStringSpaces(strSection, true, true);iniAppInfo.SrctionNameRaw = strSection;iniAppInfo.SectionComment = vComment;vComment.clear();}else{auto itFind = item.find(_T("="));// 过滤注释if (_tstring::npos == itFind || item.empty() || _IsComment(item)){vComment.push_back(item);continue;}// 获取原始值名和值数据_tstring strRawName = item.substr(0, itFind);_tstring strRawValue = item.substr(itFind + 1);// 移除值名前后空格_tstring strName = RemoveStringSpaces(strRawName, true, true);// 移除数据前面空格_tstring strValue = RemoveStringSpaces(strRawValue, true, true);// 移除值数据前后引号if (strValue.size() >= 2){// 移除值数据前后单引号if (_T('\'') == strValue.front() && _T('\'') == strValue.back()){strValue = strValue.substr(1, strValue.size() - 2);}// 移除值数据前后双引号else if (_T('\"') == strValue.front() && _T('\"') == strValue.back()){strValue = strValue.substr(1, strValue.size() - 2);}}INI_CFG_VALUE info(strName, strValue, vComment);info.ValueNameRaw = strRawName;info.ValueDataRaw = strRawValue;iniAppInfo.ValueList.push_back(info);vComment.clear();}}//插入节配置if (!strSection.empty()){m_SectionList.push_back(iniAppInfo);}EndTextList = vComment;return true;
}_tstring CIniHelperX::_GetTextList(const std::vector<_tstring>& strList) const
{_tstring strResult;size_t nCount = strList.size();for (const auto& item : strList){nCount--;if (item.empty() && nCount > 0){strResult += m_strCRLF;}else{strResult += item;if (nCount > 0){strResult += m_strCRLF;}}}return strResult;
}_tstring CIniHelperX::_Dump(const INI_SECTION_LIST& mapData) const
{std::vector<_tstring> vOutput;size_t nCount = 0;for (const auto& section : mapData){// 节注释nCount += section.SectionComment.size();// 节名nCount++;for (const auto& value : section.ValueList){// 值注释nCount += value.ValueComment.size();// 值名 = 值数据nCount++;}}nCount += EndTextList.size();vOutput.reserve(nCount);for (const auto& section : mapData){// 节注释vOutput.insert(vOutput.end(), section.SectionComment.begin(), section.SectionComment.end());// 节名vOutput.emplace_back(_T("[") + section.SrctionNameRaw + _T("]"));// 值列表for (const auto& value : section.ValueList){// 值注释vOutput.insert(vOutput.end(), value.ValueComment.begin(), value.ValueComment.end());// 值名 = 值数据vOutput.emplace_back(value.ValueNameRaw + _T("=") + value.ValueDataRaw);}}vOutput.insert(vOutput.end(), EndTextList.begin(), EndTextList.end());return _GetTextList(vOutput);
}_tstring CIniHelperX::GetString(const _tstring& strSec, const _tstring& strKey, const _tstring& strDefault/* = _T("")*/) const
{_tstring strText = strDefault;auto itSec = std::find(m_SectionList.begin(), m_SectionList.end(), strSec);if (itSec != m_SectionList.end()){auto itValue = std::find(itSec->ValueList.begin(), itSec->ValueList.end(), strKey);if (itValue != itSec->ValueList.end()){strText = itValue->ValueData;}}return strText;
}bool CIniHelperX::SetString(const _tstring& strSec, const _tstring& strKey, const _tstring& strVal)
{auto itSec = std::find(m_SectionList.begin(), m_SectionList.end(), strSec);if (itSec != m_SectionList.end()){auto itValue = std::find(itSec->ValueList.begin(), itSec->ValueList.end(), strKey);if (itValue != itSec->ValueList.end()){itValue->ValueData = strVal;itValue->ValueDataRaw = strVal;}else{// 修改值, 原始值名与原始值数据也需要修改INI_CFG_VALUE value(strKey, strVal);value.ValueNameRaw = strKey;value.ValueDataRaw = strVal;itSec->ValueList.push_back(value);}}else{// 修改值, 原始值名与原始值数据也需要修改INI_CFG_VALUE value(strKey, strVal);value.ValueNameRaw = strKey;value.ValueDataRaw = strVal;// 修改节, 原始节名也需要修改INI_CFG_SECTION info(strSec, { value }, {});info.SrctionNameRaw = strSec;m_SectionList.push_back(info);}if (m_fAutoSave){Save();}return true;
}bool CIniHelperX::GetBool(const _tstring& strSec, const _tstring& strKey, bool fDefault/* = false*/) const
{return 0 == _tcsicmp(GetString(strSec, strKey, fDefault ? _T("true") : _T("false")).c_str(), _T("true"));
}bool CIniHelperX::SetBool(const _tstring& strSec, const _tstring& strKey, bool fValue)
{return SetString(strSec, strKey, fValue ? _T("true") : _T("false"));
}int64_t CIniHelperX::GetInt(const _tstring& strSec, const _tstring& strKey, int64_t dwDefault/* = 0*/, int radix/* = 10*/) const
{TCHAR szBuf[MAX_PATH] = { 0 };::_i64tot_s(dwDefault, szBuf, _countof(szBuf), radix);return(::_tcstoll(GetString(strSec, strKey, szBuf).c_str(), nullptr, radix));
}bool CIniHelperX::SetInt(const _tstring& strSec, const _tstring& strKey, int64_t dwNumber, int radix/* = 10*/)
{TCHAR szBuf[MAX_PATH] = { 0 };::_i64tot_s(dwNumber, szBuf, _countof(szBuf), radix);return SetString(strSec, strKey, szBuf);
}double CIniHelperX::GetFloat(const _tstring& strSec, const _tstring& strKey, double dDefault/* = 0.0f*/) const
{TCHAR szBuf[MAX_PATH] = { 0 };::_stprintf_s(szBuf, _countof(szBuf), _T("%g"), dDefault);return(::_tcstod(GetString(strSec, strKey, szBuf).c_str(), nullptr));
}bool CIniHelperX::SetFloat(const _tstring& strSec, const _tstring& strKey, double dNumber)
{TCHAR szBuf[MAX_PATH] = { 0 };::_stprintf_s(szBuf, _countof(szBuf), _T("%g"), dNumber);return SetString(strSec, strKey, szBuf);
}bool CIniHelperX::DeleteSection(const _tstring& strSec)
{auto itSec = std::find(m_SectionList.begin(), m_SectionList.end(), strSec);if (itSec == m_SectionList.end()){return false;}m_SectionList.erase(itSec);return true;
}bool CIniHelperX::DeleteValue(const _tstring& strSec, const _tstring& strKey/* = _T("")*/)
{auto itSec = std::find(m_SectionList.begin(), m_SectionList.end(), strSec);if (itSec == m_SectionList.end()){return false;}auto itValue = std::find(itSec->ValueList.begin(), itSec->ValueList.end(), strKey);if (itValue == itSec->ValueList.end()){return false;}itSec->ValueList.erase(itValue);return true;
}bool CIniHelperX::IsEncrypted(const uint8_t* pData, size_t nSize)
{bool fResult = false;do{PINI_ENCRYPTED_HEADER pEnc = (PINI_ENCRYPTED_HEADER)pData;if (nSize < sizeof(INI_ENCRYPTED_HEADER)){break;}// 检查标识if (ENCRYPTED_ID != pEnc->magic){break;}// 检查大小if (pEnc->data_size + sizeof(INI_ENCRYPTED_HEADER) != nSize){break;}if (pEnc->crc_data != GetCrc32Value(pEnc->data, pEnc->data_size)){break;}fResult = true;} while (false);return fResult;
}std::vector<uint8_t> CIniHelperX::GetEncryptData(const uint8_t* pData, size_t nSize)
{std::vector<uint8_t> reault;do{if (!pData || (0 == nSize)){break;}// 检查是否已经加密过if (IsEncrypted(pData, nSize)){reault.resize(nSize);memcpy(reault.data(), pData, nSize);return reault;}// 加密数据INI_ENCRYPTED_HEADER ide = { 0 };ide.magic = ENCRYPTED_ID;ide.data_size = nSize;reault.resize(sizeof(INI_ENCRYPTED_HEADER) + nSize);PINI_ENCRYPTED_HEADER pEnc = (PINI_ENCRYPTED_HEADER)reault.data();memcpy(pEnc, &ide, sizeof(INI_ENCRYPTED_HEADER));memcpy(pEnc->data, pData, nSize);// 计算加密前数据校验和pEnc->crc_raw = GetCrc32Value(pEnc->data, pEnc->data_size);// 加密数据uint8_t* pBytesData = pEnc->data;size_t nBytesSize = pEnc->data_size;for (size_t i = 0; i < nBytesSize; i++){pBytesData[i] = (pBytesData[i] ^ (uint8_t)(0x80 + i)) + i;}// 计算加密后数据校验和pEnc->crc_data = GetCrc32Value(pEnc->data, pEnc->data_size);} while (false);return reault;
}std::vector<uint8_t> CIniHelperX::GetDecryptData(const uint8_t* pData, size_t nSize)
{std::vector<uint8_t> reault;do{if (!pData || (0 == nSize)){break;}PINI_ENCRYPTED_HEADER pEnc = (PINI_ENCRYPTED_HEADER)pData;if (nSize < sizeof(INI_ENCRYPTED_HEADER)){break;}// 检查标识if (ENCRYPTED_ID != pEnc->magic){break;}// 检查大小if (pEnc->data_size + sizeof(INI_ENCRYPTED_HEADER) != nSize){break;}std::vector<uint8_t> vDataBuf(pEnc->data_size);memcpy(vDataBuf.data(), pEnc->data, pEnc->data_size);uint8_t* pBytesData = vDataBuf.data();size_t nBytesSize = vDataBuf.size();// 检查加密后数据校验和if (pEnc->crc_data != GetCrc32Value(pBytesData, nBytesSize)){break;}// 解密数据for (size_t i = 0; i < nBytesSize; i++){pBytesData[i] = (pBytesData[i] - i) ^ (uint8_t)(0x80 + i);}// 检查解密后数据校验和if (pEnc->crc_raw != GetCrc32Value(pBytesData, nBytesSize)){break;}reault = std::move(vDataBuf);} while (false);return reault;
}
main.cpp
#include <locale.h>
#include <tchar.h>
#include "Win32Utils/CIniHelperX.h"int _tmain(int argc, LPCTSTR argv[])
{setlocale(LC_ALL, "");CIniHelperX obj;obj.SetString(_T("config"), _T("name"), _T("FlameCyclone"));obj.SetInt(_T("config"), _T("age"), 30);obj.SetFloat(_T("config"), _T("float"), 3.141592653589793);obj.Save();obj.SetEncrypt(true);obj.SaveToFile(_T("Encrypt.ini"));return 0;
}