Skip to content

Commit facf507

Browse files
committed
XML Support
1 parent 3de9c1f commit facf507

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1225
-146
lines changed

.idea/.idea.PetroglyphTools/.idea/projectSettingsUpdater.xml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PG.Commons/PG.Commons/Data/IId.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ public interface IId : IEquatable<IId>
1717
/// </summary>
1818
/// <returns></returns>
1919
string Unwrap();
20-
}
20+
}

PG.Commons/PG.Commons/Data/IdBase.cs

+12-3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ public string Unwrap()
4343
return b.ToString();
4444
}
4545

46+
/// <inheritdoc />
47+
public override string ToString()
48+
{
49+
return Unwrap();
50+
}
51+
4652
/// <summary>
4753
/// Convenience method to access components in a type-safe manner.
4854
/// </summary>
@@ -65,7 +71,10 @@ public string Unwrap()
6571
/// <inheritdoc />
6672
public override int GetHashCode()
6773
{
68-
return HashCode.Combine(GetConfiguredArity(), HashCode.Combine(Components));
74+
var hash = Arity.GetHashCode();
75+
hash = Components.OfType<object>()
76+
.Aggregate(hash, (current, component) => current * 31 + component.GetHashCode());
77+
return hash;
6978
}
7079

7180
/// <summary>
@@ -74,12 +83,12 @@ public override int GetHashCode()
7483
/// <returns></returns>
7584
protected virtual bool IsNullId()
7685
{
77-
return Components.Any();
86+
return Components.Any(o => o != null);
7887
}
7988

8089
/// <summary>
8190
/// The arity of this ID type.
8291
/// </summary>
8392
/// <returns></returns>
8493
protected abstract int GetConfiguredArity();
85-
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
namespace PG.Commons.Data.Serialization;
2+
3+
/// <summary>
4+
/// Simple XML serialization helper service.
5+
/// </summary>
6+
public interface IXmlSerializationSupportService
7+
{
8+
/// <summary>
9+
/// Serializes an object to XML and stores it to the file path.
10+
/// </summary>
11+
/// <param name="filePath"></param>
12+
/// <param name="serializableObject"></param>
13+
/// <param name="overwrite"></param>
14+
/// <typeparam name="T"></typeparam>
15+
bool SerializeObjectAndStoreToDisc<T>(string filePath, T serializableObject, bool overwrite = true) where T : class;
16+
17+
/// <summary>
18+
/// Serializes the given object to an XML string.
19+
/// </summary>
20+
/// <param name="serializableObject"></param>
21+
/// <typeparam name="T"></typeparam>
22+
/// <returns></returns>
23+
string SerializeObject<T>(T serializableObject) where T : class;
24+
25+
/// <summary>
26+
/// Deserializes an XML file read form disc to an object.
27+
/// </summary>
28+
/// <param name="filePath"></param>
29+
/// <typeparam name="T"></typeparam>
30+
/// <returns></returns>
31+
T? DeSerializeObjectFromDisc<T>(string filePath) where T : class;
32+
33+
/// <summary>
34+
/// Deserializes an object from a XML string.
35+
/// </summary>
36+
/// <param name="xmlString"></param>
37+
/// <typeparam name="T"></typeparam>
38+
/// <returns></returns>
39+
T? DeSerializeObject<T>(string xmlString) where T : class;
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) Alamo Engine Tools and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for details.
3+
4+
using System;
5+
using System.IO;
6+
using System.Xml;
7+
using System.Xml.Serialization;
8+
using Microsoft.Extensions.Logging;
9+
using PG.Commons.Services;
10+
11+
namespace PG.Commons.Data.Serialization;
12+
13+
/// <inheritdoc cref="IXmlSerializationSupportService" />
14+
public sealed class XmlSerializationSupportService : ServiceBase, IXmlSerializationSupportService
15+
{
16+
/// <inheritdoc />
17+
public XmlSerializationSupportService(IServiceProvider services) : base(services)
18+
{
19+
}
20+
21+
/// <inheritdoc />
22+
public string SerializeObject<T>(T serializableObject) where T : class
23+
{
24+
try
25+
{
26+
var xmlSerializer = new XmlSerializer(typeof(T));
27+
var stringWriter = new StringWriter();
28+
using var writer = XmlWriter.Create(stringWriter);
29+
xmlSerializer.Serialize(writer, serializableObject);
30+
return stringWriter.ToString();
31+
}
32+
catch (Exception e)
33+
{
34+
Logger.LogError("An exception occurred whilst serializing: {}", e);
35+
}
36+
37+
return string.Empty;
38+
}
39+
40+
/// <inheritdoc />
41+
public T? DeSerializeObjectFromDisc<T>(string filePath) where T : class
42+
{
43+
var fileInfo = FileSystem.FileInfo.New(filePath);
44+
if (!fileInfo.Exists) throw new FileNotFoundException("The file {} could not be found!", filePath);
45+
return DeSerializeObject<T>(FileSystem.File.ReadAllText(filePath));
46+
}
47+
48+
/// <inheritdoc />
49+
public T? DeSerializeObject<T>(string xmlString) where T : class
50+
{
51+
if (string.IsNullOrEmpty(xmlString)) return null;
52+
var xmlSerializer = new XmlSerializer(typeof(T));
53+
var stringReader = new StringReader(xmlString);
54+
using var reader = XmlReader.Create(stringReader);
55+
var obj = xmlSerializer.Deserialize(reader);
56+
return obj as T;
57+
}
58+
59+
/// <inheritdoc />
60+
public bool SerializeObjectAndStoreToDisc<T>(string filePath, T serializableObject, bool overwrite = false)
61+
where T : class
62+
{
63+
try
64+
{
65+
var fileInfo = FileSystem.FileInfo.New(filePath);
66+
if (fileInfo.Exists && !overwrite)
67+
throw new UnauthorizedAccessException(
68+
$"The file already exists. Force overwrite with {nameof(overwrite)}=true.");
69+
fileInfo.Delete();
70+
71+
var directoyInfo = fileInfo.Directory;
72+
if (directoyInfo is { Exists: false }) FileSystem.Directory.CreateDirectory(directoyInfo.FullName);
73+
74+
FileSystem.File.WriteAllText(filePath, SerializeObject(serializableObject));
75+
}
76+
catch (Exception e)
77+
{
78+
Logger.LogError("An exception occurred whilst serializing: {}", e);
79+
return false;
80+
}
81+
82+
return true;
83+
}
84+
}

PG.Commons/PG.Commons/PGServiceContribution.cs

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using AnakinRaW.CommonUtilities.Hashing;
22
using Microsoft.Extensions.DependencyInjection;
33
using PG.Commons.Attributes;
4+
using PG.Commons.Data.Serialization;
45
using PG.Commons.Extensibility;
56
using PG.Commons.Hashing;
67

@@ -16,5 +17,6 @@ public void ContributeServices(IServiceCollection serviceCollection)
1617
{
1718
serviceCollection.AddSingleton<IHashAlgorithmProvider>(sp => new Crc32HashingProvider());
1819
serviceCollection.AddSingleton<ICrc32HashingService>(sp => new Crc32HashingService(sp));
20+
serviceCollection.AddSingleton<IXmlSerializationSupportService>(sp => new XmlSerializationSupportService(sp));
1921
}
2022
}

PG.Commons/PG.Commons/Utilities/StringUtilities.cs

+34-13
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for details.
33

44
using System;
5+
using System.Linq;
56
using System.Runtime.CompilerServices;
67
using System.Text;
78
#if NETSTANDARD2_0
@@ -12,13 +13,14 @@
1213
namespace PG.Commons.Utilities;
1314

1415
/// <summary>
15-
/// Provides primitive helper methods for strings.
16+
/// Provides primitive helper methods for strings.
1617
/// </summary>
1718
public static class StringUtilities
1819
{
1920
/// <summary>
20-
/// Checks whether a given string, when converted to bytes, is not longer than the max value of an <see cref="ushort"/>.
21-
/// Throws an <see cref="ArgumentException"/> if the string is longer.
21+
/// Checks whether a given string, when converted to bytes, is not longer than the max value of an
22+
/// <see cref="ushort" />.
23+
/// Throws an <see cref="ArgumentException" /> if the string is longer.
2224
/// </summary>
2325
/// <param name="value">The string to validate.</param>
2426
/// <param name="encoding">The encoding that shall be used to get the string length.</param>
@@ -32,17 +34,18 @@ public static ushort ValidateStringByteSizeUInt16(ReadOnlySpan<char> value, Enco
3234
if (encoding == null)
3335
throw new ArgumentNullException(nameof(encoding));
3436

35-
var size = encoding.GetByteCount(value);
37+
var size = encoding.GetByteCount(value);
3638

3739
if (size is < 0 or > ushort.MaxValue)
38-
throw new ArgumentException($"The value is longer than the expected {ushort.MaxValue} characters.", nameof(value));
40+
throw new ArgumentException($"The value is longer than the expected {ushort.MaxValue} characters.",
41+
nameof(value));
3942

4043
return (ushort)size;
4144
}
4245

4346
/// <summary>
44-
/// Checks whether a given character sequence has no more characters than the max value of an <see cref="ushort"/>.
45-
/// Throws an <see cref="ArgumentException"/> if the string is longer.
47+
/// Checks whether a given character sequence has no more characters than the max value of an <see cref="ushort" />.
48+
/// Throws an <see cref="ArgumentException" /> if the string is longer.
4649
/// </summary>
4750
/// <param name="value">The string to validate.</param>
4851
/// <returns>The actual length of the value in characters.</returns>
@@ -55,13 +58,14 @@ public static ushort ValidateStringCharLengthUInt16(ReadOnlySpan<char> value)
5558

5659
var length = value.Length;
5760
if (length is < 0 or > ushort.MaxValue)
58-
throw new ArgumentException($"The value is longer that the expected {ushort.MaxValue} characters.", nameof(value));
61+
throw new ArgumentException($"The value is longer that the expected {ushort.MaxValue} characters.",
62+
nameof(value));
5963

6064
return (ushort)length;
6165
}
6266

6367
/// <summary>
64-
/// Throws an <see cref="ArgumentException"/> if the given character sequence contains non-ASCII characters.
68+
/// Throws an <see cref="ArgumentException" /> if the given character sequence contains non-ASCII characters.
6569
/// </summary>
6670
/// <param name="value">The character sequence to validate.</param>
6771
/// <exception cref="ArgumentException">The character sequence contains non-ASCII characters.</exception>
@@ -74,7 +78,7 @@ public static void ValidateIsAsciiOnly(ReadOnlySpan<char> value)
7478
}
7579

7680
/// <summary>
77-
/// Throws an <see cref="ArgumentException"/> if the given character sequence contains non-ASCII characters.
81+
/// Throws an <see cref="ArgumentException" /> if the given character sequence contains non-ASCII characters.
7882
/// </summary>
7983
/// <param name="value">The character sequence to validate.</param>
8084
/// <exception cref="ArgumentException">The character sequence contains non-ASCII characters.</exception>
@@ -85,10 +89,27 @@ public static bool IsAsciiOnly(ReadOnlySpan<char> value)
8589
throw new ArgumentNullException(nameof(value));
8690

8791
foreach (var ch in value)
88-
{
8992
if ((uint)ch > '\x007f')
9093
return false;
91-
}
9294
return true;
9395
}
94-
}
96+
97+
/// <summary>
98+
/// Basic validation algorithm.
99+
/// </summary>
100+
/// <param name="s"></param>
101+
/// <returns></returns>
102+
public static string Validate(string? s)
103+
{
104+
var stringBuilder = new StringBuilder();
105+
106+
if (string.IsNullOrEmpty(s)) return string.Empty;
107+
108+
foreach (var t in s.Where(t => t == 0x9 || t == 0xA || t == 0xD ||
109+
(t >= 0x20 && t <= 0xD7FF) ||
110+
(t >= 0xE000 && t <= 0xFFFD)))
111+
stringBuilder.Append(t);
112+
113+
return stringBuilder.ToString();
114+
}
115+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) Alamo Engine Tools and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for details.
3+
4+
namespace PG.Commons.Utilities;
5+
6+
/// <summary>
7+
/// XML file utility.
8+
/// </summary>
9+
public static class XmlUtilities
10+
{
11+
/// <summary>
12+
/// Escape XML Content.
13+
/// </summary>
14+
/// <param name="s"></param>
15+
/// <returns></returns>
16+
public static string? EscapeXml(string? s)
17+
{
18+
if (string.IsNullOrEmpty(s)) return s;
19+
20+
var returnString = s!;
21+
returnString = returnString.Replace("&", "&amp;");
22+
returnString = returnString.Replace("<", "&lt;");
23+
returnString = returnString.Replace(">", "&gt;");
24+
returnString = returnString.Replace("'", "&apos;");
25+
returnString = returnString.Replace("\"", "&quot;");
26+
return returnString;
27+
}
28+
29+
/// <summary>
30+
/// Unescape XML content.
31+
/// </summary>
32+
/// <param name="s"></param>
33+
/// <returns></returns>
34+
public static string? UnescapeXml(string? s)
35+
{
36+
if (string.IsNullOrEmpty(s)) return s;
37+
38+
var returnString = s!;
39+
returnString = returnString.Replace("&apos;", "'");
40+
returnString = returnString.Replace("&quot;", "\"");
41+
returnString = returnString.Replace("&gt;", ">");
42+
returnString = returnString.Replace("&lt;", "<");
43+
returnString = returnString.Replace("&amp;", "&");
44+
return returnString;
45+
}
46+
}

0 commit comments

Comments
 (0)