OSDN Git Service

crystaledit: Use GetProfile*()/WriteProfile*() to read and write the registry wheneve...
[winmerge-jp/winmerge-jp.git] / Src / Common / CIniOptionsMgr.cpp
1 /**
2  * @file CIniOptionsMgr.cpp
3  *
4  * @brief Implementation of Ini file Options management class.
5  *
6  */
7
8 #include "pch.h"
9 #include "CIniOptionsMgr.h"
10 #include "OptionsMgr.h"
11 #include <Windows.h>
12 #include <codecvt>
13 #include <filesystem>
14 #include <string>
15 #include <fstream>
16
17 using std::filesystem::current_path;
18
19 LPCWSTR CIniOptionsMgr::lpFilePath = NULL;
20
21 LPCWSTR lpAppName = TEXT("WinMerge");
22 LPCWSTR lpFileName = TEXT("\\winmerge.ini");
23
24 CIniOptionsMgr::CIniOptionsMgr()
25 {
26         InitializeCriticalSection(&m_cs);
27 }
28
29 CIniOptionsMgr::~CIniOptionsMgr()
30 {
31         DeleteCriticalSection(&m_cs);
32         delete[] CIniOptionsMgr::lpFilePath;
33 }
34
35 /**
36  * @brief Checks wheter INI file exists.
37  * @return TRUE if INI file exist,
38  *   FALSE otherwise.
39  */
40 bool CIniOptionsMgr::CheckIfIniFileExist()
41 {
42         std::ifstream f(GetFilePath());
43         return f.good();
44 }
45
46 /**
47  * @brief Get path to INI file.
48  * @return path to INI file
49  */
50 LPCWSTR CIniOptionsMgr::GetFilePath()
51 {
52         if (CIniOptionsMgr::lpFilePath == NULL)
53         {
54                 // create path
55                 std::filesystem::path p = current_path();
56                 p += lpFileName;
57
58                 // change type
59                 std::wstring str = p.wstring();
60                 size_t length = str.length() + 1;
61                 wchar_t* strCp = new wchar_t[length];
62                 wcscpy_s(strCp, length, str.c_str());
63
64                 // set path
65                 CIniOptionsMgr::lpFilePath = strCp;
66         }
67
68         return CIniOptionsMgr::lpFilePath;
69 }
70
71 int CIniOptionsMgr::InitOption(const String& name, const varprop::VariantValue& defaultValue)
72 {
73         // Check type & bail if null
74         int valType = defaultValue.GetType();
75         if (valType == varprop::VT_NULL)
76                 return COption::OPT_ERR;
77
78         // If we're not loading & saving options, bail
79         if (!m_serializing)
80                 return AddOption(name, defaultValue);
81
82         EnterCriticalSection(&m_cs);
83
84         // check if value exist
85         String textValue = ReadValueFromFile(name);
86         bool found = textValue.size() != 0;
87
88         // Actually save value into our in-memory options table
89         int retVal = AddOption(name, defaultValue);
90
91         // Update registry if successfully saved to in-memory table
92         if (retVal == COption::OPT_OK)
93         {
94                 if (found)
95                 {
96                         varprop::VariantValue value(defaultValue);
97                         retVal = ParseValue(name, textValue, value);
98                         if (retVal == COption::OPT_OK)
99                         {
100                                 retVal = Set(name, value);
101                         }
102                 }
103         }
104
105         LeaveCriticalSection(&m_cs);
106         return retVal;
107 }
108
109 int CIniOptionsMgr::InitOption(const String& name, const String& defaultValue)
110 {
111         varprop::VariantValue defValue;
112         defValue.SetString(defaultValue);
113         return InitOption(name, defValue);
114 }
115
116 int CIniOptionsMgr::InitOption(const String& name, const TCHAR* defaultValue)
117 {
118         return InitOption(name, String(defaultValue));
119 }
120
121 int CIniOptionsMgr::InitOption(const String& name, int defaultValue, bool serializable)
122 {
123         varprop::VariantValue defValue;
124         int retVal = COption::OPT_OK;
125
126         defValue.SetInt(defaultValue);
127         if (serializable)
128                 retVal = InitOption(name, defValue);
129         else
130                 AddOption(name, defValue);
131         return retVal;
132 }
133
134 int CIniOptionsMgr::InitOption(const String& name, bool defaultValue)
135 {
136         varprop::VariantValue defValue;
137         defValue.SetBool(defaultValue);
138         return InitOption(name, defValue);
139 }
140
141 int CIniOptionsMgr::SaveOption(const String& name)
142 {
143         if (!m_serializing) return COption::OPT_OK;
144
145         varprop::VariantValue value;
146         int retVal = COption::OPT_OK;
147
148         value = Get(name);
149         int valType = value.GetType();
150         if (valType == varprop::VT_NULL)
151                 retVal = COption::OPT_NOTFOUND;
152
153         if (retVal == COption::OPT_OK)
154         {
155                 if (valType == varprop::VT_STRING)
156                 {
157                         String strVal = value.GetString();
158                         LPCWSTR text = strVal.c_str();
159                         WritePrivateProfileString(lpAppName, name.c_str(), text, GetFilePath());
160                 }
161                 else if (valType == varprop::VT_INT)
162                 {
163                         DWORD dwordVal = value.GetInt();
164                         String strVal = strutils::to_str(dwordVal);
165                         LPCWSTR text = strVal.c_str();
166                         WritePrivateProfileString(lpAppName, name.c_str(), text, GetFilePath());
167                 }
168                 else if (valType == varprop::VT_BOOL)
169                 {
170                         DWORD dwordVal = value.GetBool() ? 1 : 0;
171                         String strVal = strutils::to_str(dwordVal);
172                         LPCWSTR text = strVal.c_str();
173                         WritePrivateProfileString(lpAppName, name.c_str(), text, GetFilePath());
174                 }
175                 else
176                 {
177                         retVal = COption::OPT_UNKNOWN_TYPE;
178                 }
179         }
180         return retVal;
181 }
182
183 /**
184  * @brief Set new value for option and save option to file
185  */
186 int CIniOptionsMgr::SaveOption(const String& name, const varprop::VariantValue& value)
187 {
188         int retVal = Set(name, value);
189         if (retVal == COption::OPT_OK)
190                 retVal = SaveOption(name);
191         return retVal;
192 }
193
194 /**
195  * @brief Set new string value for option and save option to file
196  */
197 int CIniOptionsMgr::SaveOption(const String& name, const String& value)
198 {
199         varprop::VariantValue val;
200         val.SetString(value);
201         int retVal = Set(name, val);
202         if (retVal == COption::OPT_OK)
203                 retVal = SaveOption(name);
204         return retVal;
205 }
206
207 /**
208  * @brief Set new string value for option and save option to file
209  */
210 int CIniOptionsMgr::SaveOption(const String& name, const TCHAR* value)
211 {
212         return SaveOption(name, String(value));
213 }
214
215 int CIniOptionsMgr::SaveOption(const String& name, int value)
216 {
217         varprop::VariantValue val;
218         val.SetInt(value);
219         int retVal = Set(name, val);
220         if (retVal == COption::OPT_OK)
221                 retVal = SaveOption(name);
222         return retVal;
223 }
224
225 int CIniOptionsMgr::SaveOption(const String& name, bool value)
226 {
227         varprop::VariantValue val;
228         val.SetBool(value);
229         int retVal = Set(name, val);
230         if (retVal == COption::OPT_OK)
231                 retVal = SaveOption(name);
232         return retVal;
233 }
234
235 int CIniOptionsMgr::RemoveOption(const String& name)
236 {
237         int retVal = COption::OPT_OK;
238
239         String strPath;
240         String strValueName;
241
242         SplitName(name, strPath, strValueName);
243
244         if (!strValueName.empty())
245         {
246                 retVal = COptionsMgr::RemoveOption(name);
247         }
248         else
249         {
250                 for (auto it = m_optionsMap.begin(); it != m_optionsMap.end(); )
251                 {
252                         if (it->first.find(strPath) == 0)
253                                 it = m_optionsMap.erase(it);
254                         else
255                                 ++it;
256                 }
257                 retVal = COption::OPT_OK;
258         }
259
260         EnterCriticalSection(&m_cs);
261
262         WritePrivateProfileString(lpAppName, name.c_str(), NULL, GetFilePath());
263
264         LeaveCriticalSection(&m_cs);
265
266         return retVal;
267 }
268
269 int CIniOptionsMgr::ExportOptions(const String& filename, const bool bHexColor) const
270 {
271         if (std::filesystem::copy_file(CIniOptionsMgr::GetFilePath(), filename))
272         {
273                 return COption::OPT_OK;
274         }
275         else
276         {
277                 return COption::OPT_ERR;
278         }
279 }
280
281 int CIniOptionsMgr::ImportOptions(const String& filename)
282 {
283         if (std::filesystem::copy_file(filename, CIniOptionsMgr::GetFilePath()))
284         {
285                 return COption::OPT_OK;
286         }
287         else
288         {
289                 return COption::OPT_ERR;
290         }
291 }
292
293 String CIniOptionsMgr::ReadValueFromFile(const String& name)
294 {
295         const int size = 100;
296         LPWSTR buffor = new TCHAR[size];
297         DWORD result = GetPrivateProfileString(lpAppName, name.c_str(), NULL, buffor, size, GetFilePath());
298         return buffor;
299 }
300
301 int CIniOptionsMgr::ParseValue(const String& strName, String& textValue, varprop::VariantValue& value)
302 {
303         int valType = value.GetType();
304         int retVal = COption::OPT_OK;
305
306         if (valType == varprop::VT_STRING)
307         {
308                 value.SetString(textValue);
309                 retVal = Set(strName, value);
310         }
311         else if (valType == varprop::VT_INT)
312         {
313                 value.SetInt(std::stoi(textValue));
314                 retVal = Set(strName, value);
315         }
316         else if (valType == varprop::VT_BOOL)
317         {
318                 value.SetBool(textValue[0] == '1' ? true : false);
319                 retVal = Set(strName, value);
320         }
321         else
322                 retVal = COption::OPT_WRONG_TYPE;
323
324         return retVal;
325 }
326
327 /**
328  * @brief Split option name to path (in registry) and
329  * valuename (in registry).
330  *
331  * Option names are given as "full path", e.g. "Settings/AutomaticRescan".
332  * This function splits that to path "Settings/" and valuename
333  * "AutomaticRescan".
334  * @param [in] strName Option name
335  * @param [out] srPath Path (key) in registry
336  * @param [out] strValue Value in registry
337  */
338 void CIniOptionsMgr::SplitName(const String& strName, String& strPath,
339         String& strValue) const
340 {
341         size_t pos = strName.rfind('/');
342         if (pos != String::npos)
343         {
344                 size_t len = strName.length();
345                 strValue = strName.substr(pos + 1, len - pos - 1); //Right(len - pos - 1);
346                 strPath = strName.substr(0, pos);  //Left(pos);
347         }
348         else
349         {
350                 strValue = strName;
351                 strPath.erase();
352         }
353 }