Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Persistence/3.3/Default/Xml/XmlParser.cs @ 14928

Last change on this file since 14928 was 14927, checked in by gkronber, 8 years ago

#2520: changed all usages of StorableClass to use StorableType with an auto-generated GUID (did not add StorableType to other type definitions yet)

File size: 10.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections;
24using System.Collections.Generic;
25using System.IO;
26using System.IO.Compression;
27using System.Xml;
28using HeuristicLab.Persistence.Core;
29using HeuristicLab.Persistence.Core.Tokens;
30using HeuristicLab.Persistence.Interfaces;
31
32namespace HeuristicLab.Persistence.Default.Xml {
33  /// <summary>
34  /// Type of compression used for the Xml stream or file.
35  /// </summary>
36  public enum CompressionType {
37    GZip,
38    Zip
39  }
40
41  /// <summary>
42  /// Main entry point of persistence loading from XML. Use the static
43  /// methods to load from a file or stream.
44  /// </summary>
45  public class XmlParser : IEnumerable<ISerializationToken> {
46
47    private readonly XmlTextReader reader;
48    private delegate IEnumerator<ISerializationToken> Handler();
49    private readonly Dictionary<string, Handler> handlers;
50
51    /// <summary>
52    /// Initializes a new instance of the <see cref="XmlParser"/> class.
53    /// </summary>
54    /// <param name="input">The input.</param>
55    public XmlParser(TextReader input) {
56      reader = new XmlTextReader(input);
57      reader.WhitespaceHandling = WhitespaceHandling.All;
58      reader.Normalization = false;
59      handlers = new Dictionary<string, Handler> {
60                     {XmlStringConstants.PRIMITIVE, ParsePrimitive},
61                     {XmlStringConstants.COMPOSITE, ParseComposite},
62                     {XmlStringConstants.REFERENCE, ParseReference},
63                     {XmlStringConstants.NULL, ParseNull},
64                     {XmlStringConstants.METAINFO, ParseMetaInfo},
65                     {XmlStringConstants.TYPE, ParseTypeInfo},
66                   };
67    }
68
69    /// <summary>
70    /// Returns an enumerator that iterates through the serialization tokens.
71    /// </summary>
72    /// <returns>
73    /// An that can be used to iterate through the collection of serialization tokens.
74    /// </returns>
75    public IEnumerator<ISerializationToken> GetEnumerator() {
76      while (reader.Read()) {
77        if (!reader.IsStartElement()) {
78          break;
79        }
80        IEnumerator<ISerializationToken> iterator;
81        try {
82          iterator = handlers[reader.Name].Invoke();
83        } catch (KeyNotFoundException) {
84          throw new PersistenceException(String.Format(
85            "Invalid XML tag \"{0}\" in persistence file.",
86            reader.Name));
87        }
88        while (iterator.MoveNext()) {
89          yield return iterator.Current;
90        }
91      }
92    }
93
94    /// <summary>
95    /// Returns an enumerator that iterates through the serialization tokens.
96    /// </summary>
97    /// <returns>
98    /// An that can be used to iterate through the collection of serialization tokens.
99    /// </returns>
100    IEnumerator IEnumerable.GetEnumerator() {
101      return GetEnumerator();
102    }
103
104    private IEnumerator<ISerializationToken> ParsePrimitive() {
105      int? id = null;
106      string idString = reader.GetAttribute("id");
107      if (idString != null)
108        id = int.Parse(idString);
109      string name = reader.GetAttribute("name");
110      int typeId = int.Parse(reader.GetAttribute("typeId"));
111      string typeName = reader.GetAttribute("typeName");
112      string serializer = reader.GetAttribute("serializer");
113      if (typeName != null)
114        yield return new TypeToken(typeId, typeName, serializer);
115      XmlReader inner = reader.ReadSubtree();
116      inner.Read();
117      string xml = inner.ReadInnerXml();
118      inner.Close();
119      yield return new PrimitiveToken(name, typeId, id, new XmlString(xml));
120    }
121
122    private IEnumerator<ISerializationToken> ParseComposite() {
123      string name = reader.GetAttribute("name");
124      string idString = reader.GetAttribute("id");
125      int? id = null;
126      if (idString != null)
127        id = int.Parse(idString);
128      int typeId = int.Parse(reader.GetAttribute("typeId"));
129      string typeName = reader.GetAttribute("typeName");
130      string serializer = reader.GetAttribute("serializer");
131      if (typeName != null)
132        yield return new TypeToken(typeId, typeName, serializer);
133      yield return new BeginToken(name, typeId, id);
134      IEnumerator<ISerializationToken> iterator = GetEnumerator();
135      while (iterator.MoveNext())
136        yield return iterator.Current;
137      yield return new EndToken(name, typeId, id);
138    }
139
140    private IEnumerator<ISerializationToken> ParseReference() {
141      yield return new ReferenceToken(
142        reader.GetAttribute("name"),
143        int.Parse(reader.GetAttribute("ref")));
144    }
145
146    private IEnumerator<ISerializationToken> ParseNull() {
147      yield return new NullReferenceToken(reader.GetAttribute("name"));
148    }
149
150    private IEnumerator<ISerializationToken> ParseMetaInfo() {
151      yield return new MetaInfoBeginToken();
152      IEnumerator<ISerializationToken> iterator = GetEnumerator();
153      while (iterator.MoveNext())
154        yield return iterator.Current;
155      yield return new MetaInfoEndToken();
156    }
157
158    private IEnumerator<ISerializationToken> ParseTypeInfo() {
159      yield return new TypeToken(
160        int.Parse(reader.GetAttribute("id")),
161        reader.GetAttribute("typeName"),
162        reader.GetAttribute("serializer"));
163    }
164
165    /// <summary>
166    /// Parses the type cache.
167    /// </summary>
168    /// <param name="reader">The reader.</param>
169    /// <returns>A list of type mapping entries.</returns>
170    public static List<TypeMapping> ParseTypeCache(TextReader reader) {
171      try {
172        var typeCache = new List<TypeMapping>();
173        XmlReader xmlReader = XmlReader.Create(reader);
174        while (xmlReader.Read()) {
175          if (xmlReader.Name == XmlStringConstants.TYPE) {
176            typeCache.Add(new TypeMapping(
177              int.Parse(xmlReader.GetAttribute("id")),
178              xmlReader.GetAttribute("typeName"),
179              xmlReader.GetAttribute("serializer")));
180          }
181        }
182        return typeCache;
183      } catch (PersistenceException) {
184        throw;
185      } catch (Exception e) {
186        throw new PersistenceException("Unexpected exception during type cache parsing.", e);
187      }
188    }
189
190    /// <summary>
191    /// Deserializes an object from the specified filename.
192    /// </summary>
193    /// <param name="filename">The filename.</param>
194    /// <returns>A fresh object instance</returns>
195    public static object Deserialize(string filename) {
196      TimeSpan start = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
197      try {
198        using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
199          using (ZipArchive zip = new ZipArchive(fs)) {
200            return Deserialize(zip);
201          }
202        }
203      } finally {
204        TimeSpan end = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
205        Tracing.Logger.Info(string.Format(
206          "deserialization of {0} took {1} seconds",
207          filename, (end - start).TotalSeconds));
208      }
209    }
210
211    /// <summary>
212    /// Deserializes the specified filename.
213    /// </summary>
214    /// <typeparam name="T">object type expected from the serialized file</typeparam>
215    /// <param name="filename">The filename.</param>
216    /// <returns>A fresh object of type T</returns>
217    public static T Deserialize<T>(string filename) {
218      return (T)Deserialize(filename);
219    }
220
221    /// <summary>
222    /// Deserializes an object from the specified stream.
223    /// </summary>
224    /// <typeparam name="T">object type expected from the serialized stream</typeparam>
225    /// <param name="stream">The stream.</param>
226    /// <param name="compressionType">Type of compression, default is GZip.</param>
227    /// <returns>A fresh object instance.</returns>
228    public static T Deserialize<T>(Stream stream, CompressionType compressionType = CompressionType.GZip) {
229      return (T)Deserialize(stream, compressionType);
230    }
231
232    /// <summary>
233    /// Deserializes an object from the specified stream.
234    /// </summary>
235    /// <param name="stream">The stream.</param>
236    /// <param name="compressionType">Type of compression, default is GZip.</param>
237    /// <returns>A fresh object instance.</returns>
238    public static object Deserialize(Stream stream, CompressionType compressionType = CompressionType.GZip) {
239      if (compressionType == CompressionType.Zip) {
240        ZipArchive zipFile = new ZipArchive(stream);
241        return Deserialize(zipFile);
242      } else {
243        try {
244          using (StreamReader reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress))) {
245            XmlParser parser = new XmlParser(reader);
246            Deserializer deserializer = new Deserializer(new TypeMapping[] { });
247            return deserializer.Deserialize(parser);
248          }
249        } catch (PersistenceException) {
250          throw;
251        } catch (Exception x) {
252          throw new PersistenceException("Unexpected exception during deserialization", x);
253        }
254      }
255    }
256
257    private static object Deserialize(ZipArchive zipFile) {
258      try {
259        ZipArchiveEntry typecache = zipFile.GetEntry("typecache.xml");
260        if (typecache == null) throw new PersistenceException("file does not contain typecache.xml");
261        Deserializer deSerializer;
262        using (StreamReader sr = new StreamReader(typecache.Open())) {
263          deSerializer = new Deserializer(ParseTypeCache(sr));
264        }
265
266        ZipArchiveEntry data = zipFile.GetEntry("data.xml");
267        if (data == null) throw new PersistenceException("file does not contain data.xml");
268        object result;
269        using (StreamReader sr = new StreamReader(data.Open())) {
270          XmlParser parser = new XmlParser(sr);
271          result = deSerializer.Deserialize(parser);
272        }
273
274        return result;
275      } catch (PersistenceException) {
276        throw;
277      } catch (Exception e) {
278        throw new PersistenceException("Unexpected exception during deserialization", e);
279      }
280    }
281  }
282}
Note: See TracBrowser for help on using the repository browser.