xref: /MusicPlayer2/MusicPlayer2/IniHelper.cpp (revision 4b9b29893b3bb42cad0f3ee69501a6a01e2c802f)
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