Skip to content

Commit

Permalink
Fix issue #1925: Export/Import settings bug with Substitution Filters
Browse files Browse the repository at this point in the history
  • Loading branch information
sdottaka committed Jul 7, 2023
1 parent ca31edb commit e1dc4ed
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 13 deletions.
8 changes: 8 additions & 0 deletions Src/Common/IniOptionsMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ int CIniOptionsMgr::SaveValueToFile(const String& name, const varprop::VariantVa
{
String strVal = EscapeValue(value.GetString());
LPCWSTR text = strVal.c_str();
// https://learn.microsoft.com/en-us/answers/questions/578134/error-in-writeprivateprofilestring-function-when-j
WritePrivateProfileString(lpAppName, name.c_str(), nullptr, GetFilePath());
retValReg = WritePrivateProfileString(lpAppName, name.c_str(), text, GetFilePath());
}
else if (valType == varprop::VT_INT)
Expand Down Expand Up @@ -346,6 +348,9 @@ int CIniOptionsMgr::ExportOptions(const String& filename, const bool bHexColor /
{
if (m_optionsMap.find(key) == m_optionsMap.end())
{
// https://learn.microsoft.com/en-us/answers/questions/578134/error-in-writeprivateprofilestring-function-when-j
WritePrivateProfileString(_T("WinMerge"), key.c_str(),
nullptr, filename.c_str());
WritePrivateProfileString(_T("WinMerge"), key.c_str(),
EscapeValue(value).c_str(), filename.c_str());
}
Expand All @@ -362,6 +367,9 @@ int CIniOptionsMgr::ImportOptions(const String& filename)
if (m_optionsMap.find(key) == m_optionsMap.end())
{
m_iniFileKeyValues.insert_or_assign(key, value);
// https://learn.microsoft.com/en-us/answers/questions/578134/error-in-writeprivateprofilestring-function-when-j
WritePrivateProfileString(_T("WinMerge"), key.c_str(),
nullptr, GetFilePath());
WritePrivateProfileString(_T("WinMerge"), key.c_str(),
EscapeValue(value).c_str(), GetFilePath());
}
Expand Down
51 changes: 38 additions & 13 deletions Src/Common/OptionsMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "pch.h"
#include "OptionsMgr.h"
#include "UniFile.h"
#include <algorithm>
#include <cassert>
#include <Windows.h>
Expand Down Expand Up @@ -684,7 +685,12 @@ int COptionsMgr::ExportOptions(const String& filename, const bool bHexColor /*=
strVal = EscapeValue(value.GetString());
}

// https://learn.microsoft.com/en-us/answers/questions/578134/error-in-writeprivateprofilestring-function-when-j
bool bRet = !!WritePrivateProfileString(_T("WinMerge"), name.c_str(),
nullptr, filename.c_str());
if (!bRet)
retVal = COption::OPT_ERR;
bRet = !!WritePrivateProfileString(_T("WinMerge"), name.c_str(),
strVal.c_str(), filename.c_str());
if (!bRet)
retVal = COption::OPT_ERR;
Expand Down Expand Up @@ -816,23 +822,42 @@ std::pair<String, String> COptionsMgr::SplitName(const String& strName)
std::map<String, String> COptionsMgr::ReadIniFile(const String& filename, const String& section)
{
std::map<String, String> iniFileKeyValues;
std::vector<tchar_t> str(65536);
if (GetPrivateProfileSection(section.c_str(), str.data(), static_cast<DWORD>(str.size()), filename.c_str()) > 0)
UniMemFile file;
if (!file.OpenReadOnly(filename))
return {};
file.ReadBom();
String line, eol;
bool lossy = false;
bool inTargetSection = false;
while (file.ReadString(line, eol, &lossy))
{
const tchar_t* p = str.data();
while (*p)
auto itBegin = std::find_if(line.begin(), line.end(), [](int ch) {
return !std::isspace(ch); });

// Skip empty lines or lines starting with a comment
if (itBegin == line.end() || *itBegin == ';')
continue;

if (*itBegin == '[' && line.back() == ']')
{
const tchar_t* v = tc::tcschr(p, '=');
if (!v)
break;
++v;
size_t vlen = tc::tcslen(v);
String value{ v, v + vlen };
String key{ p, v - 1 };
iniFileKeyValues.insert_or_assign(key, UnescapeValue(value));
p = v + vlen + 1;
// section
String currentSection = line.substr(itBegin - line.begin() + 1, line.end() - itBegin - 2);
inTargetSection = (currentSection == section);
continue;
}

if (!inTargetSection)
continue;

std::size_t equalsPos = line.find('=');
if (equalsPos == String::npos)
continue;

iniFileKeyValues.insert_or_assign(
/* key */line.substr(itBegin - line.begin(), equalsPos - (itBegin - line.begin())),
/* value */ UnescapeValue(line.substr(equalsPos + 1)));
}
file.Close();
return iniFileKeyValues;
}

3 changes: 3 additions & 0 deletions Src/Common/RegOptionsMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,9 @@ int CRegOptionsMgr::ExportAllUnloadedValues(HKEY hKey, const String& strPath, co
_T("int"), filename.c_str());
break;
case REG_SZ:
// https://learn.microsoft.com/en-us/answers/questions/578134/error-in-writeprivateprofilestring-function-when-j
WritePrivateProfileString(_T("WinMerge"), strName.c_str(),
nullptr, filename.c_str());
WritePrivateProfileString(_T("WinMerge"), strName.c_str(),
EscapeValue(reinterpret_cast<tchar_t*>(data.data())).c_str(), filename.c_str());
WritePrivateProfileString(_T("WinMerge.TypeInfo"), strName.c_str(),
Expand Down
19 changes: 19 additions & 0 deletions Testing/GoogleTest/OptionsMgr/RegOptionsMgr_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#include <vector>
#include "UnicodeString.h"
#include "RegOptionsMgr.h"
#include "Environment.h"
#include "paths.h"
#include "TFile.h"

using std::vector;

Expand Down Expand Up @@ -74,4 +77,20 @@ namespace
EXPECT_EQ(COption::OPT_OK, mgr.InitOption(_T("BoolOpt2"), true));
EXPECT_EQ(true, mgr.GetBool(_T("BoolOpt2")));
}

TEST_F(RegOptionsMgrTest, ExportAndImport)
{
CRegOptionsMgr mgr;
mgr.SetRegRootKey(_T("Thingamahoochie\\WinMerge\\UnitTesting"));
EXPECT_EQ(COption::OPT_OK, mgr.InitOption(_T("StringOpt1"), _T("")));
EXPECT_EQ(COption::OPT_OK, mgr.SaveOption(_T("StringOpt1"), _T(" abc\r\ndef\tghi ")));
EXPECT_EQ(_T(" abc\r\ndef\tghi "), mgr.GetString(_T("StringOpt1")));
String inifile = paths::ConcatPath(env::GetTemporaryPath(), _T("wm_tmp.ini"));
mgr.ExportOptions(inifile);
EXPECT_EQ(COption::OPT_OK, mgr.SaveOption(_T("StringOpt1"), _T("")));
EXPECT_EQ(_T(""), mgr.GetString(_T("StringOpt1")));
mgr.ImportOptions(inifile);
EXPECT_EQ(_T(" abc\r\ndef\tghi "), mgr.GetString(_T("StringOpt1")));
TFile(inifile).remove();
}
}

0 comments on commit e1dc4ed

Please sign in to comment.