Override FieldLoader to not crash on invalid input; Implemented for settings loading.

This commit is contained in:
Paul Chote
2010-07-11 17:52:01 +12:00
parent af71f564e9
commit d680956b02
2 changed files with 69 additions and 15 deletions

View File

@@ -27,6 +27,16 @@ namespace OpenRA.FileFormats
{
public static class FieldLoader
{
public static Func<string,Type,string,object> InvalidValueAction = (s,t,f) =>
{
throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s,f,t) );
};
public static Action<string,Type> UnknownFieldAction = (s,f) =>
{
throw new NotImplementedException( "FieldLoader: Missing field `{0}` on `{1}`".F( s, f.Name ) );
};
public static void Load(object self, IniSection ini)
{
foreach (var x in ini)
@@ -59,22 +69,39 @@ namespace OpenRA.FileFormats
public static void LoadField( object self, string key, string value )
{
var field = self.GetType().GetField( key.Trim() );
if( field == null )
throw new NotImplementedException( "Missing field `{0}` on `{1}`".F( key.Trim(), self.GetType().Name ) );
field.SetValue( self, GetValue( field.FieldType, value ) );
UnknownFieldAction(key.Trim(), self.GetType());
else
field.SetValue( self, GetValue( field.Name, field.FieldType, value ) );
}
public static object GetValue( Type fieldType, string x )
public static object GetValue( string field, Type fieldType, string x )
{
if (x != null) x = x.Trim();
if( fieldType == typeof( int ) )
return int.Parse( x );
{
int res;
if (int.TryParse(x,out res))
return res;
return InvalidValueAction(x,fieldType, field);
}
else if( fieldType == typeof( ushort ) )
return ushort.Parse( x );
{
ushort res;
if (ushort.TryParse(x,out res))
return res;
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(float))
return float.Parse(x.Replace("%","")) * (x.Contains( '%' ) ? 0.01f : 1f);
{
float res;
if (float.TryParse(x.Replace("%",""), out res))
return res * (x.Contains( '%' ) ? 0.01f : 1f);
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(string))
return x;
@@ -82,14 +109,21 @@ namespace OpenRA.FileFormats
else if (fieldType == typeof(System.Drawing.Color))
{
var parts = x.Split(',');
if (parts.Length != 3)
return InvalidValueAction(x,fieldType, field);
return System.Drawing.Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
}
else if (fieldType.IsEnum)
{
if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower()))
return InvalidValueAction(x,fieldType, field);
return Enum.Parse(fieldType, x, true);
}
else if (fieldType == typeof(bool))
return ParseYesNo(x);
return ParseYesNo(x, fieldType, field);
else if (fieldType.IsArray)
{
@@ -100,7 +134,7 @@ namespace OpenRA.FileFormats
var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length);
for (int i = 0; i < parts.Length; i++)
ret.SetValue(GetValue(fieldType.GetElementType(), parts[i].Trim()), i);
ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i);
return ret;
}
else if (fieldType == typeof(int2))
@@ -108,18 +142,19 @@ namespace OpenRA.FileFormats
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new int2(int.Parse(parts[0]), int.Parse(parts[1]));
}
else
throw new InvalidOperationException("FieldLoader: don't know how to load field of type " + fieldType.ToString());
UnknownFieldAction("[Type] {0}".F(x),fieldType);
return null;
}
static bool ParseYesNo( string p )
static object ParseYesNo( string p, System.Type fieldType, string field )
{
p = p.ToLowerInvariant();
if( p == "yes" ) return true;
if( p == "true" ) return true;
if( p == "no" ) return false;
if( p == "false" ) return false;
throw new InvalidOperationException();
return InvalidValueAction(p,fieldType, field);
}
}

View File

@@ -69,6 +69,22 @@ namespace OpenRA.GameRules
defaults = new UserSettings();
SettingsFile = Game.SupportDir + "settings.yaml";
// Override settings loading to not crash
var err1 = FieldLoader.UnknownFieldAction;
var err2 = FieldLoader.InvalidValueAction;
FieldLoader.InvalidValueAction = (s,t,f) =>
{
object ret = defaults.GetType().GetField(f).GetValue(defaults);
System.Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) );
return ret;
};
FieldLoader.UnknownFieldAction = (s,f) =>
{
System.Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
};
if (File.Exists(SettingsFile))
{
System.Console.WriteLine("Loading settings file {0}",SettingsFile);
@@ -79,6 +95,9 @@ namespace OpenRA.GameRules
foreach (var f in this.GetType().GetFields())
if (args.Contains(f.Name))
OpenRA.FileFormats.FieldLoader.LoadField( this, f.Name, args.GetValue(f.Name, "") );
FieldLoader.UnknownFieldAction = err1;
FieldLoader.InvalidValueAction = err2;
}
public void Save()