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

Last change on this file since 1784 was 1784, checked in by kopal, 11 years ago
  • now Enumerations will be serialized without errors
File size: 25.1 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            if (o is Enum)
249            {
250                return true;
251            }
252
253            return (o.GetType().IsPrimitive || o.GetType().FullName.Substring(0, 6).Equals("System"));
254        }
255
256        /// <summary>
257        /// Returns true if MemberType is Field or Property
258        /// </summary>
259        /// <param name="objMemberInfo"></param>
260        /// <param name="objSearch"></param>
261        /// <returns></returns>
262        private static bool DelegateToSearchCriteria(MemberInfo objMemberInfo, Object objSearch)
263        {
264            if (objMemberInfo.MemberType == MemberTypes.Field)
265            {
266                return true;
267            }
268            else
269            {
270                return false;
271            }
272        }
273
274        /// <summary>
275        /// Replaces
276        /// <           with            &lt;
277        /// >           with            &gt;
278        /// &           with            &amp;
279        /// "           with            &quot;
280        /// '           with            &apos;
281        /// If input string is null it returns "null" string
282        /// </summary>
283        /// <param name="str"></param>
284        /// <returns></returns>
285        private static string ReplaceXMLSymbols(String str)
286        {
287            if (str == null)
288            {
289                return "null";
290            }
291
292            return str.
293                Replace("<", "&lt;").
294                Replace(">", "&gt").
295                Replace("&", "&amp;").
296                Replace("\"", "&quot;").
297                Replace("'", "&apos;");
298        }
299
300        /// <summary>
301        /// Inverse to ReplaceXMLSymbols
302        /// </summary>
303        /// <param name="str"></param>
304        /// <returns></returns>
305        private static string RevertXMLSymbols(String str)
306        {
307            if (str == null)
308            {
309                return "null";
310            }
311
312            return str.
313                Replace("&lt;","<").
314                Replace("&gt", ">").
315                Replace("&amp;","&").
316                Replace("&quot;","\"").
317                Replace("&apos;","'");
318        }
319
320        /// <summary>
321        /// Deserializes the given XML and returns the root as obj
322        /// </summary>
323        /// <param name="filename"></param>
324        /// <param name="compress"></param>
325        /// <returns></returns>
326        public static object Deserialize(String filename, bool compress=false)
327        {
328            FileStream sourceFile = File.OpenRead(filename);
329            XmlDocument doc = new XmlDocument(); ;
330            GZipStream compStream = null;
331
332            if (compress)
333            {
334                compStream = new GZipStream(sourceFile, CompressionMode.Decompress);
335                doc.Load(compStream);
336            }
337            else
338            {
339                doc.Load(sourceFile);
340            }
341
342            try
343            {
344                return XMLSerialization.Deserialize(doc);
345            }
346            finally
347            {
348                if (compStream != null)
349                {
350                    compStream.Close();
351                }
352            }
353        }
354
355        /// <summary>
356        /// Deserializes the given XMLDocument and returns the root as obj
357        /// </summary>
358        /// <param name="doc"></param>
359        /// <returns></returns>
360        public static object Deserialize(XmlDocument doc)
361        {
362            Dictionary<string, object> createdObjects = new Dictionary<string, object>();
363            LinkedList<object[]> links = new LinkedList<object[]>();
364
365            XmlElement objects = doc.DocumentElement;
366
367            foreach (XmlNode objct in objects.ChildNodes)
368            {
369                XmlNode type = objct.ChildNodes[0];
370                XmlNode id = objct.ChildNodes[1];
371                XmlNode members = objct.ChildNodes[2];
372
373                object newObject = System.Activator.CreateInstance(Type.GetType(type.InnerText));
374                createdObjects.Add(id.InnerText, newObject);
375
376                foreach (XmlNode member in members.ChildNodes)
377                {
378                    XmlNode membername = member.ChildNodes[0];
379                    XmlNode membertype = member.ChildNodes[1];
380
381                    object newmember;
382
383                    if (member.ChildNodes[2].Name.Equals("value"))
384                    {
385                        XmlNode value = member.ChildNodes[2];
386                        if (RevertXMLSymbols(membertype.InnerText).Equals("System.String"))
387                        {
388
389                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
390                                BindingFlags.NonPublic |
391                                BindingFlags.Public |
392                                BindingFlags.Instance).SetValue(newObject, RevertXMLSymbols(value.InnerText));
393                        }
394                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int16"))
395                        {
396                            Int16 result = 0;
397                            System.Int16.TryParse(RevertXMLSymbols(value.InnerText), out result);
398                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
399                                BindingFlags.NonPublic |
400                                BindingFlags.Public |
401                                BindingFlags.Instance).SetValue(newObject, result);
402                        }
403                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int32"))
404                        {
405                            Int32 result = 0;
406                            System.Int32.TryParse(RevertXMLSymbols(value.InnerText), out result);
407                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
408                                BindingFlags.NonPublic |
409                                BindingFlags.Public |
410                                BindingFlags.Instance).SetValue(newObject, result);
411                        }
412                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int64"))
413                        {
414                            Int64 result = 0;
415                            System.Int64.TryParse(RevertXMLSymbols(value.InnerText), out result);
416                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
417                                BindingFlags.NonPublic |
418                                BindingFlags.Public |
419                                BindingFlags.Instance).SetValue(newObject, result);
420                        }
421                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Double"))
422                        {
423                            Double result = 0;
424                            System.Double.TryParse(RevertXMLSymbols(value.InnerText), out result);
425                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
426                                BindingFlags.NonPublic |
427                                BindingFlags.Public |
428                                BindingFlags.Instance).SetValue(newObject, result);
429                        }
430                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Char"))
431                        {
432                            Char result = ' ';
433                            System.Char.TryParse(RevertXMLSymbols(value.InnerText), out result);
434                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
435                                BindingFlags.NonPublic |
436                                BindingFlags.Public |
437                                BindingFlags.Instance).SetValue(newObject, result);
438                        }
439                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Boolean"))
440                        {
441                            Boolean result = false;
442                            System.Boolean.TryParse(RevertXMLSymbols(value.InnerText), out result);
443                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
444                                BindingFlags.NonPublic |
445                                BindingFlags.Public |
446                                BindingFlags.Instance).SetValue(newObject, result);
447                        }
448                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Windows.Point"))
449                        {
450                            string[] values = value.InnerText.Split(new char[] { ';' });
451
452                            double x = 0;
453                            double y = 0;
454                            double.TryParse(values[0], out x);
455                            double.TryParse(values[1], out y);
456
457                            System.Windows.Point result = new System.Windows.Point(x, y);
458                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
459                                BindingFlags.NonPublic |
460                                BindingFlags.Public |
461                                BindingFlags.Instance).SetValue(newObject, result);
462                        }
463                        else
464                        {
465                            newmember = System.Activator.CreateInstance(Type.GetType(RevertXMLSymbols(membertype.InnerText)));
466                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
467                                BindingFlags.NonPublic |
468                                BindingFlags.Public |
469                                BindingFlags.Instance).SetValue(newObject, newmember);
470                        }
471                    }
472                    else if (member.ChildNodes[2].Name.Equals("reference"))
473                    {
474                        XmlNode reference = member.ChildNodes[2];
475                        links.AddLast(new object[] { 
476                                newObject, 
477                                RevertXMLSymbols(membername.InnerText),
478                                RevertXMLSymbols(reference.InnerText),
479                                false});
480                    }
481                    else if (member.ChildNodes[2].Name.Equals("list"))
482                    {
483                        newmember = System.Activator.CreateInstance(Type.GetType(RevertXMLSymbols(membertype.InnerText)));
484                        newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
485                                BindingFlags.NonPublic |
486                                BindingFlags.Public |
487                                BindingFlags.Instance).SetValue(newObject, newmember);
488
489                        foreach (XmlNode entry in member.ChildNodes[2].ChildNodes)
490                        {
491                            if (entry.ChildNodes[1].Name.Equals("reference"))
492                            {
493                                XmlNode reference = entry.ChildNodes[1];
494                                links.AddLast(new object[] { 
495                                    newObject, 
496                                    RevertXMLSymbols(membername.InnerText),
497                                    RevertXMLSymbols(reference.InnerText),
498                                    true});
499                            }
500                            else
501                            {
502                                XmlNode typ = entry.ChildNodes[1];
503                                XmlNode value = entry.ChildNodes[1];
504                                if (RevertXMLSymbols(typ.InnerText).Equals("System.String"))
505                                {
506
507                                    ((IList)newmember).Add(RevertXMLSymbols(value.InnerText));
508                                }
509                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int16"))
510                                {
511                                    Int16 result = 0;
512                                    System.Int16.TryParse(RevertXMLSymbols(value.InnerText), out result);
513                                    ((IList)newmember).Add(result);
514                                }
515                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int32"))
516                                {
517                                    Int32 result = 0;
518                                    System.Int32.TryParse(RevertXMLSymbols(value.InnerText), out result);
519                                    ((IList)newmember).Add(result);
520                                }
521                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int64"))
522                                {
523                                    Int64 result = 0;
524                                    System.Int64.TryParse(RevertXMLSymbols(value.InnerText), out result);
525                                    ((IList)newmember).Add(result);
526                                }
527                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Double"))
528                                {
529                                    Double result = 0;
530                                    System.Double.TryParse(RevertXMLSymbols(value.InnerText), out result);
531                                    ((IList)newmember).Add(result);
532                                }
533                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Char"))
534                                {
535                                    Char result = ' ';
536                                    System.Char.TryParse(RevertXMLSymbols(value.InnerText), out result);
537                                    ((IList)newmember).Add(result);
538                                }
539                            }
540                        }
541                    }
542                }
543            }
544
545            foreach (object[] triple in links)
546            {
547
548                object obj = triple[0];
549                string membername = (string)triple[1];
550                string reference = (string)triple[2];
551                bool isList = (bool)triple[3];
552                object obj2 = null;
553                createdObjects.TryGetValue(reference, out obj2);
554
555                if (isList)
556                {
557                    ((IList)obj.GetType().GetField(membername).GetValue(obj)).Add(obj2);
558                }
559                else
560                {
561                    if (obj != null && obj2 != null)
562                    {
563                        FieldInfo fieldInfo = obj.GetType().GetField(membername,
564                            BindingFlags.NonPublic |
565                            BindingFlags.Public |
566                            BindingFlags.Instance);
567
568                        fieldInfo.SetValue(obj, obj2);
569                    }
570                }
571            }
572
573            return createdObjects.Values.First();
574        }
575    }
576}
Note: See TracBrowser for help on using the repository browser.