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

Last change on this file since 1787 was 1787, checked in by kopal, 11 years ago
  • enumerations loading bug fixed
File size: 26.6 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                                    if (o is Enum)
179                                    {
180                                        writer.WriteLine("<value>" + o.GetHashCode() + "</value>");
181                                    }
182                                    else
183                                    {
184                                        writer.WriteLine("<value>" + o + "</value>");
185                                    }
186                                }
187                                else
188                                {
189                                    writer.WriteLine("<reference>" + o.GetHashCode() + "</reference>");
190                                }
191                                writer.WriteLine("</entry>");
192                            }
193                        }
194                        writer.WriteLine("</list>");
195                    }
196                    else if (value == null)
197                    {
198                        writer.WriteLine("<value></value>");
199                    }
200                    else if (isPrimitive(value))
201                    {
202                        if (value is Enum)
203                        {
204                            writer.WriteLine("<value>" + value.GetHashCode() + "</value>");
205                        }
206                        else
207                        {
208                            writer.WriteLine("<value>" + ReplaceXMLSymbols(value.ToString()) + "</value>");
209                        }                       
210                    }
211                    else
212                    {
213                        writer.WriteLine("<reference>" + value.GetHashCode() + "</reference>");
214                    }
215                    writer.WriteLine("</member>");
216                } 
217            }
218           
219            writer.WriteLine("</members>");
220            writer.WriteLine("</object>");
221            writer.Flush();
222           
223            //Save obj so that we will not work on it again
224            alreadySerializedObjects.Add(obj);
225
226            foreach (MemberInfo memberInfo in memberInfos)
227            {
228                if (memberInfo.MemberType == MemberTypes.Field)
229                {
230                    string type = obj.GetType().GetField(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FieldType.FullName;
231                    object value = obj.GetType().GetField(memberInfo.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(obj);
232
233                    if (value is System.Collections.IList)
234                    {
235                        foreach (object o in (System.Collections.IList)value)
236                        {
237                            SerializeIt(o, writer, alreadySerializedObjects);
238                        }
239                    }
240                    else
241                    {
242                        SerializeIt(value, writer, alreadySerializedObjects);
243                    }
244                   
245                }             
246            }
247        }
248
249        /// <summary>
250        /// Check if the given object ist Primitve
251        /// Primitive means isPrimitive returns true
252        /// or Fullname does not start with "System"
253        /// </summary>
254        /// <param name="o"></param>
255        /// <returns></returns>
256        private static Boolean isPrimitive(object o)       
257        {
258            if (o == null)
259            {
260                return false;
261            }
262            if (o is Enum)
263            {
264                return true;
265            }
266
267            return (o.GetType().IsPrimitive || o.GetType().FullName.Substring(0, 6).Equals("System"));
268        }
269
270        /// <summary>
271        /// Returns true if MemberType is Field or Property
272        /// </summary>
273        /// <param name="objMemberInfo"></param>
274        /// <param name="objSearch"></param>
275        /// <returns></returns>
276        private static bool DelegateToSearchCriteria(MemberInfo objMemberInfo, Object objSearch)
277        {
278            if (objMemberInfo.MemberType == MemberTypes.Field)
279            {
280                return true;
281            }
282            else
283            {
284                return false;
285            }
286        }
287
288        /// <summary>
289        /// Replaces
290        /// <           with            &lt;
291        /// >           with            &gt;
292        /// &           with            &amp;
293        /// "           with            &quot;
294        /// '           with            &apos;
295        /// If input string is null it returns "null" string
296        /// </summary>
297        /// <param name="str"></param>
298        /// <returns></returns>
299        private static string ReplaceXMLSymbols(String str)
300        {
301            if (str == null)
302            {
303                return "null";
304            }
305
306            return str.
307                Replace("<", "&lt;").
308                Replace(">", "&gt").
309                Replace("&", "&amp;").
310                Replace("\"", "&quot;").
311                Replace("'", "&apos;");
312        }
313
314        /// <summary>
315        /// Inverse to ReplaceXMLSymbols
316        /// </summary>
317        /// <param name="str"></param>
318        /// <returns></returns>
319        private static string RevertXMLSymbols(String str)
320        {
321            if (str == null)
322            {
323                return "null";
324            }
325
326            return str.
327                Replace("&lt;","<").
328                Replace("&gt", ">").
329                Replace("&amp;","&").
330                Replace("&quot;","\"").
331                Replace("&apos;","'");
332        }
333
334        /// <summary>
335        /// Deserializes the given XML and returns the root as obj
336        /// </summary>
337        /// <param name="filename"></param>
338        /// <param name="compress"></param>
339        /// <returns></returns>
340        public static object Deserialize(String filename, bool compress=false)
341        {
342            FileStream sourceFile = File.OpenRead(filename);
343            XmlDocument doc = new XmlDocument(); ;
344            GZipStream compStream = null;
345
346            if (compress)
347            {
348                compStream = new GZipStream(sourceFile, CompressionMode.Decompress);
349                doc.Load(compStream);
350            }
351            else
352            {
353                doc.Load(sourceFile);
354            }
355
356            try
357            {
358                return XMLSerialization.Deserialize(doc);
359            }
360            finally
361            {
362                if (compStream != null)
363                {
364                    compStream.Close();
365                }
366            }
367        }
368
369        /// <summary>
370        /// Deserializes the given XMLDocument and returns the root as obj
371        /// </summary>
372        /// <param name="doc"></param>
373        /// <returns></returns>
374        public static object Deserialize(XmlDocument doc)
375        {
376            Dictionary<string, object> createdObjects = new Dictionary<string, object>();
377            LinkedList<object[]> links = new LinkedList<object[]>();
378
379            XmlElement objects = doc.DocumentElement;
380
381            foreach (XmlNode objct in objects.ChildNodes)
382            {
383                XmlNode type = objct.ChildNodes[0];
384                XmlNode id = objct.ChildNodes[1];
385                XmlNode members = objct.ChildNodes[2];
386
387                object newObject = System.Activator.CreateInstance(Type.GetType(type.InnerText));
388                createdObjects.Add(id.InnerText, newObject);
389
390                foreach (XmlNode member in members.ChildNodes)
391                {
392                    XmlNode membername = member.ChildNodes[0];
393                    XmlNode membertype = member.ChildNodes[1];
394
395                    object newmember;
396
397                    if (member.ChildNodes[2].Name.Equals("value"))
398                    {
399                        XmlNode value = member.ChildNodes[2];
400                        if (RevertXMLSymbols(membertype.InnerText).Equals("System.String"))
401                        {
402
403                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
404                                BindingFlags.NonPublic |
405                                BindingFlags.Public |
406                                BindingFlags.Instance).SetValue(newObject, RevertXMLSymbols(value.InnerText));
407                        }
408                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int16"))
409                        {
410                            Int16 result = 0;
411                            System.Int16.TryParse(RevertXMLSymbols(value.InnerText), out result);
412                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
413                                BindingFlags.NonPublic |
414                                BindingFlags.Public |
415                                BindingFlags.Instance).SetValue(newObject, result);
416                        }
417                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int32"))
418                        {
419                            Int32 result = 0;
420                            System.Int32.TryParse(RevertXMLSymbols(value.InnerText), out result);
421                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
422                                BindingFlags.NonPublic |
423                                BindingFlags.Public |
424                                BindingFlags.Instance).SetValue(newObject, result);
425                        }
426                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Int64"))
427                        {
428                            Int64 result = 0;
429                            System.Int64.TryParse(RevertXMLSymbols(value.InnerText), out result);
430                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
431                                BindingFlags.NonPublic |
432                                BindingFlags.Public |
433                                BindingFlags.Instance).SetValue(newObject, result);
434                        }
435                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Double"))
436                        {
437                            Double result = 0;
438                            System.Double.TryParse(RevertXMLSymbols(value.InnerText), out result);
439                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
440                                BindingFlags.NonPublic |
441                                BindingFlags.Public |
442                                BindingFlags.Instance).SetValue(newObject, result);
443                        }
444                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Char"))
445                        {
446                            Char result = ' ';
447                            System.Char.TryParse(RevertXMLSymbols(value.InnerText), out result);
448                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
449                                BindingFlags.NonPublic |
450                                BindingFlags.Public |
451                                BindingFlags.Instance).SetValue(newObject, result);
452                        }
453                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Boolean"))
454                        {
455                            Boolean result = false;
456                            System.Boolean.TryParse(RevertXMLSymbols(value.InnerText), out result);
457                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
458                                BindingFlags.NonPublic |
459                                BindingFlags.Public |
460                                BindingFlags.Instance).SetValue(newObject, result);
461                        }
462                        else if (RevertXMLSymbols(membertype.InnerText).Equals("System.Windows.Point"))
463                        {
464                            string[] values = value.InnerText.Split(new char[] { ';' });
465
466                            double x = 0;
467                            double y = 0;
468                            double.TryParse(values[0], out x);
469                            double.TryParse(values[1], out y);
470
471                            System.Windows.Point result = new System.Windows.Point(x, y);
472                            newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
473                                BindingFlags.NonPublic |
474                                BindingFlags.Public |
475                                BindingFlags.Instance).SetValue(newObject, result);
476                        }
477                        else
478                        {
479                            newmember = System.Activator.CreateInstance(Type.GetType(RevertXMLSymbols(membertype.InnerText)));
480                           
481                            if (newmember is Enum)
482                            {
483                                Int32 result = 0;
484                                System.Int32.TryParse(RevertXMLSymbols(value.InnerText), out result);
485                                object newEnumValue = Enum.ToObject(Type.GetType(RevertXMLSymbols(membertype.InnerText)), result);
486
487                                newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
488                                    BindingFlags.NonPublic |
489                                    BindingFlags.Public |
490                                    BindingFlags.Instance).SetValue(newObject, newEnumValue);                               
491                            }
492                            else
493                            {
494                                newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
495                                    BindingFlags.NonPublic |
496                                    BindingFlags.Public |
497                                    BindingFlags.Instance).SetValue(newObject, newmember);
498                            }
499
500                        }
501                    }
502                    else if (member.ChildNodes[2].Name.Equals("reference"))
503                    {
504                        XmlNode reference = member.ChildNodes[2];
505                        links.AddLast(new object[] { 
506                                newObject, 
507                                RevertXMLSymbols(membername.InnerText),
508                                RevertXMLSymbols(reference.InnerText),
509                                false});
510                    }
511                    else if (member.ChildNodes[2].Name.Equals("list"))
512                    {
513                        newmember = System.Activator.CreateInstance(Type.GetType(RevertXMLSymbols(membertype.InnerText)));
514                        newObject.GetType().GetField(RevertXMLSymbols(membername.InnerText),
515                                BindingFlags.NonPublic |
516                                BindingFlags.Public |
517                                BindingFlags.Instance).SetValue(newObject, newmember);
518
519                        foreach (XmlNode entry in member.ChildNodes[2].ChildNodes)
520                        {
521                            if (entry.ChildNodes[1].Name.Equals("reference"))
522                            {
523                                XmlNode reference = entry.ChildNodes[1];
524                                links.AddLast(new object[] { 
525                                    newObject, 
526                                    RevertXMLSymbols(membername.InnerText),
527                                    RevertXMLSymbols(reference.InnerText),
528                                    true});
529                            }
530                            else
531                            {
532                                XmlNode typ = entry.ChildNodes[1];
533                                XmlNode value = entry.ChildNodes[1];
534                                if (RevertXMLSymbols(typ.InnerText).Equals("System.String"))
535                                {
536
537                                    ((IList)newmember).Add(RevertXMLSymbols(value.InnerText));
538                                }
539                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int16"))
540                                {
541                                    Int16 result = 0;
542                                    System.Int16.TryParse(RevertXMLSymbols(value.InnerText), out result);
543                                    ((IList)newmember).Add(result);
544                                }
545                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int32"))
546                                {
547                                    Int32 result = 0;
548                                    System.Int32.TryParse(RevertXMLSymbols(value.InnerText), out result);
549                                    ((IList)newmember).Add(result);
550                                }
551                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Int64"))
552                                {
553                                    Int64 result = 0;
554                                    System.Int64.TryParse(RevertXMLSymbols(value.InnerText), out result);
555                                    ((IList)newmember).Add(result);
556                                }
557                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Double"))
558                                {
559                                    Double result = 0;
560                                    System.Double.TryParse(RevertXMLSymbols(value.InnerText), out result);
561                                    ((IList)newmember).Add(result);
562                                }
563                                else if (RevertXMLSymbols(typ.InnerText).Equals("System.Char"))
564                                {
565                                    Char result = ' ';
566                                    System.Char.TryParse(RevertXMLSymbols(value.InnerText), out result);
567                                    ((IList)newmember).Add(result);
568                                }
569                            }
570                        }
571                    }
572                }
573            }
574
575            foreach (object[] triple in links)
576            {
577
578                object obj = triple[0];
579                string membername = (string)triple[1];
580                string reference = (string)triple[2];
581                bool isList = (bool)triple[3];
582                object obj2 = null;
583                createdObjects.TryGetValue(reference, out obj2);
584
585                if (isList)
586                {
587                    ((IList)obj.GetType().GetField(membername).GetValue(obj)).Add(obj2);
588                }
589                else
590                {
591                    if (obj != null && obj2 != null)
592                    {
593                        FieldInfo fieldInfo = obj.GetType().GetField(membername,
594                            BindingFlags.NonPublic |
595                            BindingFlags.Public |
596                            BindingFlags.Instance);
597
598                        fieldInfo.SetValue(obj, obj2);
599                    }
600                }
601            }
602
603            return createdObjects.Values.First();
604        }
605    }
606}
Note: See TracBrowser for help on using the repository browser.