// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace Microsoft.AspNetCore.Razor.Language { /// /// The Razor template source. /// public abstract class RazorSourceDocument { internal const int LargeObjectHeapLimitInChars = 40 * 1024; // 40K Unicode chars is 80KB which is less than the large object heap limit. internal static readonly RazorSourceDocument[] EmptyArray = new RazorSourceDocument[0]; /// /// Gets the encoding of the text in the original source document. /// /// /// Depending on the method used to create a the encoding may be used to /// read the file contents, or it may be solely informational. Refer to the documentation on the method /// used to create the for details. /// public abstract Encoding Encoding { get; } /// /// Gets the file path of the orginal source document. /// /// /// The file path may be either an absolute path or project-relative path. An absolute path is required /// to generate debuggable assemblies. /// public abstract string FilePath { get; } /// /// Gets the project-relative path to the source file. May be null. /// /// /// The relative path (if provided) is used for display (error messages). The project-relative path may also /// be used to embed checksums of the original source documents to support runtime recompilation of Razor code. /// public virtual string RelativePath => null; /// /// Gets a character at given position. /// /// The position to get the character from. public abstract char this[int position] { get; } /// /// Gets the length of the text in characters. /// public abstract int Length { get; } /// /// Gets the . /// public abstract RazorSourceLineCollection Lines { get; } /// /// Copies a range of characters from the to the specified . /// /// The index of the first character in this instance to copy. /// The destination buffer. /// The index in destination at which the copy operation begins. /// The number of characters in this instance to copy to destination. public abstract void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count); /// /// Calculates the checksum for the . /// /// The checksum. public abstract byte[] GetChecksum(); /// /// Gets the name of the algorithm used to compute the checksum returned by . /// /// /// This member did not exist in the 2.0 release, so it is possible for an implementation to return /// the wrong value (or null). Implementations of should /// override this member and specify their choice of hash algorithm even if it is the same as the /// default (SHA1). /// public virtual string GetChecksumAlgorithm() { return HashAlgorithmName.SHA1.Name; } /// /// Gets the file path in a format that should be used for display. /// /// The if set, or the . public virtual string GetFilePathForDisplay() { return RelativePath ?? FilePath; } /// /// Reads the from the specified . /// /// The to read from. /// The file name of the template. /// The . public static RazorSourceDocument ReadFrom(Stream stream, string fileName) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } var properties = new RazorSourceDocumentProperties(fileName, relativePath: null); return new StreamSourceDocument(stream, null, properties); } /// /// Reads the from the specified . /// /// The to read from. /// The file name of the template. /// The to use to read the . /// The . public static RazorSourceDocument ReadFrom(Stream stream, string fileName, Encoding encoding) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } var properties = new RazorSourceDocumentProperties(fileName, relativePath: null); return new StreamSourceDocument(stream, encoding, properties); } /// /// Reads the from the specified . /// /// The to read from. /// The to use to read the . /// Properties to configure the . /// The . public static RazorSourceDocument ReadFrom(Stream stream, Encoding encoding, RazorSourceDocumentProperties properties) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } if (properties == null) { throw new ArgumentNullException(nameof(properties)); } return new StreamSourceDocument(stream, encoding, properties); } /// /// Reads the from the specified . /// /// The to read from. /// The . public static RazorSourceDocument ReadFrom(RazorProjectItem projectItem) { if (projectItem == null) { throw new ArgumentNullException(nameof(projectItem)); } // ProjectItem.PhysicalPath is usually an absolute (rooted) path. var filePath = projectItem.PhysicalPath; if (string.IsNullOrEmpty(filePath)) { // Fall back to the relative path only if necessary. filePath = projectItem.RelativePhysicalPath; } if (string.IsNullOrEmpty(filePath)) { // Then fall back to the FilePath (yeah it's a bad name) which is like an MVC view engine path // It's much better to have something than nothing. filePath = projectItem.FilePath; } using (var stream = projectItem.Read()) { // Autodetect the encoding. var relativePath = projectItem.RelativePhysicalPath ?? projectItem.FilePath; return new StreamSourceDocument(stream, null, new RazorSourceDocumentProperties(filePath, relativePath)); } } /// /// Creates a from the specified . /// /// The source document content. /// The file name of the . /// The . /// Uses public static RazorSourceDocument Create(string content, string fileName) { if (content == null) { throw new ArgumentNullException(nameof(content)); } return Create(content, fileName, Encoding.UTF8); } /// /// Creates a from the specified . /// /// The source document content. /// Properties to configure the . /// The . /// Uses public static RazorSourceDocument Create(string content, RazorSourceDocumentProperties properties) { if (content == null) { throw new ArgumentNullException(nameof(content)); } if (properties == null) { throw new ArgumentNullException(nameof(properties)); } return Create(content, Encoding.UTF8, properties); } /// /// Creates a from the specified . /// /// The source document content. /// The file name of the . /// The of the file was read from. /// The . public static RazorSourceDocument Create(string content, string fileName, Encoding encoding) { if (content == null) { throw new ArgumentNullException(nameof(content)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } var properties = new RazorSourceDocumentProperties(fileName, relativePath: null); return new StringSourceDocument(content, encoding, properties); } /// /// Creates a from the specified . /// /// The source document content. /// The encoding of the source document. /// Properties to configure the . /// The . public static RazorSourceDocument Create(string content, Encoding encoding, RazorSourceDocumentProperties properties) { if (content == null) { throw new ArgumentNullException(nameof(content)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } if (properties == null) { throw new ArgumentNullException(nameof(properties)); } return new StringSourceDocument(content, encoding, properties); } } }