source: trunk/CrypPlugins/WorkspaceManager/Model/XMLSerialization.cs @ 1782

Last change on this file since 1782 was 1782, checked in by kopal, 11 years ago
  • XMLSerialization now uses GZip to compress created XML documents and GZip to decompress XML documents
File size: 25.0 KB
Line 
1/*                             
2   Copyright 2010 Nils Kopal, Viktor M.
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21using System.Reflection;
22using System.IO;
23using System.Xml;
24using System.Collections;
25using System.IO.Compression;
26
27namespace XMLSerialization
28{
29    /// <summary>
30    /// Provides static methods for XML serialization and deserialization
31    /// </summary>
32    public class XMLSerialization
33    {
34        /// <summary>
35        /// Serializes the given object and all of its members to the given file using UTF-8 encoding
36        /// Works only on objects which are marked as "Serializable"
37        /// If compress==true then GZip is used for compressing
38        /// </summary>
39        /// <param name="obj"></param>
40        /// <param name="filename"></param>
41        /// /// <param name="compress"></param>
42        public static void Serialize(object obj, string filename,bool compress = false)
43        {
44            XMLSerialization.Serialize(obj, filename, Encoding.UTF8,compress);
45        }
46
47        /// <summary>
48        /// Serializes the given object and all of its members to the given file using
49        /// the given encoding
50        /// Works only on objects which are marked as "Serializable"
51        /// If compress==true then GZip is used for compressing
52        /// </summary>
53        /// <param name="obj"></param>
54        /// <param name="filename"></param>
55        /// <param name="compress"></param>
56        public static void Serialize(object obj, string filename,Encoding encoding,bool compress = false)
57        {
58
59            FileStream sourceFile = File.OpenWrite(filename);
60            if (compress)
61            {
62                GZipStream compStream = new GZipStream(sourceFile, CompressionMode.Compress);
63                StreamWriter writer = new StreamWriter(compStream);
64                try
65                {
66
67                    XMLSerialization.Serialize(obj, writer,compress);
68                }
69                finally
70                {
71                    if (writer != null)
72                    {
73                        writer.Close();
74                    }
75                    if (compStream != null)
76                    {
77                        compStream.Dispose();
78                    }
79                    if (sourceFile != null)
80                    {
81                        sourceFile.Close();
82                    }
83                }
84            }
85            else
86            {
87                StreamWriter writer = new StreamWriter(sourceFile);
88                try
89                {
90                   
91                    XMLSerialization.Serialize(obj, writer);
92                }
93                finally
94                {
95                    if (writer != null)
96                    {
97                        writer.Close();
98                    }                   
99                    if (sourceFile != null)
100                    {
101                        sourceFile.Close();
102                    }
103                }
104            }
105        }
106        /// <summary>
107        /// Serializes the given object and all of its members to the given writer as xml
108        /// Works only on objects which are marked as "Serializable"
109        /// </summary>
110        /// <param name="obj"></param>
111        /// <param name="writer"></param>
112        public static void Serialize(object obj, StreamWriter writer,bool compress=false)
113        {
114            HashSet<object> alreadySerializedObjects = new HashSet<object>();
115
116            writer.WriteLine("<?xml version=\"1.0\" encoding=\"" + writer.Encoding.HeaderName + "\"?>");
117            writer.WriteLine("<!--");
118            writer.WriteLine("     XML serialized C# Objects");
119            writer.WriteLine("     File created: " + System.DateTime.Now);
120            writer.WriteLine("     File compressed: " + compress);
121            writer.WriteLine("     XMLSerialization created by Nils Kopal");
122            writer.WriteLine("     mailto: Nils.Kopal(AT)stud.uni-due.de");
123            writer.WriteLine("-->");
124            writer.WriteLine("<objects>");
125            SerializeIt(obj, writer, alreadySerializedObjects);
126            writer.WriteLine("</objects>");
127            writer.Flush();
128        }
129
130        /// <summary>
131        /// Serializes the given object and all of its members to the given writer as xml
132        /// Works only on object which are marked as "Serializable"
133        /// </summary>
134        /// <param name="obj"></param>
135        /// <param name="writer"></param>
136        private static void SerializeIt(object obj, StreamWriter writer,HashSet<object> alreadySerializedObjects)
137        {
138            //we only work on complex objects which are serializable and we did not see before
139            if (obj == null || 
140                isPrimitive(obj) || 
141                !obj.GetType().IsSerializable || 
142                alreadySerializedObjects.Contains(obj))
143            {
144                return;
145            }
146
147            MemberInfo[] memberInfos = obj.GetType().FindMembers(
148                MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, new MemberFilter(DelegateToSearchCriteria), "ReferenceEquals");
149           
150            writer.WriteLine("<object>");
151            writer.WriteLine("<type>" + obj.GetType().FullName + "</type>");
152            writer.WriteLine("<id>" + obj.GetHashCode() + "</id>");
153
154            writer.WriteLine("<members>");
155
156            foreach (MemberInfo memberInfo in memberInfos)
157            {
158                if (memberInfo.MemberType == MemberTypes.Field && !obj.GetType().GetField(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).IsNotSerialized)
159                {
160                    string type = obj.GetType().GetField(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FieldType.FullName;
161                    object value = obj.GetType().GetField(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(obj);
162                   
163                    writer.WriteLine("<member>");
164                    writer.WriteLine("<name>" + ReplaceXMLSymbols(memberInfo.Name) + "</name>");                                       
165                    writer.WriteLine("<type>" + ReplaceXMLSymbols(type) + "</type>");
166                   
167                    if(value is System.Collections.IList)
168                    {
169                        writer.WriteLine("<list>");
170                        foreach (object o in (System.Collections.IList)value)
171                        {
172                            if (o.GetType().IsSerializable)
173                            {
174                                writer.WriteLine("<entry>");
175                                writer.WriteLine("<type>" + o.GetType().FullName + "</type>");
176                                if (isPrimitive(o))
177                                {
178                                    writer.WriteLine("<value>" + o + "</value>");
179                                }
180                                else
181                                {
182                                    writer.WriteLine("<reference>" + o.GetHashCode() + "</reference>");
183                                }
184                                writer.WriteLine("</entry>");
185                            }
186                        }
187                        writer.WriteLine("</list>");
188                    }
189                    else if (value == null)
190                    {
191                        writer.WriteLine("<value></value>");
192                    }
193                    else if (isPrimitive(value))
194                    {
195                        writer.WriteLine("<value>" + ReplaceXMLSymbols(value.ToString()) + "</value>");
196                    }
197                    else
198                    {
199                        writer.WriteLine("<reference>" + value.GetHashCode() + "</reference>");
200                    }
201                    writer.WriteLine("</member>");
202                } 
203            }
204           
205            writer.WriteLine("</members>");
206            writer.WriteLine("</object>");
207            writer.Flush();
208           
209            //Save obj so that we will not work on it again
210            alreadySerializedObjects.Add(obj);
211
212            foreach (MemberInfo memberInfo in memberInfos)
213            {
214                if (memberInfo.MemberType == MemberTypes.Field)
215                {
216                    string type = obj.GetType().GetField(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FieldType.FullName;
217                    object value = obj.GetType().GetField(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(obj);
218
219                    if (value is System.Collections.IList)
220                    {
221                        foreach (object o in (System.Collections.IList)value)
222                        {
223                            SerializeIt(o, writer, alreadySerializedObjects);
224                        }
225                    }
226                    else
227                    {
228                        SerializeIt(value, writer, alreadySerializedObjects);
229                    }
230                   
231                }             
232            }
233        }
234
235        /// <summary>
236        /// Check if the given object ist Primitve
237        /// Primitive means isPrimitive returns true
238        /// or Fullname does not start with "System"
239        /// </summary>
240        /// <param name="o"></param>
241        /// <returns></returns>
242        private static Boolean isPrimitive(object o)       
243        {
244            if (o == null)
245            {
246                return false;
247            }
248            return (o.GetType().IsPrimitive || o.GetType().FullName.Substring(0, 6).Equals("System"));
249        }
250
251        /// <summary>
252        /// Returns true if MemberType is Field or Property
253        /// </summary>
254        /// <param name="objMemberInfo"></param>
255        /// <param name="objSearch"></param>
256        /// <returns></returns>
257        private static bool DelegateToSearchCriteria(MemberInfo objMemberInfo, Object objSearch)
258        {
259            if (objMemberInfo.MemberType == MemberTypes.Field)
260            {
261                return true;
262            }
263            else
264            {
265                return false;
266            }
267        }
268
269        /// <summary>
270        /// Replaces
271        /// <           with            &lt;
272        /// >           with            &gt;
273        /// &           with            &amp;
274        /// "           with            &quot;
275        /// '           with            &apos;
276        /// If input string is null it returns "null" string
277        /// </summary>
278        /// <param name="str"></param>
279        /// <returns></returns>
280        private static string ReplaceXMLSymbols(String str)
281        {
282            if (str == null)
283            {
284                return "null";
285            }
286
287            return str.
288                Replace("<", "&lt;").
289                Replace(">", "&gt").
290                Replace("&", "&amp;").
291                Replace("\"", "&quot;").
292                Replace("'", "&apos;");
293        }
294
295        /// <summary>
296        /// Inverse to ReplaceXMLSymbols
297        /// </summary>
298        /// <param name="str"></param>
299        /// <returns></returns>
300        private static string RevertXMLSymbols(String str)
301        {
302            if (str == null)
303            {
304                return "null";
305            }
306
307            return str.
308                Replace("&lt;","<").
309                Replace("&gt", ">").
310                Replace("&amp;","&").
311                Replace("&quot;","\"").
312                Replace("&apos;","'");
313        }
314
315        /// <summary>
316        /// Deserializes the given XML and returns the root as obj
317        /// </summary>
318        /// <param name="filename"></param>
319        /// <param name="compress"></param>
320        /// <returns></returns>
321        public static object Deserialize(String filename, bool compress=false)
322        {
323            FileStream sourceFile = File.OpenRead(filename);
324            XmlDocument doc = new XmlDocument(); ;
325            GZipStream compStream = null;
326
327            if (compress)
328            {
329                compStream = new GZipStream(sourceFile, CompressionMode.Decompress);
330                doc.Load(compStream);
331            }
332            else
333            {
334                doc.Load(sourceFile);
335            }
336
337            try
338            {
339                return XMLSerialization.Deserialize(doc);
340            }
341            finally
342            {
343                if (compStream != null)
344                {
345                    compStream.Close();
346                }
347            }
348        }
349
350        /// <summary>
351        /// Deserializes the given XMLDocument and returns the root as obj
352        /// </summary>
353        /// <param name="doc"></param>
354        /// <returns></returns>
355        public static object Deserialize(XmlDocument doc)
356        {
357            Dictionary<string, object> createdObjects = new Dictionary<string, object>();
358            LinkedList<object[]> links = new LinkedList<object[]>();
359
360            XmlElement objects = doc.DocumentElement;
361
362            foreach (XmlNode objct in objects.ChildNodes)
363            {
364                XmlNode type = objct.ChildNodes[0];
365                XmlNode id = objct.ChildNodes[1];
366                XmlNode members = objct.ChildNodes[2];
367
368                object newObject = System.Activator.CreateInstance(Type.GetType(type.InnerText));
369                createdObjects.Add(id.InnerText, newObject);
370
371                foreach (XmlNode member in members.ChildNodes)
372                {
373                    XmlNode membername = member.ChildNodes[0];
374                    XmlNode membertype = member.ChildNodes[1];
375
376                    object newmember;
377
378                    if (member.ChildNodes[2].Name.Equals("value"))
379                    {
380                        XmlNode value = member.ChildNodes[2];
381                        if (RevertXMLSymbols(membertype.InnerText).Equals("System.String"))
382                        {
383
384                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
385                                BindingFlags.NonPublic |
386                                BindingFlags.Public |
387                                BindingFlags.Instance).SetValue(newObject, RevertXMLSymbols(value.InnerText));
388                        }
389                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int16"))
390                        {
391                            Int16 result = 0;
392                            System.Int16.TryParse(RevertXMLSymbols(value.InnerText), out result);
393                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
394                                BindingFlags.NonPublic |
395                                BindingFlags.Public |
396                                BindingFlags.Instance).SetValue(newObject, result);
397                        }
398                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int32"))
399                        {
400                            Int32 result = 0;
401                            System.Int32.TryParse(RevertXMLSymbols(value.InnerText), out result);
402                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
403                                BindingFlags.NonPublic |
404                                BindingFlags.Public |
405                                BindingFlags.Instance).SetValue(newObject, result);
406                        }
407                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int64"))
408                        {
409                            Int64 result = 0;
410                            System.Int64.TryParse(RevertXMLSymbols(value.InnerText), out result);
411                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
412                                BindingFlags.NonPublic |
413                                BindingFlags.Public |
414                                BindingFlags.Instance).SetValue(newObject, result);
415                        }
416                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Double"))
417                        {
418                            Double result = 0;
419                            System.Double.TryParse(RevertXMLSymbols(value.InnerText), out result);
420                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
421                                BindingFlags.NonPublic |
422                                BindingFlags.Public |
423                                BindingFlags.Instance).SetValue(newObject, result);
424                        }
425                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Char"))
426                        {
427                            Char result = ' ';
428                            System.Char.TryParse(RevertXMLSymbols(value.InnerText), out result);
429                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
430                                BindingFlags.NonPublic |
431                                BindingFlags.Public |
432                                BindingFlags.Instance).SetValue(newObject, result);
433                        }
434                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Boolean"))
435                        {
436                            Boolean result = false;
437                            System.Boolean.TryParse(RevertXMLSymbols(value.InnerText), out result);
438                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
439                                BindingFlags.NonPublic |
440                                BindingFlags.Public |
441                                BindingFlags.Instance).SetValue(newObject, result);
442                        }
443                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Windows.Point"))
444                        {
445                            string[] values = value.InnerText.Split(new char[] { ';' });
446
447                            double x = 0;
448                            double y = 0;
449                            double.TryParse(values[0], out x);
450                            double.TryParse(values[1], out y);
451
452                            System.Windows.Point result = new System.Windows.Point(x, y);
453                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
454                                BindingFlags.NonPublic |
455                                BindingFlags.Public |
456                                BindingFlags.Instance).SetValue(newObject, result);
457                        }
458                        else
459                        {
460                            newmember = System.Activator.CreateInstance(Type.GetType(RevertXMLSymbols(membertype.InnerText)));
461                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
462                                BindingFlags.NonPublic |
463                                BindingFlags.Public |
464                                BindingFlags.Instance).SetValue(newObject, newmember);
465                        }
466                    }
467                    else if (member.ChildNodes[2].Name.Equals("reference"))
468                    {
469                        XmlNode reference = member.ChildNodes[2];
470                        links.AddLast(new object[] { 
471                                newObject, 
472                                RevertXMLSymbols(membername.InnerText),
473                                RevertXMLSymbols(reference.InnerText),
474                                false});
475                    }
476                    else if (member.ChildNodes[2].Name.Equals("list"))
477                    {
478                        newmember = System.Activator.CreateInstance(Type.GetType(RevertXMLSymbols(membertype.InnerText)));
479                        newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
480                                BindingFlags.NonPublic |
481                                BindingFlags.Public |
482                                BindingFlags.Instance).SetValue(newObject, newmember);
483
484                        foreach (XmlNode entry in member.ChildNodes[2].ChildNodes)
485                        {
486                            if (entry.ChildNodes[1].Name.Equals("reference"))
487                            {
488                                XmlNode reference = entry.ChildNodes[1];
489                                links.AddLast(new object[] { 
490                                    newObject, 
491                                    RevertXMLSymbols(membername.InnerText),
492                                    RevertXMLSymbols(reference.InnerText),
493                                    true});
494                            }
495                            else
496                            {
497                                XmlNode typ = entry.ChildNodes[1];
498                                XmlNode value = entry.ChildNodes[1];
499                                if (RevertXMLSymbols(typ.InnerText).Equals("System.String"))
500                                {
501
502                                    ((IList)newmember).Add(RevertXMLSymbols(value.InnerText));
503                                }
504                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int16"))
505                                {
506                                    Int16 result = 0;
507                                    System.Int16.TryParse(RevertXMLSymbols(value.InnerText), out result);
508                                    ((IList)newmember).Add(result);
509                                }
510                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int32"))
511                                {
512                                    Int32 result = 0;
513                                    System.Int32.TryParse(RevertXMLSymbols(value.InnerText), out result);
514                                    ((IList)newmember).Add(result);
515                                }
516                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int64"))
517                                {
518                                    Int64 result = 0;
519                                    System.Int64.TryParse(RevertXMLSymbols(value.InnerText), out result);
520                                    ((IList)newmember).Add(result);
521                                }
522                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Double"))
523                                {
524                                    Double result = 0;
525                                    System.Double.TryParse(RevertXMLSymbols(value.InnerText), out result);
526                                    ((IList)newmember).Add(result);
527                                }
528                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Char"))
529                                {
530                                    Char result = ' ';
531                                    System.Char.TryParse(RevertXMLSymbols(value.InnerText), out result);
532                                    ((IList)newmember).Add(result);
533                                }
534                            }
535                        }
536                    }
537                }
538            }
539
540            foreach (object[] triple in links)
541            {
542
543                object obj = triple[0];
544                string membername = (string)triple[1];
545                string reference = (string)triple[2];
546                bool isList = (bool)triple[3];
547                object obj2 = null;
548                createdObjects.TryGetValue(reference, out obj2);
549
550                if (isList)
551                {
552                    ((IList)obj.GetType().GetField(membername).GetValue(obj)).Add(obj2);
553                }
554                else
555                {
556                    if (obj != null && obj2 != null)
557                    {
558                        FieldInfo fieldInfo = obj.GetType().GetField(membername,
559                            BindingFlags.NonPublic |
560                            BindingFlags.Public |
561                            BindingFlags.Instance);
562
563                        fieldInfo.SetValue(obj, obj2);
564                    }
565                }
566            }
567
568            return createdObjects.Values.First();
569        }
570    }
571}
Note: See TracBrowser for help on using the repository browser.