aspnetcore/src/Microsoft.AspNetCore.Razor..../StreamSourceDocument.cs

120 lines
4.2 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.Security.Cryptography;
using System.Text;
namespace Microsoft.AspNetCore.Razor.Language
{
internal class StreamSourceDocument : RazorSourceDocument
{
// Internal for testing
internal readonly RazorSourceDocument _innerSourceDocument;
private readonly byte[] _checksum;
public StreamSourceDocument(Stream stream, Encoding encoding, RazorSourceDocumentProperties properties)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
if (properties == null)
{
throw new ArgumentNullException(nameof(properties));
}
// Notice we don't validate the encoding here. StreamSourceDocument can compute it.
_checksum = ComputeChecksum(stream);
_innerSourceDocument = CreateInnerSourceDocument(stream, encoding, properties);
}
public override char this[int position] => _innerSourceDocument[position];
public override Encoding Encoding => _innerSourceDocument.Encoding;
public override string FilePath => _innerSourceDocument.FilePath;
public override int Length => _innerSourceDocument.Length;
public override RazorSourceLineCollection Lines => _innerSourceDocument.Lines;
public override string RelativePath => _innerSourceDocument.RelativePath;
public override void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
=> _innerSourceDocument.CopyTo(sourceIndex, destination, destinationIndex, count);
public override byte[] GetChecksum()
{
var copiedChecksum = new byte[_checksum.Length];
_checksum.CopyTo(copiedChecksum, 0);
return copiedChecksum;
}
private static byte[] ComputeChecksum(Stream stream)
{
using (var hashAlgorithm = SHA1.Create())
{
var checksum = hashAlgorithm.ComputeHash(stream);
stream.Position = 0;
return checksum;
}
}
private static RazorSourceDocument CreateInnerSourceDocument(Stream stream, Encoding encoding, RazorSourceDocumentProperties properties)
{
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 LargeTextSourceDocument.
return new LargeTextSourceDocument(
reader,
LargeObjectHeapLimitInChars,
contentEncoding,
properties);
}
content = reader.ReadToEnd();
}
}
return new StringSourceDocument(content, contentEncoding, properties);
}
}
}