diff --git a/Nuclex.Support (mono-3.5).csproj b/Nuclex.Support (mono-3.5).csproj
index c5a0fb9..66adcc3 100644
--- a/Nuclex.Support (mono-3.5).csproj
+++ b/Nuclex.Support (mono-3.5).csproj
@@ -267,10 +267,6 @@
TypeHelper.cs
-
-
- Semaphore.cs
-
FloatHelper.cs
@@ -300,9 +296,6 @@
StringSegment.cs
-
- WeakReference.cs
-
WeakReference.cs
diff --git a/Source/Parsing/ParserHelper.cs b/Source/Parsing/ParserHelper.cs
index b6dbf10..69032ae 100644
--- a/Source/Parsing/ParserHelper.cs
+++ b/Source/Parsing/ParserHelper.cs
@@ -176,6 +176,75 @@ namespace Nuclex.Support.Parsing {
return false;
}
+ /// Tried to parse a boolean literal
+ /// Value that will be parsed as a boolean literal
+ ///
+ /// True or false if the value was a boolean literal, null if it wasn't
+ ///
+ public static bool? ParseBooleanLiteral(string value) {
+ if(value == null) {
+ return null;
+ }
+
+ var stringSegment = new StringSegment(value, 0, value.Length);
+ return ParseBooleanLiteral(ref stringSegment);
+ }
+
+ /// Tried to parse a boolean literal
+ /// Value that will be parsed as a boolean literal
+ ///
+ /// True or false if the value was a boolean literal, null if it wasn't
+ ///
+ public static bool? ParseBooleanLiteral(ref StringSegment value) {
+ switch(value.Count) {
+
+ // If the string spells 'no', it is considered a boolean
+ case 2: {
+ bool isSpellingNo =
+ ((value.Text[value.Offset + 0] == 'n') || (value.Text[value.Offset + 0] == 'N')) &&
+ ((value.Text[value.Offset + 1] == 'o') || (value.Text[value.Offset + 1] == 'O'));
+ return isSpellingNo ? new Nullable(false) : null;
+ }
+
+ // If the string spells 'yes', it is considered a boolean
+ case 3: {
+ bool isSpellingYes =
+ ((value.Text[value.Offset + 0] == 'y') || (value.Text[value.Offset + 0] == 'Y')) &&
+ ((value.Text[value.Offset + 1] == 'e') || (value.Text[value.Offset + 1] == 'E')) &&
+ ((value.Text[value.Offset + 2] == 's') || (value.Text[value.Offset + 2] == 'S'));
+ return isSpellingYes ? new Nullable(true) : null;
+ }
+
+ // If the string spells 'true', it is considered a boolean
+ case 4: {
+ bool isSpellingTrue =
+ ((value.Text[value.Offset + 0] == 't') || (value.Text[value.Offset + 0] == 'T')) &&
+ ((value.Text[value.Offset + 1] == 'r') || (value.Text[value.Offset + 1] == 'R')) &&
+ ((value.Text[value.Offset + 2] == 'u') || (value.Text[value.Offset + 2] == 'U')) &&
+ ((value.Text[value.Offset + 3] == 'e') || (value.Text[value.Offset + 3] == 'E'));
+ return isSpellingTrue ? new Nullable(true) : null;
+ }
+
+ // If the string spells 'false', it is considered a boolean
+ case 5: {
+ bool isSpellingFalse =
+ ((value.Text[value.Offset + 0] == 'f') || (value.Text[value.Offset + 0] == 'F')) &&
+ ((value.Text[value.Offset + 1] == 'a') || (value.Text[value.Offset + 1] == 'A')) &&
+ ((value.Text[value.Offset + 2] == 'l') || (value.Text[value.Offset + 2] == 'L')) &&
+ ((value.Text[value.Offset + 3] == 's') || (value.Text[value.Offset + 3] == 'S')) &&
+ ((value.Text[value.Offset + 4] == 'e') || (value.Text[value.Offset + 4] == 'E'));
+ return isSpellingFalse ? new Nullable(false) : null;
+ }
+
+ // Anything else is not considered a boolean
+ default: {
+ return null;
+ }
+
+ }
+ }
+
+
}
} // namespace Nuclex.Support.Parsing
diff --git a/Source/Settings/ConfigurationFileStore.Parsing.cs b/Source/Settings/ConfigurationFileStore.Parsing.cs
index ed8b6cc..d5a2e0b 100644
--- a/Source/Settings/ConfigurationFileStore.Parsing.cs
+++ b/Source/Settings/ConfigurationFileStore.Parsing.cs
@@ -253,67 +253,13 @@ namespace Nuclex.Support.Settings {
}
// If it parses as a boolean literal, then it must be a boolean
- if(parseBooleanLiteral(ref value) != null) {
+ if(ParserHelper.ParseBooleanLiteral(ref value) != null) {
return typeof(bool);
}
return typeof(string);
}
- /// Tried to parse a boolean literal
- /// Value that will be parsed as a boolean literal
- ///
- /// True or false if the value was a boolean literal, null if it wasn't
- ///
- private static bool? parseBooleanLiteral(ref StringSegment value) {
- switch(value.Count) {
-
- // If the string spells 'no', it is considered a boolean
- case 2: {
- bool isSpellingNo =
- ((value.Text[value.Offset + 0] == 'n') || (value.Text[value.Offset + 0] == 'N')) &&
- ((value.Text[value.Offset + 1] == 'o') || (value.Text[value.Offset + 1] == 'O'));
- return isSpellingNo ? new Nullable(false) : null;
- }
-
- // If the string spells 'yes', it is considered a boolean
- case 3: {
- bool isSpellingYes =
- ((value.Text[value.Offset + 0] == 'y') || (value.Text[value.Offset + 0] == 'Y')) &&
- ((value.Text[value.Offset + 1] == 'e') || (value.Text[value.Offset + 1] == 'E')) &&
- ((value.Text[value.Offset + 2] == 's') || (value.Text[value.Offset + 2] == 'S'));
- return isSpellingYes ? new Nullable(true) : null;
- }
-
- // If the string spells 'true', it is considered a boolean
- case 4: {
- bool isSpellingTrue =
- ((value.Text[value.Offset + 0] == 't') || (value.Text[value.Offset + 0] == 'T')) &&
- ((value.Text[value.Offset + 1] == 'r') || (value.Text[value.Offset + 1] == 'R')) &&
- ((value.Text[value.Offset + 2] == 'u') || (value.Text[value.Offset + 2] == 'U')) &&
- ((value.Text[value.Offset + 3] == 'e') || (value.Text[value.Offset + 3] == 'E'));
- return isSpellingTrue ? new Nullable(true) : null;
- }
-
- // If the string spells 'false', it is considered a boolean
- case 5: {
- bool isSpellingFalse =
- ((value.Text[value.Offset + 0] == 'f') || (value.Text[value.Offset + 0] == 'F')) &&
- ((value.Text[value.Offset + 1] == 'a') || (value.Text[value.Offset + 1] == 'A')) &&
- ((value.Text[value.Offset + 2] == 'l') || (value.Text[value.Offset + 2] == 'L')) &&
- ((value.Text[value.Offset + 3] == 's') || (value.Text[value.Offset + 3] == 'S')) &&
- ((value.Text[value.Offset + 4] == 'e') || (value.Text[value.Offset + 4] == 'E'));
- return isSpellingFalse ? new Nullable(false) : null;
- }
-
- // Anything else is not considered a boolean
- default: {
- return null;
- }
-
- }
- }
-
}
} // namespace Nuclex.Support.Configuration
diff --git a/Source/Settings/WindowsRegistryStore.Test.cs b/Source/Settings/WindowsRegistryStore.Test.cs
index a99399b..79107d4 100644
--- a/Source/Settings/WindowsRegistryStore.Test.cs
+++ b/Source/Settings/WindowsRegistryStore.Test.cs
@@ -29,6 +29,9 @@ namespace Nuclex.Support.Settings {
/// Unit tests for the windows registry settings store
[TestFixture]
internal class WindowsRegistryStoreTest {
+
+
+
}
} // namespace Nuclex.Support.Settings
diff --git a/Source/Settings/WindowsRegistryStore.cs b/Source/Settings/WindowsRegistryStore.cs
index 33def6b..04e0567 100644
--- a/Source/Settings/WindowsRegistryStore.cs
+++ b/Source/Settings/WindowsRegistryStore.cs
@@ -23,28 +23,74 @@ License along with this library
using System;
using System.Collections.Generic;
+using Microsoft.Win32;
+using Nuclex.Support.Parsing;
+
namespace Nuclex.Support.Settings {
/// Stores settings in the registry on Windows operating systems
public class WindowsRegistryStore : ISettingsStore, IDisposable {
-
+ /// Initializes a new settings store on the specified registry path
+ /// Hive in which to look
+ /// Base path of the settings in the specified hive
+ /// Whether to open the registry in writable mode
+ public WindowsRegistryStore(RegistryHive hive, string directory, bool writable = true) {
+ using(RegistryKey hiveKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default)) {
+ this.rootKey = hiveKey.OpenSubKey(directory, writable);
+ }
+ this.writable = writable;
+ }
+
+ /// Initializes a new settings store on the specified registry key
+ /// Registry key the settings are stored under
+ /// Whether the registry was opened in writable mode
+ ///
+ /// This constructor takes ownership of the registry key. It will be disposed when
+ /// the settings store is disposed.
+ ///
+ public WindowsRegistryStore(RegistryKey rootKey, bool writable = true) {
+ this.rootKey = rootKey;
+ this.writable = writable;
+ }
/// Immediately releases all resources owned by the instance
public void Dispose() {
+ if(this.rootKey != null) {
+ this.rootKey.Dispose();
+ this.rootKey = null;
+ }
}
/// Enumerates the categories defined in the configuration
/// An enumerable list of all used categories
public IEnumerable EnumerateCategories() {
- throw new NotImplementedException();
+ return this.rootKey.GetSubKeyNames();
}
/// Enumerates the options stored under the specified category
/// Category whose options will be enumerated
/// An enumerable list of all options in the category
public IEnumerable EnumerateOptions(string category = null) {
- throw new NotImplementedException();
+ if(string.IsNullOrEmpty(category)) {
+ string[] valueNames = this.rootKey.GetValueNames();
+ for(int index = 0; index < valueNames.Length; ++index) {
+ yield return new OptionInfo() {
+ Name = valueNames[index],
+ OptionType = getBestMatchingType(this.rootKey, valueNames[index])
+ };
+ }
+ } else {
+ using(RegistryKey categoryKey = this.rootKey.OpenSubKey(category, this.writable)) {
+ string[] valueNames = categoryKey.GetValueNames();
+ for(int index = 0; index < valueNames.Length; ++index) {
+ yield return new OptionInfo() {
+ Name = valueNames[index],
+ OptionType = getBestMatchingType(categoryKey, valueNames[index])
+ };
+ }
+ }
+ }
}
/// Retrieves the value of the specified option
@@ -81,6 +127,15 @@ namespace Nuclex.Support.Settings {
///
public bool TryGet(string category, string optionName, out TValue value) {
throw new NotImplementedException();
+ if(string.IsNullOrEmpty(category)) {
+ object valueAsObject = this.rootKey.GetValue(optionName);
+ value = (TValue)Convert.ChangeType(valueAsObject, typeof(TValue));
+ } else {
+ using(RegistryKey categoryKey = this.rootKey.OpenSubKey(category, this.writable)) {
+ object valueAsObject = this.rootKey.GetValue(optionName);
+ value = (TValue)Convert.ChangeType(valueAsObject, typeof(TValue));
+ }
+ }
}
/// Saves an option in the settings store
@@ -100,6 +155,61 @@ namespace Nuclex.Support.Settings {
throw new NotImplementedException();
}
+ /// Figures out which .NET type best matches the registry value
+ /// Registry key the key is stored in
+ /// Name of the option that will be retrieved
+ /// The best matching .NET type for the registry key's value
+ private static Type getBestMatchingType(RegistryKey categoryKey, string optionName) {
+ RegistryValueKind valueKind = categoryKey.GetValueKind(optionName);
+ switch(valueKind) {
+ case RegistryValueKind.Binary: { return typeof(byte[]); }
+ case RegistryValueKind.DWord: { return typeof(int); }
+ case RegistryValueKind.QWord: { return typeof(long); }
+ case RegistryValueKind.MultiString: { return typeof(string[]); }
+ case RegistryValueKind.ExpandString:
+ case RegistryValueKind.String: {
+ string value = (string)categoryKey.GetValue(optionName);
+ if(value.Length == 0) {
+ return typeof(string);
+ }
+
+ // If there are at least two characters, it may be an integer with
+ // a sign in front of it
+ if(value.Length >= 2) {
+ int index = 0;
+ if(ParserHelper.SkipInteger(value, ref index)) {
+ if(index >= value.Length) {
+ return typeof(int);
+ }
+ if(value[index] == '.') {
+ return typeof(float);
+ }
+ }
+ } else { // If it's just a single character, it may be a number
+ if(char.IsNumber(value, 0)) {
+ return typeof(int);
+ }
+ }
+
+ // If it parses as a boolean literal, then it must be a boolean
+ if(ParserHelper.ParseBooleanLiteral(value) != null) {
+ return typeof(bool);
+ }
+
+ return typeof(string);
+ }
+
+ case RegistryValueKind.Unknown:
+ case RegistryValueKind.None:
+ default: { return typeof(string); }
+ }
+ }
+
+ /// Key on which the registry store is operating
+ private RegistryKey rootKey;
+ /// Whether the user can write to the registry key
+ private bool writable;
+
}
} // namespace Nuclex.Support.Settings
diff --git a/Source/WeakReference.cs b/Source/WeakReference.cs
index f5b7e34..7c62959 100644
--- a/Source/WeakReference.cs
+++ b/Source/WeakReference.cs
@@ -31,15 +31,15 @@ namespace Nuclex.Support {
#if !NO_SERIALIZATION
[Serializable]
#endif
- public class WeakReference : WeakReference
- where ReferencedType : class {
+ public class WeakReference : WeakReference
+ where TReferenced : class {
///
/// Initializes a new instance of the WeakReference class, referencing
/// the specified object.
///
/// The object to track or null.
- public WeakReference(ReferencedType target) :
+ public WeakReference(TReferenced target) :
base(target) { }
///
@@ -51,7 +51,7 @@ namespace Nuclex.Support {
/// Indicates when to stop tracking the object. If true, the object is tracked
/// after finalization; if false, the object is only tracked until finalization.
///
- public WeakReference(ReferencedType target, bool trackResurrection) :
+ public WeakReference(TReferenced target, bool trackResurrection) :
base(target, trackResurrection) { }
#if !NO_SERIALIZATION
@@ -89,8 +89,8 @@ namespace Nuclex.Support {
/// The reference to the target object is invalid. This can occur if the current
/// System.WeakReference object has been finalized
///
- public new ReferencedType Target {
- get { return (base.Target as ReferencedType); }
+ public new TReferenced Target {
+ get { return (base.Target as TReferenced); }
set { base.Target = value; }
}