Files
SabreTools/SabreTools.Library/IO/IniReader.cs
Matt Nadareski 41d3d0c848 IO namespace
2020-08-01 22:46:28 -07:00

143 lines
3.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace SabreTools.Library.IO
{
public class IniReader : IDisposable
{
/// <summary>
/// Internal stream reader for inputting
/// </summary>
private StreamReader sr;
/// <summary>
/// Get if at end of stream
/// </summary>
public bool EndOfStream
{
get
{
return sr?.EndOfStream ?? true;
}
}
/// <summary>
/// Contents of the currently read line as a key value pair
/// </summary>
public KeyValuePair<string, string>? KeyValuePair { get; private set; } = null;
/// <summary>
/// Contents of the currently read line
/// </summary>
public string Line { get; private set; } = string.Empty;
/// <summary>
/// Current row type
/// </summary>
public IniRowType RowType { get; private set; } = IniRowType.None;
/// <summary>
/// Current section being read
/// </summary>
public string Section { get; private set; } = string.Empty;
/// <summary>
/// Validate that rows are in key=value format
/// </summary>
public bool ValidateRows { get; set; } = true;
/// <summary>
/// Constructor for reading from a file
/// </summary>
public IniReader(string filename)
{
sr = new StreamReader(filename);
}
/// <summary>
/// Constructor for reading from a stream
/// </summary>
public IniReader(Stream stream, Encoding encoding)
{
sr = new StreamReader(stream, encoding);
}
/// <summary>
/// Read the next line in the INI file
/// </summary>
public bool ReadNextLine()
{
if (!(sr.BaseStream?.CanRead ?? false) || sr.EndOfStream)
return false;
Line = sr.ReadLine().Trim();
ProcessLine();
return true;
}
/// <summary>
/// Process the current line and extract out values
/// </summary>
private void ProcessLine()
{
// Comment
if (Line.StartsWith(";"))
{
KeyValuePair = null;
RowType = IniRowType.Comment;
}
// Section
else if (Line.StartsWith("[") && Line.EndsWith("]"))
{
KeyValuePair = null;
RowType = IniRowType.SectionHeader;
Section = Line.TrimStart('[').TrimEnd(']');
}
// KeyValuePair
else if (Line.Contains("="))
{
// Split the line by '=' for key-value pairs
string[] data = Line.Split('=');
// If the value field contains an '=', we need to put them back in
string key = data[0].Trim();
string value = string.Join("=", data.Skip(1)).Trim();
KeyValuePair = new KeyValuePair<string, string>(key, value);
RowType = IniRowType.KeyValue;
}
// Empty
else if (string.IsNullOrEmpty(Line))
{
KeyValuePair = null;
Line = string.Empty;
RowType = IniRowType.None;
}
// Invalid
else
{
KeyValuePair = null;
RowType = IniRowType.Invalid;
if (ValidateRows)
throw new InvalidDataException($"Invalid INI row found, cannot continue: {Line}");
}
}
/// <summary>
/// Dispose of the underlying reader
/// </summary>
public void Dispose()
{
sr.Dispose();
}
}
}