2019-05-17 12:08:06 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
|
2019-06-30 22:01:19 +00:00
|
|
|
|
using RobloxFiles.DataTypes;
|
2019-05-17 12:08:06 +00:00
|
|
|
|
using RobloxFiles.XmlFormat.PropertyTokens;
|
|
|
|
|
|
|
|
|
|
namespace RobloxFiles.XmlFormat
|
|
|
|
|
{
|
2019-05-19 04:44:51 +00:00
|
|
|
|
public static class XmlRobloxFileWriter
|
2019-05-17 12:08:06 +00:00
|
|
|
|
{
|
2019-05-19 04:44:51 +00:00
|
|
|
|
public static readonly XmlWriterSettings Settings = new XmlWriterSettings()
|
2019-05-17 12:08:06 +00:00
|
|
|
|
{
|
|
|
|
|
Indent = true,
|
|
|
|
|
IndentChars = "\t",
|
|
|
|
|
NewLineChars = "\r\n",
|
|
|
|
|
Encoding = Encoding.UTF8,
|
2019-05-19 04:44:51 +00:00
|
|
|
|
OmitXmlDeclaration = true
|
2019-05-17 12:08:06 +00:00
|
|
|
|
};
|
|
|
|
|
|
2019-05-19 04:44:51 +00:00
|
|
|
|
public static string CreateReferent()
|
2019-05-17 12:08:06 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
2019-06-30 22:01:19 +00:00
|
|
|
|
if (inst.Referent == null || inst.Referent.Length < 35)
|
2019-06-08 03:43:28 +00:00
|
|
|
|
inst.Referent = CreateReferent();
|
2019-05-19 04:44:51 +00:00
|
|
|
|
|
2019-06-08 03:43:28 +00:00
|
|
|
|
file.Instances.Add(inst.Referent, inst);
|
2019-05-17 12:08:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2019-06-30 22:01:19 +00:00
|
|
|
|
SharedString value = prop.CastValue<SharedString>();
|
|
|
|
|
file.SharedStrings.Add(value.MD5_Key);
|
2019-05-17 12:08:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return propNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static XmlNode WriteInstance(Instance instance, XmlDocument doc, XmlRobloxFile file)
|
|
|
|
|
{
|
2019-06-30 22:01:19 +00:00
|
|
|
|
if (!instance.Archivable)
|
|
|
|
|
return null;
|
|
|
|
|
|
2019-05-17 12:08:06 +00:00
|
|
|
|
XmlElement instNode = doc.CreateElement("Item");
|
|
|
|
|
instNode.SetAttribute("class", instance.ClassName);
|
2019-06-08 03:43:28 +00:00
|
|
|
|
instNode.SetAttribute("referent", instance.Referent);
|
2019-05-17 12:08:06 +00:00
|
|
|
|
|
|
|
|
|
XmlElement propsNode = doc.CreateElement("Properties");
|
|
|
|
|
instNode.AppendChild(propsNode);
|
|
|
|
|
|
2019-06-30 22:01:19 +00:00
|
|
|
|
var props = instance.RefreshProperties();
|
2019-05-19 04:44:51 +00:00
|
|
|
|
|
2019-05-17 12:08:06 +00:00
|
|
|
|
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())
|
|
|
|
|
{
|
2019-06-30 22:01:19 +00:00
|
|
|
|
if (child.Archivable)
|
|
|
|
|
{
|
|
|
|
|
XmlNode childNode = WriteInstance(child, doc, file);
|
|
|
|
|
instNode.AppendChild(childNode);
|
|
|
|
|
}
|
2019-05-17 12:08:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return instNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static XmlNode WriteSharedStrings(XmlDocument doc, XmlRobloxFile file)
|
|
|
|
|
{
|
|
|
|
|
XmlElement sharedStrings = doc.CreateElement("SharedStrings");
|
|
|
|
|
|
|
|
|
|
var binaryWriter = XmlPropertyTokens.GetHandler<BinaryStringToken>();
|
2019-06-30 22:01:19 +00:00
|
|
|
|
var binaryBuffer = new Property("SharedString", PropertyType.String);
|
2019-05-17 12:08:06 +00:00
|
|
|
|
|
2019-06-30 22:01:19 +00:00
|
|
|
|
foreach (string md5 in file.SharedStrings)
|
2019-05-17 12:08:06 +00:00
|
|
|
|
{
|
|
|
|
|
XmlElement sharedString = doc.CreateElement("SharedString");
|
|
|
|
|
sharedString.SetAttribute("md5", md5);
|
|
|
|
|
|
2019-06-30 22:01:19 +00:00
|
|
|
|
binaryBuffer.RawBuffer = SharedString.FindRecord(md5);
|
|
|
|
|
binaryWriter.WriteProperty(binaryBuffer, doc, sharedString);
|
2019-05-17 12:08:06 +00:00
|
|
|
|
|
|
|
|
|
sharedStrings.AppendChild(sharedString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sharedStrings;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|