Brought spec up to date, improvements to stability
This commit is contained in:
@ -11,7 +11,7 @@ namespace RobloxFiles.XmlFormat
|
||||
{
|
||||
var errorHandler = new Func<string, Exception>((message) =>
|
||||
{
|
||||
string contents = $"XmlDataReader.{label}: {message}";
|
||||
string contents = $"XmlRobloxFileReader.{label}: {message}";
|
||||
return new Exception(contents);
|
||||
});
|
||||
|
||||
@ -29,19 +29,25 @@ namespace RobloxFiles.XmlFormat
|
||||
{
|
||||
if (sharedString.Name == "SharedString")
|
||||
{
|
||||
XmlNode md5Node = sharedString.Attributes.GetNamedItem("md5");
|
||||
XmlNode hashNode = sharedString.Attributes.GetNamedItem("md5");
|
||||
|
||||
if (md5Node == null)
|
||||
if (hashNode == null)
|
||||
throw error("Got a SharedString without an 'md5' attribute!");
|
||||
|
||||
string key = md5Node.InnerText;
|
||||
string key = hashNode.InnerText;
|
||||
string value = sharedString.InnerText.Replace("\n", "");
|
||||
|
||||
byte[] buffer = Convert.FromBase64String(value);
|
||||
SharedString record = SharedString.FromBase64(value);
|
||||
byte[] hash = Convert.FromBase64String(key);
|
||||
var record = SharedString.FromBase64(value);
|
||||
|
||||
if (record.MD5_Key != key)
|
||||
throw error("The provided md5 hash did not match with the md5 hash computed for the value!");
|
||||
if (hash.Length != 16)
|
||||
throw error($"SharedString base64 key '{key}' must decode to byte[16]!");
|
||||
|
||||
if (key != record.Key)
|
||||
{
|
||||
SharedString.Register(key, record.SharedValue);
|
||||
record.Key = key;
|
||||
}
|
||||
|
||||
file.SharedStrings.Add(key);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
@ -47,6 +48,9 @@ namespace RobloxFiles.XmlFormat
|
||||
|
||||
public static XmlNode WriteProperty(Property prop, XmlDocument doc, XmlRobloxFile file)
|
||||
{
|
||||
if (prop.Name == "Archivable")
|
||||
return null;
|
||||
|
||||
string propType = prop.XmlToken;
|
||||
|
||||
if (propType == null)
|
||||
@ -78,6 +82,7 @@ namespace RobloxFiles.XmlFormat
|
||||
case PropertyType.String:
|
||||
propType = (prop.HasRawBuffer ? "BinaryString" : "string");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,6 +94,19 @@ namespace RobloxFiles.XmlFormat
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prop.Type == PropertyType.SharedString)
|
||||
{
|
||||
SharedString value = prop.CastValue<SharedString>();
|
||||
|
||||
if (value.ComputedKey == null)
|
||||
{
|
||||
var newShared = SharedString.FromBuffer(value.SharedValue);
|
||||
value.Key = newShared.ComputedKey;
|
||||
}
|
||||
|
||||
file.SharedStrings.Add(value.Key);
|
||||
}
|
||||
|
||||
XmlElement propElement = doc.CreateElement(propType);
|
||||
propElement.SetAttribute("name", prop.Name);
|
||||
|
||||
@ -102,12 +120,6 @@ namespace RobloxFiles.XmlFormat
|
||||
propNode = newNode;
|
||||
}
|
||||
|
||||
if (prop.Type == PropertyType.SharedString)
|
||||
{
|
||||
SharedString value = prop.CastValue<SharedString>();
|
||||
file.SharedStrings.Add(value.MD5_Key);
|
||||
}
|
||||
|
||||
return propNode;
|
||||
}
|
||||
|
||||
@ -124,11 +136,19 @@ namespace RobloxFiles.XmlFormat
|
||||
instNode.AppendChild(propsNode);
|
||||
|
||||
var props = instance.RefreshProperties();
|
||||
|
||||
var orderedKeys = props
|
||||
.OrderBy(pair => pair.Key)
|
||||
.Select(pair => pair.Key);
|
||||
|
||||
foreach (string propName in props.Keys)
|
||||
foreach (string propName in orderedKeys)
|
||||
{
|
||||
Property prop = props[propName];
|
||||
XmlNode propNode = WriteProperty(prop, doc, file);
|
||||
|
||||
if (propNode == null)
|
||||
continue;
|
||||
|
||||
propsNode.AppendChild(propNode);
|
||||
}
|
||||
|
||||
@ -151,12 +171,12 @@ namespace RobloxFiles.XmlFormat
|
||||
var binaryWriter = XmlPropertyTokens.GetHandler<BinaryStringToken>();
|
||||
var binaryBuffer = new Property("SharedString", PropertyType.String);
|
||||
|
||||
foreach (string md5 in file.SharedStrings)
|
||||
foreach (string key in file.SharedStrings)
|
||||
{
|
||||
XmlElement sharedString = doc.CreateElement("SharedString");
|
||||
sharedString.SetAttribute("md5", md5);
|
||||
sharedString.SetAttribute("md5", key);
|
||||
|
||||
binaryBuffer.RawBuffer = SharedString.FindRecord(md5);
|
||||
binaryBuffer.RawBuffer = SharedString.Find(key);
|
||||
binaryWriter.WriteProperty(binaryBuffer, doc, sharedString);
|
||||
|
||||
sharedStrings.AppendChild(sharedString);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Xml;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using RobloxFiles.DataTypes;
|
||||
|
||||
namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
@ -10,7 +11,7 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
ProtectedString contents = token.InnerText;
|
||||
prop.Type = PropertyType.String;
|
||||
prop.Type = PropertyType.ProtectedString;
|
||||
prop.Value = contents;
|
||||
|
||||
return true;
|
||||
@ -18,16 +19,26 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
|
||||
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||
{
|
||||
string value = prop.CastValue<ProtectedString>();
|
||||
ProtectedString value = prop.CastValue<ProtectedString>();
|
||||
|
||||
if (value.Contains("\r") || value.Contains("\n"))
|
||||
if (value.IsCompiled)
|
||||
{
|
||||
XmlCDataSection cdata = doc.CreateCDataSection(value);
|
||||
node.AppendChild(cdata);
|
||||
var binary = XmlPropertyTokens.GetHandler<BinaryStringToken>();
|
||||
binary.WriteProperty(prop, doc, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.InnerText = value;
|
||||
string contents = Encoding.UTF8.GetString(value.RawBuffer);
|
||||
|
||||
if (contents.Contains("\r") || contents.Contains("\n"))
|
||||
{
|
||||
XmlCDataSection cdata = doc.CreateCDataSection(contents);
|
||||
node.AppendChild(cdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.InnerText = contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,17 +9,25 @@ namespace RobloxFiles.XmlFormat.PropertyTokens
|
||||
|
||||
public bool ReadProperty(Property prop, XmlNode token)
|
||||
{
|
||||
string md5 = token.InnerText;
|
||||
string key = token.InnerText;
|
||||
prop.Type = PropertyType.SharedString;
|
||||
prop.Value = new SharedString(md5);
|
||||
prop.Value = new SharedString(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void WriteProperty(Property prop, XmlDocument doc, XmlNode node)
|
||||
{
|
||||
SharedString value = prop.CastValue<SharedString>();
|
||||
node.InnerText = value.MD5_Key;
|
||||
var value = prop.CastValue<SharedString>();
|
||||
string key = value.Key;
|
||||
|
||||
if (value.ComputedKey == null)
|
||||
{
|
||||
var newShared = SharedString.FromBuffer(value.SharedValue);
|
||||
key = newShared.ComputedKey;
|
||||
}
|
||||
|
||||
node.InnerText = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ namespace RobloxFiles
|
||||
foreach (Property sharedProp in sharedProps)
|
||||
{
|
||||
SharedString shared = sharedProp.CastValue<SharedString>();
|
||||
SharedStrings.Add(shared.MD5_Key);
|
||||
SharedStrings.Add(shared.Key);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
Reference in New Issue
Block a user