2 * @file IniOptionsMgr.cpp
4 * @brief Implementation of Ini file Options management class.
9 #include "IniOptionsMgr.h"
10 #include "OptionsMgr.h"
17 using std::filesystem::current_path;
19 LPCWSTR CIniOptionsMgr::lpFilePath = NULL;
21 LPCWSTR lpAppName = TEXT("WinMerge");
22 LPCWSTR lpFileName = TEXT("\\winmerge.ini");
24 CIniOptionsMgr::CIniOptionsMgr()
27 InitializeCriticalSection(&m_cs);
30 CIniOptionsMgr::~CIniOptionsMgr()
32 DeleteCriticalSection(&m_cs);
33 delete[] CIniOptionsMgr::lpFilePath;
37 * @brief Checks wheter INI file exists.
38 * @return TRUE if INI file exist,
41 bool CIniOptionsMgr::CheckIfIniFileExist()
43 std::ifstream f(GetFilePath());
48 * @brief Get path to INI file.
49 * @return path to INI file
51 LPCWSTR CIniOptionsMgr::GetFilePath()
53 if (CIniOptionsMgr::lpFilePath == NULL)
56 std::filesystem::path p = current_path();
60 std::wstring str = p.wstring();
61 size_t length = str.length() + 1;
62 wchar_t* strCp = new wchar_t[length];
63 wcscpy_s(strCp, length, str.c_str());
66 CIniOptionsMgr::lpFilePath = strCp;
69 return CIniOptionsMgr::lpFilePath;
72 int CIniOptionsMgr::InitOption(const String& name, const varprop::VariantValue& defaultValue)
74 // Check type & bail if null
75 int valType = defaultValue.GetType();
76 if (valType == varprop::VT_NULL)
77 return COption::OPT_ERR;
79 // If we're not loading & saving options, bail
81 return AddOption(name, defaultValue);
83 EnterCriticalSection(&m_cs);
85 // check if value exist
86 String textValue = ReadValueFromFile(name);
87 bool found = textValue.size() != 0;
89 // Actually save value into our in-memory options table
90 int retVal = AddOption(name, defaultValue);
92 // Update registry if successfully saved to in-memory table
93 if (retVal == COption::OPT_OK)
97 varprop::VariantValue value(defaultValue);
98 retVal = ParseValue(name, textValue, value);
99 if (retVal == COption::OPT_OK)
101 retVal = Set(name, value);
106 LeaveCriticalSection(&m_cs);
110 int CIniOptionsMgr::InitOption(const String& name, const String& defaultValue)
112 varprop::VariantValue defValue;
113 defValue.SetString(defaultValue);
114 return InitOption(name, defValue);
117 int CIniOptionsMgr::InitOption(const String& name, const TCHAR* defaultValue)
119 return InitOption(name, String(defaultValue));
122 int CIniOptionsMgr::InitOption(const String& name, int defaultValue, bool serializable)
124 varprop::VariantValue defValue;
125 int retVal = COption::OPT_OK;
127 defValue.SetInt(defaultValue);
129 retVal = InitOption(name, defValue);
131 AddOption(name, defValue);
135 int CIniOptionsMgr::InitOption(const String& name, bool defaultValue)
137 varprop::VariantValue defValue;
138 defValue.SetBool(defaultValue);
139 return InitOption(name, defValue);
142 int CIniOptionsMgr::SaveOption(const String& name)
144 if (!m_serializing) return COption::OPT_OK;
146 varprop::VariantValue value;
147 int retVal = COption::OPT_OK;
150 int valType = value.GetType();
151 if (valType == varprop::VT_NULL)
152 retVal = COption::OPT_NOTFOUND;
154 if (retVal == COption::OPT_OK)
156 if (valType == varprop::VT_STRING)
158 String strVal = value.GetString();
159 LPCWSTR text = strVal.c_str();
160 WritePrivateProfileString(lpAppName, name.c_str(), text, GetFilePath());
162 else if (valType == varprop::VT_INT)
164 DWORD dwordVal = value.GetInt();
165 String strVal = strutils::to_str(dwordVal);
166 LPCWSTR text = strVal.c_str();
167 WritePrivateProfileString(lpAppName, name.c_str(), text, GetFilePath());
169 else if (valType == varprop::VT_BOOL)
171 DWORD dwordVal = value.GetBool() ? 1 : 0;
172 String strVal = strutils::to_str(dwordVal);
173 LPCWSTR text = strVal.c_str();
174 WritePrivateProfileString(lpAppName, name.c_str(), text, GetFilePath());
178 retVal = COption::OPT_UNKNOWN_TYPE;
185 * @brief Set new value for option and save option to file
187 int CIniOptionsMgr::SaveOption(const String& name, const varprop::VariantValue& value)
189 int retVal = Set(name, value);
190 if (retVal == COption::OPT_OK)
191 retVal = SaveOption(name);
196 * @brief Set new string value for option and save option to file
198 int CIniOptionsMgr::SaveOption(const String& name, const String& value)
200 varprop::VariantValue val;
201 val.SetString(value);
202 int retVal = Set(name, val);
203 if (retVal == COption::OPT_OK)
204 retVal = SaveOption(name);
209 * @brief Set new string value for option and save option to file
211 int CIniOptionsMgr::SaveOption(const String& name, const TCHAR* value)
213 return SaveOption(name, String(value));
216 int CIniOptionsMgr::SaveOption(const String& name, int value)
218 varprop::VariantValue val;
220 int retVal = Set(name, val);
221 if (retVal == COption::OPT_OK)
222 retVal = SaveOption(name);
226 int CIniOptionsMgr::SaveOption(const String& name, bool value)
228 varprop::VariantValue val;
230 int retVal = Set(name, val);
231 if (retVal == COption::OPT_OK)
232 retVal = SaveOption(name);
236 int CIniOptionsMgr::RemoveOption(const String& name)
238 int retVal = COption::OPT_OK;
243 SplitName(name, strPath, strValueName);
245 if (!strValueName.empty())
247 retVal = COptionsMgr::RemoveOption(name);
251 for (auto it = m_optionsMap.begin(); it != m_optionsMap.end(); )
253 if (it->first.find(strPath) == 0)
254 it = m_optionsMap.erase(it);
258 retVal = COption::OPT_OK;
261 EnterCriticalSection(&m_cs);
263 WritePrivateProfileString(lpAppName, name.c_str(), NULL, GetFilePath());
265 LeaveCriticalSection(&m_cs);
270 String CIniOptionsMgr::ReadValueFromFile(const String& name)
272 if (m_iniFileKeyValues.empty())
274 std::vector<TCHAR> str(32768);
275 if (GetPrivateProfileSection(lpAppName, str.data(), static_cast<DWORD>(str.size()), GetFilePath()) > 0)
277 TCHAR* p = str.data();
280 TCHAR* v = _tcschr(p, '=');
284 size_t vlen = _tcslen(v);
285 m_iniFileKeyValues.insert_or_assign(String{ p, v - 1 }, String{v, v + vlen});
290 return m_iniFileKeyValues[name];
293 int CIniOptionsMgr::ParseValue(const String& strName, String& textValue, varprop::VariantValue& value)
295 int valType = value.GetType();
296 int retVal = COption::OPT_OK;
298 if (valType == varprop::VT_STRING)
300 value.SetString(textValue);
301 retVal = Set(strName, value);
303 else if (valType == varprop::VT_INT)
305 value.SetInt(std::stoul(textValue));
306 retVal = Set(strName, value);
308 else if (valType == varprop::VT_BOOL)
310 value.SetBool(textValue[0] == '1' ? true : false);
311 retVal = Set(strName, value);
314 retVal = COption::OPT_WRONG_TYPE;
320 * @brief Split option name to path (in registry) and
321 * valuename (in registry).
323 * Option names are given as "full path", e.g. "Settings/AutomaticRescan".
324 * This function splits that to path "Settings/" and valuename
326 * @param [in] strName Option name
327 * @param [out] srPath Path (key) in registry
328 * @param [out] strValue Value in registry
330 void CIniOptionsMgr::SplitName(const String& strName, String& strPath,
331 String& strValue) const
333 size_t pos = strName.rfind('/');
334 if (pos != String::npos)
336 size_t len = strName.length();
337 strValue = strName.substr(pos + 1, len - pos - 1); //Right(len - pos - 1);
338 strPath = strName.substr(0, pos); //Left(pos);