Roblox-File-Format/XmlFormat/XmlPropertyTokens.cs
CloneTrooper1019 de8df15d3f Large scale refactor to add class support!
Instance classes are now strongly typed with real property fields that
are derived from the JSON API Dump! This required a lot of reworking
across the board:

- Classes and Enums are auto-generated in the 'Generated' folder now.
This is done using a custom built-in plugin, which can be found in
the Plugins folder of this project.
- Property objects are now tied to .NET's reflection system. Reading
and writing from them will try to redirect into a field of the
Instance they are bound to.
- Property types that were loosely defined now have proper data types
(such as Color3uint8, Content, ProtectedString, SharedString, etc)
- Fixed an error with the CFrame directional vectors.
- The binary PRNT chunk now writes instances in child->parent order.
- Enums are now generated correctly, with up-to-date values.
- INST chunks are now referred to as 'Classes' instead of 'Types'.
- Unary operator added to Vector2 and Vector3.
- CollectionService tags can now be manipulated per-instance using
the Instance.Tags member.
- The Instance.Archivable property now works correctly.
- XML files now save/load metadata correctly.
- Cleaned up the property tokens directory.

I probably missed a few things, but that's a general overview of
everything that changed.
2019-06-30 17:01:19 -05:00

106 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Xml;
namespace RobloxFiles.XmlFormat
{
public static class XmlPropertyTokens
{
public static IReadOnlyDictionary<string, IXmlPropertyToken> Handlers;
static XmlPropertyTokens()
{
// Initialize the PropertyToken handler singletons.
Type IXmlPropertyToken = typeof(IXmlPropertyToken);
var handlerTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(type => type != IXmlPropertyToken)
.Where(type => IXmlPropertyToken.IsAssignableFrom(type));
var propTokens = handlerTypes.Select(handlerType => Activator.CreateInstance(handlerType) as IXmlPropertyToken);
var tokenHandlers = new Dictionary<string, IXmlPropertyToken>();
foreach (IXmlPropertyToken propToken in propTokens)
{
var tokens = propToken.Token.Split(';')
.Select(token => token.Trim())
.ToList();
tokens.ForEach(token => tokenHandlers.Add(token, propToken));
}
Handlers = tokenHandlers;
}
public static bool ReadPropertyGeneric<T>(XmlNode token, out T outValue) where T : struct
{
try
{
string value = token.InnerText;
Type type = typeof(T);
object result = null;
if (type == typeof(int))
result = Formatting.ParseInt(value);
else if (type == typeof(float))
result = Formatting.ParseFloat(value);
else if (type == typeof(double))
result = Formatting.ParseDouble(value);
if (result == null)
{
Type resultType = typeof(T);
var converter = TypeDescriptor.GetConverter(resultType);
result = converter.ConvertFromString(token.InnerText);
}
outValue = (T)result;
return true;
}
catch
{
outValue = default(T);
return false;
}
}
public static bool ReadPropertyGeneric<T>(Property prop, PropertyType propType, XmlNode token) where T : struct
{
T result;
if (ReadPropertyGeneric(token, out result))
{
prop.Type = propType;
prop.Value = result;
return true;
}
return false;
}
public static IXmlPropertyToken GetHandler(string tokenName)
{
IXmlPropertyToken result = null;
if (Handlers.ContainsKey(tokenName))
result = Handlers[tokenName];
return result;
}
public static T GetHandler<T>() where T : IXmlPropertyToken
{
IXmlPropertyToken result = Handlers.Values
.Where(token => token is T)
.First();
return (T)result;
}
}
}