Skip to content

Commit

Permalink
Fix Default/OEM encoding behavior PowerShell Core (#3467)
Browse files Browse the repository at this point in the history
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))
  • Loading branch information
iSazonov authored and daxian-dbw committed Apr 6, 2017
1 parent 459b0b5 commit 0883438
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 17 deletions.
Expand Up @@ -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" />
Expand Down
Expand Up @@ -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" />
Expand Down
Expand Up @@ -7569,8 +7569,7 @@ private static Encoding GetEncodingFromEnum(FileSystemCmdletProviderEncoding typ

case FileSystemCmdletProviderEncoding.Oem:
{
uint oemCP = NativeMethods.GetOEMCP();
encoding = System.Text.Encoding.GetEncoding((int)oemCP);
encoding = ClrFacade.GetOEMEncoding();
}
break;

Expand Down Expand Up @@ -7607,11 +7606,6 @@ public bool WasStreamTypeSpecified
} // get
} // WasStreamTypeSpecified

private static class NativeMethods
{
[DllImport(PinvokeDllNames.GetOEMCPDllName, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern uint GetOEMCP();
}
} // class FileSystemContentDynamicParametersBase

/// <summary>
Expand Down
44 changes: 35 additions & 9 deletions src/System.Management.Automation/utils/ClrFacade.cs
Expand Up @@ -530,22 +530,26 @@ internal static object[] GetCustomAttributes<T>(Assembly assembly)
#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>
Expand All @@ -555,18 +559,34 @@ internal static Encoding GetOEMEncoding()
{
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
Expand Down Expand Up @@ -1033,6 +1053,12 @@ private static class NativeMethods
[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>
Expand Down
2 changes: 2 additions & 0 deletions src/System.Management.Automation/utils/PInvokeDllNames.cs
Expand Up @@ -135,6 +135,7 @@ internal static class PinvokeDllNames
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*/
Expand Down Expand Up @@ -257,6 +258,7 @@ internal static class PinvokeDllNames
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
}
}

0 comments on commit 0883438

Please sign in to comment.