source code checkin

This commit is contained in:
Brett Hewitson 2021-01-07 16:23:23 +10:00
parent 5f8fb2c825
commit 7e57b72e35
675 changed files with 168433 additions and 0 deletions

View file

@ -0,0 +1,461 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Enums;
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ServerManagerTool.Common.Serialization
{
public abstract class BaseSystemIniFile
{
protected BaseSystemIniFile(string iniPath)
{
this.BasePath = iniPath;
}
public string BasePath
{
get;
private set;
}
public abstract Dictionary<Enum, string> FileNames
{
get;
}
public abstract Dictionary<Enum, string> SectionNames
{
get;
}
public void Deserialize(object obj, Enum[] exclusions)
{
var iniFiles = new Dictionary<string, IniFile>();
var fields = obj.GetType().GetProperties().Where(f => f.IsDefined(typeof(BaseIniFileEntryAttribute), false));
if (exclusions == null)
exclusions = new Enum[0];
foreach (var field in fields)
{
var attributes = field.GetCustomAttributes(typeof(BaseIniFileEntryAttribute), false);
foreach (var attr in attributes.OfType<BaseIniFileEntryAttribute>())
{
if (exclusions.Contains(attr.Category))
continue;
try
{
if (attr.IsCustom)
{
// this code is to handle custom sections
var collection = field.GetValue(obj) as IIniSectionCollection;
if (collection != null)
{
ReadFile(iniFiles, attr.File);
var sectionNames = ReadCustomSectionNames(iniFiles, attr.File);
foreach (var sectionName in sectionNames)
{
var sectionValues = ReadSection(iniFiles, attr.File, sectionName);
collection.Add(sectionName, sectionValues);
}
}
}
else
{
var keyName = string.IsNullOrWhiteSpace(attr.Key) ? field.Name : attr.Key;
if (attr.WriteBoolValueIfNonEmpty)
{
// Don't really need to do anything here, we don't care about this on reading it.
// extraBoolValue = Convert.ToBoolean(IniReadValue(SectionNames[attr.Section], attr.Key));
}
else
{
var iniValue = ReadValue(iniFiles, attr.File, attr.Section, keyName);
var fieldType = field.PropertyType;
var collection = field.GetValue(obj) as IIniValuesCollection;
if (collection != null)
{
var section = ReadSection(iniFiles, attr.File, attr.Section);
var filteredSection = collection.IsArray
? section.Where(s => s.StartsWith(collection.IniCollectionKey + "["))
: section.Where(s => s.StartsWith(collection.IniCollectionKey + "="));
collection.FromIniValues(filteredSection);
}
else if (fieldType == typeof(string))
{
var stringValue = iniValue;
if (attr.QuotedString == QuotedStringType.True)
{
// remove the leading and trailing quotes, if any
if (stringValue.StartsWith("\""))
stringValue = stringValue.Substring(1);
if (stringValue.EndsWith("\""))
stringValue = stringValue.Substring(0, stringValue.Length - 1);
}
else if (attr.QuotedString == QuotedStringType.Remove)
{
// remove the leading and trailing quotes, if any
if (stringValue.StartsWith("\""))
stringValue = stringValue.Substring(1);
if (stringValue.EndsWith("\""))
stringValue = stringValue.Substring(0, stringValue.Length - 1);
}
if (attr.Multiline)
{
stringValue = stringValue.Replace(attr.MultilineSeparator, Environment.NewLine);
}
field.SetValue(obj, stringValue);
}
else
{
if (string.IsNullOrWhiteSpace(iniValue))
{
// Skip non-string values which are not found
continue;
}
// Update the ConditionedOn flag, if this field has one.
if (!string.IsNullOrWhiteSpace(attr.ConditionedOn))
{
var conditionField = obj.GetType().GetProperty(attr.ConditionedOn);
conditionField.SetValue(obj, true);
}
var valueSet = StringUtils.SetPropertyValue(iniValue, obj, field, attr);
if (!valueSet)
throw new ArgumentException($"Unexpected field type {fieldType} for INI key {keyName} in section {attr.Section}.");
}
}
}
}
catch (Exception)
{
throw;
}
}
}
}
public void Serialize(object obj, Enum[] exclusions)
{
var iniFiles = new Dictionary<string, IniFile>();
var fields = obj.GetType().GetProperties().Where(f => f.IsDefined(typeof(BaseIniFileEntryAttribute), false));
if (exclusions == null)
exclusions = new Enum[0];
foreach (var field in fields)
{
var attributes = field.GetCustomAttributes(typeof(BaseIniFileEntryAttribute), false).OfType<BaseIniFileEntryAttribute>();
foreach (var attr in attributes)
{
if (exclusions.Contains(attr.Category))
continue;
try
{
if (attr.IsCustom)
{
// this code is to handle custom sections
var collection = field.GetValue(obj) as IIniSectionCollection;
if (collection != null)
{
collection.Update();
foreach (var section in collection.Sections)
{
// clear the entire section
WriteValue(iniFiles, attr.File, section.IniCollectionKey, null, null);
if (section.IsEnabled)
{
WriteSection(iniFiles, attr.File, section.IniCollectionKey, section.ToIniValues().ToArray());
}
}
}
}
else
{
var value = field.GetValue(obj);
var keyName = string.IsNullOrWhiteSpace(attr.Key) ? field.Name : attr.Key;
if (attr.ClearSection)
{
WriteValue(iniFiles, attr.File, attr.Section, null, null);
}
//
// If this is a collection, we need to first remove all of its values from the INI.
//
var collection = value as IIniValuesCollection;
if (collection != null)
{
var section = ReadSection(iniFiles, attr.File, attr.Section);
var filteredSection = section
.Where(s => !s.StartsWith(collection.IniCollectionKey + (collection.IsArray ? "[" : "=")))
.ToArray();
WriteSection(iniFiles, attr.File, attr.Section, filteredSection);
}
if (!string.IsNullOrEmpty(attr.ConditionedOn))
{
var conditionField = obj.GetType().GetProperty(attr.ConditionedOn);
var conditionValue = conditionField.GetValue(obj);
if (conditionValue is bool && (bool)conditionValue == false)
{
// The condition value was not set to true, so clear this attribute instead of writing it
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
continue;
}
}
if (!string.IsNullOrEmpty(attr.ClearWhenOff))
{
var updateOffField = obj.GetType().GetProperty(attr.ClearWhenOff);
var updateOffValue = updateOffField.GetValue(obj);
if (updateOffValue is bool && (bool)updateOffValue == false)
{
// The attributed value was set to false, so clear this attribute instead of writing it
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
}
continue;
}
if (attr.WriteBoolValueIfNonEmpty)
{
if (value == null)
{
var keyValue = string.Empty;
if (attr.WriteBooleanAsInteger)
keyValue = "0";
else
keyValue = "False";
WriteValue(iniFiles, attr.File, attr.Section, keyName, keyValue);
}
else
{
if (value is string)
{
var strValue = value as string;
var keyValue = string.Empty;
if (attr.WriteBooleanAsInteger)
keyValue = string.IsNullOrEmpty(strValue) ? "0" : "1";
else
keyValue = string.IsNullOrEmpty(strValue) ? "False" : "True";
WriteValue(iniFiles, attr.File, attr.Section, keyName, keyValue);
}
else
{
// Not supported
throw new NotSupportedException("Unexpected IniFileEntry value type.");
}
}
}
else
{
if (collection != null)
{
if (collection.IsEnabled)
{
// Remove all the values in the collection with this key name
var section = ReadSection(iniFiles, attr.File, attr.Section);
var filteredSection = collection.IsArray
? section.Where(s => !s.StartsWith(keyName + "["))
: section.Where(s => !s.StartsWith(keyName + "="));
var result = filteredSection;
var objValue = attr.WriteIfNotValue;
if (objValue != null && collection is IIniValuesList valueList)
{
result = result.Concat(valueList.ToIniValues(objValue));
}
else
{
result = result.Concat(collection.ToIniValues());
}
WriteSection(iniFiles, attr.File, attr.Section, result?.ToArray());
}
}
else
{
//
// If this is a NullableValue, we need to check if it has a value.
//
if (value is INullableValue nullableValue && !nullableValue.HasValue)
{
// The attributed value does not have a value, so clear this attribute instead of writing it.
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
continue;
}
var strValue = StringUtils.GetPropertyValue(value, field, attr);
var objValue = attr.WriteIfNotValue;
if (objValue != null)
{
var strValue2 = StringUtils.GetPropertyValue(objValue, field, attr);
if (string.Equals(strValue, strValue2, StringComparison.OrdinalIgnoreCase))
{
// The attributed value is the same as the specified value, so clear this attribute instead of writing it.
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
continue;
}
}
if (attr.QuotedString == QuotedStringType.True)
{
// add the leading and trailing quotes, if not already have them.
if (!strValue.StartsWith("\""))
strValue = "\"" + strValue;
if (!strValue.EndsWith("\""))
strValue = strValue + "\"";
}
else if (attr.QuotedString == QuotedStringType.Remove)
{
// remove the leading and trailing quotes, if any
if (strValue.StartsWith("\""))
strValue = strValue.Substring(1);
if (strValue.EndsWith("\""))
strValue = strValue.Substring(0, strValue.Length - 1);
}
if (attr.Multiline)
{
// substitutes the NewLine string with "\n"
strValue = strValue.Replace(Environment.NewLine, attr.MultilineSeparator);
}
WriteValue(iniFiles, attr.File, attr.Section, keyName, strValue);
}
}
}
}
catch (Exception)
{
throw;
}
}
}
SaveFiles(iniFiles);
}
public string[] ReadSection(Enum iniFile, Enum section)
{
return ReadSection(iniFile, SectionNames[section]);
}
public string[] ReadSection(Enum iniFile, string sectionName)
{
var file = Path.Combine(this.BasePath, FileNames[iniFile]);
return IniFileUtils.ReadSection(file, sectionName);
}
public void WriteSection(Enum iniFile, Enum section, string[] values)
{
WriteSection(iniFile, SectionNames[section], values);
}
public void WriteSection(Enum iniFile, string sectionName, string[] values)
{
var file = Path.Combine(this.BasePath, FileNames[iniFile]);
var result = IniFileUtils.WriteSection(file, sectionName, values);
}
private string[] ReadCustomSectionNames(Dictionary<string, IniFile> iniFiles, Enum iniFile)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return new string[0];
return iniFiles[FileNames[iniFile]].Sections.Select(s => s.SectionName).Where(s => !SectionNames.ContainsValue(s)).ToArray();
}
private string[] ReadSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section)
{
return ReadSection(iniFiles, iniFile, SectionNames[section]);
}
private string[] ReadSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, string sectionName)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return new string[0];
return iniFiles[FileNames[iniFile]].GetSection(sectionName)?.KeysToStringArray() ?? new string[0];
}
private string ReadValue(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section, string keyName)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return string.Empty;
return iniFiles[FileNames[iniFile]].GetKey(SectionNames[section], keyName)?.KeyValue ?? string.Empty;
}
private void WriteSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section, string[] values)
{
WriteSection(iniFiles, iniFile, SectionNames[section], values);
}
private void WriteSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, string sectionName, string[] values)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return;
iniFiles[FileNames[iniFile]].WriteSection(sectionName, values);
}
private void WriteValue(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section, string keyName, string keyValue)
{
WriteValue(iniFiles, iniFile, SectionNames[section], keyName, keyValue);
}
private void WriteValue(Dictionary<string, IniFile> iniFiles, Enum iniFile, string sectionName, string keyName, string keyValue)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return;
iniFiles[FileNames[iniFile]].WriteKey(sectionName, keyName, keyValue);
}
private void ReadFile(Dictionary<string, IniFile> iniFiles, Enum iniFile)
{
if (!iniFiles.ContainsKey(FileNames[iniFile]))
{
var file = Path.Combine(this.BasePath, FileNames[iniFile]);
iniFiles.Add(FileNames[iniFile], IniFileUtils.ReadFromFile(file));
}
}
private void SaveFiles(Dictionary<string, IniFile> iniFiles)
{
foreach (var iniFile in iniFiles)
{
var file = Path.Combine(this.BasePath, iniFile.Key);
var result = IniFileUtils.SaveToFile(file, iniFile.Value);
}
}
}
}

View file

@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ServerManagerTool.Common.Serialization
{
public class IniFile
{
public IniFile()
{
Sections = new List<IniSection>();
}
public List<IniSection> Sections;
public IniSection AddSection(string sectionName, bool allowEmptyName = false)
{
if (!allowEmptyName && string.IsNullOrWhiteSpace(sectionName))
return null;
var section = Sections.FirstOrDefault(s => s.SectionName.Equals(sectionName, StringComparison.OrdinalIgnoreCase));
if (section == null)
{
section = new IniSection() { SectionName = sectionName };
Sections.Add(section);
}
return section;
}
public IniKey AddKey(string keyName, string keyValue)
{
var section = Sections.LastOrDefault();
if (section == null)
section = AddSection(string.Empty, true);
return section.AddKey(keyName, keyValue);
}
public IniKey AddKey(string keyValuePair)
{
var section = Sections.LastOrDefault();
if (section == null)
section = AddSection(string.Empty, true);
return section.AddKey(keyValuePair);
}
public IniSection GetSection(string sectionName)
{
return Sections?.FirstOrDefault(s => s.SectionName.Equals(sectionName, StringComparison.OrdinalIgnoreCase));
}
public IniKey GetKey(string sectionName, string keyName)
{
return GetSection(sectionName)?.GetKey(keyName);
}
public void RemoveSection(string sectionName)
{
var section = GetSection(sectionName);
RemoveSection(section);
}
public void RemoveSection(IniSection section)
{
if (Sections.Contains(section))
Sections.Remove(section);
}
public bool WriteSection(string sectionName, string[] keysValuePairs)
{
if (sectionName == null)
return false;
var result = true;
// get the section.
var section = GetSection(sectionName);
// check if the section exists.
if (section != null)
{
// delete the section.
RemoveSection(section);
}
// create the section.
section = AddSection(sectionName);
if (section != null)
{
foreach (var key in keysValuePairs)
{
section.AddKey(key);
}
}
return result;
}
public bool WriteKey(string sectionName, string keyName, string keyValue)
{
if (sectionName == null)
return false;
var result = true;
// get the section.
var section = GetSection(sectionName);
// check if the section exists.
if (section == null)
{
// section does not exist, check if keyname is NULL.
if (keyName == null)
{
// do nothing, the section does not exist and does not need to be removed.
}
else
{
// create the section.
section = AddSection(sectionName);
}
}
else
{
// section does exists, check if the keyname is NULL.
if (keyName == null)
{
// keyname is NULL, we need to delete the section.
RemoveSection(section);
// reset the section variable.
section = null;
}
}
// check if the section exists.
if (section != null)
{
// get the key.
var key = section.GetKey(keyName);
// check if the key exists.
if (key == null)
{
// key does not exist, check if keyvalue is NULL.
if (keyValue == null)
{
// do nothing, the key does not exist and does not need to be removed.
}
else
{
// create the key.
key = section.AddKey(keyName, keyValue);
}
}
else
{
// key does exists, check if the keyvalue is NULL.
if (keyValue == null)
{
// keyvalue is NULL, we need to delete the key and exit.
section.RemoveKey(key);
// reset the key variable.
key = null;
}
else
{
// update the keyvalue.
key.KeyValue = keyValue;
}
}
}
return result;
}
public string ToOutputString()
{
var result = new StringBuilder();
foreach (var section in Sections)
{
result.AppendLine($"[{section.SectionName}]");
foreach (var keyString in section.KeysToStringArray())
{
result.AppendLine(keyString);
}
result.AppendLine();
}
return result.ToString();
}
}
}

View file

@ -0,0 +1,19 @@
namespace ServerManagerTool.Common.Serialization
{
public class IniKey
{
public IniKey()
{
KeyName = string.Empty;
KeyValue = string.Empty;
}
public string KeyName;
public string KeyValue;
public override string ToString()
{
return $"{KeyName}={KeyValue}";
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServerManagerTool.Common.Serialization
{
public class IniSection
{
public IniSection()
{
SectionName = string.Empty;
Keys = new List<IniKey>();
}
public string SectionName;
public List<IniKey> Keys;
public IniKey AddKey(string keyName, string keyValue)
{
var key = new IniKey() { KeyName = keyName, KeyValue = keyValue };
Keys.Add(key);
return key;
}
public IniKey AddKey(string keyValuePair)
{
var parts = keyValuePair?.Split(new[] { '=' }, 2) ?? new string[1];
if (string.IsNullOrWhiteSpace(parts[0]))
return null;
var key = new IniKey() { KeyName = parts[0] };
if (parts.Length > 1)
key.KeyValue = parts[1];
Keys.Add(key);
return key;
}
public IniKey GetKey(string keyName)
{
return Keys?.FirstOrDefault(s => s.KeyName.Equals(keyName, StringComparison.OrdinalIgnoreCase));
}
public string[] KeysToStringArray()
{
return Keys.Select(k => k.ToString()).ToArray();
}
public void RemoveKey(string keyName)
{
var key = GetKey(keyName);
RemoveKey(key);
}
public void RemoveKey(IniKey key)
{
if (Keys.Contains(key))
Keys.Remove(key);
}
public override string ToString()
{
return $"[{SectionName}]";
}
}
}