diff --git a/Source/Ini/IniDocument.cs b/Source/Ini/IniDocument.cs
index bbb2d42..cfab2e9 100644
--- a/Source/Ini/IniDocument.cs
+++ b/Source/Ini/IniDocument.cs
@@ -39,6 +39,7 @@ public class IniDocument
IniSectionCollection sections = new IniSectionCollection ();
ArrayList initialComment = new ArrayList ();
IniFileType fileType = IniFileType.Standard;
+ bool extended = false;
#endregion
#region Public properties
@@ -52,52 +53,108 @@ public IniFileType FileType
#region Constructors
///
- public IniDocument (string filePath)
+ public IniDocument(string filePath)
{
fileType = IniFileType.Standard;
- Load (filePath);
+ Load(filePath);
+ }
+
+ ///
+ public IniDocument(string filePath, bool supportExtended)
+ {
+ fileType = IniFileType.Standard;
+ extended = supportExtended;
+ Load(filePath);
+ }
+
+ ///
+ public IniDocument(string filePath, IniFileType type)
+ {
+ fileType = type;
+ Load(filePath);
}
///
- public IniDocument (string filePath, IniFileType type)
+ public IniDocument(string filePath, IniFileType type, bool supportExtended)
{
fileType = type;
- Load (filePath);
+ extended = supportExtended;
+ Load(filePath);
}
///
- public IniDocument (TextReader reader)
+ public IniDocument(TextReader reader)
{
fileType = IniFileType.Standard;
- Load (reader);
+ Load(reader);
+ }
+
+ ///
+ public IniDocument(TextReader reader, bool supportExtended)
+ {
+ fileType = IniFileType.Standard;
+ extended = supportExtended;
+ Load(reader);
}
///
- public IniDocument (TextReader reader, IniFileType type)
+ public IniDocument(TextReader reader, IniFileType type)
{
fileType = type;
- Load (reader);
+ Load(reader);
}
-
+
+ ///
+ public IniDocument(TextReader reader, IniFileType type, bool supportExtended)
+ {
+ fileType = type;
+ extended = supportExtended;
+ Load(reader);
+ }
+
///
- public IniDocument (Stream stream)
+ public IniDocument(Stream stream)
{
fileType = IniFileType.Standard;
- Load (stream);
+ Load(stream);
+ }
+
+ ///
+ public IniDocument(Stream stream, bool supportExtended)
+ {
+ fileType = IniFileType.Standard;
+ extended = supportExtended;
+ Load(stream);
+ }
+
+ ///
+ public IniDocument(Stream stream, IniFileType type)
+ {
+ fileType = type;
+ Load(stream);
}
///
- public IniDocument (Stream stream, IniFileType type)
+ public IniDocument(Stream stream, IniFileType type, bool supportExtended)
{
fileType = type;
- Load (stream);
+ extended = supportExtended;
+ Load(stream);
+ }
+
+ ///
+ public IniDocument(IniReader reader)
+ {
+ fileType = IniFileType.Standard;
+ Load(reader);
}
///
- public IniDocument (IniReader reader)
+ public IniDocument(IniReader reader, bool supportExtended)
{
fileType = IniFileType.Standard;
- Load (reader);
+ extended = supportExtended;
+ Load(reader);
}
///
@@ -232,6 +289,71 @@ private void LoadReader (IniReader reader)
// Always close the file
reader.Close ();
}
+
+ MergeSections();
+ }
+
+ ///
+ /// Supports section merging where a colon is in the key, e.g. ExtendedSection : BaseSection
+ ///
+ private void MergeSections()
+ {
+ if(!extended)
+ {
+ return;
+ }
+
+ foreach (DictionaryEntry entry in sections)
+ {
+ IniSection section = (IniSection)entry.Value;
+
+ if (!section.Name.Contains(":"))
+ {
+ continue;
+ }
+
+ var parts = section.Name.Split(new char[] { ':' });
+ var newName = parts[0].TrimEnd();
+ var extendedSectionName = parts[1].TrimStart();
+
+ if (sections[newName] != null)
+ {
+ sections.Remove(newName);
+ }
+
+ if (sections[extendedSectionName] == null)
+ {
+ throw new ArgumentException(String.Format("Section {0} is trying to extend section {1} but it does not exist.", newName, extendedSectionName));
+ }
+
+ IniSection baseSection = sections[extendedSectionName];
+ var baseKeys = baseSection.GetKeys();
+
+ var newSection = new IniSection(newName, section.Comment);
+
+ for (var i = 0; i < baseSection.ItemCount; i++)
+ {
+ var item = baseSection.GetItem(i);
+
+ if (item.Value != null)
+ {
+ newSection.Set(item.Name, item.Value, item.Comment);
+ }
+ }
+
+ for (var i = 0; i < section.ItemCount; i++)
+ {
+ var item = section.GetItem(i);
+
+ if (item.Value != null)
+ {
+ newSection.Set(item.Name, item.Value, item.Comment);
+ }
+ }
+
+ sections.Add(newSection);
+ sections.Remove(section.Name);
+ }
}
///
diff --git a/Source/Test/Config/ConfigBaseTests.cs b/Source/Test/Config/ConfigBaseTests.cs
index 9dbb31a..62e501f 100644
--- a/Source/Test/Config/ConfigBaseTests.cs
+++ b/Source/Test/Config/ConfigBaseTests.cs
@@ -110,8 +110,11 @@ public void GetFloat ()
IniConfigSource source = new IniConfigSource
(new StringReader (writer.ToString ()));
IConfig config = source.Configs["Test"];
-
- Assert.AreEqual (494.59, config.GetFloat ("value 1"));
+
+ // Compensate for floating point storage.
+ var comparison = Math.Abs(494.59 - config.GetFloat("value 1"));
+ Assert.Less(comparison, 0.0001);
+
Assert.AreEqual ((float)5656.2853,
config.GetFloat ("Not Here", (float)5656.2853));
}
diff --git a/Source/Test/Ini/IniDocumentTests.cs b/Source/Test/Ini/IniDocumentTests.cs
index 7b9415f..b2cb133 100644
--- a/Source/Test/Ini/IniDocumentTests.cs
+++ b/Source/Test/Ini/IniDocumentTests.cs
@@ -246,6 +246,41 @@ public void DuplicateSections ()
Assert.IsNotNull (doc.Sections["Test"].GetValue ("value 1"));
}
+ [Test]
+ public void ExtendedSections ()
+ {
+ StringWriter writer = new StringWriter();
+ writer.WriteLine("[ExtendedSection : BaseSection]");
+ writer.WriteLine("keyB = overwrittenB");
+ writer.WriteLine("keyC = valueC");
+ writer.WriteLine("[BaseSection]");
+ writer.WriteLine("keyA = valueA");
+ writer.WriteLine("keyB = valueB");
+
+ IniDocument doc = new IniDocument(new StringReader(writer.ToString()), true);
+
+ Assert.IsNotNull(doc.Sections["BaseSection"], "BaseSection is null");
+ Assert.IsNotNull(doc.Sections["ExtendedSection"], "ExtendedSection is null");
+ Assert.IsNull(doc.Sections["ExtendedSection : BaseSection"], "ExtendedSection:BaseSection is not null");
+ Assert.AreEqual(2, doc.Sections.Count);
+
+ Assert.AreEqual("valueA", doc.Sections["BaseSection"].GetValue("keyA"));
+ Assert.AreEqual("valueB", doc.Sections["BaseSection"].GetValue("keyB"));
+
+ Assert.AreEqual("valueC", doc.Sections["ExtendedSection"].GetValue("keyC"));
+ Assert.AreEqual("overwrittenB", doc.Sections["ExtendedSection"].GetValue("keyB"));
+ }
+
+ [Test]
+ [ExpectedException(ExpectedException = typeof(ArgumentException), ExpectedMessage = "Section ExtendedSection is trying to extend section BaseSectionInvalid but it does not exist", MatchType = MessageMatch.Contains)]
+ public void ExtendedSectionsValidNames()
+ {
+ StringWriter writer = new StringWriter();
+ writer.WriteLine("[ExtendedSection : BaseSectionInvalid]");
+
+ IniDocument doc = new IniDocument(new StringReader(writer.ToString()), true);
+ }
+
[Test]
public void DuplicateKeys ()
{