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 _sections = new List(); private readonly Dictionary _fullKeyNameToValue = new Dictionary(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 } }