Files
SimpleRemoter/common/IniParser.h
2026-01-29 19:35:40 +01:00

165 lines
4.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
// IniParser.h - 轻量级 INI 文件解析器header-only
// 特点:
// - 不 trim key/value保留原始空格适用于多语言 key 精确匹配)
// - 无文件大小限制(不依赖 GetPrivateProfileSection
// - 支持 ; 和 # 注释
// - 支持多 section
// - 支持转义序列:\n \r \t \\ \" key 和 value 均支持)
// - 纯 C++ 标准库,不依赖 MFC / Windows API
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
class CIniParser
{
public:
typedef std::map<std::string, std::string> TKeyVal;
typedef std::map<std::string, TKeyVal> TSections;
CIniParser() {}
void Clear()
{
m_sections.clear();
}
// 加载 INI 文件,返回是否成功
// 文件不存在返回 false空文件返回 true
bool LoadFile(const char* filePath)
{
Clear();
if (!filePath || !filePath[0])
return false;
FILE* f = nullptr;
#ifdef _MSC_VER
if (fopen_s(&f, filePath, "r") != 0 || !f)
return false;
#else
f = fopen(filePath, "r");
if (!f)
return false;
#endif
std::string currentSection;
char line[4096];
while (fgets(line, sizeof(line), f)) {
// 去除行尾换行符
size_t len = strlen(line);
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
line[--len] = '\0';
if (len == 0)
continue;
// 跳过注释
if (line[0] == ';' || line[0] == '#')
continue;
// 检测 section 头: [SectionName]
// 真正的 section 头:']' 后面没有 '='(否则是 key=value
if (line[0] == '[') {
char* end = strchr(line, ']');
if (end) {
char* eqAfter = strchr(end + 1, '=');
if (!eqAfter) {
// 纯 section 头,如 [Strings]
*end = '\0';
currentSection = line + 1;
continue;
}
// ']' 后有 '=',如 [使用FRP]=[Using FRP],当作 key=value 处理
}
}
// 不在任何 section 内则跳过
if (currentSection.empty())
continue;
// 解析 key=value只按第一个 '=' 分割,不 trim
// key 和 value 均做反转义(\n \r \t \\ \"
char* eq = strchr(line, '=');
if (eq && eq != line) {
*eq = '\0';
std::string key = Unescape(std::string(line));
std::string value = Unescape(std::string(eq + 1));
m_sections[currentSection][key] = value;
}
}
fclose(f);
return true;
}
// 获取指定 section 下的 key 对应的 value
// 未找到时返回 defaultVal
const char* GetValue(const char* section, const char* key,
const char* defaultVal = "") const
{
auto itSec = m_sections.find(section ? section : "");
if (itSec == m_sections.end())
return defaultVal;
auto itKey = itSec->second.find(key ? key : "");
if (itKey == itSec->second.end())
return defaultVal;
return itKey->second.c_str();
}
// 获取整个 section 的所有键值对,不存在返回 nullptr
const TKeyVal* GetSection(const char* section) const
{
auto it = m_sections.find(section ? section : "");
if (it == m_sections.end())
return nullptr;
return &it->second;
}
// 获取 section 中的键值对数量
size_t GetSectionSize(const char* section) const
{
const TKeyVal* p = GetSection(section);
return p ? p->size() : 0;
}
// 获取所有 section
const TSections& GetAllSections() const
{
return m_sections;
}
private:
TSections m_sections;
// 反转义:将字面量 \n \r \t \\ \" 转为对应的控制字符
static std::string Unescape(const std::string& s)
{
std::string result;
result.reserve(s.size());
for (size_t i = 0; i < s.size(); i++) {
if (s[i] == '\\' && i + 1 < s.size()) {
switch (s[i + 1]) {
case 'n': result += '\n'; i++; break;
case 'r': result += '\r'; i++; break;
case 't': result += '\t'; i++; break;
case '\\': result += '\\'; i++; break;
case '"': result += '"'; i++; break;
default: result += s[i]; break; // 未知转义保留原样
}
} else {
result += s[i];
}
}
return result;
}
};