Added support for saving XML files!
Support for binary files will be coming later.
This commit is contained in:
parent
45a84e34d0
commit
34642f5656
@ -100,5 +100,10 @@ namespace RobloxFiles.BinaryFormat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteFile(Stream stream)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Not implemented yet!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -12,6 +13,8 @@ namespace RobloxFiles
|
|||||||
public interface IRobloxFile
|
public interface IRobloxFile
|
||||||
{
|
{
|
||||||
Instance Contents { get; }
|
Instance Contents { get; }
|
||||||
|
|
||||||
void ReadFile(byte[] buffer);
|
void ReadFile(byte[] buffer);
|
||||||
|
void WriteFile(Stream stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ namespace RobloxFiles.XmlFormat
|
|||||||
public interface IXmlPropertyToken
|
public interface IXmlPropertyToken
|
||||||
{
|
{
|
||||||
string Token { get; }
|
string Token { get; }
|
||||||
bool ReadToken(Property prop, XmlNode token);
|
|
||||||
|
bool ReadProperty(Property prop, XmlNode token);
|
||||||
|
void WriteProperty(Property prop, XmlDocument doc, XmlNode node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,11 @@ namespace RobloxFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteFile(Stream stream)
|
||||||
|
{
|
||||||
|
InnerFile.WriteFile(stream);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a RobloxFile from a provided byte sequence that represents the file.
|
/// Creates a RobloxFile from a provided byte sequence that represents the file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -97,11 +97,13 @@
|
|||||||
<Compile Include="DataTypes\UDim2.cs" />
|
<Compile Include="DataTypes\UDim2.cs" />
|
||||||
<Compile Include="DataTypes\Vector2.cs" />
|
<Compile Include="DataTypes\Vector2.cs" />
|
||||||
<Compile Include="DataTypes\Vector3.cs" />
|
<Compile Include="DataTypes\Vector3.cs" />
|
||||||
|
<Compile Include="Utility\Formatting.cs" />
|
||||||
<Compile Include="Utility\MaterialInfo.cs" />
|
<Compile Include="Utility\MaterialInfo.cs" />
|
||||||
<Compile Include="Utility\Quaternion.cs" />
|
<Compile Include="Utility\Quaternion.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="XmlFormat\PropertyTokens\SharedString.cs" />
|
<Compile Include="XmlFormat\PropertyTokens\SharedString.cs" />
|
||||||
<Compile Include="XmlFormat\PropertyTokens\Vector3int16.cs" />
|
<Compile Include="XmlFormat\PropertyTokens\Vector3int16.cs" />
|
||||||
|
<Compile Include="XmlFormat\XmlDataWriter.cs" />
|
||||||
<Compile Include="XmlFormat\XmlPropertyTokens.cs" />
|
<Compile Include="XmlFormat\XmlPropertyTokens.cs" />
|
||||||
<Compile Include="XmlFormat\XmlDataReader.cs" />
|
<Compile Include="XmlFormat\XmlDataReader.cs" />
|
||||||
<Compile Include="XmlFormat\XmlRobloxFile.cs" />
|
<Compile Include="XmlFormat\XmlRobloxFile.cs" />
|
||||||
|
@ -12,11 +12,11 @@ namespace RobloxFiles
|
|||||||
public class Instance
|
public class Instance
|
||||||
{
|
{
|
||||||
/// <summary>The ClassName of this Instance.</summary>
|
/// <summary>The ClassName of this Instance.</summary>
|
||||||
public readonly string ClassName;
|
public string ClassName;
|
||||||
|
|
||||||
/// <summary>A list of properties that are defined under this Instance.</summary>
|
/// <summary>A list of properties that are defined under this Instance.</summary>
|
||||||
public Dictionary<string, Property> Properties = new Dictionary<string, Property>();
|
public Dictionary<string, Property> Properties = new Dictionary<string, Property>();
|
||||||
|
|
||||||
private List<Instance> Children = new List<Instance>();
|
private List<Instance> Children = new List<Instance>();
|
||||||
private Instance rawParent;
|
private Instance rawParent;
|
||||||
|
|
||||||
@ -24,6 +24,8 @@ namespace RobloxFiles
|
|||||||
public string Name => ReadProperty("Name", ClassName);
|
public string Name => ReadProperty("Name", ClassName);
|
||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
|
|
||||||
|
internal string XmlReferent;
|
||||||
|
|
||||||
/// <summary>Creates an instance using the provided ClassName.</summary>
|
/// <summary>Creates an instance using the provided ClassName.</summary>
|
||||||
/// <param name="className">The ClassName to use for this Instance.</param>
|
/// <param name="className">The ClassName to use for this Instance.</param>
|
||||||
public Instance(string className = "Instance")
|
public Instance(string className = "Instance")
|
||||||
@ -292,7 +294,7 @@ namespace RobloxFiles
|
|||||||
/// This is used during the file loading procedure.
|
/// This is used during the file loading procedure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="prop">A reference to the property that will be added.</param>
|
/// <param name="prop">A reference to the property that will be added.</param>
|
||||||
public void AddProperty(ref Property prop)
|
internal void AddProperty(ref Property prop)
|
||||||
{
|
{
|
||||||
Properties.Add(prop.Name, prop);
|
Properties.Add(prop.Name, prop);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ namespace RobloxFiles
|
|||||||
PhysicalProperties,
|
PhysicalProperties,
|
||||||
Color3uint8,
|
Color3uint8,
|
||||||
Int64,
|
Int64,
|
||||||
SharedString
|
SharedString,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Property
|
public class Property
|
||||||
@ -44,7 +44,9 @@ namespace RobloxFiles
|
|||||||
public PropertyType Type;
|
public PropertyType Type;
|
||||||
public object Value;
|
public object Value;
|
||||||
|
|
||||||
|
public string XmlToken = "";
|
||||||
private byte[] RawBuffer = null;
|
private byte[] RawBuffer = null;
|
||||||
|
|
||||||
public bool HasRawBuffer
|
public bool HasRawBuffer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
108
Utility/Formatting.cs
Normal file
108
Utility/Formatting.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
// This global class defines extension methods to numeric types
|
||||||
|
// where I don't want system globalization to come into play.
|
||||||
|
|
||||||
|
internal static class Formatting
|
||||||
|
{
|
||||||
|
private static CultureInfo invariant => CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
|
public static string ToInvariantString(this float value)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
|
||||||
|
if (float.IsPositiveInfinity(value))
|
||||||
|
result = "INF";
|
||||||
|
else if (float.IsNegativeInfinity(value))
|
||||||
|
result = "-INF";
|
||||||
|
else if (float.IsNaN(value))
|
||||||
|
result = "NAN";
|
||||||
|
else
|
||||||
|
result = value.ToString(invariant);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToInvariantString(this double value)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
|
||||||
|
if (double.IsPositiveInfinity(value))
|
||||||
|
result = "INF";
|
||||||
|
else if (double.IsNegativeInfinity(value))
|
||||||
|
result = "-INF";
|
||||||
|
else if (double.IsNaN(value))
|
||||||
|
result = "NAN";
|
||||||
|
else
|
||||||
|
result = value.ToString(invariant);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToInvariantString(this int value)
|
||||||
|
{
|
||||||
|
return value.ToString(invariant);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToInvariantString(this object value)
|
||||||
|
{
|
||||||
|
if (value is float)
|
||||||
|
{
|
||||||
|
float f = (float)value;
|
||||||
|
return f.ToInvariantString();
|
||||||
|
}
|
||||||
|
else if (value is double)
|
||||||
|
{
|
||||||
|
double d = (double)value;
|
||||||
|
return d.ToInvariantString();
|
||||||
|
}
|
||||||
|
else if (value is int)
|
||||||
|
{
|
||||||
|
int i = (int)value;
|
||||||
|
return i.ToInvariantString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Unhandled
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float ParseFloat(string value)
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
|
||||||
|
if (value == "INF")
|
||||||
|
result = float.PositiveInfinity;
|
||||||
|
else if (value == "-INF")
|
||||||
|
result = float.NegativeInfinity;
|
||||||
|
else if (value == "NAN")
|
||||||
|
result = float.NaN;
|
||||||
|
else
|
||||||
|
result = float.Parse(value, invariant);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ParseDouble(string value)
|
||||||
|
{
|
||||||
|
double result;
|
||||||
|
|
||||||
|
if (value == "INF")
|
||||||
|
result = double.PositiveInfinity;
|
||||||
|
else if (value == "-INF")
|
||||||
|
result = double.NegativeInfinity;
|
||||||
|
else if (value == "NAN")
|
||||||
|
result = double.NaN;
|
||||||
|
else
|
||||||
|
result = double.Parse(value, invariant);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ParseInt(string s)
|
||||||
|
{
|
||||||
|
return int.Parse(s, invariant);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -6,10 +7,9 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
public class AxesToken : IXmlPropertyToken
|
public class AxesToken : IXmlPropertyToken
|
||||||
{
|
{
|
||||||
public string Token => "Axes";
|
public string Token => "Axes";
|
||||||
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
|
||||||
{
|
{
|
||||||
bool success = XmlPropertyTokens.ReadTokenGeneric<uint>(prop, PropertyType.Axes, token);
|
bool success = XmlPropertyTokens.ReadPropertyGeneric<uint>(prop, PropertyType.Axes, token);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@ -27,5 +27,14 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
XmlElement axes = doc.CreateElement("axes");
|
||||||
|
node.AppendChild(axes);
|
||||||
|
|
||||||
|
int value = (int)prop.Value;
|
||||||
|
axes.InnerText = value.ToInvariantString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "BinaryString";
|
public string Token => "BinaryString";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
// BinaryStrings are encoded in base64
|
// BinaryStrings are encoded in base64
|
||||||
string base64 = token.InnerText;
|
string base64 = token.InnerText.Replace("\n", "");
|
||||||
prop.Type = PropertyType.String;
|
prop.Type = PropertyType.String;
|
||||||
prop.Value = base64;
|
prop.Value = base64;
|
||||||
|
|
||||||
@ -19,5 +19,28 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
byte[] data = prop.GetRawBuffer();
|
||||||
|
string value = Convert.ToBase64String(data);
|
||||||
|
|
||||||
|
if (value.Length > 72)
|
||||||
|
{
|
||||||
|
string buffer = "";
|
||||||
|
|
||||||
|
while (value.Length > 72)
|
||||||
|
{
|
||||||
|
string chunk = value.Substring(0, 72);
|
||||||
|
value = value.Substring(72);
|
||||||
|
buffer += chunk + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
value = buffer + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlCDataSection cdata = doc.CreateCDataSection(value);
|
||||||
|
node.AppendChild(cdata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,18 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "bool";
|
public string Token => "bool";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
return XmlPropertyTokens.ReadTokenGeneric<bool>(prop, PropertyType.Bool, token);
|
return XmlPropertyTokens.ReadPropertyGeneric<bool>(prop, PropertyType.Bool, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
string boolString = prop.Value
|
||||||
|
.ToString()
|
||||||
|
.ToLower();
|
||||||
|
|
||||||
|
node.InnerText = boolString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -10,16 +11,18 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
// Since BrickColors are written as ints, the IntToken class will try to redirect
|
// Since BrickColors are written as ints, the IntToken class will try to redirect
|
||||||
// to this handler if it believes that its representing a BrickColor.
|
// to this handler if it believes that its representing a BrickColor.
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
bool success = XmlPropertyTokens.ReadTokenGeneric<int>(prop, PropertyType.BrickColor, token);
|
bool success = XmlPropertyTokens.ReadPropertyGeneric<int>(prop, PropertyType.BrickColor, token);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
int value = (int)prop.Value;
|
int value = (int)prop.Value;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
BrickColor brickColor = BrickColor.FromNumber(value);
|
BrickColor brickColor = BrickColor.FromNumber(value);
|
||||||
|
prop.XmlToken = "BrickColor";
|
||||||
prop.Value = brickColor;
|
prop.Value = brickColor;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -28,8 +31,19 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
BrickColor value = prop.Value as BrickColor;
|
||||||
|
|
||||||
|
XmlElement brickColor = doc.CreateElement("int");
|
||||||
|
brickColor.InnerText = value.Number.ToInvariantString();
|
||||||
|
|
||||||
|
brickColor.SetAttribute("name", prop.Name);
|
||||||
|
brickColor.AppendChild(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coord = token[key];
|
var coord = token[key];
|
||||||
components[i] = float.Parse(coord.InnerText);
|
components[i] = Formatting.ParseFloat(coord.InnerText);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -30,18 +30,35 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
return new CFrame(components);
|
return new CFrame(components);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ReadToken(Property property, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
CFrame result = ReadCFrame(token);
|
CFrame result = ReadCFrame(token);
|
||||||
bool success = (result != null);
|
bool success = (result != null);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
property.Type = PropertyType.CFrame;
|
prop.Type = PropertyType.CFrame;
|
||||||
property.Value = result;
|
prop.Value = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
CFrame cf = prop.Value as CFrame;
|
||||||
|
float[] components = cf.GetComponents();
|
||||||
|
|
||||||
|
for (int i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
string coordName = Coords[i];
|
||||||
|
float coordValue = components[i];
|
||||||
|
|
||||||
|
XmlElement coord = doc.CreateElement(coordName);
|
||||||
|
coord.InnerText = coordValue.ToInvariantString();
|
||||||
|
|
||||||
|
node.AppendChild(coord);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
public string Token => "Color3";
|
public string Token => "Color3";
|
||||||
private string[] Fields = new string[3] { "R", "G", "B" };
|
private string[] Fields = new string[3] { "R", "G", "B" };
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
float[] fields = new float[Fields.Length];
|
float[] fields = new float[Fields.Length];
|
||||||
@ -21,7 +21,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coord = token[key];
|
var coord = token[key];
|
||||||
fields[i] = XmlPropertyTokens.ParseFloat(coord.InnerText);
|
fields[i] = Formatting.ParseFloat(coord.InnerText);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -43,10 +43,35 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
// Try falling back to the Color3uint8 technique...
|
// Try falling back to the Color3uint8 technique...
|
||||||
var color3uint8 = XmlPropertyTokens.GetHandler<Color3uint8Token>();
|
var color3uint8 = XmlPropertyTokens.GetHandler<Color3uint8Token>();
|
||||||
success = color3uint8.ReadToken(prop, token);
|
success = color3uint8.ReadProperty(prop, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
if (prop.Name == "Color3uint8")
|
||||||
|
{
|
||||||
|
var handler = XmlPropertyTokens.GetHandler<Color3uint8Token>();
|
||||||
|
handler.WriteProperty(prop, doc, node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Color3 color = prop.Value as Color3;
|
||||||
|
float[] rgb = new float[3] { color.R, color.G, color.B };
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
string field = Fields[i];
|
||||||
|
float value = rgb[i];
|
||||||
|
|
||||||
|
XmlElement channel = doc.CreateElement(field);
|
||||||
|
channel.InnerText = value.ToInvariantString();
|
||||||
|
|
||||||
|
node.AppendChild(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "Color3uint8";
|
public string Token => "Color3uint8";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
bool success = XmlPropertyTokens.ReadTokenGeneric<uint>(prop, PropertyType.Color3, token);
|
bool success = XmlPropertyTokens.ReadPropertyGeneric<uint>(prop, PropertyType.Color3, token);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@ -25,5 +25,17 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
Color3 color = prop.Value as Color3;
|
||||||
|
|
||||||
|
uint r = (uint)(color.R * 256);
|
||||||
|
uint g = (uint)(color.G * 256);
|
||||||
|
uint b = (uint)(color.B * 256);
|
||||||
|
|
||||||
|
uint rgb = (255u << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
node.InnerText = rgb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "ColorSequence";
|
public string Token => "ColorSequence";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
string contents = token.InnerText.Trim();
|
string contents = token.InnerText.Trim();
|
||||||
string[] buffer = contents.Split(' ');
|
string[] buffer = contents.Split(' ');
|
||||||
@ -23,11 +23,11 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
for (int i = 0; i < length; i += 5)
|
for (int i = 0; i < length; i += 5)
|
||||||
{
|
{
|
||||||
float Time = float.Parse(buffer[i]);
|
float Time = Formatting.ParseFloat(buffer[i]);
|
||||||
|
|
||||||
float R = float.Parse(buffer[i + 1]);
|
float R = Formatting.ParseFloat(buffer[i + 1]);
|
||||||
float G = float.Parse(buffer[i + 2]);
|
float G = Formatting.ParseFloat(buffer[i + 2]);
|
||||||
float B = float.Parse(buffer[i + 3]);
|
float B = Formatting.ParseFloat(buffer[i + 3]);
|
||||||
|
|
||||||
Color3 Value = new Color3(R, G, B);
|
Color3 Value = new Color3(R, G, B);
|
||||||
keypoints[i / 5] = new ColorSequenceKeypoint(Time, Value);
|
keypoints[i / 5] = new ColorSequenceKeypoint(Time, Value);
|
||||||
@ -44,5 +44,10 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
node.InnerText = prop.Value.ToString() + ' ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "Content";
|
public string Token => "Content";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
string content = token.InnerText;
|
string content = token.InnerText;
|
||||||
prop.Type = PropertyType.String;
|
prop.Type = PropertyType.String;
|
||||||
@ -28,5 +28,21 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
string content = prop.Value.ToString();
|
||||||
|
string type = "null";
|
||||||
|
|
||||||
|
if (prop.HasRawBuffer)
|
||||||
|
type = "binary";
|
||||||
|
else if (content.Length > 0)
|
||||||
|
type = "url";
|
||||||
|
|
||||||
|
XmlElement contentType = doc.CreateElement(type);
|
||||||
|
contentType.InnerText = content;
|
||||||
|
|
||||||
|
node.AppendChild(contentType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,14 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "double";
|
public string Token => "double";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
return XmlPropertyTokens.ReadTokenGeneric<double>(prop, PropertyType.Double, token);
|
return XmlPropertyTokens.ReadPropertyGeneric<double>(prop, PropertyType.Double, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
node.InnerText = prop.Value.ToInvariantString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,14 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "token";
|
public string Token => "token";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
return XmlPropertyTokens.ReadTokenGeneric<uint>(prop, PropertyType.Enum, token);
|
return XmlPropertyTokens.ReadPropertyGeneric<uint>(prop, PropertyType.Enum, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
node.InnerText = prop.Value.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "Faces";
|
public string Token => "Faces";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
bool success = XmlPropertyTokens.ReadTokenGeneric<uint>(prop, PropertyType.Faces, token);
|
bool success = XmlPropertyTokens.ReadPropertyGeneric<uint>(prop, PropertyType.Faces, token);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@ -27,5 +27,14 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
XmlElement faces = doc.CreateElement("faces");
|
||||||
|
node.AppendChild(faces);
|
||||||
|
|
||||||
|
int value = (int)prop.Value;
|
||||||
|
faces.InnerText = value.ToInvariantString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,14 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "float";
|
public string Token => "float";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
try
|
return XmlPropertyTokens.ReadPropertyGeneric<float>(prop, PropertyType.Float, token);
|
||||||
{
|
}
|
||||||
float value = XmlPropertyTokens.ParseFloat(token.InnerText);
|
|
||||||
prop.Type = PropertyType.Float;
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
prop.Value = value;
|
{
|
||||||
return true;
|
node.InnerText = prop.Value.ToInvariantString();
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "int";
|
public string Token => "int";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
// BrickColors are represented by ints, see if
|
// BrickColors are represented by ints, see if
|
||||||
// we can infer when they should be a BrickColor.
|
// we can infer when they should be a BrickColor.
|
||||||
@ -14,12 +14,19 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
if (prop.Name.Contains("Color") || prop.Instance.ClassName.Contains("Color"))
|
if (prop.Name.Contains("Color") || prop.Instance.ClassName.Contains("Color"))
|
||||||
{
|
{
|
||||||
var brickColorToken = XmlPropertyTokens.GetHandler<BrickColorToken>();
|
var brickColorToken = XmlPropertyTokens.GetHandler<BrickColorToken>();
|
||||||
return brickColorToken.ReadToken(prop, token);
|
return brickColorToken.ReadProperty(prop, token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return XmlPropertyTokens.ReadTokenGeneric<int>(prop, PropertyType.Int, token);
|
return XmlPropertyTokens.ReadPropertyGeneric<int>(prop, PropertyType.Int, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
node.InnerText = prop.Value.ToInvariantString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,14 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "int64";
|
public string Token => "int64";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
return XmlPropertyTokens.ReadTokenGeneric<long>(prop, PropertyType.Int64, token);
|
return XmlPropertyTokens.ReadPropertyGeneric<long>(prop, PropertyType.Int64, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
node.InnerText = prop.Value.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -7,7 +8,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "NumberRange";
|
public string Token => "NumberRange";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
string contents = token.InnerText.Trim();
|
string contents = token.InnerText.Trim();
|
||||||
string[] buffer = contents.Split(' ');
|
string[] buffer = contents.Split(' ');
|
||||||
@ -17,8 +18,8 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
float min = float.Parse(buffer[0]);
|
float min = Formatting.ParseFloat(buffer[0]);
|
||||||
float max = float.Parse(buffer[1]);
|
float max = Formatting.ParseFloat(buffer[1]);
|
||||||
|
|
||||||
prop.Type = PropertyType.NumberRange;
|
prop.Type = PropertyType.NumberRange;
|
||||||
prop.Value = new NumberRange(min, max);
|
prop.Value = new NumberRange(min, max);
|
||||||
@ -31,5 +32,10 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
node.InnerText = prop.Value.ToString() + ' ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "NumberSequence";
|
public string Token => "NumberSequence";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
string contents = token.InnerText.Trim();
|
string contents = token.InnerText.Trim();
|
||||||
string[] buffer = contents.Split(' ');
|
string[] buffer = contents.Split(' ');
|
||||||
@ -23,9 +23,9 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
for (int i = 0; i < length; i += 3)
|
for (int i = 0; i < length; i += 3)
|
||||||
{
|
{
|
||||||
float Time = float.Parse(buffer[ i ]);
|
float Time = Formatting.ParseFloat(buffer[ i ]);
|
||||||
float Value = float.Parse(buffer[i + 1]);
|
float Value = Formatting.ParseFloat(buffer[i + 1]);
|
||||||
float Envelope = float.Parse(buffer[i + 2]);
|
float Envelope = Formatting.ParseFloat(buffer[i + 2]);
|
||||||
|
|
||||||
keypoints[i / 3] = new NumberSequenceKeypoint(Time, Value, Envelope);
|
keypoints[i / 3] = new NumberSequenceKeypoint(Time, Value, Envelope);
|
||||||
}
|
}
|
||||||
@ -41,5 +41,10 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
node.InnerText = prop.Value.ToString() + ' ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
@ -17,10 +18,10 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
var readBool = createReader(bool.Parse, token);
|
var readBool = createReader(bool.Parse, token);
|
||||||
var readFloat = createReader(XmlPropertyTokens.ParseFloat, token);
|
var readFloat = createReader(Formatting.ParseFloat, token);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -46,5 +47,40 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
bool hasCustomPhysics = (prop.Value != null);
|
||||||
|
|
||||||
|
XmlElement customPhysics = doc.CreateElement("CustomPhysics");
|
||||||
|
customPhysics.InnerText = hasCustomPhysics
|
||||||
|
.ToString()
|
||||||
|
.ToLower();
|
||||||
|
|
||||||
|
node.AppendChild(customPhysics);
|
||||||
|
|
||||||
|
if (hasCustomPhysics)
|
||||||
|
{
|
||||||
|
var customProps = prop.Value as PhysicalProperties;
|
||||||
|
|
||||||
|
var data = new Dictionary<string, float>()
|
||||||
|
{
|
||||||
|
{ "Density", customProps.Density },
|
||||||
|
{ "Friction", customProps.Friction },
|
||||||
|
{ "Elasticity", customProps.Elasticity },
|
||||||
|
{ "FrictionWeight", customProps.FrictionWeight },
|
||||||
|
{ "ElasticityWeight", customProps.ElasticityWeight }
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string elementType in data.Keys)
|
||||||
|
{
|
||||||
|
float value = data[elementType];
|
||||||
|
|
||||||
|
XmlElement element = doc.CreateElement(elementType);
|
||||||
|
element.InnerText = value.ToInvariantString();
|
||||||
|
node.AppendChild(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -8,7 +9,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
public string Token => "Ray";
|
public string Token => "Ray";
|
||||||
private static string[] Fields = new string[2] { "origin", "direction" };
|
private static string[] Fields = new string[2] { "origin", "direction" };
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -35,5 +36,18 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
Ray ray = prop.Value as Ray;
|
||||||
|
|
||||||
|
XmlElement origin = doc.CreateElement("origin");
|
||||||
|
Vector3Token.WriteVector3(doc, origin, ray.Origin);
|
||||||
|
node.AppendChild(origin);
|
||||||
|
|
||||||
|
XmlElement direction = doc.CreateElement("direction");
|
||||||
|
Vector3Token.WriteVector3(doc, direction, ray.Direction);
|
||||||
|
node.AppendChild(direction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -8,7 +9,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
public string Token => "Rect2D";
|
public string Token => "Rect2D";
|
||||||
private static string[] Fields = new string[2] { "min", "max" };
|
private static string[] Fields = new string[2] { "min", "max" };
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -35,5 +36,18 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
Rect rect = prop.Value as Rect;
|
||||||
|
|
||||||
|
XmlElement min = doc.CreateElement("min");
|
||||||
|
Vector2Token.WriteVector2(doc, min, rect.Min);
|
||||||
|
node.AppendChild(min);
|
||||||
|
|
||||||
|
XmlElement max = doc.CreateElement("max");
|
||||||
|
Vector2Token.WriteVector2(doc, max, rect.Max);
|
||||||
|
node.AppendChild(max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "Ref";
|
public string Token => "Ref";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
string refId = token.InnerText;
|
string refId = token.InnerText;
|
||||||
prop.Type = PropertyType.Ref;
|
prop.Type = PropertyType.Ref;
|
||||||
@ -14,5 +14,18 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
string result = "null";
|
||||||
|
|
||||||
|
if (prop.Value != null && prop.Value.ToString() != "null")
|
||||||
|
{
|
||||||
|
Instance inst = prop.Value as Instance;
|
||||||
|
result = inst.XmlReferent;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.InnerText = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System;
|
||||||
|
using System.Text;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -7,7 +8,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "SharedString";
|
public string Token => "SharedString";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
string contents = token.InnerText;
|
string contents = token.InnerText;
|
||||||
prop.Type = PropertyType.SharedString;
|
prop.Type = PropertyType.SharedString;
|
||||||
@ -15,5 +16,11 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
var BinaryStringToken = XmlPropertyTokens.GetHandler<BinaryStringToken>();
|
||||||
|
BinaryStringToken.WriteProperty(prop, doc, node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System;
|
||||||
|
using System.Text;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -7,16 +8,28 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "string; ProtectedString";
|
public string Token => "string; ProtectedString";
|
||||||
|
|
||||||
public bool ReadToken(Property prop, XmlNode token)
|
public bool ReadProperty(Property prop, XmlNode token)
|
||||||
{
|
{
|
||||||
string contents = token.InnerText;
|
string contents = token.InnerText;
|
||||||
prop.Type = PropertyType.String;
|
prop.Type = PropertyType.String;
|
||||||
prop.Value = contents;
|
prop.Value = contents;
|
||||||
|
|
||||||
byte[] buffer = Encoding.UTF8.GetBytes(contents);
|
|
||||||
prop.SetRawBuffer(buffer);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
string value = prop.Value.ToInvariantString();
|
||||||
|
|
||||||
|
if (value.Contains("\r") || value.Contains("\n"))
|
||||||
|
{
|
||||||
|
XmlCDataSection cdata = doc.CreateCDataSection(value);
|
||||||
|
node.AppendChild(cdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node.InnerText = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -12,7 +13,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
XmlElement scaleToken = token[prefix + 'S'];
|
XmlElement scaleToken = token[prefix + 'S'];
|
||||||
float scale = XmlPropertyTokens.ParseFloat(scaleToken.InnerText);
|
float scale = Formatting.ParseFloat(scaleToken.InnerText);
|
||||||
|
|
||||||
XmlElement offsetToken = token[prefix + 'O'];
|
XmlElement offsetToken = token[prefix + 'O'];
|
||||||
int offset = int.Parse(offsetToken.InnerText);
|
int offset = int.Parse(offsetToken.InnerText);
|
||||||
@ -25,7 +26,18 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ReadToken(Property property, XmlNode token)
|
public static void WriteUDim(XmlDocument doc, XmlNode node, UDim value, string prefix = "")
|
||||||
|
{
|
||||||
|
XmlElement scale = doc.CreateElement(prefix + 'S');
|
||||||
|
scale.InnerText = value.Scale.ToInvariantString();
|
||||||
|
node.AppendChild(scale);
|
||||||
|
|
||||||
|
XmlElement offset = doc.CreateElement(prefix + 'O');
|
||||||
|
offset.InnerText = value.Offset.ToInvariantString();
|
||||||
|
node.AppendChild(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ReadProperty(Property property, XmlNode token)
|
||||||
{
|
{
|
||||||
UDim result = ReadUDim(token);
|
UDim result = ReadUDim(token);
|
||||||
bool success = (result != null);
|
bool success = (result != null);
|
||||||
@ -38,5 +50,11 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
UDim value = prop.Value as UDim;
|
||||||
|
WriteUDim(doc, node, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -7,7 +8,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
public string Token => "UDim2";
|
public string Token => "UDim2";
|
||||||
|
|
||||||
public bool ReadToken(Property property, XmlNode token)
|
public bool ReadProperty(Property property, XmlNode token)
|
||||||
{
|
{
|
||||||
UDim xUDim = UDimToken.ReadUDim(token, "X");
|
UDim xUDim = UDimToken.ReadUDim(token, "X");
|
||||||
UDim yUDim = UDimToken.ReadUDim(token, "Y");
|
UDim yUDim = UDimToken.ReadUDim(token, "Y");
|
||||||
@ -22,5 +23,16 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
UDim2 value = prop.Value as UDim2;
|
||||||
|
|
||||||
|
UDim xUDim = value.X;
|
||||||
|
UDimToken.WriteUDim(doc, node, xUDim, "X");
|
||||||
|
|
||||||
|
UDim yUDim = value.Y;
|
||||||
|
UDimToken.WriteUDim(doc, node, yUDim, "Y");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
{
|
{
|
||||||
var coord = token[key];
|
var coord = token[key];
|
||||||
string text = coord.InnerText;
|
string text = coord.InnerText;
|
||||||
xy[i] = XmlPropertyTokens.ParseFloat(text);
|
xy[i] = Formatting.ParseFloat(text);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -31,7 +31,18 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
return new Vector2(xy);
|
return new Vector2(xy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ReadToken(Property property, XmlNode token)
|
public static void WriteVector2(XmlDocument doc, XmlNode node, Vector2 value)
|
||||||
|
{
|
||||||
|
XmlElement x = doc.CreateElement("X");
|
||||||
|
x.InnerText = value.X.ToInvariantString();
|
||||||
|
node.AppendChild(x);
|
||||||
|
|
||||||
|
XmlElement y = doc.CreateElement("Y");
|
||||||
|
y.InnerText = value.Y.ToInvariantString();
|
||||||
|
node.AppendChild(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ReadProperty(Property property, XmlNode token)
|
||||||
{
|
{
|
||||||
Vector2 result = ReadVector2(token);
|
Vector2 result = ReadVector2(token);
|
||||||
bool success = (result != null);
|
bool success = (result != null);
|
||||||
@ -44,5 +55,11 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
Vector2 value = prop.Value as Vector2;
|
||||||
|
WriteVector2(doc, node, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Xml;
|
using System;
|
||||||
|
using System.Xml;
|
||||||
using RobloxFiles.DataTypes;
|
using RobloxFiles.DataTypes;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||||
@ -19,7 +20,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coord = token[key];
|
var coord = token[key];
|
||||||
xyz[i] = XmlPropertyTokens.ParseFloat(coord.InnerText);
|
xyz[i] = Formatting.ParseFloat(coord.InnerText);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -30,7 +31,22 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
return new Vector3(xyz);
|
return new Vector3(xyz);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ReadToken(Property property, XmlNode token)
|
public static void WriteVector3(XmlDocument doc, XmlNode node, Vector3 value)
|
||||||
|
{
|
||||||
|
XmlElement x = doc.CreateElement("X");
|
||||||
|
x.InnerText = value.X.ToInvariantString();
|
||||||
|
node.AppendChild(x);
|
||||||
|
|
||||||
|
XmlElement y = doc.CreateElement("Y");
|
||||||
|
y.InnerText = value.Y.ToInvariantString();
|
||||||
|
node.AppendChild(y);
|
||||||
|
|
||||||
|
XmlElement z = doc.CreateElement("Z");
|
||||||
|
z.InnerText = value.Z.ToInvariantString();
|
||||||
|
node.AppendChild(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ReadProperty(Property property, XmlNode token)
|
||||||
{
|
{
|
||||||
Vector3 result = ReadVector3(token);
|
Vector3 result = ReadVector3(token);
|
||||||
bool success = (result != null);
|
bool success = (result != null);
|
||||||
@ -43,5 +59,11 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
Vector3 value = prop.Value as Vector3;
|
||||||
|
WriteVector3(doc, node, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
public string Token => "Vector3int16";
|
public string Token => "Vector3int16";
|
||||||
private static string[] Coords = new string[3] { "X", "Y", "Z" };
|
private static string[] Coords = new string[3] { "X", "Y", "Z" };
|
||||||
|
|
||||||
public bool ReadToken(Property property, XmlNode token)
|
public bool ReadProperty(Property property, XmlNode token)
|
||||||
{
|
{
|
||||||
short[] xyz = new short[3];
|
short[] xyz = new short[3];
|
||||||
|
|
||||||
@ -36,5 +36,22 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||||
|
{
|
||||||
|
Vector3int16 value = prop.Value as Vector3int16;
|
||||||
|
|
||||||
|
XmlElement x = doc.CreateElement("X");
|
||||||
|
x.InnerText = value.X.ToString();
|
||||||
|
node.AppendChild(x);
|
||||||
|
|
||||||
|
XmlElement y = doc.CreateElement("Y");
|
||||||
|
y.InnerText = value.Y.ToString();
|
||||||
|
node.AppendChild(y);
|
||||||
|
|
||||||
|
XmlElement z = doc.CreateElement("Z");
|
||||||
|
z.InnerText = value.Z.ToString();
|
||||||
|
node.AppendChild(z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,9 @@ namespace RobloxFiles.XmlFormat
|
|||||||
Property prop = new Property();
|
Property prop = new Property();
|
||||||
prop.Name = propName.InnerText;
|
prop.Name = propName.InnerText;
|
||||||
prop.Instance = instance;
|
prop.Instance = instance;
|
||||||
|
prop.XmlToken = propType;
|
||||||
|
|
||||||
if (!tokenHandler.ReadToken(prop, propNode))
|
if (!tokenHandler.ReadProperty(prop, propNode))
|
||||||
Console.WriteLine("Could not read property: " + prop.GetFullName() + '!');
|
Console.WriteLine("Could not read property: " + prop.GetFullName() + '!');
|
||||||
|
|
||||||
instance.AddProperty(ref prop);
|
instance.AddProperty(ref prop);
|
||||||
@ -75,7 +76,7 @@ namespace RobloxFiles.XmlFormat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instance ReadInstance(XmlNode instNode, XmlRobloxFile file = null)
|
public static Instance ReadInstance(XmlNode instNode, XmlRobloxFile file)
|
||||||
{
|
{
|
||||||
var error = createErrorHandler("ReadInstance");
|
var error = createErrorHandler("ReadInstance");
|
||||||
|
|
||||||
|
194
XmlFormat/XmlDataWriter.cs
Normal file
194
XmlFormat/XmlDataWriter.cs
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
using RobloxFiles.XmlFormat.PropertyTokens;
|
||||||
|
|
||||||
|
namespace RobloxFiles.XmlFormat
|
||||||
|
{
|
||||||
|
public static class XmlDataWriter
|
||||||
|
{
|
||||||
|
public static XmlWriterSettings Settings = new XmlWriterSettings()
|
||||||
|
{
|
||||||
|
Indent = true,
|
||||||
|
IndentChars = "\t",
|
||||||
|
NewLineChars = "\r\n",
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
OmitXmlDeclaration = true,
|
||||||
|
NamespaceHandling = NamespaceHandling.Default
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string CreateReferent()
|
||||||
|
{
|
||||||
|
Guid referentGuid = Guid.NewGuid();
|
||||||
|
|
||||||
|
string referent = "RBX" + referentGuid
|
||||||
|
.ToString()
|
||||||
|
.ToUpper();
|
||||||
|
|
||||||
|
return referent.Replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetEnumName<T>(T item) where T : struct
|
||||||
|
{
|
||||||
|
return Enum.GetName(typeof(T), item);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void RecordInstances(XmlRobloxFile file, Instance inst)
|
||||||
|
{
|
||||||
|
foreach (Instance child in inst.GetChildren())
|
||||||
|
RecordInstances(file, child);
|
||||||
|
|
||||||
|
string referent = CreateReferent();
|
||||||
|
file.Instances.Add(referent, inst);
|
||||||
|
inst.XmlReferent = referent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlElement CreateRobloxElement(XmlDocument doc)
|
||||||
|
{
|
||||||
|
XmlElement roblox = doc.CreateElement("roblox");
|
||||||
|
doc.AppendChild(roblox);
|
||||||
|
|
||||||
|
roblox.SetAttribute("xmlns:xmime", "http://www.w3.org/2005/05/xmlmime");
|
||||||
|
roblox.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
|
||||||
|
roblox.SetAttribute("xsi:noNamespaceSchemaLocation", "http://www.roblox.com/roblox.xsd");
|
||||||
|
roblox.SetAttribute("version", "4");
|
||||||
|
|
||||||
|
XmlElement externalNull = doc.CreateElement("External");
|
||||||
|
roblox.AppendChild(externalNull);
|
||||||
|
externalNull.InnerText = "null";
|
||||||
|
|
||||||
|
XmlElement externalNil = doc.CreateElement("External");
|
||||||
|
roblox.AppendChild(externalNil);
|
||||||
|
externalNil.InnerText = "nil";
|
||||||
|
|
||||||
|
return roblox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlNode WriteProperty(Property prop, XmlDocument doc, XmlRobloxFile file)
|
||||||
|
{
|
||||||
|
string propType = prop.XmlToken;
|
||||||
|
|
||||||
|
if (prop.XmlToken.Length == 0)
|
||||||
|
{
|
||||||
|
propType = GetEnumName(prop.Type);
|
||||||
|
|
||||||
|
switch (prop.Type)
|
||||||
|
{
|
||||||
|
case PropertyType.CFrame:
|
||||||
|
case PropertyType.Quaternion:
|
||||||
|
propType = "CoordinateFrame";
|
||||||
|
break;
|
||||||
|
case PropertyType.Enum:
|
||||||
|
propType = "token";
|
||||||
|
break;
|
||||||
|
case PropertyType.Rect:
|
||||||
|
propType = "Rect2D";
|
||||||
|
break;
|
||||||
|
case PropertyType.Int:
|
||||||
|
case PropertyType.Bool:
|
||||||
|
case PropertyType.Float:
|
||||||
|
case PropertyType.Int64:
|
||||||
|
case PropertyType.Double:
|
||||||
|
propType = propType.ToLower();
|
||||||
|
break;
|
||||||
|
case PropertyType.String:
|
||||||
|
propType = (prop.HasRawBuffer ? "BinaryString" : "string");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IXmlPropertyToken handler = XmlPropertyTokens.GetHandler(propType);
|
||||||
|
|
||||||
|
if (handler == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("XmlDataWriter.WriteProperty: No token handler found for property type: {0}", propType);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlElement propElement = doc.CreateElement(propType);
|
||||||
|
propElement.SetAttribute("name", prop.Name);
|
||||||
|
|
||||||
|
XmlNode propNode = propElement;
|
||||||
|
handler.WriteProperty(prop, doc, propNode);
|
||||||
|
|
||||||
|
if (propNode.ParentNode != null)
|
||||||
|
{
|
||||||
|
XmlNode newNode = propNode.ParentNode;
|
||||||
|
newNode.RemoveChild(propNode);
|
||||||
|
propNode = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop.Type == PropertyType.SharedString)
|
||||||
|
{
|
||||||
|
string data = prop.Value.ToString();
|
||||||
|
byte[] buffer = Convert.FromBase64String(data);
|
||||||
|
|
||||||
|
using (MD5 md5 = MD5.Create())
|
||||||
|
{
|
||||||
|
byte[] hash = md5.ComputeHash(buffer);
|
||||||
|
string key = Convert.ToBase64String(hash);
|
||||||
|
|
||||||
|
if (!file.SharedStrings.ContainsKey(key))
|
||||||
|
file.SharedStrings.Add(key, data);
|
||||||
|
|
||||||
|
propNode.InnerText = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return propNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlNode WriteInstance(Instance instance, XmlDocument doc, XmlRobloxFile file)
|
||||||
|
{
|
||||||
|
XmlElement instNode = doc.CreateElement("Item");
|
||||||
|
instNode.SetAttribute("class", instance.ClassName);
|
||||||
|
instNode.SetAttribute("referent", instance.XmlReferent);
|
||||||
|
|
||||||
|
XmlElement propsNode = doc.CreateElement("Properties");
|
||||||
|
instNode.AppendChild(propsNode);
|
||||||
|
|
||||||
|
var props = instance.Properties;
|
||||||
|
|
||||||
|
foreach (string propName in props.Keys)
|
||||||
|
{
|
||||||
|
Property prop = props[propName];
|
||||||
|
XmlNode propNode = WriteProperty(prop, doc, file);
|
||||||
|
propsNode.AppendChild(propNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Instance child in instance.GetChildren())
|
||||||
|
{
|
||||||
|
XmlNode childNode = WriteInstance(child, doc, file);
|
||||||
|
instNode.AppendChild(childNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlNode WriteSharedStrings(XmlDocument doc, XmlRobloxFile file)
|
||||||
|
{
|
||||||
|
XmlElement sharedStrings = doc.CreateElement("SharedStrings");
|
||||||
|
|
||||||
|
var binaryWriter = XmlPropertyTokens.GetHandler<BinaryStringToken>();
|
||||||
|
var bufferProp = new Property("SharedString", PropertyType.String);
|
||||||
|
|
||||||
|
foreach (string md5 in file.SharedStrings.Keys)
|
||||||
|
{
|
||||||
|
XmlElement sharedString = doc.CreateElement("SharedString");
|
||||||
|
sharedString.SetAttribute("md5", md5);
|
||||||
|
|
||||||
|
string data = file.SharedStrings[md5];
|
||||||
|
byte[] buffer = Convert.FromBase64String(data);
|
||||||
|
|
||||||
|
bufferProp.SetRawBuffer(buffer);
|
||||||
|
binaryWriter.WriteProperty(bufferProp, doc, sharedString);
|
||||||
|
|
||||||
|
sharedStrings.AppendChild(sharedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sharedStrings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,8 @@ using System.ComponentModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
|
using RobloxFiles;
|
||||||
|
|
||||||
namespace RobloxFiles.XmlFormat
|
namespace RobloxFiles.XmlFormat
|
||||||
{
|
{
|
||||||
public static class XmlPropertyTokens
|
public static class XmlPropertyTokens
|
||||||
@ -35,17 +37,30 @@ namespace RobloxFiles.XmlFormat
|
|||||||
Handlers = tokenHandlers;
|
Handlers = tokenHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool ReadTokenGeneric<T>(Property prop, PropertyType propType, XmlNode token) where T : struct
|
public static bool ReadPropertyGeneric<T>(Property prop, PropertyType propType, XmlNode token) where T : struct
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Type resultType = typeof(T);
|
string value = token.InnerText;
|
||||||
TypeConverter converter = TypeDescriptor.GetConverter(resultType);
|
|
||||||
|
if (typeof(T) == typeof(int))
|
||||||
|
prop.Value = Formatting.ParseInt(value);
|
||||||
|
else if (typeof(T) == typeof(float))
|
||||||
|
prop.Value = Formatting.ParseFloat(value);
|
||||||
|
else if (typeof(T) == typeof(double))
|
||||||
|
prop.Value = Formatting.ParseDouble(value);
|
||||||
|
|
||||||
|
if (prop.Value == null)
|
||||||
|
{
|
||||||
|
Type resultType = typeof(T);
|
||||||
|
TypeConverter converter = TypeDescriptor.GetConverter(resultType);
|
||||||
|
|
||||||
|
object result = converter.ConvertFromString(token.InnerText);
|
||||||
|
prop.Value = result;
|
||||||
|
}
|
||||||
|
|
||||||
object result = converter.ConvertFromString(token.InnerText);
|
|
||||||
prop.Type = propType;
|
prop.Type = propType;
|
||||||
prop.Value = result;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -72,21 +87,5 @@ namespace RobloxFiles.XmlFormat
|
|||||||
|
|
||||||
return (T)result;
|
return (T)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float ParseFloat(string value)
|
|
||||||
{
|
|
||||||
float result;
|
|
||||||
|
|
||||||
if (value == "INF")
|
|
||||||
result = float.PositiveInfinity;
|
|
||||||
else if (value == "-INF")
|
|
||||||
result = float.NegativeInfinity;
|
|
||||||
else if (value == "NAN")
|
|
||||||
result = float.NaN;
|
|
||||||
else
|
|
||||||
result = float.Parse(value);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -15,11 +16,15 @@ namespace RobloxFiles.XmlFormat
|
|||||||
|
|
||||||
// Runtime Specific
|
// Runtime Specific
|
||||||
public readonly XmlDocument Root = new XmlDocument();
|
public readonly XmlDocument Root = new XmlDocument();
|
||||||
|
|
||||||
public Dictionary<string, Instance> Instances = new Dictionary<string, Instance>();
|
public Dictionary<string, Instance> Instances = new Dictionary<string, Instance>();
|
||||||
public Dictionary<string, string> SharedStrings = new Dictionary<string, string>();
|
public Dictionary<string, string> SharedStrings = new Dictionary<string, string>();
|
||||||
|
|
||||||
public void ReadFile(byte[] buffer)
|
public void ReadFile(byte[] buffer)
|
||||||
{
|
{
|
||||||
|
Instances.Clear();
|
||||||
|
SharedStrings.Clear();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string xml = Encoding.UTF8.GetString(buffer);
|
string xml = Encoding.UTF8.GetString(buffer);
|
||||||
@ -31,7 +36,7 @@ namespace RobloxFiles.XmlFormat
|
|||||||
}
|
}
|
||||||
|
|
||||||
XmlNode roblox = Root.FirstChild;
|
XmlNode roblox = Root.FirstChild;
|
||||||
|
|
||||||
if (roblox != null && roblox.Name == "roblox")
|
if (roblox != null && roblox.Name == "roblox")
|
||||||
{
|
{
|
||||||
// Verify the version we are using.
|
// Verify the version we are using.
|
||||||
@ -108,5 +113,52 @@ namespace RobloxFiles.XmlFormat
|
|||||||
throw new Exception("XmlRobloxFile: No 'roblox' tag found!");
|
throw new Exception("XmlRobloxFile: No 'roblox' tag found!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteFile(Stream stream)
|
||||||
|
{
|
||||||
|
XmlDocument doc = new XmlDocument();
|
||||||
|
XmlElement roblox = XmlDataWriter.CreateRobloxElement(doc);
|
||||||
|
|
||||||
|
Instances.Clear();
|
||||||
|
SharedStrings.Clear();
|
||||||
|
|
||||||
|
Instance[] topLevelItems = Contents.GetChildren();
|
||||||
|
|
||||||
|
// First, record all of the instances.
|
||||||
|
foreach (Instance inst in topLevelItems)
|
||||||
|
XmlDataWriter.RecordInstances(this, inst);
|
||||||
|
|
||||||
|
// Now append them into the document.
|
||||||
|
foreach (Instance inst in Contents.GetChildren())
|
||||||
|
{
|
||||||
|
XmlNode instNode = XmlDataWriter.WriteInstance(inst, doc, this);
|
||||||
|
roblox.AppendChild(instNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the shared strings.
|
||||||
|
if (SharedStrings.Count > 0)
|
||||||
|
{
|
||||||
|
XmlNode sharedStrings = XmlDataWriter.WriteSharedStrings(doc, this);
|
||||||
|
roblox.AppendChild(sharedStrings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the XML file.
|
||||||
|
using (StringWriter buffer = new StringWriter())
|
||||||
|
{
|
||||||
|
XmlWriterSettings settings = XmlDataWriter.Settings;
|
||||||
|
|
||||||
|
using (XmlWriter xmlWriter = XmlWriter.Create(buffer, settings))
|
||||||
|
doc.WriteContentTo(xmlWriter);
|
||||||
|
|
||||||
|
string result = buffer.ToString()
|
||||||
|
.Replace("<![CDATA[]]>", "");
|
||||||
|
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
byte[] data = Encoding.UTF8.GetBytes(result);
|
||||||
|
writer.Write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user