public static XmlNode WriteInstance(Instance instance, XmlDocument doc, XmlRobloxFile file) { if (!instance.Archivable) { return(null); } XmlElement instNode = doc.CreateElement("Item"); instNode.SetAttribute("class", instance.ClassName); instNode.SetAttribute("referent", instance.Referent); XmlElement propsNode = doc.CreateElement("Properties"); instNode.AppendChild(propsNode); var props = instance.RefreshProperties(); var orderedKeys = props .OrderBy(pair => pair.Key) .Select(pair => pair.Key); foreach (string propName in orderedKeys) { Property prop = props[propName]; bool isDefault = false; object a = DefaultProperty.Get(instance, prop); object b = prop.Value; if (a is double d0 && b is double d1) { isDefault = d0.FuzzyEquals(d1); }
public static Instance ReadInstance(XmlNode instNode, XmlRobloxFile file) { var error = createErrorHandler("ReadInstance"); // Process the instance itself if (instNode.Name != "Item") { throw error("Provided XmlNode's name should be 'Item'!"); } XmlNode classToken = instNode.Attributes.GetNamedItem("class"); if (classToken == null) { throw error("Got an Item without a defined 'class' attribute!"); } string className = classToken.InnerText; Type instType = Type.GetType($"RobloxFiles.{className}") ?? typeof(Instance); Instance inst = Activator.CreateInstance(instType) as Instance; // The 'referent' attribute is optional, but should be defined if a Ref property needs to link to this Instance. XmlNode refToken = instNode.Attributes.GetNamedItem("referent"); if (refToken != null && file != null) { string referent = refToken.InnerText; inst.Referent = referent; if (file.Instances.ContainsKey(referent)) { throw error("Got an Item with a duplicate 'referent' attribute!"); } file.Instances.Add(referent, inst); } // Process the child nodes of this instance. foreach (XmlNode childNode in instNode.ChildNodes) { if (childNode.Name == "Properties") { ReadProperties(inst, childNode); } else if (childNode.Name == "Item") { Instance child = ReadInstance(childNode, file); child.Parent = inst; } } return(inst); }
internal static void RecordInstances(XmlRobloxFile file, Instance inst) { inst.Referent = "RBX" + file.RefCounter++; foreach (Instance child in inst.GetChildren()) { RecordInstances(file, child); } file.Instances.Add(inst.Referent, inst); }
internal static void RecordInstances(XmlRobloxFile file, Instance inst) { foreach (Instance child in inst.GetChildren()) { RecordInstances(file, child); } if (inst.Referent == null || inst.Referent.Length < 35) { inst.Referent = CreateReferent(); } file.Instances.Add(inst.Referent, inst); }
public static XmlNode WriteInstance(Instance instance, XmlDocument doc, XmlRobloxFile file) { if (!instance.Archivable) { return(null); } XmlElement instNode = doc.CreateElement("Item"); instNode.SetAttribute("class", instance.ClassName); instNode.SetAttribute("referent", instance.Referent); XmlElement propsNode = doc.CreateElement("Properties"); instNode.AppendChild(propsNode); var props = instance.RefreshProperties(); var orderedKeys = props .OrderBy(pair => pair.Key) .Select(pair => pair.Key); foreach (string propName in orderedKeys) { Property prop = props[propName]; XmlNode propNode = WriteProperty(prop, doc, file); if (propNode == null) { continue; } propsNode.AppendChild(propNode); } foreach (Instance child in instance.GetChildren()) { if (child.Archivable) { 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 binaryBuffer = new Property("SharedString", PropertyType.String); foreach (string key in file.SharedStrings) { XmlElement sharedString = doc.CreateElement("SharedString"); sharedString.SetAttribute("md5", key); binaryBuffer.RawBuffer = SharedString.Find(key); binaryWriter.WriteProperty(binaryBuffer, doc, sharedString); sharedStrings.AppendChild(sharedString); } return(sharedStrings); }
public static void ReadSharedStrings(XmlNode sharedStrings, XmlRobloxFile file) { var error = CreateErrorHandler(nameof(ReadSharedStrings)); if (sharedStrings.Name != "SharedStrings") { throw error("Provided XmlNode's class must be 'SharedStrings'!"); } foreach (XmlNode sharedString in sharedStrings) { if (sharedString.Name == "SharedString") { XmlNode hashNode = sharedString.Attributes.GetNamedItem("md5"); if (hashNode == null) { throw error("Got a SharedString without an 'md5' attribute!"); } string key = hashNode.InnerText; string value = sharedString.InnerText.Replace("\n", ""); byte[] hash = Convert.FromBase64String(key); var record = SharedString.FromBase64(value); if (hash.Length != 16) { throw error($"SharedString base64 key '{key}' must align to byte[16]!"); } if (key != record.Key) { SharedString.Register(key, record.SharedValue); record.Key = key; } file.SharedStrings.Add(key); } } }
public static void ReadMetadata(XmlNode meta, XmlRobloxFile file) { var error = CreateErrorHandler(nameof(ReadMetadata)); if (meta.Name != "Meta") { throw error("Provided XmlNode's class should be 'Meta'!"); } XmlNode propName = meta.Attributes.GetNamedItem("name"); if (propName == null) { throw error("Got a Meta node without a 'name' attribute!"); } string key = propName.InnerText; string value = meta.InnerText; file.Metadata[key] = value; }
public static XmlNode WriteProperty(Property prop, XmlDocument doc, XmlRobloxFile file) { if (prop.Name == "Archivable") { return(null); } string propType = prop.XmlToken; if (propType == null) { propType = ""; } if (propType.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(CultureInfo.InvariantCulture); break; case PropertyType.String: propType = (prop.HasRawBuffer ? "BinaryString" : "string"); break; default: break; } } IXmlPropertyToken handler = XmlPropertyTokens.GetHandler(propType); if (handler == null) { if (RobloxFile.LogErrors) { Console.Error.WriteLine("XmlDataWriter.WriteProperty: No token handler found for property type: {0}", propType); } return(null); } if (prop.Type == PropertyType.SharedString) { SharedString str = prop.CastValue <SharedString>(); if (str == null) { byte[] value = prop.CastValue <byte[]>(); str = SharedString.FromBuffer(value); } if (str.ComputedKey == null) { var newShared = SharedString.FromBuffer(str.SharedValue); str.Key = newShared.ComputedKey; } file.SharedStrings.Add(str.Key); } 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; } return(propNode); }
public static Instance ReadInstance(XmlNode instNode, XmlRobloxFile file) { var error = CreateErrorHandler(nameof(ReadInstance)); // Process the instance itself if (instNode.Name != "Item") { throw error("Provided XmlNode's name should be 'Item'!"); } XmlNode classToken = instNode.Attributes.GetNamedItem("class"); if (classToken == null) { throw error("Got an Item without a defined 'class' attribute!"); } string className = classToken.InnerText; Type instType = Type.GetType($"RobloxFiles.{className}"); if (instType == null) { if (RobloxFile.LogErrors) { var typeError = error($"Unknown class {className} while reading Item."); Console.Error.WriteLine(typeError.Message); } return(null); } Instance inst = Activator.CreateInstance(instType) as Instance; // The 'referent' attribute is optional, but should be defined if a Ref property needs to link to this Instance. XmlNode refToken = instNode.Attributes.GetNamedItem("referent"); if (refToken != null && file != null) { string referent = refToken.InnerText; inst.Referent = referent; if (file.Instances.ContainsKey(referent)) { throw error("Got an Item with a duplicate 'referent' attribute!"); } file.Instances.Add(referent, inst); } // Process the child nodes of this instance. foreach (XmlNode childNode in instNode.ChildNodes) { switch (childNode.Name) { case "Item": Instance child = ReadInstance(childNode, file); if (child != null) { child.Parent = inst; } break; case "Properties": ReadProperties(inst, childNode); break; default: break; } } return(inst); }