/// <summary> /// Initializes a new instance of the <see cref="IniFile" /> class. /// </summary> public IniFile() { GlobalProperties = new IniSection(null); Sections = new IniSectionCollection(); ErrorLines = new IniErrorLine[0].ToReadOnlyCollection(); }
/// <summary> /// Creates an <see cref="IniFile" /> object from the specified <see cref="Stream" />. /// </summary> /// <param name="stream">The <see cref="Stream" /> from which to parse the INI file from.</param> /// <param name="encoding">The encoding to use to read the file.</param> /// <param name="parsingOptions">A <see cref="IniFileParsingOptions" /> object with format specifications for INI parsing, or <see langword="null" /> to use default parsing options.</param> /// <param name="leaveOpen">A <see cref="bool" /> value indicating whether to leave <paramref name="stream" /> open.</param> /// <returns> /// The <see cref="IniFile" /> this method creates. /// </returns> public static IniFile FromStream(Stream stream, Encoding encoding, IniFileParsingOptions parsingOptions, bool leaveOpen) { Check.ArgumentNull(stream, nameof(stream)); Check.ArgumentNull(encoding, nameof(encoding)); if (parsingOptions == null) { parsingOptions = new IniFileParsingOptions(); } IniFile ini = new IniFile(); IniSection section = ini.GlobalProperties; bool ignoreSection = false; List <IniErrorLine> errorLines = new List <IniErrorLine>(); using StreamReader reader = new StreamReader(stream, encoding, true, 4096, leaveOpen); for (int lineNumber = 1; !reader.EndOfStream; lineNumber++) { string line = reader.ReadLine(); string trimmedLine = line.Trim(); if (trimmedLine.StartsWith(";") && parsingOptions.AllowSemicolonComments || trimmedLine.StartsWith("#") && parsingOptions.AllowNumberSignComments) { } else if (trimmedLine == "") { AbortIf(!parsingOptions.AllowEmptyLines); } else if (trimmedLine.StartsWith("[") && trimmedLine.EndsWith("]")) { string newSection = trimmedLine.Substring(1, trimmedLine.Length - 2); if (parsingOptions.TrimSectionNames) { newSection = newSection.Trim(); } AbortIf(!parsingOptions.AllowSectionNameClosingBracket && newSection.Contains("]")); IniSection duplicate = ini.Sections.FirstOrDefault(sect => sect.Name.Equals(newSection, parsingOptions.DuplicateSectionNameIgnoreCase ? SpecialStringComparisons.IgnoreCase : SpecialStringComparisons.None)); bool create = false; switch (parsingOptions.DuplicateSectionNameBehavior) { case IniDuplicateSectionNameBehavior.Abort: AbortIf(duplicate != null); create = true; break; case IniDuplicateSectionNameBehavior.Ignore: if (duplicate == null) { create = true; } else { ignoreSection = true; } break; case IniDuplicateSectionNameBehavior.Merge: if (duplicate == null) { create = true; } else { section = duplicate; } break; case IniDuplicateSectionNameBehavior.Duplicate: create = true; break; default: throw Throw.InvalidEnumArgument(nameof(parsingOptions.DuplicatePropertyNameBehavior), parsingOptions.DuplicatePropertyNameBehavior); } if (create) { section = new IniSection(newSection); ini.Sections.Add(section); } } else if (parsingOptions.PropertyDelimiter == IniPropertyDelimiter.EqualSign && line.Contains("=")) { ParseProperty("="); } else if (parsingOptions.PropertyDelimiter == IniPropertyDelimiter.Colon && line.Contains(":")) { ParseProperty(":"); } else { Abort(); } void Abort() { if (parsingOptions.IgnoreErrors) { errorLines.Add(new IniErrorLine(lineNumber, line)); } else { throw new IniParsingException(lineNumber, line); } } void AbortIf(bool condition) { if (condition) { Abort(); } } void ParseProperty(string delimiter) { if (!ignoreSection) { AbortIf(!parsingOptions.AllowGlobalProperties && section == ini.GlobalProperties); IniProperty property = new IniProperty(line.SubstringUntil(delimiter), line.SubstringFrom(delimiter)); if (parsingOptions.TrimPropertyNames) { property.Name = property.Name.Trim(); } if (parsingOptions.TrimPropertyValues) { property.Value = property.Value.Trim(); } IniProperty duplicate = section.Properties.FirstOrDefault(prop => prop.Name.Equals(property.Name, parsingOptions.DuplicatePropertyNameIgnoreCase ? SpecialStringComparisons.IgnoreCase : SpecialStringComparisons.None)); if (duplicate == null) { section.Properties.Add(property); } else { switch (parsingOptions.DuplicatePropertyNameBehavior) { case IniDuplicatePropertyNameBehavior.Abort: Abort(); break; case IniDuplicatePropertyNameBehavior.Ignore: break; case IniDuplicatePropertyNameBehavior.Overwrite: duplicate.Value = property.Value; break; case IniDuplicatePropertyNameBehavior.Duplicate: section.Properties.Add(property); break; default: throw Throw.InvalidEnumArgument(nameof(parsingOptions.DuplicatePropertyNameBehavior), parsingOptions.DuplicatePropertyNameBehavior); } } } } } ini.ErrorLines = errorLines.AsReadOnly(); return(ini); }