Files
certmgr/certmgr/Core/Converters/Impl/StorageConverter.cs
2025-10-18 10:26:43 +02:00

122 lines
4.2 KiB
C#

using System.Diagnostics.CodeAnalysis;
using CertMgr.Core.Log;
using CertMgr.Core.Storage;
namespace CertMgr.Core.Converters.Impl;
internal sealed class StorageConverter : ValueConverter<IStorage>
{
private const char Separator = '|';
protected override Task<IStorage?> DoConvertAsync(string rawValue, Type targetType, CancellationToken cancellationToken)
{
ReadOnlySpan<char> rawSpan = rawValue.AsSpan();
int storageTypeSplitIndex = rawSpan.IndexOf(Separator);
if (storageTypeSplitIndex == -1)
{
return Task.FromResult((IStorage?)EmptyStorage.Empty);
}
IStorage? storage;
ReadOnlySpan<char> storageTypeSpan = rawSpan.Slice(0, storageTypeSplitIndex);
ReadOnlySpan<char> storageDefinition = rawSpan.Slice(storageTypeSplitIndex + 1);
switch (storageTypeSpan)
{
case "file":
if (!TryGetFileStore(storageDefinition, out storage))
{
storage = EmptyStorage.Empty;
}
break;
default:
storage = EmptyStorage.Empty;
break;
}
return Task.FromResult((IStorage?)storage);
}
private bool TryGetFileStore(ReadOnlySpan<char> storageDefinition, [NotNullWhen(true)] out IStorage? storage)
{
// expecting that 'storageDefinition' is something like:
// <store-mode>|<file-path>
// or
// |<file-path>
// or
// <file-path>
//
// where <store-mode> can be:
// 'o' or 'overwrite' or 'overwriteornew'
// or
// 'a' or 'append' or 'appendornew'
// or
// 'c' or 'create' or 'createnew'
//
// where <file-path> can be:
// 'c:\path\myfile.txt'
// or
// '/path/myfile.txt'
// or
// './path/myfile.txt'
// in addition - <file-path> can be either quoted or double-quoted
storage = null;
FileStoreMode defaultStoreMode = FileStoreMode.OverwriteOrNew;
FileStoreMode storeMode;
ReadOnlySpan<char> filename;
int firstSplitIndex = storageDefinition.IndexOf(Separator);
if (firstSplitIndex != -1)
{
// there is a splitter. On the left side of it there must be <store-mode>. On the right there is a <file-path>
ReadOnlySpan<char> firstPart = storageDefinition.Slice(0, firstSplitIndex);
filename = storageDefinition.Slice(firstSplitIndex + 1);
if (firstPart.Length == 0)
{
storeMode = defaultStoreMode;
}
else if (Enum.TryParse(firstPart, true, out FileStoreMode tmpMode))
{
storeMode = tmpMode;
}
else if (firstPart.Equals("w", StringComparison.OrdinalIgnoreCase) || firstPart.Equals("overwrite", StringComparison.OrdinalIgnoreCase))
{
storeMode = FileStoreMode.OverwriteOrNew;
}
else if (firstPart.Equals("c", StringComparison.OrdinalIgnoreCase) || firstPart.Equals("createnew", StringComparison.OrdinalIgnoreCase))
{
storeMode = FileStoreMode.Create;
}
else if (firstPart.Equals("a", StringComparison.OrdinalIgnoreCase) || firstPart.Equals("append", StringComparison.OrdinalIgnoreCase))
{
storeMode = FileStoreMode.AppendOrNew;
}
else if (firstPart.Equals("o", StringComparison.OrdinalIgnoreCase) || firstPart.Equals("open", StringComparison.OrdinalIgnoreCase))
{
storeMode = FileStoreMode.Open;
}
else
{
// it is not store-mode or there is a typo or unsupported value
CLog.Error(string.Concat("Unsupported store-mode '", firstPart, "'"));
storeMode = defaultStoreMode;
}
}
else
{
// no split-char => just filename
storeMode = defaultStoreMode;
filename = storageDefinition;
}
storage = new FileStorage(filename.ToString(), storeMode);
return true;
}
}