|
|
@@ -3,6 +3,7 @@
|
|
|
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.Globalization;
|
|
|
using System.IO;
|
|
|
using System.Linq;
|
|
|
using System.Reflection;
|
|
|
@@ -87,21 +88,23 @@ public class EmbeddedFileProvider : IFileProvider
|
|
|
// Relative paths starting with a leading slash okay
|
|
|
if (subpath.StartsWith("/", StringComparison.Ordinal))
|
|
|
{
|
|
|
- builder.Append(subpath, 1, subpath.Length - 1);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- builder.Append(subpath);
|
|
|
+ subpath = subpath.Substring(1, subpath.Length - 1);
|
|
|
}
|
|
|
|
|
|
- for (var i = _baseNamespace.Length; i < builder.Length; i++)
|
|
|
+ // Make valid everett id from directory name
|
|
|
+ // The call to this method also replaces directory separator chars to dots
|
|
|
+ var everettId = MakeValidEverettIdentifier(Path.GetDirectoryName(subpath));
|
|
|
+
|
|
|
+ // if directory name was empty, everett id is empty as well
|
|
|
+ if (!string.IsNullOrEmpty(everettId))
|
|
|
{
|
|
|
- if (builder[i] == '/' || builder[i] == '\\')
|
|
|
- {
|
|
|
- builder[i] = '.';
|
|
|
- }
|
|
|
+ builder.Append(everettId);
|
|
|
+ builder.Append('.');
|
|
|
}
|
|
|
|
|
|
+ // Append file name of path
|
|
|
+ builder.Append(Path.GetFileName(subpath));
|
|
|
+
|
|
|
var resourcePath = builder.ToString();
|
|
|
if (HasInvalidPathChars(resourcePath))
|
|
|
{
|
|
|
@@ -175,4 +178,123 @@ public class EmbeddedFileProvider : IFileProvider
|
|
|
{
|
|
|
return path.IndexOfAny(_invalidFileNameChars) != -1;
|
|
|
}
|
|
|
+
|
|
|
+ #region Helper methods
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Is the character a valid first Everett identifier character?
|
|
|
+ /// </summary>
|
|
|
+ private static bool IsValidEverettIdFirstChar(char c)
|
|
|
+ {
|
|
|
+ return
|
|
|
+ char.IsLetter(c) ||
|
|
|
+ CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Is the character a valid Everett identifier character?
|
|
|
+ /// </summary>
|
|
|
+ private static bool IsValidEverettIdChar(char c)
|
|
|
+ {
|
|
|
+ var cat = CharUnicodeInfo.GetUnicodeCategory(c);
|
|
|
+
|
|
|
+ return
|
|
|
+ char.IsLetterOrDigit(c) ||
|
|
|
+ cat == UnicodeCategory.ConnectorPunctuation ||
|
|
|
+ cat == UnicodeCategory.NonSpacingMark ||
|
|
|
+ cat == UnicodeCategory.SpacingCombiningMark ||
|
|
|
+ cat == UnicodeCategory.EnclosingMark;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Make a folder subname into an Everett-compatible identifier
|
|
|
+ /// </summary>
|
|
|
+ private static void MakeValidEverettSubFolderIdentifier(StringBuilder builder, string subName)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(subName)) { return; }
|
|
|
+
|
|
|
+ // the first character has stronger restrictions than the rest
|
|
|
+ if (IsValidEverettIdFirstChar(subName[0]))
|
|
|
+ {
|
|
|
+ builder.Append(subName[0]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ builder.Append('_');
|
|
|
+ if (IsValidEverettIdChar(subName[0]))
|
|
|
+ {
|
|
|
+ // if it is a valid subsequent character, prepend an underscore to it
|
|
|
+ builder.Append(subName[0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // process the rest of the subname
|
|
|
+ for (var i = 1; i < subName.Length; i++)
|
|
|
+ {
|
|
|
+ if (!IsValidEverettIdChar(subName[i]))
|
|
|
+ {
|
|
|
+ builder.Append('_');
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ builder.Append(subName[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Make a folder name into an Everett-compatible identifier
|
|
|
+ /// </summary>
|
|
|
+ internal static void MakeValidEverettFolderIdentifier(StringBuilder builder, string name)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(name)) { return; }
|
|
|
+
|
|
|
+ // store the original length for use later
|
|
|
+ var length = builder.Length;
|
|
|
+
|
|
|
+ // split folder name into subnames separated by '.', if any
|
|
|
+ var subNames = name.Split('.');
|
|
|
+
|
|
|
+ // convert each subname separately
|
|
|
+ MakeValidEverettSubFolderIdentifier(builder, subNames[0]);
|
|
|
+
|
|
|
+ for (var i = 1; i < subNames.Length; i++)
|
|
|
+ {
|
|
|
+ builder.Append('.');
|
|
|
+ MakeValidEverettSubFolderIdentifier(builder, subNames[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // folder name cannot be a single underscore - add another underscore to it
|
|
|
+ if ((builder.Length - length) == 1 && builder[length] == '_')
|
|
|
+ {
|
|
|
+ builder.Append('_');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// This method is provided for compatibility with Everett which used to convert parts of resource names into
|
|
|
+ /// valid identifiers
|
|
|
+ /// </summary>
|
|
|
+ private static string? MakeValidEverettIdentifier(string? name)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(name)) { return name; }
|
|
|
+
|
|
|
+ var everettId = new StringBuilder(name.Length);
|
|
|
+
|
|
|
+ // split the name into folder names
|
|
|
+ var subNames = name.Split(new[] { '/', '\\' });
|
|
|
+
|
|
|
+ // convert every folder name
|
|
|
+ MakeValidEverettFolderIdentifier(everettId, subNames[0]);
|
|
|
+
|
|
|
+ for (var i = 1; i < subNames.Length; i++)
|
|
|
+ {
|
|
|
+ everettId.Append('.');
|
|
|
+ MakeValidEverettFolderIdentifier(everettId, subNames[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return everettId.ToString();
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
}
|