in Configurator/Core/Ini/IniTemplate.cs [675:822]
public void UpgradeIniFile(bool skipExistingValues = false)
{
// Load the existing ini file into memory.
IniFile oldIniFile = new IniFile(ConfigurationFile);
// Replace the existing ini file with a fresh one created from the template.
ProcessTemplate(true);
// Load the refreshed file created from the template into memory.
IniFile iniTemplateFile = new IniFile(ConfigurationFile);
// Now, to produce a merged new ini file that contains everything we need, first we need to add new sections if any.
var newIniFileSections = iniTemplateFile.Lines.FindAll(s => s.IniLineType == IniLineType.Section && !oldIniFile.SectionExists(s.Section));
foreach (var newSection in newIniFileSections)
{
if (oldIniFile.SectionExists(newSection.Section))
{
continue;
}
oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.EmptyLine, false, oldIniFile.GetLastSection()));
oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.Section, false, newSection.Section));
}
// We need to remove any deprecated Server variables, otherwise they will create conflicts with the new Server version.
var deprecatedVariablesInSeries = DeprecatedVariablesForVersion;
if (deprecatedVariablesInSeries != null)
{
var deprecatedLines = oldIniFile.Lines.FindAll(oldLine => deprecatedVariablesInSeries.Any(dv => dv.Name.Equals(oldLine.Key, StringComparison.OrdinalIgnoreCase)));
foreach (var deprecatedLine in deprecatedLines)
{
// First we remove any comments related to the deprecated lines
// and we keep inserting these comments on top of the key until we're done working with them.
int previousLineIndex = oldIniFile.Lines.IndexOf(deprecatedLine) - 1;
while (previousLineIndex >= 0
&& oldIniFile.Lines[previousLineIndex].IniLineType != IniLineType.EmptyLine
&& oldIniFile.Lines[previousLineIndex].IsCommented)
{
oldIniFile.Lines.RemoveAt(previousLineIndex);
previousLineIndex--;
}
// Now we remove the deprecated line itself.
oldIniFile.Lines.Remove(deprecatedLine);
}
}
// Then we need to replace the old values for keys from the old ini file for the recalculated ones from the refreshed file.
var recalculatedLines = iniTemplateFile.Lines.FindAll(newline =>
newline.IniLineType == IniLineType.KeyValuePair
| newline.IniLineType == IniLineType.Flag);
foreach (var recalculatedLine in recalculatedLines)
{
// Find the index of correspondent variable from the refreshed file to old ini file.
var index = oldIniFile.Lines.FindLastIndex(oldLine => oldLine.Key == recalculatedLine.Key && oldLine.Section == recalculatedLine.Section);
if (index >= 0)
{
// Skip replacement of existing variables if flag is set to true.
if (skipExistingValues)
{
continue;
}
// If found, replace the old value of the key with the recalculated one.
oldIniFile.Lines[index].Value = recalculatedLine.Value;
oldIniFile.Lines[index].IsCommented = recalculatedLine.IsCommented;
}
else
{
// If the key is new, we add it to the correspondent section on the old ini file.
int indexForInsertOnOldFile = oldIniFile.GetLastIndexForSection(recalculatedLine.Section);
bool collectionLimitReached = indexForInsertOnOldFile >= oldIniFile.Lines.Count;
// We add a new line at the bottom of the section on the old file.
if (collectionLimitReached)
{
//If it is found at the end of the file we need to use Add() instead of Insert() to avoid an out of bounds exception.
oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.EmptyLine, false, oldIniFile.GetLastSection()));
oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.KeyValuePair, recalculatedLine.IsCommented, oldIniFile.GetLastSection(), recalculatedLine.Key, recalculatedLine.Value));
}
else
{
oldIniFile.Lines.Insert(indexForInsertOnOldFile++, new IniLineFullDetail(IniLineType.EmptyLine, false, oldIniFile.GetLastSection()));
oldIniFile.Lines.Insert(indexForInsertOnOldFile, new IniLineFullDetail(IniLineType.KeyValuePair, recalculatedLine.IsCommented, oldIniFile.GetLastSection(), recalculatedLine.Key, recalculatedLine.Value));
}
// Then we need to gather all previous comments in top of the key value pair and insert them after that empty space.
int recalculatedLinePreviousIndex = iniTemplateFile.Lines.IndexOf(recalculatedLine) - 1;
// And we keep inserting these comments on top of the key until we're done working with them.
while (iniTemplateFile.Lines[recalculatedLinePreviousIndex].IniLineType != IniLineType.EmptyLine
&& iniTemplateFile.Lines[recalculatedLinePreviousIndex].IsCommented)
{
oldIniFile.Lines.Insert(collectionLimitReached ? oldIniFile.Lines.Count - 1 : indexForInsertOnOldFile, iniTemplateFile.Lines[recalculatedLinePreviousIndex]);
recalculatedLinePreviousIndex--;
// We need to break the while circle if we had reached the top of the template file.
if (recalculatedLinePreviousIndex < 0) break;
}
}
}
// Here we just write the merged line by line result into the ini file.
var writer = new StreamWriter(ConfigurationFile);
IniLineFullDetail previousLine = null;
foreach (var line in oldIniFile.Lines)
{
if (previousLine != null
&& previousLine.IniLineType == IniLineType.EmptyLine
&& line.IniLineType == IniLineType.EmptyLine)
{
continue;
}
var sb = new StringBuilder();
if (line.IsCommented)
{
sb.Append("# ");
}
switch (line.IniLineType)
{
case IniLineType.Comment:
sb.Append(line.Key);
break;
case IniLineType.Section:
sb.Append("[" + line.Section + "]");
break;
case IniLineType.KeyValuePair:
sb.Append(line.Key + "=" + line.Value);
break;
case IniLineType.Flag:
sb.Append(line.Key);
break;
}
writer.WriteLine(sb.ToString());
previousLine = line;
}
writer.Close();
writer.Dispose();
}