diff --git a/README.md b/README.md
index 9c3d022..60e74c9 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,61 @@
# RolandK.Formats.Gpx
-### Common Information
+## Common Information
A .NET Standard library for reading and writing GPX (GPS Exchange Format) files.
This library was build for my [GpxViewer](https://github.com/RolandKoenig/GpxViewer) project. It is based
on the System.Xml.Serialization.XmlSerializer class and therefore available for .NET Framework and .NET Core projects.
-### Build
+## Build
[![Continuous integration](https://github.com/RolandKoenig/RolandK.Formats.Gpx/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/RolandKoenig/RolandK.Formats.Gpx/actions/workflows/continuous-integration.yml)
-### Feature overview
+## Feature overview
- Full document model for gpx files
- Load gpx files
- Write gpx files
- - Add custom metadata to gpx files
- - Don't lose other custom metadate after loading and saving gpx files
\ No newline at end of file
+ - Add custom xml extensions to gpx files
+ - Don't lose other custom xml extensions information after loading and saving gpx files
+
+## Samples
+### Load GPX file
+Load file file (here Kösseine.gpx) and get total count of tracks, routes and waypoints in the file
+```csharp
+var gpxFile = await GpxFile.LoadAsync("Kösseine.gpx");
+
+var countTracks = gpxFile.Tracks.Count;
+var countRoutes = gpxFile.Routes.Count;
+var countWaypoints = gpxFile.Waypoints.Count;
+```
+
+### Save GPX file
+Save a previously loaded / created / modified file
+```csharp
+await GpxFile.SaveAsync(gpxFile, "MyFile.gpx");
+```
+
+### Add custom xml extension
+Your have to define your own xml extension types and give them a namespace
+```csharp
+[XmlType("MyTrackExtension", Namespace = "http://testing.rolandk.net/")]
+public class MyTrackExtension
+{
+ public bool AlreadyDone { get; set; } = false;
+}
+```
+
+Then you have to register these xml extension types and their namespaces to GpxFile.
+You should do this somewhere in your startup code of your application.
+```csharp
+// You have to register your own xml extension types
+GpxFile.RegisterExtensionType(typeof(MyTrackExtension));
+GpxFile.RegisterNamespace("rktest", "http://testing.rolandk.net/");
+```
+
+Now you can access these xml extensions from c# code
+```csharp
+var gpxFile = await GpxFile.LoadAsync(inStream);
+var gpxTrack = gpxFile.Tracks[0];
+
+gpxTrack.Extensions ??= new GpxExtensions();
+var myTrackExtension = gpxTrack.Extensions.GetOrCreateExtension();
+
+myTrackExtension.AlreadyDone = true; // This property comes from our own xml extension
+```
\ No newline at end of file
diff --git a/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileCustomExtensionsTests.cs b/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileCustomExtensionsTests.cs
new file mode 100644
index 0000000..1fa65d1
--- /dev/null
+++ b/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileCustomExtensionsTests.cs
@@ -0,0 +1,48 @@
+using System.Xml.Serialization;
+
+namespace RolandK.Formats.Gpx.Tests.FileLoad;
+
+public class GpxFileCustomExtensionsTests
+{
+ [Fact]
+ public async Task AddCustomMetadata()
+ {
+ // Arrange
+ await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
+ typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");
+
+ // Act
+ GpxFile.RegisterExtensionType(typeof(MyTrackExtension));
+ GpxFile.RegisterNamespace("rktest", "http://testing.rolandk.net/");
+
+ var originalGpxFile = await GpxFile.LoadAsync(inStream);
+ var originalGpxTrack = originalGpxFile.Tracks[0];
+
+ originalGpxTrack.Extensions ??= new GpxExtensions();
+ var myTrackExtension = originalGpxTrack.Extensions.GetOrCreateExtension();
+
+ myTrackExtension.AlreadyDone = true;
+
+ using var writingMemoryStream = new MemoryStream(1024 * 100);
+ await GpxFile.SaveAsync(originalGpxFile, writingMemoryStream);
+
+ using var readingMemoryStream = new MemoryStream(writingMemoryStream.GetBuffer());
+ var reloadedFile = await GpxFile.LoadAsync(readingMemoryStream);
+
+ // Assert
+ Assert.Single(reloadedFile.Tracks);
+
+ var reloadedTrack = reloadedFile.Tracks[0];
+ Assert.NotNull(reloadedTrack.Extensions);
+
+ var reloadedExtension = reloadedTrack.Extensions.TryGetSingleExtension();
+ Assert.NotNull(reloadedExtension);
+ Assert.True(reloadedExtension.AlreadyDone);
+ }
+
+ [XmlType("MyTrackExtension", Namespace = "http://testing.rolandk.net/")]
+ public class MyTrackExtension
+ {
+ public bool AlreadyDone { get; set; }
+ }
+}
diff --git a/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadAsyncTests.cs b/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadAsyncTests.cs
new file mode 100644
index 0000000..13ae951
--- /dev/null
+++ b/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadAsyncTests.cs
@@ -0,0 +1,107 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+
+namespace RolandK.Formats.Gpx.Tests.FileLoad;
+
+[SuppressMessage("ReSharper", "RedundantArgumentDefaultValue")]
+public class GpxFileLoadAsyncTests
+{
+ [Fact]
+ public async Task GpxVersion1_1_CompatibilityMode()
+ {
+ // Arrange
+ await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
+ typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");
+
+ // Act
+ var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);
+
+ // Assert
+ Assert.NotNull(gpxFile);
+ Assert.NotNull(gpxFile.Metadata);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
+ Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
+ }
+
+ [Fact]
+ public async Task GpxVersion1_1_Gpx1_1Mode()
+ {
+ // Arrange
+ await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
+ typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");
+
+ // Act
+ var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.OnlyGpx1_1);
+
+ // Assert
+ Assert.NotNull(gpxFile);
+ Assert.NotNull(gpxFile.Metadata);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
+ Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
+ }
+
+ [Fact]
+ public async Task GpxVersion1_1_on_xml_1_1()
+ {
+ // Arrange
+ await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
+ typeof(GpxFileLoadTests),"Test_Gpx1_1_on_xml_1_1.gpx");
+
+ // Act
+ var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);
+
+ // Assert
+ Assert.NotNull(gpxFile);
+ Assert.NotNull(gpxFile.Metadata);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
+ Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
+ }
+
+ [Fact]
+ public async Task GpxVersion1_0()
+ {
+ // Arrange
+ await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
+ typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");
+
+ // Act
+ var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);
+
+ // Assert
+ Assert.NotNull(gpxFile);
+ Assert.NotNull(gpxFile.Metadata);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
+ Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
+ }
+
+ [Fact]
+ public async Task GpxVersion1_0_SaveAs1_1()
+ {
+ // Arrange
+ await using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
+ typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");
+
+ // Act
+ var gpxFile = await GpxFile.LoadAsync(inStream, GpxFileDeserializationMethod.Compatibility);
+ var outStrBuilder = new StringBuilder(33000);
+ using (var strWriter = new StringWriter(outStrBuilder))
+ {
+ await GpxFile.SaveAsync(gpxFile, strWriter);
+ }
+ var writtenFile = outStrBuilder.ToString();
+
+ // Assert
+ Assert.True(writtenFile.Contains("version=\"1.1\""), "Version attribute");
+ Assert.True(writtenFile.Contains("xmlns=\"http://www.topografix.com/GPX/1/1\""), "Default namespace");
+
+ Assert.Equal("1.0", gpxFile.Version);
+ }
+}
\ No newline at end of file
diff --git a/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadTests.cs b/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadTests.cs
index 343f345..2b698d9 100644
--- a/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadTests.cs
+++ b/src/RolandK.Formats.Gpx.Tests/FileLoad/GpxFileLoadTests.cs
@@ -1,84 +1,107 @@
-using System.Text;
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
namespace RolandK.Formats.Gpx.Tests.FileLoad;
+[SuppressMessage("ReSharper", "RedundantArgumentDefaultValue")]
public class GpxFileLoadTests
{
[Fact]
public void GpxVersion1_1_CompatibilityMode()
{
+ // Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");
- var gpxFile = GpxFile.Deserialize(inStream, GpxFileDeserializationMethod.Compatibility);
+ // Act
+ var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);
+ // Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
- Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}
[Fact]
public void GpxVersion1_1_Gpx1_1Mode()
{
+ // Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1.gpx");
- var gpxFile = GpxFile.Deserialize(inStream, GpxFileDeserializationMethod.OnlyGpx1_1);
+ // Act
+ var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.OnlyGpx1_1);
+ // Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
- Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}
[Fact]
public void GpxVersion1_1_on_xml_1_1()
{
+ // Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_1_on_xml_1_1.gpx");
- var gpxFile = GpxFile.Deserialize(inStream, GpxFileDeserializationMethod.Compatibility);
+ // Act
+ var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);
+ // Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
- Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}
[Fact]
public void GpxVersion1_0()
{
+ // Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");
- var gpxFile = GpxFile.Deserialize(inStream, GpxFileDeserializationMethod.Compatibility);
+ // Act
+ var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);
+ // Assert
Assert.NotNull(gpxFile);
Assert.NotNull(gpxFile.Metadata);
- Assert.Equal("Kösseine", gpxFile!.Metadata!.Name);
+ Assert.Equal("Kösseine", gpxFile.Metadata.Name);
Assert.Single(gpxFile.Tracks);
+ Assert.Single(gpxFile.Tracks[0].Segments);
+ Assert.Equal(228, gpxFile.Tracks[0].Segments[0].Points.Count);
}
[Fact]
public void GpxVersion1_0_SaveAs1_1()
{
+ // Arrange
using var inStream = GpxTestUtilities.ReadFromEmbeddedResource(
typeof(GpxFileLoadTests),"Test_Gpx1_0.gpx");
- var gpxFile = GpxFile.Deserialize(inStream, GpxFileDeserializationMethod.Compatibility);
+ // Act
+ var gpxFile = GpxFile.Load(inStream, GpxFileDeserializationMethod.Compatibility);
var outStrBuilder = new StringBuilder(33000);
using (var strWriter = new StringWriter(outStrBuilder))
{
- GpxFile.Serialize(gpxFile, strWriter);
+ GpxFile.Save(gpxFile, strWriter);
}
var writtenFile = outStrBuilder.ToString();
- // Check output
+ // Assert
Assert.True(writtenFile.Contains("version=\"1.1\""), "Version attribute");
Assert.True(writtenFile.Contains("xmlns=\"http://www.topografix.com/GPX/1/1\""), "Default namespace");
- // Check original data
Assert.Equal("1.0", gpxFile.Version);
}
}
\ No newline at end of file
diff --git a/src/RolandK.Formats.Gpx/GpxFile.cs b/src/RolandK.Formats.Gpx/GpxFile.cs
index 2d70ec2..86253e1 100644
--- a/src/RolandK.Formats.Gpx/GpxFile.cs
+++ b/src/RolandK.Formats.Gpx/GpxFile.cs
@@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
+using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using RolandK.Formats.Gpx.Metadata;
@@ -44,31 +45,6 @@ static GpxFile()
s_cachedSerializer = new ConcurrentDictionary();
}
- public GpxTrack CreateAndAddDummyTrack(string name, params GpxWaypoint[] waypoints)
- {
- var gpxTrack = new GpxTrack();
- gpxTrack.Name = name;
- this.Tracks.Add(gpxTrack);
-
- var gpxTrackSegment = new GpxTrackSegment();
- gpxTrack.Segments.Add(gpxTrackSegment);
-
- gpxTrackSegment.Points.AddRange(waypoints);
-
- return gpxTrack;
- }
-
- public GpxRoute CreateAndAddDummyRoute(string name, params GpxWaypoint[] waypoints)
- {
- var gpxRoute = new GpxRoute();
- gpxRoute.Name = name;
- this.Routes.Add(gpxRoute);
-
- gpxRoute.RoutePoints.AddRange(waypoints);
-
- return gpxRoute;
- }
-
public void EnsureNamespaceDeclarations()
{
if(s_extensionNamespaces != null)
@@ -140,24 +116,64 @@ public static XmlSerializer GetSerializer(GpxVersion version)
return result;
}
- public static void Serialize(GpxFile gpxFile, TextWriter textWriter)
+ public static void Save(GpxFile gpxFile, TextWriter textWriter)
{
gpxFile.EnsureNamespaceDeclarations();
+ var fileToSave = PrepareGpxFileForSaving(gpxFile);
+
+ GetSerializer(GpxVersion.V1_1).Serialize(textWriter, fileToSave);
+ }
+
+ public static async Task SaveAsync(GpxFile gpxFile, TextWriter textWriter)
+ {
+ gpxFile.EnsureNamespaceDeclarations();
+
+ var fileToSave = PrepareGpxFileForSaving(gpxFile);
+
+ await Task.Run(() => GetSerializer(GpxVersion.V1_1).Serialize(textWriter, fileToSave));
+ }
+
+ public static void Save(GpxFile gpxFile, Stream stream)
+ {
+ using var streamWriter = new StreamWriter(stream);
+ Save(gpxFile, streamWriter);
+ }
+
+ public static async Task SaveAsync(GpxFile gpxFile, Stream stream)
+ {
+ using var streamWriter = new StreamWriter(stream);
+ await SaveAsync(gpxFile, streamWriter);
+ }
+
+ public static void Save(GpxFile gpxFile, string targetFile)
+ {
+ using var streamWriter = new StreamWriter(File.Create(targetFile));
+ Save(gpxFile, streamWriter);
+ }
+
+ public static async Task SaveAsync(GpxFile gpxFile, string targetFile)
+ {
+ using var streamWriter = new StreamWriter(File.Create(targetFile));
+ await SaveAsync(gpxFile, streamWriter);
+ }
+
+ private static GpxFile PrepareGpxFileForSaving(GpxFile originalFile)
+ {
// Copy given GpxFile object to new one to enable some modifications before serializing
// The original GpxFile object will not be modified during this process
var fileToSave = new GpxFile();
- fileToSave.Waypoints.AddRange(gpxFile.Waypoints);
- fileToSave.Extensions = gpxFile.Extensions;
- fileToSave.Routes.AddRange(gpxFile.Routes);
- fileToSave.Metadata = gpxFile.Metadata;
- fileToSave.Tracks.AddRange(gpxFile.Tracks);
+ fileToSave.Waypoints.AddRange(originalFile.Waypoints);
+ fileToSave.Extensions = originalFile.Extensions;
+ fileToSave.Routes.AddRange(originalFile.Routes);
+ fileToSave.Metadata = originalFile.Metadata;
+ fileToSave.Tracks.AddRange(originalFile.Tracks);
fileToSave.Creator = "RK GpxViewer";
// Force http://www.topografix.com/GPX/1/1 to be default namespace
- if (gpxFile.Xmlns != null)
+ if (originalFile.Xmlns != null)
{
- var namespaceArray = gpxFile.Xmlns.ToArray();
+ var namespaceArray = originalFile.Xmlns.ToArray();
var newNamespaces = new List(namespaceArray.Length);
for (var loop = 0; loop < namespaceArray.Length; loop++)
{
@@ -182,27 +198,55 @@ public static void Serialize(GpxFile gpxFile, TextWriter textWriter)
}
fileToSave.Version = "1.1";
- // Serialization logic
- GetSerializer(GpxVersion.V1_1).Serialize(textWriter, fileToSave);
+ return fileToSave;
}
- public static void Serialize(GpxFile gpxFile, Stream stream)
+ public static GpxFile Load(TextReader textReader, GpxFileDeserializationMethod method = GpxFileDeserializationMethod.Compatibility)
{
- using(var streamWriter = new StreamWriter(stream))
+ switch (method)
{
- Serialize(gpxFile, streamWriter);
- }
- }
+ case GpxFileDeserializationMethod.Compatibility:
+ // Read whole file to memory to do some checking / manipulations first
+ // - Correct xml namespace
+ // - Correct xml version (.Net does not support xml 1.1)
+ var fullText = textReader.ReadToEnd();
+ var gpxVersion = fullText.Contains("xmlns=\"http://www.topografix.com/GPX/1/1\"") ? GpxVersion.V1_1 : GpxVersion.V1_0;
- public static void Serialize(GpxFile gpxFile, string targetFile)
- {
- using(var streamWriter = new StreamWriter(File.Create(targetFile)))
- {
- Serialize(gpxFile, streamWriter);
+ using (var strReader = new StringReader(fullText))
+ {
+ // Discard initial xml header
+ // In this way the XmlSerializer does also try to read xml 1.1 content
+ if (fullText.StartsWith("", StringComparison.Ordinal);
+ if (endTagIndex < 0)
+ {
+ throw new InvalidOperationException($"Unable to process xml declaration!");
+ }
+ strReader.ReadBlock(new char[endTagIndex + 2], 0, endTagIndex + 2);
+ }
+
+ // Try to deserialize
+ if (GetSerializer(gpxVersion).Deserialize(strReader) is not GpxFile result1)
+ {
+ throw new GpxFileException($"Unable to deserialize {nameof(GpxFile)}: Unknown error");
+ }
+ return result1;
+ }
+
+ case GpxFileDeserializationMethod.OnlyGpx1_1:
+ if (GetSerializer(GpxVersion.V1_1).Deserialize(textReader) is not GpxFile result2)
+ {
+ throw new GpxFileException($"Unable to deserialize {nameof(GpxFile)}: Unknown error");
+ }
+ return result2;
+
+ default:
+ throw new ArgumentException($"Unknown deserialization method {method}", nameof(method));
}
}
- public static GpxFile Deserialize(TextReader textReader, GpxFileDeserializationMethod method)
+ public static async Task LoadAsync(TextReader textReader, GpxFileDeserializationMethod method = GpxFileDeserializationMethod.Compatibility)
{
switch (method)
{
@@ -210,7 +254,7 @@ public static GpxFile Deserialize(TextReader textReader, GpxFileDeserializationM
// Read whole file to memory to do some checking / manipulations first
// - Correct xml namespace
// - Correct xml version (.Net does not support xml 1.1)
- var fullText = textReader.ReadToEnd();
+ var fullText = await textReader.ReadToEndAsync().ConfigureAwait(false);
var gpxVersion = fullText.Contains("xmlns=\"http://www.topografix.com/GPX/1/1\"") ? GpxVersion.V1_1 : GpxVersion.V1_0;
using (var strReader = new StringReader(fullText))
@@ -224,11 +268,13 @@ public static GpxFile Deserialize(TextReader textReader, GpxFileDeserializationM
{
throw new InvalidOperationException($"Unable to process xml declaration!");
}
- strReader.ReadBlock(new char[endTagIndex + 2], 0, endTagIndex + 2);
+ await strReader.ReadBlockAsync(new char[endTagIndex + 2], 0, endTagIndex + 2);
}
// Try to deserialize
- if (GetSerializer(gpxVersion).Deserialize(strReader) is not GpxFile result1)
+ var loadedObject1 = await Task.Run(() => GetSerializer(gpxVersion).Deserialize(strReader))
+ .ConfigureAwait(false);
+ if (loadedObject1 is not GpxFile result1)
{
throw new GpxFileException($"Unable to deserialize {nameof(GpxFile)}: Unknown error");
}
@@ -236,7 +282,9 @@ public static GpxFile Deserialize(TextReader textReader, GpxFileDeserializationM
}
case GpxFileDeserializationMethod.OnlyGpx1_1:
- if (GetSerializer(GpxVersion.V1_1).Deserialize(textReader) is not GpxFile result2)
+ var loadedObject2 = await Task.Run(() => GetSerializer(GpxVersion.V1_1).Deserialize(textReader))
+ .ConfigureAwait(false);
+ if (loadedObject2 is not GpxFile result2)
{
throw new GpxFileException($"Unable to deserialize {nameof(GpxFile)}: Unknown error");
}
@@ -245,21 +293,33 @@ public static GpxFile Deserialize(TextReader textReader, GpxFileDeserializationM
default:
throw new ArgumentException($"Unknown deserialization method {method}", nameof(method));
}
+ }
+ public static GpxFile Load(Stream stream, GpxFileDeserializationMethod method = GpxFileDeserializationMethod.Compatibility)
+ {
+ using var streamReader = new StreamReader(stream);
+
+ return Load(streamReader, method);
}
- public static GpxFile Deserialize(Stream stream, GpxFileDeserializationMethod method)
+ public static async Task LoadAsync(Stream stream, GpxFileDeserializationMethod method = GpxFileDeserializationMethod.Compatibility)
{
using var streamReader = new StreamReader(stream);
- return Deserialize(streamReader, method);
+ return await LoadAsync(streamReader, method);
+ }
+
+ public static GpxFile Load(string sourceFile, GpxFileDeserializationMethod method = GpxFileDeserializationMethod.Compatibility)
+ {
+ using var fileStream = File.OpenRead(sourceFile);
+ return Load(fileStream, method);
}
- public static GpxFile Deserialize(string sourceFile, GpxFileDeserializationMethod method)
+ public static async Task LoadAsync(string sourceFile, GpxFileDeserializationMethod method = GpxFileDeserializationMethod.Compatibility)
{
using var fileStream = File.OpenRead(sourceFile);
- return Deserialize(fileStream, method);
+ return await LoadAsync(fileStream, method);
}
}
\ No newline at end of file