Fix Default/OEM encoding behavior PowerShell Core (#3467)

Based on the conclusion in discussion #3248, this PR fix "OEM" and "Default" encoding in powershell.
1. OEM -- We need an internal fix because .Net Core has no "OEM" encoding.
The fix gives the following PowerShell Core behavior on "OEM" encoding:
   - on Windows - as Windows PowerShell based on GetOEMCP() and legacy encodings (System.Text.Encoding.CodePages)
   - on Unix - the same as default encoding in PowerShell Core

2. Default -- We need internal fix because CoreFX `Encoding.default` for all platforms is UTF8.
Until we complete the `Encoding RFC` we should restore behavior as in Windows PowerShell.
The fix gives the following PowerShell Core behavior on "Default" encoding:
   - on Windows - as Windows PowerShell based on GetACP() and legacy encodings (System.Text.Encoding.CodePages)
   - on Unix - UTF-8 without BOM (We are expecting that the same will be [in CoreFX](https://github.com/dotnet/coreclr/issues/10643))
This commit is contained in:
Ilya
2017-04-05 18:22:18 -07:00
committed by Dongbo Wang
parent 459b0b5f29
commit 0883438e55
5 changed files with 39 additions and 17 deletions
@@ -85,7 +85,6 @@
<PackageReference Include="System.ServiceModel.Primitives" Version="4.3.0" />
<PackageReference Include="System.ServiceModel.Security" Version="4.3.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.3.0" />
<PackageReference Include="System.Text.Encodings.Web" Version="4.3.0" />
<PackageReference Include="System.Threading.AccessControl" Version="4.3.0" />
<PackageReference Include="System.Threading.Overlapped" Version="4.3.0" />
@@ -47,6 +47,7 @@
<PackageReference Include="System.Security.Cryptography.Algorithms" Version="4.3.0" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="4.3.0" />
<PackageReference Include="System.Security.Cryptography.X509Certificates" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.3.0" />
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
@@ -7569,8 +7569,7 @@ namespace Microsoft.PowerShell.Commands
case FileSystemCmdletProviderEncoding.Oem:
{
uint oemCP = NativeMethods.GetOEMCP();
encoding = System.Text.Encoding.GetEncoding((int)oemCP);
encoding = ClrFacade.GetOEMEncoding();
}
break;
@@ -7607,11 +7606,6 @@ namespace Microsoft.PowerShell.Commands
} // get
} // WasStreamTypeSpecified
private static class NativeMethods
{
[DllImport(PinvokeDllNames.GetOEMCPDllName, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern uint GetOEMCP();
}
} // class FileSystemContentDynamicParametersBase
/// <summary>
@@ -530,22 +530,26 @@ namespace System.Management.Automation
#region Encoding
/// <summary>
/// Facade for Encoding.Default
/// Facade for getting default encoding
/// </summary>
internal static Encoding GetDefaultEncoding()
{
if (s_defaultEncoding == null)
{
#if CORECLR // Encoding.Default is not in CoreCLR
// As suggested by CoreCLR team (tarekms), use latin1 (ISO-8859-1, CodePage 28591) as the default encoding.
// We will revisit this if it causes any failures when running tests on Core PS.
s_defaultEncoding = Encoding.GetEncoding(28591);
#else
#if UNIX // PowerShell Core on Unix
s_defaultEncoding = new UTF8Encoding(false);
#elif CORECLR // PowerShell Core on Windows
EncodingRegisterProvider();
uint currentAnsiCp = NativeMethods.GetACP();
s_defaultEncoding = Encoding.GetEncoding((int)currentAnsiCp);
#else // Windows PowerShell
s_defaultEncoding = Encoding.Default;
#endif
}
return s_defaultEncoding;
}
private static volatile Encoding s_defaultEncoding;
/// <summary>
@@ -555,18 +559,34 @@ namespace System.Management.Automation
{
if (s_oemEncoding == null)
{
#if CORECLR // The OEM code page '437' is not supported by CoreCLR.
// Use the default encoding (ISO-8859-1, CodePage 28591) as the OEM encoding in OneCore powershell.
#if UNIX // PowerShell Core on Unix
s_oemEncoding = GetDefaultEncoding();
#else
#elif CORECLR // PowerShell Core on Windows
EncodingRegisterProvider();
uint oemCp = NativeMethods.GetOEMCP();
s_oemEncoding = Encoding.GetEncoding((int)oemCp);
#else // Windows PowerShell
uint oemCp = NativeMethods.GetOEMCP();
s_oemEncoding = Encoding.GetEncoding((int)oemCp);
#endif
}
return s_oemEncoding;
}
private static volatile Encoding s_oemEncoding;
#if CORECLR
private static void EncodingRegisterProvider()
{
if (s_defaultEncoding == null && s_oemEncoding == null)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}
}
#endif
#endregion Encoding
#region Security
@@ -1033,6 +1053,12 @@ namespace System.Management.Automation
[DllImport(PinvokeDllNames.GetOEMCPDllName, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern uint GetOEMCP();
/// <summary>
/// Pinvoke for GetACP to get the Windows operating system code page.
/// </summary>
[DllImport(PinvokeDllNames.GetACPDllName, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern uint GetACP();
public const int S_OK = 0x00000000;
/// <summary>
@@ -135,6 +135,7 @@ namespace System.Management.Automation
internal const string CreateToolhelp32SnapshotDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*120*/
internal const string Process32FirstDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*121*/
internal const string Process32NextDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*122*/
internal const string GetACPDllName = "api-ms-win-core-localization-l1-2-0.dll"; /*123*/
#else
internal const string QueryDosDeviceDllName = "kernel32.dll"; /*1*/
internal const string CreateSymbolicLinkDllName = "kernel32.dll"; /*2*/
@@ -257,6 +258,7 @@ namespace System.Management.Automation
internal const string CreateToolhelp32SnapshotDllName = "kernel32.dll"; /*120*/
internal const string Process32FirstDllName = "kernel32.dll"; /*121*/
internal const string Process32NextDllName = "kernel32.dll"; /*122*/
internal const string GetACPDllName = "kernel32.dll"; /*123*/
#endif
}
}