| File: Manifest\ManifestParser.cs | Web Access |
| Project: src\aspnetcore\src\FileProviders\Embedded\src\Microsoft.Extensions.FileProviders.Embedded.csproj (Microsoft.Extensions.FileProviders.Embedded) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Xml; using System.Xml.Linq; using Microsoft.AspNetCore.Shared; namespace Microsoft.Extensions.FileProviders.Embedded.Manifest; internal static class ManifestParser { private const string DefaultManifestName = "Microsoft.Extensions.FileProviders.Embedded.Manifest.xml"; public static EmbeddedFilesManifest Parse(Assembly assembly) { return Parse(assembly, DefaultManifestName); } public static EmbeddedFilesManifest Parse(Assembly assembly, string name) { ArgumentNullThrowHelper.ThrowIfNull(assembly); ArgumentNullThrowHelper.ThrowIfNull(name); var stream = assembly.GetManifestResourceStream(name); if (stream == null) { throw new InvalidOperationException($"Could not load the embedded file manifest " + $"'{name}' for assembly '{assembly.GetName().Name}'."); } var document = XDocument.Load(stream); var manifest = EnsureElement(document, "Manifest"); var manifestVersion = EnsureElement(manifest, "ManifestVersion"); var version = EnsureText(manifestVersion); if (!string.Equals("1.0", version, StringComparison.Ordinal)) { throw new InvalidOperationException($"The embedded file manifest '{name}' for " + $"assembly '{assembly.GetName().Name}' specifies an unsupported file format" + $" version: '{version}'."); } var fileSystem = EnsureElement(manifest, "FileSystem"); var entries = fileSystem.Elements(); var entriesList = new List<ManifestEntry>(); foreach (var element in entries) { var entry = BuildEntry(element); entriesList.Add(entry); } ValidateEntries(entriesList); var rootDirectory = ManifestDirectory.CreateRootDirectory(entriesList.ToArray()); return new EmbeddedFilesManifest(rootDirectory); } private static void ValidateEntries(List<ManifestEntry> entriesList) { for (int i = 0; i < entriesList.Count - 1; i++) { for (int j = i + 1; j < entriesList.Count; j++) { if (string.Equals(entriesList[i].Name, entriesList[j].Name, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException( "Found two entries with the same name but different casing:" + $" '{entriesList[i].Name}' and '{entriesList[j]}'"); } } } } private static ManifestEntry BuildEntry(XElement element) { RuntimeHelpers.EnsureSufficientExecutionStack(); if (element.NodeType != XmlNodeType.Element) { throw new InvalidOperationException($"Invalid manifest format. Expected a 'File' or a 'Directory' node:" + $" '{element}'"); } if (string.Equals(element.Name.LocalName, "File", StringComparison.Ordinal)) { var entryName = EnsureName(element); var path = EnsureElement(element, "ResourcePath"); var pathValue = EnsureText(path); return new ManifestFile(entryName, pathValue); } if (string.Equals(element.Name.LocalName, "Directory", StringComparison.Ordinal)) { var directoryName = EnsureName(element); var children = new List<ManifestEntry>(); foreach (var child in element.Elements()) { children.Add(BuildEntry(child)); } ValidateEntries(children); return ManifestDirectory.CreateDirectory(directoryName, children.ToArray()); } throw new InvalidOperationException($"Invalid manifest format.Expected a 'File' or a 'Directory' node. " + $"Got '{element.Name.LocalName}' instead."); } private static XElement EnsureElement(XContainer container, string elementName) { var element = container.Element(elementName); if (element == null) { throw new InvalidOperationException($"Invalid manifest format. Missing '{elementName}' element name"); } return element; } private static string EnsureName(XElement element) { var value = element.Attribute("Name")?.Value; if (value == null) { throw new InvalidOperationException($"Invalid manifest format. '{element.Name}' must contain a 'Name' attribute."); } return value; } private static string EnsureText(XElement element) { if (!element.Elements().Any() && !element.IsEmpty && element.Nodes().Count() == 1 && element.FirstNode?.NodeType == XmlNodeType.Text) { return element.Value; } throw new InvalidOperationException( $"Invalid manifest format. '{element.Name.LocalName}' must contain " + $"a text value. '{element.Value}'"); } }