|
3 | 3 |
|
4 | 4 | using System;
|
5 | 5 | using System.Collections.Generic;
|
| 6 | +using System.Globalization; |
6 | 7 | using System.IO;
|
7 | 8 | using System.Linq;
|
8 | 9 | using System.Reflection;
|
@@ -87,21 +88,23 @@ public IFileInfo GetFileInfo(string subpath)
|
87 | 88 | // Relative paths starting with a leading slash okay
|
88 | 89 | if (subpath.StartsWith("/", StringComparison.Ordinal))
|
89 | 90 | {
|
90 |
| - builder.Append(subpath, 1, subpath.Length - 1); |
91 |
| - } |
92 |
| - else |
93 |
| - { |
94 |
| - builder.Append(subpath); |
| 91 | + subpath = subpath.Substring(1, subpath.Length - 1); |
95 | 92 | }
|
96 | 93 |
|
97 |
| - for (var i = _baseNamespace.Length; i < builder.Length; i++) |
| 94 | + // Make valid everett id from directory name |
| 95 | + // The call to this method also replaces directory separator chars to dots |
| 96 | + var everettId = MakeValidEverettIdentifier(Path.GetDirectoryName(subpath)); |
| 97 | + |
| 98 | + // if directory name was empty, everett id is empty as well |
| 99 | + if (!string.IsNullOrEmpty(everettId)) |
98 | 100 | {
|
99 |
| - if (builder[i] == '/' || builder[i] == '\\') |
100 |
| - { |
101 |
| - builder[i] = '.'; |
102 |
| - } |
| 101 | + builder.Append(everettId); |
| 102 | + builder.Append('.'); |
103 | 103 | }
|
104 | 104 |
|
| 105 | + // Append file name of path |
| 106 | + builder.Append(Path.GetFileName(subpath)); |
| 107 | + |
105 | 108 | var resourcePath = builder.ToString();
|
106 | 109 | if (HasInvalidPathChars(resourcePath))
|
107 | 110 | {
|
@@ -175,4 +178,123 @@ private static bool HasInvalidPathChars(string path)
|
175 | 178 | {
|
176 | 179 | return path.IndexOfAny(_invalidFileNameChars) != -1;
|
177 | 180 | }
|
| 181 | + |
| 182 | + #region Helper methods |
| 183 | + |
| 184 | + /// <summary> |
| 185 | + /// Is the character a valid first Everett identifier character? |
| 186 | + /// </summary> |
| 187 | + private static bool IsValidEverettIdFirstChar(char c) |
| 188 | + { |
| 189 | + return |
| 190 | + char.IsLetter(c) || |
| 191 | + CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation; |
| 192 | + } |
| 193 | + |
| 194 | + /// <summary> |
| 195 | + /// Is the character a valid Everett identifier character? |
| 196 | + /// </summary> |
| 197 | + private static bool IsValidEverettIdChar(char c) |
| 198 | + { |
| 199 | + var cat = CharUnicodeInfo.GetUnicodeCategory(c); |
| 200 | + |
| 201 | + return |
| 202 | + char.IsLetterOrDigit(c) || |
| 203 | + cat == UnicodeCategory.ConnectorPunctuation || |
| 204 | + cat == UnicodeCategory.NonSpacingMark || |
| 205 | + cat == UnicodeCategory.SpacingCombiningMark || |
| 206 | + cat == UnicodeCategory.EnclosingMark; |
| 207 | + } |
| 208 | + |
| 209 | + /// <summary> |
| 210 | + /// Make a folder subname into an Everett-compatible identifier |
| 211 | + /// </summary> |
| 212 | + private static void MakeValidEverettSubFolderIdentifier(StringBuilder builder, string subName) |
| 213 | + { |
| 214 | + if (string.IsNullOrEmpty(subName)) { return; } |
| 215 | + |
| 216 | + // the first character has stronger restrictions than the rest |
| 217 | + if (IsValidEverettIdFirstChar(subName[0])) |
| 218 | + { |
| 219 | + builder.Append(subName[0]); |
| 220 | + } |
| 221 | + else |
| 222 | + { |
| 223 | + builder.Append('_'); |
| 224 | + if (IsValidEverettIdChar(subName[0])) |
| 225 | + { |
| 226 | + // if it is a valid subsequent character, prepend an underscore to it |
| 227 | + builder.Append(subName[0]); |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + // process the rest of the subname |
| 232 | + for (var i = 1; i < subName.Length; i++) |
| 233 | + { |
| 234 | + if (!IsValidEverettIdChar(subName[i])) |
| 235 | + { |
| 236 | + builder.Append('_'); |
| 237 | + } |
| 238 | + else |
| 239 | + { |
| 240 | + builder.Append(subName[i]); |
| 241 | + } |
| 242 | + } |
| 243 | + } |
| 244 | + |
| 245 | + /// <summary> |
| 246 | + /// Make a folder name into an Everett-compatible identifier |
| 247 | + /// </summary> |
| 248 | + internal static void MakeValidEverettFolderIdentifier(StringBuilder builder, string name) |
| 249 | + { |
| 250 | + if (string.IsNullOrEmpty(name)) { return; } |
| 251 | + |
| 252 | + // store the original length for use later |
| 253 | + var length = builder.Length; |
| 254 | + |
| 255 | + // split folder name into subnames separated by '.', if any |
| 256 | + var subNames = name.Split('.'); |
| 257 | + |
| 258 | + // convert each subname separately |
| 259 | + MakeValidEverettSubFolderIdentifier(builder, subNames[0]); |
| 260 | + |
| 261 | + for (var i = 1; i < subNames.Length; i++) |
| 262 | + { |
| 263 | + builder.Append('.'); |
| 264 | + MakeValidEverettSubFolderIdentifier(builder, subNames[i]); |
| 265 | + } |
| 266 | + |
| 267 | + // folder name cannot be a single underscore - add another underscore to it |
| 268 | + if ((builder.Length - length) == 1 && builder[length] == '_') |
| 269 | + { |
| 270 | + builder.Append('_'); |
| 271 | + } |
| 272 | + } |
| 273 | + |
| 274 | + /// <summary> |
| 275 | + /// This method is provided for compatibility with Everett which used to convert parts of resource names into |
| 276 | + /// valid identifiers |
| 277 | + /// </summary> |
| 278 | + private static string? MakeValidEverettIdentifier(string? name) |
| 279 | + { |
| 280 | + if (string.IsNullOrEmpty(name)) { return name; } |
| 281 | + |
| 282 | + var everettId = new StringBuilder(name.Length); |
| 283 | + |
| 284 | + // split the name into folder names |
| 285 | + var subNames = name.Split(new[] { '/', '\\' }); |
| 286 | + |
| 287 | + // convert every folder name |
| 288 | + MakeValidEverettFolderIdentifier(everettId, subNames[0]); |
| 289 | + |
| 290 | + for (var i = 1; i < subNames.Length; i++) |
| 291 | + { |
| 292 | + everettId.Append('.'); |
| 293 | + MakeValidEverettFolderIdentifier(everettId, subNames[i]); |
| 294 | + } |
| 295 | + |
| 296 | + return everettId.ToString(); |
| 297 | + } |
| 298 | + |
| 299 | + #endregion |
178 | 300 | }
|
0 commit comments