Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Persistence/3.3/Default/Xml/XmlParser.cs @ 17983

Last change on this file since 17983 was 17181, checked in by swagner, 5 years ago

#2875: Merged r17180 from trunk to stable

File size: 11.4 KB
RevLine 
[3742]1#region License Information
2/* HeuristicLab
[17181]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3742]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
[1454]22using System;
23using System.Collections;
[4068]24using System.Collections.Generic;
[1454]25using System.IO;
[4068]26using System.IO.Compression;
27using System.Xml;
[17097]28using HEAL.Attic;
[1454]29using HeuristicLab.Persistence.Core;
[4068]30using HeuristicLab.Persistence.Core.Tokens;
[1454]31using HeuristicLab.Persistence.Interfaces;
32
33namespace HeuristicLab.Persistence.Default.Xml {
[12727]34  /// <summary>
35  /// Type of compression used for the Xml stream or file.
36  /// </summary>
37  public enum CompressionType {
38    GZip,
39    Zip
40  }
[1454]41
[3028]42  /// <summary>
43  /// Main entry point of persistence loading from XML. Use the static
44  /// methods to load from a file or stream.
45  /// </summary>
[1454]46  public class XmlParser : IEnumerable<ISerializationToken> {
47
[3293]48    private readonly XmlTextReader reader;
[1454]49    private delegate IEnumerator<ISerializationToken> Handler();
50    private readonly Dictionary<string, Handler> handlers;
51
[3028]52    /// <summary>
53    /// Initializes a new instance of the <see cref="XmlParser"/> class.
54    /// </summary>
55    /// <param name="input">The input.</param>
[1454]56    public XmlParser(TextReader input) {
[3293]57      reader = new XmlTextReader(input);
58      reader.WhitespaceHandling = WhitespaceHandling.All;
59      reader.Normalization = false;
[1454]60      handlers = new Dictionary<string, Handler> {
[1612]61                     {XmlStringConstants.PRIMITIVE, ParsePrimitive},
62                     {XmlStringConstants.COMPOSITE, ParseComposite},
63                     {XmlStringConstants.REFERENCE, ParseReference},
64                     {XmlStringConstants.NULL, ParseNull},
65                     {XmlStringConstants.METAINFO, ParseMetaInfo},
[3005]66                     {XmlStringConstants.TYPE, ParseTypeInfo},
[1454]67                   };
68    }
69
[3028]70    /// <summary>
71    /// Returns an enumerator that iterates through the serialization tokens.
72    /// </summary>
73    /// <returns>
74    /// An that can be used to iterate through the collection of serialization tokens.
75    /// </returns>
[1454]76    public IEnumerator<ISerializationToken> GetEnumerator() {
77      while (reader.Read()) {
78        if (!reader.IsStartElement()) {
79          break;
80        }
81        IEnumerator<ISerializationToken> iterator;
82        try {
83          iterator = handlers[reader.Name].Invoke();
[4068]84        }
85        catch (KeyNotFoundException) {
[1625]86          throw new PersistenceException(String.Format(
87            "Invalid XML tag \"{0}\" in persistence file.",
[1454]88            reader.Name));
89        }
90        while (iterator.MoveNext()) {
91          yield return iterator.Current;
92        }
93      }
94    }
95
[3028]96    /// <summary>
97    /// Returns an enumerator that iterates through the serialization tokens.
98    /// </summary>
99    /// <returns>
100    /// An that can be used to iterate through the collection of serialization tokens.
101    /// </returns>
102    IEnumerator IEnumerable.GetEnumerator() {
103      return GetEnumerator();
104    }
105
[1454]106    private IEnumerator<ISerializationToken> ParsePrimitive() {
107      int? id = null;
108      string idString = reader.GetAttribute("id");
109      if (idString != null)
110        id = int.Parse(idString);
[1616]111      string name = reader.GetAttribute("name");
112      int typeId = int.Parse(reader.GetAttribute("typeId"));
[3005]113      string typeName = reader.GetAttribute("typeName");
114      string serializer = reader.GetAttribute("serializer");
115      if (typeName != null)
116        yield return new TypeToken(typeId, typeName, serializer);
[1616]117      XmlReader inner = reader.ReadSubtree();
118      inner.Read();
119      string xml = inner.ReadInnerXml();
[1703]120      inner.Close();
[1616]121      yield return new PrimitiveToken(name, typeId, id, new XmlString(xml));
[1454]122    }
123
124    private IEnumerator<ISerializationToken> ParseComposite() {
[1566]125      string name = reader.GetAttribute("name");
[1454]126      string idString = reader.GetAttribute("id");
127      int? id = null;
128      if (idString != null)
129        id = int.Parse(idString);
[1564]130      int typeId = int.Parse(reader.GetAttribute("typeId"));
[3005]131      string typeName = reader.GetAttribute("typeName");
132      string serializer = reader.GetAttribute("serializer");
133      if (typeName != null)
134        yield return new TypeToken(typeId, typeName, serializer);
[1454]135      yield return new BeginToken(name, typeId, id);
136      IEnumerator<ISerializationToken> iterator = GetEnumerator();
137      while (iterator.MoveNext())
138        yield return iterator.Current;
139      yield return new EndToken(name, typeId, id);
140    }
141
142    private IEnumerator<ISerializationToken> ParseReference() {
143      yield return new ReferenceToken(
144        reader.GetAttribute("name"),
145        int.Parse(reader.GetAttribute("ref")));
146    }
147
148    private IEnumerator<ISerializationToken> ParseNull() {
149      yield return new NullReferenceToken(reader.GetAttribute("name"));
150    }
151
[1553]152    private IEnumerator<ISerializationToken> ParseMetaInfo() {
153      yield return new MetaInfoBeginToken();
154      IEnumerator<ISerializationToken> iterator = GetEnumerator();
155      while (iterator.MoveNext())
156        yield return iterator.Current;
157      yield return new MetaInfoEndToken();
158    }
159
[3005]160    private IEnumerator<ISerializationToken> ParseTypeInfo() {
161      yield return new TypeToken(
162        int.Parse(reader.GetAttribute("id")),
163        reader.GetAttribute("typeName"),
164        reader.GetAttribute("serializer"));
165    }
166
[3028]167    /// <summary>
168    /// Parses the type cache.
169    /// </summary>
170    /// <param name="reader">The reader.</param>
171    /// <returns>A list of type mapping entries.</returns>
[1454]172    public static List<TypeMapping> ParseTypeCache(TextReader reader) {
[1625]173      try {
174        var typeCache = new List<TypeMapping>();
175        XmlReader xmlReader = XmlReader.Create(reader);
176        while (xmlReader.Read()) {
177          if (xmlReader.Name == XmlStringConstants.TYPE) {
178            typeCache.Add(new TypeMapping(
179              int.Parse(xmlReader.GetAttribute("id")),
180              xmlReader.GetAttribute("typeName"),
181              xmlReader.GetAttribute("serializer")));
182          }
[1454]183        }
[1625]184        return typeCache;
[4068]185      }
186      catch (PersistenceException) {
[1625]187        throw;
[4068]188      }
189      catch (Exception e) {
[1625]190        throw new PersistenceException("Unexpected exception during type cache parsing.", e);
[1454]191      }
192    }
193
[3028]194    /// <summary>
195    /// Deserializes an object from the specified filename.
196    /// </summary>
197    /// <param name="filename">The filename.</param>
198    /// <returns>A fresh object instance</returns>
[1734]199    public static object Deserialize(string filename) {
[3913]200      TimeSpan start = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
201      try {
[11932]202        using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
203          using (ZipArchive zip = new ZipArchive(fs)) {
204            return Deserialize(zip);
205          }
[3913]206        }
[4068]207      }
208      finally {
[3913]209        TimeSpan end = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
210        Tracing.Logger.Info(string.Format(
211          "deserialization of {0} took {1} seconds",
212          filename, (end - start).TotalSeconds));
[2874]213      }
[1734]214    }
215
[3028]216    /// <summary>
217    /// Deserializes the specified filename.
218    /// </summary>
219    /// <typeparam name="T">object type expected from the serialized file</typeparam>
220    /// <param name="filename">The filename.</param>
221    /// <returns>A fresh object of type T</returns>
222    public static T Deserialize<T>(string filename) {
223      return (T)Deserialize(filename);
224    }
225
226    /// <summary>
227    /// Deserializes an object from the specified stream.
228    /// </summary>
[12727]229    /// <typeparam name="T">object type expected from the serialized stream</typeparam>
[3028]230    /// <param name="stream">The stream.</param>
[12727]231    /// <param name="compressionType">Type of compression, default is GZip.</param>
[3028]232    /// <returns>A fresh object instance.</returns>
[12727]233    public static T Deserialize<T>(Stream stream, CompressionType compressionType = CompressionType.GZip) {
234      return (T)Deserialize(stream, compressionType);
[1734]235    }
236
[3028]237    /// <summary>
238    /// Deserializes an object from the specified stream.
239    /// </summary>
240    /// <param name="stream">The stream.</param>
[12727]241    /// <param name="compressionType">Type of compression, default is GZip.</param>
[3028]242    /// <returns>A fresh object instance.</returns>
[12727]243    public static object Deserialize(Stream stream, CompressionType compressionType = CompressionType.GZip) {
244      if (compressionType == CompressionType.Zip) {
245        ZipArchive zipFile = new ZipArchive(stream);
246        return Deserialize(zipFile);
247      } else {
248        try {
249          using (StreamReader reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress))) {
250            XmlParser parser = new XmlParser(reader);
251            Deserializer deserializer = new Deserializer(new TypeMapping[] { });
252            return deserializer.Deserialize(parser);
253          }
254        }
255        catch (PersistenceException) {
256          throw;
257        }
258        catch (Exception x) {
259          throw new PersistenceException("Unexpected exception during deserialization", x);
260        }
261      }
[3028]262    }
263
[11932]264    private static object Deserialize(ZipArchive zipFile) {
[1779]265      try {
[11932]266        ZipArchiveEntry typecache = zipFile.GetEntry("typecache.xml");
267        if (typecache == null) throw new PersistenceException("file does not contain typecache.xml");
268        Deserializer deSerializer;
269        using (StreamReader sr = new StreamReader(typecache.Open())) {
270          deSerializer = new Deserializer(ParseTypeCache(sr));
271        }
272
273        ZipArchiveEntry data = zipFile.GetEntry("data.xml");
274        if (data == null) throw new PersistenceException("file does not contain data.xml");
275        object result;
276        using (StreamReader sr = new StreamReader(data.Open())) {
277          XmlParser parser = new XmlParser(sr);
278          result = deSerializer.Deserialize(parser);
279        }
280
[1625]281        return result;
[4068]282      }
283      catch (PersistenceException) {
[1625]284        throw;
[4068]285      }
286      catch (Exception e) {
[1625]287        throw new PersistenceException("Unexpected exception during deserialization", e);
288      }
[1454]289    }
[17105]290
291    /// <summary>
292    /// Checks if the given file can be opened as <see cref="ZipArchive" />.
293    /// </summary>
294    /// <param name="filename">The filename.</param>
295    /// <returns><see langword="true" /> if the file can be opened as <see cref="ZipArchive" />; otherwise, <see langword="false" />.</returns>
296    public static bool CanOpen(string filename) {
297      try {
298        using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
299          using (ZipArchive zip = new ZipArchive(fs)) {
300            return true;
301          }
302        }
303      } catch (InvalidDataException) {
304        return false;
305      }
306    }
[1566]307  }
[1564]308}
Note: See TracBrowser for help on using the repository browser.