2019-01-30 06:36:56 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
|
2019-02-01 17:19:20 +00:00
|
|
|
|
namespace RobloxFiles.XmlFormat
|
2019-01-30 06:36:56 +00:00
|
|
|
|
{
|
|
|
|
|
public class XmlRobloxFile : IRobloxFile
|
|
|
|
|
{
|
|
|
|
|
// IRobloxFile
|
|
|
|
|
internal readonly Instance XmlContents = new Instance("Folder", "XmlRobloxFile");
|
|
|
|
|
public Instance Contents => XmlContents;
|
|
|
|
|
|
|
|
|
|
// Runtime Specific
|
|
|
|
|
public readonly XmlDocument Root = new XmlDocument();
|
|
|
|
|
public Dictionary<string, Instance> Instances = new Dictionary<string, Instance>();
|
2019-05-17 06:14:04 +00:00
|
|
|
|
public Dictionary<string, string> SharedStrings = new Dictionary<string, string>();
|
2019-01-30 06:36:56 +00:00
|
|
|
|
|
|
|
|
|
public void ReadFile(byte[] buffer)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
string xml = Encoding.UTF8.GetString(buffer);
|
|
|
|
|
Root.LoadXml(xml);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
2019-02-01 18:40:39 +00:00
|
|
|
|
throw new Exception("XmlRobloxFile: Could not read provided buffer as XML!");
|
2019-01-30 06:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XmlNode roblox = Root.FirstChild;
|
|
|
|
|
|
|
|
|
|
if (roblox != null && roblox.Name == "roblox")
|
|
|
|
|
{
|
|
|
|
|
// Verify the version we are using.
|
|
|
|
|
XmlNode version = roblox.Attributes.GetNamedItem("version");
|
|
|
|
|
int schemaVersion;
|
|
|
|
|
|
|
|
|
|
if (version == null || !int.TryParse(version.Value, out schemaVersion))
|
|
|
|
|
throw new Exception("XmlRobloxFile: No version number defined!");
|
|
|
|
|
else if (schemaVersion < 4)
|
|
|
|
|
throw new Exception("XmlRobloxFile: Provided version must be at least 4!");
|
|
|
|
|
|
|
|
|
|
// Process the instances.
|
|
|
|
|
foreach (XmlNode child in roblox.ChildNodes)
|
|
|
|
|
{
|
|
|
|
|
if (child.Name == "Item")
|
|
|
|
|
{
|
2019-02-04 19:30:33 +00:00
|
|
|
|
Instance item = XmlDataReader.ReadInstance(child, this);
|
2019-01-30 06:36:56 +00:00
|
|
|
|
item.Parent = XmlContents;
|
|
|
|
|
}
|
2019-05-17 06:14:04 +00:00
|
|
|
|
else if (child.Name == "SharedStrings")
|
|
|
|
|
{
|
|
|
|
|
XmlDataReader.ReadSharedStrings(child, this);
|
|
|
|
|
}
|
2019-01-30 06:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-17 06:14:04 +00:00
|
|
|
|
// Query the properties.
|
|
|
|
|
var props = Instances.Values
|
2019-01-30 06:36:56 +00:00
|
|
|
|
.SelectMany(inst => inst.Properties)
|
2019-05-17 06:14:04 +00:00
|
|
|
|
.Select(pair => pair.Value);
|
|
|
|
|
|
|
|
|
|
// Resolve referent properties.
|
|
|
|
|
var refProps = props.Where(prop => prop.Type == PropertyType.Ref);
|
|
|
|
|
|
2019-01-30 06:36:56 +00:00
|
|
|
|
foreach (Property refProp in refProps)
|
|
|
|
|
{
|
|
|
|
|
string refId = refProp.Value as string;
|
2019-05-17 06:14:04 +00:00
|
|
|
|
|
2019-01-30 06:36:56 +00:00
|
|
|
|
if (Instances.ContainsKey(refId))
|
|
|
|
|
{
|
|
|
|
|
Instance refInst = Instances[refId];
|
|
|
|
|
refProp.Value = refInst;
|
|
|
|
|
}
|
|
|
|
|
else if (refId != "null")
|
|
|
|
|
{
|
2019-05-17 06:14:04 +00:00
|
|
|
|
string name = refProp.GetFullName();
|
|
|
|
|
Console.WriteLine("XmlRobloxFile: Could not resolve reference for {0}", name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Resolve shared strings.
|
|
|
|
|
var sharedProps = props.Where(prop => prop.Type == PropertyType.SharedString);
|
|
|
|
|
|
|
|
|
|
foreach (Property sharedProp in sharedProps)
|
|
|
|
|
{
|
|
|
|
|
string md5 = sharedProp.Value as string;
|
|
|
|
|
|
|
|
|
|
if (SharedStrings.ContainsKey(md5))
|
|
|
|
|
{
|
|
|
|
|
string value = SharedStrings[md5];
|
|
|
|
|
sharedProp.Value = value;
|
|
|
|
|
|
|
|
|
|
byte[] data = Convert.FromBase64String(value);
|
|
|
|
|
sharedProp.SetRawBuffer(data);
|
|
|
|
|
|
|
|
|
|
continue;
|
2019-01-30 06:36:56 +00:00
|
|
|
|
}
|
2019-05-17 06:14:04 +00:00
|
|
|
|
|
|
|
|
|
string name = sharedProp.GetFullName();
|
|
|
|
|
Console.WriteLine("XmlRobloxFile: Could not resolve shared string for {0}", name);
|
2019-01-30 06:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-05-17 06:14:04 +00:00
|
|
|
|
throw new Exception("XmlRobloxFile: No 'roblox' tag found!");
|
2019-01-30 06:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|