1 #include "stdafx.h"
2 #include "IniHelper.h"
3
4
CIniHelper(const wstring & file_path)5 CIniHelper::CIniHelper(const wstring& file_path)
6 {
7 m_file_path = file_path;
8 ifstream file_stream{ file_path };
9 if (!file_stream.is_open())
10 return;
11 // 获取文件大小
12 file_stream.seekg(0, std::ios::end);
13 size_t file_size = static_cast<size_t>(file_stream.tellg());
14 file_stream.seekg(0, std::ios::beg);
15 // 读取文件内容
16 string ini_str;
17 ini_str.resize(file_size + 1);
18 file_stream.read(&ini_str[0], file_size);
19 // 检查并添加末尾的空行
20 if (!ini_str.empty() && ini_str.back() != L'\n')
21 ini_str.push_back(L'\n');
22 // 转换成Unicode
23 m_ini_str = CCommon::StrToUnicode(ini_str, CodeType::AUTO);
24 }
25
CIniHelper(UINT id,CodeType code_type)26 CIniHelper::CIniHelper(UINT id, CodeType code_type)
27 {
28 m_ini_str = CCommon::GetTextResource(id, code_type);
29 }
30
31
~CIniHelper()32 CIniHelper::~CIniHelper()
33 {
34 }
35
SetSaveAsUTF8(bool utf8)36 void CIniHelper::SetSaveAsUTF8(bool utf8)
37 {
38 m_save_as_utf8 = utf8;
39 }
40
WriteString(const wchar_t * AppName,const wchar_t * KeyName,const wstring & str)41 void CIniHelper::WriteString(const wchar_t* AppName, const wchar_t* KeyName, const wstring& str)
42 {
43 wstring write_str{ str };
44 if (!write_str.empty() && (write_str[0] == L' ' || write_str.back() == L' ')) //如果字符串前后含有空格,则在字符串前后添加引号
45 {
46 write_str = L'\"' + write_str;
47 write_str.push_back(L'\"');
48 }
49 _WriteString(AppName, KeyName, write_str);
50 }
51
GetString(const wchar_t * AppName,const wchar_t * KeyName,const wchar_t * default_str) const52 wstring CIniHelper::GetString(const wchar_t* AppName, const wchar_t* KeyName, const wchar_t* default_str) const
53 {
54 wstring rtn{ _GetString(AppName, KeyName, default_str) };
55 //如果读取的字符串前后有引号,则删除它
56 if (!rtn.empty() && rtn.front() == L'\"')
57 rtn = rtn.substr(1);
58 if (!rtn.empty() && rtn.back() == L'\"')
59 rtn.pop_back();
60 return rtn;
61 }
62
WriteInt(const wchar_t * AppName,const wchar_t * KeyName,int value)63 void CIniHelper::WriteInt(const wchar_t* AppName, const wchar_t* KeyName, int value)
64 {
65 wchar_t buff[16]{};
66 _itow_s(value, buff, 10);
67 _WriteString(AppName, KeyName, wstring(buff));
68 }
69
GetInt(const wchar_t * AppName,const wchar_t * KeyName,int default_value) const70 int CIniHelper::GetInt(const wchar_t* AppName, const wchar_t* KeyName, int default_value) const
71 {
72 wchar_t default_str_buff[16]{};
73 _itow_s(default_value, default_str_buff, 10);
74 wstring rtn{ _GetString(AppName, KeyName, default_str_buff) };
75 if (rtn == L"true")
76 return 1;
77 else if (rtn == L"false")
78 return 0;
79 else
80 return _ttoi(rtn.c_str());
81 }
82
WriteDouble(const wchar_t * AppName,const wchar_t * KeyName,double value)83 void CIniHelper::WriteDouble(const wchar_t* AppName, const wchar_t* KeyName, double value)
84 {
85 _WriteString(AppName, KeyName, std::to_wstring(value));
86 }
87
GetDouble(const wchar_t * AppName,const wchar_t * KeyName,double default_value) const88 double CIniHelper::GetDouble(const wchar_t* AppName, const wchar_t* KeyName, double default_value) const
89 {
90 wstring rtn{ _GetString(AppName, KeyName, std::to_wstring(default_value).c_str()) };
91 return _wtof(rtn.c_str());
92 }
93
WriteBool(const wchar_t * AppName,const wchar_t * KeyName,bool value)94 void CIniHelper::WriteBool(const wchar_t* AppName, const wchar_t* KeyName, bool value)
95 {
96 if (value)
97 _WriteString(AppName, KeyName, wstring(L"true"));
98 else
99 _WriteString(AppName, KeyName, wstring(L"false"));
100 }
101
GetBool(const wchar_t * AppName,const wchar_t * KeyName,bool default_value) const102 bool CIniHelper::GetBool(const wchar_t* AppName, const wchar_t* KeyName, bool default_value) const
103 {
104 wstring rtn{ _GetString(AppName, KeyName, (default_value ? L"true" : L"false")) };
105 if (rtn == L"true")
106 return true;
107 else if (rtn == L"false")
108 return false;
109 else
110 return (_ttoi(rtn.c_str()) != 0);
111 }
112
WriteIntArray(const wchar_t * AppName,const wchar_t * KeyName,const int * values,int size)113 void CIniHelper::WriteIntArray(const wchar_t* AppName, const wchar_t* KeyName, const int* values, int size)
114 {
115 CString str, tmp;
116 for (int i{}; i < size; i++)
117 {
118 tmp.Format(_T("%d,"), values[i]);
119 str += tmp;
120 }
121 _WriteString(AppName, KeyName, wstring(str));
122 }
123
GetIntArray(const wchar_t * AppName,const wchar_t * KeyName,int * values,int size,int default_value) const124 void CIniHelper::GetIntArray(const wchar_t* AppName, const wchar_t* KeyName, int* values, int size, int default_value) const
125 {
126 CString default_str;
127 default_str.Format(_T("%d"), default_value);
128 wstring str;
129 str = _GetString(AppName, KeyName, default_str);
130 size_t index{}, index0{};
131 for (int i{}; i < size; i++)
132 {
133 index0 = index;
134 if (index0 < 256 && str[index0] == L',')
135 index0++;
136 index = str.find(L',', index + 1);
137 if (index0 == index)
138 {
139 if (i != 0)
140 values[i] = values[i - 1]; //如果后面已经没有数据,则填充为前一个数据
141 else
142 values[i] = default_value;
143 }
144 else
145 {
146 wstring tmp = str.substr(index0, index - index0);
147 values[i] = _wtoi(tmp.c_str());
148 }
149 }
150 }
151
WriteBoolArray(const wchar_t * AppName,const wchar_t * KeyName,const bool * values,int size)152 void CIniHelper::WriteBoolArray(const wchar_t* AppName, const wchar_t* KeyName, const bool* values, int size)
153 {
154 int value{};
155 for (int i{}; i < size; i++)
156 {
157 if (values[i])
158 value |= (1 << i);
159 }
160 return WriteInt(AppName, KeyName, value);
161 }
162
GetBoolArray(const wchar_t * AppName,const wchar_t * KeyName,bool * values,int size,bool default_value) const163 void CIniHelper::GetBoolArray(const wchar_t* AppName, const wchar_t* KeyName, bool* values, int size, bool default_value) const
164 {
165 int value = GetInt(AppName, KeyName, 0);
166 for (int i{}; i < size; i++)
167 {
168 values[i] = ((value >> i) % 2 != 0);
169 }
170 }
171
WriteStringList(const wchar_t * AppName,const wchar_t * KeyName,const vector<wstring> & values)172 void CIniHelper::WriteStringList(const wchar_t* AppName, const wchar_t* KeyName, const vector<wstring>& values)
173 {
174 wstring str_write{ CCommon::MergeStringList(values) };
175 _WriteString(AppName, KeyName, str_write);
176 }
177
GetStringList(const wchar_t * AppName,const wchar_t * KeyName,vector<wstring> & values,const vector<wstring> & default_values) const178 void CIniHelper::GetStringList(const wchar_t* AppName, const wchar_t* KeyName, vector<wstring>& values, const vector<wstring>& default_values) const
179 {
180 wstring default_str{ CCommon::MergeStringList(default_values) };
181 wstring str_value{ _GetString(AppName, KeyName, default_str.c_str()) };
182 CCommon::SplitStringList(values, str_value);
183 }
184
GetValue(const wchar_t * AppName,const wchar_t * KeyName,CVariant default_value) const185 CVariant CIniHelper::GetValue(const wchar_t* AppName, const wchar_t* KeyName, CVariant default_value) const
186 {
187 wstring str_value = GetString(AppName, KeyName, default_value.ToString());
188 return CVariant(str_value);
189 }
190
WriteValue(const wchar_t * AppName,const wchar_t * KeyName,CVariant value)191 void CIniHelper::WriteValue(const wchar_t* AppName, const wchar_t* KeyName, CVariant value)
192 {
193 WriteString(AppName, KeyName, value.ToString().GetString());
194 }
195
196
GetAllAppName(const wstring & prefix) const197 vector<wstring> CIniHelper::GetAllAppName(const wstring& prefix) const
198 {
199 vector<wstring> list;
200 size_t pos{};
201 while ((pos = m_ini_str.find(L"\n[" + prefix, pos)) != wstring::npos)
202 {
203 size_t end = m_ini_str.find(L']', pos + 1);
204 if (end != wstring::npos)
205 {
206 wstring tmp(m_ini_str.begin() + pos + prefix.size() + 2, m_ini_str.begin() + end);
207 list.push_back(std::move(tmp));
208 pos = end + 1;
209 }
210 }
211 return list;
212 }
213
GetAllKeyValues(const wstring & AppName,std::map<wstring,wstring> & map) const214 void CIniHelper::GetAllKeyValues(const wstring& AppName, std::map<wstring,wstring>& map) const
215 {
216 wstring app_str{ L"[" };
217 app_str.append(AppName).append(L"]");
218 size_t app_pos{}, app_end_pos{};
219 app_pos = m_ini_str.find(app_str);
220 if (app_pos == wstring::npos)
221 return;
222 app_end_pos = m_ini_str.find(L"\n[", app_pos + 2);
223 if (app_end_pos != wstring::npos)
224 app_end_pos++;
225 app_str = m_ini_str.substr(app_pos, app_end_pos - app_pos);
226 vector<wstring> line;
227 CCommon::StringSplit(app_str, L'\n', line);
228 for (wstring str : line)
229 {
230 // CCommon::StringSplit会跳过空字符串,str一定非空
231 if (str[0] == L';' || str[0] == L'#') // 跳过注释行(只支持行首注释)
232 continue;
233 size_t pos = str.find_first_of(L'=');
234 if (pos == wstring::npos)
235 continue;
236 wstring key{ str.substr(0, pos) };
237 wstring value{ str.substr(pos + 1) };
238 CCommon::StringNormalize(key);
239 CCommon::StringNormalize(value);
240 if (!key.empty() && !value.empty())
241 {
242 if (value.front() == L'\"' && value.back() == L'\"')
243 value = value.substr(1, value.size() - 2);
244 UnEscapeString(value);
245 map[key] = value;
246 }
247 }
248 }
249
Save()250 bool CIniHelper::Save()
251 {
252 if (m_file_path.empty())
253 return false;
254 ofstream file_stream{ m_file_path };
255 if (file_stream.fail())
256 return false;
257 string ini_str{ CCommon::UnicodeToStr(m_ini_str, m_save_as_utf8 ? CodeType::UTF8 : CodeType::ANSI) };
258 file_stream << ini_str;
259 return true;
260 }
261
UnEscapeString(wstring & str)262 void CIniHelper::UnEscapeString(wstring& str)
263 {
264 if (str.find(L'\\') == wstring::npos) // 仅含有‘\’时需要处理转义字符
265 return;
266 bool escape{ false };
267 wstring result;
268 result.reserve(str.size());
269 for (const wchar_t ch : str)
270 {
271 if (escape)
272 {
273 switch (ch)
274 {
275 case L'n': result += L'\n'; break;
276 case L'r': result += L'\r'; break;
277 case L't': result += L'\t'; break;
278 case L'"': result += L'"'; break;
279 case L';': result += L';'; break;
280 case L'#': result += L'#'; break;
281 case L'\\': result += L'\\'; break;
282 default:result += '\\'; result += ch; break;
283 }
284 escape = false;
285 }
286 else if (ch == L'\\')
287 escape = true;
288 else
289 result += ch;
290 }
291 str.swap(result);
292 }
293
_WriteString(const wchar_t * AppName,const wchar_t * KeyName,const wstring & str)294 void CIniHelper::_WriteString(const wchar_t* AppName, const wchar_t* KeyName, const wstring& str)
295 {
296 wstring app_str{ L"[" };
297 app_str.append(AppName).append(L"]");
298 size_t app_pos{}, app_end_pos, key_pos;
299 app_pos = m_ini_str.find(app_str);
300 if (app_pos == wstring::npos) //找不到AppName,则在最后面添加
301 {
302 if (!m_ini_str.empty() && m_ini_str.back() != L'\n')
303 m_ini_str += L"\n";
304 app_pos = m_ini_str.size();
305 m_ini_str += app_str;
306 m_ini_str += L"\n";
307 }
308 app_end_pos = m_ini_str.find(L"\n[", app_pos + 2);
309 if (app_end_pos != wstring::npos)
310 app_end_pos++;
311
312 key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L' ', app_pos); //查找“\nkey_name ”
313 if (key_pos >= app_end_pos) //如果找不到“\nkey_name ”,则查找“\nkey_name=”
314 key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L'=', app_pos);
315 if (key_pos >= app_end_pos) //找不到KeyName,则插入一个
316 {
317 //wchar_t buff[256];
318 //swprintf_s(buff, L"%s = %s\n", KeyName, str.c_str());
319 std::wstring str_temp = KeyName;
320 str_temp += L" = ";
321 str_temp += str;
322 str_temp += L"\n";
323 if (app_end_pos == wstring::npos)
324 m_ini_str += str_temp;
325 else
326 m_ini_str.insert(app_end_pos, str_temp);
327 }
328 else //找到了KeyName,将等号到换行符之间的文本替换
329 {
330 size_t str_pos;
331 str_pos = m_ini_str.find(L'=', key_pos + 2);
332 size_t line_end_pos = m_ini_str.find(L'\n', key_pos + 2);
333 if (str_pos > line_end_pos) //所在行没有等号,则插入一个等号
334 {
335 m_ini_str.insert(key_pos + wcslen(KeyName) + 1, L" =");
336 str_pos = key_pos + wcslen(KeyName) + 2;
337 }
338 else
339 {
340 str_pos++;
341 }
342 size_t str_end_pos;
343 str_end_pos = m_ini_str.find(L"\n", str_pos);
344 m_ini_str.replace(str_pos, str_end_pos - str_pos, L" " + str);
345 }
346 }
347
_GetString(const wchar_t * AppName,const wchar_t * KeyName,const wchar_t * default_str) const348 wstring CIniHelper::_GetString(const wchar_t* AppName, const wchar_t* KeyName, const wchar_t* default_str) const
349 {
350 wstring app_str{ L"[" };
351 app_str.append(AppName).append(L"]");
352 size_t app_pos{}, app_end_pos, key_pos;
353 app_pos = m_ini_str.find(app_str);
354 if (app_pos == wstring::npos) //找不到AppName,返回默认字符串
355 return default_str;
356
357 app_end_pos = m_ini_str.find(L"\n[", app_pos + 2);
358 if (app_end_pos != wstring::npos)
359 app_end_pos++;
360
361 key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L' ', app_pos); //查找“\nkey_name ”
362 if (key_pos >= app_end_pos) //如果找不到“\nkey_name ”,则查找“\nkey_name=”
363 key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L'=', app_pos);
364 if (key_pos >= app_end_pos) //找不到KeyName,返回默认字符串
365 {
366 return default_str;
367 }
368 else //找到了KeyName,获取等号到换行符之间的文本
369 {
370 size_t str_pos;
371 str_pos = m_ini_str.find(L'=', key_pos + 2);
372 size_t line_end_pos = m_ini_str.find(L'\n', key_pos + 2);
373 if (str_pos > line_end_pos) //所在行没有等号,返回默认字符串
374 {
375 return default_str;
376 }
377 else
378 {
379 str_pos++;
380 }
381 size_t str_end_pos;
382 str_end_pos = m_ini_str.find(L"\n", str_pos);
383 //获取文本
384 wstring return_str{ m_ini_str.substr(str_pos, str_end_pos - str_pos) };
385 //如果前后有空格,则将其删除
386 CCommon::StringNormalize(return_str);
387 return return_str;
388 }
389 }
390