Sicherung
This commit is contained in:
48
Config.Net/Stores/AppConfigStore.cs
Normal file
48
Config.Net/Stores/AppConfigStore.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Config.Net.Stores
|
||||
{
|
||||
/// <summary>
|
||||
/// Standard app.config (web.config) configuration store. Read-only.
|
||||
/// </summary>
|
||||
class AppConfigStore : IConfigStore
|
||||
{
|
||||
public string Name => "App.config";
|
||||
|
||||
public bool CanRead => true;
|
||||
|
||||
public bool CanWrite => false;
|
||||
|
||||
public string? Read(string key)
|
||||
{
|
||||
if(key == null) return null;
|
||||
|
||||
//first, look at appsettings and connection strings
|
||||
string? value = ConfigurationManager.AppSettings[key] ?? ConfigurationManager.ConnectionStrings[key]?.ConnectionString;
|
||||
|
||||
if(value == null)
|
||||
{
|
||||
int idx = key.IndexOf('.');
|
||||
if(idx != -1)
|
||||
{
|
||||
string sectionName = key.Substring(0, idx);
|
||||
if(ConfigurationManager.GetSection(sectionName) is NameValueCollection nvsc)
|
||||
{
|
||||
string keyName = key.Substring(idx + 1);
|
||||
value = nvsc[keyName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void Write(string key, string? value) => throw new NotSupportedException();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
61
Config.Net/Stores/AssemblyConfigStore.cs
Normal file
61
Config.Net/Stores/AssemblyConfigStore.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Config.Net.Stores
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads configuration from the .dll.config or .exe.config file.
|
||||
/// </summary>
|
||||
class AssemblyConfigStore : IConfigStore
|
||||
{
|
||||
private readonly Configuration _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of assembly configuration store (.dll.config files)
|
||||
/// </summary>
|
||||
/// <param name="assembly">reference to the assembly to look for</param>
|
||||
public AssemblyConfigStore(Assembly assembly)
|
||||
{
|
||||
_configuration = ConfigurationManager.OpenExeConfiguration(assembly.Location);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Store name
|
||||
/// </summary>
|
||||
public string Name => Path.GetFileName(_configuration.FilePath);
|
||||
|
||||
/// <summary>
|
||||
/// Store is readable
|
||||
/// </summary>
|
||||
public bool CanRead => true;
|
||||
|
||||
/// <summary>
|
||||
/// Store is not writeable
|
||||
/// </summary>
|
||||
public bool CanWrite => false;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the value by key
|
||||
/// </summary>
|
||||
public string? Read(string key)
|
||||
{
|
||||
KeyValueConfigurationElement element = _configuration.AppSettings.Settings[key];
|
||||
|
||||
return element?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writing is not supported
|
||||
/// </summary>
|
||||
public void Write(string key, string? value) => throw new NotSupportedException();
|
||||
|
||||
/// <summary>
|
||||
/// Nothing to dispose
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Config.Net/Stores/DictionaryConfigStore.cs
Normal file
64
Config.Net/Stores/DictionaryConfigStore.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Config.Net.Core;
|
||||
|
||||
namespace Config.Net.Stores
|
||||
{
|
||||
class DictionaryConfigStore : IConfigStore
|
||||
{
|
||||
private readonly IDictionary<string, string> _container;
|
||||
|
||||
public DictionaryConfigStore(IDictionary<string, string>? container = null)
|
||||
{
|
||||
_container = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
if(container != null)
|
||||
{
|
||||
foreach(KeyValuePair<string, string> item in container)
|
||||
{
|
||||
_container[item.Key] = item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanRead => true;
|
||||
|
||||
public bool CanWrite => true;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string? Read(string key)
|
||||
{
|
||||
if (key == null) return null;
|
||||
|
||||
if (FlatArrays.IsArrayLength(key, k => _container.GetValueOrDefaultInternal(k), out int length))
|
||||
{
|
||||
return length.ToString();
|
||||
}
|
||||
|
||||
if (FlatArrays.IsArrayElement(key, k => _container.GetValueOrDefaultInternal(k), out string? element))
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
return _container.GetValueOrDefaultInternal(key);
|
||||
}
|
||||
|
||||
public void Write(string key, string? value)
|
||||
{
|
||||
if (key == null) return;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
_container.Remove(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_container[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
Config.Net/Stores/EnvironmentVariablesStore.cs
Normal file
76
Config.Net/Stores/EnvironmentVariablesStore.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Config.Net.Core;
|
||||
|
||||
namespace Config.Net.Stores
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses system environment variables
|
||||
/// </summary>
|
||||
class EnvironmentVariablesStore : IConfigStore
|
||||
{
|
||||
/// <summary>
|
||||
/// Readable
|
||||
/// </summary>
|
||||
public bool CanRead => true;
|
||||
|
||||
/// <summary>
|
||||
/// Writeable
|
||||
/// </summary>
|
||||
public bool CanWrite => true;
|
||||
|
||||
/// <summary>
|
||||
/// Store name
|
||||
/// </summary>
|
||||
public string Name => "System Environment";
|
||||
|
||||
/// <summary>
|
||||
/// Reads value by key
|
||||
/// </summary>
|
||||
public string? Read(string key)
|
||||
{
|
||||
if (key == null) return null;
|
||||
|
||||
foreach(string variant in GetAllKeyVariants(key))
|
||||
{
|
||||
if (FlatArrays.IsArrayLength(variant, k => Environment.GetEnvironmentVariable(k), out int length))
|
||||
{
|
||||
return length.ToString();
|
||||
}
|
||||
|
||||
if (FlatArrays.IsArrayElement(variant, k => Environment.GetEnvironmentVariable(k), out string? element))
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
string? value = Environment.GetEnvironmentVariable(variant);
|
||||
if (value != null) return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes value by key
|
||||
/// </summary>
|
||||
public void Write(string key, string? value)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(key, value);
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetAllKeyVariants(string key)
|
||||
{
|
||||
var result = new List<string>();
|
||||
result.Add(key);
|
||||
result.Add(key.ToUpper().Replace(".", "_"));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Nothing to dispose
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Config.Net/Stores/Formats/Ini/IniComment.cs
Normal file
21
Config.Net/Stores/Formats/Ini/IniComment.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace Config.Net.Stores.Formats.Ini
|
||||
{
|
||||
class IniComment : IniEntity
|
||||
{
|
||||
public const string CommentSeparator = ";";
|
||||
|
||||
public IniComment(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public string EscapedValue
|
||||
{
|
||||
get { return Value.Replace("\r", @"\r").Replace("\n", @"\n"); }
|
||||
}
|
||||
|
||||
public override string ToString() => Value;
|
||||
}
|
||||
}
|
||||
6
Config.Net/Stores/Formats/Ini/IniEntity.cs
Normal file
6
Config.Net/Stores/Formats/Ini/IniEntity.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Config.Net.Stores.Formats.Ini
|
||||
{
|
||||
abstract class IniEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
72
Config.Net/Stores/Formats/Ini/IniKeyValue.cs
Normal file
72
Config.Net/Stores/Formats/Ini/IniKeyValue.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
|
||||
namespace Config.Net.Stores.Formats.Ini
|
||||
{
|
||||
internal class IniKeyValue : IniEntity
|
||||
{
|
||||
public const string KeyValueSeparator = "=";
|
||||
|
||||
public IniKeyValue(string key, string value, string? comment)
|
||||
{
|
||||
if(key == null) throw new ArgumentNullException(nameof(key));
|
||||
Key = key;
|
||||
Value = value;
|
||||
Comment = comment == null ? null : new IniComment(comment);
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public string EscapedKey
|
||||
{
|
||||
get { return Key.Replace("\r", @"\r").Replace("\n", @"\n"); }
|
||||
}
|
||||
|
||||
public string EscapedValue
|
||||
{
|
||||
get { return Value.Replace("\r", @"\r").Replace("\n", @"\n"); }
|
||||
}
|
||||
|
||||
public IniComment? Comment { get; }
|
||||
|
||||
public static IniKeyValue? FromLine(string line, bool parseInlineComments, bool unescapeNewLines = false)
|
||||
{
|
||||
int idx = line.IndexOf(KeyValueSeparator, StringComparison.CurrentCulture);
|
||||
if(idx == -1) return null;
|
||||
|
||||
string key = line.Substring(0, idx).Trim();
|
||||
string value = line.Substring(idx + 1).Trim();
|
||||
string? comment = null;
|
||||
|
||||
if (parseInlineComments)
|
||||
{
|
||||
idx = value.LastIndexOf(IniComment.CommentSeparator, StringComparison.CurrentCulture);
|
||||
if (idx != -1)
|
||||
{
|
||||
comment = value.Substring(idx + 1).Trim();
|
||||
value = value.Substring(0, idx).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
if(unescapeNewLines)
|
||||
{
|
||||
key = UnescapeString(key);
|
||||
value = UnescapeString(value);
|
||||
comment = (comment != null) ? UnescapeString(comment) : null;
|
||||
}
|
||||
|
||||
return new IniKeyValue(key, value, comment);
|
||||
}
|
||||
|
||||
private static string UnescapeString(string key)
|
||||
{
|
||||
return key.Replace(@"\r", "\r").Replace(@"\n", "\n");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Config.Net/Stores/Formats/Ini/IniSection.cs
Normal file
121
Config.Net/Stores/Formats/Ini/IniSection.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Config.Net.Stores.Formats.Ini
|
||||
{
|
||||
class IniSection
|
||||
{
|
||||
public const string SectionKeySeparator = ".";
|
||||
|
||||
private readonly List<IniEntity> _entities = new List<IniEntity>();
|
||||
private readonly Dictionary<string, IniKeyValue> _keyToValue = new Dictionary<string, IniKeyValue>();
|
||||
|
||||
/// <summary>
|
||||
/// Section name
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="name">Pass null to work with global section</param>
|
||||
public IniSection(string? name)
|
||||
{
|
||||
if(name != null)
|
||||
{
|
||||
if (name.StartsWith("[")) name = name.Substring(1);
|
||||
if (name.EndsWith("]")) name = name.Substring(0, name.Length - 1);
|
||||
}
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void Add(IniEntity entity)
|
||||
{
|
||||
_entities.Add(entity);
|
||||
|
||||
IniKeyValue? ikv = entity as IniKeyValue;
|
||||
if(ikv != null)
|
||||
{
|
||||
_keyToValue[ikv.Key] = ikv;
|
||||
}
|
||||
}
|
||||
|
||||
public IniKeyValue? Set(string key, string? value)
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
IniKeyValue? ikv;
|
||||
if(_keyToValue.TryGetValue(key, out ikv))
|
||||
{
|
||||
_keyToValue.Remove(key);
|
||||
return ikv;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IniKeyValue? ikv;
|
||||
if(_keyToValue.TryGetValue(key, out ikv))
|
||||
{
|
||||
ikv.Value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
ikv = new IniKeyValue(key, value, null);
|
||||
Add(ikv);
|
||||
}
|
||||
return ikv;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SplitKey(string fullKey, out string? sectionName, out string keyName)
|
||||
{
|
||||
int idx = fullKey.IndexOf(SectionKeySeparator, StringComparison.CurrentCulture);
|
||||
|
||||
if(idx == -1)
|
||||
{
|
||||
sectionName = null;
|
||||
keyName = fullKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
sectionName = fullKey.Substring(0, idx);
|
||||
keyName = fullKey.Substring(idx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteTo(StreamWriter writer)
|
||||
{
|
||||
foreach(IniEntity entity in _entities)
|
||||
{
|
||||
IniKeyValue? ikv = entity as IniKeyValue;
|
||||
if(ikv != null)
|
||||
{
|
||||
writer.Write($"{ikv.EscapedKey}{IniKeyValue.KeyValueSeparator}{ikv.EscapedValue}");
|
||||
if(ikv.Comment != null)
|
||||
{
|
||||
writer.Write(" ");
|
||||
writer.Write(IniComment.CommentSeparator);
|
||||
writer.Write(ikv.Comment.EscapedValue);
|
||||
}
|
||||
writer.WriteLine();
|
||||
continue;
|
||||
}
|
||||
|
||||
IniComment? comment = entity as IniComment;
|
||||
if(comment != null)
|
||||
{
|
||||
writer.Write(IniComment.CommentSeparator);
|
||||
writer.WriteLine(comment.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Config.Net/Stores/Formats/Ini/StructuredIniFile.cs
Normal file
130
Config.Net/Stores/Formats/Ini/StructuredIniFile.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Config.Net.Stores.Formats.Ini
|
||||
{
|
||||
class StructuredIniFile
|
||||
{
|
||||
private const string _sectionBegin = "[";
|
||||
private const string _sectionEnd = "]";
|
||||
private static readonly char[] _sectionTrims = {'[', ']'};
|
||||
|
||||
private readonly IniSection _globalSection;
|
||||
private readonly List<IniSection> _sections = new List<IniSection>();
|
||||
private readonly Dictionary<string, IniKeyValue> _fullKeyNameToValue = new Dictionary<string, IniKeyValue>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
public StructuredIniFile()
|
||||
{
|
||||
_globalSection = new IniSection(null);
|
||||
_sections.Add(_globalSection);
|
||||
}
|
||||
|
||||
public string? this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if(key == null) return null;
|
||||
|
||||
IniKeyValue? value;
|
||||
return !_fullKeyNameToValue.TryGetValue(key, out value) ? null : value.Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
if(key == null) return;
|
||||
|
||||
IniSection.SplitKey(key, out string? sectionName, out string keyName);
|
||||
IniSection? section = sectionName == null
|
||||
? _globalSection
|
||||
: _sections.FirstOrDefault(s => s.Name == sectionName);
|
||||
if(section == null)
|
||||
{
|
||||
section = new IniSection(sectionName);
|
||||
_sections.Add(section);
|
||||
}
|
||||
IniKeyValue? ikv = section.Set(keyName, value);
|
||||
|
||||
//update the local cache
|
||||
if(ikv != null)
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
_fullKeyNameToValue.Remove(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fullKeyNameToValue[key] = ikv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static StructuredIniFile ReadFrom(Stream inputStream, bool parseInlineComments, bool unescapeNewLines = false)
|
||||
{
|
||||
if(inputStream == null) throw new ArgumentNullException(nameof(inputStream));
|
||||
|
||||
var file = new StructuredIniFile();
|
||||
|
||||
using(var reader = new StreamReader(inputStream))
|
||||
{
|
||||
IniSection section = file._globalSection;
|
||||
|
||||
string? line;
|
||||
while((line = reader.ReadLine()) != null)
|
||||
{
|
||||
line = line.Trim();
|
||||
|
||||
if(line.StartsWith(_sectionBegin))
|
||||
{
|
||||
//start new section
|
||||
line = line.Trim();
|
||||
section = new IniSection(line);
|
||||
file._sections.Add(section);
|
||||
}
|
||||
else if(line.StartsWith(IniComment.CommentSeparator))
|
||||
{
|
||||
//whole line is a comment
|
||||
string comment = line.Substring(1).Trim();
|
||||
section.Add(new IniComment(comment));
|
||||
}
|
||||
else
|
||||
{
|
||||
IniKeyValue? ikv = IniKeyValue.FromLine(line, parseInlineComments, unescapeNewLines);
|
||||
if(ikv == null) continue;
|
||||
|
||||
section.Add(ikv);
|
||||
string fullKey = section.Name == null
|
||||
? ikv.Key
|
||||
: $"{section.Name}{IniSection.SectionKeySeparator}{ikv.Key}";
|
||||
file._fullKeyNameToValue[fullKey] = ikv;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
public void WriteTo(Stream outputStream)
|
||||
{
|
||||
if(outputStream == null) throw new ArgumentNullException(nameof(outputStream));
|
||||
|
||||
using(var writer = new StreamWriter(outputStream))
|
||||
{
|
||||
foreach(IniSection section in _sections)
|
||||
{
|
||||
if(section.Name != null)
|
||||
{
|
||||
writer.WriteLine();
|
||||
writer.WriteLine($"{_sectionBegin}{section.Name}{_sectionEnd}");
|
||||
}
|
||||
|
||||
section.WriteTo(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private static
|
||||
}
|
||||
}
|
||||
102
Config.Net/Stores/Impl/CommandLine/CommandLineConfigStore.cs
Normal file
102
Config.Net/Stores/Impl/CommandLine/CommandLineConfigStore.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Config.Net.Core;
|
||||
using Config.Net.TypeParsers;
|
||||
|
||||
namespace Config.Net.Stores.Impl.CommandLine
|
||||
{
|
||||
class CommandLineConfigStore : IConfigStore
|
||||
{
|
||||
private readonly Dictionary<string, string> _nameToValue;
|
||||
private static readonly char[] ArgPrefixes = new[] { '-', '/' };
|
||||
private static readonly string[] ArgDelimiters = new[] { "=", ":" };
|
||||
private readonly bool _isCaseSensitive;
|
||||
|
||||
public bool CanRead => true;
|
||||
|
||||
public bool CanWrite => false;
|
||||
|
||||
public CommandLineConfigStore(string[]? args = null, bool isCaseSensitive = false, IEnumerable<KeyValuePair<string, int>>? nameToPosition = null)
|
||||
{
|
||||
_isCaseSensitive = isCaseSensitive;
|
||||
|
||||
_nameToValue = new Dictionary<string, string>(_isCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
Parse(args ?? Environment.GetCommandLineArgs(), nameToPosition);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public string? Read(string key)
|
||||
{
|
||||
if (key == null) return null;
|
||||
|
||||
if(FlatArrays.IsArrayLength(key, k => _nameToValue.GetValueOrDefaultInternal(k), out int length))
|
||||
{
|
||||
return length.ToString();
|
||||
}
|
||||
|
||||
if(FlatArrays.IsArrayElement(key, k => _nameToValue.GetValueOrDefaultInternal(k), out string? element))
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
string? value;
|
||||
_nameToValue.TryGetValue(key, out value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private string[]? GetAsArray(string key)
|
||||
{
|
||||
if (!_nameToValue.TryGetValue(key, out string? allString)) return null;
|
||||
|
||||
if (!StringArrayParser.TryParse(allString, out string[]? ar)) return null;
|
||||
return ar;
|
||||
}
|
||||
|
||||
public void Write(string key, string? value)
|
||||
{
|
||||
throw new NotSupportedException("command line cannot be written to");
|
||||
}
|
||||
|
||||
private void Parse(string[] args, IEnumerable<KeyValuePair<string, int>>? nameToPosition)
|
||||
{
|
||||
_nameToValue.Clear();
|
||||
|
||||
var posToName = new Dictionary<int, string>();
|
||||
if (nameToPosition != null)
|
||||
{
|
||||
foreach(KeyValuePair<string, int> p in nameToPosition)
|
||||
{
|
||||
if (p.Key != null)
|
||||
{
|
||||
posToName[p.Value] = p.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (args == null) return;
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
string? name;
|
||||
string? value;
|
||||
|
||||
Tuple<string, string?>? nameValue = Utils.SplitByDelimiter(args[i], ArgDelimiters);
|
||||
name = nameValue?.Item1.TrimStart(ArgPrefixes);
|
||||
value = nameValue?.Item2;
|
||||
|
||||
if (name != null && value != null)
|
||||
{
|
||||
_nameToValue[name] = value;
|
||||
}
|
||||
else if(name != null && posToName.TryGetValue(i, out string? ptnName))
|
||||
{
|
||||
_nameToValue[ptnName] = args[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Config.Net/Stores/IniFileConfigStore.cs
Normal file
120
Config.Net/Stores/IniFileConfigStore.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Config.Net.Core;
|
||||
using Config.Net.Stores.Formats.Ini;
|
||||
|
||||
namespace Config.Net.Stores
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple INI storage.
|
||||
/// </summary>
|
||||
class IniFileConfigStore : IConfigStore
|
||||
{
|
||||
private readonly string? _fullName;
|
||||
private readonly StructuredIniFile _iniFile;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>r
|
||||
/// <param name="name">File does not have to exist, however it will be created as soon as you
|
||||
/// try to write to it</param>
|
||||
public IniFileConfigStore(string name, bool isFilePath, bool parseInlineComments, bool unescapeNewLines = false)
|
||||
{
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (isFilePath)
|
||||
{
|
||||
_fullName = Path.GetFullPath(name); // Allow relative path to INI file
|
||||
|
||||
string? parentDirPath = Path.GetDirectoryName(_fullName);
|
||||
if (string.IsNullOrEmpty(parentDirPath)) throw new IOException("the provided directory path is not valid");
|
||||
if (!Directory.Exists(parentDirPath))
|
||||
{
|
||||
Directory.CreateDirectory(parentDirPath);
|
||||
}
|
||||
|
||||
_iniFile = ReadIniFile(_fullName, parseInlineComments, unescapeNewLines);
|
||||
|
||||
CanWrite = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_iniFile = ReadIniContent(name, parseInlineComments, unescapeNewLines);
|
||||
|
||||
CanWrite = false;
|
||||
}
|
||||
|
||||
CanRead = true;
|
||||
}
|
||||
|
||||
public string Name => ".ini";
|
||||
|
||||
public bool CanRead { get; }
|
||||
|
||||
public bool CanWrite { get; }
|
||||
|
||||
public string? Read(string key)
|
||||
{
|
||||
if (FlatArrays.IsArrayLength(key, k => _iniFile[k], out int length))
|
||||
{
|
||||
return length.ToString();
|
||||
}
|
||||
|
||||
if (FlatArrays.IsArrayElement(key, k => _iniFile[k], out string? element))
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
return _iniFile[key];
|
||||
}
|
||||
|
||||
public void Write(string key, string? value)
|
||||
{
|
||||
if (!CanWrite) return;
|
||||
|
||||
_iniFile[key] = value;
|
||||
|
||||
WriteIniFile();
|
||||
}
|
||||
|
||||
private static StructuredIniFile ReadIniFile(string fullName, bool parseInlineComments, bool unescapeNewLines = false)
|
||||
{
|
||||
FileInfo iniFile = new FileInfo(fullName);
|
||||
if(iniFile.Exists)
|
||||
{
|
||||
using(FileStream stream = iniFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
return StructuredIniFile.ReadFrom(stream, parseInlineComments, unescapeNewLines);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new StructuredIniFile();
|
||||
}
|
||||
}
|
||||
|
||||
private static StructuredIniFile ReadIniContent(string content, bool parseInlineComments, bool unescapeNewLines = false)
|
||||
{
|
||||
using (Stream input = new MemoryStream(Encoding.UTF8.GetBytes(content)))
|
||||
{
|
||||
return StructuredIniFile.ReadFrom(input, parseInlineComments, unescapeNewLines);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteIniFile()
|
||||
{
|
||||
if (_fullName == null) return;
|
||||
|
||||
using(FileStream stream = File.Create(_fullName))
|
||||
{
|
||||
_iniFile.WriteTo(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//nothing to dispose
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Config.Net/Stores/JsonConfigStore.cs
Normal file
165
Config.Net/Stores/JsonConfigStore.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Config.Net.Core;
|
||||
|
||||
namespace Config.Net.Stores
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple JSON storage using System.Text.Json
|
||||
/// </summary>
|
||||
public class JsonConfigStore : IConfigStore
|
||||
{
|
||||
private readonly string? _pathName;
|
||||
private JsonNode? _j;
|
||||
|
||||
/// <summary>
|
||||
/// Create JSON storage in the file specified in <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the file, either path to JSON storage file, or json file content.</param>
|
||||
/// <param name="isFilePath">Set to true if <paramref name="name"/> specifies file name, otherwise false. </param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="name"/> is null.</exception>
|
||||
/// <exception cref="IOException">Provided path is not valid.</exception>
|
||||
/// <remarks>Storage file does not have to exist, however it will be created as soon as first write performed.</remarks>
|
||||
public JsonConfigStore(string name, bool isFilePath)
|
||||
{
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (isFilePath)
|
||||
{
|
||||
_pathName = Path.GetFullPath(name); // Allow relative path to JSON file
|
||||
_j = ReadJsonFile(_pathName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_j = ReadJsonString(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// nothing to dispose.
|
||||
}
|
||||
|
||||
public string Name => "json";
|
||||
|
||||
public bool CanRead => true;
|
||||
|
||||
public bool CanWrite => _pathName != null;
|
||||
|
||||
public string? Read(string rawKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(rawKey) || _j == null) return null;
|
||||
|
||||
bool isLength = OptionPath.TryStripLength(rawKey, out string? key);
|
||||
if (key == null) return null;
|
||||
|
||||
string[] parts = key.Split('.');
|
||||
if (parts.Length == 0) return null;
|
||||
|
||||
JsonNode? node = _j;
|
||||
foreach (string rawPart in parts)
|
||||
{
|
||||
bool isIndex = OptionPath.TryStripIndex(rawPart, out string? part, out int partIndex);
|
||||
if (part == null) return null;
|
||||
|
||||
node = node![part];
|
||||
if (node == null) return null;
|
||||
|
||||
if (isIndex)
|
||||
{
|
||||
if (!(node is JsonArray ja)) return null;
|
||||
|
||||
if (partIndex < ja.Count)
|
||||
{
|
||||
node = ja[partIndex];
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLength)
|
||||
return node is JsonArray ja ? ja.Count.ToString() : null;
|
||||
|
||||
return node!.ToString();
|
||||
}
|
||||
|
||||
public void Write(string key, string? value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_pathName))
|
||||
throw new InvalidOperationException("please specify file name for writeable config");
|
||||
|
||||
if (_j == null) _j = new JsonObject();
|
||||
|
||||
// navigate to target element, create if needed
|
||||
string[] parts = key.Split('.');
|
||||
if (parts.Length == 0) return;
|
||||
|
||||
JsonNode? node = _j;
|
||||
string? lastPart = null;
|
||||
foreach (string rawPart in parts)
|
||||
{
|
||||
bool isIndex = OptionPath.TryStripIndex(rawPart, out string? part, out int partIndex);
|
||||
if (part == null) return;
|
||||
lastPart = part;
|
||||
|
||||
JsonNode? nextNode = node[part];
|
||||
|
||||
if (isIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nextNode == null)
|
||||
{
|
||||
//create missing node
|
||||
nextNode = new JsonObject();
|
||||
node[part] = nextNode;
|
||||
}
|
||||
}
|
||||
|
||||
node = nextNode;
|
||||
|
||||
}
|
||||
|
||||
JsonObject? parent = node.Parent as JsonObject;
|
||||
parent!.Remove(lastPart!);
|
||||
parent![lastPart!] = JsonValue.Create(value);
|
||||
|
||||
string js = _j.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
|
||||
|
||||
FileInfo file = new FileInfo(_pathName);
|
||||
|
||||
if (file is not null)
|
||||
{
|
||||
if (file.Directory is not null)
|
||||
{
|
||||
file.Directory.Create();
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText(_pathName, js);
|
||||
|
||||
}
|
||||
|
||||
private static JsonNode? ReadJsonFile(string fileName)
|
||||
{
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
string json = File.ReadAllText(fileName);
|
||||
return ReadJsonString(json);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static JsonNode? ReadJsonString(string jsonString)
|
||||
{
|
||||
return JsonNode.Parse(jsonString);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user