Simplify getting Encoding in TranscriptionOption.FlushContentToDisk (#13910)

This commit is contained in:
Xavier Hahn 2020-12-09 20:37:29 +01:00 committed by GitHub
parent 41ab20cce3
commit 971c428769
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 12 additions and 109 deletions

View file

@ -1391,96 +1391,11 @@ namespace System.Management.Automation
return hresult >= 0;
}
// Attempt to determine the existing encoding
internal static Encoding GetEncoding(string path)
{
if (!File.Exists(path))
{
return ClrFacade.GetDefaultEncoding();
}
byte[] initialBytes = new byte[100];
int bytesRead = 0;
try
{
using (FileStream stream = System.IO.File.OpenRead(path))
{
using (BinaryReader reader = new BinaryReader(stream))
{
bytesRead = reader.Read(initialBytes, 0, 100);
}
}
}
catch (IOException)
{
return ClrFacade.GetDefaultEncoding();
}
// Test for four-byte preambles
string preamble = null;
Encoding foundEncoding = ClrFacade.GetDefaultEncoding();
if (bytesRead > 3)
{
preamble = string.Join("-", initialBytes[0], initialBytes[1], initialBytes[2], initialBytes[3]);
if (encodingMap.TryGetValue(preamble, out foundEncoding))
{
return foundEncoding;
}
}
// Test for three-byte preambles
if (bytesRead > 2)
{
preamble = string.Join("-", initialBytes[0], initialBytes[1], initialBytes[2]);
if (encodingMap.TryGetValue(preamble, out foundEncoding))
{
return foundEncoding;
}
}
// Test for two-byte preambles
if (bytesRead > 1)
{
preamble = string.Join("-", initialBytes[0], initialBytes[1]);
if (encodingMap.TryGetValue(preamble, out foundEncoding))
{
return foundEncoding;
}
}
// Check for binary
string initialBytesAsAscii = System.Text.Encoding.ASCII.GetString(initialBytes, 0, bytesRead);
if (initialBytesAsAscii.IndexOfAny(nonPrintableCharacters) >= 0)
{
return Encoding.Unicode;
}
return utf8NoBom;
}
// BigEndianUTF32 encoding is possible, but requires creation
internal static readonly Encoding BigEndianUTF32Encoding = new UTF32Encoding(bigEndian: true, byteOrderMark: true);
// [System.Text.Encoding]::GetEncodings() | Where-Object { $_.GetEncoding().GetPreamble() } |
// Add-Member ScriptProperty Preamble { $this.GetEncoding().GetPreamble() -join "-" } -PassThru |
// Format-Table -Auto
internal static readonly Dictionary<string, Encoding> encodingMap =
new Dictionary<string, Encoding>()
{
{ "255-254", Encoding.Unicode },
{ "254-255", Encoding.BigEndianUnicode },
{ "255-254-0-0", Encoding.UTF32 },
{ "0-0-254-255", BigEndianUTF32Encoding },
{ "239-187-191", Encoding.UTF8 },
};
internal static readonly char[] nonPrintableCharacters = {
(char) 0, (char) 1, (char) 2, (char) 3, (char) 4, (char) 5, (char) 6, (char) 7, (char) 8,
(char) 11, (char) 12, (char) 14, (char) 15, (char) 16, (char) 17, (char) 18, (char) 19, (char) 20,
(char) 21, (char) 22, (char) 23, (char) 24, (char) 25, (char) 26, (char) 28, (char) 29, (char) 30,
(char) 31, (char) 127, (char) 129, (char) 141, (char) 143, (char) 144, (char) 157 };
internal static readonly UTF8Encoding utf8NoBom =
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

View file

@ -1071,22 +1071,7 @@ namespace System.Management.Automation.Host
/// <summary>
/// The path that this transcript is being logged to.
/// </summary>
internal string Path
{
get
{
return _path;
}
set
{
_path = value;
// Get the encoding from the file, or default (UTF8-NoBom)
Encoding = Utils.GetEncoding(value);
}
}
private string _path;
internal string Path { get; set; }
/// <summary>
/// Any output to log for this transcript.
@ -1104,12 +1089,6 @@ namespace System.Management.Automation.Host
/// </summary>
internal bool IncludeInvocationHeader { get; set; }
/// <summary>
/// The encoding of this transcript, so that appending to it
/// can be done correctly.
/// </summary>
internal Encoding Encoding { get; private set; }
/// <summary>
/// Logs buffered content to disk. We use this instead of File.AppendAllLines
/// so that we don't need to pay seek penalties all the time, and so that we
@ -1117,6 +1096,13 @@ namespace System.Management.Automation.Host
/// </summary>
internal void FlushContentToDisk()
{
static Encoding GetPathEncoding(string path)
{
using StreamReader reader = new StreamReader(path, Utils.utf8NoBom, detectEncodingFromByteOrderMarks: true);
_ = reader.Read();
return reader.CurrentEncoding;
}
lock (OutputBeingLogged)
{
if (!_disposed)
@ -1125,11 +1111,13 @@ namespace System.Management.Automation.Host
{
try
{
var currentEncoding = GetPathEncoding(this.Path);
// Try to first open the file with permissions that will allow us to read from it
// later.
_contentWriter = new StreamWriter(
new FileStream(this.Path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read),
this.Encoding);
currentEncoding);
_contentWriter.BaseStream.Seek(0, SeekOrigin.End);
}
catch (IOException)
@ -1138,7 +1126,7 @@ namespace System.Management.Automation.Host
// file permissions.
_contentWriter = new StreamWriter(
new FileStream(this.Path, FileMode.Append, FileAccess.Write, FileShare.Read),
this.Encoding);
Utils.utf8NoBom);
}
_contentWriter.AutoFlush = true;