#nullable enable using System; using System.IO; using System.Linq; using MediaBrowser.Model.Serialization; namespace Emby.Server.Implementations.AppBase { /// /// Class ConfigurationHelper. /// public static class ConfigurationHelper { /// /// Reads an xml configuration file from the file system /// It will immediately re-serialize and save if new serialization data is available due to property changes. /// /// The type. /// The path. /// The XML serializer. /// System.Object. public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer) { object configuration; byte[]? buffer = null; // Use try/catch to avoid the extra file system lookup using File.Exists try { buffer = File.ReadAllBytes(path); configuration = xmlSerializer.DeserializeFromBytes(type, buffer); } catch (Exception) { var instanceConfiguration = Activator.CreateInstance(type); configuration = instanceConfiguration ?? throw new NullReferenceException(nameof(instanceConfiguration)); } using var stream = new MemoryStream(buffer?.Length ?? 0); xmlSerializer.SerializeToStream(configuration, stream); // Take the object we just got and serialize it back to bytes byte[] newBytes = stream.GetBuffer(); int newBytesLen = (int)stream.Length; // If the file didn't exist before, or if something has changed, re-save if (buffer == null || !newBytes.AsSpan(0, newBytesLen).SequenceEqual(buffer)) { var directory = Path.GetDirectoryName(path); if (directory == null) { throw new NullReferenceException(nameof(directory)); } Directory.CreateDirectory(directory); // Save it after load in case we got new items using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read)) { fs.Write(newBytes, 0, newBytesLen); } } return configuration; } } }