C# 实现xml二进制数据打包和解包

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace BinaryPacker
{
    class Program
    {
        static void Main(string[] args)
        {
            //输出到xml
            //创建xml文档
            //实例化一个xmldocument类
            XmlDocument xDoc = new XmlDocument();

            //声明一个xml所需要的语法的变量,添加在末尾
            XmlDeclaration xmlDeclaration = xDoc.CreateXmlDeclaration("1.0", "UTF-8", "yes");

            //创建根节点
            XmlElement ele = null;// xDoc.CreateElement("grades");
            BinaryPacker.Element element = BinaryPacker.FromBinary(@"H:\Maps\Maps\0-Intro.bin");
            //xDoc.AppendChild(ele);
            string xmlname = "";
            element.ToStringXML(xDoc, ele,ref xmlname);
            
            xDoc.Save(xmlname+".xml");

        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace BinaryPacker
{
    class BinaryPacker
    {
        
        public static void ToBinary(string filename, string outdir = null)
        {
            string extension = Path.GetExtension(filename);
            if (outdir != null)
            {
                Path.Combine(new string[]
                {
                    outdir + Path.GetFileName(filename)
                });
            }
            filename.Replace(extension, BinaryPacker.OutputFileExtension);
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(filename);
            XmlElement rootElement = null;
            foreach (object obj in xmlDocument.ChildNodes)
            {
                if (obj is XmlElement)
                {
                    rootElement = (obj as XmlElement);
                    break;
                }
            }
            BinaryPacker.ToBinary(rootElement, outdir);
        }

        
        public static void ToBinary(XmlElement rootElement, string outfilename)
        {
            BinaryPacker.stringValue.Clear();
            BinaryPacker.stringCounter = 0;
            BinaryPacker.CreateLookupTable(rootElement);
            BinaryPacker.AddLookupValue(BinaryPacker.InnerTextAttributeName);
            using (FileStream fileStream = new FileStream(outfilename, FileMode.Create))
            {
                BinaryWriter binaryWriter = new BinaryWriter(fileStream);
                binaryWriter.Write("CELESTE MAP");
                binaryWriter.Write(Path.GetFileNameWithoutExtension(outfilename));
                binaryWriter.Write((short)BinaryPacker.stringValue.Count);
                foreach (KeyValuePair<string, short> keyValuePair in BinaryPacker.stringValue)
                {
                    binaryWriter.Write(keyValuePair.Key);
                }
                BinaryPacker.WriteElement(binaryWriter, rootElement);
                binaryWriter.Flush();
            }
        }

        
        private static void CreateLookupTable(XmlElement element)
        {
            BinaryPacker.AddLookupValue(element.Name);
            foreach (object obj in element.Attributes)
            {
                XmlAttribute xmlAttribute = (XmlAttribute)obj;
                if (!BinaryPacker.IgnoreAttributes.Contains(xmlAttribute.Name))
                {
                    BinaryPacker.AddLookupValue(xmlAttribute.Name);
                    byte b;
                    object obj2;
                    if (BinaryPacker.ParseValue(xmlAttribute.Value, out b, out obj2) && b == 5)
                    {
                        BinaryPacker.AddLookupValue(xmlAttribute.Value);
                    }
                }
            }
            foreach (object obj3 in element.ChildNodes)
            {
                if (obj3 is XmlElement)
                {
                    BinaryPacker.CreateLookupTable(obj3 as XmlElement);
                }
            }
        }

        
        private static void AddLookupValue(string name)
        {
            if (!BinaryPacker.stringValue.ContainsKey(name))
            {
                BinaryPacker.stringValue.Add(name, BinaryPacker.stringCounter);
                BinaryPacker.stringCounter += 1;
            }
        }

        
        private static void WriteElement(BinaryWriter writer, XmlElement element)
        {
            int num = 0;
            IEnumerator enumerator = element.ChildNodes.GetEnumerator();
            while (enumerator.MoveNext())
            {
                if (enumerator.Current is XmlElement)
                {
                    num++;//遍历有多少xml子结点结点
                }
            }

            int num2 = 0;
            foreach (object obj in element.Attributes)
            {
                XmlAttribute xmlAttribute = (XmlAttribute)obj;
                if (!BinaryPacker.IgnoreAttributes.Contains(xmlAttribute.Name))
                {
                    num2++;
                }
            }
            if (element.InnerText.Length > 0 && num == 0)
            {
                num2++;
            }
            writer.Write(BinaryPacker.stringValue[element.Name]);
            writer.Write((byte)num2);
            foreach (object obj2 in element.Attributes)
            {
                XmlAttribute xmlAttribute2 = (XmlAttribute)obj2;
                if (!BinaryPacker.IgnoreAttributes.Contains(xmlAttribute2.Name))
                {
                    byte value;
                    object obj3;
                    BinaryPacker.ParseValue(xmlAttribute2.Value, out value, out obj3);
                    writer.Write(BinaryPacker.stringValue[xmlAttribute2.Name]);
                    writer.Write(value);
                    switch (value)
                    {
                        case 0:
                            writer.Write((bool)obj3);
                            break;
                        case 1:
                            writer.Write((byte)obj3);
                            break;
                        case 2:
                            writer.Write((short)obj3);
                            break;
                        case 3:
                            writer.Write((int)obj3);
                            break;
                        case 4:
                            writer.Write((float)obj3);
                            break;
                        case 5:
                            writer.Write(BinaryPacker.stringValue[(string)obj3]);
                            break;
                    }
                }
            }
            if (element.InnerText.Length > 0 && num == 0)
            {
                writer.Write(BinaryPacker.stringValue[BinaryPacker.InnerTextAttributeName]);
                if (element.Name == "solids" || element.Name == "bg")
                {
                    byte[] array = RunLengthEncoding.Encode(element.InnerText);
                    writer.Write(7);
                    writer.Write((short)array.Length);
                    writer.Write(array);
                }
                else
                {
                    writer.Write(6);
                    writer.Write(element.InnerText);
                }
            }
            writer.Write((short)num);
            foreach (object obj4 in element.ChildNodes)
            {
                if (obj4 is XmlElement)
                {
                    BinaryPacker.WriteElement(writer, obj4 as XmlElement);
                }
            }
        }

        
        private static bool ParseValue(string value, out byte type, out object result)
        {
            bool flag;
            byte b;
            short num;
            int num2;
            float num3;
            if (bool.TryParse(value, out flag))
            {
                type = 0;
                result = flag;
            }
            else if (byte.TryParse(value, out b))
            {
                type = 1;
                result = b;
            }
            else if (short.TryParse(value, out num))
            {
                type = 2;
                result = num;
            }
            else if (int.TryParse(value, out num2))
            {
                type = 3;
                result = num2;
            }
            else if (float.TryParse(value, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out num3))
            {
                type = 4;
                result = num3;
            }
            else
            {
                type = 5;
                result = value;
            }
            return true;
        }

        
        public static BinaryPacker.Element FromBinary(string filename)
        {
            BinaryPacker.Element element;
            using (FileStream fileStream = File.OpenRead(filename))
            {
                BinaryReader binaryReader = new BinaryReader(fileStream);
                binaryReader.ReadString();
                string package = binaryReader.ReadString();
                short num = binaryReader.ReadInt16();
                BinaryPacker.stringLookup = new string[(int)num];
                for (int i = 0; i < (int)num; i++)
                {
                    BinaryPacker.stringLookup[i] = binaryReader.ReadString();
                }
                element = BinaryPacker.ReadElement(binaryReader);
                element.Package = package;
            }
            return element;
        }

        
        private static BinaryPacker.Element ReadElement(BinaryReader reader)
        {
            BinaryPacker.Element element = new BinaryPacker.Element();
            element.Name = BinaryPacker.stringLookup[(int)reader.ReadInt16()];
            byte b = reader.ReadByte();
            if (b > 0)
            {
                element.Attributes = new Dictionary<string, object>();
            }
            for (int i = 0; i < (int)b; i++)
            {
                string key = BinaryPacker.stringLookup[(int)reader.ReadInt16()];
                byte b2 = reader.ReadByte();
                object value = null;
                if (b2 == 0)
                {
                    value = reader.ReadBoolean();
                }
                else if (b2 == 1)
                {
                    value = Convert.ToInt32(reader.ReadByte());
                }
                else if (b2 == 2)
                {
                    value = Convert.ToInt32(reader.ReadInt16());
                }
                else if (b2 == 3)
                {
                    value = reader.ReadInt32();
                }
                else if (b2 == 4)
                {
                    value = reader.ReadSingle();
                }
                else if (b2 == 5)
                {
                    value = BinaryPacker.stringLookup[(int)reader.ReadInt16()];
                }
                else if (b2 == 6)
                {
                    value = reader.ReadString();
                }
                else if (b2 == 7)
                {
                    short count = reader.ReadInt16();
                    value = RunLengthEncoding.Decode(reader.ReadBytes((int)count));
                }
                element.Attributes.Add(key, value);
            }
            short num = reader.ReadInt16();
            if (num > 0)
            {
                element.Children = new List<BinaryPacker.Element>();
            }
            for (int j = 0; j < (int)num; j++)
            {
                element.Children.Add(BinaryPacker.ReadElement(reader));
            }
            return element;
        }

        
        public static readonly HashSet<string> IgnoreAttributes = new HashSet<string>
        {
            "_eid"
        };

        
        public static string InnerTextAttributeName = "innerText";

        
        public static string OutputFileExtension = ".bin";

        
        private static Dictionary<string, short> stringValue = new Dictionary<string, short>();

        
        private static string[] stringLookup;

        
        private static short stringCounter;

        
        public class Element
        {
            
            public bool HasAttr(string name)
            {
                return this.Attributes != null && this.Attributes.ContainsKey(name);
            }

            
            public string Attr(string name, string defaultValue = "")
            {
                object obj;
                if (this.Attributes == null || !this.Attributes.TryGetValue(name, out obj))
                {
                    obj = defaultValue;
                }
                return obj.ToString();
            }

            
            public bool AttrBool(string name, bool defaultValue = false)
            {
                object obj;
                if (this.Attributes == null || !this.Attributes.TryGetValue(name, out obj))
                {
                    obj = defaultValue;
                }
                if (obj is bool)
                {
                    return (bool)obj;
                }
                return bool.Parse(obj.ToString());
            }

            
            public float AttrFloat(string name, float defaultValue = 0f)
            {
                object obj;
                if (this.Attributes == null || !this.Attributes.TryGetValue(name, out obj))
                {
                    obj = defaultValue;
                }
                if (obj is float)
                {
                    return (float)obj;
                }
                return float.Parse(obj.ToString(), CultureInfo.InvariantCulture);
            }

            
            public string Package;

            
            public string Name;

            
            public Dictionary<string, object> Attributes;

            
            public List<BinaryPacker.Element> Children;
          
            public void ToStringXML(XmlDocument xDoc,XmlElement element,ref string name)
            {
                if (element != null) {
                    
                    XmlElement elementc =  xDoc.CreateElement(Name);
                    element.AppendChild(elementc);
                    element = elementc;
                    if (Package != null)
                    {
                        element.SetAttribute("Package", Package);
                    }
                }
                else {
                    element = xDoc.CreateElement(Name);
                    name = Package;
                    xDoc.AppendChild(element);
                    element.SetAttribute("Package", Package);

                }
                
                

                
                if (Attributes!=null) {
                    List<KeyValuePair<string, object>> lit = Attributes.ToList();
                    for (int j = 0; j < lit.Count; j++)
                    {
                        element.SetAttribute(lit[j].Key, lit[j].Value.ToString());

                    }
                }
                if (Children != null)
                {
                    for (int i = 0; i < Children.Count; i++)
                    {
                        Children[i].ToStringXML(xDoc, element,ref name);
                    }
                }




            }  

        }
    }

}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BinaryPacker
{
    public static  class RunLengthEncoding
    {
        public static byte[] Encode(string str)
        {
            List<byte> list = new List<byte>();
            for (int i = 0; i < str.Length; i++)
            {
                byte b = 1;
                char c = str[i];
                while (i + 1 < str.Length && str[i + 1] == c && b < 255)
                {
                    b += 1;
                    i++;
                }
                list.Add(b);
                list.Add((byte)c);
            }
            return list.ToArray();
        }

        
        public static string Decode(byte[] bytes)
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < bytes.Length; i += 2)
            {
                stringBuilder.Append((char)bytes[i + 1], (int)bytes[i]);
            }
            return stringBuilder.ToString();
        }
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值