Files
OpenRA/OpenRA.Game/FieldSaver.cs
RoosterDragon d11e60474a Ensure the elements of arrays and sets are formatted correctly in FormatValue.
We call FormatValue on each element to ensure correct culture and other formatting that would otherwise not be applied.
2015-08-28 19:39:25 +01:00

124 lines
3.2 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.Linq;
using System.Reflection;
namespace OpenRA
{
public static class FieldSaver
{
public static MiniYaml Save(object o, bool includePrivateByDefault = false)
{
var nodes = new List<MiniYamlNode>();
string root = null;
foreach (var info in FieldLoader.GetTypeLoadInfo(o.GetType(), includePrivateByDefault))
{
if (info.Attribute.FromYamlKey)
root = FormatValue(o, info.Field);
else
nodes.Add(new MiniYamlNode(info.YamlName, FormatValue(o, info.Field)));
}
return new MiniYaml(root, nodes);
}
public static MiniYaml SaveDifferences(object o, object from, bool includePrivateByDefault = false)
{
if (o.GetType() != from.GetType())
throw new InvalidOperationException("FieldLoader: can't diff objects of different types");
var fields = FieldLoader.GetTypeLoadInfo(o.GetType(), includePrivateByDefault)
.Where(info => FormatValue(o, info.Field) != FormatValue(from, info.Field));
return new MiniYaml(
null,
fields.Select(info => new MiniYamlNode(info.YamlName, FormatValue(o, info.Field))).ToList());
}
public static MiniYamlNode SaveField(object o, string field)
{
return new MiniYamlNode(field, FormatValue(o, o.GetType().GetField(field)));
}
public static string FormatValue(object v)
{
if (v == null)
return "";
var t = v.GetType();
// Color.ToString() does the wrong thing; force it to format as an array
if (t == typeof(Color))
{
var c = (Color)v;
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
((int)c.R).Clamp(0, 255),
((int)c.G).Clamp(0, 255),
((int)c.B).Clamp(0, 255));
}
if (t == typeof(ImageFormat))
{
return ((ImageFormat)v).ToString();
}
if (t == typeof(Rectangle))
{
var r = (Rectangle)v;
return "{0},{1},{2},{3}".F(r.X, r.Y, r.Width, r.Height);
}
if (t.IsArray && t.GetArrayRank() == 1)
{
return ((Array)v).Cast<object>().Select(FormatValue).JoinWith(", ");
}
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(HashSet<>))
{
return ((System.Collections.IEnumerable)v).Cast<object>().Select(FormatValue).JoinWith(", ");
}
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(OpenRA.Primitives.Cache<,>))
return ""; // TODO
if (t == typeof(DateTime))
return ((DateTime)v).ToString("yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture);
// Try the TypeConverter
var conv = TypeDescriptor.GetConverter(t);
if (conv.CanConvertTo(typeof(string)))
{
try
{
return conv.ConvertToInvariantString(v);
}
catch
{
}
}
return v.ToString();
}
public static string FormatValue(object o, FieldInfo f)
{
return FormatValue(f.GetValue(o));
}
}
}