private static void WriteObject(XmlWriter writer, Interface.Object o)
        {
            writer.WriteElementString("name", o.Name);
            writer.WriteElementString("type", o.Type);

            writer.WriteStartElement("baseline");
            foreach (var kv in o.Baseline.Properties)
            {
                writer.WriteStartElement("property");
                WriteProperty(writer, kv);
                writer.WriteEndElement(); // property
            }
            writer.WriteEndElement();     // baseline

            writer.WriteStartElement("overrides");
            foreach (var resolution in o.Overrides)
            {
                writer.WriteStartElement("resolution");
                writer.WriteElementString("name", resolution.Key);

                foreach (var kv in resolution.Value.Properties)
                {
                    writer.WriteStartElement("property");
                    WriteProperty(writer, kv);
                    writer.WriteEndElement(); // property
                }

                writer.WriteEndElement(); // resolution
            }
            writer.WriteEndElement();     // overrides

            writer.WriteStartElement("children");
            foreach (Interface.Object child in o.Children)
            {
                writer.WriteStartElement("object");
                WriteObject(writer, child);
                writer.WriteEndElement(); // object
            }
            writer.WriteEndElement();     // children
        }
        public void Deserialize(Stream input)
        {
            var magic = input.ReadValueU32(Endian.Little);

            if (magic != Signature && magic.Swap() != Signature)
            {
                throw new FormatException();
            }
            var endian = magic == Signature ? Endian.Little : Endian.Big;

            var nameIndex             = input.ReadValueS32(endian);
            var version               = input.ReadValueU16(endian);
            var animationTime         = input.ReadValueF32(endian);
            var metadataCount         = input.ReadValueU32(endian);
            var criticalResourceCount = input.ReadValueU32(endian);
            var stringTableOffset     = input.ReadValueU32(endian);
            var elementCount          = input.ReadValueU16(endian);
            var animationCount        = input.ReadValueU16(endian);

            if (version != 1 && version != 2)
            {
                throw new FormatException();
            }

            if (stringTableOffset >= input.Length)
            {
                throw new FormatException();
            }

            var position = input.Position;

            input.Seek(stringTableOffset, SeekOrigin.Begin);
            var strings = new Interface.StringTable();

            strings.Deserialize(input, endian);
            input.Seek(position, SeekOrigin.Begin);

            if (nameIndex != 0)
            {
                throw new FormatException();
            }

            var fileName = strings.ReadString(nameIndex);

            var criticalResources = new Interface.CriticalResource[criticalResourceCount];

            for (uint i = 0; i < criticalResourceCount; i++)
            {
                var type = input.ReadValueEnum <Interface.CriticalResourceType>();
                if (type != Interface.CriticalResourceType.Peg &&
                    type != Interface.CriticalResourceType.Document)
                {
                    throw new FormatException();
                }

                var name     = strings.ReadString(input, endian);
                var autoload = this._Version >= 2 && input.ReadValueB8() == true;

                if (autoload == true &&
                    type != Interface.CriticalResourceType.Peg)
                {
                    throw new FormatException();
                }

                criticalResources[i] = new Interface.CriticalResource()
                {
                    Type     = type,
                    Name     = name,
                    Autoload = autoload,
                };
            }

            var metadatas = new Interface.Metadata[metadataCount];

            for (uint i = 0; i < metadataCount; i++)
            {
                var name  = strings.ReadString(input, endian);
                var value = strings.ReadString(input, endian);
                metadatas[i] = new Interface.Metadata(name, value);
            }

            var elements = new Interface.Object[elementCount];

            for (ushort i = 0; i < elementCount; i++)
            {
                var element = new Interface.Object();
                element.Deserialize(input, endian, strings);
                elements[i] = element;
            }

            var animations = new Interface.Object[animationCount];

            for (ushort i = 0; i < animationCount; i++)
            {
                var animation = new Interface.Object();
                animation.Deserialize(input, endian, strings);
                animations[i] = animation;
            }

            if (input.Position != stringTableOffset)
            {
                throw new FormatException();
            }

            this._Endian        = endian;
            this._Name          = fileName;
            this._Version       = version;
            this._AnimationTime = animationTime;
            this._CriticalResources.Clear();
            this._CriticalResources.AddRange(criticalResources);
            this._Metadata.Clear();
            this._Metadata.AddRange(metadatas);
            this._Elements.Clear();
            this._Elements.AddRange(elements);
            this._Animations.Clear();
            this._Animations.AddRange(animations);
        }