10
10
11
11
namespace Salaros . Configuration
12
12
{
13
- public class ConfigParser
13
+ public partial class ConfigParser
14
14
{
15
15
private static readonly ILog Logger = LogProvider . GetCurrentClassLogger ( ) ;
16
16
protected readonly ConfigSection fileHeader ;
@@ -48,18 +48,19 @@ static ConfigParser()
48
48
public ConfigParser ( ConfigParserSettings settings = null )
49
49
{
50
50
Settings = settings ?? new ConfigParserSettings ( ) ;
51
+ NullSection = new NullConfigSection ( this ) ;
51
52
52
53
fileHeader = new ConfigSection ( ) ;
53
54
sections = new Dictionary < string , ConfigSection > ( ) ;
54
55
}
55
56
56
57
/// <inheritdoc />
57
58
/// <summary>
58
- /// Initializes a new instance of the <see cref="T: Salaros.Configuration.ConfigParser" /> class.
59
+ /// Initializes a new instance of the <see cref="Salaros.Configuration.ConfigParser" /> class.
59
60
/// </summary>
60
61
/// <param name="configFile">The configuration file (may be path or file content).</param>
61
62
/// <param name="settings">The settings.</param>
62
- /// <exception cref="T: System.ArgumentException">configFilePath</exception>
63
+ /// <exception cref="System.ArgumentException">configFilePath</exception>
63
64
public ConfigParser ( string configFile , ConfigParserSettings settings = null )
64
65
: this ( settings )
65
66
{
@@ -111,16 +112,25 @@ public ConfigParser(string configFile, ConfigParserSettings settings = null)
111
112
/// <value>
112
113
/// The sections.
113
114
/// </value>
114
- public ReadOnlyCollection < ConfigSection > Sections =>
115
- new ReadOnlyCollection < ConfigSection > ( sections . Values . ToArray ( ) ) ;
115
+ #if NET40
116
+ public ReadOnlyCollection < ConfigSection > Sections => new ReadOnlyCollection < ConfigSection > (
117
+ #else
118
+ public IReadOnlyCollection < ConfigSection > Sections => new Collection < ConfigSection > (
119
+ #endif
120
+ sections . Values . ToList ( ) ) ;
116
121
117
122
/// <summary>
118
123
/// Gets configuration file's lines.
119
124
/// </summary>
120
125
/// <value>The lines.</value>
121
- public ReadOnlyCollection < IConfigLine > Lines
122
- => new ReadOnlyCollection < IConfigLine > ( fileHeader . Lines . Concat ( sections . Values . SelectMany ( s => s . Lines ) )
123
- . ToArray ( ) ) ;
126
+ #if NET40
127
+ public ReadOnlyCollection < IConfigLine > Lines => new ReadOnlyCollection < IConfigLine > (
128
+ #else
129
+ public IReadOnlyCollection < IConfigLine > Lines => new Collection < IConfigLine > (
130
+ #endif
131
+ fileHeader . Lines . Concat ( sections . Values . SelectMany ( s => s . Lines ) ) . ToList ( ) ) ;
132
+
133
+ public NullConfigSection NullSection { get ; }
124
134
125
135
#endregion Properties
126
136
@@ -143,19 +153,20 @@ public ReadOnlyCollection<IConfigLine> Lines
143
153
/// </exception>
144
154
internal virtual bool TryGetValue < T > ( string sectionName , string keyName , out T value )
145
155
{
146
- if ( string . IsNullOrWhiteSpace ( sectionName ) )
156
+ if ( sectionName is null )
147
157
throw new ArgumentNullException ( nameof ( sectionName ) ) ;
158
+
148
159
if ( string . IsNullOrWhiteSpace ( keyName ) )
149
- throw new ArgumentNullException ( nameof ( keyName ) ) ;
160
+ throw new ArgumentException ( "Key name must be a non-empty string." , nameof ( keyName ) ) ;
150
161
151
162
#pragma warning disable IDE0034 // Simplify 'default' expression
152
163
value = default ( T ) ;
153
164
#pragma warning restore IDE0034 // Simplify 'default' expression
154
165
155
166
if ( ! sections . TryGetValue ( sectionName , out var section ) )
156
- return false ;
167
+ section = null ;
157
168
158
- var key = section . Keys . FirstOrDefault ( k => Equals ( keyName , k . Name ) ) ;
169
+ var key = ( section ?? fileHeader ? . Section ) . Keys . FirstOrDefault ( k => Equals ( keyName , k . Name ) ) ;
159
170
if ( key == null )
160
171
return false ;
161
172
@@ -173,13 +184,13 @@ internal virtual bool TryGetValue<T>(string sectionName, string keyName, out T v
173
184
/// <typeparam name="T">The 1st type parameter.</typeparam>
174
185
internal virtual T GetRawValue < T > ( string sectionName , string keyName , T defaultValue )
175
186
{
176
- if ( string . IsNullOrWhiteSpace ( sectionName ) )
187
+ if ( sectionName is null )
177
188
throw new ArgumentNullException ( nameof ( sectionName ) ) ;
189
+
178
190
if ( string . IsNullOrWhiteSpace ( keyName ) )
179
- throw new ArgumentNullException ( nameof ( keyName ) ) ;
191
+ throw new ArgumentException ( "Key name must be a non-empty string." , nameof ( keyName ) ) ;
180
192
181
193
var iniKey = new ConfigKeyValue < T > ( keyName , Settings . KeyValueSeparator , defaultValue , - 1 ) ;
182
-
183
194
if ( ! sections . TryGetValue ( sectionName , out var section ) )
184
195
{
185
196
section = new ConfigSection ( sectionName , Lines . Any ( ) ? Lines . Max ( l => l . LineNumber ) : 0 ) ;
@@ -188,11 +199,14 @@ internal virtual T GetRawValue<T>(string sectionName, string keyName, T defaultV
188
199
sections . Add ( sectionName , section ) ;
189
200
}
190
201
191
- var key = section . Keys . FirstOrDefault ( k => Equals ( keyName , k . Name ) ) ;
202
+ var key = ( section ?? fileHeader ? . Section ) . Keys . FirstOrDefault ( k => Equals ( keyName , k . Name ) ) ;
192
203
if ( key != null )
193
204
return ( T ) key . ValueRaw ;
194
205
195
- section . AddLine ( iniKey ) ;
206
+ if ( section is null && Settings . MultiLineValues . HasFlag ( MultiLineValues . AllowEmptyTopSection ) )
207
+ section = fileHeader . Section ;
208
+
209
+ section ? . AddLine ( iniKey ) ;
196
210
return defaultValue ;
197
211
}
198
212
@@ -421,7 +435,7 @@ public virtual bool ValueIsArray(string sectionName, string keyName)
421
435
return values . Any ( ) && string . IsNullOrWhiteSpace ( values . First ( ) ) ;
422
436
}
423
437
424
- #endregion
438
+ #endregion
425
439
426
440
#region SetValue
427
441
@@ -540,7 +554,7 @@ public virtual bool SetValue(string sectionName, string keyName, byte[] value)
540
554
return SetValue ( sectionName , keyName , EncodeByteArray ( value ) ) ;
541
555
}
542
556
543
- #endregion
557
+ #endregion SetValue
544
558
545
559
#region Indexing
546
560
@@ -564,7 +578,7 @@ public ConfigSection this[string sectionName]
564
578
}
565
579
}
566
580
567
- #endregion
581
+ #endregion Indexing
568
582
569
583
/// <summary>
570
584
/// Save configuration file's content.
@@ -641,7 +655,7 @@ public override string ToString()
641
655
) ;
642
656
}
643
657
644
- #endregion
658
+ #endregion Methods
645
659
646
660
#region Helpers
647
661
@@ -819,10 +833,17 @@ private void ReadKeyAndValue(ref ConfigSection currentSection, ref ConfigLine cu
819
833
throw new ConfigParserException ( "Unknown key=value situation detected!" , lineNumber ) ;
820
834
}
821
835
822
- if ( append )
823
- currentLine . Content = $ "{ currentLine . Content } { Settings . NewLine } { value } ";
824
- else
825
- currentLine = new ConfigKeyValue < object > ( keyName , separator , value , lineNumber ) ;
836
+ try
837
+ {
838
+ if ( append )
839
+ currentLine . Content = $ "{ currentLine . Content } { Settings . NewLine } { value } ";
840
+ else
841
+ currentLine = new ConfigKeyValue < object > ( keyName , separator , value , lineNumber ) ;
842
+ }
843
+ catch ( Exception ex )
844
+ {
845
+ throw new ConfigParserException ( $ "Failed to parse the following line: '{ lineRaw } '", lineNumber , ex ) ;
846
+ }
826
847
}
827
848
828
849
/// <summary>
0 commit comments