199 lines
8.0 KiB
C#
199 lines
8.0 KiB
C#
// 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.Text;
|
|
|
|
namespace Microsoft.AspNetCore.Razor.Evolution
|
|
{
|
|
/// <summary>
|
|
/// The Razor template source.
|
|
/// </summary>
|
|
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];
|
|
|
|
/// <summary>
|
|
/// Encoding of the file that the text was read from.
|
|
/// </summary>
|
|
public abstract Encoding Encoding { get; }
|
|
|
|
/// <summary>
|
|
/// Path of the file the content was read from.
|
|
/// </summary>
|
|
public abstract string FileName { get; }
|
|
|
|
/// <summary>
|
|
/// Gets a character at given position.
|
|
/// </summary>
|
|
/// <param name="position">The position to get the character from.</param>
|
|
public abstract char this[int position] { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the length of the text in characters.
|
|
/// </summary>
|
|
public abstract int Length { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="RazorSourceLineCollection"/>.
|
|
/// </summary>
|
|
public abstract RazorSourceLineCollection Lines { get; }
|
|
|
|
/// <summary>
|
|
/// Copies a range of characters from the <see cref="RazorSourceDocument"/> to the specified <paramref name="destination"/>.
|
|
/// </summary>
|
|
/// <param name="sourceIndex">The index of the first character in this instance to copy.</param>
|
|
/// <param name="destination">The destination buffer.</param>
|
|
/// <param name="destinationIndex">The index in destination at which the copy operation begins.</param>
|
|
/// <param name="count">The number of characters in this instance to copy to destination.</param>
|
|
public abstract void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count);
|
|
|
|
/// <summary>
|
|
/// Reads the <see cref="RazorSourceDocument"/> from the specified <paramref name="stream"/>.
|
|
/// </summary>
|
|
/// <param name="stream">The <see cref="Stream"/> to read from.</param>
|
|
/// <param name="fileName">The file name of the template.</param>
|
|
/// <returns>The <see cref="RazorSourceDocument"/>.</returns>
|
|
public static RazorSourceDocument ReadFrom(Stream stream, string fileName)
|
|
{
|
|
if (stream == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(stream));
|
|
}
|
|
|
|
return ReadFromInternal(stream, fileName, encoding: null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the <see cref="RazorSourceDocument"/> from the specified <paramref name="stream"/>.
|
|
/// </summary>
|
|
/// <param name="stream">The <see cref="Stream"/> to read from.</param>
|
|
/// <param name="fileName">The file name of the template.</param>
|
|
/// <param name="encoding">The <see cref="System.Text.Encoding"/> to use to read the <paramref name="stream"/>.</param>
|
|
/// <returns>The <see cref="RazorSourceDocument"/>.</returns>
|
|
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));
|
|
}
|
|
|
|
return ReadFromInternal(stream, fileName, encoding);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the <see cref="RazorSourceDocument"/> from the specified <paramref name="projectItem"/>.
|
|
/// </summary>
|
|
/// <param name="projectItem">The <see cref="RazorProjectItem"/> to read from.</param>
|
|
/// <returns>The <see cref="RazorSourceDocument"/>.</returns>
|
|
public static RazorSourceDocument ReadFrom(RazorProjectItem projectItem)
|
|
{
|
|
if (projectItem == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(projectItem));
|
|
}
|
|
|
|
var path = projectItem.PhysicalPath;
|
|
if (string.IsNullOrEmpty(path))
|
|
{
|
|
path = projectItem.Path;
|
|
}
|
|
|
|
using (var inputStream = projectItem.Read())
|
|
{
|
|
return ReadFrom(inputStream, path);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a <see cref="RazorSourceDocument"/> from the specified <paramref name="content"/>.
|
|
/// </summary>
|
|
/// <param name="content">The template content.</param>
|
|
/// <param name="fileName">The file name of the <see cref="RazorSourceDocument"/>.</param>
|
|
/// <returns>The <see cref="RazorSourceDocument"/>.</returns>
|
|
/// <remarks>Uses <see cref="System.Text.Encoding.UTF8" /></remarks>
|
|
public static RazorSourceDocument Create(string content, string fileName)
|
|
=> Create(content, fileName, Encoding.UTF8);
|
|
|
|
/// <summary>
|
|
/// Creates a <see cref="RazorSourceDocument"/> from the specified <paramref name="content"/>.
|
|
/// </summary>
|
|
/// <param name="content">The template content.</param>
|
|
/// <param name="fileName">The file name of the <see cref="RazorSourceDocument"/>.</param>
|
|
/// <param name="encoding">The <see cref="System.Text.Encoding"/> of the file <paramref name="content"/> was read from.</param>
|
|
/// <returns>The <see cref="RazorSourceDocument"/>.</returns>
|
|
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));
|
|
}
|
|
|
|
return new DefaultRazorSourceDocument(content, encoding, fileName);
|
|
}
|
|
|
|
private static RazorSourceDocument ReadFromInternal(Stream stream, string fileName, Encoding encoding)
|
|
{
|
|
var streamLength = (int)stream.Length;
|
|
var content = string.Empty;
|
|
var contentEncoding = encoding ?? Encoding.UTF8;
|
|
|
|
if (streamLength > 0)
|
|
{
|
|
var bufferSize = Math.Min(streamLength, LargeObjectHeapLimitInChars);
|
|
|
|
var reader = new StreamReader(
|
|
stream,
|
|
contentEncoding,
|
|
detectEncodingFromByteOrderMarks: true,
|
|
bufferSize: bufferSize,
|
|
leaveOpen: true);
|
|
|
|
using (reader)
|
|
{
|
|
reader.Peek(); // Just to populate the encoding
|
|
|
|
if (encoding == null)
|
|
{
|
|
contentEncoding = reader.CurrentEncoding;
|
|
}
|
|
else if (encoding != reader.CurrentEncoding)
|
|
{
|
|
throw new InvalidOperationException(
|
|
Resources.FormatMismatchedContentEncoding(
|
|
encoding.EncodingName,
|
|
reader.CurrentEncoding.EncodingName));
|
|
}
|
|
|
|
if (streamLength > LargeObjectHeapLimitInChars)
|
|
{
|
|
// If the resulting string would end up on the large object heap, then use LargeTextRazorSourceDocument.
|
|
return new LargeTextRazorSourceDocument(
|
|
reader,
|
|
LargeObjectHeapLimitInChars,
|
|
contentEncoding,
|
|
fileName);
|
|
}
|
|
|
|
content = reader.ReadToEnd();
|
|
}
|
|
}
|
|
|
|
return new DefaultRazorSourceDocument(content, contentEncoding, fileName);
|
|
}
|
|
}
|
|
}
|