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);
                }
예제 #2
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }